/* BARE CSS — Boring, Accessible, Restrained, Equitable. */
/* A minimal CSS framework. */

/* ============================================
   1. ROOT & CUSTOM PROPERTIES
   ============================================ */

:root {
  --bare-text: #1a1a1a;
  --bare-bg: #fffefd;      /* beige très clair */
  /* Bleu des liens par défaut, clair et sombre : défini UNE fois, repris par
     les modes ci-dessous et par l'échantillon « Par défaut » des Réglages. */
  --bare-link-clair: #0000ee;
  --bare-link-sombre: #7db3fa;
  --bare-link: var(--bare-link-clair);
  --bare-border: #ddd;
  --bare-muted: #666;
  --bare-mark-bg: #fff3a0;
  --bare-mark-text: inherit;
  --bare-btn-bg: #efefef;
  --bare-card-header-bg: #f8f8f8;
  --bare-focus: #888;
  --bare-ok: #145214;
  --bare-warning: #5c4500;
  --bare-danger: #7a1010;
  --bare-ok-bg: #e6f4e6;
  --bare-warning-bg: #fff8e0;
  --bare-danger-bg: #fde8e8;
  /* Grille des écarts budgétaires (`.ecart-*`) : le CHIFFRE prend le vert et
     le rouge du THÈME — ses --bare-ok / --bare-danger, choisis pour lire sur SON
     fond. */
  --bare-ecart-pos: var(--bare-ok);
  --bare-ecart-neg: var(--bare-danger);
  --bare-gap-s: 0.3em;
  --bare-gap: 1em;
  --bare-gap-l: 2em;
  /* Largeur de la barre latérale (l'unique menu) et largeur de lecture du
     contenu. Le gabarit réserve la 1re colonne à la barre, la 2e au contenu ;
     replier la barre ramène sa colonne à zéro (cf. `--bare-sidebar-gutter`). */
  --bare-sidebar-w: 14em;
  --bare-content-w: 60em;
  /* Barre supérieure du contenu : elle porte le SEUL bouton qui déplie/replie
     le menu (elle-même n'est pas un menu). Elle défile avec la page — RIEN
     n'est figé en haut (à la demande) : un en-tête de tableau .sticky-head se
     fige donc au ras de l'écran (--bare-nav-h = 0). */
  --bare-topbar-h: 2.5rem;   /* = la ligne du h1 (2rem × interligne 1.25) */
  --bare-tete-pad: 0.75rem;  /* le blanc au-dessus du chat, du bouton et du h1 */
  --bare-nav-h: 0px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bare-text: #e0e0e0;
    --bare-bg: #1a1a1a;
    --bare-link: var(--bare-link-sombre);
    --bare-border: #444;
    --bare-muted: #aaa;
    --bare-mark-bg: #ffdd00;
    --bare-mark-text: #1a1a1a;
    --bare-btn-bg: #333;
    --bare-card-header-bg: #222;
    --bare-ok: #50dc50;
    --bare-warning: #e4c000;
    --bare-danger: #f09898;
    --bare-ok-bg: #1a3a1a;
    --bare-warning-bg: #3a3000;
    --bare-danger-bg: #3a1a1a;
    --bare-focus: #888;
  }
}

:root[data-theme="dark"] {
  --bare-text: #e0e0e0;
  --bare-bg: #1a1a1a;
  --bare-link: var(--bare-link-sombre);
  --bare-border: #444;
  --bare-muted: #aaa;
  --bare-mark-bg: #ffdd00;
  --bare-mark-text: #1a1a1a;
  --bare-btn-bg: #333;
  --bare-card-header-bg: #222;
  --bare-ok: #50dc50;
  --bare-warning: #e4c000;
  --bare-danger: #f09898;
  --bare-ok-bg: #1a3a1a;
  --bare-warning-bg: #3a3000;
  --bare-danger-bg: #3a1a1a;
  --bare-focus: #888;
}

/* ============================================
   1a. COULEUR D'ACCENT (reprise de Diffa)
   ============================================
   Indépendante du thème clair/sombre (catalogue : `themes.ACCENTS`, cookie,
   `data-accent` sur <html>). Chaque accent a une nuance pour fond clair
   (--accent-l) et une pour fond sombre (--accent-d) ; `data-mode` (posé avec
   un thème choisi) ou `prefers-color-scheme` (automatique) choisit laquelle
   devient --bare-accent. Un accent choisi est AUSSI la couleur des liens ;
   sans accent, l'accent est le bleu des liens par défaut. Les fonds sont ceux
   de Diffa : des gris qui prennent quelques pour cent de l'accent (la barre
   latérale, sur un gris plus foncé, un peu plus que la page) ; le survol et
   l'entrée courante du menu ne sont qu'un voile neutre, sans accent ; les
   champs de saisie gardent le fond pur du thème. */
:root {
  --accent-l: var(--bare-link);
  --accent-d: var(--bare-link);
  --bare-accent: var(--accent-l);
  --bare-page-bg: color-mix(in srgb, var(--bare-accent) 2%, var(--bare-bg));
  --bare-sidebar-bg: color-mix(in srgb, var(--bare-accent) 6%, #ececec);
  --bare-sidebar-hover: rgba(0, 0, 0, 0.045);
  --bare-sidebar-current: rgba(0, 0, 0, 0.075);
  --bare-card-head-bg: color-mix(in srgb, var(--bare-accent) 4%, var(--bare-card-header-bg));
  --bare-selection: color-mix(in srgb, var(--bare-accent) 18%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-mode]) {
    --bare-accent: var(--accent-d);
    --bare-page-bg: color-mix(in srgb, var(--bare-accent) 3%, var(--bare-bg));
    --bare-sidebar-bg: color-mix(in srgb, var(--bare-accent) 4%, #161618);
    --bare-sidebar-hover: rgba(255, 255, 255, 0.05);
    --bare-sidebar-current: rgba(255, 255, 255, 0.08);
    --bare-card-head-bg: color-mix(in srgb, var(--bare-accent) 3%, var(--bare-card-header-bg));
    --bare-selection: color-mix(in srgb, var(--bare-accent) 30%, transparent);
  }
}
:root[data-mode="sombre"] {
  --bare-accent: var(--accent-d);
  --bare-page-bg: color-mix(in srgb, var(--bare-accent) 3%, var(--bare-bg));
  --bare-sidebar-bg: color-mix(in srgb, var(--bare-accent) 4%, #161618);
  --bare-sidebar-hover: rgba(255, 255, 255, 0.05);
  --bare-sidebar-current: rgba(255, 255, 255, 0.08);
  --bare-card-head-bg: color-mix(in srgb, var(--bare-accent) 3%, var(--bare-card-header-bg));
  --bare-selection: color-mix(in srgb, var(--bare-accent) 30%, transparent);
}

/* Sans color-mix (navigateurs d'avant 2023) : les fonds purs du thème. */
@supports not (color: color-mix(in srgb, red 2%, blue)) {
  /* Mêmes sélecteurs que les blocs sombres (spécificité égale, posés après) :
     sinon leurs color-mix, invalides ici, laissent la page sans fond. */
  :root, :root:not([data-mode]), :root[data-mode="sombre"] {
    --bare-page-bg: var(--bare-bg);
    --bare-sidebar-bg: var(--bare-bg);
    --bare-sidebar-hover: var(--bare-btn-bg);
    --bare-sidebar-current: var(--bare-btn-bg);
    --bare-card-head-bg: var(--bare-card-header-bg);
    --bare-selection: var(--bare-mark-bg);
  }
}

/* Sélecteur sans :root : la même règle colore la pastille du choix (Réglages). */
[data-accent="brun"]     { --accent-l: #8b5a2b; --accent-d: #c9935f; }
[data-accent="olive"]    { --accent-l: #5b6b12; --accent-d: #b5c45a; }
[data-accent="ocre"]     { --accent-l: #a85d00; --accent-d: #f0a33a; }
[data-accent="emeraude"] { --accent-l: #046c4e; --accent-d: #34c38f; }
[data-accent="sarcelle"] { --accent-l: #0b6573; --accent-d: #3fb6c4; }
[data-accent="cobalt"]   { --accent-l: #1d4ed8; --accent-d: #6b93ff; }
[data-accent="indigo"]   { --accent-l: #3730a3; --accent-d: #8b8cf5; }
[data-accent="prune"]    { --accent-l: #6b21a8; --accent-d: #b98cf0; }

/* L'accent choisi colore les liens (après les blocs sombres : même spécificité). */
:root[data-accent] { --bare-link: var(--bare-accent); }

::selection { background: var(--bare-selection); }

/* Choix de l'accent (Réglages) : un rond de la couleur, dans la nuance du
   mode courant ; « par défaut » montre le bleu des liens par défaut
   (--bare-link-clair | --bare-link-sombre : --bare-link porte déjà l'accent
   choisi). */
.nuances {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bare-gap-s) var(--bare-gap);
}
.nuance {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
}
.echantillon {
  width: 1.2em;
  height: 1.2em;
  border-radius: 50%;
  background: var(--accent-l);
}
.echantillon:not([data-accent]) {
  --accent-l: var(--bare-link-clair);
  --accent-d: var(--bare-link-sombre);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-mode]) .echantillon { background: var(--accent-d); }
}
:root[data-mode="sombre"] .echantillon { background: var(--accent-d); }

/* ============================================
   2. BASE
   ============================================ */

*, *::before, *::after {
  box-sizing: border-box;
}

/* La place de la barre de défilement est TOUJOURS réservée : sans elle, la
   colonne de contenu (centrée) sautait de quelques pixels entre une page
   courte (pas de barre) et une page longue — ou dans la même page, quand un
   `<details>` qui s'ouvre la fait apparaître. */
html {
  scrollbar-gutter: stable;
}

body {
  margin: 0;
  /* Noto Serif d'abord : installée sur Linux, absente de macOS et Windows qui
     gardent Georgia. Sans elle, Linux tombait sur « Times New Roman », que
     fontconfig remplace par Liberation Serif. */
  font-family: "Noto Serif", Georgia, "Times New Roman", Times, serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  line-height: 1.5;
  /* La taille par défaut du navigateur (16px s'il n'a pas été réglé). */
  font-size: 100%;
  color: var(--bare-text);
  background: var(--bare-page-bg);
  /* Gabarit à barre latérale : le menu à gauche (1re colonne repliable), le
     contenu à droite (2e colonne). Deux enfants seulement : la barre (11b) et
     `.page`, toute la colonne de contenu. */
  --bare-sidebar-gutter: var(--bare-sidebar-w);
  display: grid;
  grid-template-columns: var(--bare-sidebar-gutter) minmax(0, 1fr);
  grid-template-rows: 1fr;
  align-items: stretch;
  min-height: 100vh;
}

/* Colonne de contenu : barre supérieure, tête de page, corps, pied — en flux
   FLEX vertical, pour que la barre supérieure (sticky) ait une hauteur où se
   coller et que le corps (`main`, 1fr) pousse le pied en bas (sticky footer). */
.page {
  grid-column: 2;
  min-width: 0;
  /* Conteneur de requête : `.pleine-largeur` se mesure en `cqw` sur la colonne
     de contenu réelle (sans la barre de défilement que `vw` inclut). */
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.page > main {
  flex: 1 0 auto;
}

/* Colonne de lecture : largeur bornée et CENTRÉE dans la place laissée par la
   barre latérale (comme l'ancienne colonne centrée du body). */
.page > header,
.page > main,
.page > footer {
  /* `width: 100%` : dans le flex vertical de `.page`, les marges `auto`
     annulent l'étirement — chaque bloc se rétrécissait à SON contenu puis se
     centrait, si bien que le h1 d'un en-tête court flottait vers le milieu, à
     une abscisse différente sur chaque page. Tous prennent la même colonne :
     le h1 s'aligne à gauche, sur le bord du contenu, partout. */
  width: 100%;
  max-width: var(--bare-content-w);
  margin-left: auto;
  margin-right: auto;
  padding-left: 1em;
  padding-right: 1em;
}

/* Rangée « titre + action » — PARTAGÉE par toutes les pages. Le titre (h1, ou
   h2 d'une section) à GAUCHE, sur le bord de la colonne comme un h1 seul ; une
   action (bouton, `a.btn`, petit formulaire) à DROITE, sur la même ligne,
   alignées au centre. Rien d'autre à poser dans le gabarit :
     <div class="titre-action"><h1>Titre</h1> <button …>Action</button></div>
   Le titre perd ses marges propres (portées par la rangée) — sinon ses marges
   verticales asymétriques décalent le bouton vers le haut. Sur un écran étroit,
   l'action passe SOUS le titre, calée à gauche. La rangée garde les marges
   d'un titre : 1re de l'en-tête, pas de marge haute (règle plus bas, 11). */
.titre-action {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--bare-gap-s) var(--bare-gap);
  margin: var(--bare-gap-l) 0 var(--bare-gap);
}
.titre-action > h1,
.titre-action > h2 {
  margin: 0;
  min-width: 0;
}
.titre-action > :not(h1):not(h2) {
  flex: 0 1 auto;
  max-width: 100%;          /* un long libellé passe à la ligne, ne déborde pas */
  white-space: normal;
  margin: 0;
}

/* Page hors dossier (invitation) : sans barre latérale ni barre du haut —
   la colonne du menu se réduit à rien, les pastilles montent tout en haut. */
body.sans-cadre {
  --bare-sidebar-gutter: 0px;
  --bare-nav-h: 0px;
}
body.sans-cadre .page { padding-top: var(--bare-gap-l); }

/* Page publique (accueil du visiteur, `base_public.html`) : en tête de la
   colonne, une rangée alignée sur elle — le chat (retour à l'accueil) au-dessus
   du h1, le lien de compte (« Connexion » ou « Mon compte ») au bord droit. */
body.public .tete-public {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
body.public .logo-public { color: var(--bare-text); }
body.public .tete-public + h1 { margin-top: var(--bare-gap); }

/* Assistant (`base_assistant.html`) : plein écran, sans barre. En tête, un
   bandeau sur TOUTE la largeur : la rangée nom | sortie, puis les étapes de
   gauche à droite — chacune coiffée d'un rail en POINTILLÉ, les points de la
   barre d'avancement de la Conformité (.avancement) : couleur du texte pour
   la part saisie de l'étape, gris clair pour le reste. L'étape courante se dit par le gras
   seul. Petit écran : seuls les numéros, sauf l'étape courante. */
body.assistant .page { padding-top: var(--bare-gap); }
.assistant-bandeau { padding: 0 1em; margin-bottom: var(--bare-gap-l); }
.assistant-tete {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--bare-gap);
  margin-bottom: var(--bare-gap);
}
.assistant-nom { display: flex; align-items: center; gap: .5em; font-weight: bold; }
.assistant-nom small { font-weight: normal; }
.assistant-sorties { display: flex; align-items: center; gap: 1em; }
/* Pas le `nav` des formulaires (collant, flex, filet en bas) : un simple bloc. */
nav.assistant-nav {
  position: static;
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
}
ol.assistant-etapes {
  display: flex;
  gap: .5em;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Les points prennent la couleur du `li` (currentColor) ; le lien a la sienne. */
ol.assistant-etapes li {
  flex: 1 1 0;
  min-width: 0;
  margin: 0;
  color: var(--bare-border);
  /* `space` : des points entiers seulement (pas de demi-point au bout d'une
     étape) ; le reste se répartit entre eux. */
  background: radial-gradient(circle, currentColor 1.5px, transparent 1.6px)
              0 0 / 6px 3px space no-repeat;
}
ol.assistant-etapes li.faite { color: var(--bare-text); }
/* Le rail se remplit au fil des saisies : la part `--pct` de l'étape (posée
   par le gabarit) en couleur du texte, le reste gris — un dégradé à deux tons
   découpé par les MÊMES points (`space` : des points entiers). Sans `mask`
   (navigateurs d'avant 2023), le rail ci-dessus : foncé si faite, gris sinon. */
@supports (mask: none) {
  ol.assistant-etapes li { position: relative; background: none; }
  ol.assistant-etapes li::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    background: linear-gradient(to right, var(--bare-text) var(--pct, 0%),
                                var(--bare-border) 0);
    mask: radial-gradient(circle, #000 1.5px, transparent 1.6px)
          0 0 / 6px 3px space no-repeat;
  }
  /* Avec round() : points sur une grille de 6 px depuis la gauche, la part
     foncée arrêtée sur un point entier (pas de demi-point à la jonction,
     comme `.avancement`) ; une étape pas faite garde au moins son dernier
     point gris (99 % ne paraît pas plein). Faite : arrondi au point SUPÉRIEUR
     — 100 % tout foncé, et le rail suit encore une saisie qu'on vide. Le rail
     mesure un multiple de 6 px : il finit, lui aussi, sur un point entier. */
  @supports (width: round(down, 10%, 6px)) {
    ol.assistant-etapes li::before {
      right: auto;
      width: round(down, 100%, 6px);
      background: linear-gradient(to right, var(--bare-text)
                    round(down, min(var(--pct, 0%), 100% - 6px), 6px),
                    var(--bare-border) 0);
      mask-repeat: repeat-x;
    }
    ol.assistant-etapes li.faite::before {
      background: linear-gradient(to right, var(--bare-text)
                    round(up, var(--pct, 100%), 6px), var(--bare-border) 0);
    }
  }
}
ol.assistant-etapes a {
  display: flex;
  align-items: baseline;
  gap: .5em;
  padding-top: calc(3px + .5em);
  color: var(--bare-text);
  text-decoration: none;
}
/* Plus spécifique que `nav a:hover`, qui soulignerait aussi le numéro. */
ol.assistant-etapes a:hover { text-decoration: none; }
ol.assistant-etapes a:hover .assistant-titre { text-decoration: underline; }
ol.assistant-etapes .courante a { font-weight: bold; }
.assistant-num { flex: none; font-variant-numeric: tabular-nums; }
.assistant-titre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 40em) {
  .assistant-nom small { display: none; }
  /* Masqué à l'œil seulement : le lecteur d'écran garde le nom du lien.
     Mêmes déclarations que .sr-only : changer l'une, c'est changer l'autre. */
  ol.assistant-etapes li:not(.courante) .assistant-titre {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  ol.assistant-etapes li.courante { flex-grow: 4; }
}

/* La barre latérale occupe la 1re colonne sur toute la hauteur (cf. 11b). */
body > nav.sidebar {
  grid-column: 1;
  grid-row: 1 / -1;
}

/* Menu replié : la colonne de la barre se réduit à rien, le contenu s'élargit
   d'autant ; la barre quitte aussi l'ordre de tabulation (visibility). */
html[data-sidebar="closed"] body {
  --bare-sidebar-gutter: 0px;
}

html[data-sidebar="closed"] body > nav.sidebar {
  visibility: hidden;
  /* Boîte ramenée à rien : sans cela, padding + filet déborderaient de la
     colonne repliée (0) et ouvriraient un défilement horizontal. */
  padding: 0;
  border-right: none;
  overflow: hidden;
}

footer {
  flex-shrink: 0;
  /* Le pied touche le bas de la fenêtre (sticky footer) ; un léger retrait le
     décolle du bord. */
  padding-bottom: var(--bare-gap);
  /* Discret : pas de filet, petit texte, une seule rangée (l'avis) —
     mais un large dégagement au-dessus, pour ne pas coller au contenu. */
  margin-top: calc(4 * var(--bare-gap-l));
  font-size: .8rem;
}

/* Skip to content — accessibility */
a[href="#content"] {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: var(--bare-gap-s) var(--bare-gap);
  background: var(--bare-text);
  color: var(--bare-bg);
  z-index: 1000;
}

a[href="#content"]:focus {
  left: 0;
}

/* ============================================
   2b. GRID
   ============================================ */

.grid {
  display: grid;
  gap: var(--bare-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(12em, 100%), 1fr));
}

.grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 40em) {
  .grid.cols-2 { grid-template-columns: 1fr; }
}

/* ============================================
   2c. FLEX
   ============================================ */

.flex        { display: flex; gap: var(--bare-gap); }
.flex.inline { display: inline-flex; }
.flex.wrap   { flex-wrap: wrap; }
.flex.col    { flex-direction: column; }
/* Ordre visuel inversé sans toucher l'ordre DOM (soumission implicite, tabulation). */
.flex.reverse { flex-direction: row-reverse; }

/* Alignment */
.flex.center  { align-items: center; }
.flex.start   { align-items: flex-start; }
.flex.end     { align-items: flex-end; }
.flex.stretch { align-items: stretch; }

/* Justification */
.flex.between { justify-content: space-between; }
.flex.around  { justify-content: space-around; }
.flex.evenly  { justify-content: space-evenly; }
.flex.jc-center { justify-content: center; }
.flex.jc-end    { justify-content: flex-end; }

/* Children */
.flex .grow   { flex-grow: 1; }
.flex .shrink { flex-shrink: 1; }
.flex .noshrink { flex-shrink: 0; }

/* Gap overrides */
.flex.gap-0 { gap: 0; }
.flex.gap-s { gap: var(--bare-gap-s); }
.flex.gap-l { gap: var(--bare-gap-l); }

/* ============================================
   3. TYPOGRAPHY
   ============================================ */

h1, h2, h3, h4, h5, h6 {
  margin-top: var(--bare-gap-l);
  margin-bottom: var(--bare-gap);
  line-height: 1.25;
}

h1 { font-size: 2em; }

/* Fil d'Ariane (sous-pages profondes : relevé, vérification, revue…) : le h1
   porte le CHEMIN, en liens — taille de texte normale et en maigre, des liens
   géants ou gras seraient criards. */
h1.fil {
  font-size: 1em;
  font-weight: normal;
}
/* Sous-titre : une phrase qui dit à quoi sert la page, juste sous le h1 (dans
   {% block header %}) ; collée au titre, en gris. */
/* Collé au titre : le h1 lâche sa marge du bas (1em à SA taille, 2em — une
   marge négative du paragraphe, comptée à la sienne, ne la compensait pas). */
h1:has(+ .sous-titre) { margin-bottom: 0; }
.sous-titre {
  color: var(--bare-muted);
  margin: var(--bare-gap-s) 0 var(--bare-gap);
}
h2 { font-size: 1.5em; }
h3 { font-size: 1.25em; }
h4 { font-size: 1em; }
h5 { font-size: 0.875em; }
h6 { font-size: 0.75em; }

p {
  margin: 0 0 var(--bare-gap);
}

small {
  font-size: 0.875em;
  color: var(--bare-muted);
}

blockquote {
  margin: var(--bare-gap) 0;
  padding: var(--bare-gap-s) var(--bare-gap);
  border-left: 3px solid var(--bare-border);
  color: var(--bare-muted);
}

blockquote > p:last-child {
  margin-bottom: 0;
}

mark {
  background: var(--bare-mark-bg);
  color: var(--bare-mark-text);
  padding: 0.1em 0.2em;
}

hr {
  border: none;
  border-top: 1px solid var(--bare-border);
  margin: var(--bare-gap-l) 0;
}

abbr[title] {
  text-decoration: underline dotted;
  cursor: help;
}

/* ============================================
   4. LINKS
   ============================================ */

a {
  color: var(--bare-link);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ============================================
   5. LISTS
   ============================================ */

ul, ol {
  margin: 0 0 var(--bare-gap);
  padding-left: var(--bare-gap-l);
}

li {
  margin-bottom: var(--bare-gap-s);
}

dt {
  font-weight: bold;
}

dd {
  margin: 0 0 var(--bare-gap-s);
}

/* ============================================
   6. TABLES
   ============================================ */

table {
  width: 100%;
  /* Georgia a des chiffres « à l'ancienne » (3, 4, 5, 7, 9 descendent) et
     proportionnels : dans un tableau on demande des chiffres alignés et de
     même chasse — les colonnes de montants restent d'aplomb. */
  font-variant-numeric: lining-nums tabular-nums;
  border-collapse: separate;
  border-spacing: 0;
  margin: var(--bare-gap) 0;
  border: 1px solid var(--bare-border);
  border-radius: 4px;
}

th, td {
  padding: var(--bare-gap-s) 0.75em;
  text-align: left;
  border-bottom: 1px solid var(--bare-border);
}

th {
  font-weight: bold;
}

tr:last-child td {
  border-bottom: none;
}

/* Pied de tableau (totaux de contrôle) : un filet le sépare du corps, comme le
   trait qu'on tire au-dessus d'un total — pas d'aplat ni de pastille, la somme
   se lit dans la continuité de sa colonne. Seule la PREMIÈRE rangée du pied
   porte le filet (un récap peut en compter plusieurs : entrées, sorties, net). */
tfoot tr:first-child > * {
  border-top: 2px solid var(--bare-border);
}

caption {
  margin-bottom: var(--bare-gap-s);
  font-size: 0.875em;
  color: var(--bare-muted);
}

/* En-têtes de tableau qui restent visibles au défilement. Le <thead> se fige
   sous la barre supérieure (la seule barre sticky du haut ; sa hauteur est
   `--bare-nav-h`) ; fond opaque + z-index pour que les lignes défilent DESSOUS.
   Fonctionne grâce au border-collapse: separate ci-dessus (le sticky d'un th est
   ignoré avec border-collapse: collapse). À poser sur les grands tableaux. */
table.sticky-head thead th,
table.grille-figee thead th {
  position: sticky;
  top: var(--bare-nav-h);
  background: var(--bare-page-bg);
  z-index: 10;
}

/* Grille FIGÉE (écarts budget – dépenses) : l'en-tête des mois reste en haut de
   l'ÉCRAN et la colonne des postes à sa gauche, quel que soit le défilement —
   les volets figés d'un tableur. Deux conditions :
   (1) la première colonne se fige à DROITE de la barre latérale (`left` vaut la
   largeur de la barre, zéro quand elle est repliée) : le fond opaque laisse les
   chiffres glisser DESSOUS et un filet à droite marque le volet ; la cellule de
   coin, figée dans les deux sens, passe au-dessus des deux bandes ;
   (2) le tableau défile avec le DOCUMENT, pas dans un `.scroll-x` : un sticky se
   fige dans son plus proche ancêtre DÉFILANT, or un cadre `overflow-x: auto` en
   est un dans les deux axes — l'en-tête n'y tiendrait que dans le cadre, jamais
   à l'écran. Le gabarit n'en met donc pas autour. */
table.grille-figee th:first-child,
table.grille-figee td:first-child {
  position: sticky;
  left: var(--bare-sidebar-gutter);
  background: var(--bare-page-bg);
  border-right: 1px solid var(--bare-border);
  z-index: 5;
}

table.grille-figee thead th:first-child {
  z-index: 15;
}

/* Treize colonnes de montants (douze mois + le total) doivent tenir dans la
   largeur de la page sans la dépasser : corps un cran plus petit, cellules
   resserrées. */
table.grille-figee { font-size: 0.9em; }
table.grille-figee th,
table.grille-figee td { padding: var(--bare-gap-s) 0.4em; }

/* Récap « Par cotisation » : la cotisation du filtre ACTIF est surlignée au
   surligneur BLEU (info), sur le TEXTE du titre. Recliquer la désélectionne
   (toggle : le href bascule côté serveur, le script en JS). Le bleu reste
   constant d'un thème à l'autre — variante claire/sombre seulement, comme
   .badge.special. */
tr.filtre-actif > td:first-child a {
  background: #dbe8f4; color: #1a4890;
  padding: 0.1em 0.25em; border-radius: 3px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) tr.filtre-actif > td:first-child a {
    background: #1a2e44; color: #8ec0ff;
  }
}
:root[data-theme="dark"] tr.filtre-actif > td:first-child a {
  background: #1a2e44; color: #8ec0ff;
}

/* ============================================
   8. FORMS
   ============================================ */

/* L'attribut HTML `hidden` doit gagner : nos règles d'AUTEUR `select/input
   { display: block }` (origine auteur) l'emportent sinon sur le `[hidden]
   { display: none }` du navigateur (origine UA), et un `<select hidden>`
   resterait visible. `!important` le garantit partout (selects masqués par JS —
   rattachements de la ventilation, lignes/bouton « Ajouter une ligne »…). */
[hidden] { display: none !important; }

label {
  display: block;
  margin-bottom: var(--bare-gap-s);
}

/* Champ obligatoire : une étoile grasse EN MARGE, à gauche du libellé, hors du
   flux (position absolue) : le texte du libellé reste aligné sur les autres.
   Le champ porte `required`, que les lecteurs d'écran annoncent. Posée par
   `required_css_class` des formulaires du projet (forms.REQUIS), à la main
   sur un libellé écrit dans un gabarit, sur le titre d'un groupe de choix. */
label.requis,
.groupe-titre.requis { position: relative; }
label.requis::before,
.groupe-titre.requis::before {
  content: "*";
  /* Décorative : texte de remplacement vide, sinon l'étoile entre dans le nom
     du champ (« étoile, Nombre d'étages ») — `required` le dit déjà. Un
     navigateur qui ignore cette syntaxe garde la déclaration du dessus. */
  content: "*" / "";
  position: absolute;
  right: 100%;
  padding-right: 0.25em;
  font-weight: bold;
  color: var(--bare-accent);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="url"],
input[type="tel"],
input[type="number"],
input[type="search"],
input[type="date"],
input[type="datetime-local"],
input[type="month"],
input[type="week"],
input[type="time"],
textarea,
select {
  display: block;
  width: 100%;
  padding: var(--bare-gap-s);
  margin-bottom: var(--bare-gap-l);
  font: inherit;
  color: var(--bare-text);
  background: var(--bare-bg);
  border: 1px solid var(--bare-border);
  border-radius: 4px;
}

textarea {
  resize: vertical;
  min-height: 6em;
}

select {
  appearance: auto;
}

/* Dans une rangée de formulaire (.flex : Date · Description · Montant, ou
   Sens · Fonds), chaque champ clôt sa colonne : la grande marge basse des
   champs pleine largeur (--bare-gap-l) se réduit, la rangée suivante reste
   dans le rythme du groupe. */
.flex label > input,
.flex label > select {
  margin-bottom: var(--bare-gap-s);
}

/* Messages en « pastilles » : petites, EN HAUT À DROITE, sous la barre du
   haut, empilées (la plus récente en bas), refermées par le script de base.html (4 s, 8 s pour une
   erreur ; clic = tout de suite — sans JS elles restent simplement affichées).
   La pastille est un ACCUSÉ DE RÉCEPTION, pas un lieu d'explication : un
   refus de formulaire s'explique AU-DESSUS du formulaire (.alert.danger) et
   la pastille se réduit alors à son ✕ (classe « bref »). */
.toasts {
  position: fixed;
  top: calc(var(--bare-nav-h, 0px) + var(--bare-gap));
  right: var(--bare-gap);
  z-index: 2000;
  display: flex;
  flex-direction: column;
  align-items: flex-end;           /* pastilles à la largeur de leur texte */
  gap: var(--bare-gap-s);
  max-width: min(26em, 92vw);
}

/* `.toasts p.toast` (et non `.toast`) pour battre la spécificité des règles
   de paragraphe de la base. Le glyphe est posé en CSS (::before) : un seul
   endroit le décide, le gabarit ne porte que le texte. */
.toasts p.toast {
  margin: 0;
  padding: 0.3em 0.6em;
  font-size: 0.9em;
  line-height: 1.35;
  border-radius: 4px;
  cursor: pointer;
  border: 1px solid var(--bare-border);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
  transition: opacity 0.4s;
  display: flex;
  align-items: baseline;
  gap: 0.4em;
}
.toasts p.toast::before { content: "✓"; font-weight: bold; }
.toasts p.toast.danger::before  { content: "✕"; }
.toasts p.toast.warning::before { content: "!"; }
.toasts p.toast.special::before { content: "i"; }

.toasts p.toast.ok      { background: var(--bare-ok-bg);      color: var(--bare-ok); }
.toasts p.toast.warning { background: var(--bare-warning-bg); color: var(--bare-warning); }
.toasts p.toast.danger  { background: var(--bare-danger-bg);  color: var(--bare-danger); }
.toasts p.toast.special { background: #dbe8f4;                color: #1a4890; }

.toast.toast-fin {
  opacity: 0;
}

/* Champ refusé : contour rouge et halo — le « rougeoiement » qui DÉSIGNE le
   champ dont le refus parle (le texte, lui, est au-dessus du formulaire).
   Posé par `aria-invalid` : forms.py le met sur les champs d'un formulaire
   Django refusé, et les écrans à formulaire écrit à la main le posent depuis
   `champs_fautifs`. Le repli `ul.errorlist + p` couvre les formulaires
   d'authentification de Django, qui n'ont pas notre mixin (cf. p.html : la
   liste d'erreurs précède le <p> du champ). */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"],
ul.errorlist + p input,
ul.errorlist + p select,
ul.errorlist + p textarea {
  border-color: var(--bare-danger);
  box-shadow: 0 0 0 3px var(--bare-danger-bg);
}

/* Un GROUPE de champs refusé (les radios d'une catégorie : on n'encercle pas
   chaque bouton) prend le même contour + halo que le ferait un champ. */
.groupe[aria-invalid="true"] {
  border: 1px solid var(--bare-danger);
  border-radius: 4px;
  padding: var(--bare-gap-s);
  box-shadow: 0 0 0 3px var(--bare-danger-bg);
}

/* Les listes d'erreurs que Django colle au champ (as_p) sont MUETTES : le
   texte du refus se dit UNE fois, au-dessus du formulaire
   (`_erreurs_formulaire.html`) ; ici, le champ se contente de rougeoyer. */
ul.errorlist {
  display: none;
}

/* Champ date (forms.DatePicker) : le <input type="date"> natif, assez large
   pour une date et pas plus — pas toute la ligne comme un champ texte. */
input[type="date"] {
  width: auto;
}

/* Rangée de champs « label AU-DESSUS du champ » posés côte à côte (répartition
   par fonds d'une cotisation, ou début · fréquence · fin) : on serre le rythme
   vertical — les grandes marges basses des champs (faites pour l'empilement)
   sont de trop ici, et le label colle à son champ. `input[type]` bat la
   spécificité de `input[type="number"]` de la base (cf. la règle des cellules). */
.rangee-champs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bare-gap);
  align-items: flex-end;
  margin-bottom: var(--bare-gap);
}
/* Variante en colonnes égales, chacune avec son aide dessous (les dates d'un
   mandat) : alignées en haut, l'aide la plus longue ne décale pas les champs. */
.rangee-champs.colonnes { align-items: flex-start; }
.rangee-champs.colonnes > * { flex: 1 1 11rem; }
.rangee-champs.colonnes .help { margin-bottom: 0; }
.rangee-champs label { margin-bottom: var(--bare-gap-s); }
.rangee-champs input[type],
.rangee-champs select { margin-bottom: 0; }

/* Dans une cellule de tableau (ventilation, postes du budget), c'est la
   rangée qui donne le rythme : aucun champ n'y porte de marge basse, et tous
   partagent la même hauteur alignée au milieu (sinon l'input Montant et les
   selects voisins décrochent). `input[type]` et non `input` : il faut battre
   la spécificité du sélecteur d'attribut `input[type="number"]` de la base,
   sinon la grande marge basse survit sur les inputs (mais pas les selects). */
td > input[type],
td > select {
  margin-bottom: 0;
  height: 2.4em;
  vertical-align: middle;
}

/* Ventilation : tableau PLEINE LARGEUR à 3 colonnes (Montant · Fonds ·
   Catégorie). Chaque champ remplit sa cellule ; le rattachement de cotisation
   s'empile SOUS la catégorie (même cellule) avec un léger espace. Mise en page
   FIXE : les colonnes gardent leurs proportions quel que soit le texte des
   options (sinon un libellé de cotisation très long élargirait sa colonne).
   S'applique à la revue (#table-ventilation) ET à l'éditeur de règle
   (#table-ventilation-regle). */
#table-ventilation,
#table-ventilation-regle { width: 100%; table-layout: fixed; }
/* Sans cadre ni filets (à la demande) : ce n'est pas un tableau à LIRE mais
   une rangée de champs — les contours des inputs suffisent à la structurer.
   La première colonne colle à la marge, alignée sur les champs au-dessus. */
#table-ventilation,
#table-ventilation-regle { border: none; border-radius: 0; margin: var(--bare-gap-l) 0; }
#table-ventilation th, #table-ventilation td,
#table-ventilation-regle th, #table-ventilation-regle td { border: none; }
#table-ventilation th:first-child, #table-ventilation td:first-child,
#table-ventilation-regle th:first-child,
#table-ventilation-regle td:first-child { padding-left: 0; }
#table-ventilation th:last-child, #table-ventilation td:last-child,
#table-ventilation-regle th:last-child,
#table-ventilation-regle td:last-child { padding-right: 0; }
#table-ventilation th, #table-ventilation-regle th { padding: 0 var(--bare-gap-s); font-weight: normal; }
#table-ventilation td,
#table-ventilation-regle td { padding: var(--bare-gap-s); vertical-align: top; }
#table-ventilation th:nth-child(1), #table-ventilation td:nth-child(1),
#table-ventilation-regle th:nth-child(1),
#table-ventilation-regle td:nth-child(1) { width: 20%; }
#table-ventilation th:nth-child(2), #table-ventilation td:nth-child(2),
#table-ventilation-regle th:nth-child(2),
#table-ventilation-regle td:nth-child(2) { width: 28%; }
#table-ventilation input[type="number"], #table-ventilation select,
#table-ventilation-regle input[type="number"],
#table-ventilation-regle select { width: 100%; }
#table-ventilation td > select + select,
#table-ventilation-regle td > select + select { margin-top: var(--bare-gap-s); }

/* Champs pré-remplis par une règle d'association (revue / vérification) : le
   jaune de <mark> porté PAR LE CHAMP lui-même — la provenance se voit, à
   confirmer du regard. Uniforme label/select/input : chaque champ (y compris
   une ligne de ventilation) est marqué INDIVIDUELLEMENT, donc un champ laissé
   vide n'est jamais surligné. */
label.prerempli,
select.prerempli,
input.prerempli {
  background: var(--bare-mark-bg);
  color: var(--bare-mark-text);
}

/* Période en une phrase : « Du 1er [mois][année] au 31 [mois][année] ».
   Les menus se dimensionnent à leur contenu et coulent dans le texte au lieu de
   prendre 100 % de la largeur (le défaut classless ci-dessus). */
.periode {
  line-height: 2.2;
}

.periode select {
  display: inline-block;
  width: auto;
  margin-bottom: 0;
  vertical-align: baseline;
}

/* Fin d'exercice : jour et mois côte à côte, chacun à la largeur de son
   contenu (FinExerciceWidget). */
select.jour-mois {
  display: inline-block;
  width: auto;
}
select.jour-mois + select.jour-mois { margin-left: var(--bare-gap-s); }

/* Cases à cocher de comptes (état partiel) : en ligne. */
.comptes label {
  display: inline-block;
  margin: 0 var(--bare-gap) var(--bare-gap-s) 0;
}

/* Barre de filtres (journal) : les champs coulent en une rangée compacte —
   menus et champs à leur taille de contenu, sans la grande marge de bloc du
   défaut classless (l'espacement vient du gap du conteneur .flex). */
.filtres label { margin-bottom: 0; }
.filtres input,
.filtres select,
.filtres button {
  display: inline-block;
  width: auto;
  margin-bottom: 0;
  /* Même hauteur pour TOUS les contrôles (date, menu, recherche, bouton) : les
     widgets natifs (date vs select) et les boutons (padding plus petit) diffèrent
     sinon de quelques pixels. box-sizing border-box (global) inclut padding + bordure. */
  height: 2.4em;
}
.filtres button {
  /* Texte du bouton centré verticalement dans sa hauteur fixe. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* Le menu « exercice fiscal » : assez large pour afficher « Exercice 2025 »
   ou le titre « Exercice fiscal ? » sans troncature. */
.filtres .fy-select { min-width: 12em; }
/* Rangée de menus (2e ligne) ÉTIRÉE : chaque menu grandit également pour
   remplir toute la largeur (même base + même grow = largeurs égales). */
.filtres .menus-full select { flex: 1 1 12em; }

/* Bouton « Surligner » : jaune constant (même jaune que le stabilo), pour
   l'action de MISE EN ÉVIDENCE (montre toute la période, marque les
   correspondances). Constant d'un thème à l'autre, comme les boutons sémantiques. */
button.jaune {
  background: #fde047;
  color: #1a1a1a;
  border-color: #fde047;
}
/* Ligne du journal SURLIGNÉE (résultat du mode « Surligner ») : fond jaune doux,
   texte foncé lisible. */
tr.surlignee > td { background-color: #fef08a; color: #1a1a1a; }
/* La flèche « ← » (raccourci exercice) centrée verticalement sur la rangée,
   à la même hauteur que les champs voisins. */
.filtres .fy-arrow {
  display: inline-flex;
  align-items: center;
  height: 2.4em;
  line-height: 1;
}

/* Clignotement : signale au regard un champ qui vient d'être pré-rempli
   (journal — le menu « exercice fiscal » remplit les deux dates). Trois flashs
   brefs, puis retour à l'état normal. */
@keyframes clignote { 0%, 100% { opacity: 1; } 50% { opacity: 0.15; } }
.clignote { animation: clignote 0.4s ease-in-out 3; }

fieldset {
  border: 1px solid var(--bare-border);
  padding: var(--bare-gap);
  margin: var(--bare-gap) 0;
  border-radius: 4px;
}

legend {
  font-weight: bold;
  padding: 0 0.25em;
}

/* Groupe de champs SANS bordure — alternative au <fieldset> à l'intérieur
   d'une carte (préférence projet : jamais de <fieldset> dans une .card, pour
   éviter le double encadré). */
.groupe {
  margin: var(--bare-gap) 0;
}

.groupe-titre {
  font-weight: bold;
  margin: 0 0 var(--bare-gap-s);
}

.help {
  font-size: 0.875em;
  color: var(--bare-muted);
  margin: var(--bare-gap-s) 0 var(--bare-gap);
}

/* L'aide qui suit un champ lui colle : le champ lâche sa grande marge du bas
   (l'aide la reprend), et l'aide en <span> passe en bloc pour que sa marge
   du haut compte. (L'aide d'une case à cocher suit son libellé : règle plus bas.) */
:is(input:not([type="checkbox"], [type="radio"]), select, textarea):has(+ .help) {
  margin-bottom: 0;
}
:is(input:not([type="checkbox"], [type="radio"]), select, textarea) + span.help {
  display: block;
}
/* L'aide posée sous le libellé, HORS de lui (le nom du champ reste court au
   lecteur d'écran ; le champ la désigne par aria-describedby) : elle colle au
   libellé et garde son écart avec le champ. */
label:has(+ span.help) {
  margin-bottom: 0;
}
label + span.help {
  display: block;
  margin: 0 0 var(--bare-gap-s);
}

input[type="checkbox"],
input[type="radio"] {
  margin-right: var(--bare-gap-s);
  vertical-align: middle;
  margin-top: -0.2em;
}

input[type="checkbox"] + label,
input[type="radio"] + label {
  display: inline;
  margin-right: var(--bare-gap);
}

.vertical {
  display: flex;
  flex-direction: column;
  gap: var(--bare-gap-s);
}

/* ============================================
   8b. FORM VALIDATION
   ============================================ */

input:user-valid,
textarea:user-valid,
select:user-valid {
  border-color: var(--bare-ok);
}

input:user-invalid,
textarea:user-invalid,
select:user-invalid {
  border-color: var(--bare-danger);
}

.help.ok     { color: var(--bare-ok); }
.help.danger { color: var(--bare-danger); }

/* ============================================
   8c. INPUT GROUPS
   ============================================ */

.input-group span {
  display: flex;
  align-items: center;
  padding: var(--bare-gap-s) var(--bare-gap);
  background: var(--bare-btn-bg);
  border: 1px solid var(--bare-border);
  white-space: nowrap;
  font-size: 0.875em;
}

.input-group button {
  border-radius: 0;
  margin: 0;
}

.input-group > :not(:first-child) {
  margin-left: -1px;
}

/* ============================================
   9. BUTTONS
   ============================================ */

button,
input[type="submit"],
input[type="reset"],
input[type="button"],
a.btn {
  --btn-bg: var(--bare-btn-bg);
  --btn-fg: var(--bare-text);
  font: inherit;
  padding: 0.15em 0.5em;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: 1px solid var(--btn-bg);
  border-radius: 4px;
  cursor: pointer;
}

/* Un lien présenté comme un bouton — pour NAVIGUER avec l'aspect d'un bouton
   sans imbriquer <button> dans <a> (HTML invalide). Mêmes couleurs que button. */
a.btn {
  display: inline-block;
  text-decoration: none;
}

button:hover,
input[type="submit"]:hover,
input[type="reset"]:hover,
input[type="button"]:hover,
a.btn:hover {
  background: var(--bare-page-bg);
  color: var(--bare-text);
}

/* Un bouton présenté comme un lien — pour AGIR sur la page (ouvrir une fenêtre
   `popovertarget`) au fil du texte, là où un lien rechargerait la page. */
button.lien,
button.lien:hover {
  padding: 0;
  background: none;
  border: none;
  color: var(--bare-link);
}

button.lien:hover {
  text-decoration: underline;
}

button.ok:hover,
button.danger:hover,
button.special:hover,
a.btn.ok:hover,
a.btn.danger:hover,
a.btn.special:hover {
  background: var(--btn-fg);
  color: var(--btn-bg);
}

button.ok,
a.btn.ok {
  --btn-bg: #2a7d2a;
  --btn-fg: #fff;
}

button.danger,
a.btn.danger {
  --btn-bg: #c33;
  --btn-fg: #fff;
}

button.special,
a.btn.special {
  --btn-bg: #2a5da8;
  --btn-fg: #fff;
}

button.small {
  font-size: 0.875em;
  padding: 0.15em 0.5em;
}

button[disabled],
input[disabled],
textarea[disabled],
select[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

:root[data-theme="dark"] button.ok { --btn-bg: #1e5c1e; }
:root[data-theme="dark"] button.danger { --btn-bg: #8f2424; }
:root[data-theme="dark"] button.special { --btn-bg: #234e8f; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) button.ok { --btn-bg: #1e5c1e; }
  :root:not([data-theme="light"]) button.danger { --btn-bg: #8f2424; }
  :root:not([data-theme="light"]) button.special { --btn-bg: #234e8f; }
}

/* Bouton « au trait » : la couleur sémantique (--btn-bg posé par .ok/.danger/
   .special, surcharges de thème comprises) portée en CONTOUR plutôt qu'en aplat
   — fond transparent, texte + bordure colorés. Pour une action présente mais qui
   ne doit pas crier (remplacer / supprimer un relevé). Se remplit au survol.
   Placé après les règles sémantiques : gagne à spécificité égale. */
button.outline,
a.btn.outline {
  background: transparent;
  color: var(--btn-bg);
}

button.outline:hover,
a.btn.outline:hover {
  background: var(--btn-bg);
  color: var(--btn-fg);
}

/* ============================================
   10. ALERTS
   ============================================ */

.alert {
  padding: var(--bare-gap);
  margin: var(--bare-gap) 0;
  border-radius: 4px;
}

.alert.ok {
  background: var(--bare-ok-bg);
  color: var(--bare-ok);
}

.alert.warning {
  background: var(--bare-warning-bg);
  color: var(--bare-warning);
}

.alert.danger {
  background: var(--bare-danger-bg);
  color: var(--bare-danger);
}

/* Info (bleu) — pendant « alerte » du badge special, pour un message multi-mots. */
.alert.special {
  background: #dbe8f4;
  color: #1a4890;
}

/* ============================================
   10b. BADGES
   ============================================ */

.badge {
  display: inline-block;
  padding: 0.35em 0.5em;
  font-size: 0.75em;
  font-weight: bold;
  line-height: 1;
  border-radius: 4px;
  background: var(--bare-btn-bg);
  color: var(--bare-text);
  vertical-align: middle;
}

.badge.ok      { background: var(--bare-ok-bg);      color: var(--bare-ok); }
.badge.warning { background: var(--bare-warning-bg);  color: var(--bare-warning); }
.badge.danger  { background: var(--bare-danger-bg);   color: var(--bare-danger); }
.badge.special { background: #dbe8f4; color: #1a4890; }

/* Grille des écarts budget – dépenses (`_budget_ecarts.html`) : la couleur va
   sur le CHIFFRE, la cellule reste nue, et le chiffre garde la taille du corps.
   Tons CALMES (à la demande) : le vert/rouge du THÈME (`--bare-ecart-*`, lisible
   sur son fond) adouci d'un tiers vers la couleur du texte — la nuance se voit
   sans crier, et le contraste ne baisse pas (le texte est plus contrasté encore). */
.ecart-pos { color: color-mix(in srgb, var(--bare-ecart-pos) 65%, var(--bare-text)); }
.ecart-neg { color: color-mix(in srgb, var(--bare-ecart-neg) 65%, var(--bare-text)); }
/* Case d'écart sur fond coloré (Trésorerie) : vert = rien ne manque, rouge = il manque. */
td.fond-ok     { background: var(--bare-ok-bg); color: var(--bare-ok); }
td.fond-danger { background: var(--bare-danger-bg); color: var(--bare-danger); }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .badge.special { background: #1a2e44; color: #8ec0ff; }
}
:root[data-theme="dark"] .badge.special { background: #1a2e44; color: #8ec0ff; }

/* ============================================
   10c. CARDS
   ============================================ */

.card {
  border: 1px solid var(--bare-border);
  border-radius: 4px;
  margin: var(--bare-gap) 0;
  min-width: 0;
  overflow: hidden;
}

.card > header {
  padding: var(--bare-gap-s) var(--bare-gap);
  font-weight: bold;
  background: var(--bare-card-head-bg);
  border-radius: 4px 4px 0 0;
}

.card > :not(header) {
  padding-left: var(--bare-gap);
  padding-right: var(--bare-gap);
}

.card > header + * {
  padding-top: var(--bare-gap);
}

.card > :first-child:not(header) {
  padding-top: var(--bare-gap);
}

.card > :last-child {
  padding-bottom: var(--bare-gap);
  margin-bottom: 0;
}

/* ============================================
   11. PROGRESS
   ============================================ */

progress {
  appearance: none;
  width: 100%;
  height: 1em;
  border: none;
  border-radius: 4px;
  background: var(--bare-btn-bg);
  margin: 0 0 var(--bare-gap);
}

label + progress {
  margin-top: 0;
}

progress::-webkit-progress-bar {
  background: var(--bare-btn-bg);
  border-radius: 4px;
}

progress::-webkit-progress-value {
  background: var(--bare-border);
  border-radius: 4px;
}

progress::-moz-progress-bar {
  background: var(--bare-border);
  border-radius: 4px;
}

/* ============================================
   11. NAVIGATION
   ============================================ */

nav {
  position: sticky;
  top: 0;
  background: var(--bare-page-bg);
  margin: 0 0 var(--bare-gap-l);
  padding: 0.6em 0;
  border-bottom: 1px solid var(--bare-border);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--bare-gap);
}

/* Les règles `nav` ci-dessus ne servent plus qu'aux <nav> de FORMULAIRE
   (onglets de variantes, rangée d'actions) : le menu principal vit désormais
   dans la barre latérale, dont le gabarit est en 11b. */

nav ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--bare-gap);
}

nav li {
  margin: 0;
}

nav a {
  color: var(--bare-text);
}

nav a:hover {
  text-decoration: underline;
}

nav a[aria-current="page"] {
  font-weight: bold;
}

/* (La sous-navigation « Compta » a disparu : ses pages sont maintenant des
   entrées à plat de la barre latérale, cf. 11b.) */

/* Onglets d'un formulaire à variantes (revue : Une écriture / Ventiler /
   Virement entre comptes ; règle : Une écriture / Ventiler) : un GROUPE DE
   BOUTONS accolés, centré, dans le flux de la page — des choix qui s'excluent,
   présentés comme un seul objet (une bordure commune, coins arrondis aux deux
   bouts). L'onglet actif est PLEIN (couleurs inversées), les autres au trait.
   Hors de la barre du haut, donc ni collant ni filet. Ça reste une <nav> de
   liens (commutation côté serveur, ?onglet=…) : rien ne dépend d'un script. */
nav.onglets {
  position: static;
  z-index: auto;
  justify-content: center;
  gap: 0;
  border-bottom: none;
  margin: var(--bare-gap-l) 0;
  padding: 0;
}

nav.onglets a {
  display: inline-block;
  padding: 0.25em 0.9em;
  color: var(--bare-text);
  background: var(--bare-btn-bg);
  border: 1px solid var(--bare-border);
  text-decoration: none;
}

nav.onglets a + a { margin-left: -1px; }   /* les bordures voisines se confondent */
nav.onglets a:first-child { border-radius: 4px 0 0 4px; }
nav.onglets a:last-child { border-radius: 0 4px 4px 0; }

nav.onglets a:hover {
  background: var(--bare-page-bg);
  text-decoration: none;
}

nav.onglets a[aria-current="page"] {
  position: relative;   /* sa bordure passe DEVANT celles des voisins */
  z-index: 1;
  background: var(--bare-text);
  color: var(--bare-bg);
  border-color: var(--bare-text);
}

/* Onglets d'une PAGE à plusieurs vues (Comptabilité) : de vrais onglets,
   alignés à gauche sous le titre — pas un groupe de boutons. Un trait de base
   court sous la rangée ; l'onglet actif est ouvert vers le bas (sa bordure
   inférieure prend la couleur du fond), les autres sans encadré. */
nav.onglets.pages {
  justify-content: flex-start;
  align-items: flex-end;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--bare-border);
  margin: var(--bare-gap) 0 var(--bare-gap-l);
}

nav.onglets.pages a,
nav.onglets.pages a:first-child,
nav.onglets.pages a:last-child {
  background: none;
  border: 1px solid transparent;
  border-bottom: none;
  border-radius: 4px 4px 0 0;
  margin: 0 0 -1px;
  padding: 0.35em 0.9em;
}

nav.onglets.pages a:hover {
  background: var(--bare-btn-bg);
}

nav.onglets.pages a[aria-current="page"] {
  background: var(--bare-page-bg);
  color: var(--bare-text);
  border-color: var(--bare-border);
  border-bottom: 1px solid var(--bare-page-bg);
  font-weight: bold;
}

/* « Stabilo » : surligneur jaune — état d'AVERTISSEMENT réutilisable qui signale
   un réglage manquant / incomplet (onglet Compta à configurer, fractions non
   toutes renseignées, …). Constant d'un thème à l'autre, comme les boutons
   sémantiques : fond jaune + texte foncé, lisible partout comme sur du papier. */
.stabilo {
  background-color: #fde047;
  color: #1a1a1a;
  padding: 0 0.25em;
  border-radius: 0.15em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* Entrée de menu surlignée (« à configurer ») : le jaune couvre la ligne, le
   libellé repasse en foncé pour rester lisible sur le surligneur. */
.menu li.stabilo {
  background-color: #fde047;
  color: #1a1a1a;
  border-radius: 4px;
}

.menu li.stabilo a,
.menu li.stabilo a:hover {
  color: #1a1a1a;
  background: transparent;
}

/* Le h1 est sur la MÊME LIGNE que le chat et le bouton du menu : la barre du
   haut ne prend pas de place (marge négative, cf. .topbar), l'en-tête reprend
   son blanc (--bare-tete-pad) et sa ligne (--bare-topbar-h = celle du h1).
   Hauteur minimale : un en-tête vide (ex. Clôtures) garde le contenu sous la
   ligne du bouton. */
.page > .topbar ~ header {
  padding-top: var(--bare-tete-pad);
  min-height: calc(var(--bare-tete-pad) + var(--bare-topbar-h));
}
.page > .topbar ~ header:not(:has(*)) {
  margin-bottom: var(--bare-gap-l);
}
/* Colonne étroite (petit écran, ou colonne qui touche le bouton) : la 1re ligne
   de l'en-tête se décale juste ce qu'il faut pour passer à droite du bouton
   (2.75rem, moins la marge déjà laissée par la colonne centrée). Retrait de
   1re ligne, hérité du seul premier enfant : le reste de l'en-tête n'en a pas.
   `100cqw` = la largeur réelle de `.page` (sans la barre de défilement que
   `100vw` compte). Sans JS (`data-sidebar` absent), pas de bouton : pas de
   retrait. */
html[data-sidebar] .page > .topbar ~ header {
  text-indent: max(0px, 2.75rem - max(0px, (100cqw - var(--bare-content-w)) / 2));
}
.page > .topbar ~ header > :not(:first-child),
.page > .topbar ~ header > :first-child > :not(h1) {
  text-indent: 0;
}
.page > header > :first-child {
  margin-top: 0;
}

/* Fil d'Ariane (sous-pages profondes) : centré sur la ligne du bouton, suivi
   d'un blanc franc — le contenu commence plus bas. Spécificité > règle ci-dessus. */
.page > header > h1.fil {
  margin-top: calc((var(--bare-topbar-h) - 1.25em) / 2);
  margin-bottom: var(--bare-gap-l);
}

/* Idem pour le 1er bloc du contenu : quand l'en-tête est vide (ex. Clôtures),
   la marge haute du bloc ne doit pas s'ajouter sous la barre supérieure. */
.page > main > :first-child {
  margin-top: 0;
}

/* ============================================
   11b. BARRE LATÉRALE, BARRE SUPÉRIEURE & TIROIR
   ============================================ */

/* ---- Barre latérale : l'UNIQUE menu. À plat, simplement groupé par de petits
   intitulés (pas de sous-menu, pas de dépliant). ---- */
nav.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: var(--bare-gap);
  height: 100vh;
  overflow-y: auto;
  margin: 0;
  /* En haut, le blanc de la barre du haut : le logo est sur la ligne du
     bouton du menu et du h1 (cf. .sidebar-head). */
  padding: var(--bare-tete-pad) 1em var(--bare-gap);
  border-bottom: none;
  border-right: 1px solid var(--bare-border);
  background: var(--bare-sidebar-bg);
  z-index: 100;
  font-size: 0.95em;
}

/* Tête de la barre : le logo, centré dans la ligne du h1 (celle de la barre
   du haut), et le bouton ✕ du tiroir (petit écran seulement, cf. media query). */
.sidebar-head {
  display: flex;
  align-items: center;
  gap: var(--bare-gap-s);
  min-height: var(--bare-topbar-h);
  padding-left: var(--bare-gap);
}
.sidebar-logo {
  color: var(--bare-text);
}

/* Logo (tête de la barre) : le dessin de static/logo.svg sert de MASQUE, la
   couleur vient du texte — il suit donc chaque thème (le fichier lui-même
   reste le favicon). */
.logo {
  display: block;
  width: 1.8em;
  height: 1.8em;
  background: currentColor;
  -webkit-mask: url("logo.b587d8a8aca0.svg") center / contain no-repeat;
  mask: url("logo.b587d8a8aca0.svg") center / contain no-repeat;
}

/* Bouton ✕ du tiroir : petit écran seulement (cf. media query plus bas). */
.sidebar-close {
  display: none;
  margin-left: auto;
}

/* Le bas de la barre : le sélecteur de syndicat (compte à plusieurs
   syndicats) ou, hors syndicat ouvert, la déconnexion ; le menu au-dessus. */
.sidebar-foot {
  margin-top: auto;
  padding-top: var(--bare-gap);
}
/* Sélecteur de syndicat : le syndicat courant (⇅) ; ouvert, les autres
   s'ajoutent DESSUS, comme un menu qui monte du bas de la barre. */
.changer-syndicat {
  display: flex;
  flex-direction: column-reverse;
  /* ni cadre ni retrait de `details` : aligné sur les entrées du menu */
  margin: 0;
  border: 0;
  padding: 0;
}
.changer-syndicat[open] > summary { margin-bottom: 0; }
.changer-syndicat > summary {
  padding: var(--bare-gap-s) var(--bare-gap);
  font-weight: bold;
  cursor: pointer;
  list-style: none;
}
.changer-syndicat > summary::-webkit-details-marker { display: none; }
.changer-syndicat > summary::after {
  content: " ⇅";
  content: " ⇅" / "";
  color: var(--bare-muted);
  font-weight: normal;
}

.menu-heading {
  margin: 0 0 var(--bare-gap-s);
  padding: 0 var(--bare-gap);
  font-size: 0.8em;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bare-muted);
}

.menu {
  /* `nav ul` (barres de formulaire) est en flex horizontal ; le menu de la barre
     latérale, lui, s'empile : on rétablit le flux vertical. */
  display: block;
  list-style: none;
  padding: 0;
  margin: 0;
}

.menu li {
  margin: 0;
}

.menu a {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: var(--bare-gap-s) var(--bare-gap);
  color: var(--bare-text);
  border-radius: 4px;
}

.menu a:hover {
  background: var(--bare-sidebar-hover);
  text-decoration: none;
}

.menu a[aria-current="page"] {
  background: var(--bare-sidebar-current);
  font-weight: bold;
}

/* Icône Lucide de l'entrée (static/vendor/lucide-navigation.svg) : grise,
   à la couleur d'accent sur l'entrée courante. */
.menu a > .icone {
  flex: none;
  width: 1.15em;
  height: 1.15em;
  margin: 0;
  color: var(--bare-muted);
}
.menu a[aria-current="page"] > .icone { color: var(--bare-accent); }
.menu li.stabilo a > .icone { color: inherit; }

/* Marque « ⚠ » : ce qui attend une action (services.nav_todo). La même marque
   suit le chemin — entrée de menu, onglet, puis l'élément de la page. Ambre
   d'avertissement ; le détail est au survol (title) et en .sr-only. */
.a-faire {
  color: var(--bare-warning);
  font-weight: bold;
  white-space: nowrap;
}
/* Pendant de ⚠ : « ✓ » d'un état que la plateforme constate satisfait
   (obligations continues du tableau de bord). */
.fait {
  color: var(--bare-ok);
  font-weight: bold;
}
/* Icône Lucide d'une obligation (obligations_seed.ICONES, planche
   static/vendor/lucide-obligations.svg) : trait à la couleur du texte, à la
   hauteur de la ligne, devant le titre. */
.icone {
  width: 1em;
  height: 1em;
  margin-right: .4em;
  vertical-align: -.125em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Clôtures : la coche Lucide d'un mois rapproché, seule et centrée dans sa
   case, à la couleur du texte (pas de vert). */
td > .coche, td > a > .coche { margin-right: 0; }
/* Case vide (relevé à importer, mois en cours) : rien à voir, mais toute la
   case mène à la vue du mois. */
a.case-vide { display: block; min-height: 1.5em; min-height: 1lh; }
/* Tableau de bord : l'icône est celle du GROUPE, sur son h2 ; chaque
   obligation est un paragraphe SANS icône, décalé de la largeur de l'icône du
   h2 et de son blanc (1em + .4em du h2, à 1.5em : 2.1em ici) — le titre
   s'aligne sur le texte du h2. Dans ce retrait, comme une puce sous l'icône du
   h2 : une coche quand c'est fait, rien sinon. Ce qui est fait passe au VERT —
   coche et état ; le titre (lien) ne change JAMAIS de couleur. */
.obligations {
  --puce-w: 1.5em;               /* l'icône du h2 (1em à 1.5em) */
  --puce-retrait: 2.1em;         /* … plus son blanc (.4em à 1.5em) */
}
.obligations > p {
  position: relative;
  padding-left: var(--puce-retrait);
}
.obligations > p.faite::before {
  content: "✓";                  /* repli : navigateur sans texte alternatif */
  content: "✓" / "";             /* décoratif : « Fait : » est en .sr-only */
  position: absolute;
  left: 0;
  width: var(--puce-w);
  text-align: center;
  font-weight: bold;
}
.obligations > p.faite,
.obligations > p.faite .etat { color: var(--bare-ok); }
/* L'état de l'obligation, trois mots à droite du titre. */
.obligations .etat { margin-left: .5em; white-space: nowrap; }

/* ---- Barre supérieure du contenu : le SEUL bouton qui déplie/replie le menu
   — visible menu ouvert OU replié (le logo est en tête de la barre latérale).
   Ce n'est pas un menu, et elle n'est PAS figée : elle défile avec la page (à
   la demande). Trois colonnes : la marge de gauche (le bouton), la COLONNE DE
   LECTURE (même largeur centrée que `.page > main`), la marge de droite. Pas
   de filet en bas. Elle ne prend PAS de place : sa marge basse négative fait
   remonter l'en-tête sur sa ligne, le h1 à côté du bouton. Au-dessus de
   l'en-tête (z-index) pour rester cliquable sur un écran étroit, mais
   transparente aux clics hors du bouton. */
.topbar {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(max-content, 1fr) minmax(0, var(--bare-content-w)) 1fr;
  align-items: center;
  min-height: calc(var(--bare-tete-pad) + var(--bare-topbar-h));
  padding-top: var(--bare-tete-pad);
  margin: 0 0 calc(-1 * (var(--bare-tete-pad) + var(--bare-topbar-h)));
  pointer-events: none;
}
.topbar > .sidebar-toggle {
  grid-column: 1;
  justify-self: start;
  margin-left: 1em;
  pointer-events: auto;
}

/* Barre d'avancement de la Conformité (tableau_bord.html) — en POINTILLÉ,
   une rangée de points (3px, un tous les 6px), gris clair pour le rail,
   couleur du texte pour la part faite — la même grille, les points se
   superposent exactement. Ni cadre, ni relief. Sous le h1, toute la largeur
   de la colonne (l'en-tête a la boîte de `main`). */
.avancement {
  --point: radial-gradient(circle, currentColor 1.5px, transparent 1.6px)
           0 50% / 6px 100% repeat-x;
  height: 3px;
  margin-bottom: var(--bare-gap-l);
  color: var(--bare-border);
  background: var(--point);
}
.avancement > span {
  display: block;
  width: var(--pct);
  height: 100%;
  color: var(--bare-text);
  background: var(--point);
}
/* Arrondi au point entier : pas de demi-point fait à la jonction. */
@supports (width: round(down, 10%, 6px)) {
  .avancement > span { width: round(down, var(--pct), 6px); }
}

/* Replier / fermer : l'icône seule, sans cadre ni fond ; un fond au survol,
   celui des entrées du menu. */
.sidebar-toggle,
.sidebar-close {
  line-height: 1;
  padding: 0.35em;
  background: none;
  border-color: transparent;
  color: var(--bare-muted);
}
.sidebar-toggle:hover,
.sidebar-close:hover {
  background: var(--bare-sidebar-hover);
  color: var(--bare-text);
}
.sidebar-toggle > .icone,
.sidebar-close > .icone {
  width: 1.2em;
  height: 1.2em;
  margin: 0;
  vertical-align: middle;
}

/* Voile du tiroir : inerte par défaut, armé à la seule ouverture mobile. */
.sidebar-backdrop {
  display: none;
}

/* Sans JS, la barre ne se replie pas : le bouton du menu n'aurait rien à faire,
   on ne l'affiche pas (l'attribut n'est posé que par le script). */
html:not([data-sidebar]) .sidebar-toggle {
  display: none;
}

@media (max-width: 56em) {
  /* La barre n'a plus de colonne : le contenu prend toute la largeur. */
  body {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    --bare-sidebar-gutter: 0px;
  }

  .page {
    grid-column: 1;
  }

  /* Sans JS : la barre est un simple bloc en tête, au-dessus du contenu. */
  body > nav.sidebar {
    grid-column: 1;
    grid-row: 1;
    position: static;
    align-self: stretch;
    height: auto;
    overflow: visible;
    border-right: none;
    border-bottom: 1px solid var(--bare-border);
  }

  /* Avec JS : tiroir hors écran, déployé par le bouton de la barre du haut. */
  html[data-sidebar] body > nav.sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(18em, 85vw);
    height: auto;
    overflow-y: auto;
    z-index: 300;
    border-right: 1px solid var(--bare-border);
    border-bottom: none;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.2s ease, visibility 0.2s;
  }

  html[data-sidebar="open"] body > nav.sidebar {
    transform: none;
    visibility: visible;
    box-shadow: 0 0 1em rgba(0, 0, 0, 0.25);
  }

  /* Le ✕ n'a de sens qu'en tiroir, donc seulement quand le script a posé
     l'état (sinon la barre est un bloc statique, sans rien à fermer). */
  html[data-sidebar] .sidebar-close {
    display: inline-block;
  }

  html[data-sidebar="open"] .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 250;
    background: rgba(0, 0, 0, 0.35);
  }
}

/* ============================================
   12. MEDIA
   ============================================ */

img, video, svg, canvas {
  max-width: 100%;
  height: auto;
}

figure {
  margin: var(--bare-gap) 0;
}

figcaption {
  font-size: 0.875em;
  color: var(--bare-muted);
  margin-top: var(--bare-gap-s);
}

/* ============================================
   13. DETAILS & DIALOG
   ============================================ */

details {
  margin: var(--bare-gap-l) 0;
  border: 1px solid var(--bare-border);
  border-radius: 4px;
  padding: var(--bare-gap-s) var(--bare-gap);
}

summary {
  cursor: pointer;
  font-weight: bold;
}

details[open] summary {
  margin-bottom: var(--bare-gap-l);
}

dialog {
  border: 1px solid var(--bare-border);
  border-radius: 4px;
  padding: var(--bare-gap-l);
  max-width: 40em;
}

dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

/* Fenêtre qui porte un formulaire (déclarer une réalisation) : largeur fixe,
   sinon le popover se rétrécit à son contenu et les champs s'écrasent. */
dialog.fenetre-formulaire {
  width: min(40em, calc(100vw - 2em));
  max-height: calc(100vh - 2em);
  overflow-y: auto;
}

dialog > :first-child { margin-top: 0; }

/* Fenêtre `popover` (choix du budget) — sans JS. */
dialog[popover] ul { list-style: none; padding: 0; }
dialog[popover] li { margin: var(--bare-gap-s) 0; }

/* ============================================
   14. FOCUS — ACCESSIBILITY
   ============================================ */

:focus-visible {
  outline: 2px solid var(--bare-focus);
}

/* ============================================
   15. PRINT
   ============================================ */

@media print {
  body {
    display: block;
    max-width: none;
    padding: 0;
    font-size: 12pt;
    color: #000;
    background: #fff;
  }

  /* Le gabarit à barre latérale n'a pas cours sur papier : on revient au flux. */
  .page {
    display: block;
    min-height: 0;
  }

  a {
    color: #000;
    text-decoration: underline;
  }

  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
    color: #555;
  }

  img, video, svg {
    max-width: 100% !important;
  }

  nav, .topbar, .sidebar-backdrop, .no-print {
    display: none;
  }

  /* Sans la barre supérieure, l'en-tête ne lui garde ni place ni retrait. */
  .page > .topbar ~ header,
  html[data-sidebar] .page > .topbar ~ header {
    text-indent: 0;
    padding-top: 0;
    min-height: 0;
  }
}

/* ============================================
   16. SPACING UTILITIES
   ============================================ */

/* Margin — all sides */
.m-0  { margin: 0; }
.m-s  { margin: var(--bare-gap-s); }
.m    { margin: var(--bare-gap); }
.m-l  { margin: var(--bare-gap-l); }

/* Un titre de tableau (ex. « Répartition » de la ventilation) collé à sa table :
   non gras et rapproché (la table porte margin-top: gap, trop loin sinon). */
p.titre-tableau { margin-bottom: 0; font-weight: normal; }
p.titre-tableau + table { margin-top: var(--bare-gap-s); }

/* Margin — top */
.mt-0 { margin-top: 0; }
.mt-s { margin-top: var(--bare-gap-s); }
.mt   { margin-top: var(--bare-gap); }
.mt-l { margin-top: var(--bare-gap-l); }

/* Margin — bottom */
.mb-0 { margin-bottom: 0; }
.mb-s { margin-bottom: var(--bare-gap-s); }
.mb   { margin-bottom: var(--bare-gap); }
.mb-l { margin-bottom: var(--bare-gap-l); }

/* Margin — left (start) */
.ms-0 { margin-left: 0; }
.ms-s { margin-left: var(--bare-gap-s); }
.ms   { margin-left: var(--bare-gap); }
.ms-l { margin-left: var(--bare-gap-l); }

/* Margin — right (end) */
.me-0 { margin-right: 0; }
.me-s { margin-right: var(--bare-gap-s); }
.me   { margin-right: var(--bare-gap); }
.me-l { margin-right: var(--bare-gap-l); }

/* Margin — horizontal */
.mx-0    { margin-left: 0; margin-right: 0; }
.mx-s    { margin-left: var(--bare-gap-s); margin-right: var(--bare-gap-s); }
.mx      { margin-left: var(--bare-gap); margin-right: var(--bare-gap); }
.mx-l    { margin-left: var(--bare-gap-l); margin-right: var(--bare-gap-l); }
.mx-auto { margin-left: auto; margin-right: auto; }

/* Margin — vertical */
.my-0 { margin-top: 0; margin-bottom: 0; }
.my-s { margin-top: var(--bare-gap-s); margin-bottom: var(--bare-gap-s); }
.my   { margin-top: var(--bare-gap); margin-bottom: var(--bare-gap); }
.my-l { margin-top: var(--bare-gap-l); margin-bottom: var(--bare-gap-l); }

/* Padding — all sides */
.p-0  { padding: 0; }
.p-s  { padding: var(--bare-gap-s); }
.p    { padding: var(--bare-gap); }
.p-l  { padding: var(--bare-gap-l); }

/* Padding — top */
.pt-0 { padding-top: 0; }
.pt-s { padding-top: var(--bare-gap-s); }
.pt   { padding-top: var(--bare-gap); }
.pt-l { padding-top: var(--bare-gap-l); }

/* Padding — bottom */
.pb-0 { padding-bottom: 0; }
.pb-s { padding-bottom: var(--bare-gap-s); }
.pb   { padding-bottom: var(--bare-gap); }
.pb-l { padding-bottom: var(--bare-gap-l); }

/* Padding — left (start) */
.ps-0 { padding-left: 0; }
.ps-s { padding-left: var(--bare-gap-s); }
.ps   { padding-left: var(--bare-gap); }
.ps-l { padding-left: var(--bare-gap-l); }

/* Padding — right (end) */
.pe-0 { padding-right: 0; }
.pe-s { padding-right: var(--bare-gap-s); }
.pe   { padding-right: var(--bare-gap); }
.pe-l { padding-right: var(--bare-gap-l); }

/* Padding — horizontal */
.px-0 { padding-left: 0; padding-right: 0; }
.px-s { padding-left: var(--bare-gap-s); padding-right: var(--bare-gap-s); }
.px   { padding-left: var(--bare-gap); padding-right: var(--bare-gap); }
.px-l { padding-left: var(--bare-gap-l); padding-right: var(--bare-gap-l); }

/* Padding — vertical */
.py-0 { padding-top: 0; padding-bottom: 0; }
.py-s { padding-top: var(--bare-gap-s); padding-bottom: var(--bare-gap-s); }
.py   { padding-top: var(--bare-gap); padding-bottom: var(--bare-gap); }
.py-l { padding-top: var(--bare-gap-l); padding-bottom: var(--bare-gap-l); }

/* Text & display helpers — replace the inline styles in the templates.
   `.num` (right-aligned figures) is by far the most used (numeric table cells). */
.num         { text-align: right; }
/* Un champ numérique DANS une cellule `.num` aligne son chiffre à droite comme
   la colonne (montant de part, poste de budget) — sinon le texte de l'input
   resterait calé à gauche. */
.num > input[type="number"] { text-align: right; }
.text-center { text-align: center; }
.block       { display: block; }
.inline      { display: inline; }
.full        { width: 100%; }
.scroll-x    { overflow-x: auto; }
/* Sort de la colonne de lecture (60em) pour occuper toute la largeur laissée par
   la barre latérale — la grille des écarts sur un cycle entier (12 mois + le
   total) ne tient pas dans une colonne de lettre. Toute la largeur, des DEUX
   côtés (à la demande) : la colonne de lecture étant CENTRÉE, elle laisse de
   chaque côté (100cqw − sa largeur) / 2 ; on recule d'autant à gauche et on
   file jusqu'au bord droit, moins 1em de gouttière de part et d'autre.
   `cqw` = la largeur RÉELLE de `.page` (conteneur de requête) — `100vw`
   comptait la barre de défilement verticale et ouvrait un défilement
   horizontal. `min()` reflète la largeur réelle de la colonne (bornée à 60em,
   ou moins sur écran étroit). */
.pleine-largeur {
  width: calc(100cqw - 2em);
  margin-left: calc((min(100cqw, var(--bare-content-w)) - 100cqw) / 2);
}
.nowrap      { white-space: nowrap; }
/* Coupe un mot insécable (jeton, code, référence collée) plutôt que de laisser
   la cellule pousser le tableau au-delà de sa largeur — sinon un `.scroll-x`
   affiche un défilement horizontal parasite de quelques pixels. */
.break       { overflow-wrap: anywhere; word-break: break-word; }
.big         { font-size: 1.4em; }
.muted       { color: var(--bare-muted); }
/* Ligne-résumé sous le titre d'une page d'obligation : « Tous les 5 ans ·
   prochaine échéance le … · en retard de 3 mois ». Un simple paragraphe, un
   cran au-dessus du corps — pas une pastille : le retard s'y dit en toutes
   lettres, la couleur ne fait que le souligner. */
.resume         { font-size: 1.05em; margin: 0 0 var(--bare-gap); }
/* Le retard dit en toutes lettres, souligné par la couleur — sans changer la
   taille du texte (ligne-résumé, colonne État du tableau de bord). */
.retard         { color: var(--bare-danger); font-weight: bold; }
/* Tableau de bord : la date sous l'État se déplie en sa narration (comment
   elle est obtenue) — au toucher et au clavier, pas seulement au survol.
   Discret : ni cadre ni gras, la ligne se lit comme une date. */
details.narration          { border: 0; padding: 0; }
details.narration summary  { font-weight: normal; }
details.narration[open] summary { margin-bottom: var(--bare-gap-s); }
/* Budget : l'indicateur de faillite est une simple ligne en gras (pas un
   message encadré) ; le clic déplie le calcul. */
details.faillite                { border: 0; padding: 0; margin: 0 0 var(--bare-gap); }
details.faillite[open] summary  { margin-bottom: var(--bare-gap-s); }
/* Page d'une obligation : la description en français courant, un cran
   au-dessus du corps ; les étapes « Concrètement » aérées ; un modèle de
   document se lit comme une lettre (retours à la ligne conservés, police du
   corps — pas du code). */
.lede           { font-size: 1.1em; margin: 0 0 var(--bare-gap-l); }
/* Registre de la copropriété : une liste de documents, un par ligne. Une
   pièce attendue et fournie porte le ✓ du tableau de bord, en absolu dans la
   marge : fournie ou non, chaque ligne s'aligne sur le bord gauche du h1. */
ul.documents     { list-style: none; padding-left: 0; }
ul.documents li  { position: relative; margin: 0 0 var(--bare-gap-s); }
ul.documents .coche { position: absolute; right: 100%; top: 0; padding-right: .5em; }
/* Trésorerie : une consigne par ligne, chacune précédée de son ⚠. */
ul.consignes     { list-style: none; padding-left: 0; }
ul.consignes li  { margin: 0 0 var(--bare-gap-s); }
/* Cotisations : une par ligne — titre (et pastille « active ») à gauche,
   appelé puis reste à percevoir tout à droite ; pages précédente / suivante. */
ul.cotisations, ul.budgets    { list-style: none; padding-left: 0; }
ul.cotisations li, ul.budgets li { display: flex; justify-content: space-between;
                    align-items: flex-start; gap: var(--bare-gap);
                    margin: 0 0 var(--bare-gap); }
ul.cotisations .badge, ul.budgets .badge { margin-top: .25em; }
nav.pagination    { position: static; border: 0; background: none;
                    margin: var(--bare-gap-l) 0 0; padding: 0;
                    align-items: baseline; }
/* Utilisateurs : chaque droit = la case, son nom, puis ce qu'il permet en retrait. */
.droits label, .droits p > span { display: inline; font-weight: bold; margin: 0; }
.droits small.block { margin-left: 1.75em; }
.lien-invitation small { overflow-wrap: anywhere; }
ul.documents button.small { margin-left: .5em; }
/* Visionneuse du registre : le PDF dans le cadre du site, sur presque toute la hauteur. */
iframe.visionneuse { display: block; width: 100%; height: 80vh; border: 1px solid var(--bare-border); }
.etapes li      { margin-bottom: var(--bare-gap-s); }
pre.modele      { white-space: pre-wrap; font-family: inherit; font-size: 0.95em;
                  padding: var(--bare-gap); border: 1px solid var(--bare-border);
                  border-radius: 4px; background: var(--bare-card-header-bg); }
.card.warning   { background: var(--bare-warning-bg); border-color: var(--bare-warning);
                  color: var(--bare-warning); }
.card.warning small, .card.warning .muted { color: inherit; opacity: 0.85; }
/* Lu par les lecteurs d'écran, invisible à l'œil : le texte d'une pastille
   « brève » (réduite à son ✓ / ✕) reste ainsi énoncé, jamais perdu. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Fenêtre de conversation de l'assistant : elle DÉFILE (bornée en hauteur) pour
   qu'on voie toujours la dernière réponse ET le champ juste dessous (JS place le
   scroll en bas au chargement). La réponse de l'IA coule SANS cadre ; la phrase de
   l'utilisateur est mise en RETRAIT (padding gauche/droite) pour la distinguer. */
.chat {
  max-height: 60vh;
  overflow-y: auto;
  border: 1px solid var(--bare-border);
  border-radius: 4px;
  padding: var(--bare-gap);
  margin: var(--bare-gap) 0;
}
.chat > :first-child { margin-top: 0; }
.chat > :last-child  { margin-bottom: 0; }
/* La réponse de l'IA est décalée à GAUCHE (padding à droite) ; la question de
   l'utilisateur est décalée à DROITE et alignée à droite — lecture « chat ». */
.chat-ai { padding-right: 15%; }
.chat-ai > :first-child { margin-top: 0; }
.chat-ai > :last-child  { margin-bottom: 0; }
/* La question de l'utilisateur : une bulle bleue calée à DROITE (largeur au
   contenu, jusqu'à 85 %), même bleu « info » que .badge.special / .alert.special
   — recoloré par thème plus bas. */
.chat-user {
  margin-left: auto;
  width: fit-content;
  max-width: 85%;
  padding: 0.5em 0.75em;
  border-radius: 12px;
  background: #dbe8f4;
  color: #1a4890;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chat-user { background: #1a2e44; color: #8ec0ff; }
}
:root[data-theme="dark"] .chat-user { background: #1a2e44; color: #8ec0ff; }

/* Indicateur d'attente de l'assistant IA (le SEUL de l'app) : un anneau qui
   tourne, couleurs héritées du thème (piste = bordure, arc = muted). Respecte
   prefers-reduced-motion — manifeste « calme » : pas d'animation imposée. */
.spinner {
  display: inline-block;
  width: 1em; height: 1em;
  vertical-align: -0.15em;
  border: 0.15em solid var(--bare-border);
  border-top-color: var(--bare-muted);
  border-radius: 50%;
  animation: bare-spin 0.8s linear infinite;
}
@keyframes bare-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }

/* Page en CONSULTATION SEULEMENT (le compte n'a pas le droit d'écriture de
   cette page — cf. conformite/droits.py). On masque les formulaires qui
   MODIFIENT (method="post") : offrir un bouton menant à un 403 serait
   malhonnête. Les formulaires de filtre/recherche (method="get") restent,
   la lecture étant libre. Ceci n'est QU'UN MASQUE : la barrière est le
   middleware côté serveur, jamais le CSS. Exception : `.libre-service`, un
   formulaire qui poste vers une route LIBRE (le copropriétaire qui répond au
   conseil dans son fil, celui qui signe un procès-verbal). */
main.lecture-seule form[method="post"]:not(.libre-service) { display: none; }

/* Signature dessinée d'un procès-verbal (signature_pad, `reunion.html`) : le
   cadre où l'on signe et la signature posée. Fond BLANC quel que soit le
   thème — l'encre est noire, et l'image va telle quelle au PDF. */
canvas.signature {
  display: block;
  width: 100%;
  max-width: 30em;
  height: 10em;
  border: 1px solid var(--bare-border);
  border-radius: 4px;
  background: #fff;
  touch-action: none;
}
canvas.signature[aria-invalid="true"] { border-color: var(--bare-danger); }
img.signature-image {
  max-width: 15em;
  height: auto;
  background: #fff;
  border-radius: 4px;
}

/* « Trouver un moment » (`moment.html`, `static/moment.js`) : la grille d'une
   semaine, colonnes = jours, rangées = créneaux de 30 min. Chaque case est un
   <label> qui porte une case à cocher (masquée) : sans JS, un clic coche ; avec
   JS, on glisse dans une colonne. Le fond vert dit combien d'invités sont
   libres (`n-1` à `n-4`) ; le bleu, MES disponibilités. */
.moment-grille {
  --jours: 7;
  display: grid;
  grid-template-columns: 3.5em repeat(var(--jours), minmax(0, 1fr));
  grid-auto-rows: 1.5em;
  border: 1px solid var(--bare-border);
  border-radius: 4px;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
  font-size: 0.85em;
}
.moment-grille .entete {
  grid-row: span 2;
  text-align: center;
  font-weight: bold;
  line-height: 1.3;
  padding-top: 0.2em;
  border-bottom: 1px solid var(--bare-border);
  border-left: 1px solid var(--bare-border);
}
.moment-grille .coin { grid-row: span 2; border-bottom: 1px solid var(--bare-border); }
.moment-grille .heure {
  text-align: right;
  padding-right: 0.4em;
  color: var(--bare-muted);
  font-size: 0.85em;
  border-top: 1px solid var(--bare-border);
}
.moment-grille .heure.demi { border-top-style: dashed; color: transparent; }
.moment-grille .case {
  position: relative;
  margin: 0;
  border-left: 1px solid var(--bare-border);
  border-top: 1px solid var(--bare-border);
  cursor: pointer;
  text-align: right;
  padding-right: 0.2em;
  color: var(--bare-muted);
  font-size: 0.8em;
  line-height: 1.6;
}
.moment-grille .case.demi { border-top-style: dashed; }
.moment-grille .case input { position: absolute; opacity: 0; pointer-events: none; }
.moment-grille .case.n-1 { background: color-mix(in srgb, var(--bare-ok) 12%, var(--bare-bg)); }
.moment-grille .case.n-2 { background: color-mix(in srgb, var(--bare-ok) 25%, var(--bare-bg)); }
.moment-grille .case.n-3 { background: color-mix(in srgb, var(--bare-ok) 40%, var(--bare-bg)); }
.moment-grille .case.n-4 { background: color-mix(in srgb, var(--bare-ok) 60%, var(--bare-bg)); color: var(--bare-text); }
.moment-grille .case:has(input:checked) {
  background: color-mix(in srgb, var(--bare-link) 35%, var(--bare-bg));
  box-shadow: inset 0.3em 0 0 var(--bare-link);
  color: var(--bare-text);
}
.moment-grille .case:has(input:focus-visible) { outline: 2px solid var(--bare-focus); outline-offset: -2px; }
.moment-grille .case.apercu-ajout { background: color-mix(in srgb, var(--bare-link) 18%, var(--bare-bg)); }
.moment-grille .case.apercu-retrait { background: var(--bare-danger-bg); box-shadow: none; }
.moment-grille.lecture .case { cursor: default; }

/* select2 (président·e / secrétaire d'un procès-verbal, `reunion_form.html`) :
   la boîte prend l'allure des champs du site — mêmes bordure, marge, police
   et couleurs du thème (select2 pose du blanc en dur, illisible en sombre).
   `body` en tête : select2.min.css est chargée APRÈS cette feuille, et
   gagnerait à spécificité égale (sa hauteur fixe de 28 px rognait le texte). */
body .select2-container--default .select2-selection--single {
  height: auto;
  padding: var(--bare-gap-s);
  font: inherit;
  color: var(--bare-text);
  background: var(--bare-bg);
  border: 1px solid var(--bare-border);
  border-radius: 4px;
}
body .select2-container--default .select2-selection--single .select2-selection__rendered {
  padding-left: 0;
  line-height: inherit;
  color: var(--bare-text);
}
body .select2-container--default .select2-selection--single .select2-selection__arrow {
  height: 100%;
}
body .select2-container--default.select2-container--focus .select2-selection--single,
body .select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--bare-focus);
}
body .select2-dropdown {
  color: var(--bare-text);
  background: var(--bare-bg);
  border-color: var(--bare-border);
}
body .select2-container--default .select2-search--dropdown .select2-search__field {
  margin: 0;
  color: var(--bare-text);
  background: var(--bare-bg);
  border-color: var(--bare-border);
}
body .select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
  color: var(--bare-mark-text);
  background: var(--bare-mark-bg);
}
body .select2-container--default .select2-results__option--selected {
  background: var(--bare-card-header-bg);
}
