/* ══════════════════════════════════════════════════════════════════
   SIMSIMUP — LA FEUILLE PARTAGÉE
   Version 3.1 · « La glace sans tain » · 2026-08-17

   ⚠️⚠️ **CE FICHIER EST LA FEUILLE SERVIE, ET IL N'EN EXISTE QU'UNE.
   RÉÉCRIT LE 2026-09-04.** On lisait ici *« ce fichier est la source ; la
   copie en service est `app/static/simsimup.css` »* — c'est-à-dire que ce
   fichier se désignait lui-même comme la copie de lui-même, et prescrivait
   de recopier vers une adresse qui est la sienne.

   **Mesuré** : `git ls-files | grep 'simsimup\.css$'` rend **un seul**
   chemin. La duplication décrite a existé jusqu'au 2026-08-17 ; elle a
   disparu, et la consigne lui a survécu.

   ⚠️ *Ce qui reste vrai, et qui vaut d'être dit à sa place* : cette
   feuille est **partagée**, `app/static/pages/<écran>.css` ne l'est pas.
   Le titre de page, sa ligne de sous-titre, l'encart de message, la
   largeur de page et la matière d'un champ se définissent **ici, une
   seule fois** — une feuille de page qui les redéfinit est un défaut, pas
   une variante.

   ⚠️ **CE QU'AJOUTE LA 3.1 — LE RELIEF FONCTIONNEL**, demandé par Franck
   après validation de l'écran de séance : *« un peu de mise en relief
   afin de montrer les zones de saisie ou d'interaction »*. Ce n'est pas
   un retour de « la matière » : en 2.0 TOUT portait du relief, donc il ne
   distinguait rien. Ici il **ne dit qu'une chose : ceci se manipule**, et
   il est réservé à ce qui se clique, se tape ou se déplie. Voir les trois
   jetons `--pose`, `--pose-forte`, `--saisie`.

   ─────────────────────────────────────────────────────────────────
   CE QUE CHANGE LA VERSION 3.0
   ─────────────────────────────────────────────────────────────────

   La 2.0 taillait tout l'écran dans UNE surface molle, et disait la
   hiérarchie par deux ombres opposées : **ce qui sort agit, ce qui
   s'enfonce contient.** Cette grammaire est abandonnée. Elle avait un
   défaut connu — le relief doux efface la frontière entre ce qui
   s'affiche et ce qui se clique — qu'il fallait tenir par trois parades.

   À la place, **une grammaire de camp** :

     **CE QUI SE DIT EST SUR LE PAPIER. CE QUI OBSERVE EST DANS LA NUIT.**

   Le papier porte ce que produit un humain : la parole du coach et du
   client, les rapports, les formulaires, les textes longs. La nuit porte
   ce qui l'observe et le mesure : le rail de navigation, les compteurs,
   le tuteur, la sonde, la consommation.

   ⚠️ **CE N'EST PAS UN GOÛT, C'EST LA RÈGLE MÉTIER LA PLUS STRICTE DU
   PROJET RENDUE VISIBLE.** Le client virtuel ne doit jamais voir le
   référentiel de processus ni la remarque du tuteur (D19, et les six
   interdits d'`ARCHITECTURE-LOGIQUE.md`). Sur l'écran de séance en 2.0,
   les deux colonnes ont exactement le même fond : **rien ne dit laquelle
   est vue du client.** Ici, le fond le dit.

   Corollaire opérationnel, et c'est le seul contrôle à faire en
   relisant un écran converti : *ce bloc, le client pourrait-il le voir ?*
   Si oui il est clair, si non il est sombre. Un bloc mal placé se repère
   sans discussion — ce que le relief ne permettait pas.

   ─────────────────────────────────────────────────────────────────
   ⚠️ POSER CE FICHIER NE CASSE AUCUN DES QUATORZE GABARITS
   ─────────────────────────────────────────────────────────────────

   C'est la décision d'ingénierie qui rend la refonte progressive, et
   elle mérite d'être comprise avant d'être utilisée.

   Les gabarits de la 2.0 écrivent leur relief de **deux** façons :

     ① par jeton — `box-shadow: var(--relief)` ou `var(--creux-doux)` ;
     ② en dur — `box-shadow: inset 4px 4px 8px var(--ombre), …`,
        recopié quarante fois dans l'accueil seul.

   Les deux sont neutralisées ici, et par deux moyens différents :

     ① les quatre jetons d'ombre valent **`none`** ;
     ② les trois couleurs d'ombre valent **`transparent`** — une ombre
        portée d'une couleur transparente ne se voit pas, quelle que
        soit la géométrie écrite dans le gabarit.

   **Conséquence : le jour où l'on copie ce fichier, les quatorze écrans
   basculent d'un coup sur le papier, sans relief, sans être touchés.**
   Ils ne sont pas encore *convertis* — ils n'ont ni gouttière, ni voix,
   ni camp — mais ils sont cohérents, lisibles et déployables. La
   conversion écran par écran vient ensuite, dans l'ordre donné par
   `DIRECTION-VISUELLE.md` §6.

   ⚠️ **LES ALIAS DE LA 2.0 SONT CONSERVÉS ET NE SE SUPPRIMENT PAS
   AVANT LA FIN.** `--matiere`, `--fond`, `--bord`, `--marque` et les
   autres pointent vers les nouveaux rôles. Les retirer avant que les
   quatorze écrans soient convertis rendrait blanches des pages entières.
   Le bloc porte sa propre date de péremption : voir §ALIAS.

   ─────────────────────────────────────────────────────────────────
   CE QUI EST REPRIS DE LA 2.0 SANS DISCUSSION
   ─────────────────────────────────────────────────────────────────

     · **Les jetons sont nommés par leur rôle, pas par leur teinte.**
       `--bord` survit à un changement de palette ; `--gris-clair` non.
       C'est ce qui a permis à la 2.0 d'exister, et c'est ce qui permet
       à la 3.0 de la remplacer sans réécrire treize fichiers.
     · **Les trois statuts disent un ÉTAT, jamais une catégorie**, et le
       libellé reste obligatoire à côté de la couleur.
     · **Le focus clavier est un contour PLEIN**, il ne se négocie pas.
     · **`prefers-contrast: more` et `prefers-reduced-motion`** en fin de
       fichier. Ne pas les supprimer en croyant nettoyer.
     · **Le fichier se charge AVANT le `<style>` du gabarit**, et c'est
       l'inverse de `navigation.css`. Un gabarit doit pouvoir redéfinir un
       jeton localement le temps d'une mise au point.
   ══════════════════════════════════════════════════════════════════ */


/* ══ LES POLICES ═══════════════════════════════════════════════════
   Deux familles, un rôle chacune, et le partage n'est pas décoratif :
   il **dit qui parle** avant qu'on ait lu le mot.

     · **Newsreader** — la PAROLE. Les répliques, les rapports, les
       finalités d'étape, les retours d'expérience : tout ce qu'un
       humain a écrit ou dit. Empattements, pensée pour l'écran, italique
       vivante, accentuation française complète.
     · **Archivo** — la MESURE. Les étiquettes, les nombres, les titres,
       le rail, les boutons : tout ce que l'appareil affiche.

   ⚠️ **C'EST L'INVERSE DE L'USAGE COURANT**, qui met l'empattement en
   titre et la linéale en corps. Ici le corps est la matière du produit —
   un rapport de supervision se lit sur plusieurs écrans — et le titre
   est de l'appareillage.

   ⚠️ **LES DEUX SONT SOUS SIL OPEN FONT LICENSE 1.1**, comme Liberation
   Sans qu'elles remplacent. Servables depuis le VPS sans licence
   payante, et sans requête vers un tiers : voir `DIRECTION-VISUELLE.md`
   §3 pour la procédure de récupération et de sous-ensemblage.

   ⚠️ **L'ARGUMENT « MÉTRIQUES IDENTIQUES À ARIAL » TOMBE, ET C'EST LE
   COÛT ASSUMÉ DE LA REFONTE.** Liberation Sans était métriquement
   identique à Arial : si le téléchargement tardait, la page ne bougeait
   pas d'un pixel. Ce n'est plus vrai. Les replis ci-dessous sont donc
   choisis pour être **proches**, pas identiques — Georgia pour
   Newsreader, la pile système pour Archivo —, et `font-display: swap`
   reste : le texte s'affiche tout de suite, quitte à sauter une fois.
   L'inverse — attendre la police — laisserait une page blanche.

   ⚠️ **TANT QUE LES `.woff2` NE SONT PAS DANS `/static/polices/`, LE
   REPLI S'APPLIQUE ET RIEN NE PLANTE.** Un `@font-face` dont la source
   est introuvable est ignoré en silence. On peut donc poser cette
   feuille avant d'avoir posé les polices ; la page sera moins jolie, pas
   cassée. */

/* ⚠️ **INTER ET DM SANS REMPLACENT ARCHIVO ET NEWSREADER — 2026-08-28.**
   Arbitrage de Franck sur la direction du kit fourni : *« Inter + DM Sans
   partout »*. La serif disparaît, et avec elle l'opposition entre ce qui
   a été DIT par quelqu'un et ce qui le MESURE. C'est un choix assumé, pas
   un oubli : le kit emploie deux sans, et il devait être suivi à la lettre.

   ⚠️ **QUATRE FICHIERS POUR DEUX FAMILLES, ET C'EST MOINS QU'AVANT.** Les
   deux familles sont des polices VARIABLES : un seul fichier porte toutes
   les graisses de 100 à 900, d'où `font-weight: 100 900`. Un premier
   téléchargement en avait pris six — trois graisses × deux familles — et
   les empreintes MD5 étaient identiques trois par trois. **420 Ko de
   polices au total contre 225 avant, mais toutes les graisses au lieu de
   six**, et les anciennes partiront quand les seize écrans seront
   convertis.

   ⚠️ **`unicode-range` N'EST PAS DÉCORATIF.** Sans lui, le navigateur ne
   charge que le DERNIER `@font-face` d'une famille : le sous-ensemble
   latin de base ne serait jamais demandé, et tout le texte courant
   tomberait sur la police de repli. Les plages sont celles de Google,
   recopiées telles quelles.

   ⚠️ **LES LICENCES SONT ENFIN LÀ.** `app/static/README.md` signalait que
   les six polices servies n'avaient AUCUN fichier de licence alors
   qu'elles sont sous OFL 1.1. `OFL-Inter.txt` et `OFL-DMSans.txt` sont
   déposés à côté des fichiers. */
@font-face {
  font-family: "Inter";
  src: url("/static/polices/inter.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  src: url("/static/polices/inter-ext.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "DM Sans";
  src: url("/static/polices/dmsans.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "DM Sans";
  src: url("/static/polices/dmsans-ext.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}


/* ══ `box-sizing` POUR TOUT LE MONDE, ET UNE SEULE FOIS ═════════
   Demande de Franck, 2026-09-01 : *« toutes les pages doivent couvrir la
   même surface sur le fond que la page d'accueil »*.

   ⚠⚠ **ALIGNER LES `max-width` NE SUFFISAIT PAS, ET LA MESURE L'A
   MONTRÉ** : à `max-width: var(--page-large)` identique, l'accueil
   rendait une plaque de **1 184 px** et le paramétrage **1 246** —
   **62 px d'écart, soit exactement les deux remplissages du corps.**
   L'accueil héritait de `border-box`, les autres non.

   ⚠️ **SIX ÉCRANS SUR DIX-NEUF POSAIENT `* { box-sizing }` CHEZ EUX** —
   accueil, comptes, connexion, consommation, economie, invitation — et
   les treize autres vivaient en `content-box`. *Le commentaire du champ
   de saisie, plus bas, CONSTATAIT déjà ce partage en 2026-08-17 sans le
   refermer : « huit gabarits sur quinze posent `* box-sizing` chez eux ;
   les sept autres, non — et c'est chez ceux-là que le défaut apparaît ».*

   ⚠️ **UNE RÈGLE HÉRITÉE PAR LA MOITIÉ DES ÉCRANS N'EST PAS UNE RÈGLE,
   C'EST UN TIRAGE AU SORT.** Elle vit ici désormais, et les six copies
   locales sont parties le même jour. */
*, *::before, *::after { box-sizing: border-box; }

:root {
  /* ══ LES DEUX PILES ═══════════════════════════════════════════════
     ⚠️ **NE JAMAIS ÉCRIRE `font-family` EN DUR DANS UN GABARIT.** Le nom
     du rôle survit à un changement de fonte ; le nom de la fonte, non.

     ⚠️ **LA SERIF A DISPARU LE 2026-08-28, ET AVEC ELLE UNE DISTINCTION.**
     Jusqu'ici `--parole` était une serif et disait *« ceci a été dit par
     quelqu'un »* ; `--mesure` était une sans et disait *« ceci le
     mesure »*. Le kit fourni emploie deux sans — Inter pour les titres,
     DM Sans pour le texte — et Franck a tranché : le kit à la lettre.
     **Ce qui se perd est réel** : la réplique d'un client et un intitulé
     de colonne ont désormais la même voix typographique. Ce qui distingue
     les deux ne peut plus être que la forme et la place. */
  --titre:    "Inter", system-ui, "Segoe UI", Roboto, Arial, sans-serif;
  --texte:    "DM Sans", system-ui, "Segoe UI", Roboto, Arial, sans-serif;
  --chiffres: ui-monospace, "Cascadia Mono", Consolas, monospace;
  /* Les seize écrans écrivent encore les anciens noms. Les alias évitent
     de rouvrir dix-huit feuilles pour un renommage. */
  --mesure: var(--titre);
  --parole: var(--texte);

  /* ══ LES CINQ COULEURS DU KIT, TELLES QUELLES ═════════════════════
     Recopiées de la planche fournie, sans retouche. */
  --sauge:       #5E8B7E;   /* la marque                              */
  --bleu:        #A7C7E7;   /* l'accent froid                         */
  --ardoise:     #23485c;   /* le texte, et les surfaces appuyées     */
  --blanc-casse: #F1F5F4;   /* la matière claire                      */
  --rose:        #755a5e;   /* le second accent                       */

  /* ⚠️ **UNE SEULE CORRECTION, ET ELLE EST MESURÉE.** La sauge du kit
     est un cul-de-sac pour du texte : ni le blanc (3,84:1) ni l'ardoise
     (2,88:1) ne contrastent avec elle — elle est pile au milieu de
     l'échelle. **Le bouton primaire du kit n'est donc lisible dans aucun
     sens.** `--sauge-plein` est la même teinte assombrie du minimum
     nécessaire pour porter du blanc : **4,72:1**.
     *Le rose et le bleu, eux, passent tels quels avec du texte ardoise —
     5,88:1 et 6,30:1. Ils ne sont pas touchés.* */
  --sauge-plein: #4F7C6F;
  --sauge-vif:   #57b892;   /* le survol : on descend encore           */

  /* ══ LE FOND ══════════════════════════════════════════════════════
     Une vidéo en boucle, et par-dessus un voile blanc en dégradé. Le
     voile n'est PAS une politesse : sans lui rien n'est lisible. */
  /* ⚠️ **.48 NE SUFFISAIT PAS, ET LA MESURE LE DIT.** Un titre de page
     se trouve à ~19 % de la hauteur, donc près du HAUT du dégradé. À
     .48, l'encre principale n'y donnait que **3,15:1** au pire instant
     de la boucle. À .62 elle donne 4,68 — c'est le filet de sécurité,
     pas le confort : le confort vient de la plaque de verre. */
  /* ⚠⚠ **PORTÉ DE .62 À .70 LE 2026-09-01, ET C'EST LA VIDÉO QUI
     L'A EXIGÉ — et la justification a changé le jour même, pas le
     chiffre.** Elle a d'abord été posée pour une vidéo bleu nuit ;
     celle en service est un CIEL, remisé le même jour. **Le ciel est
     plus contrasté qu'on ne croit** : remesuré sur lui, `.62` rend
     **4,85** et `.70` rend **5,37**. *La valeur tient pour les deux
     vidéos, mais elle a failli être gardée sur un motif périmé.*
     **Mesuré sur les pixels rendus,
     voile compris, en balayant la boucle** : à .62, `--encre-douce`
     tombait à **4,33:1** au pire instant — **sous le seuil AA de
     4,5**, et loin des **4,86** que cette charte se donne pour
     plancher. À .70, le pire remonte à **5,16:1**.

     ⚠️ **LE PIRE INSTANT N'EST PAS LE PREMIER** : une première mesure,
     prise sur une seule image, rendait 4,61 et paraissait tenir. *Une
     vidéo de fond se mesure sur sa BOUCLE, pas sur son affiche.*

     Ce que cela coûte : le haut de page est un peu plus voilé, donc la
     vidéo un peu moins présente. *C'est le prix d'un fond sombre sous
     une encre foncée, et il se paie en haut de page ou en lisibilité.* */
  /* ⚠️⚠️ **LE VOILE TOMBE DE 70 À 30 % LE 2026-09-06 — DEMANDE DE
     FRANCK : « diminuer de beaucoup le voile blanc ».** Le fond devient
     **2,3 fois plus visible** partout où aucune plaque ne le couvre : les
     marges de page, et toute la page de connexion autour de la carte.

     ⚠️⚠️ **ET LE TEXTE N'Y PERD RIEN, PARCE QUE LE BLANC A CHANGÉ DE
     PORTEUR, PAS DE QUANTITÉ.** Le voile et le verre sont deux blancs qui
     se cumulent, mais ils ne couvrent pas la même chose : **le voile
     couvre TOUT le fond, le verre seulement la plaque qui porte du
     texte.** En baissant l'un et montant l'autre, le blanc reçu SOUS le
     texte reste le même — et le fond se dégage partout ailleurs :

         avant   voile 70 % puis verre 32 %  →  blanc équivalent 80 %
         après   voile 30 % puis verre 70 %  →  blanc équivalent 79 %

     **Mesuré : 7 fonds sur 7 passent les deux seuils dans les deux cas.**

     ⚠️⚠️ **CE CALCUL EST PÉRIMÉ DEPUIS LE SOIR MÊME — NOTÉ LE
     2026-09-06, TROUVÉ PAR LA REVUE D'INTENTION.** Il décrit un état qui a
     duré quelques heures : `--verre` **ne vaut plus 70 % mais 31 %**, par
     arbitrage de Franck au curseur. Le blanc équivalent réel est donc
     **52 %**, pas 79.

     ⚠️⚠️ **ET SURTOUT, LE VOILE N'ENTRE PLUS DANS CE CALCUL DU TOUT.**
     La plaque pose désormais `--fond-flou`, une image **opaque** qui recouvre
     le voile : ce que l'œil reçoit sous le texte est la copie floutée plus
     31 % de blanc, et le voile ne se voit plus **que hors des plaques**.

     ⚠️ **CE QUI A ÉTÉ REMESURÉ SUR LES PIXELS PEINTS, ET QUI TIENT** :
     sur l'accueil, le texte posé **directement sur la plaque** — titres,
     tableaux, tout ce qui n'est pas dans une carte — rend **7,86 à 10,33**
     du haut au bas de la page. *Le raisonnement ci-dessus est faux ; le
     résultat, lui, est bon, et c'est `--fond-flou` qui le porte.* **Le
     chiffre qu'il faut retenir est celui de la mesure, pas celui du
     modèle.**

     ⚠️ **CE QU'ON NE POUVAIT PAS FAIRE, ET LA MESURE L'A TRANCHÉ** :
     baisser le voile SANS monter le verre. À voile 55 %, le fond le plus
     dur tombe de 4,69 à **3,45** — sous le seuil dès le premier cran. Et
     éclaircir les images ne sauvait rien : même à gamma 2,8, le meilleur
     fond plafonnait à 4,24. *Le blanc sous le texte n'est pas
     négociable ; son EMPLACEMENT l'est.* */
  --voile-haut: rgba(255, 255, 255, .30);
  --voile-bas:  rgba(255, 255, 255, .40);

  /* ══ LE VERRE ═════════════════════════════════════════════════════
     ⚠️ **CE QUI FAIT LIRE « VERRE » EST LE COUPLE FOND + ARÊTE**, pas le
     flou. Un `backdrop-filter` seul donne une vitre sale ; c'est le
     liseré blanc en haut qui fait la tranche, et l'ombre portée qui
     décolle la plaque du décor.

     ⚠️ **AUCUN TEXTE HORS D'UN PANNEAU DE VERRE — RÈGLE ABSOLUE.**
     Mesuré : l'ardoise posée directement sur le voile ne donne que
     **3,86:1** au pire instant de la boucle, contre **7,24:1** dès qu'il
     y a une plaque de verre dessous. Un titre « posé sur le fond »
     deviendrait illisible dix secondes sur vingt, et personne ne saurait
     pourquoi. */
  /* ⚠️⚠️ **LE VERRE A CESSÉ D'ÊTRE DU BLANC LE 2026-08-28 — DEMANDE DE
     FRANCK : « du verre rendant flou le fond d'écran, PAS DE BLANC ».**

     Il valait `.55`, `.74` et `.38` de blanc pur : un calque laiteux, pas
     du verre. On voyait la vidéo *à travers un voile*, on ne la voyait
     pas *déformée*. **Ce qui fait le verre est le FLOU ; le blanc ne
     faisait que masquer.**

     ⚠️ **CE N'ÉTAIT PAS UN CAPRICE DE LA VERSION D'AVANT : C'EST LE BLANC
     QUI PORTAIT LE CONTRASTE** — 7,24:1 et 4,86:1, mesurés sur 24 images
     de la boucle. Le retirer sans compenser rendait le texte illisible.

     **Ce qui compense est le flou, monté de 16 à 30 px.** Un fond
     fortement flouté est UNIFORME : il n'a plus de pixel sombre isolé
     sous une lettre. Mesuré après changement, sur les pixels rendus de
     l'écran de paramétrage : le texte secondaire — le plus exposé — donne
     **5,12:1** contre un seuil de 4,5, et le bouton **5,29:1**.

     ⚠️ **RÉSERVE À TENIR : UNE SEULE IMAGE DE LA BOUCLE.** Le rendu hors
     serveur fige la vidéo sur sa première image ; les 4,86 d'avant
     étaient un PIRE INSTANT sur 24. **Les deux nombres ne se comparent
     donc pas**, et le vrai contrôle est de relire l'écran en recette
     pendant que la vidéo tourne. */
  /* ⚠️⚠️ **CE SONT DES NIVEAUX DE PROFONDEUR, ET ILS S'ADDITIONNENT —
     2026-08-29, DEMANDE DE FRANCK : « j'ai encore des zones dont le fond
     est blanc… que les fonds soient normalisés comme sur `/seances` ».**

     **Deux verres l'un sur l'autre ne font pas un verre plus net, ils
     font du blanc** : 26 % puis 36 % donnent **59 %**. C'est arithmétique
     et rien ne le signalait — chaque feuille posait un fond correct pour
     elle, et l'empilement se produisait à l'écran.

     ⚠️ **LE NIVEAU 0 EST LA SEULE PLAQUE, ET IL Y EN A UNE PAR PAGE.**
     Elle porte le flou. Tout ce qui est DEDANS n'a plus rien à flouter :
     le fond y est déjà dépoli. Un second `backdrop-filter` coûte une
     passe de rendu pour un effet que personne ne distingue.

     ⚠️ **LES VALEURS SONT CHOISIES POUR NE RIEN DÉPLACER, ET C'EST LE
     POINT.** Une carte de niveau 1 rendait 36 % de blanc quand la plaque
     n'en posait aucun ; elle rend **34,9 %** maintenant que la plaque en
     pose 26. *Les cartes gardent leur lisibilité ; ce qui change est le
     FOND DE PAGE, qui reçoit enfin le sien, et les cartes EMBOÎTÉES, qui
     perdent une couche.* */
  /* ⚠️⚠️ **31 % — LA VALEUR RETENUE PAR FRANCK AU CURSEUR, LE 2026-09-06
     AU SOIR.** *C'est son arbitrage (D10), et il prime.*

     ⚠️⚠️ **CET ENCADRÉ A ANNONCÉ « 70 % » PENDANT QUELQUES HEURES,
     AU-DESSUS D'UNE VALEUR QUI VALAIT DÉJÀ 31 — RECTIFIÉ LE SOIR MÊME, PAR
     LA REVUE D'INTENTION.** Le 70 était vrai le matin ; le curseur l'a
     ramené à 31 l'après-midi, et le commentaire est resté. *Un commentaire
     qui défend la valeur d'avant est pire qu'aucun commentaire : il fait
     raisonner juste sur un chiffre faux.*

     ⚠️⚠️ **CE QUI RACHÈTE CES 31 %, C'EST `--verre-vif` À 70.** Le texte
     n'est presque jamais sur la plaque nue : il est dans une carte, qui pose
     son propre blanc. *Mesuré sur les pixels peints : 7,86 à 10,33 sur la
     plaque de l'accueil, 4,67 au pire dans une carte de connexion.*

     ⚠️ **LE RAIL, LUI, A DÛ ÊTRE DÉCOUPLÉ** — il n'est pas sur la plaque
     mais sur la photo, et 31 % l'y laissaient à 3,50. Voir `--rail-fond`
     dans `navigation.css`.

     ⚠️ *Passée par 26 % le 2026-08-29, 32 le matin, 70 à midi, 31 au soir.* */
  --verre:        rgba(255, 255, 255, .31);   /* NIVEAU 0 — la plaque du corps */
  /* ⚠️⚠️ **70 % — ET C'EST CE QUI PORTE LA LISIBILITÉ DEPUIS QUE LA
     PLAQUE EST À 31.** À plaque 31 % et carte 40 %, le texte de la page de
     connexion tombait à **2,70 contre 4,5 exigé**. Le blanc a été déplacé
     là où il ne se voit presque pas : une carte fait 34 rem sur un écran
     entier. *Mesuré fond par fond : les sept passent, le plus dur
     `galets-rivage` rend **4,67**.*

     ⚠️ **DEUX ENCADRÉS SE SUCCÉDAIENT ICI, L'UN DISANT 40 ET L'AUTRE 70,
     LE MÊME JOUR** — le premier a été retiré le 2026-09-06 au soir, sur
     constat de la revue d'intention. *Le 40 fut vrai le matin, quand la
     plaque valait 70 : les deux valeurs ont échangé leurs rôles dans la
     journée, et les deux commentaires sont restés côte à côte.* */
  --verre-vif:    rgba(255, 255, 255, .70);   /* NIVEAU 1 — une zone SUR elle  */
  --verre-creux:  rgba(255, 255, 255, .07);   /* un champ, une zone reçue      */
  --verre-bord:   rgba(255, 255, 255, .45);
  --verre-arete:  rgba(255, 255, 255, .78);   /* la tranche du haut        */
  /* ⚠️ **LE FLOU EST DEVENU CE QUI FAIT LE VERRE — 2026-08-28.** Il
     accompagnait un calque blanc ; il le remplace. 30 px et non 16 :
     c'est l'uniformité du fond flouté qui tient désormais le contraste,
     là où c'était l'opacité du blanc. La saturation monte avec — un fond
     très flouté se désature, et la vidéo perdrait sa couleur. */
  /* ⚠️⚠️ **60px DEPUIS LE 2026-09-06, ET LE CONTRASTE Y GAGNE — DEMANDE
     DE FRANCK : « effet très flou ».** On aurait pu craindre l'inverse ;
     la mesure dit le contraire, et le motif est mécanique : **plus le
     rayon est grand, plus le point le plus SOMBRE du fond remonte vers
     la moyenne locale.** Mesuré sur les sept fonds retenus, au pire
     point, voile 70 % et plaque comprise :

         blur(30px)  →  5 fonds sur 8 passent les DEUX seuils
         blur(60px)  →  7 fonds sur 8

     *Le seul qui reste dessous — les montagnes brumeuses, `--encre-douce`
     à 4,44 contre 4,5 — a été écarté pour cette raison.* */
  /* ⚠️ **90px LE 2026-09-06 — « augmenter de beaucoup le flou ».**
     ⚠️⚠️ **CE QU'IL FAUT SAVOIR : LE GAIN DE CONTRASTE EST SATURÉ.**
     Mesuré sur le fond le plus dur — 60px → 4,69 · 90px → 4,70 ·
     140px → 4,75. *Au-delà de 60, le flou ne fait plus qu'un effet ; il
     ne protège plus rien.* On le pousse donc pour ce qu'il montre, pas
     pour ce qu'il mesure — et 140 coûterait une passe de rendu plus large
     sans rien rendre de plus à l'œil. */
  /* ⚠️⚠️ **`--flou` NE SERT PLUS À LA GRANDE PLAQUE DEPUIS LE
     2026-09-06 — ARBITRAGE DE FRANCK : « la texture n'est pas du tout une
     texture de verre ».** Le verre se fait désormais par une **copie
     floutée du fond, calculée à la préparation**, plus un **grain
     fractal** : voir `--verre-grain` et `--fond-flou` ci-dessous.

     ⚠️ **CE QUI A DÉCIDÉ DU CHANGEMENT N'EST PAS LE GOÛT, C'EST UNE
     MESURE.** `backdrop-filter` floute, mais **il ne texture rien** : il
     rend du blanc translucide, jamais du verre. *Le micro-relief — ce qui
     fait qu'une vitre dépolie se reconnaît — n'existe pas dans le filtre.*

     ⚠️ **IL RESTE DÉFINI**, et employé par le rail et quelques barres
     collantes : là, il n'y a pas de fond photographique à recopier. */
  --flou:         blur(90px) saturate(1.7);

  /* ══ LE VERRE, DEUXIÈME MANIÈRE — 2026-09-06 ═══════════════════
     ⚠️⚠️ **LE FLOU VIT DANS LE FICHIER, PLUS DANS LE MOTEUR.** Chaque
     fond a quatre copies floutées, `<nom>-f1` à `-f4`, de la plus douce à
     la plus nette ; la cinquième est l'image elle-même. **`--fond-flou`
     désigne celle qu'on affiche**, et c'est ce que le curseur de netteté
     règle.

     ⚠️ **`background-attachment: fixed` EST CE QUI ALIGNE LES DEUX
     IMAGES.** La copie floutée et le fond net se calent tous deux sur le
     viewport, donc **ils se superposent au pixel près**, quel que soit le
     format de la fenêtre ou la position de la plaque. *Sans `fixed`,
     chaque plaque recadrerait l'image sur elle-même et le décalage
     sauterait aux yeux.*

     ⚠️⚠️ **LE GRAIN EST CE QUI MANQUAIT, ET IL TIENT EN 300 OCTETS.** Un
     bruit fractal SVG en `data:` — aucune requête réseau, aucun fichier à
     déployer. *C'est lui qui donne le micro-relief du verre dépoli ; sans
     lui, une plaque n'est qu'un aplat blanc translucide, ce que Franck a
     nommé « pas du tout une texture de verre ».*

     ⚠️ **LE `data:` RESTE AUTORISÉ PAR LA POLITIQUE DE SÉCURITÉ** :
     `img-src 'self' data:` le prévoit explicitement. *Une bibliothèque de
     « glassmorphism » servie par un CDN serait, elle, bloquée.* */
  /* ⚠️⚠️ **VALEUR RETENUE PAR FRANCK LE 2026-09-06, AU CURSEUR : cran
     55 — flou `f3`, voile 31 %.** *C'est son arbitrage, et il prime
     (D10).*

     ⚠️⚠️ **ELLE NE TIENT LE CONTRASTE QUE PARCE QUE LA CARTE A ÉTÉ
     ÉPAISSIE EN MÊME TEMPS.** À plaque 31 % et carte 40 %, le texte
     tombait à **2,70 contre 4,5 exigé** — l'outil l'annonçait en rouge.
     Le blanc a donc été déplacé là où il ne se voit presque pas : **la
     carte passe à 70 %**, et les sept fonds repassent au-dessus du seuil.
     *Mesuré fond par fond : le plus dur, `galets-rivage`, rend 4,82.*

     ⚠️ **LA PLAQUE, ELLE, GARDE SES 31 %** — c'est-à-dire l'aspect
     demandé. Ce qui change est un rectangle de 34 rem sur un écran
     entier. */
  /* ⚠️ **FOND CHANGÉ LE 2026-09-08, DEMANDE DE FRANCK** — `elg21-fog`,
     des pics karstiques dans une mer de nuages. Préparé comme les sept
     autres : 1920 de large, la copie floutée au rayon 12 (calibré sur la
     netteté des `-f3` servis : 1,09 pour une fourchette mesurée de 0,64
     à 1,36). ⚠️ **IL EST PLUS SOMBRE QUE `galets-brume` — 0,302 de
     luminance moyenne contre 0,465 — ET LE CONTRASTE A ÉTÉ REMESURÉ** :
     sur les cartes, là où le texte vit, il rend **7,93 contre 8,02**,
     très au-dessus des 4,5 de WCAG 1.4.3. *La plaque nue descend à 3,86
     au premier centile — comme l'ancien à 4,06 : c'est pour cela que le
     texte est sur les cartes et non sur la plaque.* */
  --fond-flou:    url("/static/fonds/pics-brume-f3.jpg");

  /* ⚠️⚠️ **TROIS FRÉQUENCES, ET C'EST CE QUI FAIT LA DIFFÉRENCE ENTRE DU
     SABLE ET DU VERRE — 2026-09-06, demande de Franck : « ajouter des
     zones d'imperfections ».** Un bruit unique donne une texture
     uniforme, donc plate. Une vitre réelle porte trois échelles de
     défaut, et il faut les trois :

     ① **les ondulations** — `baseFrequency: .0016`, de larges plages
        douces : la variation d'épaisseur d'un verre coulé ;
     ② **les taches** — `.007`, plus contrastées : les défauts de
        surface, les traces d'essuyage ;
     ③ **le grain** — `.7` : le dépoli lui-même.

     ⚠️⚠️ **CES TROIS CHIFFRES ONT ÉTÉ ÉCRITS `.006`, `.028` ET `.85`
     PENDANT QUELQUES HEURES — RECTIFIÉS LE 2026-09-06 AU SOIR, PAR LA
     REVUE D'INTENTION.** C'étaient ceux de la tuile de 420 px ; **la tuile
     fait maintenant 1600 × 1200**, et les fréquences ont été divisées
     d'autant pour garder la même échelle de motif à l'écran.

     ⚠️⚠️ **CE QUI REND LE BRUIT NEUTRE, C'EST L'ORDONNÉE — ET ELLE EST
     MESURÉE, PAS CALCULÉE.** Chaque étage a été rendu seul dans un canvas
     et son ordonnée corrigée jusqu'à ce que le gris moyen tombe sur
     **128**, le neutre de `soft-light`. *La formule `.5 − pente/2` ne vaut
     que pour `fractalNoise` ; `turbulence` rend une **valeur absolue**, de
     moyenne bien plus basse, et elle donnait **96 pour 128**.* D'où une
     ordonnée **négative** pour les ondulations (pente 1,7 → −0,3840) et
     **positive** pour les taches (pente 1,35 → +0,1026) : ce ne sont pas
     des réglages de goût, ce sont deux recalages vers le même gris.

     ⚠️ **LES DEUX PENTES MANQUAIENT ICI — AJOUTÉES LE 2026-09-06, PAR LE
     VÉRIFICATEUR.** Le bloc n'annonçait qu'une pente sur trois, et une
     ordonnée ne veut rien dire sans elle. ⚠️ *Et les deux ordonnées ne se
     déduisent PAS l'une de l'autre par le calcul : l'écrêtage à 0 et à 1
     après application de la pente déplace la moyenne, et c'est pourquoi
     elles ont été mesurées étage par étage plutôt que calculées.*

     ⚠️ **LE TROISIÈME ÉTAGE PORTE `slope 1.0` ET `intercept 0` — UNE
     IDENTITÉ, ET C'EST VOULU** : `fractalNoise` est **déjà** centré sur
     128, il n'a rien à recaler. *Seul son `feFuncA` travaille, en forçant
     l'alpha à 1 — sans quoi l'alpha aléatoire corrèle transparence et
     couleur, et la couche assombrit au lieu de moduler.*

     ⚠️ **1600 × 1200 ET `cover`, DONC UNE SEULE TUILE.** `feTurbulence`
     n'est pas périodique : à 420 px répétés, **le quadrillage se voyait**.
     *L'encadré disait « 420 px de côté, pas 180 » — c'était l'étape
     d'avant, et le même défaut d'un cran plus loin.* */
  --verre-grain:  url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNjAwJyBoZWlnaHQ9JzEyMDAnPjxmaWx0ZXIgaWQ9J28nIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0nc1JHQic+PGZlVHVyYnVsZW5jZSB0eXBlPSdmcmFjdGFsTm9pc2UnIGJhc2VGcmVxdWVuY3k9Jy4wMDE2JyBudW1PY3RhdmVzPScyJyBzZWVkPSc3Jy8+PGZlQ29sb3JNYXRyaXggdHlwZT0nc2F0dXJhdGUnIHZhbHVlcz0nMCcvPjxmZUNvbXBvbmVudFRyYW5zZmVyPjxmZUZ1bmNSIHR5cGU9J2xpbmVhcicgc2xvcGU9JzEuNycgaW50ZXJjZXB0PSctMC4zODQwJy8+PGZlRnVuY0cgdHlwZT0nbGluZWFyJyBzbG9wZT0nMS43JyBpbnRlcmNlcHQ9Jy0wLjM4NDAnLz48ZmVGdW5jQiB0eXBlPSdsaW5lYXInIHNsb3BlPScxLjcnIGludGVyY2VwdD0nLTAuMzg0MCcvPjxmZUZ1bmNBIHR5cGU9J2xpbmVhcicgc2xvcGU9JzAnIGludGVyY2VwdD0nMScvPjwvZmVDb21wb25lbnRUcmFuc2Zlcj48L2ZpbHRlcj48ZmlsdGVyIGlkPSd0JyBjb2xvci1pbnRlcnBvbGF0aW9uLWZpbHRlcnM9J3NSR0InPjxmZVR1cmJ1bGVuY2UgdHlwZT0ndHVyYnVsZW5jZScgYmFzZUZyZXF1ZW5jeT0nLjAwNycgbnVtT2N0YXZlcz0nMycgc2VlZD0nMTknLz48ZmVDb2xvck1hdHJpeCB0eXBlPSdzYXR1cmF0ZScgdmFsdWVzPScwJy8+PGZlQ29tcG9uZW50VHJhbnNmZXI+PGZlRnVuY1IgdHlwZT0nbGluZWFyJyBzbG9wZT0nMS4zNScgaW50ZXJjZXB0PScwLjEwMjYnLz48ZmVGdW5jRyB0eXBlPSdsaW5lYXInIHNsb3BlPScxLjM1JyBpbnRlcmNlcHQ9JzAuMTAyNicvPjxmZUZ1bmNCIHR5cGU9J2xpbmVhcicgc2xvcGU9JzEuMzUnIGludGVyY2VwdD0nMC4xMDI2Jy8+PGZlRnVuY0EgdHlwZT0nbGluZWFyJyBzbG9wZT0nMCcgaW50ZXJjZXB0PScxJy8+PC9mZUNvbXBvbmVudFRyYW5zZmVyPjwvZmlsdGVyPjxmaWx0ZXIgaWQ9J2cnIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0nc1JHQic+PGZlVHVyYnVsZW5jZSB0eXBlPSdmcmFjdGFsTm9pc2UnIGJhc2VGcmVxdWVuY3k9Jy43JyBudW1PY3RhdmVzPSczJy8+PGZlQ29sb3JNYXRyaXggdHlwZT0nc2F0dXJhdGUnIHZhbHVlcz0nMCcvPjxmZUNvbXBvbmVudFRyYW5zZmVyPjxmZUZ1bmNSIHR5cGU9J2xpbmVhcicgc2xvcGU9JzEuMCcgaW50ZXJjZXB0PScwLjAwMDAnLz48ZmVGdW5jRyB0eXBlPSdsaW5lYXInIHNsb3BlPScxLjAnIGludGVyY2VwdD0nMC4wMDAwJy8+PGZlRnVuY0IgdHlwZT0nbGluZWFyJyBzbG9wZT0nMS4wJyBpbnRlcmNlcHQ9JzAuMDAwMCcvPjxmZUZ1bmNBIHR5cGU9J2xpbmVhcicgc2xvcGU9JzAnIGludGVyY2VwdD0nMScvPjwvZmVDb21wb25lbnRUcmFuc2Zlcj48L2ZpbHRlcj48cmVjdCB3aWR0aD0nMTYwMCcgaGVpZ2h0PScxMjAwJyBmaWx0ZXI9J3VybCgjbyknIG9wYWNpdHk9JzAuNDUnLz48cmVjdCB3aWR0aD0nMTYwMCcgaGVpZ2h0PScxMjAwJyBmaWx0ZXI9J3VybCgjdCknIG9wYWNpdHk9JzAuMycvPjxyZWN0IHdpZHRoPScxNjAwJyBoZWlnaHQ9JzEyMDAnIGZpbHRlcj0ndXJsKCNnKScgb3BhY2l0eT0nMC4yNScvPjwvc3ZnPg==");
  --flou-fort:    blur(110px) saturate(1.8);

  /* ══ LES ENCRES — DEUX NIVEAUX, ET PAS TROIS ══════════════════════
     ⚠️ **LE TROISIÈME NIVEAU N'EXISTE PLUS, ET C'EST UNE CONSÉQUENCE
     MESURÉE DU VERRE.** Sur du papier plein, trois gris tenaient
     (10,1 / 6,8 / 5,0:1). Sur du verre, le fond remonte : le second
     niveau tombe déjà à 4,86:1, et un troisième passerait sous 4. **La
     hiérarchie se fait donc à la taille et à la graisse, plus à la
     pâleur.** C'est le prix de la transparence, et il se paie ici. */
  --encre:       #2F3E46;   /* 7,24:1 sur le verre au pire instant     */
  --encre-douce: #47585F;   /* 4,86:1 — LA LIMITE BASSE, rien en deçà  */
  /* Les seize écrans écrivent `--encre-pale`. Il ne peut plus être plus
     pâle que le second niveau : l'alias garde le nom sans le mensonge. */
  --encre-pale:  var(--encre-douce);

  /* ══ CE QUI RESTE DES DEUX CAMPS ══════════════════════════════════
     ⚠️ **IL N'Y A PLUS DE CAMP SOMBRE — ARBITRAGE DU 2026-08-28.** La
     règle *« le papier est ce que le client voit, la nuit est ce qu'il
     ne voit pas »* n'est plus portée par le fond : le kit n'a qu'une
     ambiance claire, et Franck a tranché pour elle.

     **Ce que le fond disait doit maintenant être ÉCRIT.** Un panneau
     invisible du client porte un cadenas et une mention en toutes
     lettres — voir `.hors-vue` plus bas. *Une règle métier qui ne se
     lisait qu'à la couleur se lit désormais au mot : c'est moins
     immédiat, mais cela survit à un écran monochrome et à un daltonien,
     ce que la couleur seule ne faisait pas.*

     Les jetons de nuit restent définis et deviennent du verre teinté
     d'ardoise : les seize écrans non convertis suivent tout seuls. */
  --nuit:        rgba(47, 62, 70, .09);
  --nuit-clair:  rgba(47, 62, 70, .16);
  --nuit-creux:  rgba(47, 62, 70, .05);
  --lueur:       var(--encre);
  --lueur-pale:  var(--encre-douce);
  --lueur-vive:  var(--encre);

  /* Les anciens noms du papier, remis sur le verre. */
  --papier:       transparent;          /* le corps laisse voir la vidéo */
  --papier-vif:   var(--verre-vif);
  --papier-creux: var(--verre-creux);
  --carte:        var(--verre);
  --matiere:      var(--verre);
  --fond:         transparent;

  /* ══ LES STATUTS ══════════════════════════════════════════════════
     Ils disent un ÉTAT, jamais une catégorie, et le libellé reste
     obligatoire. Retendus pour tenir sur le verre — un vert de statut
     trop clair s'y noierait, et il ne doit surtout pas se confondre
     avec la sauge de la marque. */
  --bon:       #24603B;
  --attention: #8A5A00;
  --alerte:    #9E2B21;
  --bon-nuit:       var(--bon);
  --attention-nuit: var(--attention);
  --alerte-nuit:    var(--alerte);
  /* ══ LES ÉTAPES DU PROCESSUS — 3.5, 2026-09-04 ════════════════════
     La frise du bandeau de séance, et elle seule. **Ce ne sont PAS des
     statuts au sens ci-dessus** : un statut dit « bon / attention /
     alerte », ceux-là disent une POSITION dans un parcours — d'où une
     famille séparée plutôt qu'un détournement de `--bon`.

     Teintes arrêtées par Franck le 2026-09-03. ⚠️ **ELLES ÉTAIENT HUIT,
     ELLES SONT SIX depuis le 2026-09-04** — les deux plus pâles ont été
     abandonnées, voir l'encadré sous la liste.

     ⚠️ **L'ENCRE SUIT LA CLARTÉ DU FOND, ET C'EST MESURÉ À CHAQUE
     RETOUCHE.** Le blanc demandé à l'origine sur les verts pâles donnait
     **1,27:1** et **1,70:1** — WCAG 1.4.3 en exige 4,5. La règle est
     donc : *blanc sur sombre, encre sur clair*. Relevé du 2026-09-04 sur
     la feuille posée : **de 4,83:1 à 9,60:1**, le pire étant le blanc sur
     `--etape-sautee`.

     ⚠️⚠️ **ET LE PIC DU BATTEMENT EST MESURÉ DEPUIS CE JOUR-LÀ, IL NE
     L'AVAIT JAMAIS ÉTÉ.** `filter: brightness(1.14) saturate(1.2)`
     s'applique à l'étape courante : **la teinte qu'on lit au sommet n'est
     pas celle qui est déclarée**. `#B5E6A2` y monte à `#CEFFB9` et
     `#8ED973` à `#9EFF7B` — **9,82:1 et 8,98:1**, donc au-dessus. *Le pic
     éclaircit, il ne fonce pas : le risque était théorique, il est
     désormais mesuré.*

     ⚠️ **LA COULEUR N'EST JAMAIS SEULE À PORTER L'ÉTAT.** Trois verts
     qui ne diffèrent que par la saturation sont indiscernables en
     niveaux de gris : chaque pastille porte sa lettre, l'étape courante
     porte son anneau, son nom et son palier en toutes lettres. */
  --etape-franchie:     #12501A;   /* le critère de passage est tenu   */
  --etape-prochaine:    #F1A983;   /* celle qui vient juste après      */
  --etape-a-venir:      #FBE2D5;   /* le reste du parcours             */
  --etape-sautee:       #BE5014;   /* enjambée sans avoir été franchie */
  --etape-entamee:      #B5E6A2;   /* l'étape courante : aucun élément */
  --etape-bien-engagee: #8ED973;   /* du critère, puis au moins un     */

  /* ⚠️⚠️ **DEUX TEINTES ONT ÉTÉ ABANDONNÉES LE 2026-09-04, ET IL FAUT
     SAVOIR LAQUELLE COMPTAIT.** Franck : *« couleur trop pastel, état pas
     clair »*. Mesuré avant d'y toucher : sur **771 lignes** peintes,
     **14 seulement étaient saturées** — 1,8 %.

     · `#DAF2D0`, l'ancien `entamee`, était le vert le plus pâle **et
       celui qu'on voyait presque toujours** : 34 relevés sur 36.
     · `#C1F0C8`, l'ancien `--etape-en-cours`, était le REPLI — l'étape
       courante dont l'avancement n'est pas mesuré. ⚠️ **Le retirer était
       le geste décisif** : il est plus pâle que le nouveau `entamee`, et
       le laisser aurait déplacé la rampe **en gardant la teinte la plus
       pâle en place**. Le repli prend donc `--etape-entamee` : « en
       cours, au minimum entamée » est vrai par construction.

     ⚠️ **`--etape-tenue` A DISPARU, LA VALEUR NON.** La migration 60
     cesse de demander `tenue` au modèle — elle était inatteignable, la
     vue ne rendant l'avancement que pour l'étape COURANTE, laquelle a
     déjà changé quand le critère est tenu. Mais `db.py` continue de
     l'ACCEPTER, et la feuille la replie sur `--etape-bien-engagee` :
     *rien n'est perdu d'une mesure plus forte que celle qu'on garde, et
     la production, qui la demande encore, ne régresse pas.*

     ⚠️ **LES RATIOS SONT RECALCULÉS PLUS BAS** — le bloc qui les porte
     disait « aucune des huit teintes n'a bougé » ; il en reste six. */

  /* alias employés par les écrans d'administration */
  --vert: var(--bon);  --rouge: var(--alerte);
  --vert-pale: rgba(36, 96, 59, .10);
  --rouge-pale: rgba(158, 43, 33, .10);

  /* ══ LA VOIX DU TUTEUR ════════════════════════════════════════════
     ⚠️ **ELLE NE VEUT DIRE QU'UNE CHOSE : c'est le tuteur ou le
     superviseur qui parle** — ni le coach, ni le client. Le jour où elle
     décore autre chose, elle ne dit plus rien.
     C'est le rose du kit, assombri pour porter du texte : la teinte
     vient de la planche, la valeur vient de la mesure. */
  --annotation:      #8C4A57;   /* 5,0:1 sur le verre                  */
  /* ⚠️ **À .40 IL PEIGNAIT, À .22 IL TEINTE** — relevé à l'écran le
     2026-08-28. Une colonne entière de rose franc reprenait le poids
     que le fond marine avait, et ramenait le défaut qu'on venait de
     retirer : un panneau qui se distingue par sa couleur SEULE. Ce
     qui doit se voir, c'est le cadenas et la mention. */
  --annotation-fond: rgba(232, 174, 183, .22);
  --annotation-nuit: var(--annotation);

  /* ══ LES FILETS ET LE FOCUS ═══════════════════════════════════════ */
  --filet:      rgba(47, 62, 70, .13);
  --filet-fort: rgba(47, 62, 70, .26);
  --filet-nuit: rgba(47, 62, 70, .16);
  --bord:       var(--filet);
  --bord-fort:  var(--filet-fort);
  --trait:      var(--filet);
  --trait-fort: var(--filet-fort);
  --focus:      var(--sauge-plein);
  --focus-nuit: var(--sauge-plein);

  --marque:       var(--sauge-plein);
  --marque-vif:   var(--sauge-vif);
  --marque-pale:  rgba(94, 139, 126, .16);
  --marque-ombre: rgba(94, 139, 126, .30);
  --accent-clair: rgba(167, 199, 231, .22);
  --accent:       var(--bleu);
  --bleu-pale:    rgba(167, 199, 231, .22);

  /* ══ LES OMBRES ═══════════════════════════════════════════════════
     ⚠️ **LE RELIEF DE LA 3.1 EST ABANDONNÉ — ARBITRAGE DU 2026-08-28.**
     La doctrine disait *ce qui agit SORT, ce qui reçoit se CREUSE*, en
     deux ombres opposées, et cela se voyait sans lire. Le kit pose des
     ombres portées simples ; il devait être suivi.

     **Ce qui remplace le relief pour distinguer un bouton d'un champ** :
     le bouton est PLEIN et coloré, le champ est CREUX et translucide.
     La différence passe de l'ombre à la matière. */
  --pose:        0 1px 2px rgba(47,62,70,.05), 0 6px 20px rgba(47,62,70,.08);
  --pose-forte:  0 2px 4px rgba(47,62,70,.07), 0 12px 32px rgba(47,62,70,.13);
  --pose-nuit:       var(--pose);
  --pose-nuit-forte: var(--pose-forte);
  /* Un champ ne s'enfonce plus : il se creuse par la transparence et un
     filet interne d'un pixel. */
  --creuse:       inset 0 0 0 1px rgba(47,62,70,.10);
  --creuse-douce: inset 0 0 0 1px rgba(47,62,70,.07);
  --creuse-nuit:  var(--creuse);
  --saisie:       var(--creuse);
  --saisie-nuit:  var(--creuse);
  --clair-papier:  rgba(255,255,255,.85);
  --sombre-papier: rgba(47,62,70,.10);
  --clair-nuit:    rgba(255,255,255,.5);
  --sombre-nuit:   rgba(47,62,70,.12);
  --relief:      none;
  --relief-doux: none;

  /* ══ LES RAYONS ═══════════════════════════════════════════════════
     Le kit est très arrondi : ses champs et ses boutons portent le rayon
     que ce produit réservait à ses pastilles. */
  /* ⚠️ **`--r-fin` EST NÉ LE 2026-08-29** : seize déclarations arrondissaient
     des jauges, des barres et des puces à 4, 6 ou 7 px, faute d'un cran sous
     `--r`. Un jeton qui manque est une valeur qu'on réinvente à chaque écran. */
  --r-fin:     6px;   /* jauges, barres, puces — plus petit qu'un bloc  */
  --r:        12px;   /* champs, boutons, petits blocs                  */
  --r-doux:   18px;   /* une carte                                      */
  --r-panneau: 24px;  /* un grand panneau de verre                      */
  --r-plein:  999px;
  /* ══ LA TOUCHE — UN VERRE BOMBÉ DANS UN CADRE MÉTALLIQUE ═════════
     ⚠️⚠️ **DEMANDE DE FRANCK, 2026-08-29, PLANCHE À L'APPUI** : *« il faut
     changer le design de ce bouton, et de tous les autres. Tous éléments
     cliquables doit avoir le style de l'image ».*

     **Ce que la planche montre, et qu'aucune de ces trois lignes n'est
     décorative** : un CADRE de métal qui prend la lumière en haut et en
     bas et s'assombrit au milieu — c'est lui qui donne l'épaisseur ; un
     CORPS presque blanc coupé par une arête horizontale vers la moitié —
     c'est le glacis, et il fait le bombé ; une PORTÉE douce dessous.

     ⚠️ **LE CADRE SE FAIT PAR `background-clip`, PAS PAR `border-color`.**
     Une bordure CSS ne prend qu'une couleur : un cadre en dégradé
     n'existe qu'en peignant deux fonds, l'un jusqu'au bord intérieur
     (`padding-box`), l'autre jusqu'au bord extérieur (`border-box`), la
     bordure elle-même étant transparente. *C'est la seule façon d'avoir
     du métal sur une pilule sans une image.*

     ⚠️ **LA CASSURE DU CORPS EST À 46 %, ET ELLE COMPTE.** Deux arrêts
     collés — 46 % clair, 46,5 % plus sombre — font une ARÊTE nette, pas
     un dégradé. C'est elle qu'on lit comme du verre bombé ; un dégradé
     continu se lit comme un aplat sale. */
  /* ⚠️ **LE CHROME DESCEND VITE ET REMONTE VITE.** Un dégradé régulier
     du blanc au gris donne du plastique ; ce qui fait le métal est la
     BANDE SOMBRE étroite au milieu, prise entre deux lumières franches.
     *Première version trop douce — le cadre ne se lisait pas à l'écran,
     mesuré sur une capture de l'élément.* */
  --chrome:       linear-gradient(180deg,
                    #ffffff 0%, #eef3f5 6%, #a8b3b9 16%,
                    #5a656b 34%, #414b51 50%, #6b757b 62%,
                    #b4bec3 78%, #f2f6f7 93%, #ffffff 100%);
  /* ⚠️ **LE GLACIS EST UNE CALOTTE, PAS UNE BANDE.** La planche montre
     une séparation COURBE entre la moitié claire et le corps : c'est elle
     qui fait le bombé. Une ligne droite se lit comme deux aplats
     empilés. L'ellipse est placée au-dessus du bouton et déborde de part
     et d'autre, ce qui lui donne sa courbure douce. */
  --touche:       radial-gradient(ellipse 132% 94% at 50% -20%,
                    #ffffff 0%, #ffffff 52%, rgba(255,255,255,0) 53%),
                  linear-gradient(180deg,
                    #eef3f5 0%, #e2e9ec 58%, #f4f8f9 100%);
  --touche-vive:  radial-gradient(ellipse 132% 94% at 50% -20%,
                    #ffffff 0%, #ffffff 56%, rgba(255,255,255,0) 57%),
                  linear-gradient(180deg,
                    #f5f9fa 0%, #eaf1f4 58%, #ffffff 100%);
  --touche-creuse: radial-gradient(ellipse 132% 94% at 50% -20%,
                    #e9eff1 0%, #e9eff1 48%, rgba(255,255,255,0) 49%),
                  linear-gradient(180deg,
                    #d8e0e4 0%, #e6edef 60%, #f6fafb 100%);
  /* Le relief de la touche, dans l'ordre où l'œil le lit : l'arête du
     haut, le creux du bas, le liseré de lumière sous le cadre, la
     portée. */
  /* ⚠️ **LE PREMIER TRAIT EST UN LISERÉ EXTÉRIEUR, ET IL EST
     NÉCESSAIRE** : sur un fond clair, un cadre qui finit en blanc pur se
     dissout dans la page. Un demi-pixel d'encre à 30 % ferme le
     contour. */
  --touche-relief: 0 0 0 .5px rgba(47, 62, 70, .30),
                   inset 0 1px 0 #ffffff,
                   inset 0 -2px 3px rgba(47, 62, 70, .13),
                   0 1px 0 rgba(255, 255, 255, .85),
                   0 5px 12px rgba(47, 62, 70, .24);
  --touche-relief-fort: 0 0 0 .5px rgba(47, 62, 70, .34),
                        inset 0 1px 0 #ffffff,
                        inset 0 -2px 3px rgba(47, 62, 70, .10),
                        0 1px 0 rgba(255, 255, 255, .9),
                        0 9px 20px rgba(47, 62, 70, .30);
  --touche-relief-enfonce: 0 0 0 .5px rgba(47, 62, 70, .34),
                           inset 0 2px 5px rgba(47, 62, 70, .26),
                           0 1px 2px rgba(47, 62, 70, .18);  /* pastilles, jetons, puces                       */
  --r-grand: var(--r-doux);
  --r-moyen: var(--r);
  --r-petit: var(--r);

  /* ⚠️ **LA GOUTTIÈRE**, et sa largeur est CONSTANTE sur tous les
     écrans : c'est ce qui fait qu'on lit la marge d'un écran à l'autre
     sans réapprendre où regarder. */
  --gouttiere: 3.4rem;

  /* ══ LES BLANCS DE REFLET ═════════════════════════════════════════
     ⚠️ **TROUVÉS PAR `verif_gabarits` LE 2026-08-29, APRÈS LA
     CENTRALISATION** — et c'est ce qui prouve que le contrôle sert : ils
     avaient échappé aux quatre passes faites à la main. `#fff` dans trois
     feuilles, deux paliers de reflet dans deux chacun.

     ⚠️ **`--blanc` N'EST PAS UN FOND**, et le nom doit le dire : sur cette
     direction, un fond est du VERRE. Le blanc pur ne sert qu'à la lumière
     — une arête, le haut d'un dégradé, le pouce d'un interrupteur. */
  --blanc:         #fff;                        /* le blanc pur — un reflet, jamais un fond */
  --reflet:        rgba(255, 255, 255, .55);    /* la lumière d'un dégradé de verre */
  --reflet-nul:    rgba(255, 255, 255, 0);      /* sa fin — un dégradé s'éteint, il ne coupe pas */

  /* ══ LES COULEURS QUI ÉTAIENT ÉCRITES DANS DEUX FEUILLES ══════════
     ⚠️ **UNE COULEUR ÉCRITE DEUX FOIS EST UNE DÉCISION PRISE DEUX
     FOIS** — 2026-08-29. Elle tient tant que personne ne touche à l'un
     des deux endroits, et le jour où quelqu'un le fait, **rien ne
     signale que l'autre n'a pas suivi**. Les huit ci-dessous étaient
     dans ce cas, relevées en croisant les vingt feuilles. */
  --fond-anomalie:       #f3dedc;                 /* le fond d'une étiquette « anomalie » */
  --fond-suggestion:     #dde9e0;                 /* le fond d'une étiquette « suggestion » */
  --fond-question:       #f2e6cc;                 /* le fond d'une étiquette « question » */
  --fond-satisfaction:   #dcdff2;                 /* le fond d'une étiquette « satisfaction » */
  --filet-pale:          #e2e2e2;                 /* un filet de séparation, plus clair que --filet */
  --mesure-bleu:         #2b6ca8;                 /* le bleu des écrans de mesure — consommation */
  --mesure-vert:         #1e7a45;                 /* le vert des écrans de mesure — les montants sur consommation, la séance sur temps */
  --rose-appui:          #f0c2c9;                 /* le rose du kit, en survol d'action secondaire */

  /* ══ L'ÉCHELLE TYPOGRAPHIQUE — SEPT CRANS, ET PAS UN DE PLUS ══════
     ⚠️⚠️ **LES VINGT FEUILLES ÉCRIVAIENT 336 `font-size` POUR 51
     VALEURS DISTINCTES — 2026-08-29, demande de Franck : « le graphisme
     n'est pas cohérent d'une page à l'autre ».**

     Il avait raison sur le constat, et la mesure a déplacé la cause :
     ce n'était pas la dispersion des fichiers, c'était que **chaque
     feuille inventait sa valeur**. `.78` et `.79`, `.81` et `.82` :
     **un sixième de pixel d'écart**, qu'aucune décision ne fonde et que
     personne ne distingue.

     ⚠️ **CHAQUE CRAN EST LE PIC DE FRÉQUENCE DE SON GROUPE**, pas une
     progression théorique : c'est ce qui fait que le moins d'endroits
     possible changent d'apparence. Une échelle géométrique aurait été
     plus élégante et aurait déplacé trois fois plus de texte.

     **Une feuille de page n'écrit plus jamais une taille.** Si aucun
     cran ne convient, c'est l'échelle qu'on discute — pas la feuille
     qu'on excepte. */
  --taille-mention:    .68rem;   /* mentions, unités, exposants — le plus petit qui reste lisible */
  --taille-etiquette:  .74rem;   /* étiquettes, intitulés de colonne, aides brèves */
  --taille-aide:       .8rem;    /* les textes d'aide et les seconds rôles */
  --taille-courant:    .87rem;   /* le texte courant d'interface : libellés, menus, touches */
  --taille-lecture:    .92rem;   /* ce qui se lit en continu : paragraphes, statuts */
  --taille-appui:      .97rem;   /* ce qui doit ressortir sans être un titre */
  --taille-fort:       1.05rem;  /* un sous-titre, une valeur mise en avant */
}


/* ══ §ALIAS — LES JETONS DE LA 2.0, LE TEMPS DE LA CONVERSION ══════
   ⚠️ **NE PAS SUPPRIMER CE BLOC AVANT QUE LES QUATORZE ÉCRANS SOIENT
   CONVERTIS.** Il est ce qui permet de poser la feuille aujourd'hui et
   de convertir demain. Le retirer trop tôt rend blanches des pages
   entières — les gabarits non convertis n'écrivent que ces noms-là.

   **Date de péremption : le jour où `DIRECTION-VISUELLE.md` §6 ne porte
   plus aucune ligne « à faire ».** Ce jour-là, supprimer ce bloc, puis
   lancer `python scripts/verif_gabarits.py` : toute page qui redevient
   illisible portait encore un jeton mort. */
/* ══ § ALIAS — LES NOMS QUE LES SEIZE ÉCRANS ÉCRIVENT ENCORE ═══════
   ⚠️ **CE BLOC A CHANGÉ DE MÉTIER LE 2026-08-28.** Il servait à ÉTEINDRE
   le relief de la 2.0 pendant la conversion, avec quatre `!important`
   qu'il assumait comme un échafaudage. Le relief n'existe plus du tout :
   les extincteurs n'ont plus rien à éteindre, et ils partent avec.

   ⚠️ **ET IL RÉÉCRIVAIT `--marque` EN PLEINE ENCRE.** Posé APRÈS le bloc
   des jetons, il gagnait : la sauge du kit n'aurait jamais atteint un
   bouton. Le défaut aurait été invisible — deux blocs `:root` dans le
   même fichier, le second silencieusement vainqueur. **C'est exactement
   la maladie que la journée a passé à soigner, à l'intérieur d'un seul
   fichier cette fois.** Les jetons de marque sont revenus dans le bloc
   principal ; ce qui reste ici ne fait que renommer. */
:root {
  --police:          var(--titre);
  --police-chiffres: var(--chiffres);
  --fond-doux: var(--verre-vif);
  --ambre: var(--attention);   /* l'accueil l'appelle ainsi */

  /* Les ombres écrites EN DUR par un gabarit non converti sont éteintes
     par la couleur : la géométrie subsiste, elle ne peint rien. */
  --lumiere:     transparent;
  --ombre:       var(--sombre-papier);
  --ombre-forte: var(--nuit-clair);
}

/* ⚠️ **ÉTEINDRE LE CREUX FAIT DISPARAÎTRE LES CHAMPS DE SAISIE, ET C'EST
   MESURÉ.** L'aperçu de l'accueil du 2026-08-17 a rendu les deux champs
   du bloc Administration **invisibles** : plus de bordure du tout.

   La cause est écrite noir sur blanc dans la feuille 2.0 : *« la bordure
   disparaît — c'est le creux qui dessine le champ »*. Les gabarits posent
   donc `border: 0` et comptent sur l'ombre. Éteindre l'ombre laisse un
   rectangle de la couleur exacte de la page.

   **Un champ de formulaire invisible n'est pas un défaut cosmétique.**
   D'où cette règle, qui rend le filet et **rien d'autre** — pas le fond,
   pour ne pas écraser `.nuit input` d'un écran déjà converti.

   Échafaudage, comme le reste de ce bloc : elle part avec lui. */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="search"],
select, textarea {
  border: 1px solid var(--filet-fort) !important;
}


/* ══ LA BASE ═══════════════════════════════════════════════════════
   Ce bloc ne pose que des **surfaces** et des **familles** : aucune
   marge, aucun cadre de mise en page. Les quatorze `<style>` en ligne
   ont chacun leur idée de la largeur et du remplissage, et cette
   feuille perd toujours contre eux à spécificité égale — elle est
   chargée avant. */

/* ⚠️ **CE QUI PRÉCÈDE A CESSÉ D'ÊTRE VRAI LE 2026-08-28**, et c'est
   l'objet de la reprise du jour. La CSS des gabarits est sortie dans
   `app/static/pages/` ; les largeurs, les titres et les encarts sont
   posés ICI, une fois, et les feuilles de page ne les redéfinissent
   plus. **Mesure d'avant** : onze largeurs de page — 46, 48, 52, 54,
   60, 62, 64, 66, 68, 74 rem et une page sans max-width ; `h1` écrit
   dans **seize** fichiers ; `.sous-titre` dans quatorze. */

/* ── LA LARGEUR DE PAGE — TROIS, NOMMÉES PAR USAGE ─────────────────
   ⚠️ **PAS UNE SEULE VALEUR, ET C'EST DÉLIBÉRÉ.** Un formulaire et un
   tableau de bord ne se lisent pas à la même largeur : à 74 rem un
   texte suivi devient illisible, à 48 rem un graphique se replie. Ce
   qu'on supprime, ce ne sont pas les différences — ce sont les ONZE
   nombres écrits à la main, dont personne ne savait dire pourquoi
   `paiements` valait 52 et `tarification` 60.

   Une page choisit son usage en une ligne, dans sa feuille :
       body { max-width: var(--page-large); }
   Elle n'écrit plus jamais un nombre. */
:root {
  /* ⚠️⚠️ **ÉLARGIES DE HUIT REM LE 2026-09-06 — DEMANDE DE FRANCK :
     « avoir des surfaces vitrées plus grandes ».** La plaque de niveau 0
     **est** le corps : sa largeur est celle de la page, et c'est donc
     ici, et nulle part ailleurs, que le verre grandit. *Une feuille de
     page qui élargirait sa propre plaque serait la faute que l'interdit
     n°8 nomme — la matière appartient à la feuille partagée.*

     ⚠️ **`--page-lecture` GRANDIT MOINS QUE LES DEUX AUTRES**, et ce
     n'est pas une inattention : elle porte du texte suivi, dont la
     longueur de ligne est un critère de lisibilité et non de place
     disponible. *Six rem, pas huit.* */
  /* ⚠️⚠️ **90 % DE LA FENÊTRE LE 2026-09-06 — DEMANDE DE FRANCK :
     « les surfaces vitrées doivent couvrir 90 % de la surface affichée ».**
     Les trois largeurs deviennent des PLAFONDS et non plus des cibles :
     `min(90vw, <plafond>)`. Sur un écran ordinaire c'est le `90vw` qui
     gagne ; le plafond ne reprend la main que sur un très grand écran,
     **et il le faut** — une ligne de texte de 1 700 px ne se lit pas.

     ⚠️ *`--page-lecture` garde le plafond le plus bas : la longueur de
     ligne est un critère de lisibilité, pas de place disponible.* */
  --page-lecture:  min(90vw, 66rem);   /* du texte suivi : formulaires */
  --page-standard: min(90vw, 92rem);   /* le défaut : listes, réglages */
  --page-large:    min(90vw, 108rem);  /* tableaux denses, la séance   */

  /* ⚠️ **LA QUATRIÈME, AJOUTÉE LE 2026-08-30 À LA DEMANDE DE FRANCK** —
     « la page de détails des processus doit prendre toute la largeur de
     la fenêtre ». Elle est ici, NOMMÉE, et non écrite en dur dans une
     feuille de page : c'est toute la raison d'être de ce bloc, qui a
     remplacé ONZE largeurs écrites à la main dont personne ne savait
     dire pourquoi `paiements` valait 52 et `tarification` 60.

     ⚠️ **ELLE NE CONVIENT PAS À DU TEXTE SUIVI**, et il faut le savoir
     avant de s'en servir ailleurs : le commentaire ci-dessus le dit déjà
     de la large — « à 74 rem un texte suivi devient illisible ». À pleine
     largeur, une ligne dépasse cent-cinquante signes. La fiche de
     processus l'assume parce qu'elle est **structurée en sections avec
     un sommaire latéral**, pas lue d'un trait comme une page de texte. */
  --page-pleine:   none;    /* la fiche de processus : toute la fenêtre  */
}

/* ══ LE FOND D'AMBIANCE ═══════════════════════════════════════════
   ⚠️ **`position: fixed` ET `z-index: -1` — LES DEUX, PAS L'UN.** Fixe,
   il ne défile pas avec la page : le décor reste immobile pendant que
   les plaques glissent dessus, ce qui est exactement l'effet du kit.
   Et derrière tout, sans quoi il faudrait poser un `z-index` sur chaque
   plaque — dix-huit occasions d'en oublier une.

   ⚠️ **`object-fit: cover` ET RIEN D'AUTRE.** La vidéo fait 1280×720 ;
   sur un écran plus large ou plus haut, tout autre ajustement la
   déforme ou laisse une bande blanche sur un bord. */
.fond-ambiance {
  /* ⚠️⚠️ **`-2` ET NON `-1` DEPUIS LE 2026-08-28.** Le corps floute
     désormais par `body::before`, lui aussi en `z-index: -1` : à valeur
     ÉGALE, c'est l'ordre de l'arbre qui tranche, et le pseudo-élément
     est le PREMIER enfant du corps — donc **peint dessous**. Le fond
     d'ambiance, opaque, le recouvrait entièrement et son
     `backdrop-filter` ne capturait plus que le fond plat de `html` :
     **le flou de la grande plaque ne se produisait pas.**

     ⚠️ **ET LA MESURE LE DISAIT, MAIS J'AI LU LA MAUVAISE CAUSE.**
     `getComputedStyle` rendait bien `blur(30px)` sur le pseudo — la
     PROPRIÉTÉ était appliquée. Ce qui manquait n'était pas la règle,
     c'était sa visibilité. *Une propriété appliquée et un effet visible
     sont deux choses différentes ; `getComputedStyle` ne connaît que la
     première.* Trouvé par `/code-review`. */
  position: fixed; inset: 0; z-index: -2;
  overflow: hidden; pointer-events: none;
  background: var(--blanc-casse);
}
/* ⚠️ **`img` DEPUIS LE 2026-09-06** — le fond d'ambiance était une vidéo
   de 5 941 Ko, il est une image de 125. Les propriétés ne changent pas :
   `object-fit: cover` fait le même travail sur les deux. */
.fond-ambiance img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* ⚠️ **LE VOILE EST CE QUI REND LISIBLE CE QUI N'EST PAS SUR UNE PLAQUE.**
   *Il était écrit « ce qui rend LA PAGE lisible », et c'était vrai tant que
   les plaques étaient translucides ; depuis le 2026-09-06 elles posent
   `--fond-flou`, une image **opaque** qui recouvre le voile.* **Ce qu'il
   tient encore, et c'est réel : le rail, les marges, les bords de page** —
   c'est précisément là que le rail perdait son contraste, et il a fallu lui
   donner son propre blanc (`--rail-fond`, dans `navigation.css`).

   ⚠⚠ **ET LA MESURE CI-DESSOUS PORTE SUR UNE VIDÉO QUI N'EST PLUS SERVIE.**
   `fond-ambiance.webm` a été remplacé par une image fixe le 2026-09-06 : il
   n'y a plus ni boucle, ni 24 images, ni pire instant. *Le chiffre est
   conservé parce qu'il dit d'où vient le voile ; il ne décrit plus ce que
   l'écran affiche.* ⚠️ **UNE VINGTAINE D'AUTRES COMMENTAIRES DE CETTE
   FEUILLE PARLENT ENCORE DE LA VIDÉO COMME PRÉSENTE** — releé par le
   vérificateur, et non purgé ici : ce serait un lot à soi seul.

   Mesuré sur les 24 images de la boucle : l'ardoise posée directement
   sur la vidéo NUE tomberait sous 2:1 au pire instant. Avec le voile et
   une plaque de verre, elle donne **7,24:1**.

   Le dégradé va du plus transparent en haut au plus couvrant en bas :
   la couleur vit là où il n'y a pas de texte long, et le bas de page —
   les tableaux, les listes — se lit sur du presque-blanc. */
.fond-voile {
  position: absolute; inset: 0;
  background: linear-gradient(178deg,
              var(--voile-haut) 0%,
              var(--voile-bas) 62%,
              var(--voile-bas) 100%);
}

body {
  font-family: var(--texte);
  background: var(--papier);
  color: var(--encre);
  line-height: 1.6;
  font-size: 15.5px;
  -webkit-font-smoothing: antialiased;

  /* ⚠️ **LE 5rem DU BAS N'EST PAS DE L'AIR — C'EST LA PLACE DE LA
     PASTILLE DE RETOUR**, qui flotte en bas à droite de chaque page.
     Sans lui, elle recouvre la dernière ligne. Trois pages écrivaient
     `4rem`, deux `0` : la pastille y mordait sur le pied de page. */
  max-width: var(--page-standard);
  /* ⚠️ **90 % DE LA HAUTEUR AUSSI — 2026-09-06.** Une plaque large mais
     courte ne couvre pas 90 % de la SURFACE : sur une page brève, elle
     s'arrêtait au tiers de l'écran. `min-height` la fait descendre ;
     `margin` symétrique laisse les 5 % de fond visibles en haut et en bas. */
  /* ⚠️ **LE REPLI `dvh` — posé le 2026-09-07 par `/boucles-up-code`.**
     Sur mobile, `vh` compte la barre d'outils du navigateur comme si elle
     n'était pas là : 90 + 2×2,5 font 95 % d'une hauteur PLUS GRANDE que
     ce qu'on voit, donc un ascenseur qui ne sert à rien. `dvh` mesure ce
     qui est réellement visible. **La déclaration se répète, elle ne se
     remplace pas** : un navigateur qui ignore `dvh` garde la première —
     même motif que `.panneau-fiche` et `.plateau`, où le dépôt écrit
     déjà `height: 80vh; height: 80dvh;`. */
  min-height: 90vh;
  min-height: 90dvh;
  margin: 2.5vh auto;
  margin: 2.5dvh auto;
  padding: 1.6rem 1.9rem 4rem;

  /* ⚠️ **LE CORPS EST LUI-MÊME UNE PLAQUE DE VERRE — 2026-08-28, ET
     C'EST CE QUE FAIT LE KIT.** Sa planche pose un grand panneau
     translucide sur la photographie, et les composants DANS ce panneau.

     ⚠️ **CE N'EST PAS UN CHOIX D'ESTHÉTIQUE, C'EST LE SEUL MOYEN DE
     TENIR LA LISIBILITÉ.** Mesuré : posée directement sur le voile,
     l'encre secondaire ne dépasse **3,85:1 même à 70 % de voile** — et
     monter le voile plus haut effacerait la vidéo, donc toute la
     direction. Sur cette plaque, elle donne 4,86. **Chaque texte de
     chaque écran est donc sur du verre par construction**, sans qu'un
     gabarit ait à y penser.

     ⚠️ **UN SEUL FLOU PAR PAGE, ET IL EST ICI.** Les panneaux internes
     ne floutent pas : ils sont simplement plus opaques. Dix
     `backdrop-filter` empilés coûtent dix passes de rendu pour un effet
     que personne ne distingue — et l'écran de séance en porterait huit.

     ⚠️ **ET SURTOUT : AUCUN `backdrop-filter` ICI.** Essayé le
     2026-08-28, et le résultat est spectaculaire. Un élément qui porte
     `backdrop-filter` — comme `filter` ou `transform` — **devient le
     bloc conteneur de ses descendants en `position: fixed`**. Posé sur
     `body`, il a enfermé DANS la page le rail de navigation *et le fond
     d'ambiance lui-même* : la colonne s'est décalée de 256 px et la
     vidéo n'a plus couvert que la largeur du contenu.

     **Le flou vit donc sur les panneaux internes et sur le rail**, qui
     ne portent aucun descendant fixe.

     ⚠️⚠️ **ET LA GRANDE PLAQUE FLOUTE DEPUIS LE 2026-08-28, PAR UN
     PSEUDO-ÉLÉMENT.** Il était écrit ici que *« la vidéo étant déjà
     douce, la différence ne se voit pas »* : **c'était une supposition,
     et Franck a mesuré le contraire à l'écran.** Entre deux panneaux, le
     fond se voyait NET à travers le corps, quand il est flou à travers
     eux — deux matières pour une seule plaque.

     ⚠️ **`body::before` PORTE LE FLOU, ET LE PIÈGE NE SE REFERME PAS
     SUR LUI.** Ce qu'un `backdrop-filter` capture, ce sont ses
     DESCENDANTS en `position: fixed` ; **un pseudo-élément n'a aucun
     descendant.** Mesuré avant d'écrire cette règle : le rectangle du
     fond d'ambiance vaut 1265 × 1000 avec et sans — au pixel près,
     alors que le poser sur `body` l'avait réduit à la largeur du
     contenu. *La règle « aucun backdrop-filter sur un élément qui
     contient un fixed » tient toujours : on ne l'a pas contournée, on a
     trouvé un porteur qui n'en contient pas.* */
  position: relative;
  /* ⚠️⚠️ **`transparent`, ET CE N'EST PAS UN ABANDON — 2026-08-29.** Il
     y avait ici `background: var(--verre)`, et **cette ligne ne peignait
     rien de ce qu'elle décrivait**. Règle du CSS : *quand `html` n'a pas
     de fond, le fond du CORPS est propagé au CANVAS* — il couvre la
     fenêtre entière, sous tout le reste, donc **sous `.fond-ambiance`**,
     qui l'efface. La plaque était nue.

     ⚠️ **CE N'EST PAS DE LA THÉORIE : C'EST MESURÉ.** Sur la page rendue
     de `/seances`, `--encre-douce` donnait **4,20:1** au pire point —
     sous le seuil de 4,5 — quand ce fichier annonçait 4,86 six lignes
     plus haut. *L'écart entre les deux nombres EST l'épaisseur du verre
     qui manquait.*

     **Le voile est donc descendu sur `body::before`**, qui épouse la
     plaque et ne propage rien. Voir la règle juste en dessous. */
  background-color: transparent;
  border: 1px solid var(--verre-bord);
  border-radius: var(--r-panneau);
  box-shadow: var(--pose), inset 0 1px 0 var(--verre-arete);
}

/* Le porteur du flou de la grande plaque. `inset: 0` et `border-radius:
   inherit` : il épouse exactement le corps, arrondis compris, sinon le
   flou déborderait aux quatre coins. `z-index: -1` le met sous le
   contenu ; `pointer-events: none` lui interdit d'intercepter un clic. */
body::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  /* ⚠️ **LE VOILE ET LA LUMIÈRE VIVENT ICI DEPUIS LE 2026-08-29**, et
     non plus sur `body` : un pseudo-élément n'est pas propagé au canvas.
     Le dégradé est recopié de la liste commune, dont `body` a été retiré
     pour la même raison — une `background-image` se propage comme une
     `background-color`. */
  /* ⚠️ **TROIS COUCHES, ET L'ORDRE EST CELUI DE LA PILE CSS** : le
     grain devant, puis le voile de verre, puis la copie floutée du fond.
     *La première ligne d'un `background` est la plus proche de l'œil.* */
  background-color: transparent;
  background-image:
    var(--verre-grain),
    linear-gradient(var(--verre), var(--verre)),
    var(--fond-flou),
    linear-gradient(180deg,
      rgba(255, 255, 255, .30) 0%, rgba(255, 255, 255, .04) 62%);
  /* ⚠️⚠️ **`soft-light` SUR LA COUCHE DE GRAIN — 2026-09-06, ET C'EST
     CE QUI SÉPARE UNE IMPERFECTION D'UNE SALISSURE.** Posé en `normal`,
     un bruit fractal **ne peut qu'assombrir** : sa moyenne est un gris
     moyen, donc les trois couches empilées couvraient **64 %** de la
     plaque de gris. *Mesuré : 41 niveaux sur 255 d'écart moyen — la
     plaque virait au gris de voile, et le verre disparaissait.*

     ⚠️ **EN `soft-light`, LE GRIS MOYEN NE FAIT RIEN.** Seuls les
     écarts comptent : le clair éclaircit, le sombre assombrit, et la
     luminance générale ne bouge pas. C'est la définition même d'un
     micro-relief — **une modulation, pas une couche**.

     ⚠️ **LES TROIS AUTRES COUCHES RESTENT EN `normal`.** Le voile de
     verre doit, lui, couvrir : c'est ce qui porte le contraste du texte,
     et le passer en fondu ferait retomber la lisibilité. */
  /* ⚠️⚠️ **`cover` SUR LA COUCHE DE GRAIN : UNE SEULE TUILE, DONC
     AUCUNE COUTURE.** À 420 px répétés, **le quadrillage se voyait** —
     `feTurbulence` n'est pas périodique, les bords ne se raccordent pas,
     et l'œil suit la grille au lieu de voir du verre. *La tuile fait
     maintenant 1600 × 1200 et se met à l'échelle de la plaque : elle est
     toujours plus grande qu'elle, donc jamais répétée.*

     ⚠️ **LE `cover` DÉFORME LÉGÈREMENT LE MOTIF**, et c'est sans
     conséquence : un bruit n'a pas d'orientation propre. *C'est ce qui
     permet de garder une seule image pour tous les formats d'écran.* */
  /* ⚠️⚠️ **`cover fixed` SUR LA COPIE FLOUTÉE — 2026-09-06, ET C'EST
     CE QUI LA CALE SUR LE FOND NET.** Elle était en `auto` / `repeat` :
     **mesuré sur la page de séance, plaque de 1 400 px pour une image de
     1 280, elle SE RÉPÉTAIT verticalement** — la couture passait au
     milieu de l'écran.

     ⚠️ **`fixed` N'EST PAS UN DÉTAIL DE CADRAGE.** Le fond net est un
     `<img>` en `position: fixed` et `object-fit: cover` ; sa copie
     floutée doit se caler sur le **même** repère, sinon les deux images
     se décalent et le verre montre un morceau de paysage qui n'est pas
     celui qu'il recouvre. *C'est déjà ce que fait `connexion.css` ; la
     grande plaque était la dernière à ne pas le faire.* */
  background-size: cover, auto, cover, auto;
  background-repeat: no-repeat, repeat, no-repeat, repeat;
  background-attachment: scroll, scroll, fixed, scroll;
  background-blend-mode: soft-light, normal, normal, normal;
  /* ⚠️⚠️ **PLUS DE `backdrop-filter` ICI — IL NE POUVAIT PLUS RIEN
     MONTRER.** La couche `--fond-flou` est une image **opaque** qui
     couvre toute la plaque : ce que le filtre floutait derrière elle
     n'atteignait jamais l'œil. *Une passe de rendu en `blur(90px)` sur
     toute la fenêtre, à chaque page, pour zéro pixel visible.*

     ⚠️ **`--flou` RESTE DÉFINI ET RESTE UTILE** : les barres collantes
     (`.bandeau` de la consommation, des comptes) l'emploient toujours,
     et là il sert — du texte défile dessous, il faut le brouiller. *Ce
     qui est retiré est le flou de la GRANDE PLAQUE, pas le jeton.* */
  z-index: -1;
  pointer-events: none;
}

/* ── LA LUMIÈRE SUR LE VERRE — 2026-08-28 ────────────────────────
   ⚠️ **UNE PLAQUE UNIFORME NE SE LIT PAS COMME DU VERRE, MÊME FLOUTÉE.**
   Ce qui manquait, la planche de Franck le montre : ses sphères ont
   toutes **une lumière en haut et une ombre en bas**. C'est ce dégradé,
   et lui seul, qui fait la matière — le flou fait la transparence.

   Il est posé en `background-image` et non en `background` : le fond de
   couleur reste où il est, chaque plaque garde le sien.

   ⚠️ **`.lancements > *` A QUITTÉ CETTE LISTE ET LA SUIVANTE —
   2026-08-30.** Les deux façons de lancer ne sont plus deux colonnes
   d'une grille mais une action puis un bandeau ; le conteneur a disparu
   d'`accueil.html`, seul gabarit à le porter. *Signalé par
   `verif_gabarits.py` dans la minute : « stylée dans une feuille
   PARTAGÉE et employée nulle part ».* */
.verre, [class*="carte"], [class*="panneau"], [class*="bloc-"],
section.choix, .option {
  background-image: linear-gradient(180deg,
      rgba(255, 255, 255, .30) 0%, rgba(255, 255, 255, .04) 62%);
}

/* ══ LE VERRE — LA PIÈCE CENTRALE DE LA DIRECTION ═════════════════
   ⚠️ **UNE SEULE DÉFINITION, ET TOUT CE QUI EST UN PANNEAU LA PREND.**
   Les seize écrans nomment leurs blocs de dix façons — `carte`, `bloc`,
   `panneau`, `section`, `option`… Les rattacher un par un aurait
   demandé d'ouvrir seize feuilles ; le sélecteur d'attribut les attrape
   par leur nom, comme le fait déjà le désamorçage de contraste.

   ⚠️ **`-webkit-backdrop-filter` EST OBLIGATOIRE.** Safari ne connaît
   pas la propriété non préfixée avant la 18 : sans elle, la moitié des
   Mac voit des plaques laiteuses sans flou — pas cassées, mais mortes.

   ⚠️ **L'ARÊTE DU HAUT EST CE QUI FAIT LA TRANCHE.** Une plaque sans
   elle ne se lit pas comme du verre mais comme un rectangle sale : le
   liseré blanc de un pixel simule la lumière qui accroche le bord
   supérieur. C'est le même constat que la carte de connexion 3.1,
   relevé alors sur douze vidéos. */
.verre, [class*="carte"], [class*="panneau"], [class*="bloc-"],
section.choix, .option {
  /* ⚠️ **`background-color` ET NON `background` — 2026-08-28.** Le
     raccourci remet **`background-image` à `none`**, et il effaçait donc
     le dégradé de lumière posé plus haut sur cette même liste de
     sélecteurs, à la même spécificité. *La règle existait, elle était
     annulée par la suivante : la fonction n'avait aucun effet visible.*
     Trouvé par `/code-review`. */
  /* ⚠️⚠️ **NIVEAU 1 : `--verre-vif`, ET AUCUN FLOU — 2026-08-29.** Ces
     zones sont posées SUR la plaque du corps, qui floute déjà. Elles
     portaient `--verre` (26 %) **et un second `backdrop-filter`** : deux
     passes de rendu, et 45 % de blanc dès que la plaque a repris le
     sien. *Ce qui fait avancer une zone n'est pas son opacité, c'est son
     filet — c'est ce que `/retours` montrait déjà.* */
  background-color: var(--verre-vif);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  /* ⚠️⚠️ **LE FILET D'ENCRE REMPLACE LA BORDURE BLANCHE — 2026-08-29,
     DEMANDE DE FRANCK : « le traitement des zones de toutes les pages,
     calqué sur `/retours` ».**

     **Ce qui distingue cet écran-là, mesuré et non deviné** : ses zones
     portent `box-shadow: var(--creuse)` — un filet **d'encre à 10 %**,
     posé à l'intérieur — quand les plaques portaient une bordure
     **blanche à 45 %**. Sur un fond clair, le blanc ne délimite rien :
     on devinait les zones, on ne les lisait pas. Le filet d'encre, si.

     ⚠️ **CE QUI N'A PAS ÉTÉ COPIÉ, ET POURQUOI.** Les zones de
     `/retours` sont **transparentes** — elles écrivent
     `background: var(--papier)`, rédigé quand `--papier` valait du
     BLANC. Depuis la 3.1 il vaut `transparent` : **elles sont sans fond
     par accident, pas par dessein.** Mesuré sur la page rendue : le
     libellé d'un compteur y tombe à **4,35:1**, sous le seuil de 4,5,
     faute d'une seconde couche sous le texte. *Calquer à la lettre
     aurait généralisé un défaut ; on calque ce qui se voit — le filet —
     et on garde le fond, qui tient la lisibilité.*

     L'arête blanche part avec la bordure : deux traits sur le même bord
     se battaient, et c'est le filet qui gagne — il fait le tour. */
  border: 0;
  border-radius: var(--r);
  box-shadow: var(--creuse);
}

/* ══ NIVEAU 2 — UNE ZONE DANS UNE ZONE NE POSE PLUS RIEN ═══════════
   ⚠️⚠️ **RETOURNÉ LE 2026-08-29.** Il était écrit ici qu'*« une carte
   interne est simplement plus opaque — c'est ce qui la fait avancer »*,
   et elle recevait 36 %. **C'était le raisonnement d'une page sur du
   papier.** Sur du verre, l'opacité ne fait pas avancer : elle efface le
   fond, et la troisième couche donne un rectangle blanc. Mesuré sur
   `/accueil` : `.option.principale` = **59 % de blanc** pour 26 attendus.

   **Ce qui fait avancer une zone de niveau 2 est son FILET, et rien
   d'autre.** C'est le traitement de `/retours` que Franck a demandé le
   2026-08-28, poussé jusqu'à sa conséquence.

   ⚠️ **`:is()` PLUTÔT QUE LE PRODUIT DES SÉLECTEURS.** La famille de
   niveau 1 compte six formes : les écrire deux à deux ferait
   **trente-six sélecteurs** à tenir à jour à chaque ajout. Sa
   spécificité est celle de son argument le plus fort — `section.choix`,
   soit (0,1,1) — ce qui donne (0,2,2) à la règle : **elle passe donc
   devant un `.option.principale` d'une feuille de page**, et c'est
   voulu.

   ⚠️ **IL Y AVAIT ICI UNE PORTE DE SORTIE, `.verre-vif`, ET ELLE EST
   PARTIE LE 2026-08-29.** Elle permettait à une zone de garder un fond
   quelle que soit sa profondeur. **Personne ne l'a jamais employée** —
   née le 2026-08-28, orpheline le lendemain, relevée par le contrôle
   d'orphelinat des feuilles partagées. *Le jour où une zone en aura
   vraiment besoin, elle se réécrit en quatre lignes ; la garder « au
   cas où » l'aurait servie à chaque page pendant des mois.* */
:is(.verre, [class*="carte"], [class*="panneau"], [class*="bloc-"],
    section.choix, .option)
:is(.verre, [class*="carte"], [class*="panneau"], [class*="bloc-"],
    section.choix, .option) {
  background-color: transparent;
  background-image: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: var(--creuse);
  border: 0;
  border-radius: var(--r);
}

/* ══ CE QUE LE CLIENT VIRTUEL NE VOIT PAS ═════════════════════════
   ⚠️ **CETTE CLASSE REMPLACE LE FOND SOMBRE, ET C'EST LA CONTREPARTIE
   DE « TOUT EN CLAIR ».** La règle D19 se lisait à la couleur : la
   colonne de nuit était ce que le client ne voit pas. Le kit n'ayant
   qu'une ambiance claire, **ce que le fond disait doit être écrit**.

   Trois signaux, et aucun n'est une couleur seule :
     · un CADENAS en tête, posé par `::before` sur le titre ;
     · une MENTION en toutes lettres, que le gabarit écrit ;
     · un LISERÉ interrompu — le seul trait discontinu du produit.

   *Moins immédiat que le fond sombre, et il faut le dire. Mais un trait
   discontinu et un mot survivent à un écran monochrome et à un
   daltonien, ce que le marine ne faisait qu'à moitié.* */
.hors-vue {
  border: 1px dashed var(--annotation) !important;
  background: var(--annotation-fond);
}
.hors-vue > .colonne-titre h2::before {
  content: "\1F512\00A0";   /* 🔒 */
  font-size: .9em;
}
.mention-hors-vue {
  font-family: var(--titre); font-size: var(--taille-mention); font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--annotation);
  display: inline-flex; align-items: center; gap: .35rem;
}

/* ══ CE QUE L'ŒIL NE VOIT PAS, ET QUE LE LECTEUR D'ÉCRAN LIT ═══════
   Posée le 2026-09-03 (/boucles-up-code, lot 7, COR-013 — HT-23, WCAG
   1.3.1). Vingt-deux tableaux n'avaient pas de `<caption>` : un lecteur
   d'écran annonçait « tableau, 4 colonnes » sans dire de quoi. Or une
   légende est VISIBLE par défaut, et l'écrire à l'écran aurait changé
   douze pages — Franck a tranché : lue, pas vue.

   ⚠️ **CE N'EST PAS `display: none`, ET C'EST TOUT LE POINT.** `none` et
   `visibility: hidden` retirent l'élément de l'arbre d'accessibilité :
   la légende n'existerait plus pour personne. Ici l'élément reste rendu,
   ramené à un pixel, rogné, hors du flux — présent pour la synthèse
   vocale, absent pour l'œil. C'est le motif « visually hidden » que
   tous les référentiels d'accessibilité reprennent tel quel.

   ⚠️ **NE PAS L'EMPLOYER POUR CACHER UN CONTRÔLE INTERACTIF** : un bouton
   masqué ainsi reçoit encore le focus, et le clavier tomberait sur un
   élément que l'écran ne montre pas. Pour ça, c'est `hidden`. */
.masque-visuel {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ⚠️ **LES TITRES SONT DE LA MESURE, PAS DE LA PAROLE.** Un titre
   nomme un écran ou un bloc : c'est de l'appareillage. Le serif est
   réservé à ce qui a été dit ou écrit par quelqu'un. */
h1, h2, h3, h4, th, label, button, .mesure {
  font-family: var(--mesure);
}

/* ── LE TITRE DE PAGE — UNE SEULE DÉFINITION ───────────────────────
   ⚠️ **IL Y EN AVAIT DEUX, ET ELLES S'OPPOSAIENT SUR LES QUATRE
   PARAMÈTRES À LA FOIS.** Mesuré à l'écran le 2026-08-28 :

     · `accueil`  — 32 px · graisse 800 · minuscules · interlettre −1,12 px
     · `retours`  — 16 px · graisse 600 · MAJUSCULES · interlettre +0,96 px

   Ce ne sont pas deux variantes d'un même titre, ce sont deux systèmes
   typographiques dans un même produit. **Celle qui l'emporte est la
   grande**, pour une raison qui n'est pas un goût : la petite version
   en capitales espacées est déjà, dans ce dépôt, la forme de
   l'ÉTIQUETTE — `.qui`, `.marge`, les intitulés de colonne. Un titre de
   page qui prend l'habit d'une étiquette ne se distingue plus de ce
   qu'il surplombe. */
/* ⚠️ **LES VALEURS ONT CHANGÉ AVEC LA POLICE — 2026-08-28.** Archivo
   supportait `800` et `-.035em` : c'est une grotesque étroite, elle se
   serre bien. **Inter serrée à ce point devient illisible** — ses
   contreformes sont larges, et le resserrement les écrase les unes sur
   les autres. Le kit affiche ses titres en `Bold` (700) sans
   resserrement notable. On le suit. */
h1 {
  font-family: var(--titre);
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -.018em;
  line-height: 1.2;
  margin: 0 0 .2rem;
}
h2, h3 { font-family: var(--titre); font-weight: 700; letter-spacing: -.012em; }

/* La ligne qui suit le titre et dit à quoi sert l'écran. Quatorze
   fichiers l'écrivaient, avec deux encres et trois tailles.

   ⚠️⚠️ **ELLE PREND L'ENCRE PLEINE DEPUIS LE 2026-08-28, ET C'EST UNE
   CORRECTION DE CONTRASTE, PAS UN CHOIX D'ESTHÉTIQUE.** Le verre ayant
   cessé d'être du blanc, le corps n'a plus qu'UNE couche là où un
   panneau en a deux : mesuré sur quatre instants de la boucle vidéo,
   l'encre douce y donnait **4,05:1** au pire — sous le seuil de 4,5 —
   quand la même encre dans un panneau donnait 5,09. En encre pleine, au
   même instant et sur le même fond : **6,04:1**.

   ⚠️ **LA HIÉRARCHIE NE PERD RIEN**, et la direction l'avait écrit avant
   d'en avoir besoin : *« il n'y a plus que deux niveaux d'encre… la
   hiérarchie se fait désormais à la taille et à la graisse, plus à la
   pâleur »*. Le titre fait 1,5 rem en 800, cette ligne .92 rem en 400 :
   elles ne se confondent pas parce qu'elles partagent une encre.

   ⚠️ **CE QUI RESTE À VÉRIFIER EN RECETTE** : les autres textes
   secondaires posés DIRECTEMENT sur le corps — pieds de page, aides hors
   panneau — sont dans le même cas et n'ont pas été mesurés un par un. */
.sous-titre {
  color: var(--encre);
  font-size: var(--taille-lecture);
  margin: 0 0 1.4rem;
}

/* ── L'ENCART DE MESSAGE — UNE FORME, TROIS TONS ───────────────────
   ⚠️ **IL Y AVAIT SIX FAÇONS DE DIRE « LIS CECI »**, relevées à
   l'écran le 2026-08-28 : une pastille à point vert, une carte
   bleutée, un texte ambre, un pavé brun plein, un encadré en
   pointillés, un filet vertical. Six formes pour une seule intention,
   et le lecteur devait apprendre six fois la même chose.

   **La forme est unique : un filet à gauche sur du papier.** Ce qui
   change est le TON du filet, et lui seul — c'est le seul endroit du
   système où la couleur porte du sens sans redondance de forme, parce
   que le mot qui suit le dit aussi. */
.message, .erreur, .avis {
  background: var(--papier);
  box-shadow: var(--creuse);
  border-left: 4px solid var(--encre-pale);
  border-radius: 0 var(--r) var(--r) 0;
  padding: .85rem 1.1rem;
  margin: 0 0 1.3rem;
  font-size: var(--taille-lecture);
}
.message { border-left-color: var(--bon); }
.erreur  { border-left-color: var(--alerte); }

/* ── LES DEUX CAMPS, EN CLASSES ────────────────────────────────────
   ⚠️ **UN GABARIT NE PEINT PAS UN BLOC SOMBRE À LA MAIN.** Il pose
   `class="nuit"` et hérite du triplet complet — fond, texte, filets,
   focus. Sans cela, chaque page choisirait son marine, et les trois
   nuances auraient divergé à la première correction faite d'un seul
   côté. C'est exactement ce qui était arrivé au rail en 2.0. */
.nuit {
  background: var(--nuit);
  color: var(--lueur);
  border-radius: var(--r);
}
.nuit h1, .nuit h2, .nuit h3, .nuit strong, .nuit b { color: var(--lueur-vive); }
.nuit a { color: var(--lueur); }
.nuit hr, .nuit td, .nuit th { border-color: var(--filet-nuit); }
.nuit :focus-visible { outline-color: var(--focus-nuit); }

/* ── L'ŒIL — l'étiquette de l'appareil ─────────────────────────────
   La seule majuscule espacée du service, et elle est réservée : elle
   nomme un bloc de mesure, jamais une phrase. */
.oeil {
  font-family: var(--mesure);
  font-size: var(--taille-mention); font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--encre-pale);
}
.nuit .oeil { color: var(--lueur-pale); }

/* ── LA GOUTTIÈRE DE MESURE ────────────────────────────────────────
   ⚠️ **C'EST LA SIGNATURE, ET ELLE SE MÉRITE : on n'y écrit QUE de la
   donnée ordonnée.** Un numéro de tour, une lettre d'étape, une date,
   une marque d'intervention. Jamais une icône décorative, jamais un
   libellé — sans quoi elle devient une colonne comme une autre et la
   marge cesse de se lire d'un balayage.

   Le sens est celui-ci : on doit pouvoir **raconter la séance en
   balayant la marge**, sans lire une seule réplique — où l'on en est,
   et à quels tours le tuteur est intervenu. */
.marge {
  font-family: var(--mesure);
  font-size: var(--taille-etiquette); font-weight: 700;
  color: var(--encre-pale);
  font-variant-numeric: tabular-nums;
  line-height: 1.4;
}
.nuit .marge { color: var(--lueur-pale); }

/* La marque du tuteur dans la marge. Elle dit « il a parlé ICI », à la
   hauteur exacte du tour concerné.

   ⚠️ **CETTE RÈGLE ÉTAIT ÉCRITE DEUX FOIS, ET LES DEUX SE BATTAIENT —
   RELEVÉ À L'ÉCRAN LE 2026-08-28.** Ici, un TRAIT : `width: 2px`,
   `background: prune`. Dans `seance.html`, depuis le 2026-08-27, une
   LETTRE : un `T` prune de .78rem, posé pour survivre à un écran
   monochrome. Le `<style>` du gabarit gagnait sur la couleur et la
   taille, **mais n'annulait pas le `width: 2px`** : mesuré, la boîte
   faisait 2 px là où le `T` en demande 9,18, et la lettre — de la
   couleur du trait — devenait un éclat par-dessus lui.

   **Les deux intentions étaient perdues à la fois** : ni trait propre,
   ni lettre lisible. C'est exactement la question V1 de la charte —
   *« le prune du tuteur se lit-il comme une erreur d'impression ? »* —
   et la réponse mesurée était oui, pour une raison mécanique.

   **La lettre l'emporte**, parce que son motif est le plus fort : la
   gouttière ne porte que de la donnée ordonnée — les numéros de tour —
   et un `T` s'y range ; un trait n'y est ni un numéro ni un rang. Et
   il survit à un écran monochrome, là où la couleur seule ne dit plus
   rien. L'infobulle porte la phrase entière. */
.marge-tuteur {
  display: block;
  font-size: var(--taille-aide); line-height: 1.35; font-weight: 700;
  letter-spacing: .06em;
  color: var(--annotation);
  cursor: help;
  animation: marge-parait .5s ease both;
}
/* ⚠️ L'animation était un `scaleY(0 → 1)` : le geste d'un TRAIT qui
   pousse. Une lettre qui s'étire verticalement se lit comme un défaut de
   rendu — elle paraît, elle ne pousse pas. */
@keyframes marge-parait {
  from { opacity: 0; transform: translateY(-.15rem); }
  to   { opacity: 1; transform: none; }
}

/* ── LES CHAMPS DE SAISIE ──────────────────────────────────────────
   ⚠️ **LE CREUX A DISPARU, LE FILET REVIENT.** En 2.0 un champ
   s'enfonçait, et c'était la seule chose qui le dessinait. Sans relief,
   il faut un fond légèrement en retrait ET un filet : un fond seul se
   confondrait avec une carte, un filet seul avec un tableau. */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="search"],
select, textarea {
  font-family: var(--texte); font-size: var(--taille-lecture);
  padding: .68rem .85rem;
  color: var(--encre);
  /* ⚠️ **LE CHAMP EST DU VERRE CREUX, PAS UNE ENTAILLE — 2026-08-28.**
     La 3.1 le creusait par une ombre interne, en réponse à une demande
     de Franck : *« qu'on VOIE les zones de saisie »*. Le relief ayant
     disparu avec la direction du kit, la demande tient toujours et la
     réponse change : **le champ est plus TRANSPARENT que la plaque qui
     le porte**. Il se creuse par la matière, pas par la lumière — un
     trou dans le verre, et un filet net pour en dire le bord.

     ⚠️ **UN CHAMP N'EST PLUS FLOUTÉ.** Il vit dans une plaque qui l'est
     déjà : un second `backdrop-filter` coûterait une passe de rendu de
     plus pour un effet nul, et l'écran de séance en porte trois. */
  background: var(--verre-creux);
  border: 1px solid var(--filet);
  border-radius: var(--r);
  box-shadow: none;
  transition: border-color .14s ease, background .14s ease, box-shadow .14s ease;
  /* ⚠️ **`box-sizing` EST POSÉ ICI, ET SEULEMENT SUR LES CHAMPS — mesuré
     le 2026-08-17 sur la planche de contrôle.** Un champ en `width: 100%`
     débordait de son bloc : le remplissage et le filet s'ajoutaient à la
     largeur. **Huit gabarits sur quinze posent `* { box-sizing }` chez
     eux ; les sept autres, non** — et c'est chez ceux-là que le défaut
     apparaît. */
  box-sizing: border-box;
}

/* ⚠️ **LE CHAMP ACTIF PREND LA SAUGE — C'EST LA PLANCHE 2 DU KIT.**
   Elle donne quatre états : par défaut, actif, rempli, en erreur. Le
   filet est le seul à changer ; ni la taille ni l'arrondi ne bougent,
   ce qui reste la demande du 2026-08-17 — *« aucune modification
   graphique sur le champ afin de garder les arrondis »*. */
input:focus, select:focus, textarea:focus {
  border-color: var(--marque);
  background: var(--voile-haut);
}
input:hover, select:hover, textarea:hover { border-color: var(--filet-fort); }
/* ⚠️ **`.champ-erreur` A ÉTÉ RETIRÉE DE CE SÉLECTEUR LE 2026-08-29**,
   et le bloc reste : `input[aria-invalid="true"]` est bien employé.
   *Un sélecteur groupé ne se supprime pas en entier parce qu'un de ses
   membres est mort.* */
input[aria-invalid="true"] {
  border-color: var(--alerte);
  background: rgba(158, 43, 33, .05);
}
input::placeholder, textarea::placeholder { color: var(--encre-pale); }

/* ── LE MENU DÉROULANT — LE SEUL OBJET RESTÉ NATIF ─────────────────
   ⚠️ **RELEVÉ À L'ÉCRAN LE 2026-08-28, SUR CINQ ÉCRANS.** Le `<select>`
   recevait bien le fond et le creux ci-dessus, mais **`appearance`
   n'était pas remis à zéro** : Chrome garde alors son propre chevron,
   son propre dégradé de bord et sa propre métrique. Résultat, au milieu
   d'une page entièrement dessinée, les menus étaient les seuls objets
   du système d'exploitation — et ils **coupaient leur texte en plein
   mot** : « RPBDC — Réel, Problème, Besoin, Demar ».

   Le chevron est une image de fond en SVG, donc sans requête et sans
   fichier à servir. Il est posé à droite, et le remplissage lui fait
   la place : sans ce `padding-right`, le texte long passe dessous.

   ⚠️ **DEUX COULEURS SONT ÉCRITES EN DUR ICI, ET C'EST LA SEULE
   EXCEPTION DU FICHIER.** La charte l'interdit — « ne jamais coder une
   couleur en dur ». Le motif : **`var()` ne traverse pas une `data:`
   URI**, une image de fond ne connaît rien du document qui la porte.
   Les deux parades coûtent plus qu'elles ne rapportent : un `mask-image`
   masquerait AUSSI le fond du champ, et un chevron en `::after`
   demanderait d'envelopper les cinq écrans d'un `<div>`. D'où deux
   variantes, jour et nuit, **à retoucher à la main si l'encre change**. */
select {
  appearance: none; -webkit-appearance: none;
  padding-right: 2.2rem;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23555' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .8rem center;
  background-size: .72rem;
  /* ⚠️ **L'ELLIPSE NE MARCHE QUE SUR UN `select` DÉ-NATIVISÉ.** C'est
     elle qui remplace la coupure en plein mot par un « … » honnête. */
  text-overflow: ellipsis;
}
.nuit select {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23b9c2d6' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* ⚠️ **LA LISTE OUVERTE, ELLE, RESTE AU SYSTÈME** — on ne la peint pas.
   Un menu déroulant réécrit en JavaScript perd le clavier, la recherche
   à la frappe et l'accessibilité, pour gagner un dégradé. */
select option { background: var(--papier); color: var(--encre); }

/* La case et le bouton radio suivent la même règle que le reste : ils
   prennent l'encre du produit au lieu du bleu du système. `accent-color`
   le fait sans reconstruire le contrôle — donc sans rien perdre. */
input[type="checkbox"], input[type="radio"] {
  accent-color: var(--encre);
  width: 1rem; height: 1rem;
  cursor: pointer;
}

/* ⚠️ **UN CHAMP ÉTEINT DOIT SE VOIR SANS ÊTRE LU.** `parametrage` le
   disait chez lui — un fond plus pâle sur `select:disabled` —, et cette
   déclaration est partie avec le reste de la matière le 2026-08-28. Elle
   revient ici, pour les cinq écrans à la fois : sur l'écran de
   paramétrage, ce sont les options **hors budget** qui s'éteignent, et
   un coach qui ne voit pas qu'une ligne est fermée la cliquera. */
input:disabled, select:disabled, textarea:disabled {
  background: var(--papier-vif);
  color: var(--encre-pale);
  box-shadow: none;
  cursor: not-allowed;
}
/* Le survol renforce le filet : la zone se déclare AVANT qu'on clique.
   C'est le pendant du soulèvement des boutons, en plus discret — un champ
   n'a pas à sauter sous le curseur, il a à se signaler. */
/* Le survol CREUSE un peu plus : la zone se déclare avant qu'on clique. */


/* ⚠️ **LA ZONE DE RÉPLIQUE EST LA SEULE EXCEPTION** : ce qu'on y écrit
   sera dit à un client, donc c'est de la parole. Le gabarit de séance
   pose `class="parole"` sur son `<textarea>`. */
textarea.parole { font-family: var(--parole); font-size: var(--taille-fort); }

/* ⚠️ **LE CHAMP NE CHANGE PLUS DE MATIÈRE AU FOCUS — 2026-08-17.** Il
   s'éclaircissait et son creux s'adoucissait : deux changements de plus
   au moment du clic, alors que Franck demande qu'il **n'en subisse
   aucun**. Le creux reste donc celui du repos, et l'arrondi avec.

   *Ce qui est perdu — le champ qui « cesse d'attendre, et reçoit » — était
   une nuance ; ce qui est gagné est la stabilité de l'objet sous le doigt.
   Le contour de focus dit déjà où l'on est.* */

/* ⚠️ **IL N'Y A PLUS DE NUIT, MAIS LA CLASSE EXISTE ENCORE** dans les
   seize écrans non convertis. Un champ dans un bloc `.nuit` ne doit
   surtout pas rester peint en marine : il prend le même verre creux
   que partout, et le bloc autour se contente d'être teinté. */
.nuit input, .nuit select, .nuit textarea {
  background: var(--verre-creux); color: var(--encre);
  border: 1px solid var(--filet);
  box-shadow: none;
}
.nuit input:focus, .nuit select:focus, .nuit textarea:focus {
  background: var(--voile-haut);
  border-color: var(--marque);
}

/* ── LES BOUTONS ───────────────────────────────────────────────────
   ⚠️ **LE PROBLÈME D'AFFORDANCE DE LA 2.0 DISPARAÎT AVEC LE RELIEF, ET
   IL N'Y A PLUS DE PARADE À TENIR** : ce qui agit est PLEIN, le reste
   ne l'est pas. Un seul signal, sans exception, sur tous les écrans.

   L'action principale est pleine encre — plus bleue. Le bleu était la
   marque ; la marque est maintenant le fond de la nuit, et deux bleus
   concurrents se seraient disputés le même sens. */
/* ══ LES BOUTONS — LA PLANCHE 1 DU KIT, LES QUATRE TYPES ══════════
   Le kit donne quatre types et quatre états pour chacun : par défaut,
   survol, appui, inactif. Ils sont repris tels quels.

   ⚠️ **LE RELIEF A DISPARU, ET LE BOUTON PERD SON SIGNAL LE PLUS FORT.**
   La 3.1 disait *« c'est le seul objet du service qui bouge sous le
   doigt, et c'est ce qui le désigne comme manipulable sans qu'aucune
   couleur ait à le dire »*. Le kit, lui, ne pose que des ombres portées
   et un changement de teinte. **Ce qui remplace le mouvement** : le
   bouton primaire est le seul objet PLEIN et COLORÉ de l'écran, tout le
   reste étant du verre translucide. La différence est de matière.

   *Le soulèvement d'un pixel au survol est conservé — c'est peu coûteux,
   et le kit ne l'interdit pas.* */
/* ⚠️ **NE PAS ÉTENDRE CE SÉLECTEUR À `button[type="submit"]`.** Essayé
   le 2026-08-28, et le défaut est instructif : le bouton « Se
   déconnecter » du rail EST un `submit` — la route est en POST —, et
   `button[type="submit"]:not(.a):not(.b)` pèse plus lourd que
   `.rail button`. La déconnexion est devenue le bouton le plus vert de
   l'écran. **Un bouton n'est principal que s'il le DIT** : `.bouton`
   ou `button.principal`, jamais par déduction. */
/* ⚠️⚠️ **UNE SEULE LISTE, ET ELLE EST LARGE À DESSEIN — 2026-08-29.**
   La demande est *« tous éléments cliquables »*. Les seize écrans
   nomment leurs actions de huit façons — `button`, `.bouton`,
   `.bouton-action`, `.bouton-rapide`, `.bouton-pdf`, `.bouton-icone`,
   `.bouton-partenaire`, `.pastille` : le sélecteur d'attribut les
   attrape par leur nom, comme le fait déjà le verre des panneaux.

   ⚠️ **CE QUI EST HORS DE CETTE LISTE, ET POURQUOI.** Le RAIL — ses
   liens ne sont pas des touches, et `navigation.css` est chargée après,
   donc il garde son dessin sans qu'un `:not()` soit nécessaire. Les
   LIENS DE TEXTE — un lien dans une phrase reste un lien ; en faire une
   touche rendrait chaque paragraphe illisible. Les ÉTIQUETTES et les
   STATUTS — ils ne se cliquent pas, et aucun ne porte « bouton » dans
   son nom.

   ⚠️⚠️ **`button` TOUT COURT, ET NON `button:not([class])`.** Première
   version, et le défaut s'est vu à l'écran : `button.rouge` et
   `button.vert` de `/comptes` portent une classe, donc `:not([class])`
   les EXCLUAIT — ils recevaient bien leur teinte, mais **ni le cadre, ni
   le rayon, ni le relief**, et gardaient la bordure grise que le
   navigateur pose par défaut sur un `<button>`. *Deux boutons plats au
   milieu d'une page de touches.*

   ⚠️ **ET `button` SEUL NE MENACE PAS LE RAIL** : `.rail button` pèse
   (0,1,1) contre (0,0,1), et `navigation.css` est chargée après. Le
   piège inverse — celui de `button[type="submit"]`, qui avait rendu « Se
   déconnecter » vert — venait d'un sélecteur PLUS lourd que `.rail`,
   pas plus léger.

   ⚠️⚠️ **IL Y AVAIT ICI UNE RÉSERVE SUR `.bouton.fantome` ET
   `.lien-action` — ELLE EST CADUQUE DEPUIS LE 2026-08-29.** Ces deux
   classes recevaient la matière par cette liste, puis leur propre règle
   la leur retirait, *« parce qu'un bouton qui n'engage rien ne doit pas
   ressembler à un bouton qui engage »*. **Les deux ont été supprimées** :
   nées le 2026-08-28, employées par aucun gabarit, jamais.

   ⚠️ *Le besoin, lui, ne l'est pas.* Le jour où un bouton doit
   ouvrir sans engager, il lui faudra de nouveau une règle qui retire la
   matière — **la liste ci-dessous la lui donnera sans rien demander.** */
/* ⚠️⚠️ **LE SÉLECTEUR D'ATTRIBUT EST BORNÉ AUX `<a>` ET AUX `<button>`
   — 2026-08-30, ET IL Y AVAIT UN DÉFAUT VISIBLE.** Écrit
   `[class*="bouton"]` tout court, il attrapait aussi les CONTENEURS qui
   portent le pluriel : `div.boutons-fin` du paramétrage,
   `div.boutons` des deux formulaires de l'écran de séance. Ces trois
   `<div>` recevaient le cadre métallique, le bombé, la portée et le
   `cursor: pointer` — **un bouton dessiné SOUS les boutons**, que
   Franck a vu sur `/parametrage` et sur `/seance/`.

   *La feuille de page ne le rattrapait pas : elle redéclare
   `display: flex`, donc la mise en ligne tenait ; le fond, la bordure
   et l'ombre, eux, restaient.*

   **Borner à `a[…]` et `button[…]` ne retire rien à personne** : les
   noms visés — `.bouton-action`, `.bouton-rapide`, `.bouton-pdf`,
   `.bouton-partenaire`, `.bouton-relance`, `.bouton-accueil` — sont
   TOUS portés par un `<a>` ou par un `<button>`, relevé sur les vingt
   gabarits. Un conteneur, lui, n'est jamais l'un des deux.
   *`.bouton-icone`, cité dans la liste du dessus, n'est employé par
   aucun gabarit : il ne prouve ni n'infirme rien.* */
.bouton, button.principal, button.secondaire, button.tuteur,
a[class*="bouton"], button[class*="bouton"], a.bouton, button,
input[type="submit"], input[type="button"], .pastille {
  font-family: var(--titre); font-size: var(--taille-lecture); font-weight: 600;
  letter-spacing: -.005em;
  padding: .68rem 1.35rem;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  gap: .45rem; text-align: center; text-decoration: none;

  /* ⚠️ **LES DEUX FONDS ET LA BORDURE TRANSPARENTE FONT LE CADRE.** Le
     corps s'arrête au bord intérieur, le métal va jusqu'au bord
     extérieur, et la bordure ne porte aucune couleur à elle. Retirer
     l'un des trois fait disparaître le cadre sans la moindre erreur. */
  background: var(--touche) padding-box, var(--chrome) border-box;
  /* 3 px et non 2 : mesuré sur une capture, à 2 px le cadre ne se lisait
     pas comme du métal mais comme un contour pâle. */
  border: 3px solid transparent;
  border-radius: var(--r-plein);

  /* ⚠️ **L'ENCRE, PAS LE BLANC.** Le corps de la planche est presque
     blanc : un libellé blanc y serait invisible. Mesuré sur le pixel le
     plus clair du corps (#ffffff) comme sur le plus sombre (#e2e9ec),
     `--encre` donne 12,6:1 et 11,0:1. */
  color: var(--encre);
  box-shadow: var(--touche-relief);
  transition: box-shadow .16s ease, transform .12s ease, background .16s ease;
}

/* ⚠️ **LE SURVOL ÉCLAIRCIT LE CORPS ET LÈVE LA PORTÉE**, il ne change
   pas de teinte : il n'y a plus de teinte à changer. */
.bouton:hover, button.principal:hover, button.secondaire:hover,
button.tuteur:hover, a[class*="bouton"]:hover, button[class*="bouton"]:hover,
a.bouton:hover,
button:hover, .pastille:hover {
  background: var(--touche-vive) padding-box, var(--chrome) border-box;
  box-shadow: var(--touche-relief-fort);
  transform: translateY(-1px);
}

/* L'appui ENFONCE : la portée rentre à l'intérieur. C'est le seul état
   où l'objet cesse d'être posé sur la page. */
.bouton:active, button.principal:active, button.secondaire:active,
button.tuteur:active, a[class*="bouton"]:active, button[class*="bouton"]:active,
a.bouton:active,
button:active, .pastille:active {
  background: var(--touche-creuse) padding-box, var(--chrome) border-box;
  box-shadow: var(--touche-relief-enfonce);
  transform: translateY(1px);
}

/* ⚠️ **L'INACTIF PERD SON MÉTAL, ET C'EST LE SIGNAL.** Sans cadre, il
   n'a plus d'épaisseur : il ne se lit plus comme un objet qu'on
   enfonce. La couleur seule ne l'aurait pas dit. */
.bouton:disabled, button:disabled, .bouton[aria-disabled="true"],
button[class*="bouton"]:disabled,
a[class*="bouton"][aria-disabled="true"],
button[class*="bouton"][aria-disabled="true"] {
  background: var(--verre-creux) padding-box,
              var(--filet) border-box;
  color: var(--encre-douce);
  box-shadow: none; cursor: not-allowed; transform: none;
}

/* ⚠️⚠️ **LA HIÉRARCHIE NE PASSE PLUS PAR LA TEINTE — 2026-08-29, ET
   C'EST LA CONSÉQUENCE ASSUMÉE DE « TOUS LES BOUTONS ».** Le principal
   était vert, le secondaire rose : deux matières différentes disaient
   laquelle des deux actions était attendue. **Toutes les touches ayant
   la même matière, ce signal disparaît.**

   **Ce qui le remplace** : le PLEIN contre le CREUX. Le principal porte
   l'encre pleine et la graisse ; le secondaire porte l'encre douce et
   une graisse normale. *C'est moins fort qu'une couleur, et il faut le
   dire — mais deux touches de teintes différentes auraient contredit la
   planche, qui n'en montre qu'une.* */
.bouton.second, button.secondaire, .bouton-rapide, .bouton-accueil {
  color: var(--encre-douce); font-weight: 500;
}
.bouton.second:hover, button.secondaire:hover,
.bouton-rapide:hover, .bouton-accueil:hover {
  color: var(--encre);
}

/* ══ LES TROIS TOUCHES QUI PORTENT UN SENS ════════════════════════
   ⚠️⚠️ **CE NE SONT PAS DES VARIANTES DE GOÛT.** Le rouge dit « ceci
   détruit », le vert « ceci rend l'accès », l'ambre « ce formulaire a
   changé et rien n'est encore enregistré ». **Un bouton qui supprime un
   compte ne peut pas avoir la même apparence que celui qui l'ouvre.**

   ⚠️ **LA TEINTE PASSE SOUS LE VERRE, ELLE NE LE REMPLACE PAS** : le
   cadre métallique et l'arête du bombé restent, seul le CORPS se
   colore. C'est ce qui garde l'unité de matière que Franck a demandée
   tout en laissant l'avertissement lisible. */
.bouton.alerte, button.rouge {
  background: linear-gradient(180deg, #fdf6f5 0%, #f7ddda 46%,
              #eec7c3 46.5%, #f6dedb 80%, #fdf7f6 100%) padding-box,
              var(--chrome) border-box;
  color: var(--alerte);
}
.bouton.bon, button.vert {
  background: linear-gradient(180deg, #f5fbf7 0%, #daeee2 46%,
              #c4e2ce 46.5%, #dcefe3 80%, #f6fbf8 100%) padding-box,
              var(--chrome) border-box;
  color: var(--bon);
}
form.modifie button, .bouton.attention {
  background: linear-gradient(180deg, #fdfaf3 0%, #f6ebd5 46%,
              #eeddb9 46.5%, #f6ecd8 80%, #fdfaf4 100%) padding-box,
              var(--chrome) border-box;
  color: var(--attention);
}

/* ⚠️⚠️ **CE QUI EST CHOISI EST ENFONCÉ, ET C'EST L'IDIOME DE LA
   MATIÈRE.** Les huit onglets de processus étaient départagés par un
   APLAT de marque ; la planche de Franck n'a qu'une seule teinte, donc
   plus d'aplat à poser. **Un objet métallique dit qu'il est actif en
   restant appuyé** — c'est ce que fait un vrai bouton poussoir, et cela
   ne coûte aucune couleur de plus.

   ⚠️ *Trouvé par `verif_gabarits.py`, pas à l'œil* : en retirant les
   fonds des feuilles de page, `.active` d'`accueil.html` est devenue une
   classe **employée qui ne peint plus rien**. Sans ce contrôle, l'onglet
   choisi aurait cessé de se distinguer en silence.

   ⚠️⚠️ **ET LA RÈGLE EST PARTIE À SON TOUR LE 2026-08-30** — le même
   contrôle, le même jour, dans l'autre sens : les huit pastilles de
   processus sont devenues une liste déroulante, `.active` n'est plus
   employée nulle part, et une peinture sans emploi est ce que la
   suivante croira pouvoir utiliser. **Le raisonnement ci-dessus reste
   vrai et sert de mode d'emploi** le jour où un onglet réapparaît :
   un objet métallique dit qu'il est actif en restant appuyé —
   `--touche-creuse`, `--touche-relief-enfonce`, `translateY(1px)`. */

/* ⚠️ **PLUS DE VARIANTE DE NUIT — il n'y a plus de nuit.** Les règles
   `.nuit .bouton` peignaient un bouton clair sur fond marine. Les blocs
   `.nuit` sont devenus du verre teinté : le bouton y garde sa sauge, et
   c'est ce qu'on veut — une action a la même couleur partout. */

/* ══ LE CADRE — SON OPACITÉ ET SON VOILE BLANC ════════════════════
   ⚠️⚠️ **MONTÉ ICI LE 2026-09-08 (soir), ET POUR LA MÊME RAISON QUE LA
   CAPSULE JUSTE EN DESSOUS.** Ces règles ont vécu une journée dans
   `pages/paiements.css`, où Franck avait demandé le curseur ; il a
   ensuite demandé *« mettre le fond du tableau comme sur la page
   /paiements »* pour `/seances`. **Un réglage qui doit valoir sur deux
   écrans en vaut vingt-quatre** : c'est une matière, pas une peinture de
   page.

   ⚠️ **`body::before` EST LA GRANDE PLAQUE** — le porteur des quatre
   couches de verre défini plus haut dans ce fichier : le grain fractal,
   le voile, la copie floutée du fond, le dégradé de lumière. Son
   `opacity` est ce que la première moitié du curseur commande.

   ⚠️ **`body::after` EST LE VOILE BLANC** — la seconde moitié de la
   course. Il n'est PAS une cinquième couche de `body::before` : celui-ci
   empile quatre `background-image` avec quatre listes parallèles
   (`-size`, `-repeat`, `-attachment`, `-blend-mode`) ; y ajouter une
   image sans rallonger les quatre listes les aurait décalées d'un cran,
   et le grain serait passé en `fixed`.

   ⚠️ **`connexion.css` DÉFINIT SES PROPRES `body::before` ET
   `body::after`** — c'est la seule page qui ne porte pas la grande
   plaque, et sa feuille est chargée APRÈS celle-ci : elle gagne, et rien
   n'y change. *Vérifié avant d'écrire ces lignes.*

   ⚠⚠ **LA VALEUR EST FIXÉE À 40 % DEPUIS LE 2026-09-08 (soir) — ARBITRAGE
   DE FRANCK, après une journée de réglage au curseur.** Elle valait `1`, et
   le curseur de `/paiements` la couvrait par une valeur de `localStorage`.
   **Les deux sont partis** : le réglage était un instrument, pas une
   préférence à offrir, et une valeur qui vit dans le navigateur d'une seule
   personne n'est ni partagée, ni versionnée, ni visible des testeurs.

   ⚠⚠ **CE QUE 40 % FAIT AU CONTRASTE — MESURÉ SUR DES PIXELS RENDUS,
   PAS DÉDUIT.** La pile des quatre couches a été reconstituée dans un
   navigateur avec les vraies images, puis échantillonnée colonne par
   colonne, hors glyphes :

   | | pire pixel de la plaque | `--encre` |
   |---|---|---|
   | à **100 %** | `rgb(91, 103, 114)` | **1,91:1** |
   | à **40 %** | `rgb(113, 123, 132)` | **2,56:1** |

   ⚠️ **LE RÉSULTAT EST L'INVERSE DE CE QU'ON CRAIGNAIT : à 40 % LE PIRE
   POINT EST PLUS CLAIR, DONC LE CONTRASTE MEILLEUR.** *La copie floutée que
   la plaque pose est plus sombre, dans sa moitié basse, que le fond
   d'ambiance qu'elle recouvre — l'effacer découvre quelque chose de plus
   clair.* **La phrase « le voile de verre EST ce qui porte le contraste »,
   écrite plus haut dans ce fichier, ne vaut donc pas partout** : elle a été
   mesurée sur `/seances`, pas sur cette image de fond.

   ⚠️⚠️ **ET LA LIMITE DE CETTE MESURE DOIT ÊTRE DITE : les deux valeurs
   sont SOUS 4,5.** Elle porte sur du texte posé NU sur la plaque, ce qui
   n'arrive presque jamais : le contenu vit dans des blocs `--verre-vif`
   (blanc à 70 %), et **ce sont eux qui portent la lisibilité**. *La mesure
   dit que 40 % ne dégrade rien ; elle ne dit pas que le pire cas est
   conforme, et il ne l'était pas davantage à 100 %.*

   ⚠️ **LE BLANC RESTE À `0`** : la seconde moitié de la course du curseur
   n'a jamais été retenue. `--blanc-cadre` et `body::after` sont conservés —
   ils ne peignent rien à zéro, et remonter la valeur est une ligne. */
/* ⚠⚠ **LE DÉFAUT PASSE À 1,25 — 2026-09-09, ARBITRAGE DE FRANCK** :
   *« valeur par défaut 1,25 pour toutes les pages »*. Il valait **0,4**
   depuis la veille, après une journée de réglage au curseur.

   ⚠️ **1,25 EST AU-DELÀ DE 1, DONC LA COURSE BASCULE DANS SA SECONDE
   MOITIÉ** : la plaque est **pleine** (`--opacite-cadre: 1`) et un voile
   blanc de **25 %** s'ajoute par-dessus. *C'est l'inverse de 0,4, qui
   effaçait la plaque aux trois cinquièmes pour laisser voir le
   paysage.* Les deux jetons portent donc le résultat du partage, jamais
   la valeur de la course — c'est `navigation.js` qui la partage, et lui
   seul.

   ⚠️ **CE QUE CELA FAIT AU CONTRASTE : IL MONTE.** La mesure du
   2026-09-08 avait montré qu'à 40 % le pire pixel de la plaque valait
   `rgb(113, 123, 132)` — 2,56:1 pour `--encre`. **Blanchir ne peut que
   l'éclaircir** : un voile blanc à 25 % posé par-dessus une plaque
   pleine remonte tous les pixels vers le blanc. *Aucune mesure n'est
   nécessaire pour l'affirmer dans ce sens-là ; c'est l'autre sens qui
   demandait la preuve.* */
body { --opacite-cadre: 1; --blanc-cadre: .25; }

body::before { opacity: var(--opacite-cadre); }

body::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background-color: rgba(255, 255, 255, var(--blanc-cadre));
  z-index: -1;
  pointer-events: none;
}

/* ══ LA CAPSULE DE PROCESSUS — 2026-09-08 ═════════════════════════
   ⚠️⚠️ **DEMANDE DE FRANCK, IMAGE À L'APPUI** : *« utilise ce PNG pour
   faire les boutons de processus »*, puis, le même jour : *« cela doit
   également être le cas PARTOUT où les processus sont cités (exemple :
   /seances) »*.

   ⚠️ **ELLE EST ICI, ET NON DANS TROIS FEUILLES DE PAGE, PARCE QUE
   C'EST UNE MATIÈRE.** C'est l'interdit n°8 de la direction visuelle :
   une page règle la taille et le rôle de ses objets, jamais leur
   matière. *Le défaut existait déjà — `pages/seances.css` et
   `pages/consommation-seance.css` portaient le MÊME bloc de six lignes,
   l'une disant d'ailleurs « les mêmes valeurs que dans seances.css ».
   Deux copies d'une même règle divergent toujours ; il y en avait deux,
   il allait y en avoir quatre.*

   ⚠️⚠️ **CES CAPSULES SORTENT DE LA TOUCHE COMMUNE, ET C'EST L'ARBITRAGE
   DE FRANCK (D10).** Le §7 quinquies veut que tout élément cliquable
   porte le verre bombé dans son cadre métallique. **Celles-ci portent SON
   image** : lui laisser en plus le cadre de `--chrome` l'aurait dessiné
   tout autour d'un PNG qui porte déjà le sien. *Aucun autre bouton du
   service n'est touché — et c'est pourquoi la classe ne contient plus le
   mot « bouton » : `a[class*="bouton"]` l'attrapait, il ne l'attrape
   plus.*

   ⚠️⚠️ **DÉCOUPAGE EN NEUF ZONES, ET C'EST CE QUI SAUVE LES ARRONDIS.**
   Un PNG étiré à la largeur du texte déforme ses calottes : elles
   deviennent des ovales, et c'est précisément l'esthétisme qu'on veut
   garder. `border-image` découpe le fichier et **ne stire QUE le
   milieu** ; les deux calottes gardent leur forme quelle que soit la
   longueur du code. *Vérifié sur le fichier avant d'écrire cette règle :
   la zone centrale ne varie que de 5 niveaux sur 255 d'un bord à
   l'autre — elle peut donc s'étirer sans que rien ne se voie.*

   ⚠️ **LES DEUX NOMBRES SONT MESURÉS SUR LE FICHIER, PAS CHOISIS.**
   `bouton-processus.png` fait **192 × 111 depuis la coupe du 2026-09-09**
   *(il faisait 195 × 118, plaque translucide comprise — voir le bloc de
   `border-width` plus bas, qui dit pourquoi elle est partie)*. La calotte
   est un demi-cercle de 53 px de rayon : **la tranche vaut 56 px**, et le
   rapport tranche / hauteur vaut **56 / 111 = 0,5045**. C'est ce facteur,
   et lui seul, qui garde la calotte proportionnée quand la hauteur
   change.

   ⚠️ **LES DEUX TERMES ONT BOUGÉ, PAS UN SEUL** — 57 → 56 et 118 → 111.
   *N'en corriger qu'un aurait aplati ou fait déborder l'arrondi, sans
   qu'aucun outil ne le dise : `border-image` découpe en pixels de
   l'image et peint dans une largeur donnée en `rem`.*

   ⚠️ **`border-image-width` N'EST PAS ÉCRIT : IL VAUT `1` PAR DÉFAUT**,
   c'est-à-dire une fois `border-width`. Poser les deux aurait fait deux
   endroits à corriger le jour où la hauteur change.

   ⚠️ **UNE SEULE VARIABLE COMMANDE TOUT** : `--capsule-h`. Une page qui
   veut des capsules plus grandes la redéfinit, et rien d'autre — ni la
   tranche, ni le rayon du contour de focus, qui en découlent par
   calcul. */
.processus-touche {
  --capsule-h: 2.4rem;
  /* ⚠⚠⚠ **`--gros` REMPLACE `transform: scale()` — 2026-09-09, CONSTAT
     DE FRANCK** : *« des lignes verticales blanches très fines apparaissent
     lorsque le bouton est en surbrillance »*.

     **LA CAUSE EST `transform: scale(1.06)`, ET C'EST MESURÉ.** Une mise à
     l'échelle non entière fait rastériser les **trois tranches** du
     `border-image` séparément : au raccord entre la calotte et le milieu
     étiré, le rééchantillonnage laisse un pixel qui ne coïncide pas. *Le
     défaut n'est donc ni dans l'image — les colonnes de part et d'autre des
     frontières sont identiques à 1 niveau près — ni dans la lumière : il
     naît au rendu, et seulement quand l'élément est mis à l'échelle.*

     **QUATRE PARADES ÉPROUVÉES DANS CHROME**, même lumière, même taille :

     | | La parade | Couture |
     |---|---|---|
     | A | `scale(1.06)` seul — témoin | **visible** |
     | B | `+ will-change: transform` | **visible** |
     | C | `+ translateZ(0)` | **visible** |
     | D | **grandir par le jeton** | **aucune** |
     | E | aucun agrandissement — témoin | aucune |

     ⚠️ **LES DEUX PARADES HABITUELLES NE SERVENT À RIEN ICI.** `will-change`
     et `translateZ(0)` promeuvent l'élément dans sa propre couche ; *ils ne
     changent rien au fait que les tranches y sont peintes séparément.*

     **CE QUE FAIT `--gros`** : la hauteur, la marge intérieure et la bordure
     sont toutes multipliées par lui, donc l'élément **grandit par la mise en
     page** et le `border-image` est repeint à sa taille finale, d'une seule
     venue. *L'agrandissement au survol est conservé — il n'était pas en
     cause, c'est la façon de l'obtenir qui l'était.*

     ⚠⚠ **ET LA MARGE NÉGATIVE EMPÊCHE LA BOUSCULADE, C'EST LA MOITIÉ QUI
     COMPTE.** `transform` ne dérange jamais la mise en page ; grandir, si.
     Sans compensation, survoler une capsule pousserait tout ce qui est
     dessous de deux pixels. La marge vaut exactement l'inverse de la
     croissance — `H×(1−g)/2` en hauteur, `H×(1−g)×.5045` de chaque côté —
     donc **la boîte extérieure ne bouge pas d'un pixel**. *Mesuré : les
     rangées font 136, 137 et 136 px au repos, à 1,06 et à 1,10.*

     ⚠️ **`--capsule-h` RESTE LE SEUL RÉGLAGE DE TAILLE**, et les deux pages
     qui le redéfinissent — `accueil` à 4,2 rem, `consommation-seances` à
     1,6 rem — n'ont rien à changer : `--gros` les multiplie. */
  --gros: 1;
  box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  height: calc(var(--capsule-h) * var(--gros));
  margin: calc(var(--capsule-h) * (1 - var(--gros)) / 2)
          calc(var(--capsule-h) * (1 - var(--gros)) * .5045);
  /* ⚠⚠ **LE LIBELLÉ EST REMONTÉ DE 17 %, ET CE N'EST PAS UN RÉGLAGE
     À L'ŒIL.** Mesuré sur le profil vertical du fichier, colonne
     centrale : la face claire du verre va de **y = 5 à y = 71** sur 111
     *(c'était 6 à 72 sur 118 ; la coupe du 2026-09-09 a retiré 1 px en
     haut, tout remonte d'autant)* ; en dessous viennent l'arête sombre
     puis le socle. **Le centre optique est donc à y = 38, quand le centre
     de la boîte est à y = 55,5** — 17,5 px plus bas, soit 15,8 % de la
     hauteur.
     ⚠️ **SANS CE DÉCALAGE, LE LIBELLÉ TOMBE SUR L'ARÊTE** : vu à la
     capture, le trait du bord passait derrière le texte et se lisait
     comme un soulignement. Une marge basse de **31,5 %** remonte le
     contenu de la moitié — exactement les 15,8 % voulus. *Elle valait
     33,8 % avant la coupe.*

     ⚠️ **ET LA HAUTEUR PART DE 2,4 rem, PAS DE 1,95.** La face claire
     ne fait que **59 % de la hauteur totale** (66 px sur 111) : à
     1,95 rem il restait 17 px pour un libellé de 12, et la capsule
     paraissait étriée. */
  /* ⚠⚠ **31,5 % ET NON 33,8 % — RECALCULÉ LE 2026-09-09 APRÈS LA
     COUPE.** Ce nombre place le texte sur la FACE de verre, pas au centre
     de la boîte : la face est au-dessus du milieu, le texte doit y monter.
     *La coupe a retiré 1 px en haut et 6 px en bas ; la face remonte donc
     dans l'image, et le décalage à compenser diminue.* **Mesure** : centre
     du texte à 0,3423 de la hauteur, face du galet à 0,3423 — les deux
     coïncident au quatrième chiffre. */
  padding: 0 .25em calc(var(--capsule-h) * var(--gros) * .315);
  border-style: solid;
  /* ⚠⚠ **56/111 ET NON 57/118 — LA COUPE A CHANGÉ LES DEUX TERMES.**
     Le cap arrondi perdait 1 px de plaque à gauche (57 → 56) et l'image
     perd 7 px de hauteur (118 → 111). *Garder l'ancien facteur étirerait
     le cap : `border-image` découpe en PIXELS DE L'IMAGE et peint dans une
     largeur donnée en `rem` — si les deux ne s'accordent pas, l'arrondi
     s'aplatit ou déborde, sans qu'aucun outil ne le dise.* */
  border-width: 0 calc(var(--capsule-h) * var(--gros) * .5045);
  border-image-source: url("/static/bouton-processus.png");
  border-image-slice: 0 56 fill;
  border-image-repeat: stretch;

  font-family: var(--titre); font-size: var(--taille-mention);
  font-weight: 700; letter-spacing: .04em; line-height: 1;
  white-space: nowrap; text-decoration: none;
  /* ⚠️ **L'ENCRE, PAS LE BLANC — MESURÉ SUR LE FICHIER.** Le pixel
     central vaut (183, 204, 231) ; `--encre` (#2F3E46) y donne 7,4:1,
     très au-dessus du seuil de 4,5. Un libellé blanc y serait
     illisible. */
  color: var(--encre);
  /* ⚠️ **DÉSATURÉE AU REPOS, PAS GRISÉE.** Grisé veut dire « inactif »
     dans tout le service, et ces capsules sont toutes cliquables. Une
     saturation basse dit seulement « en retrait ». */
  filter: saturate(.55);
  /* ⚠️ **CE NE SONT PLUS LES MÊMES PROPRIÉTÉS QUI S'ANIMENT** : `transform`
     n'a plus d'objet, et les quatre longueurs dérivées de `--gros` prennent
     sa place. *Elles s'animent bien alors que `--gros` saute : une
     propriété personnalisée non déclarée ne s'interpole pas, mais la
     LONGUEUR qu'elle calcule, elle, a une nouvelle valeur calculée — et
     c'est celle-là que la transition anime.* */
  transition: filter .18s ease,
              height .12s ease, padding .12s ease,
              border-width .12s ease, margin .12s ease;
  /* ⚠⚠⚠ **CE DIAGNOSTIC ÉTAIT FAUX, ET FRANCK A REPOSÉ LE DÉFAUT LE
     MÊME JOUR** : *« les palets en verre ont des contours visibles → crop
     pour résoudre »*. **Il avait raison, et la mesure le prouve.**

     **CE QUI ÉTAIT ÉCRIT ICI** : que `overflow: hidden` tranchait un
     « halo diffus » de quatre pixels et créait ainsi le contour. *Le
     retirer n'a rien changé — c'est ce qui aurait dû m'alerter.*

     **CE QUE LE CANAL ALPHA DIT VRAIMENT**, mesuré sur les 626 pixels du
     pourtour : **AUCUN n'était transparent.** Minimum 101, maximum 164,
     médiane 101, d'un gris-bleu uniforme (205, 210, 222). Ce n'était pas
     un halo tronqué : c'était **une plaque translucide RECTANGULAIRE
     remplissant tout le fichier**, avec son propre lisere à 164. Le galet
     était posé dessus. *Aucune règle CSS ne pouvait retirer ce que le
     fichier peignait : le défaut était dans l'image, pas dans la
     feuille.*

     ⚠️ **LE FICHIER EST DONC COUPÉ — 195 × 118 → 192 × 111.** La plaque
     part par une rampe douce (`smoothstep` 170 → 250 sur l'alpha), qui
     annule tout ce qui était plaque **sans créer de nouveau palier** :
     une coupe franche aurait remplacé un contour par un autre. **Contrôle
     après coupe : alpha maximum du pourtour = 0.**

     ⚠️ **CE QUI NE SE PERD PAS** : l'intérieur du galet est entièrement
     opaque — 8 296 pixels mesurés, **aucun sous 235** — donc la rampe ne
     l'a pas entamé. Et ce que je prenais pour une ombre portée sous le
     galet était à alpha 101, *exactement la valeur de la plaque* : il n'y
     avait pas d'ombre à préserver.

     ⚠️ **LE GALET OCCUPE DÉSORMAIS 98,2 % DE SA BOÎTE**, contre 89,8 %.
     `--capsule-h` ne bouge pas : la boîte est identique, c'est le verre
     qui cesse de flotter dans une marge invisible. *Une boîte plus grande
     que ce qu'elle montre est ce qui décalait tous les espacements.*

     ---- **`overflow: hidden` RESTE RETIRÉ, POUR SON AUTRE MOTIF**, celui
     qui était juste :

     ⚠️ **IL N'EST PLUS NÉCESSAIRE À PERSONNE.** Il ne servait qu'à borner
     la bande de lumière, qui **sortait** de son propre cadre en
     `translateX`. Elle ne bouge plus : c'est sa position de FOND qui
     s'anime, à l'intérieur d'un pseudo-élément immobile — et le fond d'un
     élément est déjà rogné par son `border-radius`. *La contrainte est
     levée à sa source, pas contournée.*

     ⚠️ **`border-radius` RESTE, ET IL NE ROGNE RIEN** : la capsule est
     peinte par `border-image`, que le rayon ignore. Il ne sert plus qu'au
     contour de focus, qui doit épouser la forme. */
  position: relative;
  border-radius: var(--r-plein);
}

/* ⚠️ **LE FOCUS CLAVIER DOIT ÊTRE REPOSÉ ICI.** Le contour commun suit
   les sélecteurs de bouton, que ces capsules ne portent plus. Sans cette
   règle, elles seraient atteintes au clavier **sans aucun signe** —
   l'écart à la direction visuelle aurait emporté une règle
   d'accessibilité avec lui. */
.processus-touche:focus-visible { outline: 3px solid var(--focus);
                                  outline-offset: 2px; }

/* ⚠️ **L'ENFONCEMENT N'EST PLUS POSSIBLE, ET IL FAUT LE DIRE.** La
   direction veut qu'un objet métallique dise qu'il est actif en restant
   appuyé — `--touche-creuse`, `--touche-relief-enfonce`. Ces jetons
   peignent un FOND ; ici le fond est une image, ils n'ont plus de prise.
   *Le signal est remplacé, pas supprimé* : la choisie est la seule à
   pleine saturation, et légèrement grandie. */
.processus-touche.choisie { filter: saturate(1.15) brightness(1.03);
                            --gros: 1.06; }

/* ── L'EFFET VERRE ET LUMIÈRE AU SURVOL ──────────────────────────
   Demande de Franck : « lorsque l'on survole le bouton il y a un effet
   verre et lumière ». Deux gestes qui se complètent : ① le verre
   s'anime — saturation et clarté montent, l'objet grandit d'un souffle ;
   ② une lumière PASSE — une bande claire inclinée traverse la capsule
   une fois, comme un reflet qui court sur un verre qu'on incline. */
.processus-touche:hover { filter: saturate(1.3) brightness(1.07);
                          --gros: 1.06; }
.processus-touche.choisie:hover { filter: saturate(1.45) brightness(1.09);
                                  --gros: 1.1; }

/* ⚠⚠⚠ **CE BLOC DÉFENDAIT UN RETRAIT QUI N'EXISTE PLUS — RETIRÉ LE
   2026-09-09, RELEVÉ PAR LA REVUE D'INTENTION.** Il justifiait un
   `inset: 3.4% 2%` par le halo que le PNG portait dans ses quatre pixels de
   marge, et concluait qu'*« une bande posée sur `inset: 0` déborderait du
   verre et passerait sur le halo »*.

   **LES DEUX MOITIÉS SONT TOMBÉES LE MÊME JOUR.** Le « halo » était en
   réalité **une plaque translucide rectangulaire**, et le fichier a été
   coupé : le galet occupe désormais **98,2 %** de sa boîte, il n'y a plus
   rien à éviter. Et l'`inset` ne vaut plus `0` mais une valeur **négative**,
   donc plus LARGE que la boîte — *l'inverse exact de ce que ce bloc
   redoutait.*

   ⚠️ **LA MENTION « les dimensions D'AVANT LA COUPE » SAUVAIT LES CHIFFRES,
   PAS LA CONCLUSION.** *Dater une phrase périmée ne la rend pas vraie ; elle
   la rend seulement plus difficile à contredire.* */
/* ⚠⚠ **LA LUMIÈRE COUVRE MAINTENANT TOUT LE GALET — 2026-09-09,
   CONSTAT DE FRANCK** : *« l'effet lumineux traversant est partiel, il ne
   couvre pas tout le galet en verre »*.

   **Deux causes, et elles se cumulaient.** ① Le pseudo-élément était en
   retrait de `3.4% 2%` — le verre seul, sans son halo : la bande
   s'arrêtait donc avant le bord. ② Il TRAVERSAIT en `translateX`, de
   −130 % à +130 % : aux deux extrémités de sa course il était **hors de
   la boîte**, et `overflow: hidden` le tranchait. *La bande ne balayait
   en pleine largeur qu'au milieu de son passage.*

   ⚠⚠ **LE MOUVEMENT CHANGE DE NATURE : C'EST LE FOND QUI GLISSE,
   PAS L'ÉLÉMENT.** Le pseudo-élément est **immobile** ; c'est
   `background-position` qui se déplace, sur un fond de 250 % de large. *Un
   fond est rogné par le `border-radius` de son propre élément — il ne peut
   donc pas déborder, et il n'a plus besoin qu'on rogne le parent.* **C'est
   ce qui a permis de retirer `overflow: hidden`, donc de rendre au halo son
   contour flou.**

   ⚠⚠⚠ **CE BLOC DISAIT « couvre `inset: 0` », ET C'ÉTAIT FAUX DEPUIS LE
   MÊME JOUR — relevé par la mission ①bis du vérificateur.** L'`inset` vaut
   désormais `0 calc(var(--capsule-h) * var(--gros) * -.5045)`, donc
   **négatif** : le pseudo-élément est **plus large que sa boîte de padding**,
   pour couvrir les deux calottes que la bordure occupe.

   ⚠️ **ET C'EST LA MÊME ERREUR QU'UN BLOC DÉMONTÉ TRENTE LIGNES PLUS HAUT,
   LE MÊME JOUR.** *Corriger une affirmation périmée et laisser sa jumelle
   dans le même fichier est précisément le motif que ce dépôt passe son temps
   à nommer — et il aura fallu deux passes du vérificateur pour le voir ici.*

   ⚠️ **LA BANDE CLAIRE EST PLUS LARGE** — de 38 % à 62 % du fond au lieu
   de 47 % à 54 %. *Sur un galet trois fois plus large que haut, une bande
   étroite se lit comme un trait qui passe, pas comme une lumière qui
   traverse.* */
.processus-touche::before {
  content: "";
  /* ⚠⚠⚠ **LES DEUX CALOTTES ÉTAIENT HORS DE LA BANDE, ET C'EST UNE
     RÈGLE DU POSITIONNEMENT ABSOLU, PAS UN RÉGLAGE** — constat de Franck,
     capture à l'appui, 2026-09-09 : *« l'effet bleu sur ces boutons, au
     survol, ne prend pas toute la largeur du bouton »*.

     **LA CAUSE** : le bloc conteneur d'un élément `position: absolute` est
     la **BOÎTE DE PADDING** de son ancêtre positionné, *jamais sa boîte de
     bordure*. Or cette capsule porte toute sa forme dans une bordure —
     `border-width: 0 calc(var(--capsule-h) * .5045)`, soit **1,21 rem de
     chaque côté** à la hauteur par défaut. `inset: 0` laissait donc les
     deux calottes **entièrement dehors**.

     ⚠️ **ET LE DÉFAUT EST PIRE SUR LES BOUTONS COURTS**, ce qui explique
     qu'il saute aux yeux sur « 5D » :

     | Le libellé | Largeur | Ce que la bande couvrait |
     |---|---|---|
     | `5D` | 4,32 rem | **44 %** |
     | `CLEAR` | 6,02 rem | 60 % |
     | `CODEVELOPPEMENT` | 11,82 rem | 80 % |

     *La bande s'arrêtait donc sur deux arêtes VERTICALES au ras des
     calottes — une lumière qui traverse un verre et s'interrompt sur une
     ligne droite se lit comme un défaut d'impression.*

     **LE GESTE** : des `inset` horizontaux **négatifs**, de la valeur exacte
     de la bordure, qui rendent au pseudo-élément la boîte de bordure.
     ⚠️ **LE MÊME JETON DES DEUX CÔTÉS** : si `--capsule-h` change — et
     `/consommation/seances` la réduit — les deux suivent ensemble. *Une
     valeur en dur ici aurait été juste sur un écran et fausse sur l'autre.*

     ⚠️ **RIEN NE DÉBORDE POUR AUTANT** : le `border-radius` ci-dessous
     rogne le fond du pseudo-élément sur SA propre boîte, qui épouse
     désormais la capsule. *C'est ce qui permet de ne pas remettre
     l'`overflow: hidden` qu'on a retiré.* */
  position: absolute;
  /* ⚠⚠⚠ **`var(--gros)` — SANS LUI, LA COMPENSATION NE VALAIT QU'À L'ÉTAT
     OÙ LA BANDE EST INVISIBLE.** Relevé par la revue d'intention, 2026-09-09.
     *Le pseudo-élément n'est peint qu'au survol et au focus — `opacity: 0` au
     repos — et ce sont précisément les états où `--gros` vaut 1,06 ou 1,1.*
     La bordure grandissait avec lui, le retrait du `::before` non : les deux
     calottes restaient **partiellement hors de la bande**, de
     `H × .5045 × (g − 1)` par côté — **2,03 px à 4,2 rem au survol, 3,39 px
     sur une capsule choisie**. *Le défaut que ce bloc existe pour fermer
     n'était donc corrigé qu'au repos, c'est-à-dire jamais vu.*

     ⚠️ **LA VERTICALE, ELLE, EST JUSTE SANS LUI** : les bordures haute et
     basse sont nulles, donc la boîte de padding égale la boîte de bordure en
     hauteur. *C'est ce qui rendait le défaut asymétrique et discret.* */
  inset: 0 calc(var(--capsule-h) * var(--gros) * -.5045);
  border-radius: var(--r-plein);
  background-image: linear-gradient(105deg,
    rgba(255, 255, 255, 0) 22%,
    rgba(255, 255, 255, .88) 38%,
    rgba(206, 230, 248, .75) 50%,
    rgba(255, 255, 255, .88) 62%,
    rgba(255, 255, 255, 0) 78%);
  background-size: 250% 100%;
  background-repeat: no-repeat;
  /* ⚠⚠ **130 % ET −25 % — LES DEUX BORNES SONT MESURÉES DANS UN
     NAVIGATEUR, 2026-09-09, ET ELLES CORRIGENT MA PROPRE ERREUR DU MATIN.**

     ⚠️ **J'AVAIS LE SENS DE LA COURSE À L'ENVERS.** J'avais écrit que la
     bande partait à droite et sortait à gauche, et j'avais « corrigé »
     −60 % en −160 % sur ce modèle. **C'est l'inverse** : un
     `background-position` en pourcentage n'est pas un décalage, il **ALIGNE
     le point X % de l'image sur le point X % du cadre**. Le décalage réel
     vaut `(largeur_cadre − largeur_fond) × X%`, donc **négatif quand X
     monte** : à 160 % la bande est **hors cadre À GAUCHE**, à −160 % elle
     est **hors cadre À DROITE**. *Ma « correction » allongeait donc le
     temps mort au lieu de le supprimer.*

     **CE QUE LA MESURE DONNE** — quinze positions rendues et photographiées
     dans Chrome, sur `5D` et sur `CODEVELOPPEMENT` : la bande **entre vers
     125 % et sort vers −20 %**. Tout le reste de la course est du vide.

     | La course | Amplitude | Part réellement visible | Traversée vue en |
     |---|---|---|---|
     | avant mes retouches (160 → −60, .62 s) | 220 % | 66 % | 0,41 s |
     | en ligne ce matin (160 → −160, .34 s) | 320 % | **45 %** | 0,15 s |
     | **ici (130 → −25, .22 s)** | 155 % | **94 %** | **0,21 s** |

     ⚠️ **LE TEMPS MORT N'EST PAS ANODIN** : à 45 %, plus d'une demi-seconde
     de survol sur deux ne montrait RIEN — la lumière passait comme un
     clignotement, puis le bouton restait inerte alors qu'il était toujours
     surviolé. *Un effet qui se termine avant qu'on ait fini de regarder se
     lit comme un raté d'affichage, pas comme une intention.*

     ⚠️ **LA DURÉE BAISSE ET POURTANT LA TRAVERSÉE RALENTIT**, et les deux
     sont voulus : .22 s couvre désormais **presque toute** la course utile,
     là où .34 s n'en couvrait que 45 %. On reste **deux fois plus rapide
     qu'avant les retouches** (0,21 s contre 0,41 s), ce que Franck avait
     demandé, **sans le clignotement**. *S'il la veut plus vive encore, le
     seul nombre à toucher est la durée — les bornes, elles, sont mesurées.* */
  background-position: 130% 0;
  opacity: 0;
  pointer-events: none;
}

/* ⚠⚠ **220 MILLISECONDES — ET LES DEUX COMMENTAIRES QUI ANNONÇAIENT 620
   PUIS 340 SONT RETIRÉS ICI, LE 2026-09-09.** Ils dataient de la même
   journée et **se contredisaient déjà l'un l'autre** — le premier décrivait
   une bande qui « traverse lentement », le second son accélération à 340.
   *Trois valeurs successives en un jour, et deux paragraphes au présent
   pour deux d'entre elles.*

   ⚠️ **LA DURÉE SEULE NE DIT RIEN : C'EST LA PART VISIBLE QUI COMPTE.**
   Les bornes de la course étaient trop larges, la bande passait donc la
   moitié du temps hors cadre. Le tableau qui mesure les trois courses est
   dans le commentaire de `background-position` au repos, quelques lignes
   plus haut ; il donne la traversée réellement vue : 0,41 s, puis 0,15 s,
   puis **0,21 s** ici.

   ⚠️ **L'OPACITÉ RESTE À 120 ms, ET L'ÉCART EST VOULU** : la lumière est
   là tout de suite, elle traverse ensuite. Une seule durée donnerait soit
   un éclair, soit une bande qui apparaît en retard.

   ⚠️ **LA COURBE NE CHANGE PAS** — c'est elle qui donne le départ vif et
   l'arrivée douce d'un reflet. */
/* ⚠⚠⚠ **CE BLOC PORTAIT UN CALCUL FAUX — RETIRÉ LE 2026-09-09 MÊME,
   APRÈS MESURE DANS UN NAVIGATEUR.** Il expliquait le passage de −60 % à
   −160 % par une arithmétique qui **inversait le sens de la course** :
   *« au repos la bande est hors cadre À DROITE, elle sort À GAUCHE »*.
   C'est le contraire. **Le modèle [P+95, P+155] était faux aussi** : il
   traitait `background-position` comme un décalage direct, alors qu'il
   **ALIGNE** — le décalage réel vaut `(cadre − fond) × X%`, donc de signe
   opposé. *Une formule qui se « vérifie » sans jamais être confrontée à un
   rendu peut se vérifier longtemps.*

   ⚠️ **ET LE DIAGNOSTIC DE FOND ÉTAIT FAUX AVEC LUI.** Ce que Franck
   décrivait — *« l'effet ne couvre pas tout le galet »* — ne venait pas
   des bornes de la course : il venait de ce que le pseudo-élément
   s'arrêtait à la **boîte de padding**, laissant les deux calottes dehors.
   *La cause est dans le bloc `inset` ci-dessus, pas ici.* Il l'a reposé le
   jour même, capture à l'appui, et il avait raison les deux fois.

   **LES BORNES EXACTES SONT MAINTENANT MESURÉES**, et elles vivent dans le
   commentaire de `background-position` au repos, quelques lignes plus haut,
   avec le tableau des trois courses. */
.processus-touche:hover::before,
.processus-touche:focus-visible::before {
  background-position: -25% 0;
  opacity: 1;
  transition: background-position .22s cubic-bezier(.22, .61, .36, 1),
              opacity .12s ease;
}

/* ⚠️ **LES TROIS DÉSAMORÇAGES — interdit n°3, ils ne se suppriment
   pas.** Qui a demandé moins d'animation ne reçoit ni bande qui passe ni
   agrandissement ; en contraste élevé la bande disparaît, parce qu'elle
   fait baisser le contraste du libellé pendant qu'elle passe ; à
   l'impression, une image de fond ne s'imprime pas — la capsule redevient
   un code encadré d'un filet. */
@media (prefers-reduced-motion: reduce) {
  .processus-touche::before { display: none; }
  /* ⚠️ **`--gros: 1` ET NON `transform: none` — 2026-09-09.** La ligne
     précédente neutralisait un `transform` qui n'existe plus : elle **ne
     désactivait donc plus rien**, et l'agrandissement au survol serait
     resté pour qui demande la réduction des animations. *Une garde qui vise
     une propriété retirée s'éteint en silence — c'est le motif que ce
     dépôt nomme ailleurs à propos des commentaires périmés.* */
  .processus-touche, .processus-touche:hover,
  .processus-touche.choisie, .processus-touche.choisie:hover { --gros: 1; }
}
@media (prefers-contrast: more) {
  .processus-touche::before { display: none; }
  .processus-touche { filter: none; }
}
@media print {
  .processus-touche::before { display: none; }
  /* ⚠⚠ **`--gros: 1` ET `margin: 0`, ET NON `transform: none` — corrigé
     le 2026-09-09 par la revue d'intention.** Le bloc voisin de
     `prefers-reduced-motion` explique longuement pourquoi `transform: none`
     ne désactive plus rien — **et le même `transform: none` subsistait ici,
     dix-huit lignes plus bas.** *Corriger une garde et laisser sa jumelle
     est le défaut que ce fichier passe son temps à nommer.*

     ⚠️ **`margin: 0` N'EST PAS UN ORNEMENT** : la règle de base pose une
     marge **négative** dès que `--gros` dépasse 1. Sans remise à zéro, une
     capsule `.choisie` s'imprimerait avec `margin: -0,126rem -0,127rem` —
     *une valeur calculée pour compenser une croissance que `height: auto`
     vient justement de supprimer.* */
  .processus-touche { border-image: none; border: 1px solid #666;
                      border-radius: var(--r-plein); height: auto;
                      padding: .1rem .5rem; filter: none;
                      margin: 0; }
  /* ⚠⚠ **LES QUATRE SÉLECTEURS, ET NON `.processus-touche` SEUL — relevé
     par la mission ①bis.** `--gros: 1` posé dans la règle ci-dessus vaut
     `(0,1,0)` ; `.processus-touche.choisie` vaut `(0,2,0)` et **n'est dans
     aucune média-requête** — *une `@media` n'ajoute aucun poids*. La garde
     était donc **inerte sur une capsule choisie**, là même où `--gros` vaut
     1,06. **Sans effet visible aujourd'hui**, parce que la règle ci-dessus
     réécrit déjà hauteur, marge intérieure, bordure et marge — *mais une
     garde décorative s'éteint en silence le jour où l'une de ces
     réécritures tombe.* Le bloc jumeau de `prefers-reduced-motion` énumère
     les quatre depuis le début ; **la correction print avait copié la
     déclaration sans copier la liste.** */
  .processus-touche, .processus-touche:hover,
  .processus-touche.choisie, .processus-touche.choisie:hover { --gros: 1; }
}

/* Un dépliant se manipule aussi : il reçoit le même geste, en plus
   discret — il ouvre, il n'engage rien. */
summary { cursor: pointer; border-radius: var(--r-doux); }
summary:hover { color: var(--encre); }

/* ⚠️ **LE CONTOUR DE FOCUS EST POSÉ ICI POUR TOUT LE SERVICE**, et il
   ne se négocie pas. Un gabarit peut le redéfinir ; aucun n'a besoin de
   le réinventer. */
/* ⚠️ **`border-radius` A ÉTÉ RETIRÉ D'ICI — 2026-08-17, demande de
   Franck : « lorsque l'on clique, aucune modification graphique ne doit
   être faite sur le champ, afin de garder les arrondis ».**

   Cette règle portait `border-radius: 2px`. Or un `border-radius` posé
   dans un bloc `:focus-visible` s'applique **à l'élément lui-même**, pas
   au contour : le champ perdait donc ses 16 px d'arrondi au moment précis
   où on le touchait, et redevenait presque carré. Le défaut venait de la
   2.0, où le rayon des champs était de 12 px et l'écart peu visible.

   **Le contour, lui, reste et ne se négocie pas** : c'est le seul repère
   de qui navigue sans souris. Il ne déforme rien — `outline` se dessine
   EN DEHORS de la boîte et épouse désormais l'arrondi du champ. */
a:focus-visible, button:focus-visible, summary:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 3px solid var(--focus); outline-offset: 3px;
}

/* ── LES TABLEAUX ──────────────────────────────────────────────────
   Les filets restent : un tableau sans séparation de lignes n'est plus
   un tableau. L'en-tête est de la mesure, et les chiffres s'alignent. */
table { border-collapse: collapse; }
th { font-family: var(--mesure); color: var(--encre-pale);
     font-size: var(--taille-mention); font-weight: 700;
     letter-spacing: .12em; text-transform: uppercase; }
td, th { border-bottom: 1px solid var(--filet); }
td, .valeur, .chiffre { font-variant-numeric: tabular-nums; }
/* Un tableau est de la donnée : son contenu est de la mesure, sauf une
   colonne de texte libre, que le gabarit repasse en `.parole`. */
td { font-family: var(--mesure); font-size: var(--taille-lecture); }

/* ── L'ÉTAT D'UNE SÉANCE ──────────────────────────────────────────
   ⚠️ **MONTÉE ICI DEPUIS `pages/seances.css` LE 2026-09-01**, quand le
   journal des consommations est devenu le SECOND écran à afficher les
   quatre états. Les déclarations sont reprises à l'identique — aucune
   couleur n'a changé, aucune valeur n'a bougé.

   **Le motif est celui de la refonte du 2026-08-28** : la même règle
   écrite dans deux feuilles de page diverge à la première correction
   faite d'un seul côté. C'était mesuré à 77 sélecteurs en double avant
   la sortie du CSS des gabarits ; ce n'est pas une abstraction, c'est ce
   qui avait déjà cassé le repère du tuteur dans la marge.

   Les quatre codes sont ceux de la contrainte `statut_connu` de
   `simulation` — `creee`, `en_cours`, `terminee`, `abandonnee` — et le
   gabarit les affiche tirets bas remplacés par des espaces. */
.etat-seance { font-size: var(--taille-aide); padding: .1rem .5rem; border-radius: 3px; }
.etat-seance.creee     { background: #eef2f7; color: var(--encre-douce); }
.etat-seance.en_cours  { background: #fff6e5; color: var(--attention); }
.etat-seance.terminee  { background-color: var(--verre-creux); color: var(--bon); }
.etat-seance.abandonnee{ background: var(--papier-creux); color: var(--encre-pale); }

/* ⚠️ **UN TABLEAU DÉBORDE SUR UN TÉLÉPHONE, ET C'EST LA PAGE ENTIÈRE QUI
   PORTE ALORS UN ASCENSEUR HORIZONTAL** — mesuré le 2026-08-17 :
   `seances.html` faisait 491 px dans 375. Le défaut est le même que celui
   du rail, qui avait vécu quatre jours dans le dépôt.

   Le tableau devient sa propre zone défilante. **C'est lui qui défile, pas
   la page** : un ascenseur sur le corps décale tout, en-tête comprise, et
   donne l'impression d'un site cassé ; un ascenseur sur le tableau se
   comprend au premier geste.

   ⚠️ `display: block` casse l'alignement des colonnes entre `thead` et
   `tbody` — c'est le prix connu de ce remède, et il ne se paie que sous
   48 rem, là où un tableau à cinq colonnes était de toute façon illisible.

   ⚠️ **LE COMPTE ÉTAIT FAUX ET IL A ÉTÉ MESURÉ LE 2026-09-01** : il
   disait « cinq écrans : séances, comptes, consommation, économie,
   tarification », et l'écran d'économie a été supprimé le 2026-08-30.
   `grep -l '<table' app/templates/` en donne **onze** : backlog,
   backlog-fiche, comptes, consommation, consommation-seances,
   paiements, parametrage, prompts, seances, tarification, versions.
   *`facturation` y figurait jusqu'au 2026-09-08, date de sa
   suppression — comme `economie` avant lui le 2026-08-30.* */
@media (max-width: 48rem) {
  table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  td, th { white-space: nowrap; }
}
td.parole { font-family: var(--parole); font-size: var(--taille-appui); }

/* ══ LE RELIEF RENDU AUX BOUTONS DES GABARITS — 3.3, 2026-08-17 ═══════
   ⚠️ **CETTE RÈGLE EXISTE PARCE QUE LA CONVERSION DES DOUZE DERNIERS
   ÉCRANS A ÉTÉ MÉCANIQUE.** Elle a supprimé 31 reliefs — c'était le bon
   défaut : *un relief est supprimé, pas converti*, une carte qui sort
   ayant l'air d'un bouton géant. Mais elle les a supprimés AUX BOUTONS
   AUSSI, qui eux doivent sortir.

   Plutôt que de les rendre un par un dans douze fichiers, on les rend
   ici : **tout élément dont la classe porte « bouton » agit**, par
   construction — c'est la convention de nommage du service depuis
   l'origine, `bouton-action`, `bouton-rapide`, `bouton-valider`,
   `bouton-accueil`, `bouton-partenaire`…

   ⚠️ **LA SPÉCIFICITÉ EST BASSE À DESSEIN** : un gabarit qui a une idée
   précise du relief de son bouton la garde, puisque son `<style>` est
   chargé après. Ici on donne un socle, on n'impose rien. */
/* ⚠️ **UN CHOIX EN RADIO SE MANIPULE AUSSI.** Les gabarits les habillent
   en `<label>` porteur d'un `<input type="radio">` masqué — le formulaire
   de retour, le paramétrage de séance. Ils n'ont pas « bouton » dans leur
   classe et la passe mécanique les avait donc laissés plats, alors qu'ils
   se cliquent. Le sélecteur les attrape par leur STRUCTURE, qui, elle, ne
   varie pas d'un gabarit à l'autre. */
label:has(> input[type="radio"]), label:has(> input[type="checkbox"]) {
  border-radius: var(--r-doux); box-shadow: var(--pose);
  padding: .45rem 1.05rem; cursor: pointer;
  transition: box-shadow .16s ease, transform .12s ease;
}
label:has(> input[type="radio"]):hover,
label:has(> input[type="checkbox"]):hover {
  box-shadow: var(--pose-forte); transform: translateY(-1px);
}
/* Le choix RETENU s'enfonce : il ne propose plus, il est acquis. */
label:has(> input:checked) { box-shadow: var(--creuse); transform: none;
                             color: var(--encre); font-weight: 600; }

/* ⚠️ **BORNÉ AUX `<a>` ET AUX `<button>` COMME LA LISTE DU HAUT —
   2026-08-30.** C'est CE bloc-ci qui posait l'ombre visible sur les
   conteneurs `div.boutons` et `div.boutons-fin` : chargé plus bas, son
   `var(--pose)` l'emportait sur le relief de touche. Le motif complet
   est écrit une seule fois, à la grande liste. */
a[class*="bouton"], button[class*="bouton"], a.bouton, button:not([class]) {
  border-radius: var(--r-doux);
  box-shadow: var(--pose);
  transition: box-shadow .16s ease, transform .12s ease, background .16s ease;
}
a[class*="bouton"]:hover, button[class*="bouton"]:hover,
a.bouton:hover, button:not([class]):hover {
  box-shadow: var(--pose-forte); transform: translateY(-1px);
}
a[class*="bouton"]:active, button[class*="bouton"]:active,
a.bouton:active, button:not([class]):active {
  transform: translateY(1px); box-shadow: var(--creuse);
}
/* ⚠️ **LE RAIL EST DE LA NUIT SANS PORTER LA CLASSE `nuit`** — il a la
   sienne, `.rail`, depuis 2026-08-10. Sans cette ligne, le bouton « Se
   déconnecter » recevait le relief du PAPIER : un halo clair au milieu du
   marine. Vu à l'écran le 2026-08-17. */
.rail button, .rail button:hover, .rail button:active { box-shadow: none;
                                                        transform: none; }
.nuit a[class*="bouton"], .nuit button[class*="bouton"] {
  box-shadow: var(--pose-nuit); }
.nuit a[class*="bouton"]:hover, .nuit button[class*="bouton"]:hover {
  box-shadow: var(--pose-nuit-forte); }
.nuit a[class*="bouton"]:active, .nuit button[class*="bouton"]:active {
  box-shadow: var(--creuse-nuit); }

/* ⚠️ **ET LE MOUVEMENT DISPARAÎT POUR QUI L'A DEMANDÉ.** Le bloc
   `prefers-reduced-motion` de fin de fichier ramène les durées à 0,001 ms,
   mais un `transform` figé reste un déplacement : on l'annule ici. */
@media (prefers-reduced-motion: reduce) {
  a[class*="bouton"]:hover, a[class*="bouton"]:active,
  button[class*="bouton"]:hover, button[class*="bouton"]:active,
  a.bouton:hover, a.bouton:active { transform: none; }
}


/* ══ LE BANDEAU D'ENVIRONNEMENT — 3.4, 2026-08-24 ══════════════════
   Le jour du dédoublement : production sur `simsimup.com`, recette sur
   `poc.simsimup.com`.

   ⚠️ **IL NE SE PEINT QUE SI LE GABARIT L'A POSÉ**, c'est-à-dire si la
   variable `ENVIRONNEMENT` existe côté serveur. En production elle est
   absente du `docker-compose.yml` : aucune de ces règles ne s'applique,
   et pas un pixel ne bouge.

   ⚠️ **AMBRE ET NON ROUGE.** L'alerte est réservée à ce qui a échoué. Ici
   rien n'est en panne — on signale un lieu, pas une faute. C'est le même
   arbitrage que la pastille de retour. */

.bandeau-environnement {
  position: fixed; top: 0; left: 0; right: 0;
  /* ⚠️ **AU-DESSUS DU RAIL, QUI EST À 20.** En dessous, il passerait sous
     la colonne de navigation sur toute sa largeur — donc invisible là où
     le regard se pose en premier. */
  z-index: 100;
  display: flex; align-items: center; justify-content: center;
  gap: .6rem;
  height: 1.75rem;
  background: var(--attention);
  color: #fff;
  font-family: var(--mesure); font-size: var(--taille-etiquette);
  letter-spacing: .04em;
  /* Il ne se ferme pas, ne se replie pas et ne se survole pas : c'est un
     état du service, pas une notification. */
  pointer-events: none;
  user-select: none;
}
.bandeau-environnement strong { font-weight: 700; letter-spacing: .12em; }
.bandeau-environnement span { opacity: .92; }

/* ⚠️ **`:has()` ÉVITE DE TOUCHER LA MISE EN PAGE DES DIX-SEPT ÉCRANS.**
   Le bandeau est en position fixe : sans ces deux règles, il recouvrirait
   le haut de chaque page et le logo du rail. Les écrire ainsi les rend
   conditionnelles à sa présence — donc inertes en production, sans le
   moindre drapeau à passer dans les gabarits.

   ⚠️ **LA SECONDE GAGNE MALGRÉ `navigation.css`, CHARGÉE APRÈS.** Ce
   n'est pas l'ordre qui tranche ici mais la spécificité : `.rail` seul
   pèse moins que ce sélecteur. Aucun `!important` n'est nécessaire, et il
   ne faut pas en ajouter — ce serait masquer la raison. */
body:has(.bandeau-environnement) { padding-top: 1.75rem; }
body:has(.bandeau-environnement) .rail { top: 1.75rem; }


/* ══ CE QUI DÉSAMORCE LE STYLE QUAND IL LE FAUT ════════════════════
   ⚠️ **NE PAS SUPPRIMER CES DEUX BLOCS EN CROYANT NETTOYER.** */

/* Qui a demandé plus de contraste à son système reçoit des filets nets
   et des encres poussées à fond. Le sélecteur d'attribut attrape les
   objets nommés par les gabarits, comme en 2.0. */
@media (prefers-contrast: more) {
  /* ⚠️ **LE VERRE DEVIENT OPAQUE ICI, ET C'EST LE POINT.** Qui demande
     plus de contraste ne peut pas recevoir un fond qui bouge : le
     contraste du texte varierait pendant toute la boucle vidéo. Les
     plaques deviennent blanches, le voile devient blanc, et la vidéo ne
     se voit plus du tout. */
  :root { --encre-pale: #3A4A52;
          --verre: #fff; --verre-vif: #fff; --verre-creux: #fff;
          --verre-bord: rgba(47,62,70,.5); --verre-arete: transparent;
          --flou: none; --flou-fort: none;
          --voile-haut: #fff; --voile-bas: #fff;
          --nuit: #fff; --nuit-clair: var(--sombre-nuit);
          --filet: rgba(47,62,70,.45); --filet-fort: rgba(47,62,70,.7); }
  .fond-ambiance { display: none; }
  [class*="carte"], [class*="bloc"], [class*="panneau"], [class*="option"],
  input, select, textarea, button, table, .nuit {
    border: 1px solid var(--encre-douce);
  }
  .nuit { border-color: var(--lueur-pale); }
}

/* Qui a demandé moins d'animations n'en reçoit aucune — y compris la
   marque du tuteur, qui se pose alors franche et immobile. C'est le bon
   comportement, pas un effet de bord. */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; animation-iteration-count: 1 !important;
      transition-duration: .001ms !important; }
}


/* ══ À L'IMPRESSION ════════════════════════════════════════════════
   ⚠️ **LA NUIT NE S'IMPRIME PAS, ET C'EST PLUS GRAVE QUE LE RELIEF DE
   LA 2.0.** Une ombre douce sortait en aplat gris sale ; un fond marine
   sort en **aplat noir plein page**, vide la cartouche et rend le texte
   clair illisible. L'export PDF de la simulation économique existe
   depuis le 2026-08-12 : ce bloc n'est pas facultatif.

   Le papier redevient blanc, la nuit redevient blanche AUSSI, et les
   filets reviennent — sur le papier, la hiérarchie se refait par le
   trait. */
@media print {
  :root {
    --papier: #fff; --papier-vif: #fff; --papier-creux: #fff;
    --nuit: #fff; --nuit-clair: #fff; --nuit-creux: #fff;
    /* ⚠️ **LE VERRE ET LA VIDÉO N'EXISTENT PAS SUR DU PAPIER** — une
       plaque translucide s'imprime en aplat gris sale, et un
       `backdrop-filter` ne s'imprime pas du tout. */
    --verre: #fff; --verre-vif: #fff; --verre-creux: #fff;
    --verre-bord: #999; --verre-arete: transparent;
    --flou: none; --flou-fort: none;
    --voile-haut: #fff; --voile-bas: #fff;
    --encre: #000; --encre-douce: #333; --encre-pale: #555;
    --lueur: #000; --lueur-pale: #555; --lueur-vive: #000;
    --annotation: #000;
    --filet: #999; --filet-fort: #666; --filet-nuit: #999;
    /* Le relief fonctionnel ne s'imprime pas : sur papier, rien ne se
       clique, et une ombre y sort en aplat gris sale. */
    --pose: none; --pose-forte: none; --saisie: none;
    --pose-nuit: none; --pose-nuit-forte: none; --saisie-nuit: none;
  }
  body { background: #fff; }
  .fond-ambiance { display: none; }
  .nuit {
    background: #fff !important; color: #000 !important;
    border: 1px solid #999;
  }
  .nuit h1, .nuit h2, .nuit h3, .nuit strong, .nuit b { color: #000 !important; }
  [class*="carte"], [class*="bloc"], [class*="panneau"] {
    box-shadow: none !important; border: 1px solid #999;
  }
}
