/**
 * LES COULEURS DU SOCLE D'ADMINISTRATION — toutes, et rien d'autre.  (DS-2a, 2026-08-27)
 *
 * CE FICHIER NE PORTE AUCUNE RÈGLE. Il déclare des custom properties, en clair
 * et en sombre, et c'est tout ce qu'il a le droit de faire : la règle K de
 * `tools/ds-check.mjs` échoue sur toute règle dont le sujet n'est pas un
 * contexte racine, ou qui porte une déclaration qui n'est pas un jeton.
 *
 * ⚠️ POURQUOI CETTE GARDE EXISTE. Il portait quarante-deux règles ciblant une
 * classe du socle, chargées après lui sur les treize écrans : il REPEIGNAIT LA
 * RÈGLE au lieu de REMAPPER LE JETON. Le prix, trois fois payé : `.fbx-btn--primary`
 * rendait le bouton principal illisible en sombre (1,81:1) pendant que
 * `--fbx-accent-fill` résolvait juste ; une ligne survolée virait au bleu sur
 * `/feedbacks` et restait violette sur `/review`, faute d'avoir repeint la
 * jumelle ; `.fbx-callout--warning` était annulée par une règle voisine plus
 * spécifique, et une alerte s'affichait comme une explication neutre.
 *
 * ⚠️ ON REMAPPE LE JETON, JAMAIS LA RÈGLE QUI LE LIT. Un rôle nouveau s'ajoute
 * ICI ; une règle qui cible une classe du socle s'écrit DANS LE SOCLE.
 *
 * ⚠️ D1 EST APPLIQUÉE PAR DÉFAUT depuis le 2026-08-06 : les blocs portent
 * `:root`. Le charger suffit, aucun attribut n'est attendu. Les treize écrans le
 * chargent, en dernier des trois.
 *
 * ⚠️ LE SÉLECTEUR SCOPÉ SURVIT À CÔTÉ DE `:root`, ET CE N'EST PAS DE LA DETTE :
 * la page « Palette » de la vitrine montre le clair et le sombre CÔTE À CÔTE,
 * dans deux `<div data-palette="p37" data-scheme="…">`. Solder une dette ne doit
 * pas coûter une capacité.
 *
 * POUR AJUSTER UNE VALEUR : ici, et nulle part ailleurs. La vitrine lit ces
 * variables par `getComputedStyle` et recalcule les contrastes à l'affichage —
 * une valeur modifiée ici se voit immédiatement, contraste compris.
 *
 * ═════════════════════════════════════════════════════════════════════════
 * DEUX COUCHES, JAMAIS MÉLANGÉES  (DS-2a)
 *
 *   1. PRIMITIVES  `--tpx-*`   des valeurs, deux rampes de neutres et une de
 *                              bleus. JAMAIS consommées par un composant.
 *   2. RÔLES       `--fbx-*`   ce que l'interface lit. Ce sont eux qui changent
 *                  `--st-*`    avec le thème.
 *
 * ⚠️ IL Y AVAIT DEUX VOCABULAIRES, ET PERSONNE NE L'AVAIT DÉCIDÉ. `--ui-*`
 * (ce fichier) et `--fbx-*` (le socle) disaient les mêmes rôles à d'autres
 * valeurs — mais EN CLAIR SEULEMENT : `--fbx-border` valait #e5e7eb et
 * `--ui-border` #e7eaee, `--fbx-text` #333333 et `--ui-text` #33383d. En sombre
 * les deux familles s'accordaient partout. La palette n'avait repeint que les
 * vingt endroits où ses auteurs l'avaient fait à la main ; le reste du socle
 * portait les neutres d'avant. Résultat, à l'écran : `.fbx-select` et
 * `.fbx-input`, côte à côte dans la même barre de filtres, avec deux gris de
 * filet. `--ui-*` a été retiré ; les valeurs retenues sont celles de D1.
 *
 * ⚠️ AUCUN CRAN DE PRIMITIVE N'EST UN RÔLE. `--tpx-grey-700` dit une valeur ;
 * `--fbx-text-soft` dit à quoi elle sert. Un composant lit le second. Le premier
 * ne se rencontre que dans ce fichier — et dans le seul bloc scopé qui doit
 * échapper à un thème local (la pastille de repli du rail, plus bas).
 *
 * ═════════════════════════════════════════════════════════════════════════
 * LA RÈGLE DE NOMMAGE DES TEINTES — l'accent et les quatre états
 *
 *   --fbx-<teinte>            la teinte elle-même              INVARIANTE
 *   --fbx-<teinte>-fg         son texte, posé sur un neutre    thémé
 *   --fbx-<teinte>-bg         son fond teinté                  thémé
 *   --fbx-<teinte>-bd         son filet teinté                 thémé
 *   --fbx-<teinte>-fill       la plaque pleine                 INVARIANTE
 *   --fbx-on-<teinte>         ce qui s'écrit sur la plaque     INVARIANTE
 *   --fbx-<teinte>-rgb        le triplet, pour composer un voile
 *
 * ⚠️ `-fill` N'EXISTE QUE POUR L'ACCENT, et c'est voulu. Pour les quatre états,
 * la teinte EST la plaque : un bouton rouge est peint avec `--fbx-danger`. Pour
 * l'accent elles diffèrent — #2BA8DD est la marque, #0F6E96 est ce qui porte du
 * texte blanc — et c'est l'écart mesuré le 2026-08-07 qui a créé le suffixe.
 * *Un suffixe qui n'existerait que par symétrie serait un doublon.*
 *
 * ⚠️ LES RÔLES NEUTRES NE SUIVENT PAS CE BARÈME : ils ne sont la déclinaison
 * d'aucune teinte. `--fbx-bg` est le fond de page, pas « le fond teinté du
 * neutre ».
 *
 * ═════════════════════════════════════════════════════════════════════════
 * ⚠️ DUPLICATION ASSUMÉE ET DOCUMENTÉE — `src/services/mail.js`
 *
 * Les mails ne peuvent pas lire de CSS : `TPX_STATUS` et `TPX` (mail.js) portent
 * les mêmes couleurs EN DUR. C'est la seule duplication acceptée du projet.
 * **Les six `--st-*-mail` ci-dessous SONT les valeurs de `mail.js`** — la
 * feuille ne porte que ce qui est SERVI. Toute modification là-bas se reporte
 * ici, et réciproquement ; `test/statuts-sources-couleurs.test.js` le vérifie.
 *
 * ⚠️ Une PROPOSITION de refonte de ces six valeurs existe, avec ses mesures et
 * le changement de mécanique qu'elle demande dans `tpxBadge` : elle vit dans
 * `doc/notes/2026-08-01-proposition-pilule-mail.md`, PAS ici. Elle a séjourné
 * dans cet en-tête du 01/08 au 27/08, et la vitrine affichait ses valeurs comme
 * si c'était l'état servi — *un design system qui montre un plan comme si
 * c'était l'état est un design system qui ment.*
 * ═════════════════════════════════════════════════════════════════════════ */


/* ═══════════════════════════════════════════════════════════════════════════
   COUCHE 1 — PRIMITIVES. Ne jamais consommer directement dans un composant.

   ⚠️ DEUX RAMPES DE NEUTRES, ET NON UNE RAMPE INVERSÉE. Le sombre n'est pas
   l'inverse du clair : sa rampe est plus bleue, et le fond de page doit y
   passer SOUS la surface là où il passe AU-DESSUS en clair. Deux rampes rendent
   ce renversement lisible ; une rampe inversée le cacherait.

   ⚠️ UNE RAMPE A DES CRANS INEMPLOYÉS, C'EST SA NATURE. `--tpx-grey-500`,
   `--tpx-grey-900`, `--tpx-blue-100` n'ont aucun lecteur : ce n'est pas du code
   mort, c'est une échelle.
   ═══════════════════════════════════════════════════════════════════════════ */
:root,
[data-palette="p37"] {
  --tpx-white: #FFFFFF;

  /* Neutres CLAIRS. Le gris 500 et le 800 sont les valeurs de la charte
     Toutenpixel, inchangées ; le reste est dérivé pour couvrir surfaces et
     contrastes.
     ⚠️ TROIS CRANS ONT ÉTÉ NOMMÉS PAR DS-2a DEPUIS DES VALEURS DÉJÀ À L'ÉCRAN
     (`75`, `300`, `700`) — nommer n'est pas inventer.
     ⚠️ `--tpx-grey-700` EST LÉGÈREMENT HORS DE LA RAMPE : #4B5563 est plus bleu
     que ses voisins #6B7178 et #33383D. Le cran « juste » serait ≈ #4F545D —
     mais ce serait inventer une couleur là où le socle en emploie déjà une. */
  --tpx-grey-50:  #FAFBFC;   /* existant (mail.js footBg) — zébrage, en-tête, retrait */
  --tpx-grey-75:  #F1F3F5;   /* canvas (2026-08-21) — était un littéral de `--ui-bg` */
  --tpx-grey-100: #EDF0F3;   /* existant (mail.js page) */
  --tpx-grey-200: #E7EAEE;   /* existant (mail.js hair) */
  --tpx-grey-300: #CBD0D6;   /* était `--fbx-n4` */
  --tpx-grey-400: #A6ADB4;
  --tpx-grey-500: #767D85;   /* « muted » charte — décoratif : 4,16, sous AA */
  --tpx-grey-600: #6B7178;   /* muted conforme AA — 4,93 */
  --tpx-grey-700: #4B5563;   /* était `--fbx-n8` — 7,56 */
  --tpx-grey-800: #33383D;   /* « ink » charte — et fond du glyphe Toutenpixel */
  --tpx-grey-900: #22262A;

  /* Neutres SOMBRES. Les surfaces se construisent autour de #33383D, le gris du
     glyphe Toutenpixel, et non d'un noir arbitraire : le sombre n'est pas une
     adaptation de la marque, c'est son terrain d'origine.
     ⚠️ CES ONZE VALEURS ÉTAIENT DES LITTÉRAUX du bloc sombre ; DS-2a les nomme
     sans en changer une seule. */
  --tpx-slate-100: #E6E9EC;
  --tpx-slate-200: #C2C8CE;
  --tpx-slate-300: #9BA3AB;
  --tpx-slate-400: #79838D;
  --tpx-slate-500: #5A646E;
  --tpx-slate-600: #414A53;
  --tpx-slate-700: #333B42;
  --tpx-slate-800: #262C32;
  --tpx-slate-850: #21272C;
  --tpx-slate-900: #1C2126;
  --tpx-slate-950: #14181B;

  /* Bleus de marque.
     ⚠️ `--tpx-blue-500` et `-600` SONT LA COPIE DE RÉFÉRENCE de `TPX.blue` et
     `TPX.blueDk` (mail.js) : c'est ici qu'on vérifie qu'un écran et un mail
     parlent de la même marque. `--tpx-brand` / `--tpx-brand-dark` portaient ce
     rôle dans `feedback-admin.css`, aux mêmes valeurs, sans consommateur — un
     doublon exact, retiré par DS-2a. */
  --tpx-blue-50:  #EAF6FC;
  --tpx-blue-100: #CBE9F7;
  --tpx-blue-300: #7CCBEB;
  --tpx-blue-500: #2BA8DD;   /* MARQUE — identité, aplats, pin. Jamais sous du texte blanc. */
  --tpx-blue-600: #1B87BC;
  --tpx-blue-700: #0F6E96;   /* porte du texte blanc — 5,69 */
  --tpx-blue-800: #0B5776;
}


/* ═══════════════════════════════════════════════════════════════════════════
   COUCHE 2 — LES RÔLES, MODE CLAIR (défaut)
   ═══════════════════════════════════════════════════════════════════════════ */
:root,
[data-palette="p37"] {

  /* ─── NEUTRES ────────────────────────────────────────────────────────────
     Quinze rôles, là où il y avait vingt-sept noms.
     ⚠️ `fill` N'EST PAS `surface`. Une SURFACE porte du contenu (carte, table,
     modale, champ) ; un FILL teinte un petit élément (pastille, tag, compteur,
     survol d'icône, barre). Les deux mots ont été employés l'un pour l'autre
     sous les noms `surface-alt` / `surface-muted`, et « muted » y disait
     « plus marqué » alors qu'il dit « moins visible » sur un texte : le même
     mot pour deux sens opposés, dans le même fichier.
     ⚠️ `--fbx-faint` ET NON `--fbx-disabled` : aucun de ses emplois n'est un
     contrôle désactivé, et le fond d'un bouton désactivé est `--fbx-fill-strong`.
     Un nom qui envoie chercher au mauvais endroit est pire qu'un nom vague. */
  --fbx-bg:              var(--tpx-grey-75);
  --fbx-surface:         var(--tpx-white);
  --fbx-surface-sunken:  var(--tpx-grey-50);
  --fbx-fill:            var(--tpx-grey-100);
  --fbx-fill-strong:     var(--tpx-grey-200);
  /* Zébrage : il doit rester SOUS le survol, sinon une ligne paire survolée
     cesse une fois sur deux de dire où est le pointeur. ⚠️ FIGÉ SUR LE CRAN 50
     ET NON SUR LE CANVAS (2026-08-21) : le canvas est descendu à #F1F3F5 pour se
     distinguer des surfaces ; le zébrage se juge contre la SURFACE de la liste
     (blanc), pas contre le fond de page. Couplés, descendre l'un rayait l'autre. */
  --fbx-row-alt:         var(--tpx-grey-50);
  /* ⚠️ FIGÉ POUR LA MÊME RAISON, et celui-ci ne doit surtout pas bouger :
     l'arbitrage du 2026-08-04 dit « pas de gris foncé sur un en-tête de tableau,
     nulle part ». Il égale le zébrage en clair, et c'est sans conséquence :
     l'en-tête se distingue par sa graisse, ses capitales et son filet. */
  --fbx-thead-bg:        var(--tpx-grey-50);
  /* Survol de ligne — UN SEUL JETON pour les deux mécaniques de tableau
     (`.fbx-table tbody tr` et `.fbx-grid-row`). La palette n'en repeignait
     qu'une, si bien qu'une ligne survolée virait au bleu sur `/feedbacks` et
     restait violette sur `/review` : même geste, deux couleurs. */
  --fbx-row-hover:       var(--fbx-accent-bg);
  --fbx-border:          var(--tpx-grey-200);
  /* Filet de LISTE — plus clair que `--fbx-border`, qui borde des surfaces. Une
     grille de comptage en trace beaucoup : au ton des surfaces, elle vire au
     quadrillage. */
  --fbx-border-list:     var(--tpx-grey-100);
  --fbx-border-strong:   var(--tpx-grey-300);
  --fbx-faint:           var(--tpx-grey-400);

  /* Trois niveaux de texte, parce que le socle en distingue trois : 22 emplois
     « courant » (intitulé de champ, libellé de case, fil de réponse, légende,
     libellé de bouton, onglet, tag), 53 « atténué », 59 « fort ».
     ⚠️ CE QUI A DISPARU EST UN DOUBLON : `--fbx-text-soft` et `--fbx-text-mute`
     valaient la MÊME chose (#6b7280) tout en servant deux populations. `-soft`
     prend le cran courant et absorbe les onze emplois directs de `--fbx-n8` ;
     `-muted` garde l'atténué. Aucun rôle nouveau : deux noms cessent de dire la
     même chose.
     ⚠️ LIMITE CONNUE — `--fbx-text-muted` SUR LE CANVAS D1 vaut 4,43, sous AA.
     Sur une SURFACE (blanc) il tient 4,93, et c'est là qu'il sert presque
     partout. Un texte atténué posé à même le canvas doit être regardé : le pied
     du seuil public a été passé à `--fbx-text-soft` pour cette raison. */
  --fbx-text:            var(--tpx-grey-800);   /* 11,84 sur blanc */
  --fbx-text-soft:       var(--tpx-grey-700);   /*  7,56 */
  --fbx-text-muted:      var(--tpx-grey-600);   /*  4,93 sur blanc · 4,43 sur le canvas */

  /* ─── ACCENT ─────────────────────────────────────────────────────────────
     ⚠️ LA PLAQUE N'EST PAS LE TEXTE, et c'est le thème sombre qui a forcé la
     distinction — le clair pouvait s'en passer, ce qui explique qu'elle ait
     manqué si longtemps :
       clair  : #0F6E96 lisible sur blanc (5,69) ET sous du blanc (5,69)
       sombre : #7CCBEB lisible sur du sombre (8,96) mais sous du blanc : 1,81
     Le bouton principal — le plus important de chaque formulaire — devenait
     illisible. Arbitré le 2026-08-07 : la plaque garde la MÊME valeur dans les
     deux thèmes, comme le bouton de connexion depuis P40. */
  --fbx-accent:            var(--tpx-blue-500);   /* aplats, pin, décor */
  --fbx-accent-fg:         var(--tpx-blue-700);   /* 5,69 — texte, liens, filets d'accent */
  --fbx-accent-bg:         var(--tpx-blue-50);
  --fbx-accent-fill:       var(--tpx-blue-700);   /* INVARIANTE — plaque sous du blanc */
  /* ⚠️ blue-800 et NON blue-700 (2026-08-07) : posé à blue-700 il valait
     exactement la couleur de repos — le survol du bouton le plus employé de
     l'outil ne rendait donc RIEN. */
  --fbx-accent-fill-hover: var(--tpx-blue-800);
  --fbx-accent-rgb:        43, 168, 221;
  /* ⚠️ LE BLANC DE CONTRASTE N'EST PAS LA SURFACE. `color: #fff` sur
     `.fbx-btn--danger` n'est pas « la couleur du papier » : c'est ce qui reste
     lisible SUR un fond coloré plein. En sombre, la surface s'inverse — pas lui. */
  --fbx-on-accent:         var(--tpx-white);
  --fbx-on-accent-rgb:     255, 255, 255;
  --fbx-focus:             rgba(43, 168, 221, .35);

  /* ─── ÉTATS ──────────────────────────────────────────────────────────────
     Quatre teintes de SENS — un avertissement, une erreur, une réussite, une
     information. Elles ne se rangent pas sur une rampe de neutres.

     ⚠️ LES QUATRE TEINTES SONT DES PLAQUES INVARIANTES, et c'est la réponse à
     « quatre couleurs d'état sans thème sombre » (relevé DS-1). Elles n'ont pas
     besoin d'un sombre : elles avaient besoin de CESSER D'ÊTRE EMPLOYÉES COMME
     TEXTE. Un bouton rouge est rouge dans les deux thèmes, exactement comme
     `--fbx-accent-fill`. Ce qui se lit SUR la surface prend le `-fg`, thémé.
     Mesuré avant de trancher : `.fbx-toast-inline--success` tenait 2,96 EN
     CLAIR, `--info` 3,29, `--error` 3,16 en sombre — tous trois lisaient la
     plaque. C'est la quatrième occurrence de la même leçon, après
     `--fbx-on-accent` ≠ la surface, `--fbx-on-warn` ≠ `--fbx-warn-fg` et
     `--fbx-accent-fill` ≠ l'accent-texte : *un jeton qui sert deux rôles ne se
     révèle qu'au thème qui les sépare*.

     ⚠️ `--fbx-on-warn` N'EST PAS `--fbx-warn-fg` : l'un se lit sur un fond ambre
     PÂLE (badge, encart), l'autre sur un fond ambre PLEIN (le toast). */
  --fbx-warn:         #F59E0B;
  --fbx-warn-rgb:     245, 158, 11;
  --fbx-warn-fg:      #92400E;
  --fbx-warn-bg:      #FEF3C7;   /* fond de badge, de pastille */
  --fbx-warn-bg-soft: #FFFBEB;   /* fond d'encart — plus pâle, plus de surface */
  --fbx-warn-bd:      #FDE68A;
  --fbx-on-warn:      #422006;   /* sur fond ambre PLEIN — 6,79 */

  --fbx-danger:       #DC2626;
  --fbx-danger-rgb:   220, 38, 38;
  /* ⚠️ CRAN NEUF — il manquait, et c'est le seul des quatre familles qui
     manquait. Sa valeur est en service : c'est `--st-needs-revision-fg` en
     clair et `--st-needs-revision` en sombre. 6,47 sur blanc, 5,91 sur son
     propre fond, contre 4,83 / 4,41 pour la plaque qu'il remplace. */
  --fbx-danger-fg:    #B91C1C;
  --fbx-danger-bg:    #FEF2F2;
  --fbx-danger-bd:    #FECACA;

  --fbx-ok:           #16A34A;
  --fbx-ok-rgb:       22, 163, 74;
  --fbx-ok-fg:        #065F46;
  --fbx-ok-bg:        #D1FAE5;
  --fbx-ok-hover:     #15803D;   /* survol du bouton plein */

  --fbx-info:         #3B82F6;
  --fbx-info-rgb:     59, 130, 246;
  --fbx-info-fg:      #3730A3;
  --fbx-info-bg:      #E0E7FF;

  /* ─── VOILES ET OMBRES ───────────────────────────────────────────────────
     ⚠️ LES VOILES SONT INVARIANTS : un voile assombrit ce qu'il y a DESSOUS,
     et ce qu'il y a dessous est une image ou une page, pas une surface du
     thème. Les trois `--fbx-overlay*` couvrent les cinq voiles du socle — un
     commentaire du socle disait déjà « la MÊME densité que `.fbx-modal-overlay` :
     deux voiles dans un même outil », sans qu'un jeton le tienne. */
  --fbx-shadow-rgb:      0, 0, 0;
  --fbx-overlay:         rgba(0, 0, 0, .5);    /* modale, connexion, célébration */
  --fbx-overlay-strong:  rgba(15, 18, 20, .85); /* visionneuse d'image */
  --fbx-overlay-thumb:   rgba(0, 0, 0, .6);    /* croix d'une vignette, posée sur l'image */

  /* Les trois élévations thémées. */
  --fbx-shadow-card:  0 1px 3px rgba(0, 0, 0, .06);
  --fbx-shadow-pop:   0 6px 24px rgba(20, 30, 40, .14);
  --fbx-shadow-modal: 0 20px 60px rgba(0, 0, 0, .2);

  /* ⚠️ LES SIX SUIVANTES NE SUIVENT PAS LE THÈME, ET C'EST UN REPORT, PAS UN
     CHOIX. Elles étaient écrites en littéral et la règle B0 oblige à les
     nommer ; mais rien ne permet de DÉRIVER leur version sombre — les trois
     ci-dessus passent de .06 à .40, de .14 à .55 et de .2 à .70, sans loi. Une
     élévation se règle à l'œil. Inscrites `INVARIANTS_THEME` avec le motif
     `différé`, et renvoyées au lot d'ombres que DS-2b §7.6 annonce. */
  --fbx-shadow-lightbox:    0 8px 40px rgba(0, 0, 0, .5);
  --fbx-shadow-knob:        0 1px 3px rgba(0, 0, 0, .2);
  --fbx-shadow-card-hover:  0 4px 12px rgba(0, 0, 0, .15);
  --fbx-shadow-sticky:      0 2px 6px rgba(0, 0, 0, .04);
  --fbx-shadow-celebration: 0 18px 48px rgba(0, 0, 0, .28);
  --fbx-shadow-embleme:     0 10px 26px rgba(0, 0, 0, .22);

  /* ─── COMPOSANTS ─────────────────────────────────────────────────────────
     ⚠️ DEUX APLATS NEUTRES QUI PORTENT DU BLANC, ET LES DEUX ÉTAIENT CASSÉS EN
     SOMBRE (relevé DS-2a). Le toast neutre et la croix d'un tag lisaient
     `--fbx-n9` et `--fbx-n7`, qui basculent : en sombre le toast affichait du
     blanc sur #E6E9EC (1,22:1) et la croix du blanc sur #9BA3AB (2,55). Ce sont
     des PLAQUES — invariantes, comme toutes les plaques du socle. */
  --fbx-toast-bg:  var(--tpx-grey-800);   /* blanc dessus : 11,84 */
  --fbx-tag-x-bg:  var(--tpx-grey-600);   /* blanc dessus :  4,93 */
  /* La bulle des entrées de la barre (2026-09-17) : la même plaque que le
     toast, sous son propre nom — un nom par rôle, même à valeur égale. */
  --fbx-bulle-bg:  var(--tpx-grey-800);   /* blanc dessus : 11,84 */

  /* ⚠️ LA PASTILLE DE REPLI DU RAIL EST À CHEVAL SUR DEUX PLANS, et c'est ce qui
     lui vaut quatre jetons à elle. Elle est posée mi-barre mi-page ; ses
     couleurs doivent être celles de la PAGE, alors qu'elle vit à l'intérieur de
     `.fbx-sidebar`, qui remappe les rôles neutres vers ceux de la barre. Un bloc
     scopé NE PEUT PAS référencer le rôle qu'il écrase — `--fbx-text:
     var(--fbx-text)` ne veut rien dire —, et référencer une primitive figerait
     le clair. D'où ces quatre-là, qui portent les valeurs des rôles de page et
     basculent avec le thème. */
  --fbx-rail-fg:        var(--tpx-grey-600);
  --fbx-rail-fg-strong: var(--tpx-grey-800);
  --fbx-rail-bg:        var(--tpx-grey-75);
  --fbx-rail-bd:        var(--tpx-grey-200);

  /* ⚠️ LA BARRE DE NAVIGATION EST UN PLAN À PART, IDENTIQUE DANS LES DEUX
     THÈMES (2026-08-21). En clair elle est un plan franc sur le canvas ; en
     sombre `--fbx-sidebar-bg` vaut exactement `--fbx-bg`, donc elle se fond dans
     le fond de page et ce sont les CARTES qui se détachent — le même rapport,
     obtenu sans seconde valeur à tenir. Depuis DS-2a, cette égalité n'est plus
     une coïncidence à surveiller : les six jetons LISENT la rampe sombre.
     ⚠️ NE JAMAIS LA REPASSER EN `transparent` : sous 720 px elle bascule en
     barre BASSE, posée SUR le contenu qui défile dessous — transparente, on
     lisait le board au travers de ses icônes (constaté à 375 px le 21/08).
     Contrastes sur #14181B : texte 14,65 · atténué 6,99 · accent 9,86. */
  --fbx-sidebar-bg:     var(--tpx-slate-950);
  --fbx-sidebar-fg:     var(--tpx-slate-100);
  --fbx-sidebar-mute:   var(--tpx-slate-300);
  --fbx-sidebar-hover:  var(--tpx-slate-800);
  --fbx-sidebar-border: var(--tpx-slate-700);
  /* ⚠️ `--fbx-accent-fg` (#0F6E96) tombe à 3,14 sur ce fond — le lien COURANT et
     ses icônes passeraient sous AA. Le bleu clair y tient à 9,86. */
  --fbx-sidebar-accent: var(--tpx-blue-300);

  /* ─── STATUTS — pastille / texte / fond ──────────────────────────────────
     ⚠️ TROIS CRÉNEAUX PAR STATUT, et non une couleur comme autrefois : une
     seule valeur ne peut pas servir les deux thèmes. Mesuré (WCAG 2.1) :
       ink #33383D    → 11,84 sur blanc  /  1,51 sur sombre
       active #F59E0B →  2,15 sur blanc  /  8,31 sur sombre
     L'une est inutilisable en sombre, l'autre en clair. D'où une PASTILLE
     (marqueur, point de chip), un TEXTE (libellé de badge) et un FOND teinté.

     ⚠️ CES SIX SÉRIES ÉTAIENT DÉCLARÉES DEUX FOIS — ici et dans
     `feedback-shared.css`, aux valeurs d'avant D1. La seconde était morte (la
     cascade donnait celle-ci) ; elle a été retirée par DS-2a.

     `active` : la pastille N'EST PAS la couleur du texte. L'ambre de charte
     #F59E0B ne tient ni l'un ni l'autre sur blanc (2,15) ; elle revient en mode
     sombre, où elle est excellente. */
  --st-active:              #D97706;   /* pastille — 3,19 */
  --st-active-fg:           #B45309;   /* texte    — 5,02 */
  --st-active-bg:           #FEF3C7;

  /* tocheck quitte #3B82F6 (3,68, sous AA) pour l'ultramarine : plus profond et
     plus saturé que le cyan de marque, dont il ne s'écarte que de 26° de teinte. */
  --st-tocheck:             #1D4ED8;   /* 6,70 */
  --st-tocheck-fg:          #1D4ED8;   /* 6,70 */
  --st-tocheck-bg:          #DBEAFE;

  /* Rouge et non l'orange #f97316 du widget : « renvoyé au correcteur » est un
     rejet, et l'orange le confondait avec `active` (38° d'écart contre 0°). */
  --st-needs-revision:      #DC2626;   /* 4,83 */
  --st-needs-revision-fg:   #B91C1C;   /* 6,47 */
  --st-needs-revision-bg:   #FEE2E2;

  /* pending / cancelled : séparés par la TEMPÉRATURE, pas par la nuance.
     Ardoise froide 215° contre taupe chaude 28° — 187° d'écart. */
  --st-pending:             #64748B;   /* 4,76 — froid, dense : vivant, en attente */
  --st-pending-fg:          #475569;   /* 7,58 */
  --st-pending-bg:          #F1F5F9;

  --st-resolved:            #16A34A;   /* 3,30 — PASTILLE : objet graphique, seuil 3 */
  /* ⚠️ #15803D (5,02 sur son fond de badge) tombait à 4,39 sur le fond du
     SÉLECTEUR de statut, plus pâle — mesuré le 2026-08-07, quand ce composant a
     cessé d'être coloré en ligne et s'est mis à lire ce jeton. Un cran plus
     foncé : 5,13 sur le sélecteur, et le badge y gagne aussi. Le contraste d'un
     rôle TEXTE se mesure contre CHACUN des fonds où il se pose. */
  --st-resolved-fg:         #166534;   /* 5,13 */
  --st-resolved-bg:         #DCFCE7;

  --st-cancelled:           #8A837D;   /* 3,73 — chaud, clair : clos, écarté */
  /* #78716C donnait 4,80 sur BLANC mais 4,40 sur son propre fond teinté — sous
     le seuil. Le contraste d'un badge se mesure contre SON fond, pas contre la
     page. Assombri d'un cran : 5,10. */
  --st-cancelled-fg:        #6E6761;   /* 5,10 sur --st-cancelled-bg */
  --st-cancelled-bg:        #F5F5F4;

  /* ⚠️ LA PLAQUE N'EST PAS LA PASTILLE, ET CETTE FOIS LE NOMBRE EST LE MÊME —
     seul le SEUIL change (2026-08-07). `--st-active` vaut #D97706, documenté
     « pastille — 3,19 » : exact, et suffisant, POUR UNE PASTILLE (objet
     graphique, seuil 3:1). Mais `.fbx-status-count` pose cette même couleur en
     FOND SOUS DU TEXTE BLANC, où le seuil est 4,5 — et le contraste étant
     symétrique, il affiche 3,19 dans les deux lectures. Rien dans la mesure ne
     distingue les deux rôles : seule la QUESTION posée les sépare. C'est le
     piège le plus discret de toute la série.
     ⚠️ ET ICI UN JETON DÉDIÉ ÉTAIT INÉVITABLE, contrairement à
     `--fbx-accent-fill` qui pouvait réemployer `--fbx-on-accent` : en thème
     sombre NI `--st-*` (la pastille, claire) NI `--st-*-fg` (le texte, clair lui
     aussi) ne portent du blanc. Il fallait une troisième valeur.
     IDENTIQUES DANS LES DEUX THÈMES : blanc dessus à 5,02 / 6,70 / 6,47 / 7,58 /
     5,02 / 5,56. Une pastille de comptage ne change pas d'aspect selon le
     thème ; c'est la page autour d'elle qui change. */
  --st-active-plate:         #B45309;
  --st-tocheck-plate:        #1D4ED8;
  --st-needs-revision-plate: #B91C1C;
  --st-pending-plate:        #475569;
  --st-resolved-plate:       #15803D;
  --st-cancelled-plate:      #6E6761;

  /* ─── CRÉNEAU MAIL — CE QUI EST SERVI ────────────────────────────────────
     Une valeur UNIQUE par statut, identique en clair et en sombre : dans un
     client mail on ne maîtrise pas le thème. Deux mécanismes coexistent et
     aucun ne se laisse piloter — Apple Mail et Outlook mac/iOS honorent
     `prefers-color-scheme` mais les couleurs de `tpxBadge` sont en attributs
     `style=` INLINE, qu'une media query ne peut pas atteindre ; Outlook
     Windows/web et Gmail en auto-dark FORCENT l'inversion.

     ⚠️ CES SIX VALEURS SONT CELLES DE `TPX_STATUS` (src/services/mail.js), AU
     CARACTÈRE PRÈS. Elles ne sont pas un objectif : elles sont ce qui part.
     `test/statuts-sources-couleurs.test.js` échoue si l'une des deux bouge sans
     l'autre.
     ⚠️ LEUR CONTRASTE EST MAUVAIS, ET C'EST LE FAIT À CONNAÎTRE : mesuré sur le
     rendu réel, `active` tient 1,99 en clair, `resolved` 2,96 — aucun des six ne
     passe AA des deux côtés. La vitrine l'affiche tel quel. Une proposition
     chiffrée existe (`doc/notes/2026-08-01-proposition-pilule-mail.md`) ; elle
     demande un changement de mécanique dans `tpxBadge` et n'a pas été exécutée. */
  --st-active-mail:         #f59e0b;
  --st-tocheck-mail:        #2563eb;
  --st-needs-revision-mail: #dc2626;
  --st-pending-mail:        #6b7280;
  --st-resolved-mail:       #16a34a;
  --st-cancelled-mail:      #78716c;
}


/* ═══════════════════════════════════════════════════════════════════════════
   COUCHE 2 — LES RÔLES, MODE SOMBRE

   L'architecture des TEINTES est identique au mode clair — seules la clarté et
   la saturation bougent, pour qu'un statut reste reconnaissable d'un thème à
   l'autre.

   ⚠️ NE FIGURENT ICI QUE LES RÔLES QUI BASCULENT. Un rôle absent de ce bloc est
   soit un alias qui bascule tout seul (`--fbx-row-hover` suit
   `--fbx-accent-bg`), soit un INVARIANT DE THÈME assumé — plaques, voiles,
   `on-*`, `--st-*-plate`, `--st-*-mail`, la barre de navigation, les six
   élévations différées. La règle T de `tools/ds-check.mjs` exige que chacun de
   ces invariants soit inscrit avec sa raison : *un jeton figé doit être une
   décision, jamais un oubli*.
   ═══════════════════════════════════════════════════════════════════════════ */
:root[data-scheme="dark"],
[data-palette="p37"][data-scheme="dark"] {

  /* ⚠️ LE SOMBRE N'EST PAS L'INVERSE DU CLAIR, et le fond de page le montre : le
     canvas doit passer SOUS la surface, alors qu'il passe au-dessus en clair.
     C'est la même intention — « la page est en retrait, la carte est posée
     dessus » — et elle demande deux gestes opposés. */
  --fbx-bg:              var(--tpx-slate-950);
  --fbx-surface:         var(--tpx-slate-900);
  --fbx-surface-sunken:  var(--tpx-slate-950);
  --fbx-fill:            var(--tpx-slate-800);
  --fbx-fill-strong:     var(--tpx-slate-700);
  /* ⚠️ En SOMBRE, la surface en relief sert déjà à l'en-tête : le zébrage prend
     un ton à part, sinon une ligne paire se lirait comme un en-tête. #21272C se
     glisse entre la surface (#1C2126) et l'en-tête (#262C32) — visible sans peser. */
  --fbx-row-alt:         var(--tpx-slate-850);
  /* En sombre, l'en-tête se DÉTACHE par le haut, l'inverse du mode clair où il
     s'efface. C'est la même intention : un en-tête n'est pas une ligne de données. */
  --fbx-thead-bg:        var(--tpx-slate-800);
  --fbx-border:          var(--tpx-slate-700);
  --fbx-border-list:     var(--tpx-slate-800);
  --fbx-border-strong:   var(--tpx-slate-600);
  --fbx-faint:           var(--tpx-slate-500);
  --fbx-text:            var(--tpx-slate-100);   /* 13,31 sur la surface */
  --fbx-text-soft:       var(--tpx-slate-200);   /*  9,61 */
  --fbx-text-muted:      var(--tpx-slate-300);   /*  6,35 */

  /* Accent : la marque tient telle quelle (6,59) ; l'accent-TEXTE s'éclaircit
     pendant que la plaque reste saturée. */
  --fbx-accent-fg:       var(--tpx-blue-300);
  --fbx-accent-bg:       rgba(43, 168, 221, .16);
  --fbx-focus:           rgba(124, 203, 235, .40);

  /* États — les fonds PÂLES du mode clair (#FEF3C7, #FEF2F2…) sont illisibles
     sur du sombre : ils y deviennent des aplats vifs. On passe à des fonds
     TRANSLUCIDES posés sur la surface, et à des textes CLAIRS — les mêmes
     valeurs que les statuts, dont le contraste est déjà calculé.
     ⚠️ LES QUATRE TEINTES NE SONT PAS ICI : ce sont des plaques, invariantes. */
  --fbx-warn-fg:      #FBBF24;
  --fbx-warn-bg:      rgba(var(--fbx-warn-rgb), .16);
  --fbx-warn-bg-soft: rgba(var(--fbx-warn-rgb), .10);
  --fbx-warn-bd:      rgba(var(--fbx-warn-rgb), .35);

  --fbx-danger-fg:    #F87171;   /* 5,86 sur la surface, contre 3,36 pour la plaque */
  --fbx-danger-bg:    rgba(var(--fbx-danger-rgb), .18);
  --fbx-danger-bd:    rgba(var(--fbx-danger-rgb), .38);

  --fbx-ok-fg:        #4ADE80;
  --fbx-ok-bg:        rgba(var(--fbx-ok-rgb), .18);
  --fbx-ok-hover:     #22C55E;

  --fbx-info-fg:      #7DA2FF;
  /* ⚠️ PAS `rgba(var(--fbx-info-rgb), …)`, ET C'EST UN ÉCART QU'ON CONSTATE SANS
     LE CORRIGER : ce voile est bâti sur l'INDIGO #1D4ED8 (celui de `tocheck`),
     alors que la teinte `--fbx-info` est le bleu #3B82F6. Toute la famille est
     dans ce cas — `--fbx-info-bg` clair vaut #E0E7FF et `--fbx-info-fg` #3730A3,
     deux indigos, pour une teinte qui n'en est pas un. Brancher le compagnon
     aurait changé le fond des badges de rôle en sombre ; DS-2a ne change pas une
     valeur qu'il n'a pas décidé de changer. La divergence est reportée. */
  --fbx-info-bg:      rgba( 29,  78, 216, .28);

  /* Les ombres portées ne se voient pas sur du sombre : une carte s'y détache
     par sa SURFACE plus claire, pas par son ombre. On les réduit au lieu de les
     supprimer — elles gardent un rôle de profondeur sur les popovers.
     ⚠️ `--fbx-shadow-pop` BASCULE, ET `.fbx-dd-pop` LE LIT DEPUIS DS-2a : le
     panneau déroulant portait l'ombre du clair en sombre, faute d'être branché.
     C'est la migration que DS-2b avait différée (`MIGRATIONS_DIFFEREES`). */
  --fbx-shadow-card:  0 1px 3px rgba(0, 0, 0, .40);
  --fbx-shadow-pop:   0 6px 24px rgba(0, 0, 0, .55);
  --fbx-shadow-modal: 0 20px 60px rgba(0, 0, 0, .70);

  /* La pastille de repli reprend les neutres de la PAGE — donc du thème. */
  --fbx-rail-fg:        var(--tpx-slate-300);
  --fbx-rail-fg-strong: var(--tpx-slate-100);
  --fbx-rail-bg:        var(--tpx-slate-800);
  --fbx-rail-bd:        var(--tpx-slate-700);

  --st-active:            #FBBF24;  --st-active-fg:            #FBBF24;  /* 10,69 */
  --st-tocheck:           #7DA2FF;  --st-tocheck-fg:           #7DA2FF;  /*  7,21 */
  --st-needs-revision:    #F87171;  --st-needs-revision-fg:    #F87171;  /*  6,45 */
  --st-pending:           #94A3B8;  --st-pending-fg:           #94A3B8;  /*  6,96 */
  --st-resolved:          #4ADE80;  --st-resolved-fg:          #4ADE80;  /* 10,25 */
  --st-cancelled:         #B5AEA8;  --st-cancelled-fg:         #B5AEA8;  /*  8,15 */

  --st-active-bg:         rgba(245, 158,  11, .16);
  --st-tocheck-bg:        rgba( 29,  78, 216, .24);
  --st-needs-revision-bg: rgba(220,  38,  38, .20);
  --st-pending-bg:        rgba(100, 116, 139, .20);
  --st-resolved-bg:       rgba( 22, 163,  74, .18);
  --st-cancelled-bg:      rgba(120, 113, 108, .18);
}
