/**
 * LES JETONS SANS COULEUR DU SOCLE — échelles et plans.
 *
 * Partagés par /feedbacks (admin) et /review (contributeur), ils étaient
 * dupliqués à l’identique dans le `:root` de chaque page.
 *
 * ⚠️ CE FICHIER NE PORTE PLUS AUCUNE COULEUR (DS-2a, 2026-08-27). Il en portait
 * dix-huit : les quatre `--fbx-primary*`, les quatre couleurs d’état, les six
 * `--st-*` et les six `--st-*-plate`. **Les six `--st-*` étaient MORTES** —
 * `feedback-palette.css`, chargée après, les redéclarait aux valeurs de D1, et
 * c’est celle-là que la cascade servait ; celles d’ici dataient d’avant. Deux
 * déclarations d’un même jeton dans deux feuilles ne se voient pas à la
 * relecture : elles se voient à l’écran, ou jamais.
 *
 * **Toutes les couleurs du socle vivent désormais dans `widget/feedback-palette.css`**,
 * en deux couches — primitives `--tpx-*`, rôles `--fbx-*` et `--st-*` — et dans
 * les deux thèmes. La règle B0 de `tools/ds-check.mjs` échoue sur toute couleur
 * littérale écrite ici, et la règle T sur tout rôle de couleur qui ne dirait pas
 * ce qu’il vaut en sombre.
 *
 * Ce qui reste ici : le rythme, la typographie, les rayons et les plans — les
 * échelles de DS-2b, qui ne dépendent d’aucun thème.
 */
:root {
  /* PANNEAU DE MENU — au-dela de quoi il cesse de suivre son contenu. Il prend
     `max-content` pour que sa ligne la plus longue fixe la largeur ; sans
     plafond, un libelle tres long le ferait sortir de l'ecran. */
  --fbx-dd-pop-max-w: 90vw;
  /* ═══ ÉCHELLE D'ESPACEMENT (DS-2b, 2026-08-27) ═══════════════════════════
     Base 2 sous 16 px, multiples de 4 au-dessus — la grille de
     `feedback-vars.css` (widget), reprise ici parce qu'une convention déjà en
     service se relit sans table de correspondance. NOMMÉS PAR LEUR VALEUR :
     `--fbx-space-16` se lit, `--fbx-space-md` se cherche.
     ⚠️ TREIZE CRANS, ET LE SEUIL EST DE TROIS EMPLOIS AU SOCLE. `1px`
     (2 emplois), `40px` (1) et `80px` (1) sont sur la grille et n'y sont PAS :
     un jeton déclaré pour un seul emploi est un jeton qu'on cherchera ailleurs
     sans le trouver. Ils restent littéraux, et la règle S les compte.
     ⚠️ CE SEUIL NE VAUT QUE POUR LES GAMMES NOMMÉES PAR LEUR VALEUR — celle-ci
     et les rayons. Les gammes nommées par leur RÔLE (tailles, graisses,
     interlignes) ne le subissent pas : un trou au milieu d'une gamme nommée
     coûte plus qu'un cran rare, parce qu'il ne se lit pas.
     ⚠️ NI ZÉRO NI NÉGATIF. `0` s'écrit `0` ; un décalage négatif n'est pas un
     cran de rythme mais un recalage — il reste littéral, ET IL EST COMPTÉ.
     Un recalage qui ne compte pas disparaît de la vue, et c'est justement ce
     qu'un lot de normalisation doit voir pour trancher. */
  --fbx-space-2:   2px;
  --fbx-space-3:   3px;
  --fbx-space-4:   4px;
  --fbx-space-6:   6px;
  --fbx-space-8:   8px;
  --fbx-space-10: 10px;
  --fbx-space-12: 12px;
  --fbx-space-14: 14px;
  --fbx-space-16: 16px;
  --fbx-space-20: 20px;

  /* LA MESURE D'UNE COLONNE DE SAISIE — un jeton de DIMENSION, nomme par son
     role, pas un cran d'echelle (cf. la regle du bareme).
     760px ≈ 90 caracteres : au-dela, un champ de texte devient penible a
     relire, et un formulaire etale sur 1400px n'a plus d'axe.
     ⚠️ IL ETAIT ECRIT DEUX FOIS EN LITTERAL le 2026-08-28 — dans
     `.fbx-card--form` et dans la grille de page qui devait s'aligner dessus.
     Deux mesures de la meme chose finissent par diverger. */
  --fbx-form-w: 760px;
  --fbx-space-24: 24px;
  --fbx-space-28: 28px;
  --fbx-space-32: 32px;

  /* ═══ ÉCHELLE TYPOGRAPHIQUE (DS-2b) ══════════════════════════════════════
     Sept tailles. Les six premières sont celles du widget, AUX MÊMES VALEURS ;
     `xl` est la dérogation — le socle a des titres, un widget n'en a pas.
     ⚠️ LE SOCLE N'A PAS DE 9 px : `--fbx-font-3xs` n'existe donc pas.
     ⚠️ LES TAILLES DE TITRE (19 à 32 px : six valeurs pour huit emplois) ET LES
     CINQ DEMI-PIXELS (`10.5` `11.5` `12.5` `13.5` `15`, quinze emplois) NE SONT
     PAS AU BARÈME, ET C'EST VOLONTAIRE : une échelle qui reprend chaque littéral
     n'est pas une échelle, et un demi-pixel est la trace d'un réglage fait à
     l'œil — il se solde à l'œil, avec un navigateur. */
  --fbx-font-2xs:  10px;
  --fbx-font-xs:   11px;
  --fbx-font-sm:   12px;
  --fbx-font-base: 13px;
  --fbx-font-md:   14px;
  --fbx-font-lg:   16px;
  --fbx-font-xl:   18px;

  /* Graisses — quatre valeurs relevées, quatre crans : couverture ENTIÈRE, la
     seule famille du relevé dans ce cas. `bold` est la dérogation : le widget
     s'arrête à `semibold`. */
  --fbx-weight-normal:   400;
  --fbx-weight-medium:   500;
  --fbx-weight-semibold: 600;
  --fbx-weight-bold:     700;

  /* Interlignes — SANS UNITÉ (un interligne se multiplie par sa taille).
     ⚠️ CETTE ÉCHELLE NE COUVRE QUE 14 DES 27 INTERLIGNES DU SOCLE, et le dire
     vaut mieux que la gonfler : onze valeurs se pressent entre 1 et 1,6 sans
     qu'aucune domine, ce qui signifie qu'il n'y a pas une échelle mais onze
     décisions ponctuelles. Le reste est de la dette, à regarder à l'écran.
     ⚠️ `tight` VAUT 1.3 ICI ET 1.25 DANS LE WIDGET : les valeurs du socle sont
     celles du socle — ce sont deux univers (règles P et Q). */
  --fbx-leading-none:   1;
  --fbx-leading-tight:  1.3;
  --fbx-leading-snug:   1.4;
  --fbx-leading-normal: 1.5;

  /* ═══ RAYONS — trois crans NEUFS (DS-2b) ═════════════════════════════════
     L'échelle nommée existait déjà et vit dans `feedback-admin.css`
     (`--fbx-radius-sm` 6px, `--fbx-radius` 8px, `-lg` 10px, `-xl` 16px). Ces
     trois-là lui manquaient, et ils sont ce que le socle emploie le plus.
     ⚠️ PAS DE CRAN POUR `7px` NI `12px`, bien qu'ils atteignent trois emplois :
     l'échelle `xs / sm / — / lg / xl` est nommée et lisible, y insérer deux
     valeurs intercalaires obligerait à la renommer entière pour six emplois. */
  --fbx-radius-xs:   4px;    /* le widget nomme 4px `sm`, mais `sm` vaut déjà
                                6px ici : le nom suit l'échelle du socle */
  --fbx-radius-full: 50%;    /* 28 emplois — de loin le rayon le plus employé */
  --fbx-radius-pill: 999px;  /* 999, la valeur EN SERVICE : le widget écrit 9999,
                                mais au-delà du demi-côté le rendu est le même et
                                l'on migre à sortie constante */

  /* ═══ PLANS (DS-2b) ══════════════════════════════════════════════════════
     NEUF couches pour SEPT valeurs, et c'est délibéré : UN NOM PAR RÔLE, MÊME À
     VALEUR ÉGALE. `--fbx-z-modal` et `--fbx-z-toast` valent 2000 aujourd'hui,
     `--fbx-z-dropdown` et `--fbx-z-lightbox` valent 9999 aujourd'hui — les
     fondre sous un nom unique cacherait exactement la question qu'un lot avec
     navigateur doit poser : un toast doit-il passer devant une modale ? une
     visionneuse devant une liste déroulante ? Deux rôles sous un seul nom
     rendent la question inposable.
     ⚠️ `login` ET NON `overlay` : « overlay » désignerait aussi bien le fond de
     modale, qui est un AUTRE plan.
     ⚠️ LES QUATRE PETITS CRANS DU SOCLE (1, 1, 1 et 2) NE SONT PAS DES PLANS :
     un glyphe posé sur son champ et le bouton de repli du rail vivent dans leur
     propre contexte d'empilement et ne se comparent à rien. Ils restent
     littéraux — c'est le cliquet O qui les tient, pas un jeton. */
  --fbx-z-sticky:        30;   /* bandeau collant des boards */
  --fbx-z-flottant:      35;   /* bouton flottant et barre de lot du téléphone, sous la navigation */
  --fbx-z-sidebar:       40;   /* barre de navigation fixe */
  --fbx-z-bulle:         50;   /* bulle d'une entrée de la barre — devant elle, sous tout voile */
  --fbx-z-login:       1000;   /* voile de connexion */
  --fbx-z-modal:       2000;   /* fond de modale */
  --fbx-z-toast:       2000;   /* même valeur AUJOURD'HUI, autre rôle */
  --fbx-z-celebration: 2500;
  --fbx-z-dropdown:    9999;   /* liste déroulante — devant une modale qui la contient */
  --fbx-z-lightbox:    9999;   /* visionneuse d'image ; même valeur, autre rôle */

  /* LE CHEVRON DU BOUTON DE DROPDOWN (2026-09-20). Trois dimensions nommées par
     leur rôle, parce qu'elles sont lues à DEUX endroits — la boîte du
     pseudo-élément et la taille du masque qui la remplit — et que les voir
     diverger donnerait un tracé étiré sans que rien ne le signale.
     10 x 6 est le tracé d'origine ; la marge droite le pose dans le rembourrage
     que `.fbx-select` réserve à droite. */
  /* LA LARGEUR D'UN MENU DÉROULANT, posée par `enhanceSelect` sur chaque bouton
     (celle de son option la plus longue). En propriété et non en `min-width` en
     ligne (2026-09-25) : le bandeau des boards au téléphone doit la relâcher. */
  --fbx-dd-min: auto;
  --fbx-dd-chevron-w: 10px;
  --fbx-dd-chevron-h: 6px;
  --fbx-dd-chevron-marge: 11px;
  /* LE TRACÉ DU CHEVRON, en un seul endroit (2026-10-02) : le menu déroulant et
     le bloc repliable (`.fbx-repli`) le posent en MASQUE, coloré par
     `background-color` — la seule façon qu'une data-URI suive le thème. */
  --fbx-chevron-masque: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ═══════════════════════════════════════════════════════════════════════════
   Contrôles de formulaire — select + checkbox custom, partagés par les boards.
   Les select/checkbox natifs (chevron collé, case système) juraient avec le
   reste de l'UI. Réutilisables sur toutes les pages qui chargent ce fichier.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Select : chevron SVG espacé (data URI, aucune ressource externe). Utiliser
   background-COLOR (pas le raccourci background) pour ne pas écraser l'image.

   ⚠️ CETTE IMAGE NE SERT PLUS QU'AU `<select>` NATIF (2026-09-20, retour
   9e74aed3) : un élément remplacé ne porte aucun pseudo-élément, c'est pourquoi
   son chevron est peint ici. Le bouton du dropdown, lui, la neutralise et pose
   un masque qui suit le thème — voir `.fbx-dd::after`. Le natif ne paraît que
   si `enhanceAll` n'a pas tourné.
   ⚠️ SA COULEUR RESTE FIGÉE, ET C'EST LE SEUL ENDROIT DU SOCLE OÙ CELA VAUT :
   elle valait `#6b7280`, qui n'était même pas dans la palette — elle prend la
   valeur du gris muted en thème clair (`--tpx-grey-600`, #6B7178), le seul
   thème où ce repli se lise correctement. */
.fbx-select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  font: inherit; font-size: var(--fbx-font-base); color: var(--fbx-text); line-height: var(--fbx-leading-tight); cursor: pointer;
  padding: 7px var(--fbx-space-32) 7px var(--fbx-space-12);
  border: 1px solid var(--fbx-border); border-radius: var(--fbx-radius); background-color: var(--fbx-surface);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%236B7178' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 11px center; background-size: 10px 6px;
  transition: border-color .15s, box-shadow .15s;
}
.fbx-select:hover { border-color: var(--fbx-border-strong); }
.fbx-select:focus { outline: none; border-color: var(--fbx-accent-fg); box-shadow: 0 0 0 3px rgba(var(--fbx-accent-rgb), .12); }

/* Checkbox : case dessinée + coche, accent marque. Élément natif → global.
   Carrée, border-radius discret ; coche centrée via translate (pas de calage
   absolu fragile). */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px; margin: 0; flex-shrink: 0; vertical-align: middle;
  border: 1.5px solid var(--fbx-border-strong); border-radius: 3px; background-color: var(--fbx-surface);
  cursor: pointer; transition: background-color .15s, border-color .15s;
}
input[type="checkbox"]:hover { border-color: var(--fbx-accent-fg); }
/* Coche SVG (même tracé que le dropdown) centrée en background — nette, alignée.
   ⚠️ Le fond et le filet prennent la PLAQUE (`--fbx-accent-fill`), pas
   l'accent-texte : la coche du data-URI ci-dessous est BLANCHE, et du blanc sur
   l'accent-texte du thème sombre (#7CCBEB) tombe à 1,81:1 — une case cochée ne
   se distinguerait plus d'une case vide. */
input[type="checkbox"]:checked {
  background-color: var(--fbx-accent-fill); border-color: var(--fbx-accent-fill);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 6.3L5 8.8L9.5 3.5' stroke='%23fff' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center; background-size: 11px 11px;
}
input[type="checkbox"]:focus-visible { outline: 2px solid rgba(var(--fbx-accent-rgb), .45); outline-offset: 1px; }

/* Dropdown maison (TPXShared.enhanceAll) — la liste native n'est pas stylable
   (surbrillance OS). Progressive enhancement : le <select.fbx-select> reste en
   DOM (état + événements change), masqué ; un bouton le pilote et ouvre une
   liste stylée. Le bouton hérite du look .fbx-select (mêmes classes). */
/* LE CHEVRON DU BOUTON SUIT LE THÈME (2026-09-20, retour 9e74aed3).

   ⚠️ IL ÉTAIT FIGÉ À `#6b7280` DANS UNE DATA-URI, donc **opaque au CSS** :
   aucune `var()` ne la traverse, et c'est pour cela qu'il a survécu au thème
   sombre du 2026-08-07 sans que rien ne le signale — un gris de thème clair
   posé sur une surface sombre. Troisième occurrence du même piège, après la
   coche du dropdown (violette dans les deux thèmes) et le chevron par statut.
   *Le tracé n'était même pas dans la palette* : `--tpx-grey-600` vaut #6B7178.

   REMÈDE, ET L'IDIOME EST CELUI DE `.fbx-dd-check` VINGT LIGNES PLUS BAS : un
   MASQUE coloré par `background-color` — le tracé ne sert plus que de pochoir,
   il passe donc en noir. La teinte devient `--fbx-text-muted`, qui bascule
   (4,93:1 en clair, 6,35:1 en sombre).

   ⚠️ SUR LE BOUTON, PAS SUR LE `<select>` : un élément remplacé ne porte aucun
   pseudo-élément — c'est la raison d'être de l'image de fond, qui reste pour le
   `<select>` natif. Elle est donc NEUTRALISÉE ici, sans quoi les deux chevrons
   se superposeraient. Le natif ne paraît que si `enhanceAll` n'a pas tourné :
   son chevron figé y reste lisible en thème clair, et ce repli est le seul
   endroit du socle où la couleur d'une data-URI ne suit pas le thème.
   ⚠️ `pointer-events: none` : le chevron est un décor posé SUR un bouton —
   sans lui, cliquer dessus viserait le pseudo-élément et non le bouton. */
.fbx-dd { text-align: left; position: relative; background-image: none; min-width: var(--fbx-dd-min, auto); }
.fbx-dd::after {
  content: ''; position: absolute; right: var(--fbx-dd-chevron-marge); top: 50%; transform: translateY(-50%);
  width: var(--fbx-dd-chevron-w); height: var(--fbx-dd-chevron-h); pointer-events: none;
  background-color: var(--fbx-text-muted);
  -webkit-mask: var(--fbx-chevron-masque) no-repeat center / var(--fbx-dd-chevron-w) var(--fbx-dd-chevron-h);
          mask: var(--fbx-chevron-masque) no-repeat center / var(--fbx-dd-chevron-w) var(--fbx-dd-chevron-h);
}
.fbx-dd .fbx-dd-label { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* UN BOUTON QUI PORTE UN BADGE PASSE EN FLEX (2026-08-29). Sans cette regle, le
   libelle est en `display: block` — il prend donc TOUTE la largeur, et le badge
   tombe A LA LIGNE sous lui. Le bouton n'etait pas flex parce qu'il n'avait
   jamais eu qu'un enfant visible : son chevron est une image de fond.
   ⚠️ CONDITIONNE PAR `:has`, jamais impose a tous les selects : les passer en
   flex changerait le calcul de largeur de chacun d'eux pour un besoin qui
   n'appartient qu'a celui-ci.
   ⚠️ `min-width: 0` SUR LE LIBELLE : un flex item ne descend pas sous sa taille
   de contenu par defaut, et l'ellipsis ne se declencherait jamais. */
.fbx-dd:has(> .fbx-dd-badge:not(:empty)) {
  display: inline-flex; align-items: center; gap: var(--fbx-space-8);
}
.fbx-dd:has(> .fbx-dd-badge:not(:empty)) .fbx-dd-label { min-width: 0; }
/* ⚠️ ET POUSSE A DROITE, comme le chevron : le badge suivait le libelle, donc
   il se deplacait avec la longueur du nom. Colle a droite, il occupe la meme
   piste que la coche des options — c'est ce qui fait qu'on le trouve sans le
   chercher. */
.fbx-dd > .fbx-dd-badge:not(:empty) { margin-left: auto; }
.fbx-dd[aria-expanded="true"] { border-color: var(--fbx-accent-fg); box-shadow: 0 0 0 3px rgba(var(--fbx-accent-rgb), .12); }
/* Natif masqué en display:none : .value/selectedIndex et l'événement change
   fonctionnent toujours ; l'accessibilité est portée par le bouton (listbox).
   !important pour battre un width:100% de page (ex. .fb-status-select) qui, en
   position:absolute, déborderait la page. */
.fbx-dd-native-hidden { display: none !important; }
/* ⚠️ LE PANNEAU S'ELARGIT A SON CONTENU (2026-08-29) : `min-width` est cale sur
   le bouton par `ddOpen`, mais un libelle plus long que lui — un nom de recette
   — debordait, et le badge n'avait plus de place a reclamer. `max-content`
   laisse la ligne la plus longue fixer la largeur ; les autres options ont alors
   toutes du mou, et leurs capsules tombent a la MEME abscisse. */
.fbx-dd-pop { width: max-content; max-width: var(--fbx-dd-pop-max-w); }
.fbx-dd-pop {
  position: fixed; z-index: var(--fbx-z-dropdown); min-width: 150px; max-height: 300px; overflow-y: auto;
  background: var(--fbx-surface); border: 1px solid var(--fbx-border); border-radius: var(--fbx-radius-lg);
  /* ⚠️ CE LITTÉRAL N'EST PAS MIGRÉ, ET SON ÉGALITÉ AVEC `--fbx-shadow-pop` EST
     UNE COÏNCIDENCE DU THÈME CLAIR (DS-2b, 2026-08-27). Les trois jetons
     d'ombre sont REDÉFINIS EN SOMBRE (`.06` → `.40`, `.14` → `.55`, `.2` →
     `.70`) : brancher celui-ci ferait passer l'ombre du dropdown de
     `rgba(20, 30, 40, .14)` à `rgba(0, 0, 0, .55)` en thème sombre. Le rendu
     changerait — donc pas ici, DS-2b migrant à SORTIE CONSTANTE.
     Que le panneau doive suivre le thème comme la modale et la carte est très
     probablement vrai ; ça ne se décide pas au `sed`, ça se regarde. Inscrit
     dans `MIGRATIONS_DIFFEREES` (`tools/ds-check.mjs`) pour que la règle S0
     l'admette SANS être desserrée pour tout le monde. */
  box-shadow: var(--fbx-shadow-pop); padding: 5px; font: inherit; color: var(--fbx-text);
}
.fbx-dd-opt {
  display: flex; align-items: center; gap: var(--fbx-space-8); padding: var(--fbx-space-8) var(--fbx-space-10); border-radius: 7px;
  font-size: var(--fbx-font-base); line-height: var(--fbx-leading-tight); color: var(--fbx-text); cursor: pointer; white-space: nowrap;
}
.fbx-dd-opt:hover, .fbx-dd-opt.active { background: var(--fbx-fill); }
/* ⚠️ LE MENU D'ACTIONS D'UNE LIGNE PARLE PLUS BAS QUE LA COMBOBOX (2026-08-31).
   Il prolonge une barre d'icones de 14 px : a la taille de base, ses trois
   libelles pesaient plus lourd que les quatre actions qu'ils completent, alors
   qu'ils portent les gestes les PLUS RARES de la ligne. La combobox, elle, garde
   sa taille — on y lit une liste, on n'y prolonge pas des icones.
   ⚠️ CIBLE PAR `[role="menu"]` ET NON PAR UNE CLASSE : l'attribut dit ce que le
   panneau EST, et une classe de plus au socle demanderait une figure a la
   vitrine pour une nuance de taille. */
.fbx-dd-pop[role="menu"] .fbx-dd-opt {
  font-size: var(--fbx-font-sm); padding: var(--fbx-space-6) var(--fbx-space-10);
}
/* Une entree peut etre un <button> (menu de compte) : sans cette remise a plat,
   le style natif du navigateur ressort — filet gris, fond, texte centre — et
   trois entrees de menu ressemblent a trois boutons empiles. */
button.fbx-dd-opt {
  width: 100%; border: 0; background: none; font: inherit; text-align: left;
  color: inherit; -webkit-appearance: none; appearance: none;
}
.fbx-dd-opt[aria-selected="true"] { font-weight: var(--fbx-weight-semibold); }
.fbx-dd-dot { width: 8px; height: 8px; border-radius: var(--fbx-radius-full); flex-shrink: 0; }
/* LE BADGE D'ETAT D'UNE OPTION (2026-08-29) — une <option data-badge="Actif"
   data-badge-statut="actif"> montre son etat DANS le controle, ferme comme
   ouvert. Voisin de `.fbx-dd-dot` : celle-ci REPERE une valeur par une couleur,
   celui-la la NOMME. Deux besoins, deux composants.
   ⚠️ IL POUSSE A DROITE DANS L'OPTION et suit le libelle sur le bouton : dans
   le panneau les etats s'alignent en colonne, donc se comparent d'un coup d'oeil ;
   sur le bouton il n'y a qu'une valeur, rien a aligner.
   ⚠️ AUCUNE COULEUR ICI : la capsule est `.fbx-livr-statut`, qui vit dans
   `feedback-admin.css` avec les autres etats. Une seconde source de couleur,
   c'est la divergence garantie. */
.fbx-dd-badge:empty { display: none; }
.fbx-dd-badge { display: inline-flex; align-items: center; flex-shrink: 0; }
.fbx-dd-opt > .fbx-dd-badge { margin-left: auto; }
/* ⚠️ UN SEUL ELEMENT RECLAME L'ESPACE LIBRE (2026-08-29). `.fbx-dd-check` porte
   elle aussi `margin-left: auto` — c'est ce qui la colle a droite dans un menu
   ordinaire. Les deux ensemble, l'espace se PARTAGE EN DEUX : mesure, le badge
   recevait 52 px de marge sur une option courte et 2,7 px sur une longue, d'ou
   trois abscisses pour trois capsules. Des qu'un badge est la, c'est LUI qui
   pousse, et la coche le suit a distance fixe. */
.fbx-dd-opt > .fbx-dd-badge ~ .fbx-dd-check { margin-left: 0; }
/* ⚠️ MEME LARGEUR POUR TOUS LES ETATS, sinon les capsules empilees forment un
   escalier : « Actif » et « Fermé » sont plus courts qu'« À venir », et leur
   bord gauche tombait a trois abscisses differentes. */
.fbx-dd-badge > .fbx-livr-statut { min-width: var(--fbx-etat-w); }
/* ⚠️ LA COCHE RESTE EN PLACE, MASQUEE : `visibility` et non `display`, sinon la
   colonne disparait et le badge se redecale — ce qu'on vient de corriger. */
.fbx-dd-opt[aria-selected="false"] > .fbx-dd-check { visibility: hidden; }
/* Coche de l'option choisie = MEME trace SVG que la checkbox, en couleur marque.
   ⚠️ ELLE ETAIT VIOLETTE (#7c3aed FIGE dans la data-URI), donc fausse DANS LES
   DEUX THEMES depuis que la palette p37 est acceptee (2026-08-03) : le commentaire
   annoncait « couleur marque » et le fichier disait autre chose. Une data-URI est
   OPAQUE au CSS — aucune `var()` ne la traverse ; c'est pour cela qu'elle a survecu
   au remappage des jetons. Le remede est un MASQUE, colore par
   `background-color` — le trace ne sert plus que de pochoir.
   (Cet idiome venait de `.fbx-status-select.fbx-dd::after`, un chevron colore
   par statut, retire le 2026-08-21 avec le fond teinte de ce menu : sans aplat,
   un chevron gris ne paraissait plus sale. La methode, elle, reste bonne.)
   Le trace passe en noir puisqu'il ne sert plus que de pochoir.
   Contrastes : 5,69:1 en clair (#0F6E96 sur blanc), 8,96:1 en sombre (#7CCBEB sur
   la surface) — ici c'est bien l'accent-TEXTE qu'il faut, la coche est un trace
   POSE SUR la surface, pas une plaque. */
.fbx-dd-check {
  margin-left: auto; width: 14px; height: 14px; flex-shrink: 0;
  background-color: var(--fbx-accent-fg);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 6.3L5 8.8L9.5 3.5' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / 12px 12px;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 6.3L5 8.8L9.5 3.5' stroke='%23000' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center / 12px 12px;
}

/* Éditeur de commentaire riche (TPXShared.mountCommentEditor) */
.fbx-editor { border: 1px solid var(--fbx-border); border-radius: var(--fbx-radius); overflow: hidden; background: var(--fbx-surface); }
.fbx-editor:focus-within { border-color: var(--fbx-accent-fg); box-shadow: 0 0 0 3px rgba(var(--fbx-accent-rgb), .1); }
.fbx-editor-toolbar { display: flex; align-items: center; gap: var(--fbx-space-2); padding: 5px var(--fbx-space-6); border-bottom: 1px solid var(--fbx-border-list); background: var(--fbx-surface-sunken); }
.fbx-ed-btn { border: none; background: transparent; min-width: 26px; height: 26px; padding: 0 5px; border-radius: var(--fbx-radius-sm); cursor: pointer; font-size: var(--fbx-font-base); color: var(--fbx-text-soft); display: inline-flex; align-items: center; justify-content: center; }
.fbx-ed-btn:hover { background: var(--fbx-fill); color: var(--fbx-text); }
/* ⚠️ `--fbx-border` et non un remplissage : c'est un FILET, simplement dessiné
   par un fond faute d'avoir une boîte à border. La règle qui range les fonds du
   côté des remplissages ne vaut pas ici — un séparateur de barre d'outils doit
   porter le même gris que les filets voisins. */
.fbx-ed-sep { width: 1px; height: 16px; background: var(--fbx-border); margin: 0 var(--fbx-space-4); }
.fbx-editor-area { min-height: 62px; max-height: 240px; overflow-y: auto; padding: 9px 11px; font: inherit; font-size: var(--fbx-font-md); line-height: var(--fbx-leading-normal); color: var(--fbx-text); outline: none; word-break: break-word; }
.fbx-editor-area:empty:before { content: attr(data-placeholder); color: var(--fbx-faint); pointer-events: none; }
.fbx-editor-area ul, .fbx-editor-area ol { margin: var(--fbx-space-4) 0 var(--fbx-space-4) 22px; }
/* Vignettes d'images — même finition que le widget front : aperçu local 80px,
   object-fit cover, croix révélée au survol, loader pendant l'upload. */
.fbx-editor-thumbs:not(:empty) { display: flex; flex-wrap: wrap; gap: var(--fbx-space-8); padding: var(--fbx-space-10) 11px; border-top: 1px solid var(--fbx-border-list); }
.fbx-ed-thumb { position: relative; width: 80px; height: 80px; border-radius: var(--fbx-radius-sm); overflow: hidden; border: 1px solid var(--fbx-border-strong); background: var(--fbx-surface-sunken); flex-shrink: 0; }
.fbx-ed-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fbx-ed-thumb-file { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: var(--fbx-text-muted); }
.fbx-ed-thumb-x { position: absolute; top: var(--fbx-space-2); right: var(--fbx-space-2); width: 20px; height: 20px; border: none; border-radius: var(--fbx-radius-full); background: var(--fbx-overlay-thumb); color: var(--fbx-on-accent); font-size: var(--fbx-font-base); line-height: 20px; text-align: center; cursor: pointer; padding: 0; opacity: 0; transition: opacity .15s; }
.fbx-ed-thumb:hover .fbx-ed-thumb-x { opacity: 1; }
.fbx-ed-thumb-x:hover { background: rgba(var(--fbx-danger-rgb), .9); }
.fbx-ed-thumb-spin { position: absolute; inset: 0; display: none; background: rgba(var(--fbx-on-accent-rgb), .55); }
.fbx-ed-thumb-uploading .fbx-ed-thumb-spin { display: block; }
.fbx-ed-thumb-uploading .fbx-ed-thumb-spin::after { content: ''; position: absolute; top: 50%; left: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px; border: 2px solid rgba(var(--fbx-shadow-rgb), .15); border-top-color: var(--fbx-accent-fg); border-radius: var(--fbx-radius-full); animation: fbx-ed-spin .7s linear infinite; }
@keyframes fbx-ed-spin { to { transform: rotate(360deg); } }

/* Actions en icônes (Répondre / Modifier / Supprimer). Le look est ici ; la
   révélation au survol est posée par la page (elle connaît .fb-row/.fb-reply). */
.fbx-actions { display: inline-flex; align-items: center; gap: var(--fbx-space-2); }
.fbx-act-btn { border: none; background: transparent; width: 28px; height: 28px; border-radius: 7px; cursor: pointer; color: var(--fbx-text-muted); display: inline-flex; align-items: center; justify-content: center; transition: background .12s, color .12s; padding: 0; }
.fbx-act-btn:hover { background: var(--fbx-fill); color: var(--fbx-text); }
.fbx-act-btn.danger:hover { background: var(--fbx-danger-bg); color: var(--fbx-danger-fg); }
.fbx-act-btn svg { display: block; }
/* ⚠️ PAS D'ÉTAT `:disabled` ICI, et c'est un retrait daté (2026-08-08). Il a
   été écrit le matin pour un bouton « renvoyer le lien » que l'écran des
   testeurs éteignait ligne par ligne — et retiré le soir avec lui, ce geste
   ayant fondu dans un seul bouton qui suit l'état. La règle qui l'a motivé
   reste vraie et vaut pour toute barre d'actions : *une action qui ne
   s'applique pas à cette ligne s'y montre éteinte, elle ne s'en retire pas* —
   retirée, elle décale les suivantes et le même geste change de place. Le jour
   où un écran en a besoin, deux déclarations suffisent, dont l'ANNULATION
   EXPLICITE DU SURVOL : `.fbx-act-btn:hover` est déclaré au-dessus et un bouton
   désactivé le prendrait quand même, s'allumant sous le curseur pour annoncer
   un geste qu'il refuse. On ne garde pas la règle « au cas où » : une
   déclaration sans consommateur est du code mort, et c'est précisément ce que
   le compteur du design system sert à débusquer. */

/* ═══════════════════════════════════════════════════════════════════════════
   COMBOBOX « saisir OU choisir » (P39) — TPXShared.openCombo()
   Elle ne réinvente PAS de popup : le panneau EST un `.fbx-dd-pop` et les
   entrées SONT des `.fbx-dd-opt`, ceux du dropdown maison. Position fixe,
   bascule au-dessus quand la place manque, surbrillance `.active` au clavier :
   tout cela existe déjà et se comporte pareil. Ce qui suit n'ajoute que ce qui
   manquait vraiment — un champ de recherche en tête, et de quoi CRÉER ce qui
   n'existe pas encore.
   ═══════════════════════════════════════════════════════════════════════════ */
.fbx-combo { padding: 0; min-width: 220px; max-height: none; overflow: visible; }
/* Le champ ne défile pas avec la liste : on cherche en voyant ce qu'on tape. */
.fbx-combo-search { padding: var(--fbx-space-8); border-bottom: 1px solid var(--fbx-border-list); }
.fbx-combo-search input {
  width: 100%; font: inherit; font-size: var(--fbx-font-base); line-height: var(--fbx-leading-tight); color: var(--fbx-text);
  padding: 7px var(--fbx-space-10); border: 1px solid var(--fbx-border); border-radius: var(--fbx-radius); background: var(--fbx-surface);
}
.fbx-combo-search input:focus {
  outline: none; border-color: var(--fbx-accent-fg);
  box-shadow: 0 0 0 3px rgba(var(--fbx-accent-rgb), .12);
}
.fbx-combo-list { max-height: 240px; overflow-y: auto; padding: 5px; }
/* Ce qui est DÉJÀ posé reste visible et se distingue, au lieu de disparaître de
   la liste : sans quoi on ne sait pas si un tag manque ou s'il est déjà là. */
.fbx-combo-list .fbx-dd-opt[aria-selected="true"] { color: var(--fbx-accent-fg); }
.fbx-combo-empty { padding: var(--fbx-space-12) var(--fbx-space-12) var(--fbx-space-14); font-size: var(--fbx-font-sm); color: var(--fbx-text-muted); text-align: center; }
/* La création est une entrée de liste, pas un bouton à part : elle se choisit
   au clavier comme les autres, dans le même mouvement. */
.fbx-combo-create { border-top: 1px solid var(--fbx-border-list); padding: 5px; }
.fbx-combo-create .fbx-dd-opt { color: var(--fbx-accent-fg); font-weight: var(--fbx-weight-semibold); }
.fbx-combo-create .fbx-dd-opt em { font-style: normal; color: var(--fbx-text); font-weight: var(--fbx-weight-normal); }
.fbx-combo-hint {
  padding: 7px var(--fbx-space-12); border-top: 1px solid var(--fbx-border-list);
  font-size: var(--fbx-font-xs); color: var(--fbx-text-muted); line-height: var(--fbx-leading-snug);
}
