/* ============================================================
   Loi lisible — charte « blanc et rouge »
   Sobre, monochrome, une seule couleur d'accent.
   Tout passe par des tokens :root.
   ============================================================ */

:root {
  /* Fonds */
  --bg:          #FFFFFF;
  --surface:     #FAF9F8;
  --surface-2:   #F2F0EE;
  --card:        #FFFFFF;

  /* Encre */
  --ink:         #1A1715;
  --ink-soft:    #55504B;
  --ink-faint:   #6B655F;   /* 5,75:1 sur blanc — mesuré au banc */

  /* Filet & accent */
  --line:        #E2DEDA;
  --line-fort:   #C9C3BC;
  --accent:      #C1121F;
  --accent-fonce:#8E0D17;
  --accent-pale: #FBEDEE;
  --sur-accent:  #FFFFFF;   /* 6,22:1 sur l'accent clair */

  /* Surlignage des mots-cles cherches. Un ton plus soutenu que
     --accent-pale, qui sert deja au survol d'un renvoi : deux fonctions
     differentes ne portent pas le meme fond. */
  --surligne:    #FADCDE;   /* encre a 13,89:1 dessus — mesure */
  --surligne-trait: var(--accent);   /* 6,22:1 sur le fond de page */

  /* DEUX ENCRES POUR LES REPERES, et une seule raison de les separer.
     Cinq styles de trait dans la meme encre finissaient brouillons. Les
     reperes se rangent donc en deux familles de sens, et chacune a son
     encre :
       --repere-regle : ce que la regle DIT — obligation, faculte, negation
       --repere-borne : QUAND, COMBIEN, SOUS QUELLE CONDITION — condition,
                        delai, montant
     Trois formes a distinguer d'un cote, deux de l'autre, au lieu de cinq.
     La couleur ne porte JAMAIS seule (WCAG 1.4.1) : chaque repere garde son
     style de trait, la couleur ne fait que regrouper.
     Contrastes mesures sur le fond de page : 9,00:1 pour le rouge, 7,93:1
     pour le violet, tres au-dessus des 3:1 demandes (WCAG 1.4.11). */
  --repere-regle: var(--accent-fonce);
  --repere-borne: #6D28A8;   /* 7,93:1 en clair, 7,74:1 en sepia — mesure */

  /* Le module pixel de la charte : le pixel garde toujours la même
     taille à l'écran, c'est le canevas qui change. Une icône = 12 unités. */
  --px:          2px;

  /* OU S'ARRETE UN SAUT D'ANCRE. L'en-tete colle a 84 px du haut, la bande
     d'etat s'intercale dessous quand la page de garde est sortie de l'ecran :
     une ancre qui ne compte que l'en-tete arrive DERRIERE la bande. Releve a
     l'ecran le 6 septembre 2026, sur le sommaire comme sur les appels de note.
     `--rappel-h` est posee par `poserHauteurRappel()` (app.js) et vaut 0 tant
     que la bande n'est pas affichee. Une seule valeur a tenir, comme le
     rappelle `allerA()`, qui lit `scroll-margin-top` au lieu de refaire le
     calcul. */
  --ancre-haut:  calc(90px + var(--rappel-h, 0px));

  /* Formes — multiples du module, sinon le rayon fabrique un escalier
     d'anti-aliasing qui trahit la grille. */
  --radius:      8px;
  --radius-sm:   4px;
  /* LA PILULE NE SERT PLUS QU'A LA JAUGE D'ATTENTE. Depuis le 6 septembre
     2026, les boutons, les pastilles et ce qui flotte prennent `--radius-sm`,
     le meme rayon que les champs de saisie : un bouton et un champ posés l'un
     a cote de l'autre se lisent alors comme une paire. Une barre de progres,
     elle, reste une pilule : c'est la forme qui dit qu'elle se remplit. */
  --r-pill:      999px;

  /* Ombres (discrètes, charte sobre) */
  --shadow:      0 1px 3px rgba(26,23,21,.08), 0 8px 24px rgba(26,23,21,.06);
  --shadow-soft: 0 1px 2px rgba(26,23,21,.06);
  /* L'ombre qui dit qu'un corps de panneau continue sous le bord. Même
     convention que les deux au-dessus : une valeur ici, redéfinie dans le
     thème sombre. */
  --ombre-defilement: rgba(26, 23, 21, .30);
  /* LE FOND DERRIERE UNE BOITE MODALE, ecrit une fois. Il l'etait a deux
     endroits, avec deux valeurs : `.panneau::backdrop` en encre chaude a 38 %,
     et `.confirmation::backdrop` de mes-textes.css en BLEUTE a 45 %. Deux
     boites modales de la meme app n'assombrissent pas la page differemment. */
  --fond-modal: rgba(26, 23, 21, .38);

  /* Typo */
  --font-ui:     system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-lecture:Georgia, "Iowan Old Style", "Times New Roman", serif;
  --ease:        cubic-bezier(.2,.7,.3,1);

  /* ---------- Panneaux ----------
     Un panneau est UN objet : ses mesures vivent ici, pas recopiées dans
     chaque famille. Convention : faire évoluer la charte, c'est
     toucher aux tokens, rien d'autre. */
  --panneau-l:        680px;   /* largeur courante */
  --panneau-l-large:  780px;   /* réglages : une grille de curseurs */
  --panneau-l-ancre:  262px;   /* ancré sous son bouton — « Réglages de lecture », mesuré */
  --panneau-marge:    20px;    /* écart au bord de l'écran */
  --panneau-marge-haut: 48px;  /* dégagement au-dessus : un panneau ancré en bas
                                  ne touche jamais le bord supérieur, sinon il se
                                  lit comme une prise de contrôle de l'écran et
                                  plus comme un panneau */
  --panneau-retrait:  18px;    /* rembourrage intérieur */
  --panneau-ecart:    12px;    /* entre l'en-tête, le corps et les actions */
  --panneau-fondu:    180ms;

  /* Ordre de superposition, écrit une fois et lisible d'un coup d'œil.
     Un <dialog> modal passe en top layer et ignore ces valeurs : elles ne
     servent qu'aux panneaux NON modaux et à ce qui flotte autour. */
  --z-entete:     20;
  --z-flottant:   25;    /* menu ancré, retour-haut */
  --z-barre:      26;    /* barre de sélection */
  --z-panneau:    45;    /* panneau non modal */
  --z-integrite:  100;
  --z-toast:      9999;

  /* ÉCHANTILLONS DES TROIS THÈMES.
     Seules couleurs écrites en dur de la feuille, et la seule exception
     légitime à la règle des tokens : une pastille qui montre le thème SÉPIA
     ne peut pas prendre la couleur du thème EN COURS, sinon les trois
     pastilles seraient identiques et le bouton ne montrerait rien. Elles
     recopient les valeurs des blocs de thème ci-dessous. À changer ensemble
     si une palette bouge. */
     LE SÉPIA MONTRE SON SURFACE-2, PAS SON FOND. Corrigé le 6 septembre 2026 :
     la pastille prenait `--bg` du thème sépia, #FBF6EC, à un cheveu du blanc
     #FFFFFF du thème clair. Sur une pastille de 16 px, les deux étaient
     indiscernables et le bouton n'annonçait visuellement ni l'état en cours ni
     celui qui vient. Elle prend maintenant #EDE5D6, qui est le `--surface-2`
     de ce même thème : une couleur qu'il porte vraiment, et celle qui le
     caractérise le mieux à cette taille. Rien n'est inventé, on choisit
     seulement la plus parlante de sa palette. */
  --ech-clair:         #FFFFFF;
  --ech-clair-encre:   #1A1715;
  --ech-sepia:         #EDE5D6;   /* --surface-2 du sépia, voir ci-dessus */
  --ech-sepia-encre:   #2B2419;
  --ech-sombre:        #161413;
  --ech-sombre-encre:  #F2EEEA;

  /* Réglages de lecture (pilotés par l'interface) */
  --taille:      1.125rem;
  --interligne:  1.7;
  --colonne:     68ch;
  --interlettre: 0em;
}

/* Thème sépia — moins de contraste, plus doux en lecture longue */
:root[data-theme="sepia"] {
  --bg: #FBF6EC; --surface: #F5EFE3; --surface-2: #EDE5D6; --card: #FBF6EC;
  --ink: #2B2419; --ink-soft: #5E5443; --ink-faint: #6E6558;   /* 5,32:1 — mesuré */
  --line: #E0D6C2; --line-fort: #C9BCA2; --accent-pale: #F6E7E3;
  --surligne: #F2DED6;   /* encre a 11,83:1 dessus — mesure */
}

/* Thème sombre */
:root[data-theme="sombre"] {
  --bg: #161413; --surface: #1F1C1A; --surface-2: #2A2624; --card: #1F1C1A;
  --ink: #F2EEEA; --ink-soft: #BDB5AE; --ink-faint: #8E8781;
  --line: #332E2B; --line-fort: #4A433F;
  --accent: #FF6B72; --accent-fonce: #FF9A9E; --accent-pale: #2E1B1D;
  --surligne: #4A2226;   /* encre a 11,75:1 dessus, trait a 6,64:1 — mesure */
  --repere-borne: #C79BE8;   /* 7,49:1 sur le fond sombre — mesure */
  --sur-accent: #161413;   /* 6,64:1 — le blanc n'y donnait que 2,76:1 */
  --shadow: 0 1px 3px rgba(0,0,0,.5), 0 8px 24px rgba(0,0,0,.4);
  --shadow-soft: 0 1px 2px rgba(0,0,0,.4);
  --ombre-defilement: rgba(0, 0, 0, .65);
  --fond-modal: rgba(0, 0, 0, .58);
}

/* OpenDyslexic, licence SIL Open Font License 1.1.
   Les fichiers vivent dans identity/polices/, servis par le site lui-meme :
   aucun CDN, c'est une regle du projet. S'ils sont absents, la pile de repli
   prend le relais et app.js masque le bouton plutot que d'offrir un
   reglage qui ne changerait rien. */
@font-face {
  font-family: 'OpenDyslexic';
  src: url('identity/polices/OpenDyslexic-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'OpenDyslexic';
  src: url('identity/polices/OpenDyslexic-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'OpenDyslexic';
  src: url('identity/polices/OpenDyslexic-Italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  font-family: 'OpenDyslexic';
  src: url('identity/polices/OpenDyslexic-BoldItalic.woff2') format('woff2');
  font-weight: 700; font-style: italic; font-display: swap;
}

/* Police de lecture au choix.
   « Lisible » suit les recommandations de la British Dyslexia Association :
   une sans-serif a lettres larges et bien differenciees. Le gain de lecture
   mesure dans la litterature vient surtout de l'espacement, d'ou le curseur
   qui l'accompagne ; OpenDyslexic repond a une preference reelle. */
:root[data-police="sans"]    { --font-lecture: var(--font-ui); }
:root[data-police="serif"]   { --font-lecture: Georgia, "Iowan Old Style", "Times New Roman", serif; }
:root[data-police="mono"]    { --font-lecture: ui-monospace, "SF Mono", Menlo, Consolas, monospace; }
:root[data-police="lisible"] { --font-lecture: Verdana, Tahoma, "Trebuchet MS", system-ui, sans-serif; }
:root[data-police="dys"]     { --font-lecture: 'OpenDyslexic', Verdana, Tahoma, system-ui, sans-serif; }

* { box-sizing: border-box; }

/* `hidden` doit gagner sur toute règle d'affichage. Sans ce !important,
   .entete__actions{display:flex} et .lecteur{display:grid} laissaient voir
   la barre de lecture et le lecteur sur l'écran d'accueil. Vu à l'écran. */
[hidden] { display: none !important; }

html { color-scheme: light; }
:root[data-theme="sombre"] { color-scheme: dark; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
}

/* ---------- Accessibilité : socle ---------- */

.saut-nav {
  position: absolute; left: -9999px; top: 0;
  background: var(--accent); color: var(--sur-accent); padding: 12px 18px;
  border-radius: 0 0 var(--radius) 0; z-index: 100; font-weight: 700;
}
.saut-nav:focus { left: 0; }

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Un conteneur qui reçoit le focus par programme (tabindex="-1") sert à
   replacer la lecture apres une mise en forme, pas a recevoir la tabulation.
   L'anneau y dessinerait un cadre de la hauteur du document entier : mesure
   a 141 652 px sur la proposition 3106. Le critere RGAA « focus visible »
   porte sur les elements atteignables au clavier, pas sur ces cibles-la. */
[tabindex="-1"]:focus-visible { outline: none; }

/* ---------- Selection ---------- */

/* Le rouge de la charte sur le texte selectionne. L'encre posee dessus
   passe par --sur-accent, pas par du blanc en dur : en theme sombre
   l'accent devient #FF6B72, ou le blanc ne donne que 2,76:1. */
::selection {
  background: var(--accent);
  color: var(--sur-accent);
}

.visuellement-cache {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------- En-tête ---------- */

.entete {
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  position: sticky; top: 0; z-index: 20;
}
/* JAMAIS deux lignes. Le retour a la ligne est interdit par construction :
   quand la place manque, ce n'est pas la ligne qui se dedouble, c'est le
   contenu qui se replie (app.js mesure le debordement reel et pose
   `data-entete-menu` puis `data-entete-baseline` sur <body>). */
.entete__interieur {
  max-width: 1180px; margin: 0 auto; padding: 14px 20px;
  display: flex; align-items: center; gap: 16px; flex-wrap: nowrap;
}
/* Aucun element de l'en-tete ne se laisse comprimer : un bouton retreci
   deborderait de son propre cadre sans que le conteneur, lui, deborde. La
   mesure du repli ne verrait rien venir. */
.entete__interieur > *, .entete__actions > *, .menu-lecture > * { flex: 0 0 auto; }

.marque {
  display: flex; align-items: baseline; gap: 9px; white-space: nowrap;
  font-weight: 800; font-size: 1.15rem; letter-spacing: -.01em;
  color: var(--ink); text-decoration: none;
}
.marque__sous { font-weight: 500; font-size: .85rem; color: var(--ink-faint); }
/* Second cran du repli : la baseline part quand le menu replie ne suffit pas
   a faire tenir la ligne. Le nom de l'outil, lui, ne part jamais. */
body[data-entete-baseline="cachee"] .marque__sous { display: none; }

/* TROISIEME CRAN : le nom de l'outil s'efface, le signe reste. Ce qui sert
   dans une en-tete de lecture, ce sont les commandes ; le nom de l'app, on
   le sait, on est dedans. Le nom accessible du lien porte toujours « Loi
   lisible, retour a l'accueil » : rien n'est perdu au lecteur d'ecran. */
body[data-entete-marque="signe"] .marque__nom { display: none; }

/* ---------- Bascule de theme, dans l'en-tete ----------
   UN bouton qui fait defiler les trois fonds. Mesure : trois boutons cote a
   cote prenaient 106 px, et a 390 px l'en-tete de lecture debordait de 23 px
   une fois ses deux crans de repli epuises. Celui-ci en prend 34.

   La pastille montre le theme EN COURS. Ici la couleur EST le contenu du
   bouton, pas le doublon d'une information ecrite ailleurs : WCAG 1.4.1 ne
   s'y oppose pas, et le nom accessible porte le mot. */

/* CIBLE TACTILE : 44 px de HAUT, 34 de LARGE. La phrase precedente disait
   « 44 px pleine, comme tout le reste », c'etait faux depuis que la largeur est
   passee a 34 pour tenir dans l'en-tete. Corrige le 6 septembre 2026.

   Les 34 px sont un choix de place, mesure : trois boutons de theme cote a cote
   prenaient 106 px et l'en-tete de lecture debordait de 23 px a 390 px une fois
   ses crans de repli epuises. Le passer a 44 coute 10 px de plus dans un en-tete
   qui n'a qu'un pixel de marge a 390 px (mesure le 6 septembre : place libre de
   1 px a 34, de -9 px a 44). La correction se joue donc avec le budget de
   l'en-tete, pas ici toute seule. Voir « L'en-tete ne passe jamais sur deux
   lignes ».

   Le banc de debordement ne voit pas cet ecart : son controle de cible tactile
   ne mesure que la hauteur. */
.theme-cle {
  width: 34px; min-height: 44px; margin-left: 2px;
  display: grid; place-items: center;
  /* FILET DE BOUTON, comme tous les autres. Il portait `--line`, presque
     invisible sur blanc, a cote d'un « Mes textes » qui porte 2 px d'encre :
     deux commandes voisines, l'une des plus discretes de la page, l'autre la
     plus appuyee de l'en-tete. Il prend `--line-fort`, le filet de `.btn` :
     c'est un bouton, il se lit comme les autres boutons. L'encre a 2 px reste
     reservee a « Mes textes », qui est l'entree vers la page personnelle. */
  border: 1px solid var(--line-fort); border-radius: var(--radius-sm);
  background: var(--card); cursor: pointer; padding: 0;
}
.theme-cle:hover { background: var(--surface-2); border-color: var(--line-fort); }

/* SUR LA GRILLE PIXEL, comme tout le reste de la charte. Deux valeurs
   suffisaient a l'en sortir : un arrondi de 4 px, soit deux unites rongees
   aux quatre coins, et un partage a 55 % qui tombait a 8,8 px sur une
   pastille de 16 et coupait donc AU MILIEU d'un pixel. Coins nets, partage
   a 50 %, soit 8 px pile. Ce n'est pas une icone : une .pix est monochrome
   et prend currentColor, elle ne peut pas montrer les couleurs d'un theme. */
.theme-cle__pastille {
  width: calc(8 * var(--px)); height: calc(8 * var(--px));
  border-radius: 0;
  border: 1px solid var(--line-fort);
  display: block;
}
/* Le demi-fond d'encre figure le texte du theme sur son fond : une pastille
   de fond seule ne distingue pas le clair du sepia sur un petit ecran.
   La coupe est nette, pas un fonde : deux arrets a la meme position. */
.theme-cle__pastille[data-ech="clair"]  { background: linear-gradient(180deg, var(--ech-clair) 50%, var(--ech-clair-encre) 50%); }
.theme-cle__pastille[data-ech="sepia"]  { background: linear-gradient(180deg, var(--ech-sepia) 50%, var(--ech-sepia-encre) 50%); }
.theme-cle__pastille[data-ech="sombre"] { background: linear-gradient(180deg, var(--ech-sombre) 50%, var(--ech-sombre-encre) 50%); }

/* PAS DE REPLI POUR CETTE BASCULE, a aucune largeur. Depuis que le reglage
   du fond a quitte le panneau de reglages, ces trois boutons sont le SEUL
   chemin vers les themes : les masquer, meme sur un petit ecran, retirerait
   le thème sombre à qui en a besoin. C'est `ajusterEntete()` qui absorbe la
   place, en repliant les commandes de lecture plus tot. */

/* `position: relative` sert d'ancrage au menu replie, qui se pose en absolu
   juste dessous. Elle vit ici et pas dans le bloc du repli : l'ancrage ne
   depend pas de l'etat. */
.entete__actions {
  margin-left: auto; position: relative;
  display: flex; gap: 8px; flex-wrap: nowrap;
}

/* ---------- Un bouton a l'icone seule ----------
   Le libelle est masque, le nom accessible vient de `aria-label`, identique
   au mot. Il redevient visible dans le menu replie. */
/* LE QUATRIEME CRAN DE REPLI : « Menu » perd son mot.

   Mesure du 6 septembre 2026, ecran de lecture a 360 px : les trois crans
   epuises, l'en-tete demandait encore 353 px pour 305 de place, le bouton
   « Menu » sortait de l'ecran a 374 et la page defilait de 14 px sur le cote.
   360 px n'est pas une largeur rare, c'est celle de beaucoup d'Android.

   C'est le bon bouton a reduire, et le dernier : le trait de menu se reconnait
   sans legende, la ou un dessin de document ne dit pas « sortir » (voir « Un
   autre texte », qui garde ses mots pour cette raison). Le nom accessible et
   l'infobulle portent le mot, et les six libelles reviennent dans le menu une
   fois ouvert.

   Il se declenche a la PLACE REELLE, comme les trois autres : au-dessus de
   360 px le mot reste. Voir `ajusterEntete()` dans app.js. */
.btn--icone,
body[data-entete-menu-icone="oui"] #btnMenu { min-width: 44px; padding-left: 11px; padding-right: 11px; justify-content: center; }
.btn--icone .btn__mot,
body[data-entete-menu-icone="oui"] #btnMenu .btn__mot { display: none; }

/* ---------- La barre de lecture, sous 1000 px ----------

   MESURE, en 390 de large, sur l'exemple du code de la sante publique :
   en-tete collante 192 px, sommaire deplie dans le flux 2 149 px pour
   39 entrees, premier mot du texte a 2 535 px du haut. Sur un ecran de
   664 px utiles, barres du navigateur comprises, ca fait pres de quatre
   ecrans a franchir avant de lire, pour un sommaire qui disparait ensuite.

   Ajouter une barre repliee SOUS l'en-tete aurait porte le collant a 239 px,
   soit 36 % de l'ecran. La barre vit donc DANS l'en-tete, et sous 720 px
   elle prend sa place des qu'on descend : 51 px collants au lieu de 239.
   L'en-tete revient des qu'on remonte, et des qu'on entre dedans au clavier
   (:focus-within), sans quoi ses commandes deviendraient injoignables. */
.barre-lecture { display: none; }

@media (max-width: 999px) {
  .barre-lecture {
    display: flex; align-items: center;
    max-width: 1180px; margin: 0 auto;
    padding: 0 12px 8px;
  }
  .barre-lecture__ouvrir {
    display: flex; align-items: center; gap: 8px;
    width: 100%; min-height: 44px;
    padding: 8px 12px;
    font: inherit; font-family: var(--font-ui); font-size: .86rem;
    text-align: left;
    color: var(--ink);
    background: var(--surface);
    border: 1px solid var(--line-fort);
    border-radius: var(--radius-sm);
    cursor: pointer;
  }
  .barre-lecture__ouvrir:hover { background: var(--surface-2); }
  .barre-lecture__signe { flex: 0 0 auto; }
  /* Un intitule de division peut faire 80 signes : il se coupe, la barre
     garde une seule ligne. */
  .barre-lecture__division {
    min-width: 0; flex: 1 1 auto;
    display: flex; align-items: baseline; gap: .4em;
    overflow: hidden; white-space: nowrap;
    font-weight: 700;
  }
  /* LE MARQUEUR ET L'INTITULE SE PARTAGENT LA LIGNE, et chacun coupe chez
     lui. Une seule boite qui coupe couperait au fil du texte : sur un
     rapport, « I. » tiendrait et le sujet disparaitrait ; sur une loi,
     « TITR… ». Ici le marqueur passe en premier et ne cede sa place qu'a
     defaut, l'intitule prend ce qui reste et porte l'ellipse.

     `overflow: hidden` sur CHACUN, pas seulement sur le conteneur : un span
     en ligne plus large que son parent garde sa boite entiere, et le banc
     de debordement le releve comme « hors cadre » alors que rien ne se voit
     a l'ecran. */
  /* LE MARQUEUR NE SE COMPRIME PAS. `flex-shrink` se repartit au prorata
     de la largeur de chaque element : face a un intitule de 1 100 px, un
     marqueur de 30 px prenait quand meme sa part du manque et perdait une
     vingtaine de pixels, donc son point final. « I » au lieu de « I. »,
     vu a l'ecran. Il garde donc sa largeur, et `max-width: 100%` le borne
     au conteneur pour le cas d'un marqueur plus long que la barre : sans
     cette borne il sortirait de son cadre et le banc de debordement le
     releverait. */
  .barre-lecture__marqueur {
    flex: 0 0 auto; min-width: 0; max-width: 100%;
    overflow: hidden; text-overflow: ellipsis;
  }
  /* L'intitule passe en graisse normale : deux informations de rang
     different sur une seule ligne, et le marqueur reste ce qui accroche
     l'oeil. */
  .barre-lecture__intitule {
    flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis;
    font-weight: 400;
  }

  /* Le sommaire sort du flux. Il ne revient qu'ouvert, en panneau. */
  .plan-panneau { display: none; }
  /* L'etat ouvert se lit sur l'attribut `open`, pose par le composant, comme
     sur un <dialog>. Une classe de plus aurait ete un second vocabulaire a
     tenir d'accord avec le premier. */
  .plan-panneau[open] {
    /* Colonne : le titre et la croix en haut, le sommaire qui defile dessous.
       Le panneau lui-meme ne defile PAS, sinon la croix part vers le haut des
       que le sommaire s'allonge, et sur un texte a 39 entrees elle est
       introuvable. Meme regle que `.panneau`. */
    display: flex; flex-direction: column;
    position: fixed; inset: 0;
    z-index: var(--z-panneau);
    margin: 0; border: 0; border-radius: 0;
    overflow: hidden;
    padding: 16px 16px 0;
  }
  .plan-panneau[open] .plan-panneau__haut { flex: 0 0 auto; }
  .plan-panneau[open] .plan-panneau__corps {
    flex: 1 1 auto;
    min-height: 0;              /* sans quoi la hauteur bornee reste sans effet */
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 40px;
  }
  /* La croix se cale en haut a droite, a l'aplomb du titre et du meme
     rembourrage que lui. Pas de marge negative pour la coller davantage au
     bord : elle depasserait le cadre de son conteneur, et le banc du
     debordement le releve, a juste titre. */
  .plan-panneau__fermer {
    flex: 0 0 auto;
    width: 44px; min-height: 44px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: auto;
  }
}

/* Le haut du panneau vaut a toutes les largeurs : au large il ne contient
   que le titre, la croix n'y est pas. */
.plan-panneau__haut {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
}

@media (min-width: 1000px) {
  /* Rien a fermer au large : le sommaire est une colonne, pas un panneau.
     Selecteur a DEUX classes : .btn pose son display plus loin dans la
     feuille, et a specificite egale c'est l'ordre qui tranche. */
  .plan-panneau .plan-panneau__fermer { display: none; }
}

/* Sous 720 px seulement : l'en-tete mesure 192 px, elle se retire pendant la
   lecture. Au-dessus elle tient sur une ligne et ne gene personne.

   Retrait en max-height, PAS en display:none. Un display:none sortirait ses
   commandes de l'arbre d'accessibilite : au lecteur d'ecran et au clavier,
   qui ne « remontent » pas comme un doigt sur un ecran, Reglages et Imprimer
   deviendraient injoignables sans revenir en haut d'un document de 141 652 px.
   Repliee, l'en-tete reste donc atteignable au clavier, et le focus la
   ramene. Le rembourrage vertical part avec, sinon il resterait 28 px de vide
   collant. */
@media (max-width: 720px) {
  .entete__interieur { transition: max-height .18s var(--ease); }
  body[data-entete="repliee"] .entete__interieur {
    max-height: 0; padding-top: 0; padding-bottom: 0; overflow: hidden;
  }
  body[data-entete="repliee"] .entete__interieur:focus-within {
    max-height: none; padding-top: 14px; padding-bottom: 14px; overflow: visible;
  }
}

/* ---------- L'etat du texte, sous l'en-tete ----------

   UNE RANGEE A ELLE, pleine largeur. Elle ne dispute donc aucune place
   horizontale a l'en-tete, dont la mesure de repli est deja a la limite a
   360 px. Et elle survit au repli de `.entete__interieur` sous 720 px,
   qui n'emporte que l'interieur.

   ELLE NE S'AFFICHE QUE QUAND LA GARDE EST SORTIE DE L'ECRAN. Tant qu'on
   la voit, la bande dirait deux fois la meme chose et prendrait une ligne
   pour rien. Voir `majRappelGarde()` dans app.js.

   LE FOND EST CELUI DE LA PAGE, pas une couleur d'alerte. La bande rappelle
   ce que le document dit, elle ne previent de rien. */
.rappel-garde {
  border-top: 1px solid var(--line);
  background: var(--bg);
}
/* ELLE N'EXISTE QUE PENDANT LA LECTURE. `majRappelGarde()` la remasque
   deja, mais il ne tourne qu'au defilement : ouvrir « Mes textes » sans
   toucher a la molette la laissait affichee au-dessus de la liste, a parler
   d'un texte qui n'etait plus a l'ecran. La regle CSS ne peut pas etre
   oubliee par un chemin de navigation. */
body:not([data-ecran="lecture"]) .rappel-garde { display: none; }
.rappel-garde__interieur {
  max-width: 1180px; margin: 0 auto; padding: 2px 20px;
  display: flex; align-items: center; gap: 10px;
}
/* Les mots du document, en petites capitales comme sur la garde elle-meme :
   la bande se lit comme un rappel de ce qui est plus haut, pas comme une
   phrase de l'app. Une seule ligne, coupee aux points de suspension : la
   suite est sous le bouton, jamais sur une deuxieme ligne. */
.rappel-garde__ligne {
  margin: 0; min-width: 0; flex: 1 1 auto;
  font-size: .82rem; font-weight: 600; letter-spacing: .04em;
  color: var(--ink-soft); text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* L'extrait colle sans garde ne se nomme pas. La phrase est de l'app, elle :
   elle se distingue donc des mots du document, en casse ordinaire. */
.rappel-garde__ligne[data-inconnu] {
  text-transform: none; letter-spacing: 0; font-weight: 500;
  color: var(--ink-faint); font-style: italic;
}
.rappel-garde__plus {
  flex: 0 0 auto; border: 1px solid var(--line); background: transparent;
  border-radius: var(--radius-sm); cursor: pointer;
  /* 44 px, le seuil que le banc d'accessibilite applique a toutes les cibles
     et aux boutons de pli. La bande fait donc 48 px de haut : c'est le prix
     d'une commande atteignable au doigt, et elle est la seule chose qui
     reste a l'ecran sous 720 px, ou l'interieur de l'en-tete se replie. */
  padding: 2px 6px 2px 10px; min-height: 44px;
  display: flex; align-items: center; gap: 2px;
  font: inherit; font-size: .78rem; color: var(--ink-faint);
}
.rappel-garde__plus:hover { color: var(--ink); border-color: var(--ink-faint); }
/* Le chevron pointe vers le bas quand le repli est ferme, et se retourne
   quand il s'ouvre : la fleche dit le geste a venir, pas l'etat courant. */
.rappel-garde__plus .ico {
  width: 16px; height: 16px; transform: rotate(90deg); transition: transform .18s var(--ease);
}
.rappel-garde__plus[aria-expanded="true"] .ico { transform: rotate(-90deg); }
/* SOUS 560 px, LE MOT PART, LE CHEVRON RESTE. Le nom accessible est porte
   par `aria-label` et ne bouge pas : le libelle masque y reste contenu,
   comme pour les boutons de l'en-tete (WCAG 2.5.3 « Label in Name »).
   En `display:none` plutot qu'a 1x1 px : un texte hors cadre serait releve
   par le banc de debordement. */
@media (max-width: 560px) {
  .rappel-garde__mot { display: none; }
  .rappel-garde__plus { padding: 2px 4px; }
}
.rappel-garde__suite {
  max-width: 1180px; margin: 0 auto; padding: 0 20px 10px;
  border-top: 1px dashed var(--line);
}
.rappel-garde__suite p {
  margin: 6px 0 0; font-size: .85rem; color: var(--ink-soft);
}

/* ---------- Le menu de l'entete ----------
   Au large, les trois commandes sont en ligne et le bouton « Menu » n'existe
   pas. Sous 720 px, elles se replient derriere lui : quatre boutons prenaient
   quatre lignes, soit un tiers de l'ecran avant le premier mot du texte.
   Le repli se fait en `display:none`, pas en `visibility` : un menu ferme doit
   sortir de l'arbre d'accessibilite, pas seulement disparaitre a l'oeil. */
.menu-lecture { display: flex; gap: 8px; flex-wrap: nowrap; }

/* Tant que la ligne tient, le bouton « Menu » n'existe pas. */
body:not([data-entete-menu="replie"]) #btnMenu { display: none; }

body[data-entete-menu="replie"] .menu-lecture {
  display: none;
  position: absolute; top: calc(100% + 10px); right: 0;
  z-index: 25;
  /* Assez large pour que le plus long libelle tienne sur une ligne :
     « Reglages de lecture », mesure au banc. */
  min-width: 262px;
  flex-direction: column; gap: 6px; flex-wrap: nowrap;
  padding: 8px;
  background: var(--card);
  border: 1px solid var(--line-fort);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
body[data-entete-menu="replie"] .menu-lecture[open] { display: flex; }
/* `text-align` compte autant que `justify-content` : un bouton centre son
   texte par defaut, et un libelle qui passe sur deux lignes se retrouvait
   centre au milieu d'une colonne alignee a gauche. */
body[data-entete-menu="replie"] .menu-lecture .btn {
  width: 100%; justify-content: flex-start; text-align: left;
}
/* Dans le menu, l'icone seule ne suffit plus : le mot revient. */
body[data-entete-menu="replie"] .menu-lecture .btn--icone { padding-left: 15px; padding-right: 15px; }
body[data-entete-menu="replie"] .menu-lecture .btn--icone .btn__mot { display: inline; }

/* DANS LE MENU, TOUS LES ITEMS ONT LE MEME CADRE. « Un autre texte » porte
   `.btn--discret` : au large, dans la rangee en ligne, c'est juste : il est
   d'un rang en dessous des commandes de lecture. Dans le menu replie, ou les
   cinq autres sont cercles, il etait le seul sans cadre au bas de la colonne,
   ce qui le faisait lire comme desactive ou comme un pied de menu. Il reprend
   donc le filet commun ICI SEULEMENT : c'est le contexte qui change, pas le
   rang du bouton. */
body[data-entete-menu="replie"] .menu-lecture .btn--discret {
  border-color: var(--line-fort);
  color: var(--ink);
}

/* ---------- La croix des champs de recherche ----------
   Le vide-champ natif de <input type="search"> est BLEU, impose par le
   navigateur : hors de la charte blanc et rouge, et il jure avec tout le
   reste de l'ecran. On ne le masque pas pour autant, ce serait retirer une
   commande utile au doigt, la ou Echap n'existe pas : on le rhabille avec
   le dessin pixel « fermer » de la charte, en masque, ce qui lui donne
   `currentColor` et le fait suivre les trois themes tout seul.

   Le dessin est recopie ici en data-URI : `js/icones.js` est produit et ne
   sait pas parler au CSS. S'il change dans identity/icones/fermer.pix, ce
   chemin est a reporter a la main. Aucun CDN, c'est une regle du projet.
   `-webkit-` seulement : Chrome et Safari, les cibles du Mac. Firefox
   n'affiche aucun bouton, avant comme apres. */
input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px;
  margin-left: 6px;
  cursor: pointer;
  background-color: var(--ink-faint);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Cpath d='M2 2H4V4H2Z M8 2H10V4H8Z M4 3H5V9H4Z M7 3H8V9H7Z M3 4H4V5H3Z M5 4H7V8H5Z M8 4H9V5H8Z M3 7H4V10H3Z M8 7H9V10H8Z M2 8H3V10H2Z M9 8H10V10H9Z' fill='black'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Cpath d='M2 2H4V4H2Z M8 2H10V4H8Z M4 3H5V9H4Z M7 3H8V9H7Z M3 4H4V5H3Z M5 4H7V8H5Z M8 4H9V5H8Z M3 7H4V10H3Z M8 7H9V10H8Z M2 8H3V10H2Z M9 8H10V10H9Z' fill='black'/%3E%3C/svg%3E") center / contain no-repeat;
}
input[type="search"]:hover::-webkit-search-cancel-button,
input[type="search"]:focus::-webkit-search-cancel-button {
  background-color: var(--accent);
}

/* ---------- Surligner ses propres mots-cles ----------
   Une commande dans la barre, un panneau pour la liste. Le panneau reprend
   `.panneau` : meme position, meme cadre, meme fermeture. */

/* Le compte sur le bouton de la barre. Decoratif : le nom accessible du
   bouton ne bouge pas, la region role="status" du panneau porte l'annonce. */
.btn__compte {
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  color: var(--accent-fonce);
}

/* Le bouton prend EXACTEMENT la hauteur du champ.
   MESURE, PAS DEVINE : le bouton sortait a 64 px contre 51 au champ. La
   cause n'etait ni son retrait ni son `min-height`, mais le
   `margin-bottom: .8em` que `.champ-recherche` porte pour son usage
   d'origine, dans le panneau de recherche. Ces 12,8 px allongeaient la
   ligne du conteneur a 63,59 px, et le bouton, lui, s'y etirait. On retire
   la marge ici, `stretch` fait le reste. La cible tactile reste tenue par
   le champ, qui ne descend jamais sous 44 px. */
.mots-cles__ajout { display: flex; gap: 8px; align-items: stretch; margin: 0 0 12px; }
.mots-cles__ajout .champ-recherche { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.mots-cles__ajout .btn { flex: 0 0 auto; }

/* La liste des mots-cles. Une pastille = un mot, son compte, sa croix.

   BEAUCOUP DE MOTS NE DOIT PAS CASSER LE PANNEAU. Mesure a dix mots-cles
   sur un ecran de 390 px : la liste faisait 460 px et le panneau 754 px sur
   844, soit toute la hauteur d'ecran. La liste est donc bornee et defile
   toute seule ; le titre, le champ et le bouton « Fermer » restent visibles
   quoi qu'il arrive. Le retrait de 2 px laisse passer l'anneau de focus des
   croix, qu'un `overflow` couperait net. */
.pastilles {
  list-style: none; margin: 0 -2px 4px; padding: 2px;
  display: flex; flex-wrap: wrap; gap: 8px;
  max-height: 34vh; overflow-y: auto;
}

/* Filet de securite : meme avec la liste bornee, le panneau ne depasse
   jamais l'ecran. Il s'ancre en bas, donc il grandit vers le haut. */
/* La hauteur bornee vaut pour tous les panneaux : voir
   `.panneau__corps`. */
.pastille {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 0 4px 0 12px;
  min-height: 44px;               /* cible tactile, regle du debordement */
  background: var(--surligne);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui); font-size: .9rem;
  color: var(--ink);
  max-width: 100%;
}
/* Le mot lui-meme peut etre long : il se coupe, la croix garde sa place. */
.pastille__mot { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pastille__compte {
  flex: 0 0 auto;
  font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--accent-fonce);
}

/* Un mot qui ne donne rien le dit. Sans ca, on croit que le surlignage est
   casse alors que le mot est simplement absent du texte. */
.pastille--vide { background: var(--surface-2); border-color: var(--line-fort); }
.pastille--vide .pastille__mot { color: var(--ink-soft); }
.pastille--vide .pastille__compte { color: var(--ink-faint); font-weight: 600; }

.pastille__retirer {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; min-height: 36px;
  padding: 0; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--ink-soft);
  cursor: pointer;
}
.pastille__retirer:hover { background: var(--card); color: var(--ink); }

.pastilles__vide { margin: 0; }

/* ---------- Avancement dans le texte ---------- */

/* Sur la proposition 3106, le document fait 141 652 px de haut et
   69 articles : sans reperage, on ne sait pas si on lit la page 3 ou 80.
   Un filet de 3 px sous l'entete, decoratif (aria-hidden). L'information
   utile, la division en cours, reste dans le sommaire. */
.avancement {
  height: 3px;
  background: var(--line);
}
/* Anime en transform plutot qu'en width : la largeur repasse la mise en page
   a chaque image, l'echelle reste sur le compositeur. Aucune transition : la
   jauge est deja recalculee a chaque frame par requestAnimationFrame, une
   transition n'ajouterait que du retard au defilement rapide. Rien a couper
   pour prefers-reduced-motion, il n'y a plus d'animation. */
.avancement__jauge {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
}

/* ---------- Boutons ---------- */

/* RECTANGLE ARRONDI, PAS PILULE, et le meme rayon que les champs.
   `--radius-sm` est ce que portent `.champ-texte`, `.champ-recherche`,
   `.plan-filtre__champ` et `.champ-url` : un bouton pose a cote d'un champ
   se lit comme sa paire, et non comme une piece rapportee. Decide le
   6 septembre 2026, apres avoir compare la pilule et les rayons de 4, 6 et
   8 px a l'ecran. */
.btn {
  font: inherit; font-weight: 600; font-size: .9rem;
  padding: 9px 15px; border-radius: var(--radius-sm);
  border: 1px solid var(--line-fort); background: var(--card); color: var(--ink);
  cursor: pointer; transition: background .18s var(--ease), border-color .18s var(--ease);
  min-height: 44px; display: inline-flex; align-items: center; gap: 7px;
  /* JAMAIS deux lignes dans un bouton. Un libelle coupe en deux double la
     hauteur du bouton, casse l'alignement de la rangee et se centre alors que
     la colonne est alignee a gauche. Si le libelle ne tient pas, c'est le
     contenant qui s'elargit ou le libelle qui raccourcit, jamais la ligne qui
     se dedouble. Le banc de debordement verifie que rien ne sort du cadre. */
  white-space: nowrap;
}
.btn:hover { background: var(--surface-2); }
.btn[aria-pressed="true"] { background: var(--accent-pale); border-color: var(--accent); color: var(--accent-fonce); }
.btn--fort { background: var(--accent); border-color: var(--accent); color: var(--sur-accent); }

/* « MES TEXTES » : IMPORTANT, MAIS PAS ROUGE.

   C'est l'entrée permanente vers la page personnelle, elle doit se détacher
   des commandes de lecture qui l'entourent. Le rouge est déjà pris par
   `.btn--fort`, qui dit « c'est le geste principal de cet écran-ci » : le lui
   donner ferait deux gestes principaux qui se contredisent.

   Elle se détache donc par l'ENCRE : filet plein de 2 px et graisse de titre,
   la même encre que le filet sous l'en-tête de l'accueil. Ça tient en niveaux
   de gris et dans les trois thèmes, et ça ne crie pas. */
.entete__mes-textes {
  border-width: 2px;
  border-color: var(--ink);
  font-weight: 700;
}
.entete__mes-textes:hover {
  background: var(--surface-2);
  border-color: var(--ink);
}
.btn--fort:hover { background: var(--accent-fonce); border-color: var(--accent-fonce); }
.btn--discret { border-color: transparent; background: transparent; color: var(--ink-soft); }
.btn--discret:hover { background: var(--surface-2); }

/* ---------- Écran d'accueil ----------
   Charte « la une » : bandeau de titre épais, hero sur deux colonnes,
   repères rouges pleins comme marqueurs de section. Tout est porté par
   les tokens de :root, aucune valeur de couleur en dur.

   L'en-tête est PARTAGÉE avec l'écran de lecture. Le filet épais du
   bandeau ne vaut donc que sur l'accueil, via `data-ecran` posé sur
   <body> par app.js. Sans l'attribut, on retombe sur le filet fin,
   qui est l'état de l'écran de lecture.
   ---------------------------------------------------------------- */

/* « Mes textes » est un ecran de SITE, comme l'accueil, pas la vue de
   lecture : il porte donc le meme filet. Sans lui, passer de l'accueil a
   « Mes textes » faisait maigrir l'en-tete de 3 px a 1 px, et toute la page
   sautait de 2 px. Mesure : en-tete a 79 px sur l'accueil, 77 px sur
   « Mes textes ». */
body[data-ecran="accueil"] .entete,
body[data-ecran="textes"] .entete { border-bottom-width: 3px; border-bottom-color: var(--ink); }

.accueil { max-width: 1180px; margin: 0 auto; padding: 0 20px 90px; }

/* --- Hero --- */

.accueil__hero {
  display: grid; gap: 48px; align-items: start;
  padding: 54px 0 48px; border-bottom: 1px solid var(--line);
}
@media (min-width: 900px) {
  .accueil__hero { grid-template-columns: 1.05fr .95fr; gap: 54px; }
}

.accueil__titre {
  font-size: clamp(1.95rem, 4.4vw, 3.1rem); font-weight: 800;
  line-height: 1.08; letter-spacing: -.028em; margin: 0 0 18px;
}
.accueil__titre em { font-style: normal; color: var(--accent); }
.accueil__chapo {
  font-size: 1.06rem; line-height: 1.68; color: var(--ink-soft);
  margin: 0 0 26px; max-width: 48ch;
}

/* --- Les trois étapes ---
   Le numéro est décoratif (`aria-hidden`) : l'ordre est déjà porté par le
   <ol>, un lecteur d'écran annonce « 1 » deux fois sinon. */
.etapes { list-style: none; margin: 0; padding: 0; }
.etape {
  display: grid; grid-template-columns: 26px 1fr; gap: 0 13px;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.etape__n {
  width: calc(13 * var(--px)); height: calc(13 * var(--px));
  display: grid; place-items: center; border-radius: var(--radius-sm);
  background: var(--accent); color: var(--sur-accent);
  font-size: .82rem; font-weight: 700; line-height: 1;
}
.etape__t { display: block; font-weight: 700; font-size: .98rem; }
.etape__q { margin: 3px 0 0; font-size: .9rem; line-height: 1.55; color: var(--ink-soft); }


/* --- Zone de collage ---
   Filet plein de 2 px au repos, et non plus un pointillé permanent : la carte
   porte l'action principale de la page, elle doit se lire comme un objet posé.
   Le pointillé revient au survol d'un fichier, là où il dit quelque chose. */
.depot {
  border: 2px solid var(--ink); border-radius: var(--radius);
  background: var(--card); padding: 20px 20px 18px; margin-bottom: 16px;
  box-shadow: var(--shadow);
  transition: border-color .18s var(--ease), background .18s var(--ease);
}
.depot.survol { border-style: dashed; border-color: var(--accent); background: var(--accent-pale); }
.depot__libelle { font-weight: 800; font-size: 1.05rem; margin: 0 0 4px; }
.depot__aide { color: var(--ink-faint); font-size: .88rem; margin: 0 0 14px; }


.champ-texte {
  width: 100%; min-height: 172px; resize: vertical;
  font-family: var(--font-lecture); font-size: 1rem; line-height: 1.6;
  padding: 13px 14px; border: 1px solid var(--line-fort); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
}
/* L'ETAT D'ERREUR DU CADRE DE COLLAGE.

   Clic sur « Mettre en forme » avec le cadre vide : le message sortait en
   toast rouge a environ 800 px sous le bouton, donc hors ecran des qu'on avait
   fait defiler, et rien ne bougeait dans le cadre. C'est une erreur de
   formulaire : elle se traite dans le formulaire.

   Trois choses ensemble, jamais la couleur seule (WCAG 1.4.1) : le filet du
   champ passe a l'accent, un message ecrit se pose sous le champ, et le focus
   revient dans le champ a corriger. Le rembourrage compense le pixel de filet
   pris en plus, sinon le texte deja tape saute d'un pixel a l'affichage de
   l'erreur. */
.champ-texte[aria-invalid="true"] {
  border: 2px solid var(--accent);
  padding: 12px 13px;
}
.depot__erreur {
  margin: 8px 0 0;
  font-size: .88rem; font-weight: 700;
  color: var(--accent-fonce);
}

.champ-url {
  width: 100%; font: inherit; padding: 12px 14px; min-height: 44px;
  border: 1px solid var(--line-fort); border-radius: var(--radius-sm);
  background: var(--card); color: var(--ink);
}
.champ-url:not(:focus) { text-overflow: ellipsis; }

/* LA NOTE LIBRE D'UN TEXTE, dans l'onglet « Mes notes ». Meme fabrique que
   le champ de collage, en plus bas : elle accompagne la lecture, elle ne
   la remplace pas. Redimensionnable a la verticale, jamais a l'horizontale,
   qui ferait deborder le panneau. */
.champ-note {
  width: 100%; min-height: 84px; resize: vertical;
  font-family: var(--font-lecture); font-size: .95rem; line-height: 1.55;
  padding: 11px 12px; border: 1px solid var(--line-fort); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
  margin-bottom: 6px;
}

/* Le sous-titre d'une section du panneau des annexes. h3 : le panneau
   porte un h2, aucun niveau n'est saute (critere RGAA). */
.annexes__soustitre {
  font-family: var(--font-ui); font-size: .95rem; font-weight: 700;
  margin: 18px 0 6px; color: var(--ink);
}

/* L'AVERTISSEMENT SUR LA DUREE DE VIE DES NOTES. Il se detache par un
   filet, jamais par une couleur d'alerte : ce n'est pas une erreur, c'est
   une limite du navigateur qu'on dit honnetement. */
.panneau__aide--filet {
  border-left: 3px solid var(--line-fort);
  padding-left: 11px;
  margin-top: 16px;
}

.rangee { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; margin-top: 14px; }

/* Dans la carte de collage, la commande secondaire garde un cadre visible.
   Sans lui, sa boîte s'aligne bien sur celle du bouton principal, mais son
   contenu est décalé du rembourrage interne : à l'œil, le bouton paraît mal
   aligné alors qu'il ne l'est pas. Un filet fin suffit à rendre la boîte
   lisible, et la hiérarchie tient toujours par le fond et la graisse. */
/* « Voir un exemple » est de troisieme rang : il se propose, il n'appelle pas.
   Un lien souligne sous la rangee, pas un troisieme bouton qui pesait autant
   que les deux commandes reelles.

   Reste un <button> dans le HTML : il declenche une action, il ne navigue pas.
   Le souligne n'est donc pas une decoration, c'est ce qui dit qu'on peut
   cliquer, puisque la boite du bouton a disparu.

   Sa cible tactile fait 40 px de haut alors que le texte fait 13 px : ce qui
   retrecit, c'est le texte, jamais la zone qu'on vise au doigt. */
.rangee-lien { margin: 6px 0 0; }

/* Le format attendu, sous la rangee et rattache au bouton par
   aria-describedby : lu a voix haute avec lui, pas cherche ailleurs. */
.rangee-aide {
  margin: 8px 0 0;
  font-size: .82rem;
  color: var(--ink-faint);
}
.rangee-aide code {
  font-size: .95em;
  background: var(--surface-2);
  padding: 1px 5px;
  border-radius: var(--radius-sm);
}

.lien-action {
  font: inherit;
  font-size: .82rem;
  color: var(--ink-soft);
  background: none;
  border: 0;
  padding: 10px 2px;
  min-height: 44px;               /* cible tactile, releve au banc a 40 */
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.lien-action:hover { color: var(--ink); text-decoration-color: var(--accent); }


/* Le sceau. Il porte le dernier conseil avant d'aller chercher son texte :
   ce qui n'est pas pris en charge, et la forme qui donne le meilleur rendu. */
.depot__sceau {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: .83rem; line-height: 1.5; color: var(--ink-faint);
}
.depot__sceau [data-ico] { color: var(--accent); flex: 0 0 auto; }
.depot__sceau .ico { width: calc(8 * var(--px)); height: calc(8 * var(--px)); }
.depot__sceau code {
  font-family: var(--font-mono, ui-monospace, monospace); font-size: .95em;
  color: var(--ink-soft);
}

.aide-source { font-size: .88rem; color: var(--ink-faint); line-height: 1.6; margin-top: 26px; }
.aide-source a { color: var(--accent-fonce); }

@media (max-width: 560px) {
  .accueil__hero { padding: 32px 0 30px; gap: 32px; }
  .depot { padding: 16px 15px 15px; }
}

/* ---------- Mise en page de lecture ---------- */

.lecteur { max-width: 1180px; margin: 0 auto; padding: 0 20px 90px; display: grid; gap: 34px; }
@media (min-width: 1000px) {
  .lecteur {
    position: relative;   /* repere de la poignee de largeur */
    grid-template-columns: var(--largeur-sommaire, 260px) minmax(0, 1fr);
    align-items: start; padding-top: 28px;
  }
}

/* ---------- Poignee de largeur du sommaire ---------- */

/* La poignee occupe TOUTE la gouttiere entre le sommaire et le texte : 34 px
   a attraper, pour un trait visible de 2. Une bordure d'un pixel ne s'attrape
   ni a la souris ni au trackpad.

   Elle n'existe qu'a partir de 1000 px. En dessous, le sommaire n'est plus
   une colonne mais un panneau pose au-dessus du texte : il n'y a pas de
   frontiere a tirer, donc pas de poignee. */
.poignee-redim { display: none; }

@media (min-width: 1000px) {
  .poignee-redim {
    display: block;
    position: absolute;
    top: 0; bottom: 0;
    left: calc(20px + var(--largeur-sommaire, 260px));
    width: 34px;
    cursor: col-resize;
    touch-action: none;   /* sinon le geste part en defilement */
    z-index: 2;
  }
  /* La poignee fait toute la hauteur du document : un trait de 140 000 px
     n'aurait aucun sens. Le repere, lui, reste a l'ecran. */
  .poignee-redim__trait {
    display: block;
    position: sticky;
    top: calc(84px + var(--rappel-h, 0px));
    height: calc(100vh - 108px - var(--rappel-h, 0px));
    width: 2px;
    margin: 0 auto;
    border-radius: 2px;
    background: transparent;
    transition: background .15s ease, width .15s ease;
  }
  .poignee-redim:hover .poignee-redim__trait { background: var(--line); width: 4px; }
  .poignee-redim:active .poignee-redim__trait { background: var(--accent); width: 4px; }
  .poignee-redim:focus-visible { outline: none; }
  .poignee-redim:focus-visible .poignee-redim__trait {
    background: var(--accent); width: 4px;
    box-shadow: 0 0 0 2px var(--accent);
  }
}

/* Pendant le glissement : plus de selection de texte, et le curseur reste
   celui du redimensionnement ou que la souris passe. Sans quoi on surligne
   la moitie de la page en tirant. */
html.redim-en-cours, html.redim-en-cours * {
  cursor: col-resize !important;
  user-select: none !important;
}

.plan-panneau {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 16px; min-inline-size: 0;
}
@media (min-width: 1000px) {
  /* `--rappel-h` vaut 0 tant que la bande d'etat n'est pas affichee, et sa
     hauteur mesuree ensuite (voir `majRappelGarde()` dans app.js). Sans ca,
     le titre du sommaire passait sous la bande des qu'elle apparaissait. */
  .plan-panneau {
    position: sticky; top: calc(84px + var(--rappel-h, 0px));
    max-height: calc(100vh - 108px - var(--rappel-h, 0px)); overflow: auto;
  }
}
.plan-panneau__titre { font-size: .78rem; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-faint); margin: 0 0 12px; font-weight: 700; }

/* ---------- Sommaire ---------- */

/* Filtre local du sommaire : il masque des entrees, il ne touche a rien
   d'autre. Sur 92 entrees, retrouver l'article 47 a l'oeil est un travail. */
.plan-filtre { margin: 0 0 12px; }
.plan-filtre__champ {
  width: 100%; min-height: 44px;   /* cible tactile, releve au banc a 40 */
  padding: 10px;
  font: inherit; font-size: .86rem;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line-fort);
  border-radius: var(--radius-sm);
}
.plan-filtre__champ::placeholder { color: var(--ink-faint); }
.plan-filtre__bilan {
  margin: 6px 0 0; font-size: .78rem; color: var(--ink-faint);
  min-height: 1em;
}

/* Le bouton de repli vit a cote du lien, jamais dedans : cliquer sur le
   titre navigue, cliquer sur le chevron replie. Deux gestes, deux cibles. */
.plan__ligne { display: flex; align-items: stretch; gap: 2px; }
.plan__ligne .plan__lien { flex: 1 1 auto; min-inline-size: 0; }

.plan__pli {
  flex: 0 0 auto;
  width: 32px; min-height: 40px;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  background: none; border: 0; border-radius: var(--radius-sm);
  color: var(--ink-faint); cursor: pointer;
}
.plan__pli:hover { background: var(--surface-2); color: var(--ink); }
.plan__chevron {
  width: 0; height: 0;
  border-top: 5px solid currentColor;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  transition: transform .15s var(--ease);
}
.plan__pli[aria-expanded="false"] .plan__chevron { transform: rotate(-90deg); }

/* Les sous-niveaux se decalent d'un cran, sans empiler les paddings. */
.plan__sous { list-style: none; margin: 0; padding: 0 0 0 12px; }
.plan__sous .plan__sous { padding-left: 10px; }

/* Le compte d'occurrences d'une entree, pose par l'interface apres chaque
   rendu. CUMULE : une division porte ce que ses articles contiennent, sinon
   un titre replie afficherait 1 quand il en cache 40. Le nombre est lu par
   le lecteur d'ecran grace au texte cache qu'il contient (« 14 occurrences »),
   donc pas d'aria-hidden ici. Blanc sur accent : la paire deja mesuree au
   banc d'accessibilite, 6,64:1 dans les trois themes. */
.plan__compte {
  flex: 0 0 auto;
  align-self: center;
  min-width: 22px;
  padding: 2px 6px;
  font-family: var(--font-ui);
  font-size: .72rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
  text-align: center;
  color: var(--sur-accent);
  background: var(--accent);
  border-radius: 999px;
}

/* Une entree trouvee par le filtre se signale sans crier. */
.plan__item--trouve > .plan__ligne > .plan__lien { background: var(--accent-pale); }

.plan { list-style: none; margin: 0; padding: 0; }
.plan__item a {
  display: flex; flex-direction: column; gap: 1px;
  padding: 7px 9px; border-radius: var(--radius-sm);
  color: var(--ink-soft); text-decoration: none; font-size: .88rem;
  min-inline-size: 0;
}
.plan__item a:hover { background: var(--surface-2); color: var(--ink); }
.plan__item a[aria-current="true"] { background: var(--accent-pale); color: var(--accent-fonce); font-weight: 700; }
.plan__libelle { font-weight: 600; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.plan__intitule {
  font-size: .8rem; color: var(--ink-faint);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; text-overflow: ellipsis;
}

/* UN MARQUEUR NE PREND PAS SA PROPRE LIGNE.

   Dans un texte normatif le libellé est « Article 12 » ou « CHAPITRE II » :
   il se lit seul et mérite sa ligne. Dans un rapport c'est « I. » ou « a. »,
   deux caractères qui occupaient une ligne entière du sommaire pendant que
   le titre, lui, était coupé à deux lignes. Sur les 132 entrées du rapport
   1770, cela faisait 132 lignes perdues.

   Le libellé repasse donc en ligne, devant le titre. Il ne se comprime
   jamais (`flex: 0 0 auto`) et il perd son `text-overflow` : deux
   caractères n'ont rien à tronquer. Le titre reprend la place et garde ses
   deux lignes. */
.plan__item--prefixe a { flex-direction: row; align-items: baseline; gap: .35em; }
.plan__item--prefixe .plan__libelle { flex: 0 0 auto; overflow: visible; }
.plan__item--prefixe .plan__intitule { flex: 1 1 auto; min-inline-size: 0; }

/* ---------- Le texte ---------- */

.texte {
  max-width: var(--colonne);
  font-family: var(--font-lecture);
  font-size: var(--taille);
  line-height: var(--interligne);
  letter-spacing: var(--interlettre);
  min-inline-size: 0;
}
.texte > * { max-width: 100%; overflow-wrap: break-word; }

.division {
  font-family: var(--font-ui);
  font-size: 1.05rem; text-transform: uppercase; letter-spacing: .06em;
  margin: 3em 0 1.2em; padding-bottom: .5em;
  border-bottom: 2px solid var(--accent);
  display: flex; flex-wrap: wrap; gap: .5em; align-items: baseline;
}
.division__nature { color: var(--accent); font-weight: 800; }
.division__intitule { color: var(--ink); font-weight: 600; letter-spacing: .03em; }
.division--expose { border-bottom-color: var(--line-fort); }
.division--expose .division__nature { color: var(--ink-soft); }

/* LES RANGS DE DIVISION.

   Toutes les divisions avaient la meme apparence : Livre, Titre et Chapitre
   se lisaient au meme etage, et il n'en restait qu'un. Sur le livre II du
   code de la sante publique, l'exemple de l'ecran d'accueil, c'etait visible
   au premier coup d'oeil. Revue juridique du 6 septembre, J11.

   Le rang vient de `poserNiveauxDivision()` et il est NORMALISE : le niveau 1
   est le plus haut rang REELLEMENT present dans le document. Sur la 3106, qui
   n'a pas de livre, le titre est donc au niveau 1 et garde l'aspect de tete.
   `.division` reste la mise en forme de ce niveau 1, ces regles-ci n'allegent
   que ce qui est dessous.

   TROIS CHOSES DECROISSENT, PAS QUATRE : le corps, le filet et l'air autour.
   Les capitales restent partout, c'est la convention des divisions dans un
   texte de loi et elles ne viennent pas du document (le source garde sa
   casse, c'est le CSS qui la met en capitales, voir `division.nature`). */
.division--2 {
  font-size: 1rem;
  margin: 2.4em 0 1em;
  border-bottom-width: 1px;
}
.division--3 {
  font-size: .95rem;
  margin: 2em 0 .9em;
  border-bottom: 1px solid var(--line-fort);
}
.division--4,
.division--5,
.division--6 {
  font-size: .9rem;
  letter-spacing: .05em;
  margin: 1.7em 0 .8em;
  padding-bottom: .3em;
  border-bottom: 1px solid var(--line);
}
.division--5 .division__nature,
.division--6 .division__nature { color: var(--accent-fonce); }

.article {
  font-family: var(--font-ui);
  font-size: 1rem; font-weight: 800;
  margin: 2.4em 0 .9em; padding-left: 14px;
  border-left: 4px solid var(--accent);
  scroll-margin-top: var(--ancre-haut);
}
.division { scroll-margin-top: var(--ancre-haut); }

/* ---------- Les recommandations d'un rapport ----------
   Encadrées dans le texte, listées seules dans leur panneau. C'est ce
   qu'on cherche dans un rapport, et c'est le seul endroit du document
   qui porte une décision plutôt qu'un constat. */

.reco {
  font-family: var(--font-ui);
  font-size: .92rem;
  line-height: 1.6;
  margin: 1.8em 0;
  padding: .9em 1em;
  border-left: 4px solid var(--accent);
  background: var(--accent-pale);
  border-radius: 0 var(--radius) var(--radius) 0;
  scroll-margin-top: var(--ancre-haut);
}
.reco__num {
  font-weight: 800;
  color: var(--accent-fonce);
}

/* La liste du panneau. Une entrée porte trois choses : son numéro, son
   énoncé, et l'endroit d'où elle vient. Sans le troisième, une
   recommandation lue seule ne dit pas de quoi elle parle. */
/* Le bouton du sommaire, au-dessus de celui des annexes. Sa mise en forme
   est celle des annexes, écrite une seule fois : voir
   « .plan-panneau__recos, .plan-panneau__annexes » plus bas. */

.recos { list-style: none; margin: 0; padding: 0; }
.recos__item + .recos__item { border-top: 1px solid var(--line); }
.recos__lien {
  display: block;
  padding: .85em .2em;
  text-decoration: none;
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: .88rem;
  line-height: 1.5;
}
.recos__lien:hover { background: var(--surface-2); }
.recos__num {
  display: inline-block;
  font-weight: 800;
  color: var(--accent);
  margin-right: .5em;
}
.recos__enonce { overflow-wrap: break-word; }
.recos__ou {
  display: block;
  margin-top: .35em;
  font-size: .76rem;
  color: var(--ink-faint);
  overflow-wrap: break-word;
}

/* ---------- Les titres d'un rapport ----------
   Cinq niveaux, et la lecture doit dire lequel SANS avoir à compter les
   points. Trois moyens qui se cumulent : la taille, le filet, et la place
   du préfixe. Le niveau 1 barre la page, le niveau 5 se contente d'une
   graisse. Le préfixe garde la couleur d'accent à tous les niveaux : c'est
   lui qui donne la position dans la structure. */

/* En bloc, PAS en flex, contrairement à `.division`. Un intitulé de
   division tient sur une ligne ; celui d'un rapport fait cent cinquante
   signes, et le préfixe se retrouvait seul sur sa ligne, l'intitulé
   dessous. Le préfixe reste donc dans le flux du texte, comme un numéro
   de paragraphe. */
.titre-rap {
  font-family: var(--font-ui);
  color: var(--ink);
  scroll-margin-top: var(--ancre-haut);
}
.titre-rap__prefixe { color: var(--accent); font-weight: 800; margin-right: .15em; }
.titre-rap__intitule { overflow-wrap: break-word; }

/* Grand bloc : partie, avant-propos, annexe. Le même filet accentué que
   les divisions de légistique, pour que les deux familles de documents
   se lisent avec le même vocabulaire visuel. */
.titre-rap--1 {
  font-size: 1.05rem; text-transform: uppercase; letter-spacing: .06em;
  font-weight: 800;
  margin: 3.4em 0 1.3em; padding-bottom: .5em;
  border-bottom: 2px solid var(--accent);
}
.titre-rap--2 {
  font-size: 1rem; text-transform: uppercase; letter-spacing: .05em;
  font-weight: 700;
  margin: 2.8em 0 1em; padding-bottom: .4em;
  border-bottom: 1px solid var(--line-fort);
}
.titre-rap--3 {
  font-size: .95rem; letter-spacing: .03em; font-weight: 700;
  margin: 2.2em 0 .85em;
}
.titre-rap--4 {
  font-size: .92rem; font-weight: 700; color: var(--ink-soft);
  margin: 1.8em 0 .7em;
}
/* Le dernier niveau ne prend ni filet ni capitales : il en resterait
   trop peu pour distinguer les quatre au-dessus. Un retrait le rattache
   visuellement au niveau qui le porte. */
.titre-rap--5 {
  font-size: .88rem; font-weight: 700; color: var(--ink-soft);
  margin: 1.5em 0 .6em; padding-left: 14px;
  border-left: 2px solid var(--line);
}

.para { margin: 0 0 1.05em; }
.para--marqueur { margin-left: 0; }

/* Le texte insere par une disposition modificative est le cœur du
   dispositif. Il etait en --ink-soft, donc attenue : il reprend l'encre
   normale. Le filet et le retrait suffisent a dire « ceci est cite ». */
/* L'ETIQUETTE D'OPERATION. Le MOT porte l'information : « ajout »,
   « remplacement », « suppression ». Pas de code couleur a apprendre, pas de
   pastille a dechiffrer, et rien qui depende de la vue des couleurs
   (WCAG 1.4.1). Elle se pose devant l'alinea d'instruction et reste petite :
   c'est une indication, pas un titre. */
.op {
  display: inline-block;
  font-family: var(--font-ui);
  font-size: .64rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  line-height: 1;
  padding: .32em .5em;
  margin-right: .55em;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-fort);
  color: var(--ink-faint);
  vertical-align: .1em;
}

/* L'ETIQUETTE SUR UN TITRE D'ARTICLE. Elle se pose APRES le titre, pas
   devant : le numero d'article est ce qu'on cherche en parcourant la page, il
   garde la tete de ligne. Sur un alinea, au contraire, l'etiquette passe
   devant, parce qu'elle qualifie l'existence meme de la ligne.
   La marge de droite du `.op` ne sert a rien en fin de ligne, elle passe a
   gauche. Revue juridique du 6 septembre, J13. */
.article .op {
  margin-right: 0;
  margin-left: .7em;
  letter-spacing: .05em;
}

/* La suppression prend un fond plein. C'est la seule des trois operations
   qui n'a AUCUN texte cite derriere elle, donc aucun encart : sans ce poids
   supplementaire elle reste la modification la plus lourde et la moins
   visible de la page. Le fond ET le mot, jamais la couleur seule. */
.op--suppression {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--sur-accent);
}

/* MASQUER LES ANNOTATIONS. Tout ce que l'app ECRIT par-dessus le texte se
   cache d'un attribut : etiquettes, intitules d'encart, avertissement des
   articles modificatifs. Le HTML ne change pas, donc aucun rendu a refaire,
   et l'encart garde son filet et son fond, qui n'ajoutent aucun mot. */
:root[data-annotations="0"] .op,
:root[data-annotations="0"] .encart__titre,
:root[data-annotations="0"] .note-modif { display: none; }

/* Sans son intitule, l'encart se refermerait sur son texte. */
:root[data-annotations="0"] .encart { padding-top: .8em; }

/* Dans le panneau de reglages, l'etiquette montre a quoi ressemble ce
   qu'on eteint : elle doit rester visible meme quand tout est masque. */
:root[data-annotations="0"] .reglage__note .op { display: inline-block; }

/* LES MARQUES DE NAVETTE. Elles parlent de CE texte-ci, pas de ce qu'il fait
   aux autres lois : le filet en tirete les separe des trois operations, qui
   l'ont plein. Le mot reste ce qui porte l'information. */
.op--navette {
  border-style: dashed;
}

/* Un alinea retire du texte : c'est un morceau qui disparait, et il n'y a
   souvent rien d'autre sur la ligne pour le dire. Encre de l'accent et
   filet plein pour le poser, sans le fond plein de la suppression, qui
   parle d'autre chose. */
.op--nav-retire {
  border-style: solid;
  border-color: var(--accent);
  color: var(--accent-fonce);
}

/* UNE PHRASE PAR LIGNE. Le decoupage est TOUJOURS dans le HTML, c'est le CSS
   qui l'affiche ou non : basculer le reglage ne redemande aucun rendu, il
   pose un attribut sur la racine. Au fil du texte, le span est transparent
   et la page est exactement celle d'avant. */
.phrase { display: inline; }

:root[data-phrases="1"] .phrase {
  display: block;
  margin-bottom: .45em;
}
:root[data-phrases="1"] .phrase:last-child { margin-bottom: 0; }

/* LE RÉGLAGE « UNE PHRASE PAR LIGNE » NE VAUT QUE DANS LA COLONNE DE
   LECTURE. Le panneau des sources reprend le bloc rendu pour garder ses
   liens cliquables, donc il reprend aussi ses `.phrase`. Avec le réglage
   allumé, chaque phrase d'une note devenait un paragraphe : la note 6 du
   rapport 2993 s'affichait en deux blocs séparés, comme si l'entrée
   contenait le texte de la suivante.

   Le confort de lecture d'un texte long n'a pas de sens dans une liste de
   283 entrées courtes. La règle est portée par le sélecteur du réglage,
   pas seulement par `.annexe__texte`, sinon les deux se valent en poids et
   c'est l'ordre du fichier qui tranche. */
:root[data-phrases="1"] .annexe__texte .phrase { display: inline; margin-bottom: 0; }

/* L'ENCART. Le filet et le fond appartiennent au BLOC, plus a chacun de ses
   alineas : quarante-trois alineas cites donnaient quarante-trois petits
   traits empiles, un motif et pas un encart. */
.encart {
  margin: 1.6em 0;
  padding: .1em 1.1em .8em;
  border-left: 3px solid var(--line-fort);
  background: var(--surface);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

/* L'intitule dit ce que personne ne devine devant des guillemets : ce qui
   suit n'est pas encore le droit. Corps de l'interface, encre attenuee, en
   capitales pour ne pas se confondre avec le texte de loi qu'il annonce. */
.encart__titre {
  font-family: var(--font-ui);
  font-size: .72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-faint);
  margin: .9em 0 .8em;
}

/* Les alineas cites n'ont plus de filet a eux : l'encart le porte. */
.encart .para--citation {
  padding: 0;
  border-left: 0;
}

/* Un alinea cite hors encart ne devrait pas exister, mais si le cas se
   presente il garde l'ancienne forme plutot que de passer inapercu. */
.para--citation {
  padding: .2em 0 .2em 1em;
  border-left: 2px solid var(--line-fort);
}
/* L'expose des motifs etait en encre attenuee. C'est pourtant le seul
   passage du document ecrit en francais courant, et sur une proposition
   comme la 3106 il fait plusieurs pages : l'affaiblir revient a rendre
   illisible la partie la plus lisible. Encre normale. La distinction
   avec le dispositif reste portee par le titre de division. */
.para--expose { color: var(--ink); }

/* UNE ENTRÉE DE LISTE : RETRAIT PENDANT.

   Le document ouvre ses listes par un cadratin, « – les collégiens et
   lycéens ont connu... ». Ce tiret EST la puce : l'app n'en ajoute pas un
   second et ne le remplace pas, la règle d'or l'interdit. Ce qui manquait
   était le retrait. La deuxième ligne revenait à la marge et l'entrée de la
   liste se perdait au milieu du paragraphe précédent.

   `text-indent` négatif plus un retrait à gauche de la même valeur : le
   tiret sort dans la marge, le texte s'aligne sous lui. Rien n'est ajouté
   au document, seule la position change.

   La valeur suit le corps du texte (`em`) et non un pixel fixe : le réglage
   de taille de lecture va de 0,9 à 1,5 rem, et un retrait fixe se
   décrochait aux deux bouts. */
.para--puce {
  padding-inline-start: 1.6em;
  text-indent: -1.6em;
  /* Les entrées d'une même liste se suivent de près : elles forment un
     bloc, pas une succession de paragraphes. L'écart d'un paragraphe
     ordinaire les dispersait autant que le texte courant. */
  margin-bottom: .5em;
}
/* La dernière entrée d'une liste retrouve l'écart d'un paragraphe : c'est
   là que la liste se ferme et que le texte reprend. */
.para--puce:not(:has(+ .para--puce)) { margin-bottom: 1.05em; }

/* Le tiret lui-même, dans la couleur d'accent et en gras : c'est ce qui
   fait qu'une liste se repère d'un coup d'œil au lieu de se deviner. Le
   signe reste celui du document, seule sa couleur change, comme pour un
   marqueur d'alinéa. */
.puce { color: var(--accent); font-weight: 700; }

/* Une liste citée porte déjà le retrait de l'encart : les deux s'ajoutaient
   et la troisième ligne partait au milieu de la colonne. */
.para--citation.para--puce { padding-inline-start: 1.6em; }

/* ---------- Profondeur des alineas ---------- */

/* Quatre niveaux reels dans un article modificatif : le chapeau,
   l'instruction (« 1° Avant l'article 222-1... »), le texte insere
   (« Art. 222-1 A. – ... ») et les alineas de ce texte insere
   (« 1° Par le conjoint... »). Ils s'affichaient sur deux niveaux.
   Le retrait est calcule par l'analyseur, pose en data-profondeur. */
.texte { --pas: 1.6em; }
.para[data-profondeur="1"] { margin-left: calc(var(--pas) * 1); }
.para[data-profondeur="2"] { margin-left: calc(var(--pas) * 2); }
.para[data-profondeur="3"] { margin-left: calc(var(--pas) * 3); }
.para[data-profondeur="4"] { margin-left: calc(var(--pas) * 4); }
.para[data-profondeur="5"] { margin-left: calc(var(--pas) * 5); }

/* Les alineas d'une meme enumeration se suivent de pres ; l'air revient
   quand le texte remonte au niveau de l'article. */
.para[data-profondeur] { margin-bottom: .55em; }
.para[data-profondeur] + .para:not([data-profondeur]) { margin-top: 1.2em; }

/* Le marqueur « 1° », « a) », « II. » : balise autour, aucun caractere
   touche. Il porte le rythme de lecture d'un texte de loi. */
.marqueur {
  font-weight: 700;
  color: var(--accent-fonce);
  font-variant-numeric: tabular-nums;
}

/* Sur un telephone, cinq niveaux a 1,6 em mangeraient la colonne. */
@media (max-width: 720px) {
  .texte { --pas: .75em; }
}

.note-modif {
  font-family: var(--font-ui); font-size: .82rem; color: var(--ink-faint);
  margin: -.6em 0 1.3em; padding-left: 12px; border-left: 2px solid var(--line);
}

/* Un renvoi est une note dans le texte, pas une phrase : il passe en plus petit
   pour ne plus hacher la lecture. Le soulignement RESTE (WCAG 1.4.1 : la couleur
   ne doit jamais porter seule l'information), et on ne descend pas sous .85em,
   sous quoi un numero d'article devient penible a lire pour tout le monde. */
.ref {
  color: var(--accent-fonce);
  font-size: .88em;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px;
}
.ref:hover { background: var(--accent-pale); }

/* UN RENVOI QUI RESTE DANS LE DOCUMENT. Meme pointille que l'appel de note
   (`.ref--note`), et pour la meme raison : la marque ne doit pas dependre de
   la couleur seule (WCAG 1.4.1). Le pointille veut dire « on ne sort pas ». */
.ref--interne {
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}

/* LE TEXTE VISE N'EST PAS ECRIT ICI : il vient du chapeau de l'article, ou du
   dernier code nomme. Le lien reste un lien, le trait passe seulement au gris
   du texte attenue. Pas de pointille, il dit deja « interieur » juste au-
   dessus, et pas de troisieme couleur : le rouge et le violet sont pris.
   La phrase, elle, est dans le `title` ET dans l'aria-label (rendu.js). */
.ref--herite { text-decoration-color: var(--ink-faint); }

/* UNE ADRESSE WEB SE COUPE OÙ IL FAUT.

   Une adresse est un seul mot pour le navigateur : le paramètre
   « srsltid=AfmBOoqIdyKaGSz7z67lLtuYnam3g6CGlFL1BTyJCLLg5FiMkR8Iu8y1 » fait
   59 signes sans une espace et sortait de la colonne de lecture. La règle du
   débordement ne souffre aucune exception : la page ne défile
   jamais horizontalement, donc c'est le mot qui cède. */
.ref--url { overflow-wrap: anywhere; }

/* ---------- Tableaux ---------- */

/* Un tableau de loi (annexe, bareme, table de concordance pour l'outre-mer)
   est plus large que la colonne de lecture. Il DEFILE DANS SON CONTENEUR,
   la page ne defile jamais horizontalement : regle du debordement,
   verifiee au banc.

   Le conteneur porte tabindex="0" parce qu'une zone qui defile doit
   s'atteindre au clavier. L'anneau de focus lui vient des regles
   d'accessibilite communes, rien a redeclarer ici. */
.tableau {
  overflow-x: auto;
  max-width: 100%;
  margin: 1.6em 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  /* Le defilement tactile s'arrete au bord du tableau au lieu d'emporter
     la page avec lui. */
  overscroll-behavior-x: contain;
}

/* `width: auto` avec `min-width: 100%` : un petit tableau occupe toute la
   largeur, un grand replie d'abord son texte et ne deborde qu'ensuite.
   Avec `width: 100%` seul, une table de concordance a six colonnes se
   comprimait jusqu'a un mot par ligne au lieu de defiler. */
.tableau__grille {
  width: auto;
  min-width: 100%;
  border-collapse: collapse;
  font-family: var(--font-ui);
  /* Une grille de donnees, pas de la prose : un cran sous la taille de
     lecture, sinon trois colonnes ne tiennent nulle part. */
  font-size: .92em;
  line-height: 1.45;
}

.tableau__grille caption {
  caption-side: top;
  text-align: left;
  padding: .7em .9em;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-ui);
  font-weight: 700;
  color: var(--ink);
}

.tableau__grille th,
.tableau__grille td {
  padding: .55em .9em;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
  /* En dessous, le repli du texte devient illisible : la colonne s'arrete
     de retrecir et c'est le conteneur qui prend le relais. */
  min-width: 8ch;
}
.tableau__grille tr:last-child > * { border-bottom: 0; }

.tableau__grille thead th {
  background: var(--surface-2);
  border-bottom: 2px solid var(--line-fort);
  font-weight: 700;
  color: var(--ink);
}

/* Un en-tete de rangee tient sa ligne : un numero d'article ne se coupe
   pas en deux (« Article 222- » / « 1 »). */
.tableau__grille th[scope="row"] {
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink);
}

@media (max-width: 720px) {
  .tableau__grille { font-size: .86em; }
  .tableau__grille th,
  .tableau__grille td { padding: .5em .6em; min-width: 7ch; }
}

/* ---------- Un tableau proposé, dans un texte collé ---------- */

/* La proposition se pose SUR le passage, jamais en tête de document :
   un texte qui porte trois tableaux pose trois questions séparées, et
   chacune se décide seule. Le bloc porte `data-ajout` : la vérification
   d'intégrité et la copie retirent ces nœuds, son texte ne compte donc
   nulle part. */
.propo-tableau {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .5em;
  margin: 1.8em 0 .5em;
  padding: .5em .7em;
  border: 1px dashed var(--line-fort);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-family: var(--font-ui);
  font-size: .85rem;
  line-height: 1.4;
}
.propo-tableau__quoi {
  margin: 0 auto 0 0;
  color: var(--ink-soft);
}
.propo-tableau button {
  font: inherit;
  padding: .3em .8em;
  /* Cible tactile de 44 px, comme le reste (voir « Cibles tactiles »). */
  min-height: 44px;
  border: 1px solid var(--line-fort);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
}
.propo-tableau__oui {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 700;
}
.propo-tableau__oui:hover  { background: var(--accent-pale); }
.propo-tableau__non:hover  { background: var(--surface-2); }

/* Les lignes visées par une proposition en cours : on voit ce qui est en
   jeu avant de répondre. Le fond seul, sans filet ni retrait : ces lignes
   portent déjà la profondeur d'alinéa du texte et un retrait de plus
   décalerait le passage pendant qu'on le lit. */
.passage-tableau {
  background: var(--surface);
  box-shadow: 0 0 0 .35em var(--surface);
}

@media (max-width: 720px) {
  .propo-tableau { font-size: .8rem; }
  .propo-tableau__quoi { flex: 1 0 100%; }
}

/* ---------- Surlignage des mots-cles ----------
   LA COULEUR NE PORTE JAMAIS SEULE L'INFORMATION (WCAG 1.4.1) : le
   surlignage combine un FOND et un TRAIT. Le fond seul ne donne que
   1,28:1 sur la page en theme clair, invisible a qui ne distingue pas
   les rouges ; le trait donne 6,22:1, au-dessus des 3:1 demandes pour
   un indicateur non textuel (WCAG 1.4.11).

   AUCUN DECALAGE DE MISE EN PAGE : le retrait horizontal est repris par
   une marge negative de meme valeur, et le retrait vertical n'entre pas
   dans la hauteur de ligne d'un element en ligne. Le texte ne bouge pas
   d'un pixel quand on tape ou qu'on efface un terme, donc la position de
   lecture est conservee au re-rendu.

   DEUX ROLES, DEUX FORMES, ET ILS SE CUMULENT. La charte est monochrome :
   deux fonctions qui coexistent se separent par la FORME, jamais par une
   teinte de plus.
   · recherche : fond + trait. Passager, ce qu'on cherche a l'instant.
   · exergue   : cadre seul, sans fond. Durable, pose a la main, il part a
                 l'impression.
   Un passage marque par les deux porte simplement les deux : fond, trait et
   cadre. Aucune regle de priorite, les deux faits sont vrais en meme temps. */
.surlignage {
  color: inherit;                     /* le jaune par defaut de <mark> */
  border-radius: var(--radius-sm);
  padding: .08em .18em;
  margin: 0 -.18em;
  background: transparent;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* LA COULEUR NE PORTE JAMAIS SEULE L'INFORMATION (WCAG 1.4.1). Le fond seul
   ne donne que 1,28:1 sur la page en theme clair, invisible a qui ne
   distingue pas les rouges ; le trait donne 6,22:1, au-dessus des 3:1
   demandes pour un indicateur non textuel (WCAG 1.4.11). */
.surlignage--recherche {
  background: var(--surligne);
  box-shadow: inset 0 -2px 0 var(--surligne-trait);
}

/* Le cadre est un OUTLINE, jamais un border : un border ajoute une boite
   dans le flux et pousserait le texte a chaque frappe. Un outline se
   dessine par-dessus, sans rien deplacer. Meme raison que la marge negative
   ci-dessus. */
.surlignage--exergue {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* UN PASSAGE NOTE. Fond ET trait, comme la recherche, parce que la couleur
   ne porte jamais seule l'information (WCAG 1.4.1). Le trait est ici en
   HAUT et EN BAS : ca dessine une bande, la ou la recherche ne pose qu'un
   soulignement, et les deux ne se confondent pas dans une charte
   monochrome ou aucune teinte n'est disponible pour les separer.

   POURQUOI PAS UN FILET SUR LE COTE, qui aurait mieux dit « passage
   garde » : un surlignage a cheval sur un renvoi sort en DEUX balises
   (voir emettre(), rendu.js). Un filet de bord se redessinerait au milieu
   d'un mot a chaque coupure. Deux filets horizontaux, eux, se prolongent
   d'une balise a l'autre et la bande se lit d'un seul tenant.

   UN SEUL STYLE DE SURLIGNAGE, comme convenu : un passage note est un
   passage note, il n'y a pas de couleurs a choisir ni de code a retenir. */
.surlignage--passage {
  background: var(--surligne);
  box-shadow: inset 0 -2px 0 var(--surligne-trait),
              inset 0  2px 0 var(--surligne-trait);
  cursor: pointer;
  /* NI MARGE NEGATIVE NI RESPIRATION LATERALE, au contraire des deux autres
     roles. La bande ne decore que le haut et le bas : elle n'a aucun besoin
     de place a gauche et a droite, et le -.18em de `.surlignage` la faisait
     depasser du cadre. Mesure au banc de debordement, en 390 px : 353 px
     rendus dans 350 px sur un alinea marque en entier, dans les trois
     themes. Un mot cherche ne le montrait pas, parce qu'il ne finit jamais
     au bord de la ligne ; un passage note couvre l'alinea entier, donc si. */
  padding-left: 0; padding-right: 0;
  margin-left: 0; margin-right: 0;
  /* ET AUCUN ARRONDI. Avec le rayon de `.surlignage`, l'ombre interne suit
     les coins et se referme aux deux bouts : la marque ressemblait alors a
     un CADRE, donc au role `exergue`, qui en est un. Les deux se
     confondaient. A rayon nul, les deux filets sont droits, ils se
     prolongent d'un morceau au suivant, et la bande se lit d'un seul
     tenant meme quand un renvoi la coupe en deux balises. */
  border-radius: 0;
}

/* Un renvoi surligne garde sa couleur de lien : deux informations
   differentes, deux signes qui cohabitent. */
.ref .surlignage--recherche { box-shadow: inset 0 -2px 0 var(--accent-fonce); }
.ref .surlignage--exergue { outline-color: var(--accent-fonce); }
.ref .surlignage--passage {
  box-shadow: inset 0 -2px 0 var(--accent-fonce),
              inset 0  2px 0 var(--accent-fonce);
}

/* LA NOTE VISEE PAR LA PROPOSITION DE RETRAIT. Tous les morceaux d'une
   meme note s'allument ensemble : une note coupee par un renvoi sort en
   plusieurs balises, et n'en marquer qu'une donnerait a croire qu'on ne
   retire que celle-la. Le trait s'epaissit, il ne change pas de teinte :
   la charte est monochrome et le signe doit tenir en niveaux de gris. */
.surlignage--passage.passage--vise {
  box-shadow: inset 0 -3px 0 var(--accent-fonce),
              inset 0  3px 0 var(--accent-fonce);
}

/* LA PROPOSITION DE RETRAIT. Un vrai bouton pose dans le document, jamais
   une boite de dialogue : on doit pouvoir relire le passage pendant qu'on
   decide. Il porte le MOT « Retirer », jamais une croix seule. */
.retirer-passage {
  position: absolute;
  z-index: var(--z-flottant);
  box-shadow: var(--shadow);
  white-space: nowrap;
}

/* CUMUL AVEC UNE RECHERCHE. Les deux roles sont dans deux familles
   distinctes, donc ils se cumulent sur les memes caracteres et la balise
   porte les deux classes. L'ordre de declaration fait gagner la bande du
   passage sur le soulignement de la recherche : le fond, lui, est le meme
   jeton dans les deux cas, si bien que le morceau reste marque des deux
   points de vue et qu'aucun des deux ne disparait. */

/* ---------- Reperes lexicaux ---------- */

/* LA CHARTE EST MONOCHROME : les reperes ne peuvent pas se distinguer par
   cinq teintes. Ils se distinguent par le TRAIT, et le trait porte seul
   l'information (WCAG 1.4.1) : un plein pour l'obligation, un pointille
   pour la faculte. C'est lisible en niveaux de gris et pour qui ne
   distingue pas les rouges.

   Le soulignement se fait en text-decoration et non en box-shadow : il
   suit le mot quand la ligne se coupe, ce qu'un fond inset ne fait pas.
   Deux pixels, la ou un renvoi en met un : les deux signes ne se
   confondent pas, et le renvoi reste en plus petit corps. */
.surlignage--obligation,
.surlignage--faculte,
.surlignage--condition,
.surlignage--duree,
.surlignage--montant,
.surlignage--negation {
  text-decoration-line: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
  text-decoration-color: var(--repere-regle);
}

/* Les bornes passent en violet. Le style de trait reste ce qui distingue,
   la couleur ne fait que dire de quelle famille on parle. */
.surlignage--condition,
.surlignage--duree,
.surlignage--montant { text-decoration-color: var(--repere-borne); }

/* L'obligation prend la graisse en plus du trait plein. Deux signes
   valent mieux qu'un sur ce qui est le plus mal lu du texte. */
.surlignage--obligation {
  text-decoration-style: solid;
  font-weight: 600;
}

/* La faculte reste en graisse normale : ce qui est facultatif n'a pas a
   peser autant que ce qui est obligatoire. */
.surlignage--faculte {
  text-decoration-style: dotted;
}

/* Le connecteur de condition prend le tirete. Trois styles de trait pour
   trois reperes : plein, pointille, tirete. Le tirete se distingue du
   pointille par la longueur du trait, pas par la couleur, et reste lisible
   en niveaux de gris.

   Pas de graisse ici : « lorsque » et « sauf » reviennent bien plus souvent
   que « doit », et les mettre en gras noircirait la page. */
.surlignage--condition {
  text-decoration-style: dashed;
}

/* Delai et montant partagent une forme : c'est un seul reglage, et les deux
   disent la meme chose, une quantite chiffree. Les deux roles restent
   distincts pour le compte et pour le libelle, pas pour l'oeil. */
.surlignage--duree,
.surlignage--montant {
  text-decoration-style: double;
}

/* La negation change d'axe : un trait DESSUS et DESSOUS, la ou les autres
   n'en ont qu'un. Cinq styles de soulignement ne se distinguent plus, et une
   negation renverse le sens d'une phrase, ce qui merite une forme a part.
   Le trait passe a 1 px : deux traits de 2 px noirciraient le mot.

   PAS DE BARRE : un texte de loi barre se lirait comme un texte supprime.
   L'app n'enleve jamais rien et ne doit jamais en avoir l'air. */
.surlignage--negation {
  text-decoration-line: underline overline;
  text-decoration-style: solid;
  text-decoration-thickness: 1px;
}

/* Dans un renvoi, le soulignement du lien et celui du repere se
   superposeraient au meme endroit. Le repere descend. */
.ref .surlignage--obligation,
.ref .surlignage--faculte,
.ref .surlignage--condition,
.ref .surlignage--duree,
.ref .surlignage--montant,
.ref .surlignage--negation { text-underline-offset: 6px; }

/* ---------- Indicateur d'attente ---------- */

/* Lire, rendre et verifier un texte de 250 000 signes prend une seconde et
   demie. role="status" annonce l'etat aux lectrices d'ecran sans voler le
   focus ; le texte porte seul le sens, la barre est decorative. */
.attente {
  display: flex; align-items: center; gap: 12px;
  margin: 16px 0 0;
  font-family: var(--font-ui);
  font-size: .9rem;
  color: var(--ink-soft);
}
.attente__barre {
  position: relative; flex: 0 0 auto;
  width: 120px; height: 6px;
  background: var(--surface-2);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.attente__barre::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0;
  width: 40%;
  background: var(--accent);
  border-radius: var(--r-pill);
  animation: attente-va 1.1s var(--ease) infinite alternate;
}
@keyframes attente-va { from { left: 0; } to { left: 60%; } }

/* Sans animation, une barre figee a 60 % ressemble a un blocage :
   on la remplit, elle dit « ca travaille » sans bouger. */
@media (prefers-reduced-motion: reduce) {
  .attente__barre::after { width: 100%; left: 0; }
}

/* ---------- Page de garde ---------- */

/* Le gabarit officiel d'un texte déposé : numéro, chambre, législature,
   date, nature, intitulé, mention de renvoi, signataires.
   L'ORDRE DU SOURCE est conservé dans le DOM, seule la hiérarchie
   typographique change ici. Aucun `order` en flex : ça casserait
   l'ordre de lecture au clavier et à la synthèse vocale. */
.garde {
  margin: 0 0 3.2em;
  padding-bottom: 1.8em;
  border-bottom: 2px solid var(--accent);
}

/* Numéro de dépôt, chambre, législature, date : le bloc d'identification,
   nécessaire mais secondaire. Petit, gris, en capitales. */
.garde__ident {
  font-family: var(--font-ui);
  font-size: .82rem;
  line-height: 1.55;
  color: var(--ink-faint);
  margin: 0 0 1.1em;
}
.garde__ligne { margin: 0 0 .25em; }

/* Le filet décoratif « _____ » du document source. Il reste affiché :
   retirer un caractère du source est hors de question. Couleur conforme,
   donc pas d'exception à déclarer au banc d'accessibilité. */
.garde__filet {
  font-family: var(--font-ui);
  color: var(--ink-faint);
  margin: .1em 0 1em;
  letter-spacing: -.05em;
}

/* Marque de pagination « – 1 – » du document imprimé d'origine.
   Discrète et alignée à droite, jamais supprimée. */
.texte > .pagination:first-child { margin-top: 0; }
.pagination {
  font-family: var(--font-ui);
  font-size: .72rem;
  letter-spacing: .1em;
  color: var(--ink-faint);
  text-align: right;
  margin: 2.2em 0 .6em;
}

/* « PROPOSITION DE LOI » : le surtitre qui annonce la nature du texte. */
.garde__nature {
  font-family: var(--font-ui);
  font-size: .8rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 .55em;
}

/* L'intitulé : le vrai titre du texte, et le h1 du document. */
.garde__titre {
  font-family: var(--font-lecture);
  font-size: clamp(1.45rem, 1.05rem + 1.7vw, 2.05rem);
  line-height: 1.22;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 .85em;
  overflow-wrap: break-word;
}
.garde__titre-l { display: inline; }

/* La mention « (Renvoyée à la commission…) » : utile, jamais centrale. */
.garde__renvoi {
  font-family: var(--font-ui);
  font-size: .84rem;
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0 0 1.3em;
  padding-left: 14px;
  border-left: 2px solid var(--line);
}

/* ---------- Pied officiel ---------- */

/* La mention de délibération et la signature du président de la chambre,
   en fin de texte adopté. Il répond visuellement à la page de garde :
   même filet accentué, de l'autre côté du texte. */
.pied {
  margin: 3.2em 0 0;
  padding-top: 1.8em;
  border-top: 2px solid var(--accent);
  font-family: var(--font-ui);
  font-size: .84rem;
  line-height: 1.6;
  color: var(--ink-soft);
}
.pied__delibere  { margin: 0 0 1.1em; }
.pied__qualite   { margin: 0 0 .25em; }
.pied__signature { margin: 0; font-weight: 600; color: var(--ink); }
.pied__ligne     { margin: 0 0 .25em; }

/* Le résidu de collage : « Description : LOGO », le texte alternatif
   d'une image emportée par le copier-coller. Il reste affiché, comme le
   filet : retirer un caractère du source est hors de question. Discret
   au maximum, c'est du bruit de collage, pas du texte de loi. */
.garde__residu {
  font-family: var(--font-ui);
  font-size: .72rem;
  color: var(--ink-faint);
  margin: 0 0 .8em;
}

/* « (Procédure accélérée) » : une mention de circuit, pas un titre. */
.garde__procedure {
  font-family: var(--font-ui);
  font-size: .8rem;
  color: var(--ink-soft);
  margin: 0 0 1.3em;
}

/* La chaîne de transmission d'un texte adopté par l'autre chambre :
   autorité, « À », destinataire. L'ORDRE DU SOURCE est conservé dans le
   DOM. Aucun `order` en flex ici non plus : ça casserait l'ordre de
   lecture au clavier et à la synthèse vocale. */
.garde__chaine {
  font-family: var(--font-ui);
  font-size: .82rem;
  line-height: 1.6;
  letter-spacing: .04em;
  color: var(--ink-soft);
  text-align: center;
  margin: 0 0 1.3em;
  padding: 1em 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.garde__chaine-l { margin: 0 0 .2em; }

/* « Le Sénat a adopté, en première lecture… » : la seule phrase de la
   page de garde qui se lit comme du texte suivi. Encre normale. */
.garde__adoption {
  font-family: var(--font-lecture);
  font-size: .95rem;
  line-height: 1.55;
  color: var(--ink);
  margin: 0 0 1.2em;
}

/* « Voir les numéros : Sénat : 801, 834… » : le renvoi au dossier
   parlementaire. Utile pour retrouver le texte, jamais central. */
.garde__numeros {
  font-family: var(--font-ui);
  font-size: .78rem;
  line-height: 1.5;
  color: var(--ink-faint);
  margin: 0 0 1.1em;
}
.garde__numeros-l { margin: 0 0 .2em; }

/* Les signataires, repliés : quarante noms en tête repoussent le texte.
   Le contenu d'un <details> fermé reste dans le DOM, donc la
   vérification d'intégrité continue de le lire. */
.garde__par { font-family: var(--font-ui); font-size: .86rem; }
.garde__par-tete {
  display: flex; align-items: center; gap: .6em; flex-wrap: wrap;
  min-height: 44px;           /* cible tactile, règle du débordement */
  padding: 4px 0;
  cursor: pointer;
  color: var(--ink-soft);
  list-style: none;
}
.garde__par-tete::-webkit-details-marker { display: none; }
.garde__par-tete::after {
  content: '';
  width: 0; height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform .15s var(--ease);
}
.garde__par[open] .garde__par-tete::after { transform: rotate(90deg); }
.garde__compte {
  font-size: .78rem;
  color: var(--ink-faint);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 1px 9px;
}
.garde__par-corps {
  line-height: 1.6;
  color: var(--ink-faint);
  padding: .5em 0 .2em 14px;
  border-left: 2px solid var(--line);
}
.garde__signataire { margin: 0 0 .4em; }

/* ---------- Page de garde d'un rapport d'information ----------
   Le gabarit du rapport, qui n'a ni « PROPOSITION DE LOI » ni
   « présentée par ». Trois niveaux de lecture : la commission qui
   produit, l'intitulé de la mission, puis les mentions de service. */

/* Le fondement réglementaire, et la phrase qui annonce l'intitulé.
   Deux mentions de service : elles se lisent, elles ne se retiennent pas. */
.garde__fondement,
.garde__objet {
  font-family: var(--font-ui);
  font-size: .84rem;
  line-height: 1.55;
  color: var(--ink-soft);
  margin: 0 0 .6em;
}

/* La commission qui produit le rapport : l'équivalent de l'auteur d'une
   proposition de loi, et à ce titre elle se lit avant le titre. */
.garde__commission {
  font-family: var(--font-ui);
  font-size: .88rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--ink);
  margin: .3em 0 .9em;
}

/* ============================================================
   L'ENVELOPPE D'UN DÉCRET
   ============================================================

   Un décret ne partage rien avec un texte parlementaire, sauf son titre.
   Six familles, dans l'ordre où elles arrivent : identifiants, mobilier,
   notice, autorité, visas, formule. Puis la signature, en pied.

   La hiérarchie tient en une phrase : la NOTICE se lit, les VISAS se
   parcourent, le reste se consulte. Les corps le disent. */

/* Les identifiants de publication : NOR, ELI, JORF. Ce qui permet de
   retrouver le texte ailleurs, donc utile mais jamais lu d'affilée. */
.garde__identifiants {
  font-family: var(--font-ui);
  font-size: .78rem;
  color: var(--ink-faint);
  margin: 0 0 .9em;
}
.garde__identifiants-l { margin: 0 0 .15em; overflow-wrap: anywhere; }

/* LE MOBILIER DU SITE. Il n'est pas retiré du document, la règle d'or
   l'interdit. Il est mis à sa place : plus petit que les identifiants,
   en italique, sans jamais disparaître. Ce qui n'est pas le texte cesse
   de se lire comme le texte. */
.garde__mobilier {
  font-family: var(--font-ui);
  font-size: .72rem;
  font-style: italic;
  color: var(--ink-faint);
  margin: 0 0 .9em;
}
.garde__mobilier-l { margin: 0 0 .1em; }

/* LA NOTICE, le bloc le plus utile de l'enveloppe et le seul écrit pour
   être lu : « Objet : le présent décret vise à… » résume le texte entier
   en une phrase. Elle a donc le corps du texte courant et un fond, pour
   se détacher du dispositif sans passer pour lui. */
.garde__notice {
  font-family: var(--font-ui);
  font-size: .88rem;
  line-height: 1.55;
  color: var(--ink);
  background: var(--surface-2);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin: 0 0 1.2em;
}
.garde__notice-l { margin: 0 0 .5em; }
.garde__notice-l:last-child { margin-bottom: 0; }

/* L'autorité qui prend le texte. Deux lignes, en encre normale : c'est
   du texte officiel, pas du service. */
.garde__autorite {
  font-family: var(--font-ui);
  font-size: .88rem;
  color: var(--ink);
  margin: 0 0 .3em;
}

/* LES VISAS. Dix lignes qui se parcourent, jamais qui se lisent : chacune
   cite un texte, et ces citations sont déjà cliquables. Le filet à gauche
   les tient ensemble et dit qu'elles forment une liste, sans qu'on ait à
   ajouter une puce à un texte qui n'en a pas. */
.garde__visas {
  border-left: 2px solid var(--line-fort);
  padding-left: 1em;
  margin: .6em 0 1.1em;
}
.garde__visa {
  font-family: var(--font-ui);
  font-size: .84rem;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0 0 .35em;
}

/* « Décrète : » ouvre le dispositif. Une seule ligne, et elle sépare
   l'enveloppe du texte : c'est le seul endroit de l'entête qui mérite du
   poids. */
.garde__formule {
  font-family: var(--font-ui);
  font-size: .95rem;
  font-weight: 700;
  color: var(--ink);
  margin: 1.1em 0 .4em;
}

/* La signature, en pied : « Fait le… », puis les ministres chargés de
   l'exécution, qualité et nom en alternance. L'alternance vient du
   document, on ne la reconstruit pas. */
.pied__signature {
  font-family: var(--font-ui);
  font-size: .86rem;
  color: var(--ink-soft);
  margin: 0 0 .25em;
}
.pied__mobilier {
  font-family: var(--font-ui);
  font-size: .72rem;
  font-style: italic;
  color: var(--ink-faint);
  margin: 0 0 .1em;
}

/* LE TOME. Un rapport de commission d'enquête est toujours en deux tomes :
   le rapport, puis les comptes rendus des auditions. La mention arrive après
   la double signature et avant le renvoi aux numéros de dossier.

   Traitée comme une étiquette et non comme un titre : elle dit dans quelle
   partie de l'ensemble on se trouve, pas de quoi le texte parle. Filet au
   dessus pour la détacher des signatures, corps réduit, capitales espacées,
   comme les autres mentions de service de la page de garde. */
.garde__tome {
  font-family: var(--font-ui);
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border-top: 1px solid var(--line);
  padding-top: .8em;
  margin: 1em 0 .8em;
}
.garde__tome-l { margin: 0 0 .15em; }

/* La composition de la mission : une seule ligne source, quinze noms.
   Repliée pour la même raison que les signataires. Le contenu d'un
   <details> fermé reste dans le DOM, donc la vérification d'intégrité
   continue de le lire. */
.garde__composition { font-family: var(--font-ui); font-size: .86rem; }
.garde__composition-tete {
  display: flex; align-items: center; gap: .6em; flex-wrap: wrap;
  min-height: 44px;           /* cible tactile, règle du débordement */
  padding: 4px 0;
  cursor: pointer;
  color: var(--ink-soft);
  list-style: none;
}
.garde__composition-tete::-webkit-details-marker { display: none; }
.garde__composition-tete::after {
  content: '';
  width: 0; height: 0;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform .15s var(--ease);
}
.garde__composition[open] .garde__composition-tete::after { transform: rotate(90deg); }
.garde__composition-l {
  line-height: 1.6;
  color: var(--ink-faint);
  margin: 0;
  padding: .5em 0 .2em 14px;
  border-left: 2px solid var(--line);
}

/* ---------- Bandeau du type de document ---------- */

/* Le type est DETECTE a l'import, jamais devine en silence : il se lit
   au-dessus du texte et se corrige d'un bouton. Meme boite que le bandeau
   d'integrite, ton plus discret : il informe, il n'alerte pas. */

.type-doc {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-family: var(--font-ui); font-size: .85rem;
  padding: 9px 14px; border-radius: var(--radius);
  border: 1px dashed var(--line); background: transparent;
  color: var(--ink-soft); margin-bottom: 10px;
  /* Voir « LA LARGEUR DU TEXTE » dans app.js : un bandeau qui annonce le texte
     s'arrete ou le texte s'arrete. `--colonne-px` est la largeur RENDUE de
     `.texte`, mesuree en JS, parce que la colonne est ecrite en `ch` et que
     les deux boites n'ont pas la meme police. Sans la variable (avant le
     premier rendu), on retombe sur la largeur du conteneur. */
  max-width: var(--colonne-px, none);
}
.type-doc__signe { color: var(--ink-faint); flex: 0 0 auto; }

/* CE QUE L'APP DIT DU TEXTE : LE SIGNE ET LA PHRASE, D'UN SEUL TENANT.

   TROIS ETATS A TENIR AVEC LA MEME REGLE. La phrase est courte quand le
   document est reconnu (« Reconnu comme un decret. »), longue quand il ne
   l'est pas (« Ce texte ne ressemble ni a un texte de loi ni a un rapport
   parlementaire. Il est affiche tel quel, sans mise en forme. »), et le
   bandeau porte une deuxieme commande quand une correction manuelle est
   posee. Aucun point de rupture ecrit a la main ne couvre les trois.

   POURQUOI UN CONTENEUR, ET PAS DEUX ELEMENTS COTE A COTE. Separes, le signe
   et la phrase negocient leur place chacun de leur cote. La phrase a d'abord
   porte `flex: 1 1 auto` : sa base valant la largeur de son contenu, le
   conteneur en `flex-wrap: wrap` la renvoyait a la ligne AVANT de la
   comprimer, et le bandeau se cassait en trois sur le cas non reconnu.
   Elle a ensuite porte `flex: 1 1 0` avec `min-width: 0` : la base nulle ne
   demandant rien, elle restait sur la rangee, mais le bouton ne se repliait
   alors JAMAIS et elle descendait sous la largeur de son propre contenu. A
   390 px, 35 px de boite pour 55 px de contenu minimum : la phrase debordait
   sans se couper. Un defaut rare echange contre un defaut permanent.

   REUNIS, ILS PORTENT UNE SEULE BASE, et c'est elle qui decide. 240 px ne
   tiennent pas a cote d'un bouton de 281 px sur une colonne de 335 : le
   bouton passe dessous, la phrase garde toute la ligne et se coupe dedans.
   Au large, les deux tiennent et le bandeau reste sur une ligne. `min-width:
   0` reste necessaire sur la phrase pour qu'elle se coupe a l'interieur du
   conteneur au lieu de le pousser. */
.type-doc__dit {
  flex: 1 1 240px; min-width: 0;
  display: flex; align-items: center; gap: 10px;
}
#texteType { min-width: 0; }

/* LA COMMANDE DE CORRECTION EST UN BOUTON, ET ELLE EN A L'AIR.

   Elle portait `.btn--discret` : ni cadre, ni fond, ni soulignement, juste du
   texte en gras dans un bandeau deja gris. Rien ne disait qu'on pouvait
   cliquer. Elle prend le `.btn` ordinaire, filet compris, en gardant le
   plancher de 44 px de cible tactile du bouton. */
/* Le bouton reste a droite quand la ligne est large, et passe dessous
   quand elle ne tient plus : `margin-inline-start: auto` sur un flex qui
   se replie garde les deux comportements sans point de rupture. */
.type-doc .btn { margin-inline-start: auto; }

/* RIEN N'A ÉTÉ RECONNU. Le bandeau passe du filet pointillé discret au trait
   plein dans la couleur d'accent : c'est le seul cas où l'app dit qu'elle ne
   sait pas, et il doit se distinguer du cas ordinaire au premier regard.

   Pas de fond plein ni d'icône d'alerte : le texte s'affiche quand même et
   rien n'est cassé. C'est une mise au point, pas un incident. */
.type-doc[data-type="inconnu"] {
  border-style: solid;
  border-color: var(--accent);
  color: var(--ink);
}
.type-doc[data-type="inconnu"] .type-doc__signe { color: var(--accent); }

@media print { .type-doc { display: none; } }

/* ---------- Bandeau d'intégrité ---------- */

.integrite {
  /* Meme regle que `.type-doc` juste au-dessus, meme raison. */
  max-width: var(--colonne-px, none);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-family: var(--font-ui); font-size: .85rem;
  padding: 11px 14px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-soft); margin-bottom: 26px;
}
.integrite--alerte { border-color: var(--accent); background: var(--accent-pale); color: var(--accent-fonce); }

/* LA MENTION GENERALE, sous le bandeau d'integrite. § 10.1 de la revue
   juridique du 6 septembre 2026.

   REPLIEE PAR DEFAUT, et c'est un arbitrage. Ouverte, elle pose trois
   paragraphes entre la personne et le texte qu'elle vient lire, a chaque
   ouverture de chaque document : au troisieme texte elle ne se lit plus, elle
   se saute. Repliee, sa PHRASE DE TETE reste lisible en permanence, et c'est
   elle qui porte l'essentiel (« où elle peut se tromper »). Le detail est a un
   clic. Un `<details>` natif : il s'ouvre au clavier, il s'imprime ouvert, et
   la recherche du navigateur le trouve.

   ELLE REPREND LE CALIBRE DU BANDEAU juste au-dessus (meme largeur de colonne,
   meme famille, meme filet) : les deux disent ce que l'app garantit et ce
   qu'elle ne garantit pas, ils se lisent comme une paire. Pas de couleur
   d'alerte : elle ne previent de rien, elle situe. */
.reserve-generale {
  max-width: var(--colonne-px, none);
  font-family: var(--font-ui);
  font-size: .85rem;
  margin: -14px 0 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-soft);
}
.reserve-generale__tete {
  padding: 10px 14px;
  cursor: pointer;
  font-weight: 600;
  color: var(--ink-soft);
  /* La cible tactile : 44 px avec le rembourrage, marqueur compris. */
  min-height: 44px;
  display: flex; align-items: center;
}
.reserve-generale__tete:hover { color: var(--ink); }
.reserve-generale[open] .reserve-generale__tete {
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}
.reserve-generale__corps { padding: 4px 14px 12px; }
.reserve-generale__corps p { margin: .7em 0; line-height: 1.55; }
.reserve-generale__corps a { color: var(--accent-fonce); }

/* A L'IMPRESSION ELLE SORT OUVERTE. Une feuille imprimee circule sans son
   contexte : c'est la que la reserve compte le plus, et c'est la que personne
   ne peut plus cliquer. L'OUVERTURE SE FAIT EN JS (`avantImpression`, dans
   impression.js), pas ici : aucune regle CSS n'ouvre un <details> de facon
   fiable dans les trois moteurs, c'est deja la lecon des signataires. Ne
   reste ici que la mise en page de la feuille. */
@media print {
  .reserve-generale {
    background: none;
    border: 1px solid #999;
    break-inside: avoid;
  }
  .reserve-generale__tete { list-style: none; }
  .reserve-generale__tete::-webkit-details-marker { display: none; }
}

/* ---------- Panneau de réglages ---------- */

/* Les reglages : le positionnement, la largeur et la hauteur bornee viennent
   de `.panneau--sous-entete`. Ne reste ici que la mise en page de ses
   reglages. */
/* DEUX BLOCS, pas huit cases a plat. Le premier ne touche qu'a la forme du
   texte, le second a ce que l'app pose par-dessus. Melangees, les cases se
   lisaient comme une liste et « Obligation ou faculte » avait l'air d'un
   reglage de police. */
/* PANNEAU PLUS TASSE, seconde passe, 6 septembre 2026. Les valeurs de la
   premiere passe sont gardees en commentaire de chaque regle. Rien n'est
   descendu sous les seuils de cible tactile : le gain vient des ecarts, pas
   de la taille des commandes. */
.reglages__bloc + .reglages__bloc {
  margin-top: 12px;      /* etait 14 */
  padding-top: 12px;     /* etait 14 */
  border-top: 1px solid var(--line);
}
.reglages__titre {
  font-family: var(--font-ui);
  font-size: .78rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-soft);
  margin: 0 0 8px;       /* etait 10 */
}

/* LA LIGNE DU TITRE PORTE AUSSI LA REMISE A ZERO. Le bouton se range a droite,
   sur la ligne qui existe deja : il ne coute aucune hauteur. La marge basse du
   titre passe sur la rangee, sinon le bouton s'alignerait dessus et laisserait
   un decrochage. */
.reglages__tete {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin: 0 0 8px;
}
.reglages__tete .reglages__titre { margin: 0; }
/* Meme gabarit que les bascules du panneau : c'est une commande du meme rang,
   et elle doit tenir sur la ligne d'un titre. Le plancher de 34 px est celui
   du panneau, voir `.groupe-btn .btn`. */
.reglages__defaut {
  flex: 0 0 auto;
  padding: 5px 10px; font-size: .82rem; min-height: 34px;
}

/* LA VALEUR DU CURSEUR, dans son libelle. Encre d'interface pleine et chiffres
   tabulaires : sans eux, passer de 9 a 10 decale le mot qui precede. Elle n'est
   ni en capitales ni espacee comme le libelle : c'est une donnee qui change, pas
   une etiquette. */
.reglage__valeur {
  margin-left: .5em;
  color: var(--ink);
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

/* Panneau plus serre : la gouttiere passe de 18 a 12 px et la case minimale
   de 210 a 180, ce qui range les quatre curseurs sur deux rangees au lieu de
   quatre cases larges. Les libelles perdent 3 px de marge basse. */
.reglages__grille { display: grid; gap: 10px 14px; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); align-items: start; }   /* etait 12px 16px */
.reglage__libelle { display: block; font-size: .76rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-faint); margin-bottom: 4px; }   /* etait 5px */
.reglage input[type="range"] { width: 100%; accent-color: var(--accent); min-height: 30px; }
.groupe-btn { display: flex; gap: 5px; flex-wrap: wrap; }   /* etait 6px */
/* 34 px et non 40 : le panneau tient sur moins de hauteur, et la cible
   reste tres au-dessus des 24 px demandes (WCAG 2.5.8). La hauteur ne bouge
   PAS a la seconde passe : c'est le plancher de cible tactile du panneau, et
   le rectangle arrondi permet de reprendre le gain sur le rembourrage
   horizontal, ou il ne coute rien. */
.groupe-btn .btn { padding: 5px 10px; font-size: .82rem; min-height: 34px; }   /* rembourrage etait 5px 11px */

/* LES AJOUTS SE RANGENT EN DEUX COLONNES. Empiles sur toute la largeur, les
   cinq reglages de cette section faisaient une colonne d'un metre de haut,
   et la section avait l'air d'une liste sans fin. Deux colonnes larges : la
   phrase explicative garde de quoi tenir sur deux lignes, et la section
   descend de moitie. */
.reglages__grille--ajouts { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.reglages__grille--ajouts .reglage__note { max-width: none; }

/* LA PHRASE EST SA PROPRE LEGENDE : le mot qui nomme le repere porte la
   marque du repere. On comprend la forme sans avoir a la chercher dans le
   texte, et il n'y a pas de legende a tenir a jour ailleurs.

   Le trait se cale sur le corps de la phrase, plus petit que celui du texte
   de loi : 2 px sous des lettres de .78 rem ecraseraient le mot. La graisse
   de l'obligation reste, elle porte l'information autant que le trait. */
/* UNE DESCRIPTION PAR FAMILLE DE DOCUMENT.

   Certains réglages n'agissent pas de la même façon selon qu'on lit une loi
   ou un rapport. « Annotations de l'app » décrivait des étiquettes d'ajout et
   de suppression qui ne s'affichent plus sur un rapport : la phrase promettait
   des marques introuvables.

   Le réglage reste affiché, seule sa description change. Un réglage qui
   disparaît après qu'on l'a posé fait chercher où il est passé, et celui-ci
   agit dans les deux cas, sur l'intitulé des encarts.

   `data-famille` est posé à la racine par app.js. Par défaut, sans famille
   connue (l'écran d'accueil), c'est la description normative qui vaut. */
[data-pour] { display: none; }
[data-pour="normatif"] { display: block; }
:root[data-famille="rapport"] [data-pour="normatif"] { display: none; }
:root[data-famille="rapport"] [data-pour="rapport"]  { display: block; }

.reglage__note .surlignage {
  padding: 0; margin: 0;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

/* Les etiquettes citees dans une phrase de reglage descendent d'un cran :
   a ce corps-la, leur boite depassait de la ligne. */
.reglage__note .op {
  font-size: .58rem;
  margin: 0 .15em;
  vertical-align: .05em;
}
.reglage__note .surlignage--negation { text-decoration-thickness: 1px; }

/* Un reglage a rangee de boutons, ou porteur d'une phrase a lire, demande
   deux colonnes : cinq boutons de police ou une phrase entiere se cassent en
   six lignes dans une case de 180 px. */
.reglage--large { grid-column: span 2; }
@media (max-width: 560px) { .reglage--large { grid-column: auto; } }

/* La phrase appartient au reglage : elle dit ce que le repere fait, et ce
   qu'il ne fait PAS, sous les boutons qui l'activent. Encre attenuee, corps
   de l'interface, jamais en capitales : c'est une phrase a lire, pas une
   etiquette. */
.reglage__note {
  margin: 5px 0 0;       /* etait 6 */
  font-family: var(--font-ui);
  font-size: .78rem;
  line-height: 1.35;     /* etait 1.4 */
  color: var(--ink-faint);
  max-width: 56ch;
}

/* ---------- Retour en haut ---------- */

/* Un texte de loi fait des dizaines d'ecrans de haut. Le bouton apparait
   apres 600 px de defilement et rend la tete du document en un clic.
   visibility: hidden autant qu'opacity : un bouton invisible ne doit pas
   se prendre le focus au clavier. */
.retour-haut {
  position: fixed;
  right: 20px; bottom: 20px;
  z-index: 25;
  width: 44px; height: 44px;          /* cible tactile, regle du debordement */
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line-fort);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  opacity: 0; visibility: hidden;
  transform: translateY(10px);
  transition: opacity .2s var(--ease), transform .2s var(--ease), visibility .2s;
}
.retour-haut--visible { opacity: 1; visibility: visible; transform: none; }
.retour-haut:hover { border-color: var(--accent); color: var(--accent); }

/* Il ne doit pas chevaucher le message qui s'affiche en bas de l'ecran. */
.retour-haut { bottom: 74px; }
@media (min-width: 721px) { .retour-haut { bottom: 20px; } }

/* Quand la barre de selection est posee, elle occupe deja ce bas d'ecran et
   le retour-haut vient se ranger a cote d'elle, sur la meme ligne. Le calcul :
   la barre fait 6 + 44 + 6 + 2 = 58 px de haut et part de 20 px, son milieu
   est donc a 49 px ; le bouton fait 44 px, il commence a 49 - 22 = 27 px.
   `:has()` fait le lien sans passer par une classe posee en JS. Un navigateur
   qui ne le connait pas garde les 74 px, le bouton reste utilisable. */
@media (max-width: 720px) {
  body:has(.barre-selection--posee) .retour-haut { bottom: 27px; right: 16px; }
}

/* ---------- Toast ---------- */

/* Le toast passe au-dessus de tout, SAUF d'un panneau modal : voir
   js/lib/toast.js, la limite est mesuree et documentee la-bas. */
#toast {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%) translateY(60px);
  background: var(--ink); color: var(--bg); padding: 11px 18px; border-radius: var(--radius-sm);
  font-weight: 700; font-size: .9rem; box-shadow: var(--shadow); z-index: var(--z-toast);
  opacity: 0; pointer-events: none; transition: transform .25s var(--ease), opacity .25s var(--ease);
  max-width: min(90vw, 460px); text-align: center;
}
#toast.show { transform: translateX(-50%) translateY(0); opacity: 1; }
#toast.toast--danger { background: var(--accent); color: var(--sur-accent); }

/* ---------- Pied du site ----------

   IL S'APPELAIT `.pied`, COMME LE PIED OFFICIEL D'UN TEXTE DE LOI. Les deux
   sont des `<footer class="pied">`, l'un posé par index.html, l'autre par
   `rendu.js` § « Pied officiel ». Même sélecteur, même spécificité : la
   dernière règle du fichier gagnait, et le pied officiel d'un texte adopté
   héritait du filet fin du site à la place de son filet accentué. Le pied du
   site s'appelle donc `.pied-site`, et `.pied` est rendu à la loi.

   Fond `--surface-2` et non une encre pleine : ce pied est présent aussi
   pendant la lecture, et un bandeau sombre en bas d'un document long gêne
   autant en thème clair qu'en thème sombre. Les trois thèmes le suivent seuls,
   puisque tout passe par les tokens. */

.pied-site {
  margin-top: 72px;
  border-top: 3px solid var(--ink);
  background: var(--surface-2);
}
.pied-site__interieur { max-width: 1180px; margin: 0 auto; padding: 34px 20px 36px; }

/* Pas d'`align-items` : les colonnes se calent en haut, donc les trois
   intitules sont sur la meme ligne. Cale sur le bas, ils partaient en
   escalier, les contenus n'ayant pas la meme hauteur. */
.pied-site__grille { display: grid; gap: 28px 34px; grid-template-columns: 1fr; }
@media (min-width: 700px)  { .pied-site__grille { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .pied-site__grille { grid-template-columns: 1.6fr 1fr 1fr 1fr; } }

.pied-site__marque {
  display: inline-flex; align-items: center; gap: 10px;
  font-weight: 800; font-size: 1.1rem; letter-spacing: -.01em; color: var(--ink);
}
.pied-site__marque [data-ico] { color: var(--accent); }
.pied-site__marque .ico { width: calc(13 * var(--px)); height: calc(13 * var(--px)); }

.pied-site__phrase {
  margin: 10px 0 0; font-size: .9rem; line-height: 1.6;
  color: var(--ink-soft); max-width: 34ch;
}

.pied-site__titre {
  margin: 0 0 9px; font-size: .71rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--accent);
}

.pied-site__liste { list-style: none; margin: 0; padding: 0; }
.pied-site__liste li { font-size: .89rem; line-height: 1.7; color: var(--ink-soft); }
.pied-site a { color: var(--accent-fonce); }

/* L'icone d'ouverture externe se pose AVANT le libelle et reste solidaire de
   lui : elle annonce qu'on quitte le site, elle ne decore pas la ligne. */
/* `inline-block` : le lien ne se coupe plus en son milieu. S'il ne tient pas
   sur la ligne en cours, il passe entier a la ligne suivante, icone et point
   compris. Coupe, l'icone se retrouvait separee du libelle qu'elle annonce. */
.lien-insecable { display: inline-block; }

.pied-site__liste a [data-ico] { margin-right: 5px; }
.pied-site__liste a .ico { width: calc(9 * var(--px)); height: calc(9 * var(--px)); vertical-align: -1px; }

/* Registre a part : ce sont les metadonnees du site, pas son propos. Elles se
   distinguent par la taille et par l'air au-dessus, pas par un fond propre.
   Un bandeau sombre aurait demande d'inverser la logique en theme sombre, ou
   le pied est deja fonce, pour un gain visuel dans un theme sur trois. */
.pied-site__bas {
  display: flex; flex-wrap: wrap; gap: 6px 22px;
  margin: 34px 0 0; padding-top: 18px; border-top: 1px solid var(--line-fort);
  font-size: .78rem;
  /* `--ink-soft` et non `--ink-faint` : l'encre atténuée est réglée pour le
     fond de page, pas pour `--surface-2`. Mesuré au banc d'accessibilité,
     elle tombait à 4,23:1 en thème sombre, sous le seuil de 4,5. */
  color: var(--ink-soft);
}
/* La provenance passe a la ligne : elle est bien plus longue que les trois
   autres mentions, et elle parle de ce que l'outil affiche, pas de l'outil. */
.pied-site__bas > span:last-child { flex-basis: 100%; }

/* ---------- Impression ---------- */

/* Mention de provenance : invisible à l'écran, imprimée sur chaque sortie. */
.mention-impression { display: none; }

/* ---------- Preparer une question ---------- */

/* La barre apparait a la selection et se pose EN BAS, hors du texte.
   Un menu flottant colle a la selection recouvrirait le passage qu'on
   vient de selectionner, et generait qui selectionne pour copier ou
   surligner sans vouloir poser de question. */
.barre-selection {
  /* Le decalage horizontal passe par une variable : la barre est centree au
     large et rangee a gauche sur telephone, et les trois etats de la
     transition (repos, posee, mouvement reduit) n'ont ainsi qu'une seule
     chaine de transformation a tenir d'accord. */
  --decalage-x: -50%;

  position: fixed;
  left: 50%; bottom: 20px;
  transform: translateX(var(--decalage-x)) translateY(10px);
  z-index: 26;
  max-width: calc(100vw - 88px);   /* laisse la place au retour-haut */
  display: flex; gap: 8px;
  padding: 8px;
  background: var(--card);
  border: 1px solid var(--line-fort);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-soft);

  /* La barre monte de dix pixels en se revelant. question.js lit cette duree
     pour savoir combien de temps attendre avant de reposer l'attribut hidden :
     une seule valeur, ecrite ici. */
  opacity: 0;
  transition: opacity 180ms var(--ease), transform 180ms var(--ease);
}
.barre-selection--posee {
  opacity: 1;
  transform: translateX(var(--decalage-x)) translateY(0);
}
.barre-selection .btn { min-height: 44px; white-space: nowrap; }

/* Sur un telephone, les deux libelles longs passaient sur trois lignes et la
   barre montait a la moitie de l'ecran. Les libelles raccourcissent (voir
   `libelleCourt` dans question.js) et le bouton se resserre. */
@media (max-width: 720px) {
  /* Rangee a gauche plutot que centree : centree, elle mordait sur le
     retour-haut des que les deux libelles etaient un peu longs. Cadree entre
     12 px a gauche et 72 px a droite, elle prend la largeur de son contenu
     dans ce qui reste, et le retour-haut garde son coin. */
  .barre-selection {
    --decalage-x: 0px;
    left: 12px; right: 72px;
    width: fit-content; max-width: none;
    padding: 6px; gap: 6px;
  }
  .barre-selection .btn { padding: 8px 13px; font-size: .86rem; }
}

/* Qui a demande moins d'animation reçoit la barre d'un coup. La duree tombe
   a zero, et question.js masque alors sans attendre. */
@media (prefers-reduced-motion: reduce) {
  .barre-selection,
  .barre-selection--posee {
    transition-duration: 0s;
    transform: translateX(var(--decalage-x));
  }
}

/* Le panneau de question, sa recherche, ses annexes et ses mots-cles
   partagent desormais `.panneau` : quatre familles pour un meme objet, c'etait
   quatre endroits a corriger au prochain defaut. */

/* ---------- Chercher un mot ailleurs ----------
   Le panneau reprend `.panneau` : meme position, meme cadre, meme
   comportement a l'impression. Seul le contenu change. */

.champ-recherche {
  width: 100%; font: inherit; padding: 12px 14px; min-height: 44px;
  border: 1px solid var(--line-fort); border-radius: var(--radius-sm);
  background: var(--card); color: var(--ink);
  margin-bottom: .8em;
}
/* L'ellipse est declaree SANS `:not(:focus)`, a la difference de .champ-url.
   Un champ de saisie recoit le focus des l'ouverture du panneau, et un mot
   de quarante signes y deborde tout de suite : avec `:not(:focus)` la
   declaration disparaissait au moment ou elle servait, et le banc du
   debordement l'a releve en 390 px dans les trois themes. Chromium impose
   `overflow: clip` a un <input>, la declarer autrement ne sert a rien.
   Pendant la frappe le navigateur ignore l'ellipse et suit le curseur. */
.champ-recherche { text-overflow: ellipsis; }

.recherche-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }

/* Une ligne par source. Le nom et sa raison d'etre tiennent dans une
   colonne qui peut retrecir, le chevron garde sa place a droite : sans
   minmax(0, 1fr), un mot long poussait l'icone hors du cadre. */
.recherche-lien {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 4px 12px;
  min-height: 44px;
  padding: 8px 12px;
  font-family: var(--font-ui);
  text-decoration: none;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.recherche-lien:hover { background: var(--surface-2); border-color: var(--line-fort); }
.recherche-lien:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.recherche-lien__nom {
  grid-column: 1; font-size: .92rem; font-weight: 700;
  overflow-wrap: anywhere;
}
.recherche-lien__quoi {
  grid-column: 1; grid-row: 2;
  font-size: .8rem; line-height: 1.4; color: var(--ink-faint);
  overflow-wrap: anywhere;
}
.recherche-lien__signe {
  grid-column: 2; grid-row: 1 / 3;
  display: inline-flex; color: var(--ink-faint);
}
.recherche-lien:hover .recherche-lien__signe { color: var(--accent-fonce); }

@media (max-width: 600px) {
  .barre-selection { max-width: calc(100vw - 24px); }
}

@media print {
  .barre-selection { display: none !important; }
}

@media print {
  /* `.pied-site` et non `.pied` : la seconde classe est celle du PIED OFFICIEL
     d'un texte adopté (« Délibéré en séance publique… », la qualité et la
     signature). Tant que les deux portaient le même nom, cette règle effaçait
     la signature du président de la chambre de toutes les impressions, ce qui
     retirait du papier une partie du texte de loi. */
  .entete, .plan-panneau, .reglages, .pied-site, .integrite,
  .poignee-redim { display: none !important; }
  .lecteur { display: block; padding: 0; }
  .texte { max-width: none; font-size: 11pt; }
  .ref { color: inherit; text-decoration: none; }

  /* L'EXERGUE SORT SUR LE PAPIER, LA RECHERCHE NON. Une feuille imprimee
     garde les mots qu'on a poses a la main ; elle n'a aucune raison de
     garder les restes d'une recherche faite deux minutes avant.
     Le cadre est la meme forme qu'a l'ecran, en noir : une page imprimee
     doit se relire comme la page qu'on avait sous les yeux. */
  /* La marge negative sert a l'ecran, pour qu'un mot marque ne decale rien
     pendant qu'on tape. Sur le papier rien ne bouge plus, et elle faisait
     coller le cadre au mot suivant : on la retire et le cadre respire. */
  .surlignage {
    padding: 0 .14em;
    margin: 0;
  }
  .surlignage--recherche {
    background: transparent; box-shadow: none;
  }
  .surlignage--exergue {
    outline: 1pt solid currentColor;
    outline-offset: 0;
  }
  /* LES REPERES SORTENT SUR LE PAPIER, comme l'exergue : ils viennent d'un
     reglage pose a la main, pas d'une recherche passagere. Le trait passe
     en encre courante, le plein et le pointille restent distincts. */
  .surlignage--obligation,
  .surlignage--faculte,
  .surlignage--condition,
  .surlignage--duree,
  .surlignage--montant,
  .surlignage--negation { text-decoration-color: currentColor; }

  /* L'etiquette d'operation sort sur le papier : elle dit ce que fait
     l'article, pas ce qu'on cherchait il y a deux minutes. Le fond plein de
     la suppression devient un cadre, l'encre economise le toner et le mot
     suffit. */
  .op { border-color: currentColor; color: inherit; }
  .op--suppression { background: transparent; color: inherit; }

  /* Un tableau ne defile pas sur du papier : il s'imprime en entier.
     Une rangee ne se coupe pas entre deux feuilles, et l'en-tete se
     repete en tete de chaque page d'un long bareme. */
  .tableau { overflow: visible; border-color: var(--line-fort); }
  .tableau__grille { width: 100%; min-width: 0; font-size: 9.5pt; }
  .tableau__grille thead { display: table-header-group; }
  .tableau__grille tr { break-inside: avoid; page-break-inside: avoid; }
  .tableau__grille th,
  .tableau__grille td { border-bottom: 1px solid var(--line-fort); }

  .mention-impression {
    display: block;
    margin-top: 28pt;
    padding-top: 8pt;
    border-top: 1px solid var(--line-fort);
    font-family: var(--font-ui);
    font-size: 8.5pt;
    color: var(--ink-soft);
  }
}

/* ---------- Icônes pixel ---------- */

/* 12 unités rendues à 12 × --px. Le dessin prend la couleur du texte : une
   icône posée dans un bouton rouge devient rouge sans rien redéclarer. */
.ico {
  width: calc(12 * var(--px));
  height: calc(12 * var(--px));
  display: block;
  flex: 0 0 auto;
}
[data-ico] { display: inline-flex; align-items: center; }

.marque__signe { color: var(--accent); }
.marque__signe .ico { width: calc(16 * var(--px)); height: calc(16 * var(--px)); }

.plan-panneau__titre { display: flex; align-items: center; gap: 7px; }
.plan-panneau__titre .ico { width: calc(10 * var(--px)); height: calc(10 * var(--px)); }

.integrite__signe { color: var(--ink-faint); flex: 0 0 auto; }
/* Meme regle que `#texteType`, meme raison : base zero pour que la phrase
   reste sur la rangee du signe et se coupe a l'interieur, au lieu de renvoyer
   le signe seul sur sa ligne. Le bandeau d'integrite y est venu le jour ou il
   a pris la largeur du texte : plus etroit, sa phrase ne tenait plus a cote du
   signe. */
#texteIntegrite { flex: 1 1 0; min-width: 0; }
.integrite--ok .integrite__signe { color: var(--accent); }
.integrite--alerte .integrite__signe { color: var(--accent-fonce); }

/* ---------- Texte original, brut ---------- */

.texte--brut {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: .92rem;
  line-height: 1.6;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  overflow-x: auto;
}

/* Une ligne du texte original. Le <pre> est rendu ligne par ligne pour que
   la bascule puisse viser une ligne précise (bascule.js). Les spans restent
   INLINE : en display: block, les retours à la ligne conservés dans le <pre>
   s'ajouteraient aux blocs et doubleraient l'interligne. */
.brut__l { display: inline; scroll-margin-top: var(--ancre-haut); }

/* La ligne d'arrivée après une bascule. Un fond neutre, pas la couleur du
   surlignage des mots-clés ni celle du survol d'un renvoi : trois fonctions
   différentes ne portent pas le même fond. Il s'efface tout seul, c'est un
   coup d'œil, pas un état à gérer. */
.repere-bascule {
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  transition: background-color .5s var(--ease);
}

/* Le sommaire et le texte ne poussent jamais leurs voisins hors de l'écran :
   min-inline-size aux DEUX niveaux (règle du débordement). */
.lecteur > * { min-inline-size: 0; }

/* Suite d'intitulé de division : « TITRE II » puis son intitulé sur les
   lignes suivantes. Même traitement visuel que le titre, sans altérer le texte. */
.division-suite {
  font-family: var(--font-ui);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .03em;
  color: var(--ink);
  margin: -.7em 0 1.4em;
  scroll-margin-top: var(--ancre-haut);
}

/* Alinéa qui modifie un texte existant : un filet, pas une phrase. */
.para--modificative {
  padding-left: 12px;
  border-left: 3px solid var(--accent);
}

/* ---------- Cibles tactiles (relevé au banc de débordement) ---------- */

/* Les entrées du sommaire sont des cibles à part entière : 44 px de haut,
   pas la hauteur de leur texte. Mesuré à 36 px avant correction. */
.plan__item a { min-height: 44px; justify-content: center; }

/* Le logo est un lien de retour : il doit se viser au doigt. Mesuré à 29 px. */
.marque { padding: 8px 4px; min-height: 44px; align-items: center; }

/* Les liens dans le corps du texte restent à la taille du texte : un renvoi
   inline ne se dimensionne pas comme un bouton, et les référentiels
   d'accessibilité l'admettent explicitement. */

/* ---------- Annexes : notes de bas de document, acronymes ---------- */

/* L'entree vit en haut du sommaire, avant les divisions : on atteint les
   sources sans descendre en bas de page. Elle est sans icone : le libelle
   se suffit.

   ELLE N'EST PLUS EN .btn--fort, decision du 6 septembre 2026. Le rouge
   plein dit « c'est le geste principal de cet ecran-ci », et il ne l'est
   pas : le geste principal de l'ecran de lecture est dans le texte, pas
   dans la colonne du sommaire. Mesure au navigateur avant correction :
   226 x 44 en fond --accent plein, en tete de colonne, au-dessus du champ
   de filtre et de toutes les entrees du plan. Trois consequences relevees :
   sur telephone, ouvrir le sommaire montrait d'abord une barre rouge pleine
   largeur qui mene ailleurs ; en theme sombre le bouton passait en #FF6B72
   et devenait la surface la plus lumineuse de l'ecran ; sur un texte non
   reconnu il etait le SEUL element de la colonne, en rouge plein, pour un
   panneau qui affiche « 0 source ».

   Le rang retenu est celui du .btn nu : fond --card, filet 1px --line-fort,
   encre --ink. C'est exactement ce que porte .plan-filtre__champ juste
   dessous, meme filet, meme fond, meme rayon, meme largeur. Le bloc que le
   commentaire ci-dessous decrit existe donc vraiment. */
/* LES DEUX BOUTONS DU SOMMAIRE, une seule règle. « Recommandations » et
   « Sources et acronymes » ouvrent tous les deux un à-côté du document,
   au même endroit : ils se lisent comme une paire, donc ils se règlent
   ensemble. Deux règles séparées avaient déjà divergé, l'une en pilule,
   l'autre en rectangle. */
.plan-panneau__recos,
.plan-panneau__annexes {
  width: 100%; justify-content: center;
  /* Meme rayon, meme corps et meme largeur que le champ de filtre juste
     dessous : les deux se lisent comme un bloc, pas comme deux pieces
     rapportees. La pilule de .btn est ecartee pour la meme raison. */
  border-radius: var(--radius-sm);
  font-size: .86rem;
  padding: 9px 12px;
  margin: 0 0 8px;
  /* 44 px reste le plancher : c'est la cible tactile relevee au banc de
     debordement, le compact se joue sur le rayon et le corps, pas dessus. */
  min-height: 44px;
}

.annexes__onglets {
  display: flex; gap: .25em;
  border-bottom: 1px solid var(--line);
  margin: .6em 0 .9em;
}

/* Un onglet actif se signale par le filet ET par la graisse : la couleur ne
   porte jamais seule l'information (WCAG 1.4.1). */
.annexes__onglet {
  min-height: 44px; padding: 0 .9em;
  border: 0; background: none; cursor: pointer;
  color: var(--ink); font: inherit;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
}
.annexes__onglet[aria-selected="true"] {
  border-bottom-color: var(--accent);
  color: var(--accent-fonce);
  font-weight: 700;
}
.annexes__onglet:hover { background: var(--accent-pale); }

.annexe-liste { list-style: none; margin: 0; padding: 0; }

.annexe__entree {
  display: flex; gap: .6em;
  padding: .55em .4em;
  border-bottom: 1px solid var(--line);
}
.annexe__num { color: var(--accent-fonce); font-weight: 700; flex: 0 0 auto; }
.annexe__texte { flex: 1 1 auto; }

/* UNE NOTE DE PASSAGE : un bouton qui deplace la lecture, plus un bouton
   qui retire. Le premier prend toute la largeur restante et se comporte
   comme du texte, pas comme une pilule : c'est une citation du texte de
   loi, elle doit se lire. */
.annexe__entree--note { align-items: flex-start; gap: .4em; }

.annexe__aller {
  display: flex; gap: .6em; align-items: baseline;
  flex: 1 1 auto; min-width: 0;
  font: inherit; color: inherit; text-align: left;
  background: none; border: 0; border-radius: var(--radius-sm);
  padding: .25em .3em; margin: -.25em -.3em;
  cursor: pointer;
  /* Cible tactile : la citation fait plusieurs lignes, mais une note d'un
     seul mot doit rester attrapable au doigt (WCAG 2.5.8). */
  min-height: 44px;
}
.annexe__aller:hover { background: var(--surface-2, var(--surface)); }
.annexe__aller .annexe__texte { overflow-wrap: anywhere; }

/* Le bouton de retrait ne bouge pas quand la citation s'allonge. */
.annexe__oter { flex: 0 0 auto; align-self: flex-start; }

/* ---------- Sigles dans le corps du texte ---------- */

/* Un sigle repere se voit sans quitter la lecture. La GRAISSE porte
   l'information autant que la couleur : elle reste lisible pour qui ne
   distingue pas le rouge (WCAG 1.4.1). Pas de soulignement : ce n'est pas
   un lien, ne pas le faire passer pour tel. */
/* Le sigle est un LIEN vers sa définition dans le lexique, comme un appel
   de note l'est vers sa source. Pas de soulignement : il y en a un par
   phrase dans un rapport, et le texte deviendrait une grille. La couleur et
   la graisse suffisent, elles étaient déjà là quand c'était un span.

   Le pointeur reste celui du texte : on ne quitte pas la page, on ouvre un
   panneau. Le trait paraît au survol et au focus, là où l'intention est
   déclarée. */
.sigle-marque {
  color: var(--accent-fonce);
  font-weight: 700;
  text-decoration: none;
  cursor: help;
}
.sigle-marque:hover,
.sigle-marque:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* ---------- Lexique des sigles ---------- */

/* Deux colonnes. Sans largeur posee, chaque definition demarrait la ou
   finissait son sigle, et la liste descendait en escalier : « COM » a
   gauche, « CASSIOPEE » bien plus loin. Une colonne fixe remet toutes les
   definitions sur la meme verticale.

   La mesure est en ch, donc indexee sur la police et sur la taille du
   texte : le reglage de corps de l'app ne casse pas l'alignement. */
#annexesSigles .annexe__entree { gap: 0; }

#annexesSigles .annexe__num {
  flex: 0 0 10ch;
  padding-right: .7em;
  margin-right: .7em;
  /* Le filet separe les deux colonnes et court sur toute la hauteur de la
     ligne : c'est lui qui fait tenir le tableau. */
  border-right: 1px solid var(--line);
  /* Un sigle plus long que la colonne passe a la ligne plutot que de
     pousser la colonne des definitions et de tout desaligner. */
  white-space: normal;
  overflow-wrap: anywhere;
}

#annexesSigles .annexe__texte {
  display: flex; flex-direction: column; gap: .25em;
  align-items: flex-start;
}

.sigle__definition { line-height: 1.45; }

/* L'origine de la definition, dite en toutes lettres. Le fond colore ne
   porte pas l'information tout seul : l'etiquette est ecrite (WCAG 1.4.1),
   la couleur ne fait que la doubler. */
.sigle__source {
  font-size: .78rem;
  padding: .12em .5em;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
}
.sigle__source--texte   { background: var(--accent-pale); color: var(--accent-fonce);
                          border-color: var(--accent); }
.sigle__source--app     { background: var(--card); color: var(--ink-faint); }
.sigle__source--inconnu { background: transparent; color: var(--ink-faint);
                          border-style: dashed; }

/* Renvoi vers l'endroit du texte ou la definition est ecrite : renvoi
   interne, donc pointille, comme les appels de note. L'encre est celle de
   l'app : sans couleur posee, le navigateur met son bleu par defaut, et
   deux bleus etrangers a la charte tombaient au milieu du rouge. */
.sigle__renvoi {
  font-size: .82rem;
  color: var(--accent-fonce);
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}
.sigle__renvoi:hover { background: var(--accent-pale); }

/* Pour un sigle que l'app ne connait pas : des sorties vers l'exterieur,
   trait plein, comme tout lien qui quitte l'outil. */
.sigle__pistes { font-size: .82rem; color: var(--ink-faint); }
.sigle__pistes a {
  color: var(--accent-fonce);
  text-underline-offset: 3px;
}
.sigle__pistes a:hover { background: var(--accent-pale); }

/* L'entree qu'on vient d'ouvrir depuis le texte : un filet, pas un aplat de
   couleur seule. */
.annexe__entree--vue {
  background: var(--accent-pale);
  border-left: 3px solid var(--accent);
  padding-left: .4em;
}

/* Un appel de note renvoie vers l'interieur du document, pas vers un site.
   Le soulignement RESTE : un fond colore est encore de la couleur, et WCAG
   1.4.1 demande une marque qui n'en depende pas. Le pointille distingue le
   renvoi interne du renvoi externe, qui garde le trait plein. */
.ref--note {
  text-decoration-style: dotted;
  text-underline-offset: 3px;
}
.ref--note:hover { background: var(--accent-pale); }

/* Le numero de tete d'une note en bas de document : une ancre reperable.
   ET UNE CIBLE DE SAUT. L'appel de note est un lien d'ancre ordinaire
   (`href="#note-N"`), le navigateur saute donc lui-meme : sans marge, le
   numero arrivait derriere l'en-tete collante. Meme valeur que les titres. */
.note__num {
  color: var(--accent-fonce); font-weight: 700;
  scroll-margin-top: var(--ancre-haut);
}

/* Les parentheses autour d'un appel de note : presentes dans le document,
   pas peintes. « ([12]) » se lit « [12] ». display:none n'ote rien au
   textContent, donc le controle d'integrite continue de les compter. */
.paren-note { display: none; }

/* ---------- Infobulle d'apercu d'une source ---------- */

/* Le `title` natif est illisible (11 px), lent (pres d'une seconde) et
   invisible au clavier. Celle-ci sort en 120 ms, se lit, et parait aussi au
   focus. L'encre passe par --sur-accent : en theme sombre l'accent devient
   #FF6B72, ou le blanc ne donne que 2,76:1. */
.infobulle {
  position: fixed;
  z-index: 70;
  max-width: min(420px, calc(100vw - 24px));
  padding: 10px 13px;
  background: var(--accent);
  color: var(--sur-accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow-soft);
  font-family: var(--font-ui);
  font-size: .95rem;
  line-height: 1.45;
  pointer-events: auto;
}

/* Une infobulle qui s'anime a chaque survol fatigue, et le mouvement est un
   probleme d'accessibilite a part entiere. */
@media (prefers-reduced-motion: no-preference) {
  .infobulle { animation: infobulle-entree .12s ease-out; }
}
@keyframes infobulle-entree {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: none; }
}

/* ============================================================
   PANNEAU — la base commune
   ============================================================ */

/* UN SEUL OBJET, UNE SEULE FAMILLE. `.plan-panneau`, `.panneau-question`,
   `.panneau-annexes` et `.barre-selection` nommaient quatre fois la même
   chose : quatre endroits à corriger au prochain défaut. `.panneau` porte
   la structure ; les modificateurs ne portent que ce qui diffère
   réellement, la position et la largeur.

   L'élément est un <dialog>. Échap, le piège de focus, le fond inerte et
   l'arrière-plan viennent du navigateur, pas d'un écouteur maison. */

.panneau {
  /* La feuille de style du navigateur est à défaire en entier : marge
     automatique, bordure pleine, largeur et hauteur bornées à la fenêtre. */
  margin: 0;
  padding: 0;
  max-width: none;
  border: 1px solid var(--line-fort);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--ink);
  box-shadow: var(--shadow);

  /* La colonne : en-tête, corps, actions. C'est elle qui tient la promesse
     d'un panneau borné dont seul le CORPS défile. */
  display: flex;
  flex-direction: column;
  overflow: hidden;          /* le rayon coupe proprement le corps qui défile */

  position: fixed;
  z-index: var(--z-panneau);

  /* PIEGE : la feuille du navigateur pose `inset-block-start: 0` ET
     `inset-block-end: 0` sur `dialog:modal`. Un modificateur qui n'ecrase que
     `bottom` laisse donc le `top: 0` du navigateur en place, et le panneau se
     colle en haut de l'ecran quelle que soit son ancre. On remet tout a `auto`
     ici, et chaque modificateur declare ensuite les cotes dont il a besoin. */
  inset: auto;

  width: min(var(--panneau-l), calc(100vw - 2 * var(--panneau-marge)));
  /* dvh suit la barre d'adresse mobile, vh sert de repli. */
  max-height: calc(100vh - var(--panneau-marge) - var(--panneau-marge-haut));
  max-height: calc(100dvh - var(--panneau-marge) - var(--panneau-marge-haut));
}

/* Un <dialog> fermé ne s'affiche pas. C'est cette règle qui remplace
   l'attribut `hidden` que les panneaux portaient jusqu'ici. */
.panneau:not([open]) { display: none; }

/* L'en-tête et les actions ne défilent JAMAIS : le titre dit où on est, la
   croix est la sortie. Ça remplace le `position: sticky` que
   `.panneau-annexes__haut` portait uniquement pour obtenir ce résultat. */
.panneau__haut,
.panneau__actions { flex: 0 0 auto; }

.panneau__haut {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--panneau-ecart);
  padding: var(--panneau-retrait) var(--panneau-retrait) 0;
}

.panneau__corps {
  flex: 1 1 auto;
  /* SANS `min-height: 0`, un élément flex ne descend jamais sous la taille
     de son contenu : la hauteur bornée serait déclarée et sans effet, et
     c'est la page entière qui défilerait. C'est la ligne qui fait marcher
     tout le reste. */
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;   /* le défilement ne fuit pas vers la page */
  padding: var(--panneau-ecart) var(--panneau-retrait);

  /* UN CORPS QUI CONTINUE LE DIT.

     Le panneau de réglages fait 684 px de haut sur un écran de 844, son corps
     déborde de 661 px, et rien ne l'annonçait : pas de zone d'actions en bas,
     pas d'ombre, pas de barre de défilement visible. La dernière rangée était
     tranchée à mi-hauteur, ce qui se lit comme un panneau cassé et non comme
     un panneau qui continue. Mesuré à 390 × 844.

     Quatre fonds superposés, et aucun script. Les deux premiers sont des
     masques de la couleur du panneau, attachés au CONTENU (`local`) : ils
     défilent avec lui et découvrent l'ombre. Les deux suivants sont les
     ombres elles-mêmes, attachées au CADRE (`scroll`) : elles ne bougent pas.
     Résultat : l'ombre du bas n'apparaît que s'il reste quelque chose en
     dessous, celle du haut que si on a déjà descendu, et les deux
     disparaissent d'elles-mêmes quand le corps tient en entier. C'est la seule
     façon connue d'obtenir ce comportement sans écouter le défilement en JS.

     Vaut pour les sept panneaux, pas seulement pour les réglages. */
  background:
    linear-gradient(var(--card) 40%, transparent) top    / 100% 26px no-repeat local,
    linear-gradient(transparent, var(--card) 60%) bottom / 100% 26px no-repeat local,
    radial-gradient(farthest-side at 50% 0,
      var(--ombre-defilement), transparent)       top    / 100% 15px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%,
      var(--ombre-defilement), transparent)       bottom / 100% 15px no-repeat scroll;
}

.panneau__actions {
  display: flex; gap: 8px; flex-wrap: wrap;
  padding: 0 var(--panneau-retrait) var(--panneau-retrait);
}
.panneau__actions .btn { min-height: 44px; }

/* Une bande qui ne defile pas, entre l'en-tete et le corps : les onglets
   des annexes. Meme regle que l'en-tete, meme raison. */
.panneau__sous-haut { flex: 0 0 auto; padding: 0 var(--panneau-retrait); }

/* ---------- Le contenu commun ---------- */

/* Dans la colonne flex, le titre ne porte plus sa marge basse : c'est le
   rembourrage de `.panneau__haut` qui tient l'ecart, et une marge en plus
   decalerait la croix vers le bas. */
.panneau__titre {
  font-family: var(--font-ui);
  font-size: 1rem; font-weight: 800;
  margin: 0;
}
.panneau__aide {
  font-family: var(--font-ui);
  font-size: .84rem; line-height: 1.5;
  color: var(--ink-soft);
  margin: 0 0 .8em;
}

/* CE QUE L'APP DEDUIT, ET OU ELLE PEUT SE TROMPER.

   Posee a cote du compte de la surface concernee, pas en tete de document :
   une phrase generale se lit une fois et s'oublie, celle-ci est sous les
   yeux au moment ou on lit la liste. Revue juridique du 6 septembre, § 10.1.

   ELLE NE DIT PAS QUE L'APP INTERPRETE. Le texte affiche n'est pas touche,
   et l'ecrire contredirait la promesse de l'accueil. Ce qui peut se tromper,
   c'est ce que l'app DEDUIT autour : les definitions relevees, les cibles de
   renvoi, le decoupage du sommaire.

   Un cran plus discret que `.panneau__aide`, et un filet a gauche pour
   qu'elle se lise comme une reserve et pas comme une consigne de plus. */
.panneau__reserve {
  font-family: var(--font-ui);
  font-size: .8rem; line-height: 1.5;
  color: var(--ink-faint);
  margin: -.4em 0 1em;
  padding-left: 10px;
  border-left: 2px solid var(--line);
}

/* ---------- La croix ----------
   TOUS les panneaux se ferment au meme endroit, en haut a droite. Un bouton
   « Fermer » en pied de panneau descend avec le contenu et se retrouve sous
   la ligne de flottaison des qu'une liste s'allonge ; la croix, elle, vit
   dans l'en-tete qui ne defile jamais. Un seul geste a apprendre, valable
   partout, et toujours au meme pixel. */
.panneau__fermer {
  flex: 0 0 auto;
  /* 44 px : cible tactile, regle du debordement. */
  width: 44px; min-height: 44px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  margin-left: auto;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}
.panneau__fermer:hover { background: var(--surface-2); color: var(--ink); }
.panneau__fermer:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* L'avertissement sur une selection trop longue. */
.panneau__avertissement {
  font-family: var(--font-ui);
  font-size: .84rem; line-height: 1.5;
  color: var(--accent-fonce);
  background: var(--accent-pale);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  margin: 0 0 .8em;
}

/* La question preparee. `field-sizing` la fait tenir a son contenu la ou il
   est connu, `rows` reste le repli partout ailleurs ; dans les deux cas
   c'est `.panneau__corps` qui borne et qui defile. */
.panneau__texte {
  display: block; width: 100%;
  font-family: var(--font-ui);
  font-size: .88rem; line-height: 1.55;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  resize: vertical;
}

/* Un titre long se coupe ; la croix garde son coin. Sans `min-width: 0` un
   element flex ne descend jamais sous son contenu, et c'est la croix qui
   sortait du cadre. */
.panneau__titre { min-width: 0; overflow-wrap: anywhere; }

/* ---------- Les modificateurs de position ---------- */

/* En bas au centre : question, recherche, annexes, mots-clés. */
.panneau--bas {
  left: 50%; bottom: var(--panneau-marge);
  transform: translateX(-50%);
}
@media (max-width: 600px) {
  .panneau--bas { bottom: 12px; }
}

/* Sous l'en-tête collante. `--haut-entete` est mesuré par app.js — une valeur
   en dur décalait le panneau dès que la barre passait sur deux lignes.

   PLUS PERSONNE NE S'EN SERT DEPUIS LE 6 SEPTEMBRE 2026. Les réglages étaient
   le seul panneau ancré ici, quand les cinq autres sont ancrés en bas : deux
   panneaux qui font la même chose, afficher un formulaire et le refermer,
   n'apparaissaient pas au même endroit. Ils sont passés en `.panneau--bas`.
   La règle est gardée, pas supprimée : elle marche, elle est mesurée, et le
   jour où un panneau doit vraiment se poser sous l'en-tête il est écrit ici.

   Sa largeur portait `calc(100vw - 28px)`, soit 14 px de marge de chaque côté
   quand `.panneau--bas` en prend 20 par `--panneau-marge`. Mesuré à 390 px :
   362 px de large contre 350 pour les quatre autres. Corrigé ici aussi, pour
   que la règle reste juste si on la ressort. */
.panneau--sous-entete {
  top: calc(var(--haut-entete, 68px) + 10px);
  left: 50%; transform: translateX(-50%);
  width: min(var(--panneau-l-large), calc(100vw - 2 * var(--panneau-marge)));
  max-height: calc(100vh - var(--haut-entete, 68px) - 28px);
  max-height: calc(100dvh - var(--haut-entete, 68px) - 28px);
}

/* LA LARGEUR DES RÉGLAGES, et rien d'autre. Le panneau porte une grille de
   quatre curseurs et six paires de bascules : il lui faut `--panneau-l-large`
   là où les autres se contentent de `--panneau-l`. La marge au bord vient du
   token, comme partout. */
.panneau--reglages {
  width: min(var(--panneau-l-large), calc(100vw - 2 * var(--panneau-marge)));
}

/* Plein écran : le sommaire sous 1000 px. */
.panneau--plein {
  inset: 0;
  width: auto; height: 100%;
  max-height: none;
  border: 0; border-radius: 0;
}

/* ---------- L'arrière-plan ---------- */

/* Discret : le texte de loi reste lisible derrière. On assombrit juste
   assez pour dire où est la main. */
.panneau::backdrop { background: var(--fond-modal); }

/* ---------- Le verrou de défilement ---------- */

/* `showModal()` ne bloque PAS le défilement du fond : il rend le document
   inerte au clavier et au pointeur, mais la molette et le geste tactile
   continuent de faire défiler la page derrière. Le verrou est donc à poser
   nous-mêmes, et c'est `Panneau` qui pose la classe.

   Le rembourrage compense la barre de défilement retirée : sans lui, toute
   la page saute latéralement à chaque ouverture. Sur les systèmes à barre
   superposée (macOS par défaut) la mesure vaut 0 et rien ne bouge. */
/* LA GOUTTIERE DE LA BARRE DE DEFILEMENT, RESERVEE EN PERMANENCE.

   Sans elle, toute page qui cesse de defiler rend sa barre au systeme et
   s'elargit d'autant : la page saute lateralement. Ca se voyait en passant
   de la lecture ou de l'accueil a « Mes textes », ou le document tombe de
   3 538 px a 900 px de haut et n'a plus rien a faire defiler.

   `stable` reserve la place dans les deux etats. Sur les systemes a barre
   superposee (macOS par defaut) la gouttiere vaut 0 et rien ne change ;
   ailleurs, on paie une bande toujours reservee, et plus aucun saut.

   ELLE REMPLACE LA COMPENSATION MANUELLE des panneaux modaux : voir la
   garde dans js/lib/panneau.js, qui met `--barre-defilement` a zero quand
   la gouttiere est stable. Sans cette garde, les deux s'additionneraient et
   la page sauterait dans l'autre sens a chaque ouverture de panneau. */
html { scrollbar-gutter: stable; }

html.fond-fige {
  overflow: hidden;
  padding-right: var(--barre-defilement, 0px);
}

@media print {
  .panneau { display: none !important; }
}

/* Les onglets sont passes hors du corps qui defile : leur marge d'origine
   creusait un vide sous l'en-tete du panneau. */
.panneau__sous-haut.annexes__onglets { margin: .5em 0 0; }
