/* ══════════════════════════════════════════════════════
   Velbo — style.css
   Aurora system · Cosmos violet · Verre · Violet+Bleu
   ── Refonte 2026-07-30 : l'accent cyan devient un BLEU. Toute
      l'interface passe du couple violet+cyan au couple violet+bleu
      en changeant ces valeurs, et rien d'autre. Le vert / l'ambre /
      le rouge restent réservés aux ÉTATS (ça va · attention · problème).
   ══════════════════════════════════════════════════════ */

/* ── Variables ───────────────────────────────────────── */
:root {
  /* ══ LE SOCLE D'UN THÈME ═══════════════════════════════════════════════════
     ⚠️⚠️ TOUT CE QU'UN THÈME A LE DROIT DE RÉÉCRIRE, ET RIEN D'AUTRE. Les cent
     trente-sept jetons qui suivent en DÉRIVENT : changer le socle change tout le
     site d'un coup, sans qu'aucun thème ait à connaître un seul sélecteur.
     La règle est dure et se vérifie automatiquement (outils/verifier-themes.py) :
     un bloc de thème qui contient autre chose qu'une ligne « --xx: valeur; » est
     un défaut. S'il doit ajouter une bordure ou déplacer quelque chose pour être
     joli, c'est le socle qui est incomplet — on répare le socle, pas le thème.

     ⚠️ --voile ET --ombre SONT LA PIÈCE MAÎTRESSE. Le site pose 868 voiles
     translucides — `rgba(var(--th-voile),0.05)` et ses quatre-vingt-dix opacités — pour
     éclaircir une surface. Sur un thème CLAIR, un voile blanc sur du papier ne se
     voit pas : la moitié de l'interface disparaîtrait. En passant les trois canaux
     en variable, une seule substitution couvre les quatre-vingt-dix opacités, et un
     thème clair n'a qu'à écrire « --th-voile: 0,0,0 » pour que tout s'inverse. */
  --th-voile:            255,255,255;   /* ce qui ÉCLAIRCIT une surface */
  --th-ombre: 0,0,0;         /* ce qui l'ASSOMBRIT */

  /* ⚠️⚠️ LE FOND ET LE PANNEAU AUSSI EN CANAUX. Une barre collante, un voile de
     dialogue, un fond de menu : tous posent la couleur du PANNEAU a une opacite, pour
     laisser deviner ce qui defile dessous. Ecrits en dur (« rgba(16,19,31,0.78) »), ils
     restaient bleu ardoise sur du papier washi -- la grande bande sombre vue sur l ecran
     Bibliotheque. Mes substitutions ne couvraient que le blanc et le noir PURS. */
  /* ══ LE DÉCOR ═══════════════════════════════════════════════════════════════
     ⚠️⚠️ UNE VARIABLE PEUT CONTENIR TOUTE UNE PILE DE FONDS. C'est ce qui permet à
     chaque thème d'avoir SA SCÈNE — les rais de l'abysse, les braises du volcan, le
     rideau de l'aurore — sans écrire un seul sélecteur, donc sans casser la règle qui
     rend sept thèmes tenables. Deux couches, comme au théâtre :
       · LOIN : ce qui est fin et lointain — poussière, étoiles, pluie, particules ;
       · PRÈS : ce qui est grand et diffus — halos, rais, silhouettes, rideau.
     ⚠️ Elles débordent de 8 % : elles BOUGENT, et sans ce débord on verrait le bord
     du décor entrer dans l'écran. */
  /* ⚠️⚠️ POURQUOI LA VALEUR PORTE DEUX NOMS — 15/08. Amadou : « la card Nuit
     violette affiche le thème que je viens de choisir ». C'était vrai, et c'était
     inévitable : la vignette de Nuit violette est la SEULE à ne pas porter de
     `data-theme` (le socle, c'est l'absence d'attribut). Elle hérite donc
     `--th-fond-scene` de `<html>` — qui porte le thème ACTIF. Elle montrait le
     décor courant, jamais le sien.
     On ne peut pas « déshériter » une variable CSS. La seule issue sans dupliquer
     les 3 190 caractères du dessin : le ranger sous un nom QUE LES THÈMES
     N'ÉCRASENT JAMAIS. `--th-fond-scene` reste la variable que tout le site lit ;
     `--socle-scene` garde la valeur d'origine, accessible partout, même quand un
     thème est posé. La valeur n'est écrite qu'une fois. */
  --socle-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230D0B1C%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%230A0916%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23070610%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22v%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%238B7FFF%22%20stop-opacity%3D%220%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%238B7FFF%22%20stop-opacity%3D%22.075%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%238B7FFF%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.20%22%3E%3Cpath%20d%3D%22M-160%20672L1760%20144v208L-160%20880z%22%20fill%3D%22url%28%23v%29%22%2F%3E%3Cg%20fill%3D%22%23CFC9FF%22%20opacity%3D%22.5%22%3E%3Ccircle%20cx%3D%22136%22%20cy%3D%22600%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%22288%22%20cy%3D%22528%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%22432%22%20cy%3D%22560%22%20r%3D%223.2%22%2F%3E%3Ccircle%20cx%3D%22568%22%20cy%3D%22472%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%22712%22%20cy%3D%22504%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%22848%22%20cy%3D%22416%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%22992%22%20cy%3D%22448%22%20r%3D%223.2%22%2F%3E%3Ccircle%20cx%3D%221136%22%20cy%3D%22368%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%221272%22%20cy%3D%22400%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%221408%22%20cy%3D%22320%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%221544%22%20cy%3D%22352%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%22224%22%20cy%3D%22664%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%22520%22%20cy%3D%22624%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22560%22%20r%3D%222.4%22%2F%3E%3Ccircle%20cx%3D%221088%22%20cy%3D%22512%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%221376%22%20cy%3D%22456%22%20r%3D%222.4%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23EDEBFF%22%3E%3Ccircle%20cx%3D%22352%22%20cy%3D%22248%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22904%22%20cy%3D%22192%22%20r%3D%226.8%22%2F%3E%3Ccircle%20cx%3D%221320%22%20cy%3D%22672%22%20r%3D%225.6%22%2F%3E%3Ccircle%20cx%3D%22608%22%20cy%3D%22768%22%20r%3D%225.2%22%2F%3E%3Ccircle%20cx%3D%221168%22%20cy%3D%22304%22%20r%3D%224.8%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%239A93C4%22%20opacity%3D%22.34%22%3E%3Ccircle%20cx%3D%22184%22%20cy%3D%22376%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%22472%22%20cy%3D%22328%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%22736%22%20cy%3D%22280%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%221048%22%20cy%3D%22736%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%221472%22%20cy%3D%22560%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%2296%22%20cy%3D%22784%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%22824%22%20cy%3D%22840%22%20r%3D%222%22%2F%3E%3Ccircle%20cx%3D%221512%22%20cy%3D%22816%22%20r%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-fond-scene: var(--socle-scene);
  --th-decor-loin: radial-gradient(2px 2px at 11% 7%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(1.5px 1.5px at 27% 18%, rgba(var(--th-voile),0.40), transparent 70%),
    radial-gradient(2.5px 2.5px at 4% 34%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(1.5px 1.5px at 19% 47%, rgba(var(--th-voile),0.35), transparent 70%),
    radial-gradient(2px 2px at 36% 36%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(1.5px 1.5px at 46% 14%, rgba(var(--th-voile),0.45), transparent 70%),
    radial-gradient(2.5px 2.5px at 56% 62%, rgba(var(--th-voile),0.50), transparent 70%),
    radial-gradient(2px 2px at 62% 26%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(2.5px 2.5px at 73% 8%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(1.5px 1.5px at 81% 38%, rgba(var(--th-voile),0.45), transparent 70%),
    radial-gradient(2px 2px at 88% 64%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(2.5px 2.5px at 95% 18%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(1.5px 1.5px at 92% 73%, rgba(var(--th-voile),0.35), transparent 70%),
    radial-gradient(1.5px 1.5px at 7% 91%, rgba(var(--th-voile),0.40), transparent 70%),
    radial-gradient(2px 2px at 24% 84%, rgba(var(--th-voile),0.50), transparent 70%),
    radial-gradient(2px 2px at 41% 94%, rgba(var(--th-voile),0.45), transparent 70%),
    radial-gradient(1.5px 1.5px at 57% 78%, rgba(var(--th-voile),0.45), transparent 70%),
    radial-gradient(2.5px 2.5px at 14% 63%, rgba(var(--th-voile),0.55), transparent 70%),
    radial-gradient(1.5px 1.5px at 33% 71%, rgba(var(--th-voile),0.40), transparent 70%),
    radial-gradient(2px 2px at 68% 53%, rgba(var(--th-voile),0.45), transparent 70%),
    radial-gradient(2px 2px at 78% 87%, rgba(var(--th-voile),0.50), transparent 70%),
    radial-gradient(1.5px 1.5px at 49% 48%, rgba(var(--th-voile),0.40), transparent 70%),
    radial-gradient(1.5px 1.5px at 86% 96%, rgba(var(--th-voile),0.40), transparent 70%),
    radial-gradient(1.5px 1.5px at 39% 58%, rgba(var(--th-voile),0.35), transparent 70%);
  --th-decor-pres: /* halo violet haut-droit, profondeur */
    radial-gradient(1000px 580px at 84% -10%, rgba(var(--th-accent-rgb),0.34), transparent 65%),
    /* halo bleu bas-gauche, profondeur */
    radial-gradient(1000px 580px at 12% 112%, rgba(var(--th-second-rgb),0.26), transparent 65%),
    /* puits violet→bleu central */
    radial-gradient(1300px 800px at 50% 55%, rgba(var(--th-accent-rgb),0.14), transparent 70%),
    /* Arc lumineux « horizon ». ⚠️ Très atténué depuis que .app-content est transparent :
       le caisson sombre le masquait, sans lui cette bande claire barrait le dernier
       tiers de CHAQUE écran, en travers des cartes. */
    radial-gradient(1500px 140px at 50% 84%, rgba(154,141,255,0.10), transparent 70%),
    radial-gradient(1200px 100px at 50% 84%, rgba(var(--th-second-rgb),0.08), transparent 70%);
  /* La vitesse. Très lente, et c'est délibéré : sur un outil où l'on passe ses
     journées, une animation qu'on REMARQUE devient une animation qui fatigue. À ces
     durées, on ne voit rien bouger — on sent seulement que ce n'est pas figé. */
  --th-derive-loin: 260s;
  --th-derive-pres: 440s;
  --socle-fond: #0B0A17;
  --th-fond: var(--socle-fond);
  --th-fond-rgb:      11,10,23;
  --th-panneau-rgb:   20,18,31;
  --th-panneau:       #14121F;
  --th-carte:         #1A1828;
  /* ⚠️ MÊME MOTIF QUE `--socle-fond` ET `--socle-scene` : la valeur d'origine est mise de
     côté sous son propre nom, pour rester lisible même quand un thème a réécrit `--th-*`.
     Sans ça, l'aperçu du socle empruntait les couleurs du thème ACTIF — on regardait
     « Nuit violette » et le bouton était turquoise (Amadou, 24/08). */
  --socle-texte:      #EEF0F7;
  --th-texte:         var(--socle-texte);
  --th-texte-2:       #B3B8C9;
  --th-texte-3:       #888CA1;
  --th-trait:         148,150,172;   /* en canaux : le trait se pose à l'opacité voulue */
  --socle-accent:     #8B7FFF;
  --th-accent:        var(--socle-accent);
  --th-accent-clair:  #D6D0FF;
  --th-accent-doux:   #9A8DFF;
  --th-accent-fort:   #9E93FF;
  --th-accent-rgb:    139,127,255;
  /* ⚠️ CE QUI S'ÉCRIT SUR L'ACCENT. 169 « color: #fff » (écrit en dur) traînaient :
     du blanc posé sur un bouton coloré. Correct tant que l'accent est sombre — et
     illisible dès que le thème choisit un accent CLAIR (l'ambre de Phosphore, le
     lichen de Sylve). Ce n'est donc pas une couleur, c'est un rôle. */
  --socle-sur-accent: #fff;
  --th-sur-accent:    var(--socle-sur-accent);
  /* ⚠️⚠️ ET CE QUI S'ÉCRIT SUR UNE SURFACE PLEINE — bouton principal, pastille active,
     dégradé violet→cyan. Ce n'est PAS la même chose que `--th-sur-accent` : celui-là
     couvre l'accent seul, celui-ci le dégradé, qui est un ton MOYEN. Mesuré : le bouton
     principal écrivait en #14121F sur un dégradé à mi-clarté — contraste 1,73, dans TOUS
     les thèmes, l'actuel compris. Ce défaut est antérieur aux thèmes ; il ne se voyait
     pas parce que personne ne l'avait mesuré. Blanc ou noir, selon ce qui gagne. */
  --th-sur-plein:     #111111;
  /* ⚠️⚠️ L'ÉTOILE DE VELBO SUIT LE THÈME. Ses deux traînées prennent l'accent et la
     seconde voix ; son cœur, lui, a besoin de ses propres jetons — un cœur BLANC sur un
     thème clair serait invisible, et c'est la marque du logiciel. Sur les sombres il
     reste blanc ; sur les clairs il descend dans l'accent. */
  --th-logo-coeur: #FFFFFF;
  --th-logo-halo:  var(--th-accent-clair);
  /* ⚠️⚠️ L'AMBIANCE FAIT PARTIE DU THÈME. Le site pose un « fond espace » sur toute
     la page : une poussière d'étoiles et deux halos, en position fixe. Magnifique sur
     une nuit violette ; absurde sur du papier washi, où ça donnait un voile mauve
     sale — vu à l'écran dès le premier essai de Sumi-e. Un thème plat écrit donc
     « --th-ambiance: 0 » et les deux couches s'éteignent, sans qu'aucune règle bouge. */
  --th-ambiance:      1;
  /* ⚠️⚠️ SUR UN THÈME CLAIR À DÉCOR, LES CARTES DOIVENT PORTER. Elles sont translucides
     (un voile posé sur le fond) : c'est juste sur une nuit unie, mais sur un sable
     dégradé le contenu se délave — vu sur Dune, texte parfaitement contrasté sur le
     papier et pourtant illisible à l'œil. Ce multiplicateur épaissit toutes les surfaces
     d'un coup, sans toucher à une seule règle. */
  --th-surface-force: 1;
  --th-second:        #6E8BFF;       /* la seconde voix : liens, volumes */
  --th-second-clair:  #B4C2FF;
  --th-second-rgb:    110,139,255;
  --th-succes:        #63D6B0;
  --th-alerte:        #F0B055;
  --th-danger:        #F0787A;
  --th-danger-rgb:    240,120,122;
  /* La géométrie fait partie du thème : six teintes du même site ne sont pas six
     thèmes. Sumi-e est presque carré, Nuit violette est arrondi. */
  --th-rayon-micro:   4px;
  --th-rayon-xs:      6px;
  --th-rayon-sm:      8px;
  --th-rayon-md:      10px;
  --th-rayon-lg:      12px;
  --th-rayon-carte:   14px;
  --th-rayon-panneau: 22px;
  /* La police aussi : un Phosphore en serif n'aurait aucun sens. */
  --th-police:        system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --th-police-titre:  var(--th-police);
  --th-police-chiffre: ui-monospace, "SF Mono", Menlo, monospace;
  --th-casse-nav:     none;          /* Bauhaus met sa navigation en capitales */
  --th-graisse-titre: 600;

  /* Background layers */
  --bg:                var(--th-fond);
  --bg-2:              color-mix(in srgb, var(--th-fond) 88%, #000);
  --bg-base: var(--bg);
  --bg-panel: rgba(var(--th-voile), calc(0.038 * var(--th-surface-force)));
  --bg-panel-solid:    var(--th-panneau);
  /* ⚠️ LE PANNEAU QUI RESPIRE. Amadou (15/08) : « elle est un peu trop là, rajoute un
     peu d'opacité ». Un panneau totalement plein écrase le décor du thème et se
     découpe durement sur la page — surtout sur les thèmes clairs, où il est presque
     blanc. À 90 %, le décor transparaît d'un dixième : assez pour que le panneau
     s'inscrive dans la page, trop peu pour qu'il redevienne le voile illisible d'avant.
     ⚠️ Il faut le TRIPLET (--th-panneau-rgb), pas l'hexadécimal : on ne peut pas poser
     une opacité sur `#FBF4EA` sans le décomposer. */
  --panneau-doux:      rgba(var(--th-panneau-rgb), 0.9);
  /* ⚠️⚠️ LE FONDU DU HAUT. Amadou (15/08) : « aux extrémités, à gauche et à droite,
     tout en haut, ça fait un trait, c'est net et ça ne fait pas très beau ».
     Un panneau qui commence d'un coup trace une arête horizontale franche là où rien
     ne la justifie — ce n'est ni une bordure ni une séparation, juste le bord de la
     peinture. On le fond sur 64 px.
     ⚠️⚠️ ET LE DÉGRADÉ NE VARIE QUE PAR L'ALPHA, jamais vers `transparent` : le
     mot-clé `transparent` vaut « noir transparent », et l'interpolation passe alors
     par du gris — un halo sale au milieu du fondu, visible surtout sur les thèmes
     clairs. Même triplet aux deux bouts, seule l'opacité bouge. */
  --panneau-fondu:     linear-gradient(to bottom,
                         rgba(var(--th-panneau-rgb), 0) 0,
                         rgba(var(--th-panneau-rgb), 0.9) 64px);
  /* ⚠️ LE FILET DOIT DESCENDRE AVEC LE FOND. Un fond qui se fond sous un trait qui,
     lui, commence net, c'est pire que les deux nets : l'arête reste, seule et
     suspendue au-dessus du dégradé. Un `border` ne se dégrade pas — `border-image`,
     si. La tranche `1` peint tous les côtés, mais seuls ceux dont la LARGEUR est non
     nulle apparaissent : on garde donc `border-width` à zéro partout sauf du bon côté. */
  --filet-fondu:       linear-gradient(to bottom,
                         rgba(var(--th-trait), 0) 0,
                         rgba(var(--th-trait), 0.23) 64px) 1;
  --bg-sidebar:        rgba(var(--th-voile),0.045);
  --bg-sidebar-solid:  color-mix(in srgb, var(--th-fond) 94%, var(--th-panneau));
  --bg-card: var(--surface-2);
  --bg-card-solid:     var(--th-carte);
  --bg-elevated:       rgba(var(--th-voile),0.06);
  --bg-hover:          rgba(var(--th-voile),0.05);
  --bg-input: var(--surface);
  --surface: rgba(var(--th-voile), calc(0.03 * var(--th-surface-force)));
  --surface-2: rgba(var(--th-voile), calc(0.055 * var(--th-surface-force)));
  /* ⚠️⚠️ TROISIÈME BARREAU — IL ÉTAIT APPELÉ HUIT FOIS ET DÉFINI NULLE PART (15/08).
     Quatre appels s'écrivaient `var(--surface-3)` tout court : une variable inexistante
     rend la déclaration invalide « au calcul », donc ces quatre fonds ne se dessinaient
     PAS DU TOUT (survols morts, panneaux sans fond). Deux autres portaient un repli
     SOMBRE EN DUR — `#161A2A` et `#1e1e2e` — qui s'appliquait dans les SEPT thèmes :
     sur Dune, une plaque presque noire au milieu du sable.
     ⚠️ C'est le piège déjà noté deux fois dans ce fichier : une variable CSS manquante
     ne lève AUCUNE erreur et n'apparaît nulle part dans l'inspecteur.
     Même formule que ses deux voisins, un cran au-dessus. Aucune invention. */
  --surface-3: rgba(var(--th-voile), calc(0.085 * var(--th-surface-force)));

  /* Borders */
  /* ⚠️ Mêmes valeurs en gris que les jetons du cockpit : garder du blanc ici aurait
     laissé deux familles de contours côte à côte dans le même écran (la barre latérale
     et les dialogues tirent d'ici, les cartes du cockpit de --cok-border). */
  --border:            rgba(var(--th-trait),0.115);
  --border-mid:        rgba(var(--th-trait),0.16);
  --border-strong:     rgba(var(--th-trait),0.23);

  /* Text */
  --text:              var(--th-texte);
  --text-1: var(--text);
  --text-2:            var(--th-texte-2);
  --text-3:            var(--th-texte-3);
  --text-muted: var(--text-2);
  --text-on-glow: var(--violet-light);

  /* Identity */
  --violet:            var(--th-accent);
  /* ⚠️⚠️ CES DEUX ALIAS N'AVAIENT JAMAIS ÉTÉ POSÉS, et rien ne le disait : un
     `color: var(--sur-accent)` dont la variable n'existe pas n'est pas une erreur pour
     le navigateur — la déclaration est simplement ignorée, et l'élément HÉRITE la
     couleur de son parent. 174 textes écrivaient donc la couleur du texte courant sur
     un bouton coloré. Invisible dans le code, invisible à la lecture, visible seulement
     en mesurant le contraste réel à l'écran. */
  --sur-accent: var(--th-sur-accent);
  /* ⚠️⚠️ CE QUI S'ÉCRIT SUR DU SOMBRE — et il ne change JAMAIS de thème, c'est tout
     l'intérêt. Une étiquette posée sur une PHOTO (badge de version, compteur de vues,
     petite croix de suppression) repose sur une plaque noire à 45-72 % : cette plaque
     est noire dans les seize thèmes, donc son texte doit être clair dans les seize.
     `--sur-accent` y était employé à tort : il vaut #03090C sur les thèmes sombres,
     c'est-à-dire du noir sur du noir. Diagnostiqué le 15/08 sur 19 règles. */
  --sur-sombre: #FFFFFF;
  --sur-plein:  var(--th-sur-plein);
  --violet-mid: var(--violet);
  --violet-hover:      var(--th-accent-fort);
  --violet-light:      var(--th-accent-clair);
  --violet-soft:       var(--th-accent-doux);
  --violet-tint:       rgba(var(--th-accent-rgb),0.16);
  --violet-tint-strong:rgba(var(--th-accent-rgb),0.26);
  --violet-glow:       rgba(var(--th-accent-rgb),0.45);
  /* ⚠️ `--accent` était appelée à dix endroits (l'onglet actif des Paramètres, les
     filtres et les pastilles de couleur de la Bibliothèque…) sans avoir JAMAIS été
     déclarée : ces éléments retombaient donc sur du blanc, ou sur rien. C'est pour
     ça que l'onglet actif des Paramètres se soulignait en blanc et pas en violet.
     Elle vaut l'accent du site — un seul mot, dix endroits réparés. */
  --accent: var(--violet-soft);

  /* « cyan » garde son nom (il est cité partout) mais vaut désormais le BLEU
     du couple violet-bleu. Zéro turquoise dans l'interface. */
  --cyan:              var(--th-second);
  --cyan-soft: var(--cyan-light);
  --cyan-light:        var(--th-second-clair);
  --cyan-tint:         rgba(var(--th-second-rgb),0.16);
  --cyan-glow:         rgba(var(--th-second-rgb),0.38);

  /* Aurora gradient — réservé au bouton primaire "Générer" */
  --aurora: linear-gradient(120deg, var(--th-accent) 0%, var(--th-accent-doux) 100%);
  --aurora-soft: linear-gradient(120deg, rgba(var(--th-accent-rgb),.85) 0%, rgba(var(--th-second-rgb),.85) 100%);

  /* Tiers — Notion-tag desaturated */
  --tier-volume-bg:    rgba(var(--th-second-rgb),0.15);
  --tier-volume-text: var(--cyan-light);
  --tier-volume-glow:  rgba(var(--th-second-rgb),0.35);
  --tier-premium-bg:   rgba(var(--th-accent-rgb),0.18);
  --tier-premium-text: var(--violet-light);
  --tier-premium-glow: rgba(var(--th-accent-rgb),0.4);
  --tier-luxe-bg:      rgba(214,176,99,0.13);
  /* ⚠️ TROISIÈME ORPHELIN de la même famille que --ose-text (réparé ce matin) :
     ses deux voisins --tier-volume-text et --tier-premium-text suivent le thème,
     lui seul portait un hexadécimal. Or et ambre disent la même chose. */
  --tier-luxe-text:    var(--th-alerte);
  --tier-luxe-glow:    rgba(214,176,99,0.3);

  /* ── Statuts prix ─────────────────────────────────────────────────────────
     ⚠️⚠️ CE BLOC EST ANTÉRIEUR AU SOCLE DES THÈMES, ET IL Y AVAIT ÉCHAPPÉ.
     Les trois `*-text` étaient des hexadécimaux ÉCRITS EN DUR : `--ose-text`
     valait `#ECA0A0` — un rose pâle — dans les SEPT thèmes. Juste sur une nuit,
     invisible sur du sable : mesuré à **1,56 de contraste** en Dune et 1,69 en
     Nimbe (il en faut 4,5). C'est ce qui rendait le bouton « Supprimer » de la
     fenêtre de confirmation illisible sur les thèmes clairs.
     Le plus troublant : la note juste en dessous dit déjà que le site s'est
     unifié sur --th-succes / --th-alerte / --th-danger. Ces trois-là n'avaient
     simplement jamais été raccordés. On les raccorde — et Dune passe de 1,56 à
     un rouge brique #96241C, foncé, fait pour du fond clair.
     ⚠️ Les fonds `*-bg` : seul le danger a un triplet de socle (--th-danger-rgb).
     `--safe-bg` et `--moy-bg` restent des aplats faute de --th-succes-rgb ; ils
     sont assez transparents (13 %) pour ne pas trahir le thème. */
  --safe-bg:           rgba(56,189,148,0.13);
  --safe-text:         var(--th-succes);
  --safe-glow:         rgba(56,189,148,0.35);
  --moy-bg:            rgba(213,156,82,0.13);
  --moy-text:          var(--th-alerte);
  --ose-bg:            rgba(var(--th-danger-rgb),0.13);
  --ose-text:          var(--th-danger);

  /* ── ÉTAT : UNE SEULE PALETTE POUR TOUT LE SITE ───────────────────────────
     ⚠️⚠️ Il y en avait DEUX. Le Cockpit disait vert #63D6B0 / rouge #F0787A /
     ambre #F0B055 ; le reste du site #6ED2A8 / #ECA0A0 / #E5C28A. Résultat : un
     badge « attention » du Cockpit et un badge « attention » de la Bibliothèque
     n'avaient PAS la même couleur alors qu'ils disent la même chose.
     On garde celle du Cockpit — plus saturée. Une alerte doit se voir, et c'est
     l'écran où l'on passe le plus de temps. Les jetons `--cok-*` gardent leur nom
     (2 000 usages) mais pointent désormais sur les mêmes valeurs. */
  --green:             var(--th-succes);
  --amber:             var(--th-alerte);
  --red:               var(--th-danger);
  /* Le rouge « danger » en fond et en trait, pour cesser de le retaper à la main :
     il existait en SIX transparences (.06 .07 .08 .12 .12 .15) que personne ne
     distingue à l'œil, mais qui étaient écrites six fois. */
  --danger-fond:       rgba(var(--th-danger-rgb),0.12);
  --danger-bord:       rgba(var(--th-danger-rgb),0.32);

  /* Type scale (px) */
/* ── L'ÉCHELLE DE TEXTE ──────────────────────────────────────────────────────
     ⚠️⚠️ ELLE EXISTAIT DÉJÀ, ET PERSONNE NE S'EN SERVAIT : 79 déclarations la
     citaient, 1 576 écrivaient leur taille à la main — dans 69 valeurs différentes,
     moitié en px moitié en rem. `0.72rem` et `11.5px` sont la MÊME taille à l'écran ;
     deux graphies suffisaient à les rendre invisibles l'une à l'autre.
     Les quatre barreaux manquants sont ajoutés d'après l'usage RÉEL du site, pas
     d'après une théorie : 13 px est la taille la plus employée (243 fois) et ne
     figurait nulle part dans l'échelle. */
/* Les grands corps : ils existaient (24, 26, 32, 38, 40 px écrits à la main dans
     27 déclarations) mais l'échelle s'arrêtait à 28. Trois barreaux les accueillent
     plutôt que de les tasser sur un cran qui ne leur va pas. */
  --t-xl:      24px;
  --t-2xl:     32px;
  --t-3xl:     40px;
  --t-nano:    8px;    /* mentions minuscules : compteurs superposés, exposants */
  --t-display: 28px;
  --t-title:   22px;
  --t-lead:    19px;   /* sous-titres d'écran */
  --t-body:    16px;
  --t-small:   14px;
  --t-base:    13px;   /* LA taille du site : 243 emplois */
  --t-meta:    12px;
  --t-mini:    11px;   /* étiquettes, pastilles */
  --t-micro:   10px;   /* mentions, compteurs */

  /* ── LE RESTE DU TEXTE ───────────────────────────────────────────────────────
     ⚠️⚠️ La taille n'était que le tiers du sujet. Mesuré le 13/08 :
       · GRAISSE       — 766 déclarations, 8 valeurs, ZÉRO variable ;
       · INTERLIGNE    — 282 déclarations, 24 valeurs, ZÉRO variable ;
       · INTERLETTRAGE — 178 déclarations, QUARANTE graphies pour 30 valeurs :
         `.04em` et `0.04em` sont le même réglage, écrit deux fois. */

  /* La graisse : quatre crans, et on n'y touche pas au-delà. 500, 600 et 700 se
     VOIENT — les confondre changerait la hiérarchie de lecture du site, ce qui
     n'est pas un rangement. Ils sont nommés, pas fusionnés. */
  --fw-normal: 400;
  --fw-moyen:  500;
  --fw-fort:   600;
  --fw-gras:   700;

  /* L'interligne : cinq crans au lieu de dix-huit. Écart maximal appliqué 0,1 —
     soit un pixel et demi sur un paragraphe entier. */
  --lh-un:     1;      /* une seule ligne : boutons, pastilles, compteurs */
  --lh-titre:  1.15;
  --lh-serre:  1.35;
  --lh-normal: 1.5;
  --lh-aere:   1.65;

  /* L'interlettrage : six crans au lieu de trente. */
  --ls-serre:  -0.01em;
  --ls-zero:   0;
  --ls-leger:  0.02em;
  --ls-large:  0.04em;
  --ls-ample:  0.06em;
  --ls-caps:   0.08em;  /* les libellés en majuscules */

  /* Spacing */
/* ── L'ÉCHELLE D'ESPACEMENT ──────────────────────────────────────────────────
     ⚠️⚠️ MESURÉ LE 13/08 : 4 874 valeurs en pixels dans les marges, les retraits et
     les gouttières — QUARANTE-SEPT valeurs distinctes. Le site employait tous les
     entiers de 1 à 18, plus une vingtaine de grandes valeurs. Mille trois cent
     seize d'entre elles étaient IMPAIRES, chacune coincée entre deux paires : un
     retrait de 7 px n'a jamais été choisi contre 6 ou 8, il est arrivé là.

     ⭐ UN SEUL BOUTON POUR TOUT AÉRER. Chaque barreau est un multiple de `--e-base` :
     passer la base de 2 à 2,5 px élargit TOUT le site de 25 %, d'une seule ligne.
     Et chaque barreau reste réglable seul si un seul écran doit bouger.

     ⚠️ `--e-1` (1 px) n'est PAS dérivé, et c'est volontaire : ce n'est pas un
     espacement mais un FILET — un trait, une correction optique d'un pixel. Le faire
     grandir avec les autres doublerait 265 traits fins du site. */
  --e-base: 2px;
  --e-1:  1px;                        /* filet, ajustement optique — jamais mis à l'échelle */
  --e-2:  calc(var(--e-base) *  1);
  --e-4:  calc(var(--e-base) *  2);
  --e-6:  calc(var(--e-base) *  3);
  --e-8:  calc(var(--e-base) *  4);
  --e-10: calc(var(--e-base) *  5);
  --e-12: calc(var(--e-base) *  6);
  --e-14: calc(var(--e-base) *  7);
  --e-16: calc(var(--e-base) *  8);
  --e-18: calc(var(--e-base) *  9);
  --e-20: calc(var(--e-base) * 10);
  --e-22: calc(var(--e-base) * 11);
  --e-24: calc(var(--e-base) * 12);
  --e-28: calc(var(--e-base) * 14);
  --e-32: calc(var(--e-base) * 16);
  --e-40: calc(var(--e-base) * 20);
  --e-48: calc(var(--e-base) * 24);

  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;

  /* ⚠️⚠️ CE BLOC ÉTAIT MORT ET IL MENTAIT. Les cinq mêmes noms sont redéfinis
     ~60 lignes plus bas (--r-sm: 8px, --r-md: 10px, --r-lg: 12px) et c'est le
     second qui gagne. Quiconque lisait ici « --r-md: 14px » croyait donc que les
     coins moyens font 14 px alors qu'ils en font 10 — le genre de piège qui
     produit la correction suivante. Seul --r-xs survit : il n'est jamais redéfini.
     ⚠️ --radius-sm / --radius ne sont PAS des alias : eux non plus ne sont jamais
     redéfinis, donc ils valent toujours 10 et 14 px. Deux boutons censés porter
     « le même petit arrondi » diffèrent de 2 px. Non touché ici : 83 règles en
     dépendent, ça se regarde écran par écran. */
  /* ── LA VIGNETTE, en trois jetons ────────────────────────────────────────────
     Changer le rayon des photos du site = changer CETTE ligne. Avant, il fallait
     retrouver les 71 règles et ne pas en oublier — ce qui n'est jamais arrivé. */
/* ── LE BOUTON, en trois jetons ──────────────────────────────────────────────
     Changer la taille de TOUS les boutons du site = changer ces trois lignes. */
/* ── LA PASTILLE, en quatre jetons ───────────────────────────────────────────
     La forme majoritaire du site : un mot court, 10 px, dans une pilule teintée. */
/* ── LA CARTE, en cinq jetons ────────────────────────────────────────────────
     L'objet qui contient tout le reste. Changer l'allure des cartes du site =
     changer ces cinq lignes. */
/* ⚠️⚠️ J'AVAIS MIS `--surface` (3 %) EN DÉFAUT, ET C'ÉTAIT FAUX. En cherchant les
     familles à raccorder, ZÉRO n'avait cette forme : la carte réelle du site est
     `--cok-card` (= `--surface-2`, 5,5 %). J'avais déduit le défaut du fond le plus
     COMPTÉ dans la feuille, pas de celui des vraies cartes — `--surface` sert surtout
     aux champs de saisie et aux fonds internes. Un composant dont personne n'a la
     forme ne raccroche personne. */
  --carte-fond:  var(--surface-2);
  --carte-filet: var(--border);
  --carte-rayon: var(--r-lg);
  --carte-pad-v: var(--e-12);
  --carte-pad-h: var(--e-14);

  --pas-texte:   var(--t-micro);
  --pas-graisse: var(--fw-fort);
  --pas-pad-v:   var(--e-2);
  --pas-pad-h:   var(--e-8);

  --btn-texte: var(--t-base);
  --btn-pad-v: var(--e-8);
  --btn-pad-h: var(--e-14);
  --btn-rayon: var(--r-md);

  --photo-ratio: 3 / 4;
  --photo-rayon: var(--r-sm);
  --photo-fond:  rgba(var(--th-voile),.03);
  --r-xs: var(--th-rayon-xs);
  /* Le coin totalement rond, qui s'écrivait 999px (121 fois), 50px (12) et 99px (6). */
  /* ⚠️⚠️ MÊME LA PASTILLE SUIT LE THÈME — 15/08. Amadou, sur Basalte : « ce thème
     volcanique, tout est carré, rien n'a d'arrondi, sauf qu'à des endroits ça
     arrondit ». Il avait raison : 157 pastilles étaient figées à 999px, donc des
     ovales parfaits au milieu d'un thème dont les cartes font 4px. Une DA à cent
     pour cent ne peut pas avoir d'exception « sauf les pastilles ».
     Le repli reste 999px : les quinze autres thèmes ne changent pas d'un pixel, et
     seul un thème qui le DÉCLARE devient carré. */
  --r-pilule: var(--th-rayon-pilule, 999px);
  /* Legacy aliases (existing classes) */
/* ── LES ARRONDIS : UNE SEULE ÉCHELLE ────────────────────────────────────────
     ⚠️⚠️ IL Y EN AVAIT DEUX, EN PARALLÈLE, ET ELLES SE CHEVAUCHAIENT :
       --r-xs 6 · --r-sm 8 · --r-md 10 · --r-lg 12 · --r-xl 18
       --radius-xs 6 · --radius-sm 10 · --radius 14 · --radius-lg 22
     Deux d'entre elles sont RIGOUREUSEMENT identiques — `--radius-xs` vaut `--r-xs`
     (6 px) et `--radius-sm` vaut `--r-md` (10 px). Deux noms pour un même arrondi :
     changer l'un ne changeait pas l'autre, et deux boutons censés porter « le même
     petit arrondi » pouvaient différer de 2 px sans que personne ne l'ait décidé.
     Les deux autres n'étaient pas des doublons mais des BARREAUX MANQUANTS : 14 px
     (cartes, modales, image agrandie) et 22 px (grands panneaux) n'existaient nulle
     part dans l'échelle principale.
     ⚠️ Je ne RENOMME PAS `--r-xl` (18 px, 62 emplois) pour y glisser 14 : un renommage
     déplacerait 62 arrondis en silence. Les deux barreaux entrent sous leur propre nom,
     et les anciens deviennent des alias — rien ne casse, tout se règle au même endroit. */
  --r-carte:   var(--th-rayon-carte);   /* cartes, modales moyennes, image agrandie */
  --r-panneau: var(--th-rayon-panneau);   /* grands panneaux : modales, studio, sélecteurs */
  --r-micro:   var(--th-rayon-micro);    /* pastilles minuscules, coches, filets */
  /* Les anciens noms survivent en renvoyant sur l'échelle — aucun appel à réécrire. */
  --radius-xs: var(--r-xs);
  --radius-sm: var(--r-md);
  --radius:    var(--r-carte);
  --radius-lg: var(--r-panneau);

  /* Shadows — soft only */
  --shadow-card:  0 1px 0 rgba(var(--th-voile),0.06) inset, 0 8px 30px rgba(var(--th-ombre),0.28);
  --shadow-panel: 0 1px 0 rgba(var(--th-voile),0.06) inset, 0 40px 80px -40px rgba(var(--th-ombre),0.55);
  --glow-violet:  0 0 0 1px rgba(var(--th-accent-rgb),0.18), 0 12px 36px -12px rgba(var(--th-accent-rgb),0.45);
  --glow-cyan:    0 0 0 1px rgba(var(--th-second-rgb),0.18), 0 12px 36px -12px rgba(var(--th-second-rgb),0.38);

  /* Motion */
  --d-fast: 120ms;
  --d-base: 200ms;
  --ease:   var(--c-pose);

  --sidebar-w:           232px;
  --sidebar-w-collapsed: 60px;
}

/* ══════════════════════════════════════════════════════════════════════════
   LE SOCLE — ce qui donne au site UNE seule façon de bouger et de répondre.
   ⚠️ MESURÉ AVANT D'ÊTRE ÉCRIT, le 07/08 : 70 durées différentes, 19 courbes,
   42 rayons, 145 classes de bouton pour 179 définitions. Personne n'avait
   décidé de ce désordre — il s'est accumulé écran après écran, et c'est lui
   qu'Amadou ressent quand il dit « ce n'est pas fluide, uniformise ».
   Trois durées suffisent, deux courbes suffisent. Tout le reste s'y ramène.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  /* Le temps. Bref = un état qui change sous le doigt (survol, appui).
     Moyen = quelque chose qui apparaît ou disparaît. Long = un panneau. */
  --t-bref:   .12s;
  --t-moyen:  .22s;
  --t-long:   .34s;
  /* La scène de la peinture : sa durée, et le pas entre deux blocs. Ce sont des
     durées de SCÈNE (comme la pastille qui respire), pas des transitions d'interface. */
  --peint-duree: .62s;
  /* La durée de l'écoulement du contour du Studio. Hors de l'échelle bref/moyen/long
     à dessein : ce n'est pas une transition d'interface mais un GESTE, qu'on doit
     avoir le temps de suivre du regard. Validée à 1,5 s par Amadou (26/08).
     ⚠️ Le halo du focus s'y accorde : apparu plus vite, il annoncerait l'arrivée de
     l'eau avant qu'elle ne soit là. */
  --studio-coule: 1.5s;
  --peint-pas: .11s;
  /* La courbe. Elle démarre franchement et se pose longuement : c'est ce qui
     fait lire « ça se pose » plutôt que « ça s'arrête ». Une seule pour tout
     ce qui entre ; la linéaire reste pour ce qui tourne en boucle. */
  --c-pose:   cubic-bezier(.22, 1, .36, 1);

  /* ⚠️⚠️ LA FAUTE DE VIRGULE, CORRIGÉE EN UN SEUL ENDROIT (09/08). 82 règles écrivaient
     `transition: background-color, border-color, color, box-shadow, transform, opacity
     var(--t-moyen)`. En CSS, chaque valeur séparée par une virgule est une transition
     COMPLÈTE : seule la dernière — `opacity` — avait une durée. Les CINQ autres changeaient
     en 0 ms. C'est ça que Amadou appelle « pas fluide » : partout dans le site, un survol
     faisait claquer la couleur, la bordure et l'ombre pendant que l'opacité, elle, se
     fondait sagement.
     ⭐ Écrire la liste complète 82 fois aurait garanti qu'elles redivergent. Une valeur
     réutilisable, et il n'y a plus qu'un endroit où se tromper. */
  --transi:     background-color var(--t-moyen) var(--c-pose),
                border-color     var(--t-moyen) var(--c-pose),
                color            var(--t-moyen) var(--c-pose),
                box-shadow       var(--t-moyen) var(--c-pose),
                transform        var(--t-moyen) var(--c-pose),
                opacity          var(--t-moyen) var(--c-pose);
  --transi-vif: background-color var(--t-bref) var(--c-pose),
                border-color     var(--t-bref) var(--c-pose),
                color            var(--t-bref) var(--c-pose),
                box-shadow       var(--t-bref) var(--c-pose),
                transform        var(--t-bref) var(--c-pose),
                opacity          var(--t-bref) var(--c-pose);
  /* ⚠️ Les anciens noms POINTENT sur le socle au lieu d'être traqués un par un dans
     huit cents déclarations. Une seule vérité, et aucune règle ne casse en route. */
  --d-fast:   var(--t-bref);
  --d-base:   var(--t-moyen);
  --d-mid:    var(--t-moyen);
  --d-slow:   var(--t-long);
  --ease:     var(--c-pose);
  --pose:     var(--c-pose);
  --c-sortie: cubic-bezier(.4, 0, 1, 1);
  /* La courbe de l'APPUI. Elle dépasse légèrement sa cible avant de revenir :
     c'est ce dépassement qui fait lire « pop » plutôt que « ça a rétréci ».
     Réservée au geste de pression — jamais pour ce qui entre ou ce qui sort. */
  --c-rebond: cubic-bezier(.34, 1.56, .64, 1);
  /* Les états d'un élément qu'on peut toucher. Trois niveaux, pas trente. */
  /* ⚠️⚠️ C'ÉTAIT DU BLANC PUR. Un voile blanc sur un fond presque noir ne peut donner
     qu'une chose : du GRIS. Amadou (09/08) : « quand je survole, le bouton se transforme
     en gris, ce n'est vraiment pas beau a voir. » Mesuré sur l'écran Annonces :
     #282734 au repos → #33323F au survol, soit +19 % de luminosité et ZÉRO degré de
     teinte gagné. Le survol porte maintenant la couleur du logiciel. */
  --survol-fond:   rgba(var(--th-accent-rgb),0.13);
  /* ⚠️⚠️ C'ÉTAIT UN VIOLET ÉCRIT EN DUR, dans un JETON — donc invisible au premier
     regard et propagé partout. Amadou (27/08) : « la flèche pour déplier la barre
     d'onglet, pareil ». Ce jeton peint le contour de focus de TOUS les boutons du
     site (`:focus-visible`) : sur le thème doré, cliquer un bouton laissait un cerne
     violet. Un jeton qui contient une couleur fixe est pire qu'une valeur brute — il
     a l'air d'être thématisé. */
  --survol-bord:   rgba(var(--th-accent-rgb),0.45);
  /* ⚠️ .975 sur un bouton de 68 px = 1,7 px de retrait : l'œil ne le voit pas.
     Amadou : « quand j'appuie dessus, il doit avoir une animation pop ». */
  --appui-echelle: .965;
  /* Les coins. Quatre marches au lieu de quarante-deux : petit (étiquette,
     champ), moyen (bouton, ligne), grand (carte), très grand (panneau).
     ⚠️ Les cercles (50 %) et les pilules (999px) restent tels quels : ce sont
     des formes voulues, pas des valeurs approximatives. */
  --r-sm: var(--th-rayon-sm);
  --r-md: var(--th-rayon-md);
  --r-lg: var(--th-rayon-lg);
  /* ⚠️ Écrit en dur, et employé 63 fois : c'était la seconde fuite. Il retombe sur le
     rayon de panneau du thème, qui est exactement ce qu'il désignait. */
  --r-xl: var(--th-rayon-xl, var(--th-rayon-panneau));
}

/* ⚠️ UNE SEULE FAÇON DE RÉPONDRE AU DOIGT, pour tout ce qui se clique. Écrit sans
   `!important` et avec une spécificité faible : chaque bouton garde ses couleurs,
   sa taille et sa forme — on n'unifie que le COMPORTEMENT, qui n'appartenait à
   personne et variait donc partout. */
button, [role="button"], .nav-item, .an-so, .cok-chip, .cok-cmd-grp, .cok-cmd-stab {
  transition: background-color var(--t-bref) var(--c-pose),
              border-color     var(--t-bref) var(--c-pose),
              color            var(--t-bref) var(--c-pose),
              opacity          var(--t-bref) var(--c-pose),
              transform        var(--t-bref) var(--c-pose);
}
/* L'appui : le même enfoncement partout. C'est le geste qui donne le sentiment
   qu'un bouton « répond » — il manquait sur la plupart. */
button:not(:disabled):active,
[role="button"]:active, .nav-item:active, .an-so:active,
.cok-chip:active, .cok-cmd-grp:active, .cok-cmd-stab:active {
  transform: scale(var(--appui-echelle));
}
/* ⚠️ Un bouton éteint ne doit pas répondre : sans cette ligne, il s'enfonçait
   comme les autres et laissait croire qu'il avait pris le clic. */
button:disabled, button[disabled] { transform: none !important; cursor: default; }
/* Le focus clavier, identique partout — il était absent d'à peu près tout. */
button:focus-visible, [role="button"]:focus-visible, a:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--survol-bord);
  outline-offset: 2px;
}

/* ── Reset ───────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: var(--t-body); scroll-behavior: smooth; }
body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  /* ⚠️⚠️ LE FOND DU SITE, ET C'EST LUI QUI TENAIT TOUT. Trois puits de lumière posés
     sur une nuit violine — et la nuit était écrite EN DUR (#0C0B1A). Sur un thème
     clair, le texte passait au noir, les cartes au blanc… et le fond restait violet :
     un site à moitié repeint, exactement ce qu'on voulait éviter. Vu à l'écran au
     premier essai de Sumi-e, pas déduit.
     ⚠️ Les trois puits s'éteignent par leur ALPHA, multiplié par --th-ambiance. On ne
     peut pas donner une opacité à une seule couche d'un empilement de fonds ; un calc
     dans l'alpha, si. À 0, il ne reste que l'aplat — ce que veut un thème plat. */
  /* ⚠️⚠️ ET LE FOND LUI-MÊME EST UNE VARIABLE. Il ne suffit pas de recolorer trois
     puits de lumière : un abysse s'assombrit vers le BAS, une dune a un HORIZON, un
     volcan rougeoie par en DESSOUS. Trois couches font la scène, et il fallait les
     trois : le fond (le ciel et le sol), la couche lointaine (les particules), la
     couche proche (les halos et les rais). Amadou : « pour la nuit violette il y a une
     sorte d'espace ; j'aimerais que chaque thème ait un fond adéquat ». */
  background: var(--th-fond-scene);
  background-attachment: fixed;
  color: var(--text);
  min-height: 100vh;
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
button { font-family: inherit; }
input, textarea, select { font-family: inherit; color: inherit; }
/* Supprime les flèches natives (spinners) moches sur TOUS les champs nombre */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* …remplacées par des flèches custom (DA Velbo), injectées par enhanceNumberInputs() */
.num-stepper { position: relative; display: inline-block; vertical-align: middle; }
.num-stepper.is-block { display: block; width: 100%; }
.num-stepper.is-block > input[type="number"] { width: 100%; }
.num-stepper > input[type="number"] { padding-right: var(--e-28) !important; }
.num-stepper-btns { position: absolute; top: 3px; right: 3px; bottom: 3px; width: 20px; display: flex; flex-direction: column; gap: var(--e-2); pointer-events: none; }
.num-stepper-btns button { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 0; border: 1px solid var(--border-mid); background: var(--surface-2); color: var(--text-2); border-radius: var(--r-micro); cursor: pointer; pointer-events: auto; transition: background var(--t-bref), color var(--t-bref), border-color var(--t-bref), transform var(--t-bref); }
.num-stepper-btns button:hover { background: var(--violet-tint); color: var(--violet-light); border-color: var(--violet); }
.num-stepper-btns button:active { transform: scale(0.9); }
.num-stepper-btns svg { width: 9px; height: 9px; display: block; }
img, svg { display: block; }
::selection { background: var(--violet-tint-strong); color: var(--text); }

*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: var(--bg-hover); border-radius: var(--r-micro); }
*::-webkit-scrollbar-thumb:hover { background: rgba(var(--th-voile),0.10); }

/* ══ ATELIER — LES TROIS ÉTAPES DE TÊTE ═══════════════════════════════════════
   ⚠️ Elles empruntent tout ce qui existe : le mur de familles (`.lib-niches-grille`,
   `.lib-fam-carte`) et les cartes de niche (`.lib-niche`) de la Bibliothèque. Seuls le
   fil d'Ariane et les deux cartes de choix sont propres à cet écran. */
.atelier-ni-fil {
  display: flex; align-items: center; gap: var(--e-8);
  font-size: var(--t-meta); color: var(--text-3);
  margin-bottom: var(--e-14);
}
.atelier-ni-back {
  display: inline-flex; align-items: center; gap: var(--e-6);
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--violet-light); font-size: var(--t-meta);
}
.atelier-ni-back:hover { color: var(--text); }
.atelier-ni-ici::before { content: '/'; margin-right: var(--e-8); color: var(--text-3); }

.atelier-duo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--e-10);
}
.atelier-choix {
  text-align: left; cursor: pointer;
  background: rgba(var(--th-voile), .03);
  border: 1px solid var(--border);
  border-radius: var(--r-carte);
  padding: var(--e-14) var(--e-16);
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose);
}
/* ⚠️⚠️ LE SURVOL NE DOIT PAS RESSEMBLER AU CHOIX. Amadou (02/09) : « lorsque je sélectionne
   une option et que je survole l'autre, ce n'est pas intuitif ». Et il avait raison au pixel :
   les deux posaient le MÊME fond (`--violet-tint`), seule la nuance du filet changeait —
   frôler l'option non choisie la faisait passer pour choisie. Le survol redevient neutre ;
   l'accent appartient à ce qui est retenu. C'est le motif de tout le site (`.nial-carte`,
   `.lib-niche`) : neutre au doigt, accent au choix. */
.atelier-choix:not(.on):hover { border-color: var(--border-mid); background: var(--bg-hover); }
.atelier-choix.on { border-color: var(--violet); background: var(--violet-tint); }
.atelier-choix-t { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); margin-bottom: var(--e-4); }
.atelier-choix-d { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-normal); }
.atelier-choix-d b { color: var(--text-2); font-weight: var(--fw-fort); }

/* La niche retenue se voit dans la grille. */
.lib-niche--on { border-color: var(--violet-light) !important; }

/* ══ DANS L'ATELIER, LES MÊMES CARTES EN PLUS PETIT ═══════════════════════════
   ⚠️⚠️ ON GARDE LES CARTES DE LA BIBLIOTHÈQUE — même dessin, même logo, même
   comportement — mais PAS leur taille. Là-bas elles montrent la photo d'un produit et
   méritent leur place ; ici elles ne servent qu'à choisir, et n'ont RIEN à afficher :
   mesuré sur la capture d'Amadou (01/09), cinq cartes par rangée, 4/5 de haut, pour un
   pavé vide. Il a demandé de les réduire « énormément ».
   ⚠️ La réduction est SCOPÉE à l'étape Niche : la Bibliothèque ne bouge pas d'un pixel. */
/* ⚠️⚠️ LE TROU EN FIN DE RANGÉE. Amadou (02/09) : « la disposition n'est pas bien
   alignée […] ça fait un effet centré, qui n'est pas une case vide. Ce n'est pas beau. »
   Avec `auto-fill` + `1fr`, les colonnes s'étirent pour remplir la largeur : la dernière
   rangée, incomplète, laissait une case béante à droite — 18 familles pour 9 colonnes.
   Colonnes à largeur FIXE + `justify-content: center` : la rangée incomplète se centre
   sous les autres au lieu de laisser un vide au bout.
   ⚠️⚠️⚠️ ET DE LA PLACE POUR LE SURVOL. « Lorsqu'on survole, étant donné que la carte
   monte, elle est coupée en haut. » La carte se lève de 3 px, et `.atelier-step-body` est
   en `overflow: hidden` — il le doit, c'est lui qui anime le dépliage. On ne peut pas lui
   rendre son débordement sans casser l'animation : on donne la place À L'INTÉRIEUR. */
/* /!\ L'ETAPE DECOR EST HABILLEE PAR LA MEME REGLE : ses cartes sont les memes, elles
   servent au meme geste — choisir. Deux tailles pour deux etapes du meme ecran, ce serait
   deux apparences a tenir. */
#atelier-step-1 .lib-niches-grille {
  /* ⚠️ 112 px n'est pas un espacement : c'est la TAILLE d'un composant. On lui donne son
     propre nom, dérivé de l'échelle — écrire `112px` ici aurait ajouté la n-ième valeur
     brute que toute la Bibliothèque sert à éviter. */
  --at-carte: calc(var(--e-28) * 4);
  /* ⚠️⚠️ ON QUITTE LA GRILLE POUR UN FLUX. Une grille ne centre PAS une rangée incomplète :
     `justify-content: center` centre le BLOC de colonnes, et la dernière rangée reste collée
     à gauche de ce bloc. Mesuré : 18 familles → 8 · 8 · 2, les deux dernières alignées à
     gauche. Un flux qui revient à la ligne centre CHAQUE rangée, la dernière comprise —
     c'est ce qu'Amadou décrit : « un effet centré, qui n'est pas une case vide ». */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--e-10);
  padding: var(--e-6) 0;
  margin-bottom: 0;
}
#atelier-step-1 .lib-niches-grille > * {
  flex: 0 0 var(--at-carte);
  width: var(--at-carte);
}
#atelier-step-1 .lib-fam-carte,
#atelier-step-1 .lib-niche {
  aspect-ratio: 1 / 1;
  padding: var(--e-10);
  border-radius: var(--r-md);
}
/* Le logo suit : 48 px dans une carte de 280 px passait ; dans une carte de 112, non. */
#atelier-step-1 .lib-fam-carte-logo {
  width: var(--e-32); height: var(--e-32);
  margin-bottom: var(--e-8);
  border-radius: var(--r-sm);
}
#atelier-step-1 .lib-fam-carte-nom { font-size: var(--t-mini); line-height: var(--lh-serre); }
#atelier-step-1 .lib-fam-carte-n   { font-size: var(--t-micro); }
/* ⚠️ LA COUVERTURE REVIENT (Amadou, 02/09) : « il faut qu'on voie les images de couverture
   des niches ». Je l'avais retirée le 01/09 en réduisant les cartes — mais réduire ne
   voulait pas dire vider. Même dessin que la Bibliothèque : la photo remplit la carte, le
   nom se pose sur le voile du bas. Seul le voile se resserre, la carte faisant 112 px. */
#atelier-step-1 .lib-niche-bas {
  padding: var(--e-16) var(--e-8) var(--e-6);
}
#atelier-step-1 .lib-niche-nom { font-size: var(--t-mini); line-height: var(--lh-serre); }
/* La carte neuve suit la taille des autres : dans un carré de 112 px, un padding de 16 et
   un texte de 13 ne laissaient plus rien au dessin — c'est ce qu'Amadou a vu. */
#atelier-step-1 .lib-niche--neuve { padding: var(--e-8); font-size: var(--t-mini); }
#atelier-step-1 .lib-niche--neuve svg { width: var(--e-20); height: var(--e-20); }
#atelier-step-1 .lib-niche--neuve > span { gap: var(--e-4); }
#atelier-step-1 .lib-niche-n   { font-size: var(--t-micro); }

/* ── Ambient espace (léger : halos violet/cyan + poussière d'étoiles) ── */
/* Couche 1 : poussière d'étoiles subtile */
body::before {
  content: '';
  position: fixed;
  inset: -8%;
  pointer-events: none;
  z-index: 0;
  opacity: var(--th-ambiance);
  background-image: var(--th-decor-loin);
  animation: velbo-derive-loin var(--th-derive-loin) linear infinite alternate;
  will-change: transform;
}

/* Couche 2 : halos radiaux violet/cyan + arc horizon (Aurora) */
body::after {
  content: '';
  position: fixed;
  inset: -8%;
  pointer-events: none;
  z-index: 0;
  opacity: var(--th-ambiance);
  background: var(--th-decor-pres);
  animation: velbo-derive-pres var(--th-derive-pres) ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes velbo-derive-loin {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-2.5%, 1.8%, 0); }
}
@keyframes velbo-derive-pres {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(1.8%, -1.2%, 0) scale(1.05); }
}
/* ⚠️ ON N'IMPOSE RIEN. Le système peut demander moins d'animations — on obéit, sans
   qu'Amadou ait à le redire au logiciel. « Apparence » offre le même interrupteur. */
@media (prefers-reduced-motion: reduce) {
  body::before, body::after { animation: none; }
}
[data-anim="off"] body::before, [data-anim="off"] body::after { animation: none; }

/* Anciens blobs neutralisés (on garde les nœuds HTML s'ils existent, juste invisibles) */
.ambient-blob { display: none; }

/* ── Couche 3 : système solaire SVG, fond translucide global ─────────── */

/* Ligne « horizon » fine au-dessus des halos.
   ⚠️ Elle est fixée à 16 % du bas, donc EN PLEIN dans le contenu, et son halo de 24 px
   en faisait un bandeau de ~48 px. Le caisson sombre de .app-content la masquait ;
   depuis qu'il est transparent, elle traverse les cartes. On la garde (elle donne
   l'horizon), mais assez discrète pour ne plus se lire à travers une carte. */
.app-shell::before {
  content: '';
  position: fixed;
  left: 8%;
  right: 8%;
  bottom: 16%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(var(--th-voile),0.10) 25%,
    rgba(var(--th-voile),0.16) 50%,
    rgba(var(--th-voile),0.10) 75%,
    transparent 100%);
  pointer-events: none;
  z-index: 0;
  box-shadow: 0 0 18px rgba(var(--th-voile),0.07);
}

/* ⚠️ LE « CIEL VIVANT » A ÉTÉ RETIRÉ (14/08). Une étoile filante, une fusée et un
   satellite traversaient le fond du site une fois ouvert. Le décor des thèmes porte
   maintenant l'ambiance à lui seul, et une animation permanente sur un outil de travail
   finit par gêner. Le rideau d'ouverture, lui, est intact : il joue une fois. */

/* ── Glassmorphism (carte glass subtile, Aurora) ─────── */
.glass-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}

/* ── Utility ─────────────────────────────────────────── */
.hidden { display: none !important; }
/* L'attribut HTML `hidden` doit TOUJOURS l'emporter. Sans ça, toute règle `.classe { display:… }`
   de spécificité égale placée plus bas écrase le `[hidden]` du navigateur → l'élément reste visible
   malgré `el.hidden = true` (bug vécu : le panneau de coloris qui ne se fermait pas). Règle standard
   des design systems (Normalize/Bootstrap). Rend inutiles les rustines ponctuelles `.x[hidden]`. */
[hidden] { display: none !important; }

/* ══════════════════════════════════════════════════════
   AURORA SYSTEM — composants partagés
   Référence : design_handoff_vintedup_remaster/screens/styles.css
   ══════════════════════════════════════════════════════ */

/* ── Sticky topbar globale (utilisée par chaque section) ── */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-18);
  padding: var(--e-20) var(--e-32);
  /* Hauteur MINIMALE, pas fixe : le titre est passé en 27 px et certains écrans
     ajoutent un chemin de retour au-dessus. Une hauteur figée les décapitait. */
  min-height: 76px;
  background: linear-gradient(180deg, var(--bg-sidebar), var(--cok-bg-2));
  backdrop-filter: blur(22px) saturate(150%);
  -webkit-backdrop-filter: blur(22px) saturate(150%);
  border-bottom: 1px solid var(--border);
}
.topbar-titles {
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
  min-width: 0;
  /* Le titre ne doit jamais passer SOUS la recherche : sur un écran étroit, la barre de
     droite grandit et venait recouvrir « Bibliothèque » (constaté à 900 px, MacBook).
     Il rétrécit d'abord, et se coupe proprement plutôt que de se superposer. */
  flex: 0 1 auto;
  overflow: hidden;
}
.topbar-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-right { min-width: 0; }
@media (max-width: 1100px) {
  /* Sous cette largeur la recherche prend ce qu'il lui faut, le titre s'efface. */
  .lib-search-top { max-width: 210px; }
}
@media (max-width: 820px) {
  #topbar-library .topbar-titles { display: none; }
}
/* Le titre de page porte l'écran : il annonce où l'on est, en grand, comme dans le
   prototype validé. Avant il faisait la même taille qu'un libellé de carte. */
.topbar-title {
  font-size: var(--t-display);
  font-weight: var(--fw-fort);
  color: var(--text);
  letter-spacing: -0.032em;
  line-height: var(--lh-un);
}
.topbar-subtitle {
  font-size: var(--t-base);
  font-weight: var(--fw-normal);
  color: var(--text-3);
  line-height: var(--lh-serre);
  margin-top: var(--e-6);
}
@media (max-width: 900px) { .topbar-title { font-size: var(--t-title); } }
/* Chemin de retour, pour les écrans qui n'ont plus de bouton dans la barre latérale
   (l'Historique, la fiche d'une vendeuse). Discret, au-dessus du titre. */
.topbar-back {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  align-self: flex-start;
  margin-bottom: var(--e-6);
  padding: var(--e-4) var(--e-8) var(--e-4) var(--e-6);
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-3);
  font-family: inherit;
  font-size: var(--t-base);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.topbar-back:hover { background: var(--bg-hover); color: var(--text); }
.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--e-12);
}
.save-indicator {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  font-size: var(--t-meta);
  color: var(--text-3);
}
.save-indicator-dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--text-3);
}
.save-indicator.saved .save-indicator-dot {
  background: var(--safe-text);
  box-shadow: 0 0 8px var(--safe-glow);
}

/* ── Card (glass subtil) — pattern partagé ──────────── */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-22) var(--e-24);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow: var(--shadow-card);
  position: relative;
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--e-18);
  gap: var(--e-12);
}
/* card-label inline (label uppercase 11px). NB : le .card-label « overlay sur image »
   est scopé à .card-wrapper plus haut dans ce fichier, donc pas de collision. */
.card-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  color: var(--text-3);
  letter-spacing: var(--ls-large);
  text-transform: uppercase;
  white-space: nowrap;
}
.card-meta {
  font-size: var(--t-mini);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex-shrink: 0;
}
.card-stack {
  display: flex;
  flex-direction: column;
  gap: var(--e-18);
}

/* ── Bouton ghost-sm (variant petit ghost) ──────────── */
.btn-ghost--sm {
  height: 28px;
  padding: 0 var(--e-10);
  font-size: var(--t-meta);
  border-radius: var(--r-sm);
}

/* ── Field label ─────────────────────────────────────── */
.field-label {
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
  margin-bottom: var(--e-10);
  display: flex;
  align-items: baseline;
  gap: var(--e-8);
}
.field-label .field-hint {
  font-size: var(--t-meta);
  font-weight: var(--fw-normal);
  color: var(--text-3);
}

/* ── Size selector (S / M / L) ───────────────────────── */
.size-row {
  display: inline-flex;
  gap: var(--e-6);
  /* ⚠️ ELLE NE REVENAIT PAS À LA LIGNE. Dix pastilles au plus sur ses produits (mesuré),
     mais « Petite XXS » à côté de « 80*120CM » suffit à sortir de l'écran. */
  flex-wrap: wrap;
}

/* ── Style chips ─────────────────────────────────── */
.style-chips-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
}
.style-chip {
  padding: var(--e-6) var(--e-14);
  border-radius: var(--r-xl);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile),0.025);
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi-vif);
}
.style-chip:hover { border-color: var(--violet-mid); color: var(--text); background: rgba(var(--th-accent-rgb),.06); }
.style-chip.active {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: rgba(var(--th-accent-rgb),.35);
}

/* ── Prix unique grand ───────────────────────────── */
.price-row--single { border: none !important; }
.price-amount--big .price-amount-sym { font-size: var(--t-title); }
.price-amount--big { font-size: var(--t-3xl); font-weight: 800; letter-spacing: -.03em; }
.price-main-input {
  background: transparent;
  border: none;
  outline: none;
  font-size: var(--t-3xl);
  font-weight: 800;
  letter-spacing: -.03em;
  color: inherit;
  width: 100%;
  min-width: 60px;
  max-width: 160px;
  text-align: center;
  -moz-appearance: textfield;
}
.price-main-input::-webkit-inner-spin-button,
.price-main-input::-webkit-outer-spin-button { -webkit-appearance: none; }
.price-main-input:focus { border-bottom: 1.5px solid var(--violet-mid); }
.price-main-input::placeholder { color: var(--text-3); font-weight: var(--fw-normal); font-size: var(--t-xl); }
.size-btn {
  width: 38px; height: 34px;
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.size-btn:hover { background: var(--bg-hover); color: var(--text); }
.size-btn.active {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: rgba(var(--th-accent-rgb),0.30);
}

/* ── Tier segmented (Volume / Premium / Luxe) ────────── */
.tier-seg {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--e-6);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-6);
}
.tier-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e-2);
  padding: var(--e-10);
  border-radius: var(--r-sm);
  background: transparent;
  border: none;
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.tier-opt:hover { background: rgba(var(--th-voile),0.04); color: var(--text); }
.tier-opt-name { font-size: var(--t-small); font-weight: var(--fw-moyen); }
.tier-opt-range {
  font-size: var(--t-mini);
  color: var(--text-3);
  font-weight: var(--fw-normal);
  font-variant-numeric: tabular-nums;
}
.tier-opt.active[data-tier="volume"] {
  background: var(--tier-volume-bg);
  color: var(--tier-volume-text);
}
.tier-opt.active[data-tier="volume"] .tier-opt-range {
  color: var(--tier-volume-text); opacity: 0.7;
}
.tier-opt.active[data-tier="premium"] {
  background: var(--tier-premium-bg);
  color: var(--tier-premium-text);
}
.tier-opt.active[data-tier="premium"] .tier-opt-range {
  color: var(--tier-premium-text); opacity: 0.7;
}
.tier-opt.active[data-tier="luxe"] {
  background: var(--tier-luxe-bg);
  color: var(--tier-luxe-text);
}
.tier-opt.active[data-tier="luxe"] .tier-opt-range {
  color: var(--tier-luxe-text); opacity: 0.7;
}

/* ── Mode rows (toggle row avec switch) ──────────────── */
.mode-stack {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
}
.mode-row {
  display: flex;
  align-items: center;
  gap: var(--e-12);
  padding: var(--e-14) var(--e-16);
  border-radius: var(--r-lg);
  background: linear-gradient(158deg, var(--cok-bg) 0%, rgba(var(--th-voile),0.01) 60%);
  border: 1px solid var(--border);
  box-shadow: inset 0 1px 0 rgba(var(--th-voile),0.04);
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
  cursor: pointer;
}
.mode-row:hover { border-color: var(--violet-mid); transform: translateY(-1px); }
.mode-row.on {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
}
.mode-row.on .mode-title,
.mode-row.on .mode-title-icon { color: var(--violet-soft); }

.mode-text { flex: 1; min-width: 0; }
.mode-title {
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
  display: flex;
  align-items: center;
  gap: var(--e-8);
}
.mode-title-icon { color: var(--text-3); flex-shrink: 0; }
.mode-sub {
  font-size: var(--t-meta);
  color: var(--text-3);
  margin-top: var(--e-2);
}

/* ── Textarea Aurora ─────────────────────────────────── */
.textarea { width: 100%;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  line-height: var(--lh-normal);
  resize: vertical;
  min-height: 78px;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose);
  outline: none }
.textarea:focus {
  border-color: rgba(var(--th-accent-rgb),0.5);
  background: rgba(var(--th-voile),0.04);
}
.textarea::placeholder { color: var(--text-3); }

/* ── Chips (instructions presets — pill rangée) ──────── */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
}

/* ── Generate block (CTA + status text) ──────────────── */
.generate-block {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}
.generate-status {
  text-align: center;
  font-size: var(--t-meta);
  color: var(--text-3);
  min-height: 16px;
}
.btn-generate-cost {
  font-size: var(--t-meta);
  font-weight: var(--fw-normal);
  padding: var(--e-2) var(--e-8);
  border-radius: var(--r-pilule);
  background: rgba(var(--th-voile),0.14);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  margin-left: var(--e-4);
}

/* ── Stack interne d'un block (chips + textarea) ─────── */
.instr-stack {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}

/* Switch (toggle on/off — utilisé dans les mode rows) */
.switch {
  width: 30px; height: 18px;
  border-radius: var(--r-pilule);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  position: relative;
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
  flex-shrink: 0;
}
.switch::after {
  content: '';
  position: absolute;
  top: 1px; left: 1px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--text-2);
  transition: left var(--d-base) var(--c-pose), background var(--d-fast) var(--c-pose);
}
.switch.on {
  background: var(--violet);
  border-color: transparent;
  box-shadow: 0 0 12px var(--violet-glow);
}
.switch.on::after { left: 13px; background: #fff; }
/* Si la switch contient déjà un thumb réel (.new-dress-thumb / .mode-toggle-thumb),
   on neutralise le pseudo-thumb pour éviter le double. */
.switch:not(:empty)::after { display: none; }

/* Le bouton mode-row peut être activé via .active (existant) ou .on (design).
   Quand actif, on aligne aussi la switch interne sans bouger les ::after déjà neutralisés
   plus haut — la switch existante a son propre fond géré par .btn-new-dress.active
   .new-dress-track etc. */
.mode-row.active {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
}
.mode-row.active .mode-title,
.mode-row.active .mode-title-icon { color: var(--violet-soft); }

/* ── App shell — deux panneaux arrondis posés sur le fond espace ─────── */
/* La coquille : barre latérale collée au bord, contenu à même le fond cosmique.
   Avant, le contenu vivait dans un grand caisson sombre posé sur le fond — ça
   « faisait trop noir » et ça écrasait l'effet verre des cartes. */
.app-shell {
  display: flex;
  gap: 0;
  height: 100vh;
  width: 100vw;
  padding: 0;
  overflow: hidden;
  position: relative;
  z-index: 1;
}

.app-content {
  flex: 1;
  overflow-y: auto;
  /* ⚠️ La place de l'ascenseur est RÉSERVÉE en permanence. Nos ascenseurs ne flottent
     pas (styler ::-webkit-scrollbar, plus haut, les rend « classiques ») : ils prennent
     donc 8 px de largeur. Les écrans qui tiennent en une hauteur — Studio, Messages —
     n'en ont pas, et étaient donc 8 px plus larges que les autres : toute l'interface
     sautait de côté en les ouvrant. C'était ça, « le petit décalage du Studio »
     (Amadou, 2026-07-30), mesuré à 1260 px contre 1268. */
  scrollbar-gutter: stable;
  position: relative;
  z-index: 1;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Section Messages : occupe exactement la hauteur visible (ne fait pas scroller toute la page).
   → la liste (gauche) et la conversation (droite) scrollent CHACUNE de leur côté,
     et la barre de chat reste fixe en bas. */
#section-messages { height: 100%; overflow: hidden; position: relative; }

.app-section {
  max-width: 2400px;
  margin: 0 auto;
  padding: var(--e-32) var(--e-32) 100px;
  display: flex;
  flex-direction: column;
  gap: var(--e-24);
}

/* Variante avec topbar sticky pleine largeur : la section laisse passer le topbar
   en pleine largeur, le contenu est constraint via .section-canvas. */
.app-section--with-topbar {
  max-width: none;
  margin: 0;
  padding: 0;
  gap: 0;
}
.section-canvas {
  max-width: 2400px;
  width: 100%;
  margin: 0 auto;
  padding: var(--e-28) var(--e-32) 100px;
  display: flex;
  flex-direction: column;
  gap: var(--e-22);
}

/* Sections « navigation » (grilles de cartes auto-fill) : pleine largeur sur très grand
   écran — les colonnes se multiplient au lieu de laisser des marges vides. */
#section-library .section-canvas,
#section-history .section-canvas,
#section-packs   .section-canvas,
#section-topday  .section-canvas { max-width: none; }

/* ⚠⚠ LES TROIS PORTES PRENNENT TOUT L'ÉCRAN. Amadou (04/09), capture en main : « cette
   espace mais améliore-le visuellement, il doit prendre toute la place ». Mesuré avant :
   trois cartes de 214 × 258 en haut à gauche d'un canevas de 1098 × 521 — 87 % de vide,
   et ça se lisait comme un écran pas fini.
   ⚠ LE PIED DE PAGE DE 100 px EST FAIT POUR UNE LISTE QUI DÉFILE. Sous trois portes qui
   vont jusqu'en bas, c'est un trou : on le ramène à l'espacement normal, ICI SEULEMENT. */
/* ⚠⚠⚠ SANS CETTE LIGNE, LES DEUX `flex: 1` EN DESSOUS NE FONT RIEN. Mesuré : la section
   est un bloc de hauteur AUTO (620 px de contenu) dans un `.app-content` de 900 px qui
   défile. Un `flex: 1` ne distribue que de la place LIBRE — dans un conteneur qui fait
   exactement la taille de son contenu, il n'y en a aucune, et les portes restaient au
   plancher des 288 px. `.app-content` a une hauteur DÉFINIE, donc `100 %` veut dire
   quelque chose ici. */
#section-packs { min-height: 100%; }
#section-packs .section-canvas { flex: 1 1 auto; min-height: 0; padding-bottom: var(--e-32); }

/* Generator stays in DOM at all times — moved off-screen instead of display:none */
.section-offscreen {
  position: fixed !important;
  left: -200vw !important;
  top: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* ── Sidebar — Aurora translucent panel ───────────────── */
:root { --sidebar-open: 232px; --sidebar-closed: 60px; }

.sidebar {
  width: var(--sidebar-open);
  min-width: var(--sidebar-open);
  height: 100%;
  background: linear-gradient(180deg, var(--bg-elevated), rgba(var(--th-voile),0.025));
  backdrop-filter: blur(16px) saturate(1.25);
  -webkit-backdrop-filter: blur(16px) saturate(1.25);
  border: 0;
  border-right: 1px solid var(--border);
  border-radius: 0;
  display: flex;
  flex-direction: column;
  transition: width var(--t-moyen) var(--c-pose), min-width var(--t-moyen) var(--c-pose);
  overflow: hidden;
  z-index: 50;
  flex-shrink: 0;
}
.sidebar.collapsed {
  width: var(--sidebar-closed);
  min-width: var(--sidebar-closed);
}

.sidebar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--e-18) var(--e-14) var(--e-14);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  gap: var(--e-8);
}

.sidebar-logo {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  overflow: hidden;
  flex: 1;
  padding: var(--e-4) var(--e-6);
  margin: calc(var(--e-4) * -1) calc(var(--e-6) * -1);
  border-radius: var(--r-md);
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  transition: background var(--d-fast) var(--c-pose);
}
.sidebar-logo:hover { background: var(--bg-hover); }
.sidebar-logo:active { transform: translateY(1px); }
.sidebar-logo:focus-visible { outline: 2px solid var(--violet-soft); outline-offset: 2px; }
.brand-mark {
  width: 34px; height: 34px;
  flex: 0 0 auto;
  /* Le halo de l'étoile déborde du cadre : c'est ce qui lui donne sa lumière. */
  filter: drop-shadow(0 4px 14px rgba(139,92,246,0.45));
  transition: transform var(--t-long) var(--pose, var(--c-pose)), filter var(--t-long) var(--c-pose);
}
.brand-mark svg { width: 100%; height: 100%; display: block; overflow: visible; }
/* Au survol, l'étoile file un peu plus loin — un clin d'œil, pas un manège. */
.sidebar-logo:hover .brand-mark {
  transform: translate(1.5px, -1.5px);
  filter: drop-shadow(0 6px 20px rgba(139,92,246,0.7));
}
/* Le nom : la même lumière que l'étoile, du blanc vers la lavande, et des lettres
   resserrées pour qu'il fasse bloc avec la marque au lieu de flotter à côté. */
.brand-word {
  font-size: var(--t-lead);
  font-weight: var(--fw-fort);
  letter-spacing: -0.028em;
  line-height: var(--lh-un);
  /* ⚠️ LE NOM ÉTAIT ÉCRIT EN BLANC-LAVANDE, EN DUR, et découpé dans le texte : sur un
     thème clair il devenait blanc sur papier, donc INVISIBLE — la marque du logiciel
     disparaissait. Vu à l'écran sur Sumi-e. Il part maintenant du texte du thème vers
     son accent : il garde son dégradé sur les onze, et il se lit sur les onze. */
  background: linear-gradient(105deg, var(--text) 0%, var(--text) 40%, var(--th-accent-clair) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  transition: opacity var(--t-moyen);
}
/* Barre repliée : il ne reste que la tuile, elle suffit à identifier le site. Le
   nom disparaît et la flèche passe SOUS la tuile — côte à côte dans 60 px, la
   tuile se faisait couper en deux. */
.sidebar.collapsed .sidebar-top { flex-direction: column; gap: var(--e-12); padding: var(--e-14) var(--e-8); }
.sidebar.collapsed .sidebar-logo { justify-content: center; flex: 0 0 auto; width: 100%; margin: 0; padding: var(--e-4) 0; }
.sidebar.collapsed .brand-word { opacity: 0; width: 0; overflow: hidden; pointer-events: none; }

.sidebar-toggle {
  flex-shrink: 0;
  width: 24px; height: 24px;
  border-radius: var(--r-xs);
  background: transparent;
  border: none;
  color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.sidebar-toggle:hover { background: var(--bg-hover); color: var(--text-2); }
.toggle-icon-open  { display: block; }
.toggle-icon-closed { display: none; }
.sidebar.collapsed .toggle-icon-open  { display: none; }
.sidebar.collapsed .toggle-icon-closed { display: block; }

/* ── Sélecteur boutique sidebar ── */
.sidebar-boutique {
  position: relative;
  padding: var(--e-8) var(--e-10);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.sidebar-boutique-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-8) var(--e-10);
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  transition: border-color var(--t-moyen), background var(--t-moyen);
  text-align: left;
}
.sidebar-boutique-btn:hover { border-color: var(--border-mid); background: rgba(var(--th-voile),0.04); }
.sidebar-boutique-name {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity var(--t-moyen);
}
.sidebar-boutique-caret { flex-shrink: 0; color: var(--text-3); }
.sidebar.collapsed .sidebar-boutique-name,
.sidebar.collapsed .sidebar-boutique-caret { opacity: 0; pointer-events: none; }

.sidebar-boutique-dropdown {
  position: absolute;
  left: 10px; right: 10px;
  top: calc(100% - 4px);
  z-index: 200;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 8px 28px rgba(var(--th-ombre),.4);
  max-height: 70vh;
  overflow-y: auto;
  padding: var(--e-4);
}
.sidebar-boutique-dropdown.hidden { display: none; }
.sidebar-boutique-opt {
  display: block;
  width: 100%;
  padding: var(--e-6) var(--e-12);
  text-align: left;
  border: none;
  background: none;
  color: var(--text);
  font-size: var(--t-meta);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background var(--t-bref);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: var(--lh-serre);
}
.sidebar-boutique-opt:hover { background: rgba(var(--th-voile),0.04); color: var(--text); }
.sidebar-boutique-opt.active { color: var(--violet-soft); font-weight: var(--fw-moyen); }
.sidebar-boutique-sep {
  height: 1px;
  background: var(--border);
  margin: var(--e-4) 0;
}
.sidebar-boutique-tier-header {
  padding: var(--e-6) var(--e-10) var(--e-2);
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  letter-spacing: .14em;
  color: var(--text-3);
  text-transform: uppercase;
}
.sidebar-boutique-all-tier {
  font-weight: var(--fw-gras);
  color: var(--text-1);
  font-size: var(--t-base);
  padding: var(--e-6) var(--e-12);
}
.sidebar-boutique-create { color: var(--text-3); display: flex; align-items: center; gap: var(--e-6); }
.sidebar-boutique-create:hover { color: var(--violet-soft); background: var(--violet-tint); }

.sidebar-nav {
  flex: 1;
  padding: var(--e-12) var(--e-8);
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
  overflow-y: auto;
  overflow-x: hidden;
}

.nav-divider {
  height: 1px;
  background: var(--border);
  margin: var(--e-8) var(--e-6);
  flex-shrink: 0;
}

.nav-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--e-12);
  height: 36px;
  padding: 0 var(--e-12);
  border-radius: var(--r-sm);
  border: none;
  background: transparent;
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
  text-align: left;
  position: relative;
}
.nav-item svg { flex-shrink: 0; color: currentColor; }
.nav-item > span:not(.nav-ic) {
  transition: opacity var(--t-moyen);
  overflow: hidden;
  flex: 1;
  text-overflow: ellipsis;
}
.sidebar.collapsed .nav-item > span:not(.nav-ic) { opacity: 0; pointer-events: none; }
.nav-item:hover:not(:disabled) {
  background: rgba(var(--th-voile),0.04);
  color: var(--text);
}
/* Actif : texte clair + icône violette + petit liseré gauche, JAMAIS de bloc plein */
.nav-item.active {
  background: transparent;
  color: var(--text);
  font-weight: var(--fw-moyen);
}
.nav-item.active svg { color: var(--violet-soft); }
.nav-item.active::before {
  content: '';
  position: absolute;
  left: -2px;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 16px;
  border-radius: 0 2px 2px 0;
  background: var(--violet-soft);
  box-shadow: 0 0 12px rgba(var(--th-accent-rgb),0.6);
}

/* ── Compacité de la barre latérale (refonte 2026-07-30) ─────────────────────
   Elle porte maintenant 12 entrées rangées en 5 groupes. Sur un MacBook 13" la
   hauteur utile tombe vers 700 px : sans ce resserrage, la Fabrique passait sous
   la ligne de flottaison et il fallait faire défiler pour la voir. */
.sidebar-nav { padding: var(--e-6) var(--e-8) var(--e-8); gap: var(--e-1); }
.nav-item { height: 32px; }
.sidebar-top { padding: var(--e-14) var(--e-12) var(--e-12); }
.sidebar-footer { padding: var(--e-8) var(--e-8) var(--e-12); gap: var(--e-2); }
.sidebar-etat { display: flex; align-items: center; justify-content: space-between; gap: var(--e-6); min-width: 0; }
.sidebar-etat .api-status { padding: var(--e-4) var(--e-2) var(--e-4) var(--e-10); min-width: 0; flex: 1 1 auto; gap: var(--e-8); }
.sidebar-etat .status-label { overflow: hidden; text-overflow: ellipsis; font-size: var(--t-mini); }
.sidebar-etat .cost-display { padding: var(--e-4) var(--e-8); flex: 0 0 auto; gap: var(--e-6); }
.sidebar-etat .cost-value { font-size: var(--t-mini); }
/* Le montant porte déjà son signe : l'icône « dollar » à côté est un doublon, et
   c'est elle qui faisait couper « Clés non configurées ». */
.sidebar-etat .cost-display svg { display: none; }
/* Repliée, les deux s'empilent : il n'y a plus la place côte à côte. */
.sidebar.collapsed .sidebar-etat { flex-direction: column; align-items: flex-start; gap: 0; }

/* Entrée « à venir » : visible pour qu'on sache que ça existe, éteinte pour qu'on
   n'essaie pas de cliquer. Le Mandataire est dans cet état depuis le 2026-07-30. */
/* ⚠️⚠️ L'ONGLET S'ATTÉNUE, MAIS PAS SA PASTILLE. Amadou (24/08) : « l'étiquette à venir
   n'est pas bonne, elle est en grise — elle doit être en rapport avec le thème ».
   Deux causes, et il fallait les deux : la pastille était peinte en GRIS NEUTRE
   (`--text-3` sur un voile), et l'`opacity: .42` posée sur tout l'onglet la délavait
   par-dessus. Un enfant ne peut PAS être plus opaque que son parent : lui écrire
   `opacity: 1` n'aurait rien changé. L'atténuation ne porte donc plus sur le bouton mais
   sur ce qui doit s'effacer — son icône et son nom. */
.nav-item--soon { cursor: not-allowed; }
/* ⚠️⚠️ ET L'ICÔNE COMPTE DANS LES DEUX FORMES QU'ELLE PREND. Amadou (27/08) : « le logo
   de l'onglet Contrôle n'est pas abaissé en opacité, ça doit être comme le Mandataire ».
   La règle ne visait que `.nav-ic` et les `span` : le Mandataire enveloppe son icône
   dans `<span class="nav-ic">`, Contrôle a un `<svg>` NU — ni l'un ni l'autre, donc son
   icône restait à pleine force à côté d'un nom délavé.
   ⚠️ Ce n'est pas Contrôle qui est mal écrit : sur les quinze onglets, DIX ont un `svg`
   nu et cinq seulement l'enveloppent. C'était la règle qui était trop étroite. On couvre
   les deux formes — sinon le prochain onglet « à venir » retombera dans le même trou,
   selon la façon dont son icône aura été écrite ce jour-là. */
.nav-item--soon > .nav-ic,
.nav-item--soon > svg,
.nav-item--soon > span:not(.nav-soon) { opacity: .42; }
.nav-item--soon:hover { background: transparent !important; color: var(--text-2) !important; }
.nav-soon {
  margin-left: auto;
  font-size: var(--t-micro);
  padding: var(--e-1) var(--e-8);
  border-radius: var(--r-pilule);
  /* Les jetons d'ACCENT, pas une teinte neutre : ils sont redéfinis par chacun des vingt
     thèmes, donc la pastille suit le thème sans qu'on ait à l'y penser thème par thème. */
  background: var(--violet-tint);
  color: var(--violet-light);
  white-space: nowrap;
  flex: 0 0 auto;
}
.sidebar.collapsed .nav-soon { display: none; }

/* ── Bascule Cockpit / Fabrique (2 parties de la sidebar) ───────────────── */
.nav-switch { display: flex;
  gap: var(--e-4);
  margin: 0 0 var(--e-10);
  flex-shrink: 0 }
.nav-switch button {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-6);
  border: none;
  background: transparent;
  color: var(--text-2);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  padding: var(--e-8) var(--e-6);
  border-radius: var(--r-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.nav-switch button svg { flex-shrink: 0; }
.nav-switch button.active { color: var(--text); }
.nav-switch button[data-part="cockpit"].active { background: linear-gradient(120deg,var(--violet-soft),var(--cyan)); }
.nav-switch button[data-part="fabrique"].active { background: linear-gradient(120deg,#8B5CFF,#6E5CFF); color: var(--sur-accent); }
.sidebar.collapsed .nav-switch { flex-direction: column; }
.sidebar.collapsed .nav-switch button span { display: none; }

.nav-part { display: flex; flex-direction: column; gap: var(--e-2); }
.nav-part[hidden] { display: none; }

/* Menu unifié : titres de groupe Cockpit / Fabrique (plus de bascule) */
/* Les intitulés de groupe RANGENT, ils ne crient pas : gris discret, jamais coloré.
   La couleur est réservée à l'onglet actif — sinon la barre a cinq accents et le
   regard ne sait plus où il est. */
.nav-group { font-size: var(--t-mini); font-weight: var(--fw-moyen); letter-spacing: var(--ls-leger); padding: var(--e-10) var(--e-12) var(--e-4); color: var(--text-3); }
.nav-group:first-child { padding-top: var(--e-2); }
.nav-group--cockpit { color: var(--text-3); }
.nav-group--fabrique { color: var(--text-3); }
.sidebar.collapsed .nav-group { height: 1px; padding: 0; margin: var(--e-8) var(--e-12); overflow: hidden; color: transparent; background: rgba(var(--th-voile),.08); border-top: none; }

/* Un seul accent pour toute la barre : le violet-bleu. Les deux accents (turquoise
   Cockpit / violet Fabrique) disaient au regard qu'il y avait deux logiciels. */
.sidebar { --nav-accent: var(--violet-soft); }
.sidebar.mode-cockpit  { --nav-accent: var(--violet-soft); }
.sidebar.mode-fabrique { --nav-accent: var(--violet-soft); }
.nav-part[data-part="cockpit"]  { --nav-accent: var(--violet-soft); }
.nav-part[data-part="fabrique"] { --nav-accent: var(--violet-soft); }
.nav-item.active svg { color: var(--nav-accent); }
.nav-item.active::before { background: var(--nav-accent); box-shadow: 0 0 12px color-mix(in srgb, var(--nav-accent) 55%, transparent); }

/* ══════════ COCKPIT — vues de supervision (widgets validés, identité violet-bleu) ══════════ */
/* Tout est scopé sous .cok avec des classes préfixées cok-* : zéro collision avec le reste du site. */
/* ══════════════════════════════════════════════════════════════════════════
   LES JETONS DU COCKPIT, DISPONIBLES PARTOUT
   ⚠️⚠️ Ils n'étaient déclarés que dans `.cok`. Or plusieurs écrans les utilisent
   SANS être dans un `.cok` — les cartes de brouillon, par exemple, vivent dans
   `dcard-grid › drafts-detail › drafts-split › section-canvas`. La variable ne s'y
   résolvait donc pas, et chaque propriété retombait sur sa valeur initiale :
     • `border-color` → `currentColor`, la couleur du TEXTE : le fameux contour blanc
       des cartes déjà déposées sur Vinted, que j'ai cherché pendant trois corrections ;
     • `color` → hérité, donc un texte secondaire affiché en blanc plein ;
     • `background` → transparent.
   ⚠️ Rien de tout ça ne se signale : pas d'erreur console, pas de règle barrée dans
   l'inspecteur. La page s'affiche, simplement fausse.
   On les remonte donc ici. `.cok` les redéclare à l'identique juste après et garde
   la main : rien ne change à l'intérieur du cockpit, tout se répare à l'extérieur.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  --cok-accent: var(--violet-soft);
  --cok-accent-bg: rgba(var(--th-accent-rgb),.20);
  --cok-accent-solid: var(--violet);
  --cok-green: var(--green);
  --cok-green-bg: rgba(93,202,165,.16);
  --cok-warn: var(--amber);
  --cok-warn-bg: rgba(230,162,60,.16);
  --cok-red: var(--red);
  --cok-red-bg: rgba(226,75,74,.18);
  --cok-blue: var(--cyan);
  --cok-blue-bg: rgba(var(--th-second-rgb),.18);
  --cok-amber: var(--amber);
  --cok-border: var(--border);   /* 0,125 contre 0,115 d'opacité : un pour cent d'écart sur un filet, invisible à l'œil, mais deux noms à tenir d'accord */
  --cok-border-2: rgba(var(--th-trait),.21);
  /* ⚠️⚠️ CE JETON A ÉTÉ UNE FAUTE, ET LA MESURE L'A DIT. `rgba(--th-trait, .34)` : un
     même alpha ne vaut PAS la même chose selon la clarté du fond — mesuré sur les 15
     thèmes, la silhouette tombait à 1,19 sur sylve et 1,33 sur médina, c'est-à-dire
     invisible, sur HUIT thèmes. C'est exactement le piège déjà consigné : « les fonds
     mentent selon la clarté ». Un ouvrier qui dort doit rester DISCRET, pas absent :
     on prend donc le jeton de texte le plus sourd, que le socle garantit lisible sur
     les seize thèmes, plutôt qu'un filet dilué au jugé. */
  --cok-inactif: var(--cok-text-3);
  --cok-line: var(--cok-border);
  --cok-bg: rgba(var(--th-voile),.035);
  --cok-bg-2: rgba(var(--th-voile),.02);
  --cok-text-1: var(--cok-text);
  --cok-card: var(--surface-2);   /* rgba(var(--th-voile),.055) et rgba(var(--th-voile),0.055) : LA MÊME couleur, deux orthographes — mon passage sur les couleurs les avait ratées pour cette seule raison */
  --cok-text: var(--text);
  --cok-text-2: var(--text-2);
  --cok-text-3: var(--text-3);
}

.cok {
  --cok-accent: var(--violet-soft); --cok-accent-bg:var(--violet-tint); --cok-accent-solid: var(--violet);
  --cok-green: var(--green); --cok-green-bg:var(--safe-bg);
  --cok-warn: var(--amber);  --cok-warn-bg:var(--moy-bg);
  --cok-red: var(--red);   --cok-red-bg:var(--ose-bg);
  --cok-blue: var(--cyan);  --cok-blue-bg:var(--cyan-tint);
  --cok-amber: var(--amber);
  /* ⚠️⚠️ GRIS, PAS BLANC. Amadou (09/08) : « le contour doit être gris transparent,
     il ne doit pas être blanc ». `rgba(var(--th-voile),.09)` est du BLANC transparent :
     sur le fond violet sombre, le liseré tire vers le clair et brille — surtout à
     côté d'une photo. Un gris légèrement bleuté, à opacité plus haute pour garder la
     même présence, donne un trait qui pose la carte sans l'éclairer.
     ⚠️⚠️ ET L'ALPHA RESTE BASSE. Premier essai : je l'avais MONTÉE (.09 → .20) en
     croyant compenser le passage au gris — « à intensité égale, un gris a besoin de
     plus d'opacité ». Le raisonnement est juste dans l'absolu et faux ici : le défaut
     n'était pas que le trait manquait de présence, c'est qu'il en avait TROP. Les
     contours sont donc devenus deux fois plus visibles qu'avant, et Amadou les voyait
     toujours — en plus marqué. On garde la couleur grise et on redescend sous
     l'intensité d'origine : un contour doit poser la carte, pas la souligner. */
  --cok-border: var(--border);   /* 0,125 contre 0,115 d'opacité : un pour cent d'écart sur un filet, invisible à l'œil, mais deux noms à tenir d'accord */ --cok-border-2:var(--border-mid);
  /* ⚠️⚠️ CES QUATRE-LÀ ÉTAIENT UTILISÉES ET JAMAIS DÉFINIES. C'était ÇA, le contour
     blanc qu'Amadou voyait depuis le début, et pourquoi je ne le reproduisais jamais :
     `.dcard-vinted` (une carte de brouillon déjà déposée sur Vinted) repose sa bordure
     avec `color-mix(… var(--cok-line))`. Une variable inexistante rend la déclaration
     invalide « au calcul », et `border-color` retombe alors sur sa valeur initiale —
     `currentColor`, c'est-à-dire LA COULEUR DU TEXTE. Un liseré quasi blanc, donc, et
     uniquement sur les cartes portant « Brouillon sur Vinted » : toutes mes cartes
     d'essai étaient « Prête à publier », sans cette classe.
     ⚠️ Une variable CSS manquante ne se voit NULLE PART : pas d'erreur, pas de règle
     barrée dans l'inspecteur, la page s'affiche. Elle se traque en comparant les
     `var(--x)` aux `--x:` du fichier.
     Les trois autres tombaient pareil : `background` devenait transparent, `color`
     héritait. Valeurs alignées sur les jetons voisins, aucune invention. */
  /* ⚠️⚠️⚠️ ET CETTE RÉPARATION-LÀ AVAIT ÉTÉ ÉCRITE DE TRAVERS — retrouvé le 15/08.
     Le diagnostic ci-dessus était juste, mais le code posé disait
     `--cok-bg: var(--cok-bg);` : chaque alias se pointait LUI-MÊME. Un cycle rend la
     propriété invalide « au calcul » — la variable vaut donc le vide, exactement comme
     avant la réparation. HUIT alias, **129 sites d'appel** : autant de fonds et de
     filets qui ne se dessinaient pas, dans les sept thèmes. Le bouton « SHEIN » du
     panneau droit de Messages n'était qu'un mot flottant.
     ⚠️ LA LEÇON : un `var(--x)` DANS la déclaration de `--x` a l'air d'un repli. Ce
     n'en est pas un — c'est un cycle. Un repli s'écrit `var(--autre, valeur)`.
     Valeurs empruntées aux jetons voisins, aucune inventée. */
  --cok-line: var(--cok-border);        /* même trait que --cok-border */
  --cok-bg:var(--surface);          /* fond de bloc, un cran sous --cok-card */
  --cok-bg-2:var(--surface-2);         /* fond creux (vignette vide, cartouche) */
  --cok-text-1:var(--cok-text);             /* le texte principal du cockpit */
  --cok-card: var(--surface-2);   /* rgba(var(--th-voile),.055) et rgba(var(--th-voile),0.055) : LA MÊME couleur, deux orthographes — mon passage sur les couleurs les avait ratées pour cette seule raison */
  --cok-text: var(--text); --cok-text-2: var(--text-2); --cok-text-3: var(--text-3);
  color:var(--cok-text); font-size:var(--t-small); line-height:var(--lh-normal);
}
.cok .num { font-variant-numeric:tabular-nums; }

.cok-metrics { display:grid; grid-template-columns:repeat(auto-fit,minmax(152px,1fr)); gap:var(--e-14); margin-bottom:var(--e-28); }
.cok-metric { backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px) }
.cok-metric .l { font-size:var(--t-base); color:var(--cok-text-2); display:flex; align-items:center; gap:var(--e-8); }
.cok-metric .v { font-size:var(--t-xl); font-weight:var(--fw-fort); margin-top:var(--e-8); }
.cok-metric.warn  { border-color:rgba(240,194,90,.25); } .cok-metric.warn .l,  .cok-metric.warn .v  { color:var(--cok-warn); }
.cok-metric.red   { border-color:rgba(240,113,90,.25); } .cok-metric.red .l,   .cok-metric.red .v   { color:var(--cok-red); }
.cok-metric.green { border-color:rgba(63,209,155,.25); } .cok-metric.green .l, .cok-metric.green .v { color:var(--cok-green); }

/* ⚠️ PAS D'ICÔNE DANS LES TITRES DE SECTION. Amadou (15/08) : « enlève les logos à
   côté des étapes… reste sobre, là il y en a beaucoup trop ». Et le site lui donnait
   déjà raison : sur dix-neuf titres `.cok-sec`, HUIT n'en portaient AUCUNE. Ce n'était
   donc pas un parti pris mais une incohérence — la moitié des écrans suivait une règle,
   l'autre moitié une autre. Les onze icônes restantes sont parties avec.
   ⚠️ Le `gap` reste : un titre peut encore porter une pastille ou un badge à sa droite,
   et sans lui ils se colleraient au texte. C'est `display:flex` qui aligne ça, pas
   l'icône disparue. */
.cok-sec { font-size:var(--t-body); font-weight:var(--fw-fort); margin:var(--e-28) 0 var(--e-14); display:flex; align-items:center; gap:var(--e-10); color:var(--cok-text); }
.cok-subt { color:var(--cok-text-2); font-size:var(--t-base); margin:calc(var(--e-4) * -1) 0 var(--e-14); }

.cok-list { border:1px solid var(--cok-border); border-radius: var(--r-lg); overflow:hidden; background:var(--cok-card); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-li { display:flex; align-items:center; gap:var(--e-14); padding:var(--e-14) var(--e-16); border-bottom:1px solid var(--cok-border); transition:background var(--t-bref); }
.cok-li:last-child { border-bottom:0; }
/* ── CE QUI T'ATTEND ──────────────────────────────────────────────────────────
   Quatre lignes visibles, le reste défile, et un fondu en bas dit qu'il y en a
   encore — il disparaît dès qu'on est arrivé en bas. Chaque ligne se ferme d'une
   croix (Amadou, 2026-07-30 : « je dois pouvoir supprimer ce qui m'attend »). */
#ov-attend {
  /* ⚠️ Hauteur RÉSERVÉE dès le départ. Au rechargement, le bloc naissait à une ligne
     (« Lecture… ») puis passait à quatre : tout ce qui est en dessous — les résultats,
     les barres, l'historique — sautait d'un coup. C'était ça, le petit bug d'ouverture
     (Amadou, 2026-07-30). Il occupe maintenant sa place avant même d'avoir son contenu. */
  min-height: 268px;
  max-height: 268px;              /* 4 lignes de 67 px */
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
}
#ov-attend.deborde {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 42px), transparent);
          mask-image: linear-gradient(to bottom, #000 calc(100% - 42px), transparent);
}
#ov-attend::-webkit-scrollbar { width: 6px; }
#ov-attend::-webkit-scrollbar-thumb { background: rgba(var(--th-voile),.10); border-radius: var(--r-sm); }

.cok-att { position: relative; }
/* La croix n'apparaît qu'au survol de SA ligne : au repos, la liste reste calme. */
.cok-x {
  flex: 0 0 auto;
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--cok-text-3);
  cursor: pointer;
  opacity: 0;
  transform: scale(.85);
  transition: opacity var(--t-bref) var(--c-pose), transform var(--t-bref) var(--c-pose),
              background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.cok-att:hover .cok-x, .cok-x:focus-visible { opacity: 1; transform: scale(1); }
.cok-x:hover { background: var(--cok-red-bg); color: var(--cok-red); }
.cok-x:active { transform: scale(.9); }
.cok-x:focus-visible { outline: 2px solid var(--violet-soft); outline-offset: 1px; }
/* Le départ : elle glisse vers la droite et se referme. */
.cok-att.part {
  animation: velbo-ecarte var(--t-moyen) var(--ease) forwards;
  pointer-events: none;
}
@keyframes velbo-ecarte {
  to { opacity: 0; transform: translateX(28px); max-height: 0;
       padding-top: 0; padding-bottom: 0; border-width: 0; }
}
.cok-att-repli {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-12);
  padding: var(--e-10) var(--e-16);
  border-top: 1px solid var(--cok-border);
  font-size: var(--t-meta); color: var(--cok-text-3);
}

/* Le choix d'identité, quand l'écran mélange encore deux propriétaires. */
.cok-cloison { gap:var(--e-10); flex-wrap:wrap; border-left:3px solid var(--cok-warn); }
.cok-cloison .cok-txt { flex:1 1 260px; }

/* Une ligne qui mène quelque part le dit : elle s'éclaire au survol. */
.cok-li-clic { cursor:pointer; }
.cok-li-clic:hover { background:rgba(var(--th-voile),.04); }
.cok-txt { flex:1; min-width:0; }
.cok-t { font-weight:var(--fw-moyen); color:var(--cok-text); }
.cok-t .cok-muted { color:var(--cok-text-3); font-weight:var(--fw-normal); }
.cok-s { font-size:var(--t-base); color:var(--cok-text-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* Une étiquette sans couleur d'état reste une étiquette : elle garde son fond neutre,
   sinon elle flotte dans le vide (cas « sans visage »). */
.cok-badge { font-size:var(--t-meta); font-weight:var(--fw-fort); padding:var(--e-4) var(--e-12); border-radius: var(--r-pilule); white-space:nowrap; background:var(--bg-elevated); color:var(--cok-text-3); }
/* « à réveiller » est un bouton, pas une étiquette : il doit se voir cliquable. */
button.cok-badge { font-family:inherit; border:1px solid transparent; cursor:pointer; transition: var(--transi-vif); }
button.cok-badge:hover:not(:disabled) { filter:brightness(1.25); border-color:currentColor; }
button.cok-badge:disabled { opacity:.6; cursor:progress; }
.cok-badge.g    { background:var(--cok-green-bg); color:var(--cok-green); }
.cok-badge.w    { background:var(--cok-warn-bg);  color:var(--cok-warn); }
.cok-badge.r    { background:var(--cok-red-bg);   color:var(--cok-red); }
.cok-badge.b    { background:var(--cok-blue-bg);  color:var(--cok-blue); }
.cok-badge.gray { background:var(--bg-hover); color:var(--cok-text-2); }

/* ⚠️ NE RESTE ICI QUE CE QUI N'EST PAS DANS LE COMPOSANT. La forme — police, taille,
   graisse, retrait, arrondi, filet, curseur — vient de `.v-btn`, déclaré plus bas et
   auquel `.cok-btn` est raccroché. Redire ces valeurs ici les figerait : changer le
   jeton `--btn-pad-h` n'aurait plus aucun effet, puisque cette ligne gagnerait. */
.cok-btn { background:var(--surface); color:var(--cok-text); transition: var(--transi-vif); white-space:nowrap; }
/* ⚠️⚠️ TROIS EXCLUSIONS, ET CHACUNE ÉVITE UN VRAI DÉGÂT :
   · `:not(.pri)` — le bouton primaire n'est protégé que par sa POSITION (`.cok-btn.pri`
     est écrit juste en dessous, à poids égal). Trois `:not()` font monter ce sélecteur
     de (0,2,0) à (0,5,0) : sans cette exclusion il battrait `.pri`, et les boutons
     violets perdraient leur aplat.
   · `:not(:disabled)` — `:hover` matche un `<button disabled>`. « Monter une orpheline »,
     éteint, s'allumait en violet avec du texte blanc.
   · `:not(.danger):not(.src-px-danger)` — le rouge est un SENS, pas une décoration. Le
     `color: var(--sur-accent)` passait devant (0,2,0 contre 0,1,0) et « Supprimer » perdait son rouge. */
/* ⚠️⚠️⚠️ `.danger` NE PEIGNAIT RIEN. Trois boutons du site le portent — « Terminer la
   formation », « Retirer ce profil », « Retirer cette sortie » — et il n'existait AUCUNE
   règle pour lui : le nom ne servait qu'à figurer dans les exclusions du survol
   ci-dessous, c'est-à-dire à ne PAS être repeint. Trois boutons qui effacent avaient donc
   exactement l'apparence des boutons ordinaires.
   Trouvé le 22/08 en cherchant pourquoi mon « Retirer » perdait sa couleur : il ne l'a
   jamais eue. On donne enfin son sens au nom qui existe, avec les jetons qui existent —
   plutôt que d'en inventer un quatrième dans son coin (c'était mon premier réflexe, et
   c'est exactement ce que la bibliothèque interdit). */
.cok-btn.danger { color: var(--red); border-color: var(--danger-bord); }
.cok-btn.danger:hover { background: var(--danger-fond); border-color: var(--red); }

.cok-btn:hover:not(.pri):not(:disabled):not(.danger):not(.src-px-danger) {
  background: var(--survol-fond); border-color: var(--survol-bord); color: var(--text);
}
/* (.cok-btn.pri : passé dans le composant, sous `.v-btn--pri`.) */
.cok-btn.pri:hover { filter:brightness(1.2); }

.cok-card { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-18) var(--e-20); margin-bottom:var(--e-12); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-cardrow { display:flex; align-items:center; justify-content:space-between; gap:var(--e-14); }

.cok-chips { display:flex; gap:var(--e-8); margin-bottom:var(--e-14); flex-wrap:wrap; }
.cok-chip { font-size:var(--t-base); padding:var(--e-8) var(--e-14); border-radius: var(--r-pilule); color:var(--cok-text-2); cursor:pointer; background:var(--cok-card); border:1px solid var(--cok-border); }
.cok-chip.on { background:var(--cok-accent-bg); color:var(--cok-accent); font-weight:var(--fw-moyen); border-color:transparent; }
/* Cadence : les crans INACTIFS restent neutres (bouton basique) ; SEUL l'actif prend sa couleur
   (prudent vert · normal violet par défaut · rapide ambre · turbo rouge). */
.cok-chip.cad.on[data-cad="prudent"] { background:rgba(52,211,153,.16); color:var(--green); border-color:transparent; }
.cok-chip.cad.on[data-cad="rapide"]  { background:rgba(240,176,85,.16); color:var(--amber); border-color:transparent; }
.cok-chip.cad.on[data-cad="turbo"]   { background:rgba(248,113,113,.16); color:var(--red); border-color:transparent; }

.cok-bars { display:flex; align-items:flex-end; gap:var(--e-10); height:100px; }
.cok-bars i { flex:1; background:var(--cok-accent-bg); border-radius:6px 6px 0 0; }
.cok-bars i.hi { background:linear-gradient(180deg,var(--cok-accent),transparent); }

.cok input[type=range] { width:100%; accent-color:var(--cok-accent-solid); margin:var(--e-6) 0; }
.cok-rng { display:flex; justify-content:space-between; font-size:var(--t-meta); color:var(--cok-text-3); }
.cok-toggle { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); padding:var(--e-12) 0; border-bottom:1px solid var(--cok-border); color:var(--cok-text); }
.cok-toggle:last-child { border-bottom:0; }

.cok-master { display:flex; gap:var(--e-4); background:var(--surface); border:1px solid rgba(var(--th-voile),.07); border-radius: var(--r-pilule); padding:var(--e-4); }
.cok-reload { display:inline-flex; align-items:center; gap:var(--e-6); background:var(--cok-card); color:var(--cok-text-2); border:1px solid var(--cok-border); border-radius: var(--r-pilule); padding:var(--e-6) var(--e-14); font-size:var(--t-base); font-weight:var(--fw-moyen); font-family:inherit; cursor:pointer; transition:background var(--t-bref), color var(--t-bref), border-color var(--t-bref); }
.cok-reload:hover { background:rgba(var(--th-accent-rgb),.14); color:var(--cok-text); border-color:var(--cok-accent); }
.cok-reload svg { width:14px; height:14px; }
.cok-master span { padding:var(--e-6) var(--e-16); border-radius: var(--r-pilule); font-size:var(--t-base); font-weight:var(--fw-moyen); cursor:pointer; color:var(--text-3); }
.cok-master span.on { background:rgba(63,209,155,.14); color:var(--green); }

.cok-feed { display:flex; flex-direction:column; border:1px solid var(--cok-border); border-radius: var(--r-lg); overflow:hidden; background:var(--cok-card); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-feed .row { display:flex; align-items:center; gap:var(--e-14); padding:var(--e-10) var(--e-14); color:var(--cok-text); border-top:1px solid var(--cok-border); font-size:var(--t-base); }
.cok-feed .row:first-child { border-top:0; }
.cok-feed .tm { font-size:var(--t-meta); color:var(--cok-text-3); width:44px; flex-shrink:0; }

/* Barre de progression (Batch en cours) */
.cok-bar { height:6px; background:rgba(var(--th-voile),.08); border-radius: var(--r-pilule); overflow:hidden; margin-top:var(--e-10); }
.cok-bar > i { display:block; height:100%; background:var(--cok-accent); border-radius: var(--r-pilule); }

/* Badge « en cours » de l'onglet Annonces (Cockpit) */
.nav-item > span.nav-live { flex:0 0 auto; overflow:visible; margin-left:var(--e-6); font-size:var(--t-micro); font-weight:var(--fw-moyen); background:var(--violet-tint); color:var(--violet-light); border-radius: var(--r-pilule); padding:var(--e-2) var(--e-8); text-transform:none; }
.sidebar.collapsed .nav-item > span.nav-live { display:none; }
/* La pastille « à venir » ne doit pas se comporter comme le libellé de l'onglet
   (qui, lui, prend toute la place restante) — sinon elle écrase le nom. */
.nav-item > span.nav-soon { flex:0 0 auto; overflow:visible; text-transform:none; }

/* Vue d'ensemble v3 : entête résultats + toggle, objectif, capteurs, 2 colonnes */
.cok-results-head { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:var(--e-10); margin-bottom:var(--e-14); }
.cok-goal { display:flex; align-items:center; gap:var(--e-16); background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-12) var(--e-18); margin:var(--e-16) 0; backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-cap-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr)); gap:var(--e-14); margin-bottom:var(--e-4); }
/* Deux cartes : elles se partagent la largeur au lieu de s'étirer chacune sur un tiers
   d'écran vide (auto-fit aurait laissé une colonne fantôme sur grand écran). */
.cok-cap-grid--2 { grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); max-width:1000px; }
.cok-cap { backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px) }
.cok-cap-head { display:flex; align-items:baseline; justify-content:space-between; margin-bottom:var(--e-8); }
.cok-cap-head > span { font-weight:var(--fw-fort); font-size:var(--t-small); color:var(--cok-text); display:flex; align-items:center; gap:var(--e-8); }
.cok-cap-head > span svg { color:var(--cok-accent); flex-shrink:0; }
.cok-cap-head > b { font-size:var(--t-title); font-weight:var(--fw-fort); color:var(--cok-accent); }
.cok-cap-row { display:flex; align-items:center; justify-content:space-between; padding:var(--e-8) 0; font-size:var(--t-base); color:var(--cok-text-2); border-top:1px solid var(--cok-border); }
.cok-cap-row:first-of-type { border-top:0; }
.cok-cap-row .num { color:var(--cok-text); font-weight:var(--fw-moyen); }
.cok-2col { display:grid; grid-template-columns:3fr 2fr; gap:44px; margin-top:var(--e-8); }
@media (max-width:900px){ .cok-2col { grid-template-columns:1fr; gap:var(--e-20); } }
.cok-note { font-size:var(--t-meta); color:var(--cok-text-3); margin-top:var(--e-8); }

/* ── SANTÉ DU PARC (Vendeuses › Santé) ─────────────────────────────────────── */
/* Les tuiles du haut SONT le filtre : cliquer « Bannies » ne montre que celles-là. */
.cok-sante-tuiles { margin-bottom:var(--e-20); }
/* `transform` doit rester dans la transition : ces tuiles héritent du léger soulèvement
   au survol des autres cartes, mais leur propre règle l'aurait rendu sec. */
.cok-metric.cok-sante-t { text-align:left; font-family:inherit; cursor:pointer; color:var(--cok-text); transition:transform var(--t-moyen) var(--c-pose), border-color var(--t-bref), background var(--t-bref); }
.cok-metric.cok-sante-t:hover { border-color:var(--cok-border-2); }
.cok-metric.cok-sante-t.on { border-color:var(--cok-accent); box-shadow:inset 0 0 0 1px var(--cok-accent-bg); }
.cok-sante-pion { width:8px; height:8px; border-radius:50%; flex:0 0 auto; background:var(--cok-text-3); }
.cok-sante-pion.g { background:var(--cok-green); }
.cok-sante-pion.w { background:var(--cok-warn); }
.cok-sante-pion.r { background:var(--cok-red); }
.cok-sante-fleche { color:var(--cok-text-3); flex:0 0 auto; display:flex; opacity:0; transition:opacity var(--t-bref); }
.cok-li-clic:hover .cok-sante-fleche { opacity:1; }

/* ── L'ESPACE D'UNE VENDEUSE (la profondeur) ───────────────────────────────── */
.vd-2col { display:grid; grid-template-columns:1fr 1fr; gap:var(--e-16); margin-bottom:var(--e-8); align-items:start; }
@media (max-width:1000px) { .vd-2col { grid-template-columns:1fr; } }
/* Les trois vues : portrait, jamais étirées, jamais déformées. */
.vd-vues { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--e-10); margin:var(--e-14) 0 var(--e-4); }
.vd-vue { margin:0; border:1px solid var(--cok-border); border-radius: var(--r-md); overflow:hidden; background:var(--surface); }
.vd-vue img { width:100%; aspect-ratio:3/4; object-fit:cover; display:block; }
.vd-vue figcaption { padding:var(--e-6) var(--e-10); font-size:var(--t-meta); color:var(--cok-text-2); }

/* ── Le panneau de fabrication ────────────────────────────────────────────────────
   Il vit dans la fiche de la MODÈLE (le seul lieu de fabrication). Il emprunte ce qui
   existe — `cok-btn`, `cok-note`, `field-label`, `lib-res-grille`, `lib-res-v`,
   `src-gab`, `vd-vue` — on ne pose ici que sa mise en page. */
.vd-atl-ouvre { margin-top: var(--e-12); }
.mdl-atl-go { width: 100%; justify-content: center; margin-top: var(--e-10); }
/* Pendant qu'une modèle arrive : le bouton cède sa place à l'étape en cours. Même
   hauteur et même largeur que lui, pour que la fiche ne saute pas sous les yeux.
   Le rond qui tourne est celui de l'Atelier (`.atelier-spinner`), en plus petit. */
.mdl-atl-encours {
  /* 38px : la hauteur exacte de `.atelier-gen-btn`, le bouton qu'on remplace. Il n'y a
     pas de jeton de hauteur dans la bibliothèque — on recopie donc la valeur de ce
     qu'on doit égaler, et on dit d'où elle vient. */
  width: 100%; margin-top: var(--e-10); height: 38px;
  display: flex; align-items: center; justify-content: center; gap: var(--e-10);
  border: var(--e-1) solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--text-2); font-size: var(--t-base); font-weight: var(--fw-moyen);
}
.mdl-atl-encours .atelier-spinner { width: var(--e-16); height: var(--e-16); }
/* ── Le contenu du GRAND panneau ─────────────────────────────────────────────────
   La coquille vient de `.lib-picker*` (le sélecteur de robes de la Génération) : on ne
   pose ici que la mise en page interne des trois volets. Le corps du panneau défile
   déjà tout seul, plus besoin de plafonner la grille comme dans l'ancienne version
   dépliée sous les vues. */
.mdl-panel-sous { font-size:var(--t-meta); font-weight:var(--fw-normal); color:var(--text-3); margin-left:var(--e-10); }
.mdl-panel-onglets { display:flex; gap:var(--e-6); flex-wrap:wrap; margin-bottom:var(--e-14); }
.mdl-panel-2col { display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,1fr); gap:var(--e-22); align-items:start; }
@media (max-width:760px){ .mdl-panel-2col { grid-template-columns:minmax(0,1fr); } }
.mdl-atl-vues { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--e-10); }
.mdl-panel-2col .field-label { margin-bottom:var(--e-8); }
#mdl-panel-footer { flex-wrap:wrap; }
/* Les visages, PLUS GROS que dans le Sourcing : ici on juge une silhouette avant de la
   choisir, pas on inventorie un stock. Le grand panneau donne la place pour ça. */
#mdl-panel-body .lib-res-grille { grid-template-columns:repeat(auto-fill,minmax(158px,1fr)); gap:var(--e-12); }
/* ⚠️ PORTRAIT, comme partout ailleurs dans la Bibliotheque (`aspect-ratio:3/4` : .dcard-ph,
   .an-th, .vd-vue img…). Une hauteur FIXE de 206 px sur des colonnes de ~215 px rendait des
   cartes quasi CARREES — Amadou : « ne mets pas les cards en format carre mais le format de
   la biblio ». Le carre de `.lib-res-v .ph` (118 px) est taille pour les vignettes serrees de
   le Sourcing, pas pour un choix plein ecran. */
#mdl-panel-body .lib-res-v .ph { height:auto; aspect-ratio:3/4; }
#mdl-panel-body .lib-res-v .n { font-size:var(--t-mini); }

/* ── Les vues du panneau : rien d'inventé ────────────────────────────────────────
   Tout vient de l'étape « Vues » de l'Atelier — atelier-views-row, atelier-view-card,
   atelier-img-zone, atelier-img-placeholder, atelier-result-img, et pour la génération
   atelier-zone-enhancing + atelier-face-enhancing + atelier-enh-scan + atelier-spinner.
   Une seule surcharge ici : le ratio de la case, 3:4 (format Vinted) au lieu du 4/5 de
   l'Atelier — sinon elle rognerait l'image qu'on vient justement de recadrer. */
#mdl-panel-body .atelier-img-zone.mdl-zone { aspect-ratio: 3/4; }
#mdl-panel-body .atelier-views-row { justify-content: flex-start; }
/* Le bouton d'import ne doit pas s'étirer sur toute la ligne comme dans l'Atelier :
   ici il est posé à côté des onglets, pas sous une carte. */
.mdl-panel-onglets .atelier-view-import-btn { width:auto; padding:var(--e-6) var(--e-12); }
/* Les cartes de vues de l'Atelier sont taillées pour une étape PLEINE LARGEUR
   (min 190, max 340, et la rangée passe à la ligne). Dans la colonne de gauche du
   panneau, les trois passaient à la ligne et écrasaient la taille à droite. On les
   resserre — c'est l'adaptation à la situation, le style reste celui de l'Atelier. */
#mdl-panel-body .atelier-view-card { min-width:0; max-width:none; }

/* ⚠️ Le voile de génération de l'Atelier est semi-transparent (rgba .55) parce que là-bas
   il se pose sur une IMAGE. Ici il tombe sur une case vide, dont la description restait
   lisible dessous : « Génération… » et « Selfie miroir de côté » se chevauchaient. On
   efface donc le texte de la case pendant que sa vue se fabrique. */
#mdl-panel-body .atelier-zone-enhancing .atelier-img-placeholder { visibility: hidden; }

/* ── Le volet des vues occupe TOUT l'espace ──────────────────────────────────────
   Amadou : « c'est trop collé, la taille avec en dessous le texte collé, c'est moche,
   il faut utiliser tout l'espace ». Les vues prennent donc la largeur entière et la
   taille passe DESSOUS, au lieu d'une colonne étroite à droite qui les écrasait. */
.mdl-vues-plein { display:flex; flex-direction:column; gap:26px; }
.mdl-vues-plein .atelier-views-row { gap:var(--e-18); }
.mdl-vues-bas { display:flex; flex-direction:column; gap:var(--e-12); }
.mdl-vues-bas .atelier-block-label { margin:0; }
/* Les deux explications côte à côte : empilées, elles se collaient l'une à l'autre. */
.mdl-vues-aides { display:grid; grid-template-columns:repeat(auto-fit,minmax(270px,1fr)); gap:var(--e-12); }
.mdl-vues-aides .atelier-hint { margin:0; }
@media (max-width:700px){ .mdl-vues-aides { grid-template-columns:minmax(0,1fr); } }

/* « Aller à sa session » — sous l'état de la voiture. Le bouton et sa phrase sur la
   même ligne quand il y a la place, empilés sinon (MacBook + grand écran). */
/* Une ligne de profil dont la session tourne : un liseré à gauche, pas une couleur de
   fond — l'état (libre/occupé/grillé) garde la sienne, et les deux doivent se lire
   ensemble sans se disputer. */
.cok-prof-l.ouvert { box-shadow: inset 2px 0 0 var(--cok-green, var(--green)); }

/* Le temps d'une vue, en haut à droite de sa carte. Discret : c'est une mesure, pas
   une alerte — sauf quand la moderation a frappe, auquel cas le temps a double et il
   faut que ca se voie. */
.card-temps { position:absolute; top:8px; right:8px; z-index:3; font-size:var(--t-mini); font-weight:var(--fw-fort);
  padding:var(--e-4) var(--e-8); border-radius: var(--r-pilule); background:rgba(var(--th-ombre),.45); color: var(--sur-sombre);
  backdrop-filter:blur(4px); pointer-events:auto; cursor:help; }
.card-temps.warn { background:var(--cok-warn-bg,rgba(240,176,85,.28)); color:var(--cok-warn,var(--amber)); }

/* ── Onglet « Son activité » : l'écran à gauche, le fil à droite ─────────────
   Amadou a tranché la proportion (05/08) : « 60 à 75 % pour l'écran, 25 à 40 %
   pour la partie à droite ». 2fr/1fr = 67/33, au milieu de sa fourchette. */
.mdl-act-grille { display:grid; grid-template-columns:minmax(0,2fr) minmax(0,1fr); gap:var(--e-12); }
/* ⚠️ SEUIL MESURE, pas devine. La fiche vit dans une colonne : a 1600 px de fenetre
   la grille n'en fait que 878. Un seuil a 900 px l'aurait donc empilee sur un
   MacBook (1440 px -> ~720 px de grille), c'est-a-dire l'ecran le plus courant ici. */
@media (max-width:1000px){ .mdl-act-grille { grid-template-columns:minmax(0,1fr); } }

.mdl-act-tuiles { display:grid; grid-template-columns:repeat(auto-fit,minmax(96px,1fr)); gap:var(--e-10); margin-bottom:var(--e-12); }
.mdl-act-tuile { background:var(--surface-2); border-radius:var(--radius-sm,8px); padding:var(--e-10) var(--e-12);
  display:flex; justify-content:space-between; align-items:baseline; }
.mdl-act-tuile span { font-size:var(--t-meta); color:var(--text-3); }
.mdl-act-tuile b { font-size:var(--t-lead); font-weight:var(--fw-fort); }

/* L'écran reste TOUJOURS affiché, même sans image : c'est dedans qu'on lit pourquoi
   il n'y a rien à voir. Un message à la place du cadre laisserait deviner de quoi
   on parle. */
.mdl-ecran { border:1px solid var(--border-strong); border-radius: var(--r-lg); overflow:hidden; background:var(--surface-2); }
.mdl-ecran-tete { display:flex; align-items:center; gap:var(--e-8); padding:var(--e-8) var(--e-12);
  border-bottom:1px solid var(--border); background:var(--surface); }
.mdl-ecran-nom { font-size:var(--t-meta); color:var(--text-3); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.mdl-ecran-pt { margin-left:auto; width:7px; height:7px; border-radius:50%; background:var(--border-strong); }
.mdl-ecran-pt.on { background:var(--cok-green,var(--green)); }
.mdl-ecran-corps { min-height:235px; display:flex; align-items:center; justify-content:center; }

/* ══ L'ÉCRAN SE RÈGLE ═════════════════════════════════════════════════════════
   Amadou (20/08) : « on va le mettre en plus petit, et quand je vais le survoler
   j'aurai la possibilité de l'agrandir — en bas à droite. Il ne prendra pas toute la
   place, mais il sera beaucoup plus grand. »
   Petit par défaut sur l'écran de création, grand à la demande. Pas de plein écran :
   agrandir ne doit pas faire perdre le reste de la page. */
.mdl-ecran { position: relative; }
/* ⚠️ LA HAUTEUR EST PORTÉE PAR UN JETON À NOUS, PAS PAR `min-height`. Mesuré : sur cet
   écran, `min-height` est remis à zéro par une autre règle du fichier et le cadre
   restait à 348 px quoi qu'on écrive. Une hauteur qu'on POSE (et qu'on plafonne) ne
   peut pas être contredite par un minimum venu d'ailleurs. Le jeton vit sur le CADRE :
   c'est lui qui porte l'état « grand », donc lui qui décide. */
/* ⚠️ LA HAUTEUR EST ÉCRITE DEUX FOIS, EN CLAIR — pas portée par un jeton hérité.
   Mesuré : le jeton posé sur le CADRE basculait bien de ×3 à ×9, et la hauteur du corps
   restait à 144 px. Une valeur qui voyage par héritage ajoute un maillon de plus à
   vérifier ; ici elle ne survivait pas au trajet. Deux règles, deux hauteurs, rien à
   déduire. */
/* ⚠️⚠️ L'ÉCRAN FAIT LA HAUTEUR DE LA CARTE D'EN FACE — MÊME PENDANT QU'IL CHARGE.
   Amadou (20/08) : « l'écran de rediffusion doit faire la même taille que la partie de
   droite, même quand l'écran se charge ». Une hauteur fixe laissait un vide sous lui
   pendant que la fiche de droite descendait beaucoup plus bas : les deux colonnes ne se
   répondaient pas. La grille aligne déjà les deux cases (`align-items: stretch`) ; il
   suffit que l'écran REMPLISSE la sienne au lieu de se donner une taille à lui.
   Le minimum garantit qu'il reste lisible quand la carte de droite est courte. */
/* ⚠️ ET IL FAUT LUI DIRE DE GRANDIR. La colonne de gauche s'étire déjà à la hauteur de
   celle de droite (mesuré : 688 px des deux côtés) — mais ses enfants, eux, gardaient
   leur taille naturelle : l'écran restait à 385 px avec 300 px de vide sous lui. Une
   case étirée n'étire pas ce qu'elle contient. */
.cok-horlo-g > #cp-compte-etat { flex: 1; }
#cp-compte-etat { display: flex; flex-direction: column; min-height: 0; }
#cp-compte-etat > * { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#cp-compte-etat .mdl-ecran { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#cp-compte-etat .mdl-ecran .mdl-ecran-corps { flex: 1; min-height: calc(var(--e-48) * 3);
  height: auto; max-height: none; overflow: hidden;
  transition: min-height var(--t-long) var(--c-pose); }
/* Agrandi, il dépasse volontairement la carte d'en face — c'est le but du bouton. */
#cp-compte-etat .mdl-ecran.grand .mdl-ecran-corps { min-height: calc(var(--e-48) * 9); }
#cp-compte-etat .mdl-ecran .mdl-ecran-corps img { width: 100%; height: 100%;
  object-fit: contain; }
.mdl-ecran-corps { transition: min-height var(--t-long) var(--c-pose); }

/* Le bouton se montre au survol — et dès qu'il a le focus, sinon la commande n'existe
   que pour ceux qui ont une souris. */
.mdl-ecran-zoom { position: absolute; right: var(--e-8); bottom: var(--e-8);
  display: flex; align-items: center; justify-content: center;
  width: var(--e-28); height: var(--e-28); padding: 0;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text-2); cursor: pointer;
  opacity: 0; transition: opacity var(--t-bref) var(--c-pose),
                          border-color var(--t-bref) var(--c-pose),
                          color var(--t-bref) var(--c-pose); }
.mdl-ecran:hover .mdl-ecran-zoom,
.mdl-ecran-zoom:focus-visible { opacity: 1; }
.mdl-ecran-zoom:hover { color: var(--text); border-color: var(--violet-mid); }
/* Une seule icône, deux états : les flèches sortent, puis rentrent. */
.mdl-ecran-zoom .z-in { display: none; }
.mdl-ecran.grand .mdl-ecran-zoom .z-out { display: none; }
.mdl-ecran.grand .mdl-ecran-zoom .z-in { display: inline; }
@media (prefers-reduced-motion: reduce) {
  .mdl-ecran-corps, .mdl-ecran-zoom { transition: none; }
}
.mdl-ecran-vide { display:flex; flex-direction:column; align-items:center; gap:var(--e-8);
  padding:1.5rem; text-align:center; color:var(--text-3); }
.mdl-ecran-vide p { margin:0; font-size:var(--t-small); color:var(--text); }
.mdl-ecran-vide span { font-size:var(--t-base); max-width:300px; line-height:var(--lh-normal); }

.mdl-fil { border:1px solid var(--border); border-radius: var(--r-lg); background:var(--surface-2);
  overflow:hidden; display:flex; flex-direction:column; }
.mdl-fil-tete { display:flex; align-items:center; gap:var(--e-8); padding:var(--e-8) var(--e-12); font-size:var(--t-meta);
  border-bottom:1px solid var(--border); }
.mdl-fil-pt { width:6px; height:6px; border-radius:50%; background:var(--cok-red,var(--red)); }
/* Le fil défile DANS sa hauteur : c'est l'écran qui fixe celle du bloc, et une liste
   qui s'allonge décalerait les deux colonnes l'une par rapport à l'autre. */
.mdl-fil-corps { overflow-y:auto; max-height:235px; }
.mdl-fil-l { display:flex; gap:var(--e-8); padding:var(--e-8) var(--e-12); align-items:flex-start; }
.mdl-fil-l + .mdl-fil-l { border-top:1px solid var(--border); }
.mdl-fil-ic { flex:none; margin-top:var(--e-1); color:var(--text-3); }
.mdl-fil-ic.g { color:var(--cok-green,var(--green)); }
.mdl-fil-ic.b { color:var(--cok-blue,#7FA8F0); }
.mdl-fil-t { font-size:var(--t-base); line-height:var(--lh-serre); }
.mdl-fil-h { font-size:var(--t-mini); color:var(--text-3); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.mdl-fil-vide { padding:1.2rem 1rem; font-size:var(--t-base); color:var(--text-3); line-height:var(--lh-normal); }

/* « Aller à » en version compacte : une étiquette cliquable au bout d'une ligne de
   liste. Elle emprunte .cok-badge pour ne pas inventer un bouton de plus. */
.vd-aller-mini { cursor:pointer; border:1px solid transparent; font-family:inherit;
  background:var(--bg-elevated); color:var(--cok-text-3); transition: var(--transi-vif); }
.vd-aller-mini:hover { border-color:currentColor; color:var(--text); }
.vd-aller-mini:disabled { opacity:.6; cursor:progress; }
.vd-aller { display:flex; align-items:center; gap:var(--e-12); flex-wrap:wrap; margin-top:var(--e-12); }
.vd-aller .cok-subt { margin:0; flex:1; min-width:220px; }

/* ── Volet 3 du panneau modele : son profil Vinted ─────────────────────────────
   Sa photo de profil a gauche, ses champs a droite. Le formulaire seul laissait
   les deux tiers bas du panneau vides (Amadou : « ameliore l'interface »).
   Colonnes taillees a la main : le 1fr/1fr de .atelier-two-col rendait « Nom
   complet » et « Ville » cote a cote dans une demi-largeur — illisible. */
#mdl-panel-body .atelier-two-col.mdl-ident { grid-template-columns:250px minmax(0,1fr); gap:var(--e-28); }
@media (max-width:860px){ #mdl-panel-body .atelier-two-col.mdl-ident { grid-template-columns:minmax(0,1fr); } }
.mdl-pp-col { align-items:center; text-align:center; }
.mdl-pp-col .atelier-block-label { align-self:stretch; text-align:left; }
/* Le rond de la fiche, en plus grand : c'est la piece principale de la colonne.
   ⚠️ SPECIFICITE. Ecrite en `.mdl-pp-rond` seule, la regle PERDAIT : .model-info-avatar
   vit 8000 lignes plus bas, meme poids, donc c'est elle qui gagnait et le rond restait
   a 104px. Mesure : 104x104 au lieu de 186. On qualifie avec les deux classes. */
.model-info-avatar.mdl-pp-rond { width:186px; height:186px; cursor:default; position:relative; }
.model-info-avatar.mdl-pp-rond:hover { border-color:var(--border-strong); transform:none; }
.mdl-pp-rond .atelier-face-enhancing { border-radius:50%; }
.mdl-pp-actions { display:flex; gap:var(--e-8); justify-content:center; flex-wrap:wrap; }
.mdl-pp-imp { display:inline-flex; align-items:center; cursor:pointer; }
/* Les deux colonnes finissent par une note de pied sur la meme ligne de base : celle de
   droite y est poussee par la grille en flex:1, celle-ci a la main. */
.mdl-pp-col .atelier-hint { margin:auto 0 0; text-align:left; }
@media (max-width:860px){ .mdl-pp-col .atelier-hint { margin:0; } }
/* Le volet occupe toute la hauteur du panneau, comme les deux premiers : c'est la bio
   qui prend le reste. Sinon le formulaire flottait dans le tiers haut. */
#mdl-panel-body .atelier-two-col.mdl-ident { align-items:stretch; min-height:100%; }
#mdl-panel-body .mdl-ident-grid { margin-top:0; flex:1; }
/* ⚠️ `>` OBLIGATOIRE. Sans lui, `:last-child` attrapait aussi « Ville » et « Poids »
   (derniers enfants de LEUR ligne) : les deux lignes gonflaient a 132px et le formulaire
   se retrouvait trou de partout. Mesure : ligne a 132px au lieu de 55. */
#mdl-panel-body .mdl-ident-grid > .atelier-identity-field:last-child { flex:1; min-height:132px; }
#mdl-panel-body .mdl-ident-grid > .atelier-identity-field:last-child .atelier-identity-input-row { flex:1; }
/* Genereuse mais plafonnee : laissee libre, elle absorbait tout le reste (368px mesures
   pour deux lignes de bio, ca crie « je remplis pour remplir »). */
#mdl-panel-body .mdl-ident-grid #mdl-atl-bio { height:100%; min-height:132px; max-height:220px; resize:vertical; }

/* ⚠️ HAUTEUR CONSTANTE d'un volet à l'autre. Amadou : « il faut que l'espace reste le
   même ». Sans ça le panneau bondissait — grand sur la grille de visages, écrasé sur
   les vues, moyen sur la personnalité. Le corps défile, le cadre ne bouge plus. */
#mdl-panel .lib-picker-panel { height:min(90vh, 860px); }
#mdl-panel-body { flex:1; min-height:0; overflow-y:auto; }
/* Le bouton de l'Atelier est en `width:100%` parce qu'il est seul au milieu de son
   étape. Dans un pied de panneau, à côté d'un autre bouton, il doit tenir sa taille. */
#mdl-panel-footer .atelier-gen-btn { width:auto; margin-top:0; }
/* ⚠️ La grille de la réserve défile DANS le panneau : sans ça, dix-huit photos poussent
   « Importer » et « Continuer » hors de l'écran, et on ne trouve plus comment avancer.
   La valeur vaut deux rangées pleines. */
.vd-atl .lib-res-grille { max-height: 340px; overflow-y: auto; }
.vd-vue--vide .vd-vue-ph { display:block; width:100%; aspect-ratio:3/4; background:var(--surface); }
/* Les champs `vd-atl-champ` sont retirés : le volet identité emploie désormais le
   formulaire de l'Atelier (atelier-identity-*, atelier-input, atelier-textarea). */
.vd-liste { margin-top:var(--e-14); }
.vd-liste-2 { display:grid; grid-template-columns:1fr 1fr; gap:0 26px; }
@media (max-width:760px) { .vd-liste-2 { grid-template-columns:1fr; } }
.vd-l { display:flex; align-items:baseline; justify-content:space-between; gap:var(--e-14); padding:var(--e-8) 0; border-bottom:1px solid var(--cok-border); font-size:var(--t-base); }
.vd-l:last-child { border-bottom:0; }
.vd-l > span { color:var(--cok-text-2); flex:0 0 auto; }
.vd-l > b { font-weight:var(--fw-moyen); color:var(--cok-text); text-align:right; min-width:0; overflow-wrap:anywhere; }
.vd-vide { color:var(--cok-text-3); font-weight:var(--fw-normal); }
/* ⚠️⚠️ `pre-wrap` : sans lui, les trois paragraphes de la bio fusionnaient en un pavé
   SUR CET ÉCRAN SEULEMENT. Une bio correctement écrite s'affichait juste ici comme si
   rien n'avait changé — le genre de défaut qui fait croire que la réparation a raté. */
.vd-bio { margin-top:var(--e-14); font-size:var(--t-base); line-height:var(--lh-aere);
  color:var(--cok-text-2); white-space: pre-wrap }
.vd-etat { display:flex; align-items:center; gap:var(--e-12); margin-top:var(--e-14); font-size:var(--t-base); color:var(--cok-text-2); }
#topbar-vendeuse .topbar-right { gap:var(--e-8); }

/* Contrôle v2 : barre compacte, ouvriers, garde-fous éditables + micro */
.cok-ctrlbar { display:flex; align-items:center; gap:var(--e-28); flex-wrap:wrap; background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-12) var(--e-18); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-ctrlbar-group { display:flex; align-items:center; gap:var(--e-12); flex-wrap:wrap; }
.cok-ctrlbar-lbl { font-size:var(--t-meta); color:var(--cok-text-2); }
/* Contrôle — bandeau de statut réel du bot (live), alimenté par /api/bot-status */
.cok-botstat { display:flex; flex-wrap:wrap; gap:var(--e-10); margin-top:var(--e-12); }
.cok-bs-item { flex:1 1 160px; display:flex; align-items:center; gap:var(--e-12); background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-12) var(--e-16); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-bs-v { font-size:var(--t-small); font-weight:var(--fw-fort); color:var(--cok-text); line-height:var(--lh-titre); }
.cok-bs-v.green { color:var(--cok-green); } .cok-bs-v.warn { color:var(--cok-warn); } .cok-bs-v.red { color:var(--cok-red); }
.cok-bs-l { font-size:var(--t-meta); color:var(--cok-text-3); margin-top:var(--e-1); }
.cok-bs-dot { flex:none; width:9px; height:9px; border-radius:50%; background:var(--cok-text-3); }
.cok-bs-dot.live { background:var(--cok-green); box-shadow:0 0 0 3px var(--cok-green-bg); animation:coklive 1.6s infinite; }
.cok-bs-dot.warn { background:var(--cok-warn); box-shadow:0 0 0 3px var(--cok-warn-bg); }
.cok-bs-dot.red  { background:var(--cok-red);  box-shadow:0 0 0 3px var(--cok-red-bg); }
/* Flottement au survol — cohérent sur tout le Cockpit (repris du pattern Fabrique) */
.cok-metric, .cok-worker, .cok-bs-item, .cok-kcard, .pa-conn-card, .cok-acct-pill {
  transition: transform var(--t-moyen) var(--c-pose), border-color var(--t-moyen) var(--c-pose);
}
.cok-metric:hover, .cok-worker:hover, .cok-bs-item:hover, .cok-kcard:hover, .pa-conn-card:hover, .cok-acct-pill:hover {
  transform: translateY(-2px); border-color: var(--cyan-glow);
}
/* Veille — tout se grise, l'interrupteur passe au rouge, un rappel s'affiche */
.cok-veille-banner { display:none; align-items:center; gap:var(--e-10); margin-top:var(--e-14); padding:var(--e-12) var(--e-16); border-radius: var(--r-lg); font-size:var(--t-base); background:var(--cok-red-bg); border:1px solid rgba(240,113,90,.3); color:var(--cok-red); }
.cok-veille-banner svg { flex:none; }
.cok.paused .cok-veille-banner { display:flex; }
.cok.paused .cok-dim { filter: grayscale(1) brightness(.62); pointer-events:none; user-select:none; }
/* Couleur du Pilote automatique selon le SEGMENT actif (plus selon l'écran) : En marche = vert,
   Veille = gris neutre (fini le « Veille en vert » dans Vue d'ensemble). Veille = dernier span. */
.cok-master span:last-child.on { background:rgba(var(--th-voile),.09); color:var(--text); }

/* Espace dédié d'un ouvrier (ouvert au clic sur sa carte) */
.cok-wspace { display:none; }
.cok.showing-worker > .cok-ctrlbar, .cok.showing-worker > .cok-veille-banner, .cok.showing-worker > .cok-dim { display:none; }
.cok.showing-worker .cok-wspace { display:block; }
.cok-back { display:inline-flex; align-items:center; gap:var(--e-8); background:transparent; border:0; color:var(--cok-text-2); font:inherit; font-size:var(--t-base); cursor:pointer; padding:0; margin-bottom:var(--e-16); }
.cok-back:hover { color:var(--cok-text); }
.cok-ws-head { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--e-12); }
.cok-ws-title { font-size:var(--t-lead); font-weight:var(--fw-fort); color:var(--cok-text); display:flex; align-items:center; gap:var(--e-10); }
.cok-ws-title svg { color:var(--cok-accent); }
.cok-ws-role { font-size:var(--t-base); color:var(--cok-text-2); margin-top:var(--e-4); }
.cok-set { border:1px solid var(--cok-border); border-radius: var(--r-lg); background:var(--cok-card); padding:var(--e-2) var(--e-16); }
.cok-set-row { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); padding:var(--e-12) 0; border-bottom:1px solid var(--cok-border); font-size:var(--t-base); }
.cok-set-row:last-child { border-bottom:0; }
.cok-set-chip { font-size:var(--t-meta); color:var(--cok-text-2); background:var(--bg-hover); border:1px solid var(--cok-border-2); border-radius: var(--r-sm); padding:var(--e-4) var(--e-12); white-space:nowrap; }
.cok-wstat-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--e-10); }
.cok-act-list { border:1px solid var(--cok-border); border-radius: var(--r-lg); background:var(--cok-card); padding:var(--e-2) var(--e-16); }
.cok-act { display:flex; gap:var(--e-10); align-items:flex-start; font-size:var(--t-base); color:var(--cok-text-2); padding:var(--e-12) 0; border-bottom:1px solid var(--cok-border); }
.cok-act:last-child { border-bottom:0; }
.cok-act svg { color:var(--cok-accent); flex:none; margin-top:var(--e-1); }
.cok-warnbox { display:flex; gap:var(--e-10); align-items:flex-start; background:var(--cok-warn-bg); border:1px solid rgba(240,194,90,.3); color:var(--cok-warn); border-radius: var(--r-lg); padding:var(--e-12) var(--e-14); font-size:var(--t-base); margin:var(--e-14) 0; }
.cok-warnbox svg { flex:none; margin-top:var(--e-1); }

.cok-wtoggle { border:0; border-radius: var(--r-pilule); padding:var(--e-4) var(--e-14); font-size:var(--t-mini); font-weight:var(--fw-fort); cursor:pointer; background:var(--cok-green-bg); color:var(--cok-green); white-space:nowrap; }
.cok-wtoggle.off { background:var(--bg-elevated); color:var(--cok-text-3); }

@keyframes cokpulse { 0%,100%{opacity:1} 50%{opacity:.45} }

/* Annonces v2 : vitrine du batch (animée), pipeline kanban, démasquage en direct */
.cok-live-dot { display:inline-block; width:8px; height:8px; border-radius:50%; background:var(--cok-green); animation:coklive 1.6s infinite; }
@keyframes coklive { 0%{box-shadow:0 0 0 0 rgba(63,209,155,.5)} 70%{box-shadow:0 0 0 7px rgba(63,209,155,0)} 100%{box-shadow:0 0 0 0 rgba(63,209,155,0)} }
.cok-vitrine { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-xl); padding:var(--e-18) var(--e-20); margin-bottom:var(--e-8); backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px); }
.cok-vitrine-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--e-14); }
.cok-live { display:flex; align-items:center; gap:var(--e-10); font-weight:var(--fw-fort); font-size:var(--t-small); color:var(--cok-text); }
.cok-vitrine-count { font-size:var(--t-base); color:var(--cok-text-2); }
.cok-vitrine-count b { color:var(--cok-accent); font-size:var(--t-body); }
.cok-vitrine-stage { display:flex; align-items:center; gap:var(--e-14); margin-bottom:var(--e-14); flex-wrap:wrap; }
.cok-vitrine-cur { display:flex; align-items:center; gap:var(--e-12); background:rgba(var(--th-second-rgb),.06); border:1px solid var(--cok-accent-bg); border-radius: var(--r-lg); padding:var(--e-10) var(--e-14); min-width:210px; }
.cok-vitrine-thumb { width:38px; height:48px; border-radius: var(--r-sm); background:linear-gradient(160deg,rgba(var(--th-accent-rgb),.28),rgba(var(--th-second-rgb),.2)); display:flex; align-items:center; justify-content:center; color:var(--cok-accent); flex-shrink:0; }
.cok-vitrine-thumb.spin svg { animation:cokspin 1.1s linear infinite; }
@keyframes cokspin { to { transform:rotate(360deg) } }
.cok-vitrine-cur-t { font-size:var(--t-base); font-weight:var(--fw-moyen); color:var(--cok-text); }
.cok-vitrine-cur-s { font-size:var(--t-meta); color:var(--cok-accent); margin-top:var(--e-2); }
.cok-vitrine-arrow { color:var(--cok-text-3); flex-shrink:0; }
.cok-vitrine-done { display:flex; gap:var(--e-6); flex-wrap:wrap; align-items:center; flex:1; min-width:120px; }
.cok-vt-done { width:26px; height:32px; border-radius: var(--r-sm); background:var(--cok-green-bg); color:var(--cok-green); display:flex; align-items:center; justify-content:center; }
.cok-kanban { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:var(--e-16); }
.cok-kcol { display:flex; flex-direction:column; gap:var(--e-10); }
.cok-kcol-head { display:flex; align-items:center; justify-content:space-between; font-size:var(--t-base); color:var(--cok-text-2); font-weight:var(--fw-fort); padding:0 var(--e-2); }
.cok-kcount { background:var(--bg-elevated); color:var(--cok-text-2); border-radius: var(--r-pilule); padding:var(--e-1) var(--e-10); font-size:var(--t-mini); }
.cok-kcard { backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px) }
.cok-kcard-t { font-size:var(--t-base); color:var(--cok-text); font-weight:var(--fw-moyen); }
.cok-kcard-s { font-size:var(--t-meta); color:var(--cok-text-3); margin-top:var(--e-2); }
.cok-kcard-meta { display:flex; gap:var(--e-12); margin-top:var(--e-10); font-size:var(--t-mini); color:var(--cok-text-2); flex-wrap:wrap; }
.cok-kcard-meta span { display:flex; align-items:center; gap:var(--e-4); }
.cok-kcard-meta .pri { color:var(--cok-accent); font-weight:var(--fw-fort); }
.cok-vit-idle { display:flex; align-items:center; justify-content:space-between; gap:var(--e-18); padding:var(--e-6) 0 var(--e-2); flex-wrap:wrap; }
.cok-vit-idle-txt { font-size:var(--t-base); color:var(--cok-text-2); }
.cok-vitrine[data-state="idle"] .cok-live-dot { background:var(--cok-text-3); animation:none; }
.cok-vitrine-thumb.gen { position:relative; overflow:hidden; }
.cok-vitrine-thumb.gen svg { opacity:.85; }
.cok-vitrine-thumb.gen::after { content:''; position:absolute; inset:0; background:linear-gradient(110deg,transparent 35%,rgba(var(--th-voile),.22) 50%,transparent 65%); transform:translateX(-120%); animation:cokshimmer 1.8s ease-in-out infinite; }
@keyframes cokshimmer { to { transform:translateX(120%) } }
.cok-vt-done { animation:cokslidein .5s ease; }
@keyframes cokslidein { from { opacity:0; transform:translateX(-10px) } to { opacity:1; transform:none } }
.cok-bar > i { transition:width .8s var(--c-pose); }

/* Messages — interface de chat 3 volets, PLEIN ÉCRAN (aucune boîte interne) */
#section-cockpit-messages { height:100%; overflow:hidden; }
#section-cockpit-messages .section-canvas { flex:1; min-height:0; padding:0; max-width:none; margin:0; display:flex; overflow:hidden; }
#section-cockpit-messages .cok { flex:1; min-height:0; display:flex; }
.cok-msg { display:flex; flex:1; min-height:0; overflow:hidden; }
/* ⚠️⚠️ LE MÊME ALPHA NE FAIT PAS LE MÊME EFFET SELON LA CLARTÉ DU FOND — 15/08.
   Amadou, capture à l'appui : « la partie gauche et droite, c'est trop foncé, ça nuit
   à la lecture ». Les deux colonnes portaient `rgba(var(--th-ombre),.4)`.
   ⚠️ `--th-ombre` vaut `0,0,0` dans les SEPT thèmes — contrairement à `--th-voile`,
   il ne s'inverse JAMAIS. Or retirer 40 % de luminance à une nuit ne retire presque
   rien (il n'en reste pas beaucoup), tandis que sur du sable ça en retire 40 % de
   beaucoup. Mesuré, écart de clarté colonne / page :
       abysse ×1,02 · basalte ×1,05 · sylve ×1,05 · aurore ×1,03 · orage ×1,06
       DUNE ×2,78 · NIMBE ×2,83          ← le même code, ~50 fois plus fort
   Les alphas de ce fichier ont été calibrés à l'œil quand seuls les thèmes sombres
   existaient. Ils sont restés tels quels quand les clairs sont arrivés.
   RÉPARATION PAR EMPRUNT : `--surface-2`, qui existe déjà (c'est la valeur de
   `--bg-card`) et qui, lui, s'appuie sur `--th-voile` ET sur le multiplicateur
   `--th-surface-force` que Dune et Nimbe règlent déjà. Les sept thèmes rentrent dans
   une fourchette unique ×1,10 à ×1,35.
   ⭐ Bénéfice inattendu sur les thèmes SOMBRES : les colonnes y étaient à ×1,02, donc
   quasi indiscernables du fond. Elles passent à ×1,10 — enfin visibles. */
/* ⚠️⚠️ ET ELLES SONT OPAQUES ELLES AUSSI — 15/08. Amadou : « fais plus ressortir les
   extrémités, on voit mal ». `--surface-2` est un VOILE : le décor du thème le traverse,
   et sur les thèmes clairs il ne pèse que ×1,32 contre la page. Le centre du fil, lui,
   n'a aucun fond — il montre le décor, et c'est très bien : c'est le CONTRASTE entre un
   centre ouvert et deux bords opaques qui fait ressortir les extrémités.
   Le filet passe de `--cok-border` (11,5 %) à `--border-strong` (23 %) : sur un thème
   clair où panneau et page ne diffèrent que de ×1,03, c'est LUI qui trace la limite. */
.cok-msg-list { width:250px; flex-shrink:0; background:var(--panneau-fondu); border-right:1px solid transparent; border-image:var(--filet-fondu); display:flex; flex-direction:column; }
/* ⚠️⚠️ NI PASTILLES NI PILULES. Amadou (23/08) : « les boutons ronds comme ça, je n'en
   veux pas, c'est moche, et c'est trop collé ». La barre porte maintenant une recherche et
   un menu déroulant, tous deux en RECTANGLES à coins doux — le dessin des autres boutons
   du site (Importer, Filtres, Vider), pas un sixième style inventé pour l'occasion. */
.cok-msg-lhead {
  padding:var(--e-10) var(--e-12);
  border-bottom:1px solid var(--cok-border);
  display:flex; align-items:center; gap:var(--e-8);
}
.cok-msg-search, .cok-msg-filtre {
  font:inherit; font-size:var(--t-meta); color:var(--cok-text);
  background:var(--surface-2); border:1px solid var(--cok-border);
  border-radius:var(--r-sm);
  padding:var(--e-6) var(--e-10);
  min-width:0;
}
.cok-msg-search { flex:1 1 auto; }
.cok-msg-search::placeholder { color:var(--cok-text-3); }
.cok-msg-search:focus, .cok-msg-filtre:focus-visible {
  outline:none; border-color:var(--violet); background:var(--surface);
}
/* ⚠️ « Sélectionner » s'affichait « Sélectionne ». Le mot était entier dans le HTML : un
   plafond de 46 % le coupait à 103 px alors qu'il en demande 110 — et pour 225 px de place
   disponible. Un plafond en POURCENTAGE ne connaît pas la longueur du mot qu'il rogne.
   L'ellipse ne se voyait même pas : posée sur le BOUTON (un conteneur flex), elle ne coupe
   pas le texte, elle le tranche. Elle appartient au LIBELLÉ.
   Seul « Trier » a besoin de se serrer — son libellé porte le nom du compte choisi. */
.cok-msg-filtre {
  flex:0 0 auto; display:flex; align-items:center; gap:var(--e-6);
  cursor:pointer; white-space:nowrap;
}
#cok-msg-filtre { flex:0 1 auto; min-width:0; }
#cok-msg-filtre-lbl { min-width:0; overflow:hidden; text-overflow:ellipsis; }
.cok-msg-filtre:hover { border-color:var(--border-strong); }
/* Un filtre ACTIF se voit : sinon on cherche pourquoi la moitié des discussions manque. */
.cok-msg-filtre.on { border-color:var(--violet); color:var(--violet-light); }
.cok-msg-filtre svg { flex:0 0 auto; opacity:.6; }

/* LE MESSAGE EN COURS DE MODIFICATION. Il se distingue sans bouger : un liseré d'accent
   et un léger retrait de l'opacité, le temps que la fenêtre de saisie soit ouverte. Le
   faire clignoter ou le déplacer ferait perdre la ligne qu'on est en train de relire. */
.cok-mb-l.en-edition .cok-mb {
  outline:2px solid var(--violet);
  outline-offset:2px;
  opacity:.75;
}

/* ── LE MODE SÉLECTION DES DISCUSSIONS ───────────────────────────────────────
   La barre n'apparaît qu'en mode sélection : au repos elle prendrait deux lignes de la
   colonne pour ne rien proposer. */
.cok-msg-selbar {
  padding:var(--e-8) var(--e-12);
  border-bottom:1px solid var(--cok-border);
  display:flex; flex-direction:column; gap:var(--e-6);
  background:var(--surface-2);
}
.cok-msg-selbar-h { display:flex; align-items:center; justify-content:space-between; gap:var(--e-8); }
.cok-msg-selbar-a { display:flex; flex-wrap:wrap; gap:var(--e-6); }
.cok-msg-selcount { font-size:var(--t-micro); color:var(--cok-text-3); font-variant-numeric:tabular-nums; }
.cok-msg-selall, .cok-msg-selact {
  font:inherit; font-size:var(--t-micro); color:var(--cok-text);
  background:var(--surface); border:1px solid var(--cok-border);
  border-radius:var(--r-xs); padding:var(--e-4) var(--e-8); cursor:pointer;
}
.cok-msg-selall:hover, .cok-msg-selact:hover { border-color:var(--border-strong); }
/* ⚠️ Un bouton d'action groupée SANS RIEN DE COCHÉ ne doit pas paraître cliquable :
   sinon on appuie, rien ne se passe, et on croit que le geste a échoué. */
.cok-msg-selact:disabled { opacity:.4; cursor:default; }
.cok-msg-selact.danger { color:var(--red); border-color:rgba(var(--th-danger-rgb),.4); }
.cok-msg-selact.danger:hover:not(:disabled) { background:rgba(var(--th-danger-rgb),.12); }
/* Une discussion en attente de réponse : elle remonte en tête ET se marque. Le liseré
   suffit — un fond rouge sur douze lignes ferait un écran d'alarme. */
.cok-mc--atraiter { border-left:2px solid var(--red); }
.cok-msg-convs { flex:1; overflow-y:auto; }
.cok-mc { display:flex; gap:var(--e-10); padding:var(--e-12) var(--e-12); cursor:pointer; border-left:2px solid transparent; }
.cok-mc:hover { background:var(--surface); }
.cok-mc.on { background:var(--bg-hover); border-left-color:var(--cok-accent); }
/* Les deux boutons du banc d'essai : empilés, la colonne d'essai est étroite. */
.pg-essai-actions { display:flex; flex-direction:column; gap:var(--e-6); margin-top:var(--e-8); }
.pg-essai-actions .pg-pick { width:100%; justify-content:center; }
/* ⚠️ Un bouton sans effet ne doit pas paraître cliquable : « Ajouter » quand les dix sont
   déjà là, « Retirer » quand il n'y en a aucune. */
.pg-essai-actions .pg-pick:disabled { opacity:.4; cursor:default; }

/* ⚠️⚠️ COCHÉE S'ÉCRIT **APRÈS** OUVERTE, et pas avant. À poids égal c'est la dernière
   règle qui gagne : écrite plus haut, elle perdait son fond au profit de `.on` — or depuis
   qu'un clic OUVRE en même temps qu'il coche, le rang qu'on vient de cocher est toujours
   celui qui est ouvert. La marque disparaissait donc exactement là où on la cherche. */
.cok-mc.choisie { background:rgba(var(--th-accent-rgb),.14); box-shadow:inset 2px 0 0 var(--violet); }
/* La coche recouvre la pastille : `inset:0`, aucun décalage à deviner, elle suit la taille
   de l'avatar si elle change un jour. */
.cok-mc-av { position:relative; }
.cok-mc-coche {
  position:absolute; inset:0; border-radius:inherit;
  background:var(--violet); color:var(--sur-accent);
  display:none; align-items:center; justify-content:center;
}
.cok-mc.choisie .cok-mc-coche { display:flex; }
.cok-mc-av { width:34px; height:34px; border-radius:50%; color: var(--sur-accent); display:flex; align-items:center; justify-content:center; font-size:var(--t-base); font-weight:var(--fw-fort); flex-shrink:0; }
/* La photo de profil de l'acheteuse. ⚠️ `object-fit: cover` : les avatars Vinted ne sont
   pas carrés, et un `contain` laisserait des bandes dans une pastille ronde. */
.cok-mc-av img { width:100%; height:100%; object-fit:cover; border-radius:inherit; display:block; }
/* Sans photo : l'initiale, pas une icône grise — quinze discussions à l'icône identique
   ne se distinguent pas, une lettre si. */
.cok-mc-av--init { background:linear-gradient(160deg,rgba(var(--th-accent-rgb),.34),rgba(var(--th-second-rgb),.24)); color:var(--cok-text); }
.cok-mc-body { min-width:0; flex:1; }
.cok-mc-top { display:flex; justify-content:space-between; gap:var(--e-6); }
.cok-mc-name { font-size:var(--t-base); font-weight:var(--fw-moyen); color:var(--cok-text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cok-mc-time { font-size:var(--t-micro); color:var(--cok-text-3); flex-shrink:0; }
.cok-mc-snip { font-size:var(--t-mini); color:var(--cok-text-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-top:var(--e-2); }
.cok-mc-badge { display:inline-block; margin-top:var(--e-6); font-size:var(--t-micro); font-weight:var(--fw-fort); border-radius: var(--r-pilule); padding:var(--e-1) var(--e-8); }
/* ⚠️ IL N'EN RESTE QU'UN À PEINDRE (Amadou, 05/09) : « repondu auto » est retiré, parce
   que répondre est devenu le standard et que l'écrire laissait croire que CETTE réponse-là
   sortait d'un robot. La seule pastille qui subsiste est celle qui réclame un geste.
   Ils étaient peints depuis app.js avec une couleur en dur, la MÊME pour le texte et pour
   le fond (à 13 %) — donc 1,14 de contraste sur Dune. Ils passent par les jetons d'état. */
/* ⚠️ ET LE LIBELLÉ REPREND LA COULEUR DU TEXTE, PAS CELLE DE L'ÉTAT. Deuxième
   passe : écrire du rouge sur un fond rouge à 13 % plafonne à ~4 de contraste, quel
   que soit le thème — les deux teintes sont trop proches par construction. Mesuré
   3,46 sur Médina, 3,72 sur Dune. Le FOND porte donc le signal (rouge / vert) et le
   libellé reste lisible : 8 à 13 de contraste dans les seize thèmes.
   ⚠️ Le liseré est indispensable : sur un thème clair, un aplat à 13 % sans contour
   ne se distingue plus du panneau, et la pastille cesse de ressembler à une pastille. */
.cok-mc-badge--atraiter { background: var(--ose-bg);  color: var(--text);
                          border: 1px solid rgba(var(--th-danger-rgb),0.34); }
/* ⭐ DE QUELLE BOÎTE ON LIT. Sans elle, le seul nom affiché était celui d'en face — et sur
   un essai entre deux comptes à soi, c'était le compte ACHETEUR. On croyait alors lire sa
   boîte, donc que les bulles étaient inversées. */
.cok-chead-nous { color: var(--cok-accent, var(--violet-soft)); font-weight: var(--fw-fort); }

/* ⭐⭐ LES TROIS POINTS. Seuls `transform` et `opacity` bougent : ce sont les deux seules
   propriétés qui ne repeignent pas la page. Une pastille livrée en août animait `filter`
   et `box-shadow` — elle était saccadée, et c'est cette leçon-là qui s'applique ici. */
.cok-pts { display:inline-flex; align-items:center; gap:var(--e-4); }
.cok-pts i { width:var(--e-4); height:var(--e-4); border-radius:50%;
             background: currentColor; opacity:.35;
             animation: cok-pts-respire 1.1s ease-in-out infinite; }
.cok-pts i:nth-child(2) { animation-delay:.18s; }
.cok-pts i:nth-child(3) { animation-delay:.36s; }
@keyframes cok-pts-respire {
  0%, 60%, 100% { opacity:.30; transform:translateY(0); }
  30%           { opacity:1;   transform:translateY(calc(var(--e-2) * -1)); }
}
/* ⚠️ Un écran qui refuse le mouvement le refuse aussi ici : les points restent, ils
   cessent seulement de bouger. Retirer l'indication entière priverait la personne de
   l'information — ce serait la punir de son réglage. */
@media (prefers-reduced-motion: reduce) {
  .cok-pts i { animation:none; opacity:.6; }
}
.cok-mc-redige { display:flex; align-items:center; gap:var(--e-6);
                 color: var(--cok-accent, var(--violet-soft)); font-style:italic; }
.cok-mb-redige { display:flex; align-items:center; gap:var(--e-8); }
.cok-mb-redige-t { font-size:var(--t-mini); opacity:.75; }

.cok-msg-chat { flex:1; display:flex; flex-direction:column; min-width:0; }
.cok-msg-chead { padding:var(--e-12) var(--e-16); border-bottom:1px solid var(--cok-border); display:flex; align-items:center; justify-content:space-between; gap:var(--e-10); }
/* ⚠️ Ces deux lignes étaient ÉCRITES DANS LE JS (13.5px / 11px, en dur). Tant qu'elles
   y étaient, Litiges ne pouvait pas porter le même en-tête sans recopier les mesures —
   et une mesure recopiée finit toujours par diverger. Les deux écrans lisent ici. */
/* ⚠️ `min-width:0` : sans lui, un titre d'annonce Vinted (ils sont longs) refuse de
   rétrécir dans un flex et pousse la pastille d'état hors du panneau. Les deux écrans
   avaient le défaut ; ils sont réparés du même coup. */
.cok-chead-l    { min-width:0; flex:1 1 auto; }
.cok-chead-qui  { font-size:var(--t-small); font-weight:var(--fw-fort); color:var(--cok-text);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cok-chead-quoi { font-size:var(--t-mini);  color:var(--cok-text-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cok-msg-thread { flex:1; overflow-y:auto; padding:var(--e-16); display:flex; flex-direction:column; }
.cok-mb.note { align-self:center; max-width:86%; text-align:center; }
.cok-mb.note .cok-mb-txt { background:var(--cok-warn-bg); border:1px solid rgba(240,194,90,.25); color:var(--cok-warn); font-size:var(--t-meta); }
.cok-msg-compose { padding:var(--e-12) var(--e-14); border-top:1px solid var(--cok-border); display:flex; gap:var(--e-8); align-items:center; }
.cok-msg-field { flex:1; min-width:0; background:rgba(var(--th-voile),.04); border:1px solid var(--cok-border); border-radius: var(--r-md); padding:var(--e-10) var(--e-12); color:var(--cok-text); font-family:inherit; font-size:var(--t-base); }
.cok-msg-field:focus { outline:none; border-color:var(--cok-accent); }
.cok-msg-sbtn { flex-shrink:0; width:38px; height:38px; border:0; border-radius: var(--r-md); background:var(--cok-accent-solid); color: var(--sur-accent); cursor:pointer; display:flex; align-items:center; justify-content:center; }
.cok-msg-ctx { width:238px; flex-shrink:0; background:var(--panneau-fondu); border-left:1px solid transparent; border-image:var(--filet-fondu); display:flex; flex-direction:column; }
.cok-msg-cbody { flex:1; overflow-y:auto; padding:var(--e-14); }
.cok-msg-photo { aspect-ratio:3/4; border-radius: var(--r-md); background:linear-gradient(160deg,rgba(var(--th-accent-rgb),.28),rgba(var(--th-second-rgb),.2)); margin-bottom:var(--e-12); }
.cok-msg-ct { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text); }
.cok-msg-cd { font-size:var(--t-meta); color:var(--cok-text-2); margin:var(--e-6) 0 var(--e-12); line-height:var(--lh-normal); }
.cok-msg-crow { display:flex; justify-content:space-between; gap:var(--e-8); font-size:var(--t-meta); padding:var(--e-6) 0; border-top:1px solid var(--cok-border); }
.cok-msg-crow .lbl { color:var(--cok-text-2); }
.cok-msg-clink { display:inline-flex; align-items:center; gap:var(--e-4); margin-top:var(--e-12); font-size:var(--t-meta); color:var(--cok-accent); text-decoration:none; }
.cok-msg-assist { border-top:1px solid var(--cok-border); padding:var(--e-12) var(--e-14); }
.cok-msg-ahead { font-size:var(--t-meta); color:var(--cok-text-2); margin-bottom:var(--e-8); display:flex; align-items:center; gap:var(--e-6); }
.cok-msg-ahead svg { color:var(--cok-accent); flex-shrink:0; }
.cok-msg-alog { display:flex; flex-direction:column; gap:var(--e-6); max-height:130px; overflow-y:auto; margin-bottom:var(--e-8); }
.cok-msg-abub { font-size:var(--t-meta); line-height:var(--lh-normal); border-radius: var(--r-md); padding:var(--e-8) var(--e-10); max-width:92%; }
.cok-msg-abub.a { background:rgba(var(--th-second-rgb),.1); color:var(--cok-text); align-self:flex-start; }
.cok-msg-abub.q { background:var(--bg-hover); color:var(--cok-text-2); align-self:flex-end; }
.cok-msg-acompose { display:flex; gap:var(--e-6); align-items:center; }
.cok-msg-afield { flex:1; min-width:0; background:rgba(var(--th-voile),.04); border:1px solid var(--cok-border); border-radius: var(--r-md); padding:var(--e-8) var(--e-10); color:var(--cok-text); font-family:inherit; font-size:var(--t-meta); }
.cok-msg-afield:focus { outline:none; border-color:var(--cok-accent); }
.cok-msg-asbtn { flex-shrink:0; width:32px; height:32px; border:0; border-radius: var(--r-sm); background:var(--cok-accent-bg); color:var(--cok-accent); cursor:pointer; display:flex; align-items:center; justify-content:center; }
@media (max-width:1080px){ .cok-msg-ctx { display:none; } }
/* Messages v3 : filtres 1 ligne, vignette photo, boutons SKU/SHEIN */
.cok-msg-lhead .cok-chips { flex-wrap:nowrap; }
.cok-mc-av { width:40px; height:40px; border-radius: var(--r-sm); background:linear-gradient(160deg,rgba(var(--th-accent-rgb),.32),rgba(var(--th-second-rgb),.22)); color:rgba(var(--th-voile),.5); }
.cok-msg-photo { display:flex; align-items:center; justify-content:center; color:rgba(var(--th-voile),.4); }
.cok-msg-cbtns { display:flex; flex-direction:column; gap:var(--e-8); margin-top:var(--e-14); }
.cok-msg-cbtn { display:inline-flex; align-items:center; justify-content:center; gap:var(--e-6); font-size:var(--t-meta); font-weight:var(--fw-moyen); padding:var(--e-10) var(--e-10); border-radius: var(--r-md); border:1px solid var(--cok-border-2); background:var(--surface); color:var(--cok-text); cursor:pointer; text-decoration:none; white-space:nowrap; }
.cok-msg-cbtn:hover { background:rgba(var(--th-voile),.07); }
.cok-msg-cbtn.shein { background:var(--cok-accent-bg); color:var(--cok-accent); border-color:transparent; }
.cok-msg-cbtn.ok { background:var(--cok-green-bg); color:var(--cok-green); border-color:transparent; }
/* Messages — mesures de la robe par taille (panneau annonce) : un bloc par taille, mesures qui s'enroulent */
.cok-mes { margin-top:var(--e-12); }
.cok-mes-lab { font-size:var(--t-meta); color:var(--cok-text-2); margin-bottom:var(--e-6); }
.cok-mes-grid { display:grid; grid-template-columns:auto 1fr 1fr 1fr; gap:0 var(--e-4); font-size:var(--t-mini); align-items:center; }
.cok-mes-grid > span { padding:var(--e-6) var(--e-2); }
.cok-mes-h { color:var(--cok-text-3); font-size:var(--t-micro); text-transform:uppercase; letter-spacing:var(--ls-leger); text-align:right; }
.cok-mes-t { font-weight:var(--fw-gras); color:var(--cok-text); text-align:left; }
.cok-mes-c { text-align:right; color:var(--cok-text); font-variant-numeric:tabular-nums; }
.cok-mes-grid > span:nth-child(n+5) { border-top:1px solid var(--cok-border); }
.cok-mes-long { display:flex; gap:var(--e-8); margin-top:var(--e-8); border-top:1px solid var(--cok-border); padding-top:var(--e-8); font-size:var(--t-mini); }
.cok-mes-longlbl { flex:none; color:var(--cok-text-3); }
.cok-mes-longv { display:flex; flex-wrap:wrap; gap:var(--e-4) var(--e-10); color:var(--cok-text); font-variant-numeric:tabular-nums; }
.cok-mes-longv i { color:var(--cok-text-3); font-style:normal; }

/* Commandes — chaîne SHEIN → entrepôt (2 boutons, sous-onglets, tableaux, porte-monnaie) */
/* Les trois filières, collées, sur leur propre rangée. Pas de `max-width` : elles se
   dimensionnent sur leur texte plutôt que de s'étirer à une largeur devinée. */
.cok-cmd-groups { display:flex; align-items:center; gap:var(--e-4); background:rgba(var(--th-voile),.04);
  border:1px solid var(--cok-border); border-radius: var(--r-md); padding:var(--e-4); margin-bottom:var(--e-12);
  min-width:0; }
.cok-cmd-groups .cok-cmd-grp { flex:0 0 auto; }
.cok-cmd-grp { flex:1; border:0; border-radius: var(--r-md); padding:var(--e-10) var(--e-6); font-family:inherit; font-size:var(--t-base); font-weight:var(--fw-fort); cursor:pointer; color:var(--cok-text-2); background:transparent; transition: var(--transi); }
/* Les trois maillons de la chaîne. Refonte 2026-07-30 : le vert d'eau de « Vinted »
   et l'orange de « Entrepôt » étaient des couleurs de marque étrangères à la palette ;
   ils ramenaient trois teintes de plus à l'écran. Un seul accent, le violet-bleu, et
   c'est la NUANCE qui distingue les trois maillons. */
.cok-cmd-grp.on-vinted { background:linear-gradient(120deg,var(--violet-soft),var(--cyan)); color: var(--sur-plein); }
.cok-cmd-grp.on-shein  { background:linear-gradient(120deg,var(--violet-soft),#5D80FF); color: var(--sur-plein); }
.cok-cmd-grp.on-wh     { background:linear-gradient(120deg,var(--cyan),#5A78EC); color: var(--sur-plein); }
/* ⚠️ La filière Litiges sort du dégradé violet-bleu des trois autres, et c'est voulu :
   c'est la seule qui annonce un problème. Corail, la teinte d'alerte déjà utilisée par
   « En retard » — on n'introduit pas une couleur de plus. */
/* .on-lit est peint plus bas, APRÈS le survol — voir « LE BOUTON LITIGES ». */
/* ⚠️⚠️ LA BARRE NE SE LIMITAIT PAS À LA LARGEUR DE L'ÉCRAN. Elle portait bien
   `overflow-x:auto`, mais ça ne sert à rien tant qu'elle est plus LARGE que son parent :
   ses boutons sont en `flex-shrink:0`, sa taille de base valait donc la somme des
   boutons (1236 px pour neuf onglets) et elle débordait du bandeau au lieu de défiler
   dedans. Mesuré à 1024 px de large : TROIS onglets hors de l'écran, et le seul moyen de
   les atteindre était de faire glisser toute la page de côté.
   ⚠️ Le piège : `#cok-cmd-subtabs.scrollWidth - clientWidth` valait 0 — de son point de
   vue rien ne débordait. C'est la CAPTURE D'ÉCRAN qui l'a montré, pas la mesure.
   Deux corrections qui vont ensemble : `flex-basis:100%` + `min-width:0` la ramènent à la
   largeur de la ligne, et `flex-wrap:wrap` fait passer les onglets en trop à la ligne
   suivante — on préfère une deuxième rangée à un défilement latéral, qui cache les
   onglets sans le dire. */
.cok-cmd-subtabs { display:flex; flex-wrap:wrap; gap:var(--e-4); row-gap:var(--e-4); flex-basis:100%; min-width:0;
  margin-bottom:var(--e-16); overflow-x:auto; white-space:nowrap; padding-bottom:var(--e-2); }
/* Le compteur de l'onglet : discret quand il est à zéro, il ne doit pas peser autant
   que le mot. Rouge dès qu'il y a du retard — c'est la seule urgence de cet écran. */
/* ⚠️⚠️ LA PLACE DU COMPTEUR EST RÉSERVÉE, sinon la barre bouge deux fois : quand les
   chiffres arrivent (le compteur est vide au premier rendu) et quand un compte passe de
   9 à 10. Amadou : « c'est le 0 dans "En retard" qui décale tout. »
   `tabular-nums` égalise déjà la largeur des chiffres ENTRE EUX ; il ne fait rien contre
   un nombre de chiffres qui change. C'est `min-width` qui règle ça.
   ⚠️ Réservé pour TROIS chiffres : il a 157 commandes, une étape peut dépasser 99. */
.cok-cmd-stab-n { margin-left:var(--e-6); font-size:var(--t-mini); font-weight:var(--fw-gras); font-variant-numeric:tabular-nums;
  color:var(--cok-text-3);
  /* ⚠️⚠️ EN `ch`, PAS EN PIXELS. `1ch` vaut la largeur du chiffre « 0 » DANS LA POLICE
     COURANTE — et comme `tabular-nums` donne à tous les chiffres la largeur du zéro,
     `3ch` réserve exactement trois chiffres, quelle que soit la police.
     ⚠️ J'ai d'abord posé 21 px, mesurés ici : il en fallait 21,34 et cinq onglets
     bougeaient encore. Surtout, cette mesure est faite dans un navigateur SANS Inter —
     elle ne vaut donc rien pour l'écran d'Amadou. `ch` supprime la question. */
  /* ⚠️ 3.4ch et non 3ch : `1ch` est la largeur du ZÉRO, et si la police n'a pas de
     chiffres à largeur fixe, « 148 » dépasse trois zéros de quelques dixièmes — mesuré
     ici, 21,34 contre 21,29. La marge rend la réserve vraie dans TOUTE police. */
  display:inline-block; min-width:3.4ch; text-align:right; }
.cok-cmd-stab.on .cok-cmd-stab-n { color:var(--cok-accent); }
.cok-cmd-stab-n.vide { opacity:.35; }
.cok-cmd-stab-n.urgent, .cok-cmd-stab.on .cok-cmd-stab-n.urgent { color:var(--red); }
.cok-cmd-stab { border:0; background:transparent; color:var(--cok-text-2); font-family:inherit; font-size:var(--t-base); font-weight:var(--fw-moyen); padding:var(--e-8) var(--e-14); border-radius: var(--r-md); cursor:pointer; white-space:nowrap; flex-shrink:0; }
.cok-cmd-stab.on { background:var(--cok-accent-bg); color:var(--cok-accent); }
.cok-cmd-tbl { border:1px solid var(--cok-border); border-radius: var(--r-lg); overflow-x:auto; background:var(--cok-bg-2); }
.cok-cmd-tbl table { width:100%; border-collapse:collapse; min-width:480px; }
.cok-cmd-tbl th { text-align:left; font-size:var(--t-micro); color:var(--cok-text-3); font-weight:var(--fw-moyen); padding:var(--e-10) var(--e-12); border-bottom:1px solid var(--cok-border); }
.cok-cmd-tbl td { font-size:var(--t-base); padding:var(--e-12); border-bottom:1px solid var(--bg-hover); color:var(--cok-text); }
.cok-cmd-tbl tbody tr:last-child td { border-bottom:0; }
.cok-cmd-tbl th.r, .cok-cmd-tbl td.r { text-align:right; }
/* Bordereaux 10×15 (Entrepôt) : zone de dépôt du PDF + message de progression */
.bord-drop { border:1px dashed var(--cok-border); border-radius: var(--r-lg); background:var(--cok-bg-2);
             padding:26px var(--e-20); text-align:center; transition:border-color var(--t-moyen), background var(--t-moyen); }
.bord-drop.over { border-color:var(--cok-accent); background:rgba(var(--th-accent-rgb),.08); }
.bord-drop-t { font-size:var(--t-small); color:var(--cok-text); font-weight:var(--fw-moyen); }
.bord-drop-s { font-size:var(--t-meta); color:var(--cok-text-3); margin:var(--e-6) 0 var(--e-14); }
/* Les trois actions d'une ligne. En flex, sinon le <svg> (mis en display:block globalement)
   casse la ligne du <a> qui le contient et le bouton part en cacahuète. */
.bord-acts { display:flex; align-items:center; justify-content:flex-end; gap:var(--e-8); }
/* Un <a> hérite l'interligne du tableau, un <button> non : sans ça « Ouvrir » fait 4 px de
   plus que ses voisins. On fixe la même hauteur de contenu (15 px) pour les trois. */
.bord-acts .cok-btn { line-height:15px; }
.bord-dl { padding:var(--e-8) var(--e-12); }   /* icône seule : 15 px + 2×7 de marge = même hauteur que le reste */
.bord-msg { font-size:var(--t-meta); margin:var(--e-10) 0 var(--e-4); min-height:16px; color:var(--cok-text-2); }
.bord-msg.ok  { color:var(--cok-green); }
.bord-msg.bad { color:var(--cok-red); }
.cok-cmd-prod { display:flex; align-items:center; gap:var(--e-10); }
.cok-cmd-thumb { width:26px; height:26px; border-radius: var(--r-sm); background:linear-gradient(160deg,rgba(var(--th-accent-rgb),.32),rgba(var(--th-second-rgb),.22)); flex-shrink:0; }
.cok-cmd-buyer { font-size:var(--t-micro); color:var(--cok-text-3); }
.cok-cmd-wallet { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); border-radius: var(--r-lg); padding:var(--e-16) var(--e-18); margin-bottom:var(--e-16); }
.cok-cmd-wallet.shein { background:linear-gradient(120deg,rgba(139,120,255,.12),rgba(var(--th-second-rgb),.05)); border:1px solid rgba(139,120,255,.25); }
.cok-cmd-wallet.wh { background:linear-gradient(120deg,rgba(240,160,90,.14),rgba(240,113,90,.06)); border:1px solid rgba(240,160,90,.28); }
.cok-cmd-shead { display:flex; align-items:center; justify-content:space-between; gap:var(--e-10); margin-bottom:var(--e-12); }
.cok-cmd-shead .t { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text); }
.cok-cmd-live { display:flex; align-items:center; gap:var(--e-8); margin-bottom:var(--e-14); font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text); }
.cok-cmd-live .dot { width:8px; height:8px; border-radius:50%; background:var(--cok-green); animation:coklive 1.6s infinite; }

/* Cockpit · Résultats — Bilan / Argent / Coûts */
.cok-rz-perbar { display:flex; gap:var(--e-8); justify-content:flex-end; flex-wrap:wrap; margin-bottom:var(--e-16); }
.cok-rz-cols { display:flex; gap:var(--e-16); flex-wrap:wrap; margin:var(--e-4) 0 var(--e-6); }
.cok-rz-card { flex:1; min-width:240px }
.cok-rz-card:first-child { flex:1.7; }
.cok-rz-h { font-size:var(--t-small); font-weight:var(--fw-fort); margin-bottom:var(--e-12); color:var(--cok-text); }
.cok-rz-chart svg { width:100%; height:150px; display:block; }
.cok-rz-xl { position:relative; height:15px; margin-top:var(--e-6); }
.cok-rz-xl span { position:absolute; transform:translateX(-50%); font-size:var(--t-micro); color:var(--cok-text-3); white-space:nowrap; }
.cok-rz-wd { width:108px; background:var(--bg-hover); border:1px solid var(--cok-border-2); border-radius: var(--r-sm); padding:var(--e-8) var(--e-10); color:var(--cok-text); font-size:var(--t-base); text-align:right; font-family:inherit; }
.cok-rz-wd:focus { outline:none; border-color:var(--cok-accent); }
.cok-rz-muted { color:var(--cok-text-3); font-size:var(--t-meta); }
.cok-rz-total { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); flex-wrap:wrap; margin-top:var(--e-16); background:var(--cok-green-bg); border:1px solid rgba(63,209,155,.25); border-radius: var(--r-lg); padding:var(--e-16) var(--e-20); }
.cok-rz-total b { color:var(--cok-green); font-size:var(--t-lead); }
.cok-rz-btn { border:0; background:var(--cok-green); color:#06231a; border-radius: var(--r-md); padding:var(--e-12) var(--e-20); font-size:var(--t-base); font-weight:var(--fw-fort); cursor:pointer; }
.cok-rz-btn:hover { filter:brightness(1.06); }
.cok-rz-want { display:flex; align-items:center; gap:var(--e-12); flex-wrap:wrap; }
.cok-rz-wlbl { font-size:var(--t-base); color:var(--cok-text); }
.cok-rz-wbox { display:inline-flex; align-items:center; gap:var(--e-6); }
.cok-rz-wbox input { width:132px; font-size:var(--t-body); font-weight:var(--fw-fort); }
.cok-rz-wbox b { color:var(--cok-text-2); font-weight:var(--fw-fort); }
.cok-rz-mini { border:0; background:var(--cok-accent-bg); color:var(--cok-accent); border-radius: var(--r-pilule); font-size: var(--t-meta); padding: var(--e-6) var(--e-12); font-weight:var(--fw-fort); cursor:pointer; }
.cok-rz-mini:hover { filter:brightness(1.1); }

/* Cockpit · Comptes — Création / Gestion */
.cok-cp-dot { display:inline-block; width:9px; height:9px; border-radius:50%; flex-shrink:0; }
.cok-cp-create { display:flex; align-items:center; gap:var(--e-12); flex-wrap:wrap; margin-bottom:var(--e-16) }
.cok-cp-qty { width:60px; background:var(--bg-hover); border:1px solid var(--cok-border-2); border-radius: var(--r-sm); padding:var(--e-8) var(--e-10); color:var(--cok-text); font-size:var(--t-base); text-align:center; font-family:inherit; }
.cok-cp-rec { display:flex; gap:var(--e-10); flex-wrap:wrap; }
.cok-cp-reccard { flex:1; min-width:190px }
.cok-cp-reccard .t { display:flex; align-items:center; gap:var(--e-8); font-size:var(--t-base); font-weight:var(--fw-fort); }
.cok-cp-reccard .d { font-size:var(--t-mini); color:var(--cok-text-2); margin-top:var(--e-4); }
.cok-cp-qcard { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-14) var(--e-16); margin-top:var(--e-10); }
.cok-cp-qhead { display:flex; align-items:center; gap:var(--e-10); margin-bottom:var(--e-12); flex-wrap:wrap; }
.cok-cp-steps { display:flex; align-items:center; gap:var(--e-6); flex-wrap:wrap; }
.cok-cp-step { font-size:var(--t-micro); padding:var(--e-4) var(--e-10); border-radius: var(--r-sm); white-space:nowrap; color:var(--cok-text-3); }
.cok-cp-step.done { color:var(--cok-green); }
.cok-cp-step.now { color:var(--cok-accent); background:var(--cok-accent-bg); }
.cok-cp-arrow { color:var(--cok-border-2); font-size:var(--t-mini); }
.cok-cp-filters { display:flex; gap:var(--e-8); flex-wrap:wrap; margin-bottom:var(--e-18); }
.cok-cp-filter { border:1px solid var(--cok-border); background:transparent; color:var(--cok-text-2); border-radius: var(--r-pilule); padding:var(--e-8) var(--e-14); font-size:var(--t-meta); font-weight:var(--fw-fort); cursor:pointer; display:inline-flex; align-items:center; gap:var(--e-8); font-family:inherit; }
.cok-cp-filter .n { opacity:.65; }
.cok-cp-acc { background:var(--cok-card); border:1px solid var(--cok-border); border-left:3px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-14) var(--e-16); margin-top:var(--e-10); }
.cok-cp-acc-head { display:flex; align-items:center; gap:var(--e-10); margin-bottom:var(--e-12); flex-wrap:wrap; }
.cok-cp-acc-name { font-size:var(--t-base); font-weight:var(--fw-fort); display:flex; align-items:center; gap:var(--e-10); }
.cok-cp-jauges { display:flex; gap:var(--e-20); flex-wrap:wrap; }
.cok-cp-jauge { flex:1; min-width:180px; }
.cok-cp-jauge-top { display:flex; justify-content:space-between; font-size:var(--t-mini); margin-bottom:var(--e-6); }
.cok-cp-track { height:7px; background:var(--bg-elevated); border-radius: var(--r-pilule); overflow:hidden; }
.cok-cp-track > i { display:block; height:100%; border-radius: var(--r-pilule); }
.cok-cp-note { font-size:var(--t-meta); color:var(--cok-text-3); margin-top:var(--e-14); line-height:var(--lh-normal); }
/* Onglet Comptes → Statut (états connexion + assistant local) */
.cok-cp-lanc { display:flex; align-items:center; gap:var(--e-10); font-size:var(--t-base); padding:var(--e-10) var(--e-14); border-radius: var(--r-md); margin-bottom:var(--e-16); border:1px solid var(--cok-border); }
.cok-cp-lanc .dot { width:8px; height:8px; border-radius:50%; flex:0 0 auto; }
.cok-cp-lanc.on { background:rgba(47,191,113,.10); border-color:rgba(47,191,113,.30); color:var(--cok-text); }
.cok-cp-lanc.on .dot { background:var(--cok-green); }
.cok-cp-lanc.off { background:rgba(226,96,122,.08); border-color:rgba(226,96,122,.28); color:var(--cok-text-2); }
.cok-cp-lanc.off .dot { background:var(--cok-red); }
.cok-cp-lanc code { background:rgba(var(--th-voile),.08); padding:var(--e-1) var(--e-6); border-radius:var(--r-micro); font-size:var(--t-meta); }
.cok-cp-relaunch { padding:var(--e-6) var(--e-10) !important; }
/* Statut → sections par état + cards de compte (avatar + nom + bouton) */
.cok-acc-sec { margin-top:var(--e-18); }
.cok-acc-sechead { display:flex; align-items:center; gap:var(--e-10); font-size:var(--t-small); margin-bottom:var(--e-12); }
.cok-acc-dot { width:9px; height:9px; border-radius:50%; flex:0 0 auto; }
.cok-acc-count { font-size:var(--t-meta); font-weight:var(--fw-fort); border-radius: var(--r-pilule); padding:var(--e-2) var(--e-10); }
.cok-acc-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:var(--e-10); }
.cok-acc-card { display:flex; align-items:center; gap:var(--e-10); background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-10) var(--e-12); transition:border-color var(--t-bref); }
.cok-acc-card:hover { border-color:var(--cok-border-2); }
.cok-acc-av { width:34px; height:34px; border-radius:50%; flex:0 0 auto; display:flex; align-items:center; justify-content:center; font-size:var(--t-small); font-weight:var(--fw-fort); color: var(--sur-accent); overflow:hidden; }
.cok-acc-av img { width:100%; height:100%; object-fit:cover; display:block; }
/* Comptes / Créer — chaîne de création + formulaire d'enregistrement */
.cok-cp-flow { display:grid; grid-template-columns:repeat(auto-fit,minmax(215px,1fr)); gap:var(--e-10); margin-bottom:var(--e-6); }
.cok-cp-fstep { display:flex; gap:var(--e-10); align-items:flex-start }
.cok-cp-fstep.hi { border-color:rgba(240,194,90,.45); }
.cok-cp-fnum { flex:0 0 auto; width:24px; height:24px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:var(--t-base); font-weight:var(--fw-gras); }
.cok-cp-fstep .t { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text); }
.cok-cp-fstep .d { font-size:var(--t-meta); color:var(--cok-text-2); margin-top:var(--e-2); }
/* Carte de lancement « Créer une vendeuse » (aperçu neutre du parcours + pastille Sourcing + CTA) */
.cok-launch { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-xl); padding:var(--e-18) var(--e-20); margin:var(--e-2) 0 var(--e-4); }
.cok-launch-head { display:flex; align-items:center; gap:var(--e-12); }
.cok-launch-title { font-size:var(--t-body); font-weight:var(--fw-fort); color:var(--cok-text); }
.cok-launch-sub { font-size:var(--t-base); color:var(--cok-text-2); margin-top:var(--e-1); }
.cok-launch-cap { font-size:var(--t-micro); color:var(--cok-text-3); text-transform:uppercase; letter-spacing:var(--ls-large); margin:var(--e-18) var(--e-2) var(--e-10); }
.cok-launch-steps { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--e-4); margin:0 0 var(--e-16); }
.cok-launch-step { display:flex; flex-direction:column; align-items:center; gap:var(--e-6); flex:1; min-width:0; }
.cok-launch-step .dot { width:34px; height:34px; border-radius:50%; border:1px solid var(--cok-border-2); color:var(--cok-text-3); display:flex; align-items:center; justify-content:center; flex:none; }
.cok-launch-step .lbl { font-size:var(--t-mini); color:var(--cok-text-3); text-align:center; }
.cok-launch-arr { color:var(--cok-text-3); margin-top:var(--e-10); flex:none; display:flex; }
.cok-launch-ready { display:flex; align-items:center; gap:var(--e-8); padding:var(--e-10) var(--e-12); border-radius: var(--r-md); font-size:var(--t-meta); margin-bottom:var(--e-16); line-height:var(--lh-serre); }
/* Le bandeau collait au texte qui le précède (« Donner un visage » puis, sans
   respirer, « Tous tes comptes ont une vendeuse »). On ne met l'espace QUE s'il suit
   quelque chose : sur les 22 endroits où il sert, il ouvre parfois la carte, et là un
   décalage en haut le ferait flotter. */
.cok-launch-ready:not(:first-child) { margin-top:var(--e-14); }
.cok-launch-ready svg { flex:none; }
.cok-launch-ready.ok { background:var(--cok-green-bg); color:var(--cok-green); }
.cok-launch-ready.warn { background:var(--cok-warn-bg); color:var(--cok-warn); }
.cok-launch-btn { width:100%; display:flex; justify-content:center; align-items:center; gap:var(--e-8); padding:var(--e-12); font-size:var(--t-small); border-radius: var(--r-lg); }
.cok-launch-note { display:flex; align-items:center; justify-content:center; gap:var(--e-6); margin-top:var(--e-12); font-size:var(--t-meta); color:var(--cok-text-3); text-align:center; }
.cok-launch-note svg { flex:none; }
.cok-cp-form { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-16); margin-top:var(--e-4); }
.cok-cp-form-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:var(--e-12); }
.cok-cp-form-grid label { display:flex; flex-direction:column; gap:var(--e-6); font-size:var(--t-meta); color:var(--cok-text-2); }
.cok-cp-form-grid input { height:36px; border:1px solid var(--cok-border-2); background:rgba(var(--th-ombre),.18); border-radius: var(--r-sm); padding:0 var(--e-10); color:var(--cok-text); font-size:var(--t-base); width:100%; box-sizing:border-box; }
.cok-cp-form-grid input:focus { outline:none; border-color:var(--cok-accent); }
/* Auto-remplissage Brave/Chrome : garder le fond sombre (sinon la case devient blanche = moche) */
.cok-cp-form-grid input:-webkit-autofill,
.cok-cp-form-grid input:-webkit-autofill:hover,
.cok-cp-form-grid input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--cok-text);
  -webkit-box-shadow: 0 0 0 1000px var(--cok-card) inset;
  caret-color: var(--cok-text);
  transition: background-color 9999s var(--c-pose) var(--t-bref); /* libre : 9999s neutralise le fond jaune de l autofill, ce n est pas une animation */
}
.cok-cp-pw { position:relative; display:flex; align-items:center; }
.cok-cp-pw input { padding-right:36px; }
.cok-cp-eye { position:absolute; right:4px; width:28px; height:28px; display:flex; align-items:center; justify-content:center; background:none; border:none; color:var(--cok-text-3); cursor:pointer; border-radius: var(--r-sm); padding:0; }
.cok-cp-eye:hover { color:var(--cok-text); }
.cok-cp-form-foot { display:flex; align-items:center; gap:var(--e-12); margin-top:var(--e-14); flex-wrap:wrap; }
/* Funnel de création : tapis roulant d'étapes (compte → e-mail → vendeuse → formation) */
.cok-fn { display:flex; flex-direction:column; gap:var(--e-2); background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-8); }
.cok-fn-step { display:flex; align-items:center; gap:var(--e-12); padding:var(--e-12) var(--e-12); border-radius: var(--r-md); transition: var(--transi); }
.cok-fn-step.on { background:var(--cok-accent-bg); }
.cok-fn-step.todo { opacity:.5; }
.cok-fn-mk { flex:none; width:22px; height:22px; border-radius:50%; border:1.5px solid var(--cok-border-2); display:flex; align-items:center; justify-content:center; color:var(--cok-text-3); }
.cok-fn-mk.done { background:var(--green); border-color:var(--green); color:#0b0b10; }
.cok-fn-mk.on { border-color:var(--cok-accent); }
.cok-fn-mk.on i { width:8px; height:8px; border-radius:50%; background:var(--cok-accent); box-shadow:0 0 0 3px color-mix(in srgb,var(--cok-accent) 25%,transparent); animation:cokFnPulse 1.4s ease-in-out infinite; }
@keyframes cokFnPulse { 0%,100%{ opacity:1; } 50%{ opacity:.35; } }
.cok-fn-tx { flex:1; min-width:0; }
.cok-fn-tx .t { font-size:var(--t-small); font-weight:var(--fw-fort); color:var(--cok-text); }
.cok-fn-step.on .cok-fn-tx .t { color:var(--cok-accent); }
.cok-fn-tx .d { font-size:var(--t-meta); color:var(--cok-text-3); margin-top:var(--e-2); }
.cok-fn-st { flex:none; font-size:var(--t-mini); font-weight:var(--fw-fort); letter-spacing:var(--ls-leger); text-transform:uppercase; color:var(--cok-text-3); }
.cok-fn-step.done .cok-fn-st { color:var(--green); }
.cok-fn-step.on .cok-fn-st { color:var(--cok-accent); }
.cok-fn-body { margin-top:var(--e-12); }
.cok-fn-done { background:color-mix(in srgb,#3fb37f 10%,transparent); border:1px solid color-mix(in srgb,#3fb37f 35%,transparent); border-radius: var(--r-lg); padding:var(--e-14) var(--e-16); font-size:var(--t-small); color:var(--cok-text); }
/* Grille des orphelines (vendeuses libres) proposées au montage */
.cok-orphgrid { grid-template-columns:repeat(auto-fill,minmax(130px,1fr)); gap:var(--e-10); margin-top:var(--e-12); }
.cok-orph-card { display:flex; flex-direction:column; align-items:center; gap:var(--e-8); background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-12) var(--e-10); }
.cok-orph-face { width:64px; height:64px; border-radius:50%; object-fit:cover; border:1.5px solid var(--cok-border-2); }
.cok-orph-noface { display:flex; align-items:center; justify-content:center; font-size:var(--t-title); font-weight:var(--fw-fort); color:var(--cok-text-3); background:rgba(var(--th-voile),.04); }
.cok-orph-nom { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text); text-align:center; line-height:var(--lh-titre); }
.cok-orph-btn { width:100%; justify-content:center; text-align:center; }
/* Widget « création en direct » : le 2e Brave incrusté — grand écran centré, épuré */
.cok-embed-wrap { width:100%; max-width:min(960px,100%); margin:var(--e-6) auto var(--e-2); }
.cok-st-row { display:flex; align-items:center; justify-content:center; gap:var(--e-10); margin:0 0 var(--e-14); flex-wrap:wrap; }
.cok-st { display:flex; align-items:center; gap:var(--e-6); font-size:var(--t-meta); color:var(--cok-text-3); }
.cok-st .cok-st-dot { width:8px; height:8px; border-radius:50%; background:var(--cok-text-3); }
.cok-st.done { color:var(--cok-text-2); } .cok-st.done .cok-st-dot { background:var(--green); }
.cok-st.on { color:var(--cok-accent); font-weight:var(--fw-fort); } .cok-st.on .cok-st-dot { background:var(--cok-accent); box-shadow:0 0 0 3px color-mix(in srgb,var(--cok-accent) 25%,transparent); }
.cok-st-sep { width:16px; height:1px; background:var(--cok-border-2); }
.cok-embed { border:1px solid var(--cok-border); border-radius: var(--r-lg); overflow:hidden; background:var(--bg); }
.cok-embed-bar { display:flex; align-items:center; gap:var(--e-8); padding:var(--e-10) var(--e-12); background:var(--surface); border-bottom:1px solid rgba(var(--th-voile),.07); }
.cok-embed-title { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--text); display:flex; align-items:center; gap:var(--e-8); }
.cok-embed-dot { width:8px; height:8px; border-radius:50%; background:var(--red); animation:cokEmbedPulse 1.6s infinite; }
.cok-embed.paused .cok-embed-dot { background:var(--amber); animation:none; }
@keyframes cokEmbedPulse { 0%{box-shadow:0 0 0 0 rgba(229,72,77,.5)} 70%{box-shadow:0 0 0 6px rgba(229,72,77,0)} 100%{box-shadow:0 0 0 0 rgba(229,72,77,0)} }
.cok-embed-btn { display:inline-flex; align-items:center; gap:var(--e-6); font-size: var(--t-meta); padding: var(--e-6) var(--e-12); border-radius: var(--r-sm); border:1px solid rgba(var(--th-voile),.16); background:var(--bg-elevated); color:var(--text); cursor:pointer; }
.cok-embed-btn:hover { background:rgba(var(--th-voile),.12); }
.cok-embed-btn.danger { border-color:rgba(229,72,77,.4); color:var(--red); background:rgba(229,72,77,.12); }
.cok-embed-btn.danger:hover { background:rgba(229,72,77,.2); }
.cok-embed-screen { display:flex; align-items:center; justify-content:center; background:var(--bg); min-height:clamp(220px,42vh,560px); max-height:80vh; padding:clamp(8px,1.6vw,18px); }
.cok-embed-screen img { display:block; max-width:100%; max-height:74vh; width:auto; height:auto; border-radius: var(--r-sm); -webkit-user-drag:none; cursor:grab; touch-action:none; }
/* curseur anti-robot : on l'agrandit un peu pour qu'il soit confortable à glisser (reste net) */
.cok-embed.cap .cok-embed-screen img { width:min(560px,100%); height:auto; max-height:none; }
.cok-embed.paused .cok-embed-screen img { cursor:not-allowed; opacity:.7; }
.cok-embed-cap { text-align:center; padding:var(--e-12) var(--e-8) 0; font-size:var(--t-base); color:var(--cok-text-2); line-height:var(--lh-normal); }
.cok-embed-foot { display:flex; align-items:center; justify-content:center; gap:var(--e-14); margin-top:var(--e-14); flex-wrap:wrap; }
.cok-embed-note { font-size:var(--t-meta); color:var(--cok-text-3); }
.cok-cp-manual { margin:var(--e-4) 0 var(--e-2); }
.cok-cp-manual > summary { cursor:pointer; font-size:var(--t-base); color:var(--cok-text-2); list-style:none; padding:var(--e-6) 0; user-select:none; }
.cok-cp-manual > summary::-webkit-details-marker { display:none; }
.cok-cp-manual > summary::before { content:'▸ '; color:var(--cok-text-3); }
.cok-cp-manual[open] > summary::before { content:'▾ '; }
.cok-cp-lock { font-size:var(--t-mini); color:var(--cok-text-3); flex:1; min-width:170px; }
.cok-cp-acc-head .cok-acc-av { width:26px; height:26px; font-size:var(--t-meta); }
/* Comptes / Gérer — grille de cartes compactes (tri : plus proches du plafond en haut) */
.cok-g-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:var(--e-12); }
.cok-g-card { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-14); display:flex; flex-direction:column; gap:var(--e-10); }
.cok-g-head { display:flex; align-items:center; gap:var(--e-10); min-width:0; }
.cok-g-head .cok-acc-av { width:30px; height:30px; font-size:var(--t-base); }
.cok-g-name { font-size:var(--t-small); font-weight:var(--fw-fort); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cok-g-charge { display:flex; justify-content:space-between; font-size:var(--t-meta); color:var(--cok-text-2); }
.cok-g-foot { margin-top:var(--e-2); display:flex; flex-direction:column; gap:var(--e-6); }
.cok-g-btn { width:100%; }
.cok-g-ok { font-size:var(--t-meta); color:var(--cok-text-3); }
/* ── Cockpit / Annonces — vitrine du batch en direct + gros plan ────────── */
@keyframes anShim { 0%{background-position:-200px 0} 100%{background-position:200px 0} }
@keyframes anPulse { 0%,100%{opacity:1} 50%{opacity:.35} }
.an-cadran { display:flex; align-items:center; gap:var(--e-18); background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-14) var(--e-18); margin-bottom:var(--e-16); flex-wrap:wrap; }
.an-gauge { position:relative; width:74px; height:74px; flex:0 0 auto; }
.an-gauge svg { width:74px; height:74px; transform:rotate(-90deg); }
.an-gauge circle.bg { fill:none; stroke:var(--cok-border-2); stroke-width:3; }
.an-gauge circle.fg { fill:none; stroke:var(--cok-accent); stroke-width:3; stroke-linecap:round; transition:stroke-dasharray .5s; }
.an-gt { position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center; }
.an-gt b { font-size:var(--t-body); font-weight:var(--fw-fort); line-height:var(--lh-un); } .an-gt span { font-size:var(--t-micro); color:var(--cok-text-3); }
.an-stats { display:flex; gap:var(--e-20); flex-wrap:wrap; } .an-stats .l { font-size:var(--t-meta); color:var(--cok-text-2); } .an-stats .v { font-size:var(--t-lead); font-weight:var(--fw-fort); }
.an-live { display:inline-flex; align-items:center; gap:var(--e-8); font-size:var(--t-meta); color:var(--cok-accent); }
.an-live-dot { width:8px; height:8px; border-radius:50%; background:var(--cok-accent); animation:anPulse 1.1s ease-in-out infinite; }
.an-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(280px,1fr)); gap:var(--e-12); }
.an-card { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-12); cursor:pointer; transition:border-color var(--t-moyen); }
.an-card:hover { border-color:var(--cok-border-2); }
.an-cardh { display:flex; align-items:center; gap:var(--e-8); margin-bottom:var(--e-10); }
.an-av { width:26px; height:26px; border-radius:50%; color: var(--sur-accent); display:flex; align-items:center; justify-content:center; font-size:var(--t-mini); font-weight:var(--fw-fort); flex:0 0 auto; }
.an-name { font-size:var(--t-base); font-weight:var(--fw-fort); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.an-robe { font-size:var(--t-meta); color:var(--cok-text-3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.an-pill { font-size:var(--t-micro); font-weight:var(--fw-fort); border-radius: var(--r-pilule); padding:var(--e-4) var(--e-10); white-space:nowrap; }
.an-thumbs { display:grid; grid-template-columns:1fr 1fr 1fr; gap:var(--e-6); }
/* (.an-th : tout est passé dans le composant `.v-photo`, plus haut.) */
.an-th-render { background:linear-gradient(100deg,rgba(var(--th-voile),.04) 30%,rgba(var(--th-voile),.12) 50%,rgba(var(--th-voile),.04) 70%); background-size:220px 100%; animation:anShim 1.1s linear infinite; }
.an-th-wait { border:1px dashed var(--cok-border-2); display:flex; align-items:center; justify-content:center; color:var(--cok-text-3); font-size:var(--t-body); }
.an-th-b { position:absolute; left:4px; bottom:4px; font-size:var(--t-micro); padding:var(--e-2) var(--e-6); border-radius: var(--r-sm); background:rgba(240,194,90,.92); color:#3a2a05; font-weight:var(--fw-fort); }
/* ── UN ESSAI EN COURS N'EST PAS UN VERDICT ──────────────────────────────────
   Le rendu refusé restait affiché avec l'étiquette « recalé » PENDANT qu'un nouvel
   essai tournait (Amadou, 13/08 : « au début ça met recalée et après ça met conforme »).
   L'image reste visible — elle dit où l'on en est — mais elle s'éteint au lieu de
   s'accuser : on voit qu'elle travaille, on ne lit pas un refus. */
/* ⭐ EXACTEMENT L'ANIMATION DE L'ONGLET GÉNÉRATION (Amadou, 13/08 : « si elle est en
   cours de modification je dois voir l'animation de modification comme dans l'onglet
   génération »). C'est `genVfScan` — le balayage violet de `.image-card.gen-verifying`,
   déjà défini plus bas dans cette feuille. On RÉUTILISE la même image de mouvement :
   deux écrans qui font la même chose doivent le dire de la même façon. */
.an-th-encours, .an-bth.an-th-encours { overflow:hidden; }
.an-th-encours::after {
  content:""; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(180deg, transparent 0%, rgba(var(--th-accent-rgb),.04) 42%, var(--tier-premium-glow) 50%, rgba(var(--th-accent-rgb),.04) 58%, transparent 100%);
  transform:translateY(-100%); animation:genVfScan 1.5s ease-in-out infinite; }
/* Le voile sombre remplace l'`opacity:.72` que Génération pose sur son <img> : ici
   l'image est un `background-image`, on ne peut pas l'atténuer sans atténuer l'étiquette. */
.an-th-encours::before {
  content:""; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:rgba(var(--th-ombre),.34); border-radius:inherit; }

/* ── ÉCARTÉE DE L'ANNONCE ────────────────────────────────────────────────────
   « Quand ça veut pas, ça veut pas » (Amadou) : la vue facultative abandonnée après
   trois essais. Elle reste VISIBLE — on doit pouvoir juger si l'abandon était fondé —
   mais elle sort de l'annonce, et le tiret du liseré le dit sans un mot. */
.an-th-ecartee { opacity:.42; outline:1px dashed rgba(var(--th-trait),.4); outline-offset:-1px; }
.an-th-b.eca { background:rgba(var(--th-trait),.9); color: var(--text); }
/* Repêchée par Le Second : elle passe, mais pas du premier coup — et ça se dit.
   L'ambre du site (--amber), pas le vert : « passée de justesse » n'est pas « conforme ». */
.an-th-b.rep { background:rgba(var(--th-accent-rgb),.92); color:#16122e; }
/* ── CE QUI CLOCHE, ET DE QUEL ORDRE ─────────────────────────────────────────
   Trois contrôles, trois questions différentes. Le liseré de gauche porte le TYPE :
   on doit savoir en un coup d'œil s'il faut refaire une photo ou relire un texte.
   ⚠️ Filet à gauche seulement → pas de coins arrondis (une bordure sur un seul côté
   avec un radius laisse un moignon de courbe dans le vide). */
.an-soucis { display:flex; flex-direction:column; gap:var(--e-6); margin-top:var(--e-12); }
.an-souci { font-size:var(--t-meta); line-height:var(--lh-normal); color:var(--cok-text-2);
  border-left:2px solid var(--cok-text-3); padding:var(--e-2) 0 var(--e-2) var(--e-10); border-radius:0; }
.an-souci b { display:block; font-weight:var(--fw-fort); font-size:var(--t-mini); color:var(--cok-text); margin-bottom:var(--e-1); }
.an-souci.fidelite  { border-left-color:var(--red); }
.an-souci.coherence { border-left-color:var(--amber); }
.an-souci.texte     { border-left-color:var(--cyan); }
.an-souci.manquante { border-left-color:var(--red); }
.an-souci.ecartee   { border-left-color:rgba(var(--th-trait),.5); }
.an-souci.ok        { border-left-color:var(--green); }
/* Le détail chiffré d'une erreur de texte : décalé, plus petit, il appartient à la ligne
   du dessus sans la répéter. */
.an-souci-d { font-size:var(--t-mini); line-height:var(--lh-normal); color:var(--cok-text-3); padding-left:var(--e-20); }
.an-souci-d i { font-style:normal; color:var(--cok-text-2); }

/* ══════════════════════════════════════════════════════════════════════════════
   PRODUCTION — L'ÉCRAN PENDANT ET APRÈS
   ══════════════════════════════════════════════════════════════════════════════
   Refonte du 13/08 : Amadou — « ce n'est pas agréable à voir et ça sort de la DA
   du site ». Trois représentations de l'avancement disaient la même chose ; les
   étapes étaient dessinées avec des caractères `● ◉ ○` ; les annonces étaient des
   cartes en grille alors qu'on cherche celle qui coince, pas qu'on les contemple. */

/* ── L'EN-TÊTE ET LA JAUGE ──────────────────────────────────────────────────
   Une seule barre. Chaque segment est une PART du lot : l'avancement se lit à la
   longueur, sans lire un chiffre. Les chiffres restent en légende — ils ne sont
   plus le moyen principal, ils sont la précision. */
.an-tete { margin-bottom: var(--e-20); }
.an-tete-h { display:flex; align-items:center; gap:var(--e-12); margin-bottom:var(--e-12); }
.an-tete-n { font-size:var(--t-meta); color:var(--cok-text-3); font-variant-numeric:tabular-nums; }
.an-jauge { display:flex; height:6px; border-radius:var(--r-pilule); overflow:hidden;
  background:rgba(var(--th-trait),.13); }
/* La largeur s'anime : on VOIT le lot avancer au lieu de le voir sauter. */
.an-jauge i { display:block; transition:width var(--t-moyen) var(--c-pose); }
.an-leg { display:flex; flex-wrap:wrap; gap:var(--e-6) var(--e-20); margin-top:var(--e-10);
  font-size:var(--t-meta); color:var(--cok-text-3); }
.an-leg span { display:inline-flex; align-items:center; gap:var(--e-8); }
.an-leg b { font-weight:var(--fw-fort); color:var(--cok-text-2); font-variant-numeric:tabular-nums; }
.an-leg i { width:6px; height:6px; border-radius:50%; background:var(--cok-text-3); flex:0 0 auto; }
.an-leg .pale { opacity:.6; }

/* ── LA MULTIPLICATION DU LANCEUR ───────────────────────────────────────────
   Le seul chiffre qui compte avant de payer : combien on fabrique. Il se lisait
   entre deux compteurs éloignés, à faire de tête. */
.an-calc { display:flex; align-items:center; justify-content:center; flex-wrap:wrap; gap:var(--e-14);
  padding:var(--e-14) var(--e-16); margin-bottom:var(--e-12); border-radius:var(--r-lg);
  background:var(--violet-tint); border:1px solid rgba(var(--th-accent-rgb),.2); }
.an-calc-n { text-align:center; display:flex; flex-direction:column; gap:var(--e-2);
  font-size:var(--t-meta); color:var(--cok-text-3); }
.an-calc-n b { font-size:var(--t-title); font-weight:var(--fw-moyen); line-height:var(--lh-titre); color:var(--cok-text);
  font-variant-numeric:tabular-nums; }
.an-calc-n.fort b { color:var(--violet-light); }
.an-calc-o { font-size:var(--t-body); color:var(--cok-text-3); }

/* ══════════════════════════════════════════════════════════════════════════════
   LES FORMES PARTAGÉES — la duplication qui restait
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️ Après le rangement en jetons, il restait des familles qui dessinent EXACTEMENT
   la même chose sans le savoir. On les a trouvées en regroupant par valeur RÉSOLUE
   (et non par texte) : `var(--border)` et `var(--cok-border)` sont le même filet
   depuis qu'ils sont alias, `var(--surface-2)` et `var(--cok-card)` le même fond —
   deux familles pouvaient donc être identiques tout en s'écrivant différemment.
   Chaque groupe ci-dessous était écrit N fois. Il l'est une. */

/* 5 familles partageaient cette forme. */
.textarea,
.atelier-textarea,
.atelier-input,
.mod-input,
.mod-textarea {
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-12) var(--e-14);
}

/* 5 familles partageaient cette forme. */
.name-modal-input,
.regen-input,
.regen-simple-input,
.model-info-textarea,
.dress-select {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: var(--e-10) var(--e-12);
}

/* 5 familles partageaient cette forme. */
.conf-extra,
.ctrl-esc-card,
.ctrl-feed-card,
.msg-reply-text,
.mand-ligne {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12);
}

/* 4 familles partageaient cette forme. */
.de-dd-trigger,
.pa-conn-card,
.batch-recap-card,
.batch-history-row {
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-14) var(--e-16);
}

/* 3 familles partageaient cette forme. */
.nav-switch,
.batch-mode-switch,
.fin-period {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-4);
}

/* 3 familles partageaient cette forme. */
.vd-bio,
.cok-gf-input,
.mand-mode {
  background: var(--surface);
  border: 1px solid var(--cok-border);
  border-radius: var(--r-md);
  padding: var(--e-12) var(--e-14);
}

/* 3 familles partageaient cette forme. */
.lit-r,
.lib-res-c,
.dom-l {
  background: var(--surface);
  border: 1px solid var(--bg-elevated);
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12);
}

/* 3 familles partageaient cette forme. */
.boutique-name-input,
.ctrl-feed-row,
.batch-stat-pill {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-14);
}

/* 3 familles partageaient cette forme. */
.cok-cons,
.cok-regl-row,
.cok-ident {
  background: var(--surface);
  border: 1px solid rgba(var(--th-voile),.07);
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12);
}

/* 3 familles partageaient cette forme. */
.cok-raf-champ,
.dom-ligne,
.form-tuile {
  background: var(--surface);
  border: 1px solid var(--cok-border,rgba(var(--th-voile),.07));
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12);
}

/* ══════════════════════════════════════════════════════════════════════════════
   LA CARTE — quatrième composant, et le plus structurant
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ MESURÉ LE 14/08 : 579 règles dessinent une carte. CENT QUARANTE-SEPT fonds
   différents, CENT TROIS filets, 17 arrondis, 107 retraits. C'est l'objet qui
   contient tout le reste du site, et il n'avait aucune définition.

   Et en mesurant, deux doublons de plus sont tombés :
     · `--cok-card` valait `rgba(var(--th-voile),.055)` et `--surface-2`
       `rgba(var(--th-voile),0.055)` — LA MÊME couleur. Mon passage sur les couleurs les
       avait ratées pour cette seule raison : un zéro devant la virgule ;
     · `--cok-border` (0,125) et `--border` (0,115) : un pour cent d'opacité d'écart
       sur un filet. Invisible à l'œil, mais deux noms à tenir d'accord.
   Les deux sont désormais des alias.

   ⭐ LA CARTE DE RÉFÉRENCE EST CELLE DU SITE : fond `--surface`, filet `--border`
   (163 emplois, largement majoritaire), arrondi `--r-lg`, retrait 12/14. Trois
   niveaux, parce que le site en a vraiment trois — la ligne de liste, la carte, le
   panneau — et pas parce qu'une théorie le veut. */
.v-carte,
/* ── Les dix familles raccrochées : celles dont la forme est DÉJÀ celle du site. ──
   Groupe ample (retrait 16/18) et groupe normal (12/14). Elles ne sont pas ajoutées
   dans le rendu — des centaines de sites d'appel — mais par cette liste. */
.cok-metric,
.cok-cap,
.cok-worker,
.cok-rz-card,
.cok-cp-create,
.cok-kcard,
.cok-cp-reccard,
.cok-cp-fstep,
.cok-tunnel-pas {
  background: var(--carte-fond);
  border: 1px solid var(--carte-filet);
  border-radius: var(--carte-rayon);
  padding: var(--carte-pad-v) var(--carte-pad-h);
}
/* ── LES TROIS NIVEAUX ──────────────────────────────────────────────────────── */
.v-carte--ligne   { --carte-rayon: var(--r-md); --carte-pad-v: var(--e-8);  --carte-pad-h: var(--e-12); }
.v-carte--panneau { --carte-rayon: var(--r-xl); --carte-pad-v: var(--e-16); --carte-pad-h: var(--e-18); }
/* La carte ample : même arrondi, plus d'air. C'est la forme des six tuiles du cockpit. */
.v-carte--ample,
.cok-metric,
.cok-cap,
.cok-worker,
.cok-rz-card,
.cok-cp-create { --carte-pad-v: var(--e-16); --carte-pad-h: var(--e-18) }
/* ── LES VARIANTES ──────────────────────────────────────────────────────────── */
/* Sans fond : une carte qui ne fait que délimiter, sans peser. */
.v-carte--nue      { --carte-fond: transparent; }
/* Posée sur une carte : un cran plus clair, sinon elle disparaît dans sa mère. */
.v-carte--posee    { --carte-fond: var(--surface-2); }
/* Celle qu'on désigne — la ligne ouverte, l'annonce choisie. */
.v-carte--choisie  { --carte-filet: var(--violet-soft); }
.v-carte--alerte   { --carte-fond: var(--danger-fond); --carte-filet: var(--danger-bord); }

/* ══════════════════════════════════════════════════════════════════════════════
   LA PASTILLE — troisième composant réutilisable
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ MESURÉ LE 14/08 : 147 règles dessinent une pilule, dont 103 purement
   décoratives — les vraies pastilles (les 44 autres sont cliquables : ce sont des
   boutons ou des onglets, ils ne rentrent pas ici).
   Vingt-deux combinaisons de retrait pour ce qui est TOUJOURS le même objet : un mot
   court dans une pilule teintée. Et la forme majoritaire — retrait 2/8, texte 10 px —
   est écrite à l'identique par ONZE familles qui s'ignorent, avec trois graisses
   différentes selon l'humeur du jour.

   ⭐ LES TONS SONT EMPRUNTÉS, PAS INVENTÉS : `--cok-green-bg`, `--cok-warn-bg`,
   `--cok-red-bg`, `--cok-accent-bg` existent déjà et servent partout. Une pastille
   « tout va bien » n'a aucune raison d'avoir son propre vert. */
.v-pastille,
.lib-marque-badge, .atelier-cost, .lib-picker-coloris-tag, .lib-card-code {
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
  font-size:   var(--pas-texte);
  font-weight: var(--pas-graisse);
  padding:     var(--pas-pad-v) var(--pas-pad-h);
  border-radius: var(--r-pilule);
  white-space: nowrap;
  line-height: var(--lh-un);
}
/* ── LES TAILLES ────────────────────────────────────────────────────────────── */
.v-pastille--md { --pas-texte: var(--t-meta); --pas-pad-v: var(--e-4); --pas-pad-h: var(--e-12); }
.v-pastille--gras { --pas-graisse: var(--fw-gras); }
/* ── LES TONS ───────────────────────────────────────────────────────────────── */
.v-pastille--ok      { background: var(--cok-green-bg);  color: var(--green); }
.v-pastille--attente { background: var(--cok-warn-bg);   color: var(--amber); }
.v-pastille--alerte  { background: var(--cok-red-bg);    color: var(--red); }
.v-pastille--violet  { background: var(--cok-accent-bg); color: var(--violet-light); }
.v-pastille--neutre  { background: var(--bg-elevated); color: var(--text-2); }

/* ══════════════════════════════════════════════════════════════════════════════
   LE BOUTON — deuxième composant réutilisable
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ MESURÉ LE 13/08 : 338 règles dessinent un bouton, réparties sur DEUX CENT
   QUINZE familles de classes. Quatre-vingt-une combinaisons de retrait pour ce qui
   n'est au fond que trois tailles, onze arrondis, douze tailles de texte.
   Et le même petit bouton — texte à 12 px, retrait 6/12 — est RÉINVENTÉ localement
   une dizaine de fois : `.dom-ligne .cok-btn`, `.lien-actes .cok-btn`, `.btn-action`
   en seconde déclaration… chacun ignorant que le voisin faisait pareil.

   ⭐ LA FORME DE RÉFÉRENCE EST CELLE DU SITE, pas une nouvelle : `.v-btn` reprend
   exactement `.cok-btn` (74 emplois, le bouton de fait). On n'invente rien, on NOMME
   ce qui existe — et on donne enfin un nom aux variantes que tout le monde
   réinventait dans son coin.

   ⚠️ Les pastilles (`.cok-chip`, `.an-racc-b`) ne sont PAS des boutons : forme de
   pilule, autre rôle. Elles auront leur composant, elles n'entrent pas ici de force. */
.v-btn,
.cok-btn {
  font-family: inherit;
  font-size:   var(--btn-texte);
  font-weight: var(--fw-moyen);
  padding:     var(--btn-pad-v) var(--btn-pad-h);
  border-radius: var(--btn-rayon);
  border: 1px solid var(--cok-border-2);
  cursor: pointer;
}
/* ── LA PETITE TAILLE, celle qu'on réinventait ─────────────────────────────── */
/* ⚠️ LE FOND ET LA COULEUR SUR `.v-btn` SEUL, pas sur la règle partagée : `.cok-btn`
   pose déjà les siens plus haut dans la feuille, et les redire ici les figerait.
   Sans cette ligne, un `class="v-btn"` tout neuf héritait du GRIS PAR DÉFAUT du
   navigateur — un composant qui, livré nu, ne ressemble à rien du site. */
.v-btn { background: var(--surface); color: var(--cok-text); white-space: nowrap;
  transition: var(--transi-vif); }
.v-btn:hover:not(:disabled) { background: var(--survol-fond); border-color: var(--survol-bord); }

.v-btn--sm { --btn-texte: var(--t-meta); --btn-pad-v: var(--e-6); --btn-pad-h: var(--e-12); }
.v-btn--lg { --btn-texte: var(--t-small); --btn-pad-v: var(--e-10); --btn-pad-h: var(--e-16); }
/* ── LES TONS ──────────────────────────────────────────────────────────────── */
.v-btn--pri, .cok-btn.pri {
  background: var(--cok-accent-bg); color: var(--cok-accent); border-color: transparent;
}
.v-btn--fantome, .cok-btn--ghost { background: var(--bg-elevated); }
.v-btn--danger {
  background: var(--danger-fond); color: var(--red); border-color: var(--danger-bord);
}
/* ── LA PILULE : même bouton, autre silhouette ─────────────────────────────── */
.v-btn--pilule { --btn-rayon: var(--r-pilule); }
/* Un bouton désactivé ne ment pas sur ce qu'il fera. */
.v-btn:disabled, .cok-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ══════════════════════════════════════════════════════════════════════════════
   LA VIGNETTE — le premier vrai composant réutilisable
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (13/08) : « faire des éléments réutilisables ».
   ⚠️⚠️ CE QUE J'AI TROUVÉ EN MESURANT. « Une photo dans une boîte arrondie » est la
   forme la plus répétée du site : SOIXANTE-ET-ONZE règles la redessinent, dont 39 au
   format 3/4. Et elles ne s'accordent sur rien —
     · deux orthographes du même ratio : `3/4` (23 fois) et `3 / 4` (16) ;
     · QUATRE rayons pour le même objet : `--r-sm` (8 px, 31 fois), `--r-md` (10 px,
       18), `--r-lg` (12), `--radius` (14), plus des `4px` et `2px` écrits à la main.
   Personne n'a jamais décidé que la photo d'une robe aurait des coins de 8 px dans la
   bibliothèque et de 10 px dans le lanceur : c'est le résultat de 71 décisions prises
   séparément, chacune raisonnable, l'ensemble incohérent.

   ⭐ LA RÈGLE DU JEU : le composant se règle ICI, par ses trois jetons. Les familles
   existantes y sont RACCROCHÉES par la liste de sélecteurs — c'est le pont de
   migration, et il ne demande pas de toucher une seule ligne de rendu. Le code NEUF,
   lui, écrit `class="v-photo"` et n'a plus de CSS à écrire du tout. */
.v-photo,
.an-sv-i,          /* lanceur : robes et vendeuses */
.an-th,            /* production : les trois vues d'une ligne */
.an-bth {          /* production : les trois vues du gros plan */
  position: relative;
  aspect-ratio: var(--photo-ratio);
  border-radius: var(--photo-rayon);
  background-color: var(--photo-fond);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  overflow: hidden;
}
/* Une image posée DANS la vignette la remplit — sinon chaque appelant réécrit les
   mêmes quatre lignes, et c'est exactement ce qu'on est en train de défaire. */
.v-photo > img, .an-sv-i > img, .an-th > img, .an-bth > img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}

/* ── UNE LIGNE PAR ANNONCE ──────────────────────────────────────────────────
   ⚠️ Pas de `translateY` au survol : sur des lignes à 6 px d'écart, une ligne qui
   se soulève passe sous sa voisine. Le survol se dit par le filet. */
.an-liste { display:flex; flex-direction:column; gap:var(--e-6); }
.an-l { display:flex; align-items:center; gap:var(--e-12); padding:var(--e-10) var(--e-12); cursor:pointer;
  border:1px solid var(--cok-border); border-radius:var(--r-lg);
  background:var(--cok-bg-2);
  transition:border-color var(--t-bref) var(--c-pose), background var(--t-bref) var(--c-pose); }
.an-l:hover { border-color:var(--violet-soft); background:rgba(var(--th-voile),.04); }
.an-l-txt { flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:var(--e-2); }
.an-l-t { font-size:var(--t-base); font-weight:var(--fw-fort); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.an-l-t em { font-style:normal; font-weight:var(--fw-normal); color:var(--cok-text-3); margin-left:var(--e-6); }
.an-l-s { font-size:var(--t-meta); display:flex; align-items:baseline; gap:var(--e-8); min-width:0; }
.an-l-r { color:var(--cok-text-3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.an-l-r.pale { opacity:.62; }
/* Le motif porte sa couleur : on sait s'il faut refaire une photo ou relire un texte
   sans avoir à lire la phrase. Mêmes couleurs que le panneau de détail. */
.an-l-mot { flex:0 0 auto; font-weight:var(--fw-fort); font-size:var(--t-micro); letter-spacing:var(--ls-leger);
  padding:var(--e-1) var(--e-8); border-radius:var(--r-pilule); }
.an-l-mot.fidelite  { background:rgba(var(--th-danger-rgb),.16); color:var(--red); }
.an-l-mot.coherence { background:rgba(240,176,85,.16);  color:var(--amber); }
.an-l-mot.texte     { background:var(--cyan-tint); color:var(--cyan-light); }
.an-l-mot.manquante { background:rgba(var(--th-danger-rgb),.16); color:var(--red); }
/* Les trois vues, alignées d'une ligne à l'autre : c'est ce qui permet de comparer
   le lot d'un seul regard vertical. */
.an-l-vues { display:flex; gap:var(--e-6); flex:0 0 auto; }
.an-l-vues .an-th { width:30px; height:40px; aspect-ratio:auto; }
.an-l .an-pr { font-size:var(--t-meta); font-weight:var(--fw-fort); color:var(--cok-green); flex:0 0 auto;
  font-variant-numeric:tabular-nums; }
.an-l .an-pill { flex:0 0 auto; }
.an-l-chev { flex:0 0 auto; display:inline-flex; color:var(--cok-text-3);
  transition:color var(--t-bref) var(--c-pose), transform var(--t-bref) var(--pose); }
.an-l:hover .an-l-chev { color:var(--violet-light); transform:translateX(2px); }

/* ── LA FIN DU LOT ──────────────────────────────────────────────────────────
   Les chips reprennent le motif de la Bibliothèque (`.lib-fchip`) : le site sait
   déjà dire « filtre » d'une seule façon, on ne va pas en inventer une deuxième. */
.an-filtres { display:flex; gap:var(--e-6); margin-bottom:var(--e-12); }
.an-fchip { font:inherit; font-size: var(--t-meta); padding: var(--e-6) var(--e-12); border-radius:var(--r-pilule);
  border:1px solid var(--cok-border-2); background:transparent; color:var(--cok-text-3);
  cursor:pointer; transition:color var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose), background var(--t-bref) var(--c-pose); }
.an-fchip:hover { color:var(--cok-text-2); border-color:rgba(var(--th-accent-rgb),.5); }
.an-fchip.on { background:var(--violet-tint); border-color:var(--tier-premium-glow); color:var(--violet-light); }
/* Le coût réel n'est pas une alerte : il se pose en pied de page, discret, et ne
   parle du dépassement que s'il y en a un. */
.an-bilan { margin-top:var(--e-16); padding-top:var(--e-14); border-top:1px solid var(--cok-border);
  font-size:var(--t-meta); color:var(--cok-text-3); display:flex; gap:var(--e-10); align-items:baseline; }
.an-bilan b { color:var(--cok-text-2); font-weight:var(--fw-fort); font-variant-numeric:tabular-nums; }

.an-txt { display:flex; align-items:center; justify-content:space-between; gap:var(--e-8); margin-top:var(--e-10); }
.an-tt { font-size:var(--t-meta); font-weight:var(--fw-moyen); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.an-pr { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-green); flex:0 0 auto; }
.an-txtw { font-size:var(--t-meta); color:var(--cok-text-3); margin-top:var(--e-10); }
.an-pipe { display:flex; gap:var(--e-6); flex-wrap:wrap; margin-top:var(--e-10); }
.an-pipe-s { font-size:var(--t-micro); display:inline-flex; align-items:center; gap:var(--e-4); } .an-pipe-s i { font-style:normal; }
.an-launch { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-18); }
.an-launch-t { font-size:var(--t-small); font-weight:var(--fw-fort); } .an-launch-s { font-size:var(--t-meta); color:var(--cok-text-2); margin:var(--e-4) 0 var(--e-14); }
.an-launch-r { display:flex; align-items:center; gap:var(--e-10); flex-wrap:wrap; } .an-launch-r .cok-btn b { font-weight:var(--fw-gras); margin-left:var(--e-4); }
.an-x { color:var(--cok-text-3); } .an-count { font-size:var(--t-base); color:var(--cok-accent); font-weight:var(--fw-fort); }
.an-focus { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-16); }
.an-focush { display:flex; align-items:center; gap:var(--e-8); margin-bottom:var(--e-14); }
.an-fviews { display:grid; grid-template-columns:1fr 1fr 1fr; gap:var(--e-10); margin-bottom:var(--e-16); }
/* (.an-bth : tout est passé dans le composant `.v-photo`. ⚠️ Elle portait --r-md
   quand sa jumelle .an-th portait --r-sm : deux rayons pour la MÊME vue, à deux
   écrans d'écart. C'est ce genre d'écart que le composant supprime.) */
.an-bthl { position:absolute; left:6px; bottom:6px; font-size:var(--t-micro); padding:var(--e-2) var(--e-8); border-radius: var(--r-md); background:rgba(var(--th-ombre),.5); color: var(--sur-sombre); }
.an-fgrid { display:grid; grid-template-columns:1.2fr 1fr; gap:var(--e-16); }
.an-ftxt, .an-fpipe { background:var(--cok-bg-2); border:1px solid var(--cok-border); border-radius: var(--r-md); padding:var(--e-12) var(--e-14); }
.an-fl { font-size:var(--t-micro); text-transform:uppercase; letter-spacing:var(--ls-large); color:var(--cok-text-3); margin:var(--e-10) 0 var(--e-4); } .an-fl:first-child { margin-top:0; }
.an-fv { font-size:var(--t-base); font-weight:var(--fw-moyen); } .an-fv2 { font-size:var(--t-meta); color:var(--cok-text-2); line-height:var(--lh-normal); }
.an-fstep { display:flex; align-items:center; gap:var(--e-8); font-size:var(--t-base); padding:var(--e-4) 0; } .an-fstep span { width:18px; text-align:center; }
@media (max-width:640px){ .an-fgrid { grid-template-columns:1fr; } }
.cok-acc-name { flex:1; min-width:0; font-size:var(--t-base); font-weight:var(--fw-moyen); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cok-acc-open { padding:var(--e-6) var(--e-12) !important; font-size:var(--t-meta) !important; }

/* (Un second bloc .nav-item--soon / .nav-soon vivait ici. Il était plus bas dans le
   fichier que celui de la refonte, donc c'était LUI qui gagnait — la pastille « à venir »
   sortait en majuscules grasses de 9 px, avec une bordure dont on ne voulait pas.
   Supprimé : la définition qui compte est celle documentée plus haut.) */

.sidebar-footer {
  padding: var(--e-10) var(--e-8) var(--e-16);
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  flex-shrink: 0;
}

.api-status {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-6) var(--e-10);
  overflow: hidden;
}
.status-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--text-3);
  flex-shrink: 0;
  transition: background var(--t-long);
}
.status-dot.ok    { background: var(--green); box-shadow: 0 0 6px var(--green); }
.status-dot.error { background: var(--red); }
.status-label {
  font-size: var(--t-meta);
  color: var(--text-3);
  white-space: nowrap;
  transition: opacity var(--t-moyen);
}
.sidebar.collapsed .status-label { opacity: 0; }

.cost-display {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-6) var(--e-10);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: border-color var(--t-moyen), background var(--t-moyen);
  overflow: hidden;
}
.cost-display:hover { border-color: var(--violet-mid); background: var(--surface-2); }
.cost-value {
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transition: opacity var(--t-moyen);
}
.cost-value.nonzero { color: var(--violet-light); }
.sidebar.collapsed .cost-value { opacity: 0; }

/* ── Buttons — Aurora system : 1 primary + 1 ghost ───── */
/* ⚠️⚠️ CES LISTES DE `transition` AVAIENT PERDU `transform`. Le socle (§ boutons) donne
   à TOUT bouton un enfoncement `scale(var(--appui-echelle))` au clic — mais chacune de
   ces règles, écrite plus tard, réécrit `transition` en n'énumérant que background,
   color et border-color. En CSS une propriété absente de la liste change en 0 ms :
   l'enfoncement claquait et repartait instantanément, donc ne se voyait PAS. Mesuré sur
   « Filtres » : transitionProperty calculé = « background, color, border-color ».
   `transform` est remis partout, avec --c-rebond pour que l'appui « pop ».
   ⚠️ Toute nouvelle règle qui réécrit `transition` sur un bouton doit l'inclure. */
.btn-icon {
  width: 34px; height: 34px;
  border-radius: var(--r-sm);
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--t-bref) var(--c-rebond);
}
.btn-icon:hover {
  background: var(--survol-fond);
  color: var(--text);
  border-color: var(--survol-bord);
}

/* Primaire : un seul style, gradient aurora violet→cyan, réservé aux CTA */
.btn-primary {
  background: var(--aurora);
  border: none;
  color: var(--sur-plein);
  padding: var(--e-10) var(--e-22);
  border-radius: var(--r-sm);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: box-shadow var(--d-base) var(--c-pose), filter var(--d-fast) var(--c-pose);
  box-shadow: var(--glow-violet);
  display: inline-flex; align-items: center; gap: var(--e-8);
}
.btn-primary:hover { filter: brightness(1.05); box-shadow: 0 0 0 1px rgba(var(--th-accent-rgb),0.2), 0 14px 40px -12px rgba(var(--th-accent-rgb),0.55); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }

/* Ghost secondary : transparent, hover = fond léger qui apparaît */
.btn-ghost,
.btn-secondary,
.btn-action {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-2);
  padding: var(--e-8) var(--e-16);
  border-radius: var(--r-sm);
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--t-bref) var(--c-rebond);
  display: inline-flex; align-items: center; gap: var(--e-8);
  white-space: nowrap;
}
.btn-ghost:hover,
.btn-secondary:hover,
.btn-action:hover {
  background: var(--survol-fond);
  color: var(--text);
  border-color: var(--survol-bord);
}
.btn-ghost:disabled,
.btn-secondary:disabled,
.btn-action:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-action {
  font-size: var(--t-meta); padding: var(--e-6) var(--e-12);
  border-radius: var(--r-xs);
}

.btn-action.copied {
  color: var(--green);
  border-color: rgba(110,210,168,0.4);
}

.link-btn {
  background: none;
  border: none;
  color: var(--violet-soft);
  cursor: pointer;
  font-size: inherit;
  text-decoration: underline;
  text-decoration-color: transparent;
  transition: text-decoration-color var(--d-fast) var(--c-pose);
  padding: 0;
}
.link-btn:hover { text-decoration-color: var(--violet-soft); }

/* Generate CTA — le seul gradient aurora, jamais ailleurs */
.btn-generate {
  width: 100%;
  padding: var(--e-14) var(--e-28);
  border-radius: var(--r-md);
  border: none;
  cursor: pointer;
  font-size: var(--t-body);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-serre);
  color: var(--sur-accent);
  background: var(--aurora);
  position: relative;
  overflow: hidden;
  transition: filter var(--d-fast) var(--c-pose), box-shadow var(--d-base) var(--c-pose), transform var(--d-fast) var(--c-pose);
  box-shadow: var(--glow-violet);
}
.btn-generate:hover { filter: brightness(1.06); box-shadow: 0 0 0 1px rgba(var(--th-accent-rgb),0.22), 0 18px 50px -14px rgba(var(--th-accent-rgb),0.6), 0 18px 50px -14px var(--tier-volume-glow); }
.btn-generate:active { transform: translateY(1px); }
.btn-generate:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; filter: grayscale(0.4); }

.btn-generate-idle,
.btn-generate-busy {
  display: flex; align-items: center; justify-content: center; gap: var(--e-10);
}

.gen-cost-estimate {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  background: rgba(var(--th-voile),0.12);
  border-radius: var(--r-pilule);
  padding: var(--e-2) var(--e-8);
  letter-spacing: var(--ls-leger);
  opacity: 0.85;
}

.gen-status-text {
  text-align: center;
  font-size: var(--t-base);
  color: var(--text-3);
  margin-top: var(--e-10);
  min-height: 1.2em;
  letter-spacing: var(--ls-zero);
  animation: fadeIn var(--t-long) ease;
}
.gen-status-text .gen-status-step {
  color: var(--accent);
  font-weight: var(--fw-fort);
}

/* ── Library ─────────────────────────────────────────── */
/* Ancien header inline neutralisé (remplacé par la sticky topbar Aurora) */
.lib-header { display: none; }
.lib-title { display: none; }
.lib-header-actions { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap; }
.lib-io-btn { display: inline-flex; align-items: center; gap: var(--e-6); }

/* Sticky control bar sous la topbar.
   ⚠️ Ne JAMAIS remettre un nombre en dur ici : l'en-tête n'a plus de hauteur fixe
   depuis la refonte (titre 27 px, chemin de retour sur certains écrans, sous-onglets).
   `--topbar-h` est mesurée puis posée sur la section par _stickyOffsets() (app.js). */
.lib-sticky-bar {
  position: sticky;
  top: var(--topbar-h, 76px);
  z-index: 9;
  background: rgba(var(--th-panneau-rgb),0.78);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  border-bottom: 1px solid var(--border);
  margin: 0 calc(var(--e-32) * -1) var(--e-16);
  padding: var(--e-14) var(--e-32);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
}
.lib-search-row { margin-bottom: 0; }

/* Search input plein largeur — pattern Aurora */
.lib-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--e-8);
  height: 38px;
  padding: 0 var(--e-12);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose);
}
.lib-search-wrap:focus-within {
  border-color: var(--violet-glow);
  background: rgba(var(--th-voile),0.04);
}
.lib-search-wrap svg { flex-shrink: 0; color: var(--text-3); }
.lib-search-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text);
  font-size: var(--t-small);
  height: 100%;
  padding: 0;
}
.lib-search-input::placeholder { color: var(--text-3); }
.lib-search-clear {
  background: none; border: none; cursor: pointer;
  color: var(--text-3); padding: var(--e-2); border-radius: var(--r-micro);
  display: flex; align-items: center;
  transition: color var(--d-fast) var(--c-pose);
}
.lib-search-clear:hover { color: var(--text); }
.lib-no-results {
  text-align: center; color: var(--text-3);
  font-size: var(--t-small); padding: var(--e-48) 0;
}

/* Row 2 : tabs Modèles/Robes + Sélectionner à droite */
.lib-filters-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-12);
  padding: 0;
}

/* Tabs Modèles / Robes — segmented pill (biblio-tabs) */
.lib-filters {
  display: inline-flex;
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-4);
  gap: var(--e-2);
}
.lib-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-6) var(--e-12);
  border-radius: var(--r-sm);
  border: none;
  background: transparent;
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.lib-filter:not(.active):hover { color: var(--text); border-color: transparent; }
.lib-filter.active {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: transparent;
}
.lib-filter-count {
  display: inline-block;
  margin-left: 0;
  padding: var(--e-1) var(--e-8);
  border-radius: var(--r-pilule);
  background: rgba(var(--th-voile),0.04);
  color: var(--text-3);
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-serre);
  min-width: 18px;
  text-align: center;
}
/* ⚠️ LE CHIFFRE ACTIF DOIT SE LIRE. Amadou, 07/08 : « on ne voit pas avec la couleur,
   c'est du violet sur du gris ». Il avait raison : #9A8DFF sur un fond violet à 18 %
   d'opacité, donc quasiment le gris de la barre — deux tons voisins, aucun contraste.
   On rétroéclaire : pastille violette PLEINE, chiffre en clair. C'est le seul endroit
   de la barre qui porte une information chiffrée, elle a le droit de se voir. */
.lib-filter.active .lib-filter-count {
  background: var(--violet);
  color: var(--sur-accent);
  font-weight: var(--fw-fort);
}
.lib-filter-add-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  border: 1.5px dashed var(--text-3);
  background: var(--surface);
  color: var(--text-2); font-size: var(--t-small); font-weight: var(--fw-fort);
  cursor: pointer; transition: border-color var(--t-moyen), color var(--t-moyen);
  flex-shrink: 0;
}
.lib-filter-add-btn:hover { border-color: var(--violet); color: var(--violet-soft); }

/* Grid : 5 cols responsive (5 → 4 → 3) */
.lib-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
  gap: var(--e-16);
  margin-top: var(--e-4);
}

/* Card — wrapper avec image légèrement enclavée (pattern biblio-card) */
.lib-card {
  display: flex;
  flex-direction: column;
  padding: var(--e-6);
  background: linear-gradient(158deg, rgba(var(--th-voile),0.042) 0%, rgba(var(--th-voile),0.012) 55%);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: visible;
  cursor: pointer;
  position: relative;
  box-shadow: 0 5px 18px -12px rgba(var(--th-ombre),0.55), inset 0 1px 0 var(--bg-sidebar);
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
.lib-card:hover {
  border-color: var(--border-mid);
  transform: translateY(-3px);
  box-shadow: 0 16px 34px -14px rgba(var(--th-accent-rgb),0.5), inset 0 1px 0 var(--bg-elevated);
}
.lib-card-cover {
  position: relative;
  width: 100%;
  border-radius: var(--r-sm);
  overflow: hidden;
  aspect-ratio: 3 / 4;
  background:
    linear-gradient(135deg, var(--bg-hover) 0%, rgba(var(--th-voile),0.015) 100%);
}
.lib-card-cover img {
  width: 100%; height: 100%;
  object-fit: cover;
}
.lib-card-cover-placeholder {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
}
.lib-card-info {
  padding: var(--e-10) var(--e-8) var(--e-6);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-6);
}
.lib-card-text { flex: 1; min-width: 0; }
.lib-card-name {
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  color: var(--text);
  line-height: var(--lh-serre);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: text;
  border-radius: var(--r-micro);
  padding: var(--e-1) var(--e-4);
  margin: calc(var(--e-1) * -1) calc(var(--e-4) * -1);
  transition: background var(--d-fast) var(--c-pose);
}
.lib-card-name { display: flex; align-items: center; gap: var(--e-4); }
.lib-card-name-text { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-card-name-edit-icon { flex-shrink: 0; opacity: 0; color: var(--text-3); transition: opacity var(--t-moyen); }
.lib-card-name:hover .lib-card-name-edit-icon { opacity: 1; }
.lib-card-name:hover { background: var(--bg-elevated); }
.lib-name-edit {
  width: 100%; font-size: var(--t-base); font-weight: var(--fw-fort);
  background: var(--surface-2); border: 1px solid var(--violet-mid);
  border-radius: var(--r-micro); color: var(--text); padding: var(--e-2) var(--e-6);
  outline: none;
}
/* Select mode */
.lib-card.select-mode { cursor: pointer; }
.lib-card.selected { border-color: var(--violet-mid); background: rgba(var(--th-accent-rgb),0.08); }
.lib-card-cb {
  position: absolute; top: 8px; left: 8px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface-2); border: 1.5px solid var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; opacity: 0; transition: opacity var(--t-moyen);
}
.lib-card.select-mode .lib-card-cb { opacity: 1; }
.lib-card.selected .lib-card-cb {
  background: var(--violet-mid); border-color: var(--violet-mid);
}
.lib-card.selected .lib-card-cb::after {
  content: ''; display: block;
  width: 5px; height: 8px;
  border: 1.5px solid #fff; border-top: none; border-left: none;
  transform: rotate(45deg) translate(-1px, -1px);
}
.lib-card-meta {
  font-size: var(--t-mini);
  color: var(--text-3);
  margin-top: var(--e-2);
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
}
/* Badge "incomplet" sur les cartes robes */
.lib-card-incomplete-badge {
  position: absolute;
  top: 7px;
  left: 7px;
  background: rgba(234, 88, 12, 0.88);
  backdrop-filter: blur(4px);
  color: var(--text);
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  padding: var(--e-2) var(--e-8) var(--e-2) var(--e-6);
  border-radius: var(--r-xl);
  border: 1px solid rgba(var(--th-voile),0.18);
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: var(--e-4);
  z-index: 4;
}
.lib-card-no-style-badge {
  position: absolute;
  bottom: 7px;
  left: 7px;
  background: rgba(var(--th-panneau-rgb),0.72);
  backdrop-filter: blur(4px);
  color: var(--text-2);
  font-size: var(--t-micro);
  font-weight: var(--fw-fort);
  letter-spacing: var(--ls-large);
  padding: var(--e-2) var(--e-8);
  border-radius: var(--r-xl);
  border: 1px solid rgba(var(--th-voile),0.1);
  pointer-events: none;
  z-index: 4;
}

/* ── Badge étoiles sur la carte ── */
.lib-card-star-badge {
  position: absolute;
  top: 7px; right: 7px;
  background: rgba(var(--th-panneau-rgb),0.65);
  backdrop-filter: blur(4px);
  border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-xl);
  padding: var(--e-2) var(--e-6);
  font-size: var(--t-micro);
  color: var(--text-3);
  cursor: pointer;
  z-index: 5;
  transition: background var(--t-moyen), color var(--t-moyen), border-color var(--t-moyen);
  display: flex; align-items: center; gap: var(--e-2);
  line-height: var(--lh-un);
}
.lib-card-star-badge:hover { background: rgba(var(--th-panneau-rgb),0.85); color: var(--amber); border-color: rgba(251,191,36,0.4); }
.lib-card-star-badge.rated { color: var(--amber); border-color: rgba(251,191,36,0.3); background: rgba(var(--th-panneau-rgb),0.75); }

/* ── Bulle « Produit uniquement » sur la carte robe (coin bas-droite) ── */
.lib-card-product-badge {
  position: absolute;
  bottom: 7px; right: 7px;
  background: rgba(var(--th-panneau-rgb),0.65);
  backdrop-filter: blur(4px);
  border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-xl);
  padding: var(--e-4) var(--e-6);
  color: var(--text-3);
  cursor: pointer;
  z-index: 5;
  display: flex; align-items: center;
  line-height: var(--lh-un);
  transition: background var(--t-moyen), color var(--t-moyen), border-color var(--t-moyen);
}
.lib-card-product-badge:hover { background: rgba(var(--th-panneau-rgb),0.9); color: var(--text-2); border-color: rgba(167,139,250,0.5); }
.lib-card-product-badge.active { background: rgba(124,58,237,0.92); color: var(--text); border-color: var(--accent); }

/* ── Toggle filtre « Produit uniquement » dans le panneau Filtres ── */
.lib-productonly-filter-row { display: flex; margin-top: var(--e-8); }
.lib-productonly-toggle {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-12);
  border-radius: var(--r-xl);
  border: 1px solid rgba(var(--th-voile),0.14);
  background: rgba(var(--th-voile),0.04);
  color: var(--text-2);
  font-size: var(--t-meta); font-weight: var(--fw-fort);
  cursor: pointer;
  transition: background var(--t-moyen), color var(--t-moyen), border-color var(--t-moyen);
}
.lib-productonly-toggle:hover { color: var(--text-2); border-color: rgba(167,139,250,0.4); }
.lib-productonly-toggle.active { background: rgba(124,58,237,0.85); color: var(--text); border-color: var(--accent); }

/* ══════════════ Espace Comptes Vinted — hub d'accès (liste compacte) ══════════════ */
.comptes-toolbar { display: flex; align-items: center; gap: var(--e-12); margin-bottom: var(--e-14); }
.comptes-search {
  flex: 1; max-width: 360px; height: 38px; padding: 0 var(--e-14);
  background: var(--bg-hover); border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-md); color: var(--text); font-size: var(--t-small); outline: none;
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
.comptes-search::placeholder { color: var(--text-3); }
.comptes-search:focus { border-color: rgba(167,139,250,0.55); background: rgba(var(--th-voile),0.07); }
.comptes-summary { font-size: var(--t-base); color: var(--text-2); white-space: nowrap; }

.comptes-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--e-16); }
.compte-w {
  position: relative;
  background: linear-gradient(160deg, var(--bg-hover), var(--cok-bg-2));
  border: 1px solid rgba(var(--th-voile),0.09);
  border-radius: var(--r-xl);
  padding: var(--e-18);
  display: flex; flex-direction: column; gap: var(--e-14);
  transition: transform var(--t-moyen) var(--c-pose), border-color var(--t-moyen) var(--c-pose), box-shadow var(--t-moyen) var(--c-pose);
}
.compte-w:hover { transform: translateY(-2px); border-color: var(--survol-bord); box-shadow: 0 10px 30px -12px rgba(124,58,237,0.45); }
.compte-w--off { border-color: rgba(var(--th-danger-rgb),0.26); background: rgba(var(--th-voile),0.04); }

.compte-w-top { display: flex; align-items: center; gap: var(--e-12); }
.compte-w-num {
  flex: 0 0 auto; min-width: 30px; text-align: center; padding: var(--e-4) var(--e-8); border-radius: var(--r-sm);
  font-size: var(--t-base); font-weight: var(--fw-gras); font-variant-numeric: tabular-nums;
  background: rgba(var(--th-accent-rgb),0.14); color: var(--violet-soft); border: 1px solid rgba(var(--th-accent-rgb),0.3);
}
.compte-w-num.none { background: var(--surface-2); color: var(--text-3); border-color: var(--border); }
.compte-w-owner {
  flex: 0 0 auto; font-size: var(--t-mini); font-weight: var(--fw-fort); padding: var(--e-4) var(--e-6); border-radius: var(--r-sm);
  background: rgba(var(--th-accent-rgb),0.12); color: var(--violet-soft); border: 1px solid rgba(var(--th-accent-rgb),0.3);
  cursor: pointer; max-width: 86px; appearance: auto;
}
.compte-w-owner:hover { border-color: rgba(var(--th-accent-rgb),0.55); }
.compte-w-dot { flex: 0 0 auto; width: 10px; height: 10px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 4px rgba(74,222,128,0.16); }
.compte-w-dot.off { background: var(--amber); box-shadow: 0 0 0 4px rgba(251,146,60,0.16); }
@keyframes comptePulse { 0%,100% { box-shadow: 0 0 0 4px rgba(251,146,60,0.18); } 50% { box-shadow: 0 0 0 7px rgba(251,146,60,0.05); } }
/* Vignette « vue Face » de la modèle (liseré = état session) */
.compte-w-face { flex: 0 0 auto; width: 42px; height: 54px; border-radius: var(--r-md); object-fit: cover; object-position: top center; border: 2px solid var(--green); background: var(--bg-hover); }
.compte-w-face.off { border-color: var(--amber); }
.compte-w-id { flex: 1; min-width: 0; }
.compte-w-login { font-weight: var(--fw-gras); font-size: var(--t-body); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.compte-w-sub { font-size: var(--t-mini); color: var(--text-2); margin-top: var(--e-1); }
.compte-w-state {
  flex: 0 0 auto; font-size: var(--t-micro); font-weight: var(--fw-gras); padding: var(--e-4) var(--e-10); border-radius: var(--r-xl);
  text-transform: uppercase; letter-spacing: var(--ls-large); white-space: nowrap;
  background: rgba(34,197,94,0.15); color: var(--green);
}
.compte-w-state.off { background: var(--moy-bg); color: var(--moy-text); }

.compte-w-badges { display: flex; flex-wrap: wrap; gap: var(--e-8); }
.compte-w-badge { font-size: var(--t-micro); font-weight: var(--fw-fort); padding: var(--e-4) var(--e-10); border-radius: var(--r-sm); background: var(--bg-hover); border: 1px solid rgba(var(--th-voile),0.08); }
.compte-w-badge.ok   { color: var(--text-2); }
.compte-w-badge.warn { color: var(--amber); background: rgba(251,191,36,0.1); border-color: rgba(251,191,36,0.25); }

.compte-w-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-10); }
.compte-w-metric {
  background: var(--cok-bg); border: 1px solid var(--bg-elevated); border-radius: var(--r-lg);
  padding: var(--e-12) var(--e-8); display: flex; flex-direction: column; align-items: center; gap: var(--e-4); text-align: center;
}
.compte-w-metric-val { font-weight: 800; font-size: var(--t-lead); color: var(--text); line-height: var(--lh-un); }
.compte-w-metric-lbl { font-size: var(--t-micro); color: var(--text-2); text-transform: uppercase; letter-spacing: var(--ls-leger); }
.compte-w-metric.ship { background: var(--moy-bg); border-color: rgba(var(--th-danger-rgb),0.3); }
.compte-w-metric.ship .compte-w-metric-val { color: var(--amber); }
.compte-w-metric.pending { background: rgba(var(--th-accent-rgb),0.14); border-color: rgba(var(--th-accent-rgb),0.3); }
.compte-w-metric.pending .compte-w-metric-val { color: var(--violet-soft, var(--violet-soft)); }

.compte-w-actions { display: flex; gap: var(--e-8); margin-top: auto; }
.compte-w-btn {
  flex: 1; text-align: center; padding: var(--e-10) var(--e-10); border-radius: var(--r-md); font-size: var(--t-meta); font-weight: var(--fw-fort);
  cursor: pointer; border: 1px solid rgba(var(--th-voile),0.12); background: var(--bg-hover);
  color: var(--text-2); text-decoration: none; transition: background var(--t-moyen), border-color var(--t-moyen), transform var(--t-bref);
}
.compte-w-btn:hover { background: rgba(var(--th-voile),0.1); border-color: var(--survol-bord); }
.compte-w-btn:active { transform: scale(0.97); }
.compte-w-btn.primary { background: var(--aurora); color: var(--sur-plein); border-color: transparent; }
.compte-w-btn.primary:hover { filter: brightness(1.08); }

/* ══════════════ Espace Commandes — liste groupée par étape ══════════════ */
.cmd-toolbar { display: flex; align-items: center; gap: var(--e-12); margin-bottom: var(--e-16); }
.cmd-list { display: flex; flex-direction: column; gap: var(--e-18); }
.cmd-sec { display: flex; flex-direction: column; gap: var(--e-8); }
.cmd-h {
  display: flex; align-items: center; gap: var(--e-8);
  font-size: var(--t-meta); font-weight: var(--fw-gras); text-transform: uppercase; letter-spacing: var(--ls-large);
  padding-bottom: var(--e-6); border-bottom: 2px solid rgba(var(--th-voile),0.08); user-select: none;
}
.cmd-h-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; background: currentColor; }
.cmd-h--toggle { cursor: pointer; }
.cmd-h.cmd { color: var(--red); border-color: rgba(248,113,113,0.4); }
.cmd-h.ord { color: var(--amber); border-color: rgba(251,191,36,0.4); }
.cmd-h.snt { color: var(--cyan-light); border-color: rgba(96,165,250,0.4); }
.cmd-h.tr  { color: var(--text-2); }
/* ⭐ « Au point relais » a sa propre couleur : ni le gris de la livraison (rien à faire),
   ni le vert de la validation (c'est fini). Un turquoise, distinct du bleu de l'entrepôt
   (#60a5fa) et du vert de la fin (var(--green)) — l'étape où le colis attend qu'on aille le
   chercher. ⚠️ Une étape sans règle `.cmd-h.<cls>` sort SANS couleur : la classe se
   nomme dans app.js mais ne se style que si elle est écrite ici. */
.cmd-h.rel { color: var(--green); border-color: rgba(56,214,200,0.4); }
.cmd-h.lit { color: var(--red); border-color: rgba(var(--th-danger-rgb),0.45); }
.cmd-h.ok  { color: var(--green); border-color: rgba(74,222,128,0.35); }
.cmd-sec-body { display: flex; flex-direction: column; gap: var(--e-6); }

.cmd-row { display: flex; align-items: center; gap: var(--e-12); padding: var(--e-10) var(--e-12); border-radius: var(--r-md);
  background: var(--cok-bg); border: 1px solid var(--bg-elevated); transition: background var(--t-bref), border-color var(--t-bref); }
.cmd-row:hover { background: var(--bg-elevated); border-color: rgba(167,139,250,0.3); }
.cmd-th { flex: 0 0 auto; width: 40px; height: 50px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--bg-hover); display: flex; align-items: center; justify-content: center; color: var(--text-3); }
.cmd-th img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.cmd-th--zoom { cursor: zoom-in; transition: box-shadow var(--t-moyen), transform var(--t-moyen); }
.cmd-th--zoom:hover { box-shadow: 0 0 0 2px rgba(var(--th-accent-rgb),0.6); transform: scale(1.04); }
.cmd-main { flex: 1; min-width: 0; }
.cmd-t { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmd-m { font-size: var(--t-mini); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: var(--e-2); }
.cmd-acts { flex: 0 0 auto; display: flex; flex-direction: column; gap: var(--e-6); align-items: stretch; }
.cmd-top { display: flex; align-items: baseline; gap: var(--e-8); }
.cmd-top .cmd-t { flex: 1; min-width: 0; }
.cmd-price { flex: 0 0 auto; font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--text); }
.cmd-tags { display: flex; align-items: center; flex-wrap: wrap; gap: var(--e-6); margin-top: var(--e-6); }
.cmd-status { font-size: var(--t-micro); font-weight: var(--fw-fort); padding: var(--e-2) var(--e-8); border-radius: var(--r-sm); white-space: nowrap;
  background: rgba(var(--th-voile),0.07); color: var(--text-2); border: 1px solid rgba(var(--th-voile),0.12); }
.cmd-status.cmd { background: rgba(248,113,113,0.14); color: var(--red); border-color: rgba(248,113,113,0.3); }
.cmd-status.ord { background: rgba(251,191,36,0.14); color: var(--amber); border-color: rgba(251,191,36,0.3); }
.cmd-status.snt { background: rgba(96,165,250,0.14); color: var(--cyan-light); border-color: rgba(96,165,250,0.3); }
.cmd-status.tr  { background: rgba(var(--th-voile),0.07); color: var(--text-2); }
.cmd-status.rel { background: rgba(56,214,200,0.14); color: var(--green); border-color: rgba(56,214,200,0.3); }
.cmd-status.lit { background: rgba(var(--th-danger-rgb),0.16); color: var(--red); border-color: rgba(var(--th-danger-rgb),0.34); }
/* Le seul geste d'un litige : faire revenir la robe. Il porte la teinte d'alerte, sans
   être un bouton plein — on ne pousse pas au clic sur un écran de problème. */
/* ══ SANTÉ D'UN PRODUIT ════════════════════════════════════════════════════════
   Les cœurs se lisent, ils ne se cliquent pas — pas de `cursor: pointer`, pas d'effet
   de survol : c'est ce qui les distingue de l'étoile posée juste au-dessus.
   ⚠️ Position calquée sur `.lib-card-star-badge` (top 7px / right 7px, hauteur ≈ 17 px) :
   29 px la place juste dessous, sur le seul bord libre de la vignette. */
.lib-card-sante-badge {
  position: absolute; top: 29px; right: 7px; z-index: 5;
  display: flex; gap: var(--e-1); align-items: center;
  padding: var(--e-2) var(--e-6); border-radius: var(--r-xl, 999px);
  background: rgba(var(--th-panneau-rgb),0.65); backdrop-filter: blur(4px);
  border: 1px solid rgba(var(--th-voile),0.10);
  font-size: var(--t-micro); line-height: var(--lh-un); letter-spacing: -.5px;
  pointer-events: none;   /* elle ne prend jamais le clic destiné à la carte */
}
/* ⚠️ Même gabarit que l'étoile juste au-dessus : le chiffre, puis le symbole. La
   gouttière et le corps sont ceux de `.lib-card-star-badge` — on ne réinvente pas une
   pastille quand sa jumelle est à six pixels. */
.lib-card-sante-badge { gap: var(--e-4); font-size: var(--t-micro); letter-spacing: var(--ls-zero); }
.lib-card-sante-badge .n     { color: var(--text-2); font-weight: var(--fw-fort); }
.lib-card-sante-badge .plein { color: var(--red); }
.lib-card-sante-badge .vide  { color: var(--text-3); }
.lib-card-sante-badge.main .n { color: var(--red); }
.lib-card-sante-badge.simule .n { color: var(--amber); }
/* ⚠️ LA MARQUE DU SIMULÉ EST VISIBLE, ET ELLE DOIT LE RESTER. Un chiffre de
   démonstration qui ressemble à un vrai chiffre est exactement le défaut qu'on a passé
   la journée à réparer ailleurs. Trait pointillé + teinte ambre : on ne peut pas le
   confondre avec une mesure. */
.lib-card-sante-badge.simule { border-style: dashed; border-color: rgba(240,176,85,0.55); }
.lib-card-sante-badge.simule .plein { color: var(--amber); }
/* Posée à la main : le liseré prend la teinte des cœurs, comme l'étoile notée juste
   au-dessus prend l'ambre. Éteinte : elle s'efface sans disparaître — la place existe. */
.lib-card-sante-badge.main   { border-color: rgba(var(--th-danger-rgb),0.45); }
.lib-card-sante-badge.eteint { opacity: .55; }

/* ══════════════════════════════════════════════════════════════════════════════
   LES TUILES DE LA RÉSERVE — Robes / Visages / Comptes Google
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ ELLES N'AVAIENT AUCUN STYLE. Amadou (12/08) : « dans la partie réserve, les
   boutons ne sont qu'affichés ». Exact : `.src-stock` et `.src-stock-c` ne portaient
   ZÉRO règle. Le JavaScript nommait les classes, la feuille de style ne les
   connaissait pas — d'où « Robes409à traiter · 409 au total » d'un seul tenant.
   ⭐ TROISIÈME FOIS AUJOURD'HUI (après `.cmd-prix` et le panneau de détail des
   commandes) : une classe nommée n'est pas une classe stylée. Rien dans le code ne
   prévient, et le rendu ne plante pas — il s'affiche nu.
   ⭐ On n'invente rien : ces tuiles portent DÉJÀ `.l` et `.v`, les classes internes de
   `.cok-metric`, la métrique du Cockpit. Elles ont manifestement été écrites pour lui
   ressembler. On reprend son fond, sa bordure, son rayon, son flou — et on n'ajoute
   que ce qu'elle n'a pas : le sous-libellé `.s` et l'état choisi, puisque celles-ci
   sont des boutons qui sélectionnent un rayon. */
/* ⚠️ DEUX SOUS-BOUTONS, PLUS DEUX GROSSES CARTES (03/09). Amadou : « les boutons
   Produits et Visages doivent être des sous-boutons pour libérer de la place ». Ils
   prenaient deux cartes pleine largeur, avec un nombre en 24 px, juste au-dessus du
   contenu qu'on vient vraiment lire. Ils portent désormais `.an-so` — l'onglet du site,
   avec sa pastille de compteur. La forme existait, on ne s'en invente pas une. */
.src-stock { display: flex; gap: var(--e-8); flex-wrap: wrap; margin-bottom: var(--e-16); }

/* Le contenu des onglets Santé et Popularité de la fiche robe.
   ⚠️ En variante « panneau », il ne redessine NI cadre NI fond : `.dress-rpanel` est déjà
   une carte, deux liserés imbriqués se voient tout de suite. */
.robe-ps-corps { display: flex; flex-direction: column; gap: var(--e-6);
  border: 1px solid rgba(var(--th-voile),0.07); border-radius: var(--r-lg, 12px);
  background: var(--cok-bg-2); padding: var(--e-12) var(--e-14); }
.robe-ps-corps--panneau { border: 0; background: none; padding: 0; }
.robe-ps-coeurs { display: flex; align-items: center; gap: var(--e-4); font-size: var(--t-body); line-height: var(--lh-un); margin-bottom: var(--e-4); }
.robe-ps-coeurs .plein { color: var(--red); }
.robe-ps-coeurs .vide  { color: var(--text-3); }
.robe-ps-coeurs.simule .plein { color: var(--amber); }
/* Les cœurs de la FICHE se cliquent — ceux de la carte non. Même geste que les étoiles
   juste à côté : on survole, on voit ce qu'on va poser, on reclique pour effacer. */
.robe-ps-coeur { font: inherit; font-size: var(--t-body); line-height: var(--lh-un); background: none; border: 0;
  padding: 0 var(--e-1); cursor: pointer; transition: transform var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose); }
.robe-ps-coeur.plein { color: var(--red); }
.robe-ps-coeur.vide  { color: var(--text-3); }
.robe-ps-coeur:hover { transform: scale(1.18); color: var(--red); }
.robe-ps-coeurs.simule .robe-ps-coeur.plein { color: var(--amber); }
.robe-ps-coeurs-lbl { margin-left: var(--e-8); font-size: var(--t-meta); color: var(--text-2); letter-spacing: var(--ls-zero); }
.robe-ps-l { display: flex; align-items: baseline; justify-content: space-between; gap: var(--e-12);
  padding: var(--e-4) 0; border-bottom: 1px solid var(--bg-hover); }
.robe-ps-l:last-of-type { border-bottom: 0; }
.robe-ps-k { font-size: var(--t-meta); color: var(--text-2); }
.robe-ps-v { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); font-variant-numeric: tabular-nums; }
.robe-ps-v.bon    { color: var(--green); }
.robe-ps-v.moyen  { color: var(--amber); }
.robe-ps-v.mauvais{ color: var(--red); }
.robe-ps-manque { font-size: var(--t-meta); line-height: var(--lh-normal); color: var(--text-2);
  border-left: 2px solid rgba(var(--th-voile),0.12); padding-left: var(--e-10); margin-top: var(--e-6); }
.robe-ps-simu { font-size: var(--t-meta); line-height: var(--lh-normal); color: var(--amber);
  background: rgba(240,176,85,0.10); border: 1px dashed rgba(240,176,85,0.42);
  border-radius: var(--r-md); padding: var(--e-8) var(--e-10); margin-bottom: var(--e-6); }
.robe-ps-pied { margin-top: var(--e-8); }

/* ── PANNEAU SANTÉ — les trois parties respirent ─────────────────────────────
   Amadou (12/08) : « dans la partie santé espace les 3 parties c'est trop serré ».
   ⚠️ La cause : les TROIS blocs (la note en cœurs, les chiffres, la démonstration)
   étaient séparés par le `gap: 6px` du conteneur — c'est-à-dire par EXACTEMENT le
   même écart que deux lignes de chiffres entre elles. Rien ne disait donc où
   finissait un bloc et où commençait le suivant : l'œil lisait une seule colonne
   de huit éléments au lieu de trois parties. On ne corrige pas ça en agrandissant
   tous les écarts (ça éloigne aussi les lignes qui vont ensemble) : on creuse
   UNIQUEMENT les deux jointures, et un filet les nomme. */
.robe-ps-corps--panneau .robe-ps-coeurs {
  margin-bottom: 12px;
  padding-bottom: var(--e-12);
  border-bottom: 1px solid rgba(var(--th-voile),0.07);
}
.robe-ps-corps--panneau .robe-ps-pied {
  margin-top: var(--e-14);
  padding-top: var(--e-14);
  border-top: 1px solid rgba(var(--th-voile),0.07);
}
/* Et les lignes elles-mêmes gagnent deux pixels : à 4 px de padding, le libellé et
   le filet du dessous se touchaient presque. */
.robe-ps-corps--panneau .robe-ps-l { padding: var(--e-6) 0; }
.robe-ps-simu-btn { font: inherit; font-size: var(--t-meta); font-weight: var(--fw-moyen); cursor: pointer;
  color: var(--text-2); background: transparent; padding: var(--e-6) var(--e-12);
  border: 1px solid rgba(var(--th-voile),0.14); border-radius: var(--r-md); }
.robe-ps-simu-btn:hover { background: var(--survol-fond); color: var(--text); }
.robe-ps-simu-btn.on { color: var(--amber); border-color: rgba(240,176,85,0.45); }

.cmd-b--retour { border-color: rgba(var(--th-danger-rgb),0.42) !important; color: var(--red) !important; }
.cmd-b--retour:hover { background: rgba(var(--th-danger-rgb),0.14) !important; color: var(--text); }

/* ── LE CHAT DU LITIGE ────────────────────────────────────────────────────────
   Une troisième colonne dans le panneau de détail, et seulement sur un litige.
   ⚠️ Elle n'invente aucune couleur : mêmes bulles, mêmes tons que le chat de
   Messages. C'est le même objet vu en plus petit, il doit se reconnaître. */
/* ══════════════════════════════════════════════════════════════════════════════
   L'ESPACE LITIGE — TROIS COLONNES, celles de l'écran Messages.
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ DEUXIÈME VERSION. La première réutilisait la liste des commandes à gauche —
   des bandes de 110 px de haut — et posait le chat à droite. Amadou (12/08) : « c'est
   vraiment pas ce que je voulais, tu dois intégrer la partie message de l'onglet
   Messages, le chat que tu avais fait en widget ». Il avait raison, et il avait la
   maquette sous les yeux : liste compacte · fil · comparaison. On ne réinvente pas la
   forme d'un écran qui existe déjà et qu'il connaît par cœur. */
.lit-espace {
  display: grid;
  grid-template-columns: 230px minmax(0, 1fr) 260px;
  gap: var(--e-12);
  align-items: stretch;
  height: calc(100vh - 300px);
  min-height: 420px;
}
/* ⚠️⚠️ OPAQUES, PAS TRANSLUCIDES — 15/08. Amadou : « enlève le transparent du milieu
   de la partie Litiges ». Ces trois colonnes portaient `--cok-bg-2`, un voile à 5,5 %.
   Sur une page NUE ça passe ; sur une page qui porte un DÉCOR (les seize thèmes en ont
   un), le dessin traverse le panneau et le fait disparaître — d'où l'impression d'un
   trou au milieu de l'écran, surtout là où il y a peu de contenu.
   ⚠️ Et le filet à 7 % n'aidait pas : sur les thèmes clairs, où panneau et page ne
   diffèrent que de ×1,03, c'est le TRAIT qui dit « ceci est un panneau », pas le fond.
   Un fond opaque + un vrai filet règlent les deux d'un coup. */
.lit-liste, .lit-fil, .lit-cote {
  min-width: 0; min-height: 0;
  border: 1px solid var(--border); border-radius: var(--r-lg, 12px);
  background: var(--panneau-doux);
  display: flex; flex-direction: column;
}
/* ⚠️⚠️ LE FIL DU MILIEU N'A AUCUN FOND — Amadou (15/08) : « la partie du milieu où il
   y a le chat doit être comme dans la partie Messages, c'est-à-dire transparent ».
   Il a raison, et ce n'est pas un détail de goût : dans Messages, c'est le CONTRASTE
   entre un centre ouvert sur le décor et deux bords pleins qui fait ressortir les
   extrémités. Un centre à moitié voilé ne donne ni l'un ni l'autre — c'est ce qui
   avait l'air sale. Ouvert ou plein, jamais entre les deux. */
.lit-fil { background: transparent; }
.lit-liste { padding: var(--e-8); gap: var(--e-4); overflow-y: auto; }
/* ⚠️ AUCUN rembourrage ici : les trois étages viennent de Messages (`cok-msg-chead`,
   `cok-msg-thread`, `cok-msg-compose`) et portent chacun le leur. Un rembourrage de plus
   décollerait le filet de l'en-tête des bords — le défaut se voit tout de suite. */
.lit-fil   { padding: 0; gap: 0; }
.lit-cote  { padding: var(--e-12) var(--e-14); gap: var(--e-12); overflow-y: auto; }
.lit-vide { margin: auto; font-size: var(--t-base); color: var(--text-3); text-align: center; padding: 0 var(--e-10); }

/* Une ligne de la liste : deux lignes de texte, rien de plus. Le motif vient du
   statut Vinted mot pour mot — c'est lui qu'on citera à l'acheteuse. */
.lit-ligne { display: block; width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: transparent; border: 0; border-radius: var(--r-md); padding: var(--e-8) var(--e-10); }
.lit-ligne:hover { background: rgba(var(--th-accent-rgb),0.10); }
.lit-ligne.on { background: rgba(var(--th-danger-rgb),0.13); }
.lit-ligne-t { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lit-ligne-m { font-size: var(--t-mini); color: var(--text-2); margin-top: var(--e-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lit-ligne.on .lit-ligne-m { color: var(--red); }

/* ══ LE PANNEAU DE DROITE ════════════════════════════════════════════════════
   ⚠️⚠️ IL S'APPELAIT « COMPARER » ET NE POUVAIT PAS COMPARER. Deux rangées de trois
   cases : une seule remplie (la photo de l'annonce), les cinq autres marquées « à
   capturer » — et RIEN ne les capture. Amadou : « l'interface est mauvaise ». Elle
   l'était, mais pas par son dessin : un écran qui réserve de la place à une donnée que
   personne ne produit ne montre pas un manque, il montre une PROMESSE.
   Il dit maintenant ce qu'il a, et pourquoi le reste manque. */
.lit-cote-t { font-size: var(--t-micro); font-weight: var(--fw-fort); letter-spacing: var(--ls-ample);
  text-transform: uppercase; color: var(--text-3); }

.lit-robe { display: flex; gap: var(--e-12); align-items: flex-start; }
.lit-robe-ph { width: 74px; height: 96px; flex: 0 0 auto; border-radius: var(--r-md);
  overflow: hidden; background: var(--surface-3); cursor: zoom-in; }
.lit-robe-ph.vide { cursor: default; border: 1px dashed var(--cok-border-2); background: none; }
.lit-robe-ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lit-robe-inf { flex: 1 1 auto; min-width: 0; }
.lit-robe-t { font-size: var(--t-base); color: var(--text); line-height: var(--lh-serre); }
.lit-robe-m { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-4);
  line-height: var(--lh-normal); }

/* ⚠️ Le manque est ÉCRIT, pas dessiné en cases vides. Une case vide fait croire qu'on
   attend une photo ; une phrase dit qu'aucune ne viendra tant que l'extension ne lit pas
   les pièces jointes. La deuxième se répare, la première se contemple. */
.lit-abs { border: 1px dashed var(--cok-border-2); border-radius: var(--r-md);
  padding: var(--e-12); font-size: var(--t-mini); color: var(--text-3);
  line-height: var(--lh-normal); }

.lit-geste { font: inherit; font-size: var(--t-base); font-weight: var(--fw-moyen); cursor: pointer; width: 100%;
  color: var(--red); background: transparent; padding: var(--e-10) var(--e-10);
  border: 1px solid rgba(var(--th-danger-rgb),0.42); border-radius: var(--r-md); }
.lit-geste:hover { background: rgba(var(--th-danger-rgb),0.14); color: var(--text); }
.lit-geste.ok { color: var(--green); border-color: rgba(74,222,128,0.42); }
.lit-geste.ok:hover { background: rgba(74,222,128,0.14); }
.lit-cote-fiche { margin-top: auto; font: inherit; font-size: var(--t-meta); cursor: pointer; width: 100%;
  color: var(--text-2); background: transparent; padding: var(--e-8) var(--e-10);
  border: 1px solid rgba(var(--th-voile),0.12); border-radius: var(--r-md); }
.lit-cote-fiche:hover { background: rgba(var(--th-accent-rgb),0.14); color: var(--violet-light, #B9AEFF); }

/* ── « Retour demandé » et « Terminées » : deux tableaux, pas de chat ─────────── */
#lit-tableau { display: flex; flex-direction: column; gap: var(--e-8); }
.lit-tuiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--e-10); margin-bottom: var(--e-6); }
.lit-tuile { background: var(--surface); border: 1px solid var(--bg-elevated);
  border-radius: var(--r-lg, 12px); padding: var(--e-12) var(--e-14); }
.lit-tuile-l { font-size: var(--t-meta); color: var(--text-2); }
.lit-tuile-v { font-size: var(--t-title); font-weight: var(--fw-fort); color: var(--text); margin-top: var(--e-4);
  font-variant-numeric: tabular-nums; }
.lit-tuile.alerte { border-color: rgba(var(--th-danger-rgb),0.3); background: rgba(var(--th-danger-rgb),0.07); }
.lit-tuile.alerte .lit-tuile-l, .lit-tuile.alerte .lit-tuile-v { color: var(--red); }
.lit-tuile.bon .lit-tuile-v { color: var(--green); }

/* Une ligne de retour : vignette, article, délai, geste. Le délai est en gros — c'est
   la seule question de cet écran. */
.lit-r { display: grid; grid-template-columns: 40px minmax(0,1fr) 92px auto; gap: var(--e-12);
  align-items: center }
.lit-r.tard { border-color: rgba(240,176,85,0.32); }
.lit-r-vig { width: 40px; height: 50px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--bg-hover); }
.lit-r-vig img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.lit-r-t { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lit-r-m { font-size: var(--t-mini); color: var(--text-2); margin-top: var(--e-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lit-r-j { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-2);
  font-variant-numeric: tabular-nums; text-align: right; }
.lit-r-j.tard { color: var(--amber); }
.lit-r-act { display: flex; align-items: center; gap: var(--e-8); }
.lit-r-etat { font-size: var(--t-mini); padding: var(--e-4) var(--e-8); border-radius: var(--r-sm); white-space: nowrap; }
.lit-r-etat.ok { background: rgba(74,222,128,0.13); color: var(--green); }
.lit-r-b { font: inherit; font-size: var(--t-meta); font-weight: var(--fw-moyen); cursor: pointer; white-space: nowrap;
  color: var(--text-2); background: transparent; padding: var(--e-6) var(--e-12);
  border: 1px solid rgba(var(--th-voile),0.14); border-radius: var(--r-md); }
.lit-r-b:hover { background: var(--tier-premium-bg); color: var(--violet-light, #B9AEFF); }
.lit-r-b.pri { color: var(--cyan-light); border-color: rgba(var(--th-accent-rgb),0.42); }

.lit-sect { font-size: var(--t-mini); font-weight: var(--fw-fort); letter-spacing: var(--ls-large); text-transform: uppercase;
  color: var(--text-2); margin-top: var(--e-14); }
.lit-bar-l { display: grid; grid-template-columns: minmax(0,1fr) 42px; gap: var(--e-10); align-items: center; }
.lit-bar { position: relative; height: 28px; border-radius: var(--r-md); overflow: hidden;
  background: rgba(var(--th-voile),0.04); }
.lit-bar-f { position: absolute; inset: 0; width: 0; background: rgba(var(--th-danger-rgb),0.22); }
.lit-bar-t { position: relative; display: block; line-height: 28px; padding-left: var(--e-10);
  font-size: var(--t-meta); color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lit-bar-n { font-size: var(--t-base); font-weight: var(--fw-fort); text-align: right; color: var(--text-2);
  font-variant-numeric: tabular-nums; }
.lit-chips { display: flex; flex-wrap: wrap; gap: var(--e-6); }
.lit-chip { display: inline-flex; align-items: center; gap: var(--e-8); font-size: var(--t-meta);
  color: var(--text-2); background: rgba(var(--th-voile),0.04);
  border-radius: var(--r-md); padding: var(--e-6) var(--e-10); }
.lit-chip b { color: var(--amber); } .lit-chip b.mauvais { color: var(--red); }
/* ⚠️ La note dit ce que l'écran NE sait PAS. Un tableau qui se tait sur ses limites
   se lit comme une vérité complète. */
.lit-note { font-size: var(--t-mini); line-height: var(--lh-normal); color: var(--text-3);
  border-left: 2px solid rgba(var(--th-voile),0.12); padding-left: var(--e-10); margin-top: var(--e-14); }

/* L'état du renvoi automatique. Trois tons, trois vérités — et « rien reçu » n'est
   PAS peint en vert : c'est exactement l'erreur du bordereau qu'on a déjà payée. */
.lit-auto { flex: 0 0 auto; font-size: var(--t-meta); line-height: var(--lh-normal); padding: var(--e-8) var(--e-10);
  border-radius: var(--r-md); border: 1px solid transparent; }
.lit-auto.ok      { background: rgba(74,222,128,0.10); border-color: rgba(74,222,128,0.28); color: var(--green); }
.lit-auto.ko      { background: var(--danger-fond); border-color: rgba(var(--th-danger-rgb),0.34); color: var(--red); }
.lit-auto.attente { background: rgba(var(--th-voile),0.04); border-color: rgba(var(--th-voile),0.10); color: var(--text-2); }

/* ⚠️⚠️ LE FIL DE LITIGES EST CELUI DE MESSAGES — il porte `cok-msg-thread`. On ne
   redéfinit ici que sa hauteur dans une colonne à trois étages.
   ⚠️ SURTOUT PAS DE `gap` : l'espacement vient des marges de `.cok-mb-l` (2 px dans une
   salve, 12 px entre deux salves). Un `gap` par-dessus écraserait tout à la même
   distance — les bulles resteraient bonnes et le GROUPEMENT disparaîtrait, ce qui est
   exactement la différence qu'Amadou voyait sans pouvoir la nommer. */
.lit-chat-fil { flex: 1 1 auto; min-height: 140px; }
.lit-chat-vide { margin: auto; font-size: var(--t-meta); color: var(--text-3); text-align: center; }
/* Les trois points de lecture se posent au MILIEU du fil — à la place exacte que
   prendra le message qui les remplace. Sinon l'attente s'affiche en haut et le contenu
   arrive au centre : l'œil voit un saut là où il n'y a qu'une substitution. */
.lit-chat-fil > .velbo-charge { margin: auto; padding: 0; }

/* ── CE QUI RESTE PROPRE AU LITIGE ────────────────────────────────────────────
   Tout le reste du chat vient de Messages. Ces deux règles sont les seules
   « spécificités » en PLUS : le trait de la réclamation, et l'estompage de ce qui la
   précède. Rien ici ne redessine une bulle. */
/* Avant la réclamation : lisible — on ne cache rien — mais qui cesse de réclamer l'œil. */
.cok-mb-l.lit-avant .cok-mb-txt { opacity: .55; }
.cok-mb-l.lit-avant .cok-mb-h   { opacity: .35; }
.lit-sep { align-self: stretch; display: flex; align-items: center; gap: var(--e-10);
  margin: var(--e-14) 0 var(--e-6);
  font-size: var(--t-micro); font-weight: var(--fw-fort); letter-spacing: var(--ls-large); text-transform: uppercase;
  color: var(--red); white-space: nowrap; }
.lit-sep::before, .lit-sep::after { content: ''; flex: 1; height: 1px; background: rgba(var(--th-danger-rgb),0.28); }

/* Sous 1100 px, deux colonnes étouffent la liste : le volet passe dessous, pleine largeur. */
/* Sous 1200 px, trois colonnes étouffent le fil : la comparaison passe sous la liste. */
@media (max-width: 1200px) {
  .lit-espace { grid-template-columns: 210px minmax(0, 1fr); grid-template-rows: 1fr auto; }
  .lit-cote { grid-column: 1 / -1; }
}

.cmd-status.ok  { background: rgba(74,222,128,0.14); color: var(--green); border-color: rgba(74,222,128,0.3); }
.cmd-age { display: inline-flex; align-items: center; gap: var(--e-4); font-size: var(--t-micro); font-weight: var(--fw-fort);
  color: var(--text-2); white-space: nowrap; }
/* Une PASTILLE, plus un mot coloré : le fond porte le ton, le libellé reste lisible
   dans les seize thèmes. Même règle que les pastilles de conversation — écrire une
   couleur sur sa propre teinte plafonne vers 4 de contraste, quoi qu'on fasse. */
.cmd-age.u-green, .cmd-age.u-orange, .cmd-age.u-red {
  padding: var(--e-2) var(--e-8); border-radius: var(--r-pilule); line-height: var(--lh-un);
  color: var(--text);
}
.cmd-age.u-green  { background: var(--safe-bg); }
.cmd-age.u-orange { background: var(--moy-bg); }
.cmd-age.u-red    { background: var(--ose-bg); border: 1px solid rgba(var(--th-danger-rgb),0.34); }
.cmd-b--conv { display: inline-flex; align-items: center; justify-content: center; gap: var(--e-6); }
.cmd-b--nosku { opacity: 0.55; cursor: not-allowed; color: var(--text-2); }
.cmd-b--nosku:hover { background: var(--bg-hover); border-color: rgba(var(--th-voile),0.12); transform: none; }

/* Bandeau de compteurs par étape (cliquables = filtre) */
.cmd-counters { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: var(--e-10); margin-bottom: var(--e-20); }
.cmd-counter { padding: var(--e-10) var(--e-14); border-radius: var(--r-lg); cursor: pointer; border: 1px solid rgba(var(--th-voile),0.08);
  background: rgba(var(--th-voile),0.04); transition: background var(--t-bref), border-color var(--t-bref), transform var(--t-bref); }
.cmd-counter:active { transform: scale(0.98); }
.cmd-counter.active { border-color: rgba(167,139,250,0.55); background: rgba(167,139,250,0.12); }

/* « En retard » n'est pas une étape du parcours mais une alerte : il se détache du
   reste du bandeau, sinon il se lit comme un compteur parmi cinq. */
.cmd-counter--retard { border-color: rgba(var(--th-danger-rgb),0.45); background: rgba(var(--th-danger-rgb),0.10); }
.cmd-counter--retard:hover { background: rgba(var(--th-danger-rgb),0.16); }
.cmd-counter--retard .cmd-counter-n { color: var(--red); }
.cmd-counter--retard.active { border-color: var(--red); background: rgba(var(--th-danger-rgb),0.20); }
.cmd-counter-n { font-size: var(--t-title); font-weight: 800; line-height: var(--lh-un); color: var(--text); }
.cmd-counter-l { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-leger); margin-top: var(--e-6); color: var(--text-2); }
.cmd-counter.cmd .cmd-counter-n { color: var(--red); }
.cmd-counter.ord .cmd-counter-n { color: var(--amber); }
.cmd-counter.snt .cmd-counter-n { color: var(--cyan-light); }
.cmd-counter.ok  .cmd-counter-n { color: var(--green); }

/* Grille de cartes (exploite la largeur) */
.cmd-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--e-12); }
.cmd-card { display: flex; flex-direction: column; gap: var(--e-10); padding: var(--e-12); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid rgba(var(--th-voile),0.08);
  transition: border-color var(--t-bref), background var(--t-bref); }
.cmd-card:hover { border-color: rgba(167,139,250,0.35); background: var(--bg-hover); }
.cmd-card-top { display: flex; gap: var(--e-10); }
.cmd-card-info { flex: 1; min-width: 0; }
.cmd-card .cmd-acts { flex-direction: row; flex-wrap: wrap; }
.cmd-card .cmd-acts .cmd-b { flex: 1 1 30%; justify-content: center; min-width: 92px; }
.cmd-b--label { display: inline-flex; align-items: center; justify-content: center; gap: var(--e-6);
  background: rgba(var(--th-accent-rgb),0.14); border-color: rgba(var(--th-accent-rgb),0.35); color: var(--violet-soft); }
.cmd-b--label:hover { background: rgba(var(--th-accent-rgb),0.24); border-color: rgba(var(--th-accent-rgb),0.55); }
.cmd-b--warehouse { display: inline-flex; align-items: center; justify-content: center; gap: var(--e-6);
  background: var(--rp-blue-tint); border-color: var(--cyan-glow); color: var(--cyan-light); }
.cmd-b--warehouse:hover { background: rgba(var(--th-second-rgb),0.24); border-color: rgba(var(--th-second-rgb),0.6); }
.cmd-b--warehouse.done { background: rgba(var(--th-second-rgb),0.10); border-color: rgba(var(--th-second-rgb),0.25); color: var(--text-2); cursor: default; }
.cmd-b--warehouse.done:hover { background: rgba(var(--th-second-rgb),0.10); border-color: rgba(var(--th-second-rgb),0.25); transform: none; }
/* Colis déclaré SANS bordereau : l'entrepôt ne peut pas l'expédier. Ça ne doit pas se
   confondre avec le bleu éteint de « c'est fait ». */
.cmd-b--warehouse.manque, .cmd-b--warehouse.manque:hover {
  background: rgba(240,176,85,0.12); color: var(--amber, var(--amber));
  border-color: rgba(240,176,85,0.42); cursor: default; transform: none;
}
.cmd-b { padding: var(--e-6) var(--e-12); border-radius: var(--r-sm); font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer; white-space: nowrap;
  border: 1px solid rgba(var(--th-voile),0.12); background: var(--bg-hover); color: var(--text-2);
  transition: background var(--t-bref), border-color var(--t-bref), transform var(--t-bref); }
.cmd-b:hover { background: rgba(var(--th-voile),0.1); border-color: var(--survol-bord); }
.cmd-b:active { transform: scale(0.96); }
.cmd-b.go { background: var(--aurora); color: var(--sur-plein); border-color: transparent; }
.cmd-b.go:hover { background: var(--aurora); filter: brightness(1.08); }
.cmd-b--undo { padding: var(--e-6) var(--e-10); color: var(--text-2); }

/* ── Refonte dense : filtre comptes · barre lot · lignes ── */
.cmd-acct { display: inline-flex; align-items: center; gap: var(--e-6); font-size: var(--t-base); padding: var(--e-6) var(--e-12);
  border-radius: var(--r-md); border: 1px solid rgba(var(--th-voile),0.1); background: transparent; color: var(--text-2);
  cursor: pointer; transition: background var(--t-bref), border-color var(--t-bref), color var(--t-bref); }
.cmd-acct:hover { background: var(--bg-hover); color: var(--text-2); }
.cmd-acct.on { border-color: rgba(167,139,250,0.55); background: rgba(167,139,250,0.12); color: var(--text); }
.cmd-acct-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; }
.cmd-acct-dot.ok { background: var(--green); }
.cmd-acct-dot.off { background: var(--red); }
/* Le compte qui a du travail se distingue de celui qu'on ne consulte que par curiosité :
   le compteur porte la différence, pas une couleur de plus. */
.cmd-acct-n { display: inline-flex; align-items: center; justify-content: center; min-width: 17px;
  height: 17px; padding: 0 var(--e-4); border-radius: var(--r-md); font-size: var(--t-micro); font-weight: var(--fw-gras);
  background: rgba(var(--th-voile),0.10); color: var(--text-2); }
.cmd-acct.on .cmd-acct-n { background: rgba(var(--th-voile),0.18); color: var(--text); }

/* Le filtre par compte, dans la barre d'outils : une ligne, que la flotte compte
   trois comptes ou cent. Il emprunte le sélecteur d'identité de la barre latérale.
   ⚠️ QUALIFIÉ PAR LES DEUX CLASSES, ET CE N'EST PAS DU ZÈLE : `.identite-menu` est
   déclaré ~15 000 lignes plus bas. À poids égal, c'est le dernier qui gagne — son
   `bottom: calc(100% + 6px)` survivait donc à mon `top`, les deux s'appliquaient
   ensemble et la hauteur du menu s'écrasait à 12 px (mesuré : scrollHeight 283,
   clientHeight 10). Le menu de la barre latérale s'ouvre vers le HAUT, celui-ci vers
   le BAS : il faut vraiment gagner. */
.cmd-cptbox { flex: 0 0 auto; }
.identite-btn.cmd-cptbtn { min-width: 190px; padding: var(--e-8) var(--e-12); }
.identite-menu.cmd-cptmenu { left: auto; right: 0; top: calc(100% + 6px); bottom: auto;
  min-width: 240px; max-height: 340px; overflow-y: auto; }
.cmd-cptmenu .identite-opt { gap: var(--e-8); }

/* ══ VENDEUSES : l'état, en UN bouton qui se déroule ═════════════════════════
   ⚠️⚠️ Amadou (15/08) : « la barre en haut dépasse s'il y a trop d'éléments ». Une
   rangée de boutons grandit avec le NOMBRE d'états et avec le CRAN d'apparence : elle
   ne peut que déborder un jour. Un bouton qui se déroule a une largeur bornée.
   Le composant est celui du choix des comptes — rien de neuf n'est dessiné.
   ⚠️ Menu qualifié par LES DEUX classes : `.identite-menu` est déclaré plus bas dans
   la feuille et son `bottom` survivrait à un `top` seul (piège déjà documenté). */
.lib-vend-etatbox { display: inline-block; min-width: 210px; }
.identite-menu.lib-vend-etatmenu { left: 0; right: auto; top: calc(100% + 6px); bottom: auto;
  min-width: 240px; max-height: 340px; overflow-y: auto; }
/* La pastille de couleur : elle DIT l'état, elle ne le décore pas. Sur « Toutes »
   elle devient un anneau creux — un tout n'a pas de couleur propre. */
.lib-vend-pt { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.lib-vend-pt.creux { background: transparent; box-shadow: inset 0 0 0 1.5px var(--text-3); }
.lib-vend-n { flex: 0 0 auto; font-size: var(--t-mini); color: var(--text-3);
  font-variant-numeric: tabular-nums; }
.lib-vend-sep { height: 1px; background: var(--border); margin: var(--e-4) var(--e-8); }

/* ── La carte d'une vendeuse ────────────────────────────────────────────────
   L'état monte SUR la photo : on le lit d'un coup d'œil en balayant la grille, et il
   libère une ligne dans le corps de la carte. */
/* ⚠️⚠️ LE COIN HAUT-GAUCHE EST UNE COLONNE — 15/08. Amadou, après avoir comparé les
   trois dispositions : « les pastilles en haut sont la meilleure solution, c'est sobre,
   ça passe tranquille », puis « mets le rond en dessous de la taille de la modèle ».
   La taille et l'état sont deux repères du même ordre : ils s'empilent au même coin.
   ⚠️ Une COLONNE, pas un décalage en pixels. Poser le point à « 31 px du haut »
   marcherait au cran normal et casserait au cran confortable, où le badge grandit avec
   le texte. Deux enfants d'un flex vertical restent collés quelle que soit la police.
   ⚠️ Et l'état n'est plus ÉCRIT sur la photo : le bandeau fondu, comme l'étiquette
   avant lui, posait un voile sur l'image — « vraiment moche », dit deux fois. Le mot
   reste au survol, et la liste du haut le nomme quand on filtre. */
.lib-card-coin {
  position: absolute; top: 7px; left: 7px; z-index: 2;
  display: flex; flex-direction: column; gap: var(--e-6);
  /* ⚠️ `center`, pas `flex-start` — Amadou (15/08) : « aligne à l'étiquette taille ».
     Collé au bord gauche, le point de 10 px pendait sous un badge deux fois plus large :
     la colonne partait de travers. Centré, il se cale sur l'axe du badge.
     ⭐ Et quand il n'y a PAS de taille, la colonne n'a plus qu'un enfant : sa largeur
     devient celle du point, qui reste donc au bord gauche. Aucun cas particulier à
     écrire — c'est le flex qui s'en occupe. */
  align-items: center;
  pointer-events: none;
}
/* Le badge de taille perd son positionnement propre : il est devenu l'enfant d'une
   colonne. Lui laisser `position: absolute` l'aurait sorti du flux et remis en haut. */
.lib-card-coin .lib-vend-gab { position: static; top: auto; left: auto; }
/* ⚠️ Le point porte un liseré sombre : sur une photo claire, un point vert clair
   disparaîtrait. Fixe et non thémé — on est sur une PHOTO, pas sur un panneau. */
.lib-card-etat-pt {
  width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
  box-shadow: 0 0 0 2.5px rgba(6,8,12,0.45), 0 1px 3px rgba(0,0,0,0.35);
  pointer-events: auto;
}

/* ⚠️⚠️ PAS DE VISAGE = ANOMALIE, et l'écran le DIT. Amadou (15/08) : « s'il n'y a pas
   de photo, c'est qu'il y a une anomalie quelque part ». L'icône neutre des robes
   laisserait croire à un chargement en cours ; le ton d'alerte, non. */
.lib-card-cover--anomalie {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-6); color: var(--ose-text); background: var(--ose-bg);
}
.lib-card-cover-anomalie-t {
  font-size: var(--t-micro); font-weight: var(--fw-fort); letter-spacing: var(--ls-leger);
}

/* Le numéro de profil, descendu du nom vers la bande du compte : il est enfin à côté
   de ce qu'il désigne, au lieu de disputer sa ligne au nom de la vendeuse. */
.lib-cpt-code {
  flex: 0 0 auto; font-size: var(--t-micro); font-weight: var(--fw-fort);
  letter-spacing: var(--ls-large); line-height: var(--lh-un);
  padding: var(--e-2) var(--e-6); border-radius: var(--r-micro);
  background: var(--surface-2); color: var(--text-2);
}

/* Le sélecteur d'espace, dans Paramètres › Sécurité. Il s'ouvre vers le BAS.
   ⚠️ QUALIFIÉ PAR LES DEUX CLASSES, pour la raison écrite plus haut : `.identite-menu`
   est déclaré ~15 000 lignes plus bas et son `bottom` survivrait à un `top` seul —
   les deux s'appliqueraient ensemble et le menu s'écraserait à douze pixels. */
.identite-menu.pa-espace-menu { left: 0; right: 0; top: calc(100% + 6px); bottom: auto;
  max-height: 300px; overflow-y: auto; }
.cmd-cptmenu .cmd-acct-dot { margin-left: var(--e-2); }

.cmd-bulkbar { display: flex; align-items: center; gap: var(--e-10); padding: var(--e-8) var(--e-12); margin: var(--e-4) 0 var(--e-10);
  border-radius: var(--r-md); background: var(--surface); border: 1px solid rgba(var(--th-voile),0.07); }
.cmd-ord-chk, .cmd-bulk-all {
  appearance: none; -webkit-appearance: none; margin: 0;
  width: 18px; height: 18px; flex: 0 0 auto; cursor: pointer;
  border-radius: var(--r-micro); border: 2px solid var(--border-strong); background: transparent;
  position: relative; transition: background var(--t-moyen), border-color var(--t-moyen); }
.cmd-ord-chk:hover, .cmd-bulk-all:hover { border-color: var(--violet); }
.cmd-ord-chk:checked, .cmd-bulk-all:checked { background: var(--violet); border-color: var(--violet); }
.cmd-ord-chk:checked::after, .cmd-bulk-all:checked::after {
  content: ''; position: absolute; left: 5px; top: 1px; width: 5px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.cmd-bulk-count { font-size: var(--t-meta); color: var(--text-2); }
.cmd-bulk-count.on { color: var(--text); font-weight: var(--fw-fort); }
.cmd-bulk-btns { display: flex; gap: var(--e-6); margin-left: auto; }
.cmd-bulk-btns .cmd-b:disabled { opacity: 0.4; cursor: default; }
.cmd-bulk-btns .cmd-b:disabled:hover { transform: none; }

.cmd-sec-body { gap: var(--e-2); }
/* ⚠️ `flex-start` et non `center` : la photo fait maintenant la hauteur de la bande, et
   centrée elle laissait la pastille et la case à cocher flotter à mi-photo, loin du
   titre auquel elles se rapportent. */
.cmd-ord { display: flex; align-items: flex-start; gap: var(--e-12); padding: var(--e-12) var(--e-10); border-radius: var(--r-md);
  border-bottom: 1px solid var(--bg-hover); transition: background var(--t-bref); }
.cmd-ord > .cmd-ord-dot, .cmd-ord > .cmd-ord-chk { margin-top: var(--e-6); }
.cmd-ord-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; background: rgba(var(--th-voile),0.18); }
.cmd-ord-dot.u-green { background: var(--green); }
.cmd-ord-dot.u-orange { background: var(--amber); }
.cmd-ord-dot.u-red { background: var(--red); }

/* Liseré d'urgence : le bord porte l'état, la pastille le confirme. Sur une liste
   longue, on lit le retard de vingt lignes sans en fixer aucune. */
.cmd-ord { border-left: 3px solid transparent; padding-left: var(--e-8); }
/* ⚠️⚠️ PLUS DE BANDE COLORÉE SUR LE FLANC — 15/08. Amadou : « la bande rouge comme ça
   vive, je ne trouve pas ça très beau ». Il a raison, et il y avait pire que le goût :
   l'information était DÉJÀ portée par la pastille d'âge juste à côté. La bande ne
   faisait que la répéter en criant — avec, en prime, deux couleurs écrites en dur
   (rgba(74,222,128) et rgba(240,176,85)) qui ne suivaient aucun thème.
   Le flanc reste neutre ; c'est la pastille qui parle, et elle le DIT en toutes
   lettres passé 48 h. */
.cmd-ord--u-green, .cmd-ord--u-orange, .cmd-ord--u-red { border-left-color: transparent; }

/* Coloris · taille · SKU. Ces trois-là ne sont PAS de la décoration : le titre Vinted
   ne les dit pas, et deux commandes du même modèle sont sinon indiscernables. */
.cmd-tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-6); margin-top: var(--e-4); }
.cmd-tag { display: inline-flex; align-items: center; gap: var(--e-6); padding: var(--e-2) var(--e-8); border-radius: var(--r-sm);
  font-size: var(--t-mini); font-weight: var(--fw-fort); line-height: var(--lh-normal); white-space: nowrap;
  border: 1px solid rgba(var(--th-voile),0.10); background: var(--bg-hover); color: var(--text-2); }
.cmd-tag--col { color: var(--text); }
.cmd-tag--col .coloris-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
  box-shadow: 0 0 0 1px rgba(var(--th-ombre),0.35); }
/* ⚠️ LA TAILLE N'EST PAS UNE ALERTE. Amadou (27/08) : « le bouton L est violet, il
   doit être gris tout comme le bouton Modifier à droite ». Elle était peinte en
   violet fixe — hors thème sur les dix-sept thèmes, et surtout elle criait plus fort
   que l'action posée juste à côté. Une étiquette qui dit un fait se lit ; elle
   n'appelle pas. Elle reprend donc le gris de `.cmd-tag`, comme ses voisines. */
.cmd-tag--size { letter-spacing: var(--ls-leger); }
/* La robe reliée : du texte lisible, plus une référence en monospace. C'est un nom
   qu'on vérifie d'un regard, pas un code qu'on déchiffre. */
.cmd-tag--sku { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: pointer; }
.cmd-tag--warn { cursor: default; }
/* Un bouton doit ressembler à un bouton : « Modifier » était une étiquette parmi les
   autres, donc invisible en tant qu'action. */
.cmd-tag--mod { cursor: pointer; color: var(--text-2); border-style: dashed;
  border-color: rgba(var(--th-voile),0.22); font-family: inherit; }
.cmd-tag--mod:hover { color: var(--text); border-color: var(--accent);
  background: var(--survol-fond); border-style: solid; }

/* Panneau « Modifier » : la robe, puis les tailles à choisir. */
/* ⚠️ QUALIFIÉ SUR LES DEUX CLASSES. `.velbo-modal { width: 380px }` est déclaré plus
   haut dans le fichier : à poids égal c'est le dernier qui gagne, et une règle
   `.velbo-modal--large` seule perdrait sans qu'on comprenne pourquoi. Même piège que
   `.identite-menu` ce matin. */
.velbo-modal.velbo-modal--large { width: 580px; max-width: 92vw; }

.mod-lab { font-size: var(--t-meta); text-transform: uppercase; letter-spacing: var(--ls-ample);
  color: var(--text-2); margin: var(--e-4) 0 var(--e-8); }
/* La robe se VOIT. Deux robes de sa bibliothèque portent des noms quasi identiques :
   seule la photo permet de vérifier qu'on tient la bonne — et la bonne COULEUR. */
.mod-carte { display: flex; align-items: center; gap: var(--e-16); padding: var(--e-14); margin-bottom: var(--e-22);
  border-radius: var(--r-lg); background: rgba(var(--th-voile),0.04); border: 1px solid rgba(var(--th-voile),0.11); }
.mod-carte.vide { cursor: pointer; border-style: dashed; border-color: rgba(240,176,85,0.45);
  background: rgba(240,176,85,0.07); }
.mod-carte.vide:hover { background: rgba(240,176,85,0.12); }
.mod-vign { flex: 0 0 auto; width: 74px; height: 100px; border-radius: var(--r-sm); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-hover); color: var(--text-3); }
.mod-vign img { width: 100%; height: 100%; object-fit: cover; }
.mod-infos { flex: 1; min-width: 0; }
.mod-nom { font-size: var(--t-body); font-weight: var(--fw-fort); line-height: var(--lh-serre); }
.mod-col { font-size: var(--t-base); color: var(--text-2); margin-top: var(--e-4); }
.mod-col:empty { display: none; }
.mod-ref { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-4);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.mod-chg { flex: 0 0 auto; padding: var(--e-8) var(--e-14); border-radius: var(--r-md); cursor: pointer;
  font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-2);
  background: var(--bg-elevated); border: 1px solid rgba(var(--th-voile),0.16); }
.mod-chg:hover { color: var(--text); border-color: var(--accent); background: rgba(167,139,250,0.14); }
.mod-carte.vide .mod-chg { display: none; }
.mod-tailles { display: flex; flex-wrap: wrap; gap: var(--e-10); }
.mod-taille { min-width: 66px; padding: var(--e-12) var(--e-16); border-radius: var(--r-md); cursor: pointer;
  font-family: inherit; font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text-2);
  background: var(--bg-hover); border: 1px solid rgba(var(--th-voile),0.13); }
.mod-taille:hover { border-color: rgba(167,139,250,0.5); color: var(--text); }
.mod-taille.on { background: var(--violet, var(--violet-soft)); border-color: var(--violet, var(--violet-soft)); color: var(--sur-plein); }
/* En rupture : visible mais barrée. La masquer laisserait croire qu'elle n'existe pas —
   ce n'est pas la même décision qu'« épuisée ». */
.mod-taille.rupture { opacity: 0.45; text-decoration: line-through; }
.mod-taille.rupture.on { background: rgba(var(--th-danger-rgb),0.3); border-color: var(--red); color: var(--text); }
.cmd-tag--sku:hover { border-color: var(--survol-bord); color: var(--text); }
/* Ce qui manque se voit autant que ce qui est là — sinon on commande à l'aveugle. */
.cmd-tag--warn { color: var(--amber); background: rgba(240,176,85,0.12); border-color: rgba(240,176,85,0.38); }
/* Un panier refusé est plus grave qu'une donnée manquante : la robe a l'air traitée
   et ne l'est pas. Elle se signale donc en rouge, pas en orange. */
.cmd-tag--echec { color: var(--red); background: rgba(var(--th-danger-rgb),0.14); border-color: rgba(var(--th-danger-rgb),0.45); }

/* ── Le panier groupé ──────────────────────────────────────────────────────
   Le montant d'abord, puis ce qu'il faut en faire. L'état colore le cadre, pas
   le texte : à distance on voit si le panier est prêt sans rien lire. */
.pan-tete { display: flex; align-items: center; gap: var(--e-20); flex-wrap: wrap;
  padding: var(--e-16) var(--e-18); border-radius: var(--r-lg); margin-bottom: var(--e-10);
  border: 1px solid rgba(var(--th-voile),0.10); background: var(--surface); }
.pan-tete--prete  { border-color: rgba(74,222,128,0.45); background: rgba(74,222,128,0.07); }
.pan-tete--urgent { border-color: rgba(var(--th-danger-rgb),0.50); background: rgba(var(--th-danger-rgb),0.07); }
.pan-chiffre { flex: 0 0 auto; }
.pan-montant { font-size: var(--t-2xl); font-weight: var(--fw-gras); line-height: var(--lh-titre); font-variant-numeric: tabular-nums; }
.pan-sur { font-size: var(--t-meta); color: var(--text-2); margin-top: var(--e-4); }
.pan-etat { flex: 1 1 260px; min-width: 0; }
.pan-etat-t { font-size: var(--t-small); font-weight: var(--fw-fort); }
.pan-etat-d { font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal); margin-top: var(--e-4); }
.pan-acts { flex: 0 0 auto; }
.pan-go { min-width: 160px; }
.pan-jauge { height: 6px; border-radius: var(--r-micro); overflow: hidden; background: rgba(var(--th-voile),0.07);
  margin-bottom: var(--e-14); }
.pan-jauge-in { height: 100%; border-radius: var(--r-micro); background: var(--violet, var(--violet-soft));
  transition: width var(--t-long) var(--c-pose); }
.pan-jauge-in.plein { background: var(--green); }
.pan-avert { padding: var(--e-10) var(--e-12); border-radius: var(--r-md); font-size: var(--t-base); line-height: var(--lh-normal);
  color: var(--amber); background: rgba(240,176,85,0.10); border: 1px solid rgba(240,176,85,0.32);
  margin-bottom: var(--e-14); }
/* ⚠️ TROIS BLOCS, PAS UNE LIGNE QUI SE REPLIE. Le libellé, le champ, l'unité et la
   règle de départ étaient sur une seule ligne en `flex-wrap` : selon la largeur,
   « € d'achat » se retrouvait seul sous un champ pleine largeur, rattaché à rien.
   Une grille verticale ne peut pas produire ça. */
.pan-reglage { display: grid; gap: var(--e-6); margin-bottom: var(--e-16);
  font-size: var(--t-base); color: var(--text-2); justify-items: start; }
.pan-reglage-lab { color: var(--text); font-weight: var(--fw-moyen); }
/* L'unité est COLLÉE au champ, dans le même cadre : « 500 € » se lit d'un bloc. */
.pan-reglage-champ { display: inline-flex; align-items: center; gap: var(--e-6);
  padding: 0 var(--e-10) 0 0; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: rgba(var(--th-voile),0.04); }
.pan-reglage-champ:focus-within { border-color: var(--accent); }
.pan-reglage-unite { color: var(--text-3); font-size: var(--t-base); }
.pan-seuil { width: 86px; padding: var(--e-6) 0 var(--e-6) var(--e-10);
  border: 0; background: transparent; font-family: inherit; font-size: var(--t-base);
  color: var(--text); }
.pan-seuil:focus { outline: none; }
.pan-reglage-note { color: var(--text-3); }
/* Une file suspendue n'est pas un avertissement de plus : c'est un geste attendu. */
.pan-avert--stop { color: var(--red); background: rgba(var(--th-danger-rgb),0.10); border-color: rgba(var(--th-danger-rgb),0.38); }

/* Bilan d'un envoi au panier : le motif compte autant que le titre de la robe, donc il
   se lit sans être cherché. */
.cmd-bilan-row { flex-direction: column; align-items: flex-start; gap: var(--e-4); }
.cmd-bilan-motif { font-size: var(--t-base); line-height: var(--lh-normal); color: var(--amber); }
/* Le détail technique est replié : il ne doit pas parler plus fort que la phrase. */
.cmd-bilan-det { margin-top: var(--e-14); font-size: var(--t-base); color: var(--text-2); }
.cmd-bilan-det summary { cursor: pointer; padding: var(--e-6) 0; }
.cmd-bilan-det pre { margin: var(--e-6) 0 0; padding: var(--e-10) var(--e-12); border-radius: var(--r-sm); overflow-x: auto;
  background: rgba(var(--th-ombre),0.28); font-size: var(--t-meta); line-height: var(--lh-aere);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--text-2); }

/* ── Entrepôt ──────────────────────────────────────────────────────────────
   Les métriques portent un sous-titre : « 184 » ne veut rien dire sans
   « 42 références », et « 3 492 € » sans « au prix d'achat ». */
.wh-metric { cursor: default; }
.wh-metric:hover { background: rgba(var(--th-voile),0.04); }
.wh-metric.bon .cmd-counter-n { color: var(--green); }
.wh-metric-sous { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-4); }
.wh-liste { display: flex; flex-direction: column; gap: var(--e-2); }
.wh-row { display: flex; align-items: center; gap: var(--e-12); padding: var(--e-10) var(--e-8); border-radius: var(--r-md);
  border-bottom: 1px solid var(--bg-hover); border-left: 3px solid transparent;
  transition: background var(--t-bref); }
.wh-row .cmd-th { width: 34px; height: 46px; }
/* Des ventes attendent une référence qui n'est pas en stock : le seul cas où il faut
   agir tout de suite. */
.wh-row--manque { border-left-color: var(--amber); background: rgba(240,176,85,0.05); }
.wh-manque { color: var(--amber); }
.wh-qte { flex: 0 0 auto; width: 46px; text-align: right; font-size: var(--t-small); font-weight: var(--fw-gras);
  font-variant-numeric: tabular-nums; }
.wh-qte.zero { color: var(--text-3); font-weight: var(--fw-moyen); }

/* État de l'extension, dans la barre d'outils. Discret quand tout va bien — c'est une
   information de fond, pas une alerte — et net quand il faut agir. */
.cmd-ext-etat { flex: 0 0 auto; font-size: var(--t-meta); padding: var(--e-4) var(--e-10); border-radius: var(--r-sm);
  white-space: nowrap; border: 1px solid transparent; }
.cmd-ext-etat:empty { display: none; }
.cmd-ext-etat.bon { color: var(--text-3); }
.cmd-ext-etat.mauvais { color: var(--amber); background: rgba(240,176,85,0.10);
  border-color: rgba(240,176,85,0.35); font-weight: var(--fw-fort); cursor: help; }

/* Retirer une ligne : le bouton reste gris jusqu'au survol. Il est à côté de
   « Commander » — il ne doit pas attirer l'œil ni la main. */
.cmd-iconb--rm { color: var(--text-3); }
.cmd-iconb--rm:hover { color: var(--red); border-color: rgba(var(--th-danger-rgb),0.5); background: rgba(var(--th-danger-rgb),0.10); }
/* L'avertissement montre la commande : on retire ce qu'on voit, pas un identifiant. */
.cmd-rm-carte { display: flex; align-items: center; gap: var(--e-12); padding: var(--e-12); border-radius: var(--r-md);
  border: 1px solid rgba(var(--th-voile),0.09); background: var(--surface); margin-bottom: var(--e-14); }
.cmd-rm-carte .cmd-th { width: 46px; height: 62px; flex: 0 0 auto; }
.cmd-rm-info { min-width: 0; }
.cmd-rm-alerte { margin-top: var(--e-12); padding: var(--e-10) var(--e-12); border-radius: var(--r-md); font-size: var(--t-base);
  line-height: var(--lh-normal); color: var(--amber); background: rgba(240,176,85,0.10);
  border: 1px solid rgba(240,176,85,0.35); }

/* La pastille disparaît là où le liseré parle déjà : l'œil ne doit pas lire deux fois
   la même information. Elle reste sur les étapes passives, qui n'ont pas de liseré. */
.cmd-ord--u-green .cmd-ord-dot, .cmd-ord--u-orange .cmd-ord-dot, .cmd-ord--u-red .cmd-ord-dot { display: none; }
.cmd-ord .cmd-age { flex: 0 0 auto; }
.cmd-ord .cmd-ord-acts { min-width: 0; }
/* ⚠️⚠️ C'EST CETTE RÈGLE QUI COMMANDE, pas `.cmd-th` : deux classes contre une, elle
   gagne toujours. Agrandir la règle de base n'avait donc aucun effet — le genre de
   correction qu'on croit faite en relisant son propre diff.
   La taille vient de variables portées par la ligne : c'est le SEUL endroit où elle se
   règle, et `--gros` n'a qu'à les redéfinir (pas de seconde recette qui contredit
   celle-ci quelques milliers de lignes plus bas). */
.cmd-ord { --cmd-ph-l: 76px; --cmd-ph-h: 95px; }
.cmd-ord--gros { --cmd-ph-l: 108px; --cmd-ph-h: 135px; }
.cmd-ord .cmd-th { width: var(--cmd-ph-l); height: var(--cmd-ph-h); align-self: flex-start; }
.cmd-ord-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--e-6); }
.cmd-ord .cmd-price { flex: 0 0 auto; width: 60px; text-align: right; font-size: var(--t-base); font-weight: var(--fw-gras); }
.cmd-ord-acts { flex: 0 0 auto; display: flex; align-items: center; gap: var(--e-6); }
.cmd-iconb { width: 30px; height: 30px; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); border: 1px solid rgba(var(--th-voile),0.12); background: rgba(var(--th-voile),0.04);
  color: var(--text-2); cursor: pointer; transition: background var(--t-bref), border-color var(--t-bref), color var(--t-bref); }
.cmd-iconb:hover { background: rgba(var(--th-voile),0.09); border-color: var(--survol-bord); color: var(--text); }
.cmd-ord .cmd-b { padding: var(--e-6) var(--e-12); min-width: 112px; display: inline-flex; align-items: center; justify-content: center; gap: var(--e-6); }

/* Bouton « Ajouter au panier » (lot) + modale de confirmation panier */
.cmd-b--cart { display: inline-flex; align-items: center; gap: var(--e-6);
  background: rgba(var(--th-accent-rgb),0.16); border-color: rgba(var(--th-accent-rgb),0.4); color: var(--accent); }
.cmd-b--cart:hover { background: rgba(var(--th-accent-rgb),0.28); border-color: rgba(var(--th-accent-rgb),0.6); }
.cmd-cart-list { display: flex; flex-direction: column; gap: var(--e-6); max-height: 260px; overflow-y: auto; margin-bottom: var(--e-12); }
.cmd-cart-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--e-12);
  padding: var(--e-8) var(--e-10); border-radius: var(--r-sm); background: rgba(var(--th-voile),0.04); }
.cmd-cart-t { font-size: var(--t-base); color: var(--text); font-weight: var(--fw-moyen); flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmd-cart-s { font-size: var(--t-meta); color: var(--text-muted); white-space: nowrap; flex: 0 0 auto; }
.cmd-cart-skip { font-size: var(--t-meta); color: var(--red); margin-bottom: var(--e-10); line-height: var(--lh-serre); }
@keyframes cmd-spin { to { transform: rotate(360deg); } }
.cmd-spin { animation: cmd-spin 0.7s linear infinite; transform-origin: center; }

/* ══════════════ Limite de vente — widget Dashboard ══════════════ */
.dash-limit { margin: var(--e-14) 0 var(--e-4); }
.dash-lim-card { background: rgba(var(--th-voile),0.04); border: 1px solid rgba(var(--th-voile),0.08); border-radius: var(--r-xl); padding: var(--e-18) var(--e-20); transition: transform var(--t-moyen) var(--c-pose), box-shadow var(--t-moyen) var(--c-pose), border-color var(--t-moyen) var(--c-pose); }
.dash-lim-card:hover { transform: translateY(-2px); box-shadow: 0 14px 34px -16px rgba(var(--th-ombre),0.7), inset 0 1px 0 var(--bg-elevated); }
.dash-lim-card--reached { border-color: rgba(248,113,113,0.45); background: rgba(248,113,113,0.06); }
.dash-lim-head { display: flex; align-items: center; justify-content: space-between; gap: var(--e-10); }
.dash-lim-title { font-size: var(--t-body); font-weight: var(--fw-gras); color: var(--text); }
.dash-lim-pill { font-size: var(--t-micro); font-weight: var(--fw-gras); padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule); white-space: nowrap; }
.dash-lim-pill--open { background: rgba(34,197,94,0.16); color: var(--green); }
.dash-lim-pill--reached { background: rgba(248,113,113,0.18); color: var(--red); }
.dash-lim-pill--off { background: rgba(var(--th-voile),0.08); color: var(--text-2); }
.dash-lim-reset { font-size: var(--t-meta); color: var(--text-2); margin-top: var(--e-4); }
.dash-lim-gauge { margin: var(--e-16) 0 var(--e-4); }
.dash-lim-gnum { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--e-8); gap: var(--e-8); }
.dash-lim-cur { font-size: var(--t-xl); font-weight: 800; color: var(--text); }
.dash-lim-thr { font-size: var(--t-base); color: var(--text-2); }
.dash-lim-track { height: 9px; border-radius: var(--r-pilule); background: rgba(var(--th-voile),0.08); overflow: hidden; }
.dash-lim-fill { height: 100%; border-radius: var(--r-pilule); background: var(--green); transition: width var(--t-long); }
.dash-lim-fill--reached { background: var(--red); }
.dash-lim-fill--off { background: rgba(var(--th-voile),0.2); }
.dash-lim-sub { font-size: var(--t-meta); color: var(--text-2); margin-top: var(--e-8); }
.dash-lim-settings { display: flex; gap: var(--e-14); flex-wrap: wrap; align-items: center; margin-top: var(--e-16); padding-top: var(--e-14); border-top: 1px solid rgba(var(--th-voile),0.07); }
.dash-lim-set { display: flex; align-items: center; gap: var(--e-8); font-size: var(--t-base); color: var(--text-2); }
.dash-lim-set strong { color: var(--text); font-weight: var(--fw-fort); }
.dash-lim-days { width: 48px; height: 28px; text-align: center; border-radius: var(--r-sm); border: 1px solid rgba(var(--th-voile),0.14); background: var(--bg-hover); color: var(--text); font-size: var(--t-base); }
.dash-lim-unit { color: var(--text-2); }
.dash-lim-btn { font-size: var(--t-meta); padding: var(--e-6) var(--e-12); border-radius: var(--r-sm); border: 1px solid rgba(var(--th-voile),0.14); background: var(--bg-hover); color: var(--text-2); cursor: pointer; transition: background var(--t-bref), border-color var(--t-bref); }
.dash-lim-btn:hover { background: rgba(var(--th-voile),0.1); border-color: rgba(167,139,250,0.4); }
.dash-lim-btn.on { background: rgba(124,58,237,0.85); color: var(--text); border-color: transparent; }
.dash-lim-accs-wrap { margin-top: var(--e-14); }
.dash-lim-accs-wrap summary { font-size: var(--t-base); color: var(--text-2); cursor: pointer; }
.dash-lim-accs { margin-top: var(--e-10); display: flex; flex-direction: column; gap: var(--e-10); }
.dash-lim-acc-top { display: flex; justify-content: space-between; font-size: var(--t-mini); color: var(--text-2); margin-bottom: var(--e-4); }
.dash-lim-acc-track { height: 6px; border-radius: var(--r-pilule); background: rgba(var(--th-voile),0.08); overflow: hidden; }
.dash-lim-acc-fill { height: 100%; border-radius: var(--r-pilule); background: var(--cyan); }
.dash-lim-acc-fill.reached { background: var(--red); }
/* Bouton « Ouvrir dans Brave » (logo Brave, contour violet) */
.compte-w-brave {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: var(--e-6);
  padding: var(--e-8) var(--e-10); border-radius: var(--r-md); font: inherit; font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer;
  border: 1px solid var(--violet); background: rgba(var(--th-accent-rgb),0.10); color: rgba(var(--th-voile),0.92);
  transition: background var(--t-moyen), border-color var(--t-moyen), transform var(--t-bref);
}
.compte-w-brave:hover { background: var(--violet-tint-strong); border-color: var(--violet-hover); }
.compte-w-brave:active { transform: scale(0.97); }
/* Bouton paramètres (choisir le profil Brave) */
.compte-w-gear {
  flex: 0 0 auto; width: 36px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); cursor: pointer; border: 1px solid rgba(var(--th-voile),0.12);
  background: var(--bg-hover); color: var(--text-2);
  transition: background var(--t-moyen), border-color var(--t-moyen), color var(--t-moyen), transform var(--t-bref);
}
.compte-w-gear:hover { background: var(--violet-tint); border-color: var(--violet); color: var(--violet-light); }
.compte-w-gear:active { transform: scale(0.95); }
.compte-w-gear svg { width: 16px; height: 16px; }

/* ════ Carte Comptes — version épurée (override) ════ */
.compte-w { padding: var(--e-14) var(--e-16); gap: var(--e-12); }
.compte-w-top { align-items: center; gap: var(--e-10); }
/* Vignette modèle neutre (l'état passe par la pastille, plus de liseré coloré) */
.compte-w-face { border: 1px solid rgba(var(--th-voile),0.12) !important; }
.compte-w-face--ph { display: flex; align-items: center; justify-content: center; color: var(--text-3); background: var(--bg-hover); }
/* #N discret (petit, à gauche) */
.compte-w-num { font-size: var(--t-micro); font-weight: var(--fw-fort); color: rgba(var(--th-voile),0.4); background: none; border: none; padding: 0; margin-right: var(--e-2); flex: 0 0 auto; }
.compte-w-num.none { opacity: 0.4; }
/* Pastille d'état, poussée à droite */
.compte-w-statedot { flex: 0 0 auto; margin-left: auto; width: 9px; height: 9px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 3px rgba(74,222,128,0.14); }
.compte-w-statedot.off { background: var(--amber); box-shadow: 0 0 0 3px rgba(251,146,60,0.16); }
/* Sous-ligne : alertes en orange (déconnecté / clé / ext) */
.compte-w-sub.warn { color: var(--amber); }
/* Métriques EN LIGNE compactes (plus de gros pavés) */
.compte-w-metrics { display: flex !important; gap: var(--e-18); }
.compte-w-m { display: flex; align-items: baseline; gap: var(--e-6); font-size: var(--t-meta); color: var(--text-2); }
.compte-w-mv { font-size: var(--t-body); font-weight: var(--fw-gras); color: var(--text); }
.compte-w-m.ship .compte-w-mv { color: var(--amber); }
/* ⚠️ L'ÂGE DES CHIFFRES DE VENTE. Il traverse les deux colonnes : ce n'est pas une mesure
   de plus, c'est un avertissement SUR les mesures d'à côté. Il prend les jetons de
   `.compte-w-m`, sa famille — rien de nouveau — mais en retrait, parce qu'il ne doit pas
   se lire avant les chiffres qu'il commente. */
.compte-w-vieux { grid-column: 1 / -1; font-size: var(--t-micro); color: var(--text-3);
  font-style: italic; margin-top: calc(var(--e-2) * -1); }
/* Icônes dans les badges (clé / alerte) */
.compte-w-badge svg { width: 12px; height: 12px; vertical-align: -2px; margin-right: var(--e-4); }

/* Indicateur d'état du lanceur Brave */
.comptes-launcher { font-size: var(--t-base); white-space: nowrap; margin-left: auto; display: inline-flex; align-items: center; }
.comptes-launcher.up { color: var(--safe-text); }
.comptes-launcher.down { color: var(--text-3); }
/* Pastille d'état (remplace l'emoji) — réutilisable partout */
.status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: var(--e-6); flex-shrink: 0; background: currentColor; }
.comptes-launcher.up .status-dot { background: var(--green); box-shadow: 0 0 0 3px rgba(110,210,168,0.15); }
.comptes-launcher.down .status-dot { background: var(--red); }

/* Sélecteur de profil Brave (modale) */
.compte-pick-list { display: flex; flex-direction: column; gap: var(--e-6); margin-top: var(--e-4); max-height: 280px; overflow-y: auto; }
.compte-pick-row {
  text-align: left; padding: var(--e-10) var(--e-12); border-radius: var(--r-md); font: inherit; font-size: var(--t-base); cursor: pointer;
  border: 1px solid var(--border-mid); background: var(--surface); color: var(--text-1);
  transition: background var(--t-bref), border-color var(--t-bref);
}
.compte-pick-row:hover { background: var(--violet-tint); border-color: var(--violet); color: var(--violet-light); }

/* Popup noter depuis la carte */
.lib-card-star-popup {
  position: fixed;
  z-index: 9999;
  background: var(--surface-2, #1e1e28);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-6) var(--e-10);
  display: flex; gap: var(--e-4);
  box-shadow: 0 8px 24px rgba(var(--th-ombre),0.5);
}
.lib-card-star-opt {
  background: none; border: none;
  font-size: var(--t-lead);
  color: var(--text-3);
  cursor: pointer; padding: 0 var(--e-1);
  transition: color var(--t-bref), transform var(--t-bref);
  line-height: var(--lh-un);
}
.lib-card-star-opt.active, .lib-card-star-opt.hover { color: var(--amber); transform: scale(1.15); }

/* Widget étoiles dans le détail */
.dress-detail-star-row {
  display: flex; align-items: center; gap: var(--e-4);
  padding: var(--e-6) 0 var(--e-10);
}
.dress-detail-star {
  background: none; border: none;
  font-size: var(--t-title);
  color: var(--text-3);
  cursor: pointer; padding: 0;
  line-height: var(--lh-un);
  transition: color var(--t-bref), transform var(--t-bref);
}
.dress-detail-star.active { color: var(--amber); }
.dress-detail-star.hover  { color: var(--amber); transform: scale(1.1); }
.dress-detail-star-label {
  font-size: var(--t-meta);
  color: var(--text-2);
  margin-left: var(--e-6);
}

/* Filtre étoiles dans les filtres avancés */
.lib-rating-filter-row {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-4) 0 var(--e-2);
}
.lib-rating-filter-label {
  font-size: var(--t-meta);
  color: var(--text-2);
  white-space: nowrap;
}
.lib-rating-stars { display: flex; gap: var(--e-2); }
.lib-rating-star {
  background: none; border: none;
  font-size: var(--t-lead);
  color: var(--text-3);
  cursor: pointer; padding: 0 var(--e-1);
  transition: color var(--t-bref), transform var(--t-bref);
  line-height: var(--lh-un);
}
.lib-rating-star.active { color: var(--amber); }
.lib-rating-star:hover  { color: var(--amber); transform: scale(1.12); }
.lib-rating-clear {
  background: none; border: none;
  color: var(--text-2); font-size: var(--t-mini);
  cursor: pointer; padding: var(--e-2) var(--e-4);
  border-radius: var(--r-micro);
  transition: color var(--t-bref);
}
.lib-rating-clear:hover { color: var(--red); }

/* ══ Bibliothèque « Vendeuses » : fiche en DEUX ZONES — le visage (haut) + le compte (bande basse) ══ */

/* Badge GABARIT — coin haut-gauche du visage, repérage rapide de la taille */
.lib-vend-gab {
  position: absolute;
  top: 7px;
  left: 7px;
  min-width: 20px;
  padding: var(--e-2) var(--e-8);
  font-size: var(--t-micro);
  font-weight: 800;
  letter-spacing: var(--ls-leger);
  text-align: center;
  color: var(--text-2);
  background: rgba(var(--th-panneau-rgb),0.72);
  backdrop-filter: blur(4px);
  border: 1px solid rgba(var(--th-voile),0.14);
  border-radius: var(--r-sm);
  pointer-events: none;
}

/* Ligne d'identité (mutée) sous le nom : « 2/3 vues · brune » */
.lib-vend-id {
  font-size: var(--t-micro);
  color: var(--text-3, #8a90a0);
}

/* Bande COMPTE — zone basse, nettement séparée du visage */
.lib-cpt-band {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  margin: var(--e-4) var(--e-2) var(--e-2);
  padding: var(--e-8) var(--e-10);
  background: rgba(var(--th-voile),0.028);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.lib-cpt-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
  box-shadow: 0 0 0 3px rgba(var(--th-voile),0.04);
}
.lib-cpt-label {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-zero);
  white-space: nowrap;
}
.lib-cpt-who {
  font-size: var(--t-micro);
  font-weight: var(--fw-fort);
  color: var(--text-2);
  margin-left: auto;
  max-width: 55%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lib-cpt-who.is-free { font-style: italic; font-weight: var(--fw-moyen); color: var(--violet-light); }
.lib-cpt-who.is-empty { font-style: italic; font-weight: var(--fw-moyen); color: var(--text-3); }
.lib-cpt-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: var(--r-sm);
  color: var(--text-3);
  border: 1px solid transparent;
  transition: color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
}
.lib-cpt-link:hover {
  color: var(--text-1);
  background: var(--bg-hover);
  border-color: var(--border);
}
/* Filtre statut dans la barre modèles : pastille de couleur + séparateur avec les tailles */
.lib-statut-dot { width: 7px; height: 7px; border-radius: 50%; margin-right: var(--e-6); flex: none; }
.lib-size-sep { width: 1px; align-self: stretch; margin: var(--e-4) var(--e-6); background: var(--border-strong, rgba(var(--th-voile),0.12)); }
.lib-card-actions {
  display: flex;
  gap: var(--e-2);
  opacity: 0;
  transition: opacity var(--t-moyen);
  flex-shrink: 0;
}
.lib-card:hover .lib-card-actions { opacity: 1; }
.lib-card-btn {
  width: 26px; height: 26px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: var(--transi);
}
.lib-card-btn:hover { border-color: var(--violet-mid); color: var(--violet-light); background: var(--surface); }
.lib-card-btn.del:hover { border-color: rgba(var(--th-danger-rgb),0.4); color: var(--red); }
.lib-card-link {
  width: 26px; height: 26px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: var(--transi);
  text-decoration: none;
  flex-shrink: 0;
  padding: 0;
  font-family: inherit;
}
.lib-card-link:hover { border-color: var(--cyan); color: var(--cyan-light); }

/* Name modal */
.name-modal-card {
  position: relative;
  z-index: 1;
  width: 360px;
  max-width: 94vw;
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.name-modal-input { margin: var(--e-8) var(--e-18) var(--e-4);
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  outline: none;
  transition: border-color var(--t-moyen) }
.name-modal-input:focus { border-color: var(--violet); }
.lib-empty {
  grid-column: 1/-1;
  text-align: center;
  padding: 60px 0;
  color: var(--text-3);
  font-size: var(--t-small);
}

/* ── Lib Picker overlay ───────────────────────────── */
.lib-picker {
  position: fixed;
  inset: 0;
  /* Au-dessus des modales de l'app (édition brouillon, planif… en z-index 9000) pour que le
     sélecteur de modèle ne s'ouvre JAMAIS derrière elles ; reste sous les toasts/confirm (9999+). */
  z-index: 9500;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lib-picker.hidden { display: none; }
.lib-picker-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(var(--th-panneau-rgb),0.72);
  backdrop-filter: blur(4px);
}
.lib-picker-panel {
  position: relative;
  z-index: 1;
  width: min(960px, 96vw);
  max-height: 90vh;
  /* ⚠️ UN PANNEAU DOIT ÊTRE OPAQUE. C'était `var(--surface)`, qui vaut
     rgba(var(--th-voile),0.03) : une TEINTE de 3 % de blanc, faite pour être posée SUR un
     fond, pas pour en servir. Le panneau n'avait donc aucun fond réel et la
     bibliothèque se lisait au travers — illisible, et ça donnait l'impression d'un
     écran mal fini. On emprunte le jeton opaque que le thème possède déjà et que cinq
     autres panneaux utilisent (--bg-card-solid), plutôt que d'inventer une couleur. */
  background: var(--bg-card-solid);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(var(--th-ombre),0.5);
}
.lib-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--e-16) var(--e-20);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.lib-picker-title {
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  color: var(--text);
}
.lib-picker-search-bar {
  padding: var(--e-10) var(--e-16);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: var(--e-10);
}
.lib-picker-search-input {
  width: 100%;
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--t-base);
  font-family: inherit;
  padding: var(--e-8) var(--e-12) var(--e-8) 34px;
  outline: none;
  transition: border-color var(--t-moyen);
  box-sizing: border-box;
}
.lib-picker-search-input:focus { border-color: var(--violet); }
.lib-picker-search-input::placeholder { color: var(--text-3); }
.lib-picker-search-wrap {
  position: relative;
  flex: 1;
}
/* Tri PRIX du sélecteur de génération (deux boutons ↑/↓, à côté de la recherche) */
.lib-picker-sort-wrap { display: flex; align-items: center; gap: var(--e-6); flex-shrink: 0; }
.lib-picker-sort-btn {
  padding: var(--e-8) var(--e-12);
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text-3);
  font-size: var(--t-base);
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
}
.lib-picker-sort-btn:hover { color: var(--text); border-color: var(--border-mid); }
.lib-picker-sort-btn.active { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }
.lib-picker-search-wrap svg {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-3);
  pointer-events: none;
}
.lib-picker-body {
  flex: 1;
  overflow-y: auto;
  padding: var(--e-16);
}
.lib-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: var(--e-8);
}
/* ⚠️ LES CARTES DE NICHE SONT CELLES DE LA BIBLIOTHÈQUE (`.lib-niche`, format 4/5) —
   on n'en dessine pas une seconde sorte. Mais la grille du sélecteur est calibrée pour
   des vignettes de 110 px : à cette largeur, une carte de niche devient un timbre. */
.lib-picker-grid--niches {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--e-12);
}
.lib-load-sentinel {
  grid-column: 1 / -1;
  height: 1px;
}
.lib-picker-card {
  position: relative;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--t-moyen), transform var(--t-moyen);
}
.lib-picker-card:hover { border-color: var(--violet-mid); transform: translateY(-2px); }
.lib-picker-card--recent { border-color: rgba(var(--th-accent-rgb),.55); }
.lib-picker-recent-badge {
  position: absolute; top: 7px; left: 7px; z-index: 2;
  font-size: var(--t-micro); font-weight: var(--fw-gras); letter-spacing: var(--ls-leger);
  color: var(--sur-accent); background: rgba(var(--th-accent-rgb),.92);
  padding: var(--e-4) var(--e-8); border-radius: var(--r-pilule);
  box-shadow: 0 2px 8px -2px rgba(var(--th-ombre),.5);
}
.lib-picker-card-cover {
  aspect-ratio: 3/4;
  background: var(--surface-3);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lib-picker-card-cover img { width: 100%; height: 100%; object-fit: cover; }
.lib-picker-card-cover-placeholder { color: var(--text-3); opacity: 0.4; }
.lib-picker-card-info {
  padding: var(--e-6) var(--e-8) var(--e-6);
}
.lib-picker-card-name {
  font-size: var(--t-mini);
  font-weight: var(--fw-fort);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lib-picker-card-meta {
  font-size: var(--t-micro);
  color: var(--text-3);
  margin-top: var(--e-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lib-picker-empty {
  text-align: center;
  padding: 60px 0;
  color: var(--text-3);
  font-size: var(--t-small);
  grid-column: 1/-1;
}

/* ⚠️ L'AVIS DE REPLI : il tient TOUTE la largeur de la grille, sinon il se rangerait
   comme une carte et se lirait comme un pack sans image. Ton ambre, pas rouge : ce
   n'est pas une panne, c'est un état du parc qu'Amadou peut changer. */
.lib-picker-avis {
  grid-column: 1/-1;
  display: flex;
  align-items: center;
  gap: var(--e-10);
  padding: var(--e-12) var(--e-14);
  margin-bottom: var(--e-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--moy-bg);
  color: var(--moy-text);
  font-size: var(--t-small);
  line-height: var(--lh-normal);
}

/* ── Étape coloris dans le picker ─────────────────────── */
.coloris-step-header {
  grid-column: 1/-1;
  display: flex;
  align-items: center;
  gap: var(--e-10);
  padding-bottom: var(--e-10);
  margin-bottom: var(--e-4);
  border-bottom: 1px solid var(--border);
}
.coloris-back-btn {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  font-size: var(--t-base);
  color: var(--text-3);
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--e-4) var(--e-10);
  cursor: pointer;
  transition: color var(--t-moyen), border-color var(--t-moyen);
}
.coloris-back-btn:hover { color: var(--text-1); border-color: var(--violet-mid); }
.coloris-step-label {
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text-2);
  letter-spacing: var(--ls-large);
}
/* ⚠️ LE BOUTON « VALIDER (N) » A ÉTÉ RETIRÉ (Amadou, 03/09) : « quand j'appuie dessus,
   je n'ai pas à appuyer sur valider ». Il n'était pas décoratif — c'était LUI qui
   enregistrait le choix — donc le clic sur un coloris enregistre désormais lui-même.
   Ce qui reste à sa place : le compte de ce qui est retenu pour CE produit. */
.coloris-step-compte { margin-left: auto; font-size: var(--t-meta); color: var(--text-2); }
.coloris-step-compte.vide { color: var(--text-3); }
.coloris-picker-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--t-moyen), transform var(--t-moyen);
  background: var(--surface-2);
  display: flex;
  flex-direction: column;
}
.coloris-picker-card:hover { border-color: var(--violet-mid); transform: translateY(-2px); }
/* Coloris sélectionné (mode multi batch) : liseré violet + pastille check */
.coloris-picker-card--sel { border-color: var(--violet); box-shadow: 0 0 0 1px var(--violet); }
.coloris-pick-check {
  position: absolute;
  top: 6px; right: 6px;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--violet);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 2;
  box-shadow: 0 1px 4px rgba(var(--th-ombre),.35);
}
.coloris-picker-card--sel .coloris-pick-check { display: flex; }
.coloris-picker-img {
  width: 100%;
  aspect-ratio: 3/4;
  object-fit: cover;
  display: block;
}
.coloris-picker-swatch {
  width: 100%;
  aspect-ratio: 3/4;
}
.coloris-picker-info {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-8) var(--e-10);
}
.coloris-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid rgba(var(--th-voile),0.15);
}
.coloris-picker-name {
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text-1);
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.coloris-picker-meta {
  font-size: var(--t-mini);
  color: var(--text-3);
  flex-shrink: 0;
}

/* ── Inline delete confirm ────────────────────────── */
.lib-card-confirm {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  font-size: var(--t-mini);
  color: var(--text-2);
  white-space: nowrap;
}
.lib-card-confirm span { margin-right: var(--e-2); }
.lib-card-confirm-yes, .lib-card-confirm-no {
  padding: var(--e-2) var(--e-8);
  border-radius: var(--r-micro);
  font-size: var(--t-mini);
  cursor: pointer;
  transition: var(--transi);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
}
.lib-card-confirm-yes { border-color: rgba(var(--th-danger-rgb),0.4); background: rgba(var(--th-danger-rgb),0.08); color: var(--ose-text); }
.lib-card-confirm-yes:hover { background: rgba(var(--th-danger-rgb),0.2); }
.lib-card-confirm-no:hover { border-color: var(--violet-mid); color: var(--text); }

/* ── Delivery badge ───────────────────────────────── */
.lib-price-badge {
  display: inline-block;
  padding: var(--e-2) var(--e-10);
  border-radius: var(--r-pilule);
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  background: var(--tier-premium-bg);
  color: var(--violet-light);
  border: 1px solid rgba(var(--th-accent-rgb),.3);
}
/* ── Marque inline sur card ── */
.lib-card-meta-row {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  flex-wrap: wrap;
}
.lib-card-marque-row {
  margin-top: var(--e-4);
}
.lib-card-marque-val {
  font-size: var(--t-mini);
  color: var(--text-muted);
  cursor: pointer;
  border-bottom: 1px dashed transparent;
  transition: var(--transi);
  padding: var(--e-1) var(--e-2);
}
.lib-card-marque-val:hover {
  color: var(--text);
  border-bottom-color: var(--border-strong);
}
.lib-card-marque-val.empty {
  color: var(--text-3);
  font-style: italic;
}
.lib-marque-inline-input {
  font-size: var(--t-mini);
  padding: var(--e-2) var(--e-6);
  border-radius: var(--r-sm);
  border: 1px solid var(--violet-mid);
  background: var(--surface);
  color: var(--text);
  outline: none;
  width: 100%;
  max-width: 120px;
}

/* ── Marque badge sur card ── */
.lib-marque-badge { background: rgba(236,72,153,.12);
  color: var(--violet);
  border: 1px solid rgba(236,72,153,.25);
  margin-right: var(--e-4); }

/* ── Barre Gammes (tiers) ── */
.lib-tier-bar {
  display: inline-flex;
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-4);
  gap: var(--e-2);
  width: auto;
  align-self: flex-start;
  border-top: 1px solid var(--border);
  margin-top: 0;
  flex-shrink: 0;
}
.lib-tier-bar.hidden { display: none; }
.lib-tier-tab {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-6) var(--e-14);
  border-radius: var(--r-sm);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-leger);
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: var(--transi);
}
.lib-tier-tab:not(.active):hover { color: var(--text); border-color: transparent; }
.lib-tier-tab.active {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: transparent;
  box-shadow: none;
}
/* Badge compteur "VOLUME 87" — pill tabular-nums */
.lib-tier-tab-count {
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
  background: rgba(var(--th-voile),0.04);
  padding: var(--e-1) var(--e-8);
  border-radius: var(--r-pilule);
  min-width: 18px;
  text-align: center;
  line-height: var(--lh-serre);
}
/* Même correction que .lib-filter-count : les sous-onglets d'état portent exactement
   le même chiffre-sur-fond-voisin, il aurait été illisible pour la même raison. */
.lib-tier-tab.active .lib-tier-tab-count {
  color: var(--sur-accent);
  font-weight: var(--fw-fort);
  background: var(--violet);
}
.lib-tier-add-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  border: 1.5px dashed var(--text-3);
  background: var(--surface);
  color: var(--text-2); font-size: var(--t-small); font-weight: var(--fw-fort);
  cursor: pointer; transition: border-color var(--t-moyen), color var(--t-moyen);
  flex-shrink: 0; margin-left: var(--e-2);
}
.lib-tier-add-btn:hover { border-color: var(--violet); color: var(--violet-soft); }

/* ── Barre boutiques (chips marques contextuelles) ── */
.lib-marque-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--e-4);
  padding: var(--e-6) 0 var(--e-2);
  margin-top: var(--e-2);
  border-top: 1px solid var(--border);
  flex: 1;
  min-width: 0;
}
.lib-marque-bar.hidden { display: none; }
.lib-marque-chip--undef { border-style: dashed; color: var(--text-3); }
.lib-marque-chip--undef:hover { color: var(--text-2); }
.lib-marque-chip--undef.active { border-style: solid; }
.lib-style-chip-wrap {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
}
.lib-style-menu-btn {
  display: flex; align-items: center; justify-content: center;
  background: none; border: none;
  color: var(--text-3); font-size: var(--t-small); line-height: var(--lh-un);
  padding: 0 var(--e-4); height: 22px;
  border-radius: var(--r-micro); cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-moyen), color var(--t-moyen);
  flex-shrink: 0;
}
.lib-style-chip-wrap:hover .lib-style-menu-btn { opacity: 1; }
.lib-style-menu-btn:hover { color: var(--text); background: rgba(var(--th-voile),.08); }

/* Bouton + ajouter un style */
.lib-style-add-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 1.5px dashed var(--text-3);
  background: var(--surface);
  color: var(--text-2);
  cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
  flex-shrink: 0;
}
.lib-style-add-btn:hover { border-color: var(--violet); color: var(--violet-soft); background: rgba(var(--th-accent-rgb),.08); }

/* Séparateur entre "Toutes" et les boutiques */
.lib-boutique-sep {
  width: 1px;
  height: 18px;
  background: var(--border);
  margin: 0 var(--e-4);
  flex-shrink: 0;
}

.lib-marque-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  padding: 0 var(--e-14);
  height: 30px;
  border-radius: var(--r-pilule);
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-2);
  transition: var(--transi);
  white-space: nowrap;
  cursor: pointer;
}
.lib-marque-chip:not(.active):hover { background: var(--surface-2); color: var(--text); border-color: var(--violet-mid); }
.lib-marque-chip.active {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
  color: var(--violet-soft);
}
.lib-marque-chip-label {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  padding: 0 var(--e-12);
  height: 100%;
  background: none;
  border: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
/* Badge compteur "H&M 18" — pill tabular-nums, plus discret que le tier */
.lib-marque-chip-count {
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
  line-height: var(--lh-un);
  opacity: 0.85;
}
.lib-marque-chip.active .lib-marque-chip-count {
  color: var(--violet-soft);
  opacity: 0.75;
}
.lib-marque-chip-edit {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 var(--e-10) 0 var(--e-4);
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  opacity: 0;
  max-width: 0;
  overflow: hidden;
  transition: opacity var(--t-moyen), max-width var(--t-moyen);
}
.lib-marque-chip:not(.active):hover .lib-marque-chip-edit,
.lib-marque-chip.active .lib-marque-chip-edit {
  opacity: .8;
  max-width: 30px;
}
.lib-marque-chip-edit:hover { opacity: 1; color: var(--violet); }
.lib-boutique-add {
  opacity: .55;
  padding: var(--e-6) var(--e-10);
  margin-left: var(--e-2);
}
.lib-boutique-add:hover { opacity: 1; }

/* ── Filtres avancés biblio ─────────────────────────────────────────────────
   ⚠️⚠️⚠️ LE PANNEAU FLOTTE, IL NE POUSSE PLUS RIEN. Amadou (25/08) : « je veux que ce soit
   vraiment discret ». Dans le flux, le déplier faisait descendre TOUS les produits d'un
   coup — l'écran entier bougeait pour montrer six réglages. Posé au-dessus, la grille ne
   perd pas un pixel : ouvert ou fermé, elle est au même endroit.
   ⚠️⚠️ IL S'ANCRE SUR `.lib-sticky-bar`, PAS SUR LA RANGÉE DES BOUTONS. Amadou (25/08) :
   « je dois pouvoir utiliser les deux en même temps » — filtrer, puis sélectionner le
   résultat. Ancré sur la rangée, le panneau retombait PAR-DESSUS la barre de sélection
   qui s'ouvre juste en dessous et cachait « Supprimer » et « Annuler » (55 px mesurés).
   La barre collante, elle, contient les DEUX : s'ancrer sur elle fait démarrer le panneau
   sous tout le bloc, que la barre de sélection soit là ou non — sans hauteur écrite en
   dur qui redeviendrait fausse au premier changement de gabarit.
   ⚠️ `position: sticky` suffit à en faire un repère ; ne PAS remettre `position: relative`
   sur la rangée, ça reprendrait l'ancrage et ramènerait le recouvrement. Son padding
   latéral vaut `--e-32`, d'où le même jeton sur le `right` du panneau : les deux bords
   droits retombent au pixel près. */
/* ⚠️ LE CONTENEUR NE PORTE PLUS RIEN. C'est `.lib-filter-content` que le bouton ouvre et
   ferme ; le conteneur, lui, reste affiché tant qu'on est sur les produits. Poser le
   cadre et l'ombre sur le conteneur aurait dessiné une boîte vide en permanence. */
.lib-adv-filters { position: static; background: none; border: 0; }
.lib-adv-filters.hidden { display: none; }

/* ⚠️⚠️⚠️ LE PANNEAU FLOTTE, IL NE POUSSE PLUS RIEN. Amadou (25/08) : « je veux que ce soit
   vraiment discret ». Dans le flux, le déplier faisait descendre TOUS les produits d'un
   coup — l'écran entier bougeait pour montrer six réglages. Posé au-dessus, la grille ne
   perd pas un pixel : ouvert ou fermé, elle est au même endroit.
   ⚠️ Il s'ancre à `.lib-sticky-bar`, seul ancêtre positionné (voir la note plus haut).
   Sans repère il se rattacherait à un bloc quelconque — mesuré une fois : écrasé à 2 px. */
.lib-filter-content {
  position: absolute; top: calc(100% + var(--e-8)); right: var(--e-32); z-index: 60;
  width: 320px; max-width: calc(100vw - var(--e-32));
  display: grid; grid-template-columns: 1fr; gap: var(--e-12);
  padding: var(--e-14) var(--e-16);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-carte);
  /* ⚠️⚠️ UN FOND OPAQUE, PAS `--surface`. Celui-ci vaut du blanc à 3 % : posé dans le flux
     il se contentait de teinter la page, mais un panneau qui FLOTTE au-dessus de la grille
     doit la masquer — on lisait les produits au travers des filtres. `--th-panneau` est la
     surface pleine du thème : sombre sur un thème sombre, claire sur un thème clair. */
  background: var(--th-panneau);
  box-shadow: 0 var(--e-16) var(--e-40) rgba(var(--th-ombre), .34);
  animation: libFiltresVient var(--t-moyen) var(--c-pose);
  text-align: left;
}
@keyframes libFiltresVient {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
.lib-filter-content.hidden { display: none; }
.lib-filter-content > * { min-width: 0; }

.lib-adv-filters-bar {
  padding: var(--e-6) var(--e-12);
}

/* ⚠️ CE BLOC NE DESSINE PLUS LE BOUTON — il porte `btn-secondary hist-mode-select-btn`,
   comme « Sélectionner » (Amadou, 25/08). Redéclarer ici un fond, une bordure et un rayon
   ferait deux dessins pour le même bouton, et l'un des deux gagnerait au hasard de l'ordre
   du fichier : il faisait 38 px de haut quand son voisin en faisait 34.
   Il ne reste que ce qui lui est PROPRE : la mise en ligne de son libellé et de son
   compteur. */
.lib-filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  cursor: pointer;
}
.lib-filter-toggle:hover { background: rgba(var(--th-voile),0.08); color: var(--text); }
.lib-filter-toggle.open { background: rgba(var(--th-accent-rgb),0.1); color: var(--accent); border-color: rgba(var(--th-accent-rgb),0.35); }
.lib-filter-toggle.has-filters { color: var(--accent); border-color: var(--tier-premium-glow); }

.lib-filter-active-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--text);
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  line-height: var(--lh-un);
}
.lib-filter-active-count.hidden { display: none; }

.lib-filter-content {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  padding: var(--e-6) var(--e-12) var(--e-10);
}
.lib-filter-content.hidden { display: none; }

.lib-adv-filters-price {
  display: flex;
  align-items: center;
  gap: var(--e-6);
}
.lib-adv-filters-price svg {
  opacity: 0.4;
  flex-shrink: 0;
}
.lib-price-inp {
  width: 76px;
  padding: var(--e-6) var(--e-8);
  background: var(--bg-elevated);
  border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--t-meta);
  outline: none;
  -moz-appearance: textfield;
}
.lib-price-inp::-webkit-outer-spin-button,
.lib-price-inp::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.lib-price-inp:focus { border-color: rgba(var(--th-accent-rgb),0.5); background: rgba(var(--th-voile),0.09); }
.lib-price-inp::placeholder { opacity: 0.4; }
.lib-price-sep {
  font-size: var(--t-meta);
  opacity: 0.4;
}
.lib-price-unit {
  font-size: var(--t-meta);
  opacity: 0.4;
}
/* Filtres à chips de la Bibliothèque (Lieu UE/CN, Taille) + boutons tri prix ↑/↓ */
.lib-filter-chip-row, .lib-filter-sort-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--e-6); margin-top: var(--e-8);
}
.lib-filter-chip-label { font-size: var(--t-mini); opacity: 0.5; margin-right: var(--e-2); }
.lib-fchip {
  padding: var(--e-4) var(--e-10);
  background: var(--bg-elevated);
  border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-sm);
  color: var(--text-3);
  font-size: var(--t-meta);
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
}
.lib-fchip:not(.active):hover { color: var(--text); border-color: rgba(var(--th-accent-rgb),0.5); }
.lib-fchip.active { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }

.lib-color-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
}
.lib-color-chips.hidden { display: none; }

.lib-color-chip {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-xl);
  border: 1px solid rgba(var(--th-voile),0.1);
  background: rgba(var(--th-voile),0.04);
  color: var(--text-muted);
  font-size: var(--t-mini);
  cursor: pointer;
  transition: var(--transi);
  white-space: nowrap;
}
.lib-color-chip:hover { background: rgba(var(--th-voile),0.08); color: var(--text); border-color: rgba(var(--th-voile),0.18); }
.lib-color-chip.active { background: rgba(var(--th-accent-rgb),0.15); color: var(--accent); border-color: var(--tier-premium-glow); }
.lib-color-chip-all { font-weight: var(--fw-moyen); }

/* ⚠️ LA COULEUR SE MONTRE. Un rond de la teinte, pas son nom : quatorze mots sur deux
   lignes deviennent quatorze ronds sur une seule. Le nom vit dans l'infobulle et dans
   l'étiquette d'accessibilité — rien n'est perdu pour qui ne distingue pas la teinte.
   ⚠️ Le liseré est indispensable : sans lui, le rond « Blanc » disparaît sur un thème
   clair et le rond « Noir » sur un thème sombre. */
.lib-color-pastille {
  width: 22px; height: 22px; padding: 0; flex: 0 0 auto;
  border-radius: 50%;
  background: var(--pastille);
  border: 1px solid rgba(var(--th-trait), .45);
  cursor: pointer;
  transition: transform var(--t-bref) var(--c-pose), box-shadow var(--t-bref) var(--c-pose);
}
.lib-color-pastille:hover { transform: scale(1.12); }
.lib-color-pastille.active {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--violet);
}

/* ── La ligne des filtres actifs ───────────────────────────────────────────── */
.lib-filtres-actifs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-12) var(--e-2);
}
.lib-filtres-actifs.hidden { display: none; }
.lib-fa {
  display: inline-flex; align-items: center; gap: var(--e-6);
  font: inherit; font-size: var(--t-micro); color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-pilule); padding: var(--e-2) var(--e-8);
  cursor: pointer;
  transition: border-color var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.lib-fa:hover { border-color: var(--border-strong); color: var(--text); }
.lib-fa-teinte {
  width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto;
  border: 1px solid rgba(var(--th-trait), .45);
}
.lib-fa-vider {
  font: inherit; font-size: var(--t-micro); color: var(--text-3);
  background: transparent; border: 0; cursor: pointer; padding: var(--e-2) var(--e-4);
}
.lib-fa-vider:hover { color: var(--text); }
.lib-color-chip-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid rgba(var(--th-voile),0.15);
}
.lib-color-chip-lbl { line-height: var(--lh-un); }

/* Menu contextuel boutique */
/* ── Modal création boutique ── */
.boutique-name-modal {
  position: fixed;
  inset: 0;
  background: var(--voile);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: var(--voile-flou);
}
.boutique-name-box {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-24);
  width: 340px;
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
  box-shadow: 0 20px 60px rgba(var(--th-ombre),.5);
}
.boutique-name-title {
  font-size: var(--t-small);
  font-weight: var(--fw-gras);
  color: var(--text);
}
.boutique-name-input { width: 100%;
  color: var(--text);
  font-size: var(--t-small);
  outline: none;
  transition: border-color var(--t-moyen);
  box-sizing: border-box }
.boutique-name-input:focus { border-color: var(--violet-mid); }
.boutique-name-btns {
  display: flex;
  align-items: center;
  gap: var(--e-8);
}
.boutique-name-spacer { flex: 1; }
.boutique-name-delete {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  padding: var(--e-8) var(--e-10);
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--ose-text);
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: background var(--t-moyen), border-color var(--t-moyen);
}
.boutique-name-delete:hover {
  background: rgba(248,113,113,.10);
  border-color: rgba(248,113,113,.35);
}
.boutique-tier-label {
  font-size: var(--t-meta);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  color: var(--text-muted);
  text-transform: uppercase;
  margin-top: var(--e-4);
}
.boutique-tier-seg {
  display: flex;
  gap: var(--e-6);
}
.boutique-tier-opt {
  flex: 1;
  padding: var(--e-10) var(--e-10);
  border-radius: var(--r-sm);
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--t-meta);
  font-weight: 800;
  letter-spacing: var(--ls-caps);
  cursor: pointer;
  transition: var(--transi);
}
.boutique-tier-opt:hover { border-color: var(--violet); color: var(--violet); }
.boutique-tier-opt.active {
  background: linear-gradient(135deg, var(--violet), var(--violet-soft));
  border-color: var(--violet-soft);
  color: var(--sur-accent);
}

.boutique-ctx-menu {
  position: fixed;
  z-index: 9999;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(var(--th-ombre),.35);
  overflow: hidden;
  min-width: 160px;
}
.boutique-ctx-menu button {
  display: block;
  width: 100%;
  padding: var(--e-10) var(--e-16);
  text-align: left;
  background: none;
  border: none;
  color: var(--text);
  font-size: var(--t-small);
  cursor: pointer;
}
.boutique-ctx-menu button:hover { background: var(--bg-hover); }

.lib-delivery-badge {
  display: inline-block;
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  padding: var(--e-1) var(--e-6);
  border-radius: var(--r-micro);
  text-transform: uppercase;
  letter-spacing: var(--ls-large);
  vertical-align: middle;
  margin-right: var(--e-4);
}
.lib-delivery-badge.rapide  { background: rgba(34,197,94,0.12);  color: var(--safe-text); }
.lib-delivery-badge.moyenne { background: rgba(251,146,60,0.12); color: var(--moy-text); }

.lib-dress-status-badge {
  font-size: var(--t-mini); font-weight: var(--fw-gras);
  margin-left: var(--e-6);
  vertical-align: middle;
}

/* ── Dress status selector ─────────────────────── */
.dress-status-wrap { margin-bottom: var(--e-20); }
.dress-status-title { font-size: var(--t-meta); font-weight: var(--fw-gras); color: var(--text-3); text-transform: uppercase; letter-spacing: var(--ls-ample); margin-bottom: var(--e-8); }
.dress-status-btns { display: flex; gap: var(--e-8); flex-wrap: wrap; }
.dress-status-btn {
  padding: var(--e-6) var(--e-16);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border);
  background: transparent;
  font-size: var(--t-base); font-weight: var(--fw-fort);
  color: var(--text-3);
  cursor: pointer;
  transition: var(--transi);
}
.dress-status-btn:hover { border-color: var(--status-color, var(--border-strong)); color: var(--status-color, var(--text)); }
.dress-status-btn.active {
  background: color-mix(in srgb, var(--status-color) 15%, transparent);
  border-color: var(--status-color);
  color: var(--status-color);
}

/* ── Delivery toggle in dress detail ─────────────── */
.delivery-toggle {
  display: flex;
  gap: var(--e-8);
}
.delivery-toggle-label {
  font-size: var(--t-base);
  color: var(--text-3);
  margin-bottom: var(--e-6);
}
.delivery-btn {
  flex: 1;
  padding: var(--e-8) 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
}
.delivery-btn.active[data-val="rapide"]  { background: rgba(34,197,94,0.12);  border-color: rgba(34,197,94,0.4);  color: var(--safe-text); }
.delivery-btn.active[data-val="moyenne"] { background: rgba(251,146,60,0.12); border-color: rgba(251,146,60,0.4); color: var(--moy-text); }

/* Detail views */
.lib-detail-header {
  margin-bottom: var(--e-28);
}
.lib-back {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  background: none;
  border: none;
  color: var(--text-3);
  font-size: var(--t-base);
  cursor: pointer;
  padding: var(--e-4) 0;
  margin-bottom: var(--e-14);
  transition: color var(--t-moyen);
}
.lib-back:hover { color: var(--violet-light); }

/* Flèches nav dans la topbar bibliothèque */
.lib-topbar-nav {
  display: flex;
  align-items: center;
  gap: var(--e-4);
}
.lib-nav-arrow {
  width: 30px; height: 30px;
  border-radius: var(--r-sm);
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-2);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--t-moyen), color var(--t-moyen), border-color var(--t-moyen);
  padding: 0;
}
.lib-nav-arrow:hover:not(:disabled) {
  background: rgba(var(--th-accent-rgb),0.1);
  border-color: var(--violet);
  color: var(--violet-light);
}
.lib-nav-arrow:disabled { opacity: 0.25; cursor: default; }
.lib-nav-pos {
  font-size: var(--t-meta);
  color: var(--text-2);
  min-width: 40px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.lib-nav-pos-fixed {
  display: none; /* remplacé par lib-topbar-nav */
  pointer-events: none;
}

.lib-detail-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-16);
}
.lib-detail-actions {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  flex-shrink: 0;
}
.lib-detail-name {
  font-size: var(--t-title);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-serre);
}

/* Model pack slots */
/* Détail modèle : 2 colonnes (vues à gauche compactes/sticky · infos à droite) */
.model-detail-2col {
  display: grid;
  /* La colonne de gauche prenait presque la moitié de l'écran pour trois photos de
     référence : elles écrasaient la fiche. Elle se resserre au profit des champs. */
  grid-template-columns: minmax(0, 4fr) minmax(0, 9fr);
  gap: var(--e-28);
  align-items: start;
}
@media (max-width: 980px) { .model-detail-2col { grid-template-columns: 1fr; } }
.model-detail-2col .model-detail-left { position: sticky; top: 8px; align-self: start; }
@media (max-width: 980px) { .model-detail-2col .model-detail-left { position: static; } }
/* ── Colonne de gauche de la fiche vendeuse ───────────────────────────────────
   L'avatar Vinted ouvre la colonne (c'est le visage qu'on reconnaît en parcourant
   vingt fiches), les vues suivent en dessous, étiquetées SOUS l'image. */
.model-avatar-head {
  padding-bottom: var(--e-18); margin-bottom: var(--e-18);
  border-bottom: 1px solid var(--border);
}
.model-info-avatar-texte { display: flex; flex-direction: column; align-items: flex-start; gap: var(--e-4); min-width: 0; }
/* ⚠️ LA PHRASE « Le visage qu'on voit sur ses annonces » EST RETIRÉE (Amadou, 04/09) :
   elle décrivait l'évidence. Sa règle part avec elle — un style sans élément est du
   poids mort qu'on relit pour rien.
   ⚠️⚠️ ET LA MARGE DU BOUTON PART AUSSI. Elle l'écartait de la phrase ; seule dans une
   colonne centrée sur le rond, elle le poussait 8 px trop bas. C'est le décalage qu'on
   voyait. Sans elle, il s'aligne sur le centre de l'avatar. */

.model-vue { display: flex; flex-direction: column; }

.model-slots {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--e-12);
}
.model-slot {
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius);
  aspect-ratio: 3/4;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e-10);
  cursor: pointer;
  transition: border-color var(--t-moyen), background var(--t-moyen);
  overflow: visible;
  position: relative;
  background: var(--surface);
}
.model-slot > img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: calc(var(--radius) - 1px);
  /* clic = agrandir (zoom-in via openGalleryZoom) ; les badges hover restent au-dessus (z-index:5) */
  cursor: zoom-in;
}
.model-slot:hover { border-color: var(--violet-mid); background: var(--surface-2); }
.model-slot.filled { border-style: solid; border-color: var(--border); cursor: default; }
/* legacy — now handled by .model-slot > img above */
.slot-remove-btn {
  position: absolute;
  top: -7px; right: -7px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--red);
  border: 2px solid var(--bg);
  color: var(--sur-accent);
  font-size: var(--t-mini); line-height: var(--lh-un);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: opacity var(--t-moyen);
  z-index: 5;
}
.model-slot:hover .slot-remove-btn { opacity: 1; }
.slot-replace-btn, .slot-dl-btn {
  position: absolute;
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 2px solid var(--bg);
  color: var(--text);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: opacity var(--t-moyen);
  z-index: 5;
}
.slot-replace-btn { top: -7px; left: -7px; background: var(--violet); }
.slot-dl-btn      { bottom: -7px; left: -7px; background: var(--cyan, var(--cyan)); }
.model-slot:hover .slot-replace-btn,
.model-slot:hover .slot-dl-btn { opacity: 1; }
.model-slot-label {
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-2);
  text-align: center;
  margin-top: var(--e-8);
  white-space: nowrap;
}
.model-slot-add-label {
  font-size: var(--t-meta);
  color: var(--text-3);
}
.slot-gen-btn {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-12);
  border-radius: var(--radius-sm);
  background: var(--violet);
  color: var(--sur-accent);
  border: none;
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: background var(--t-moyen);
  white-space: nowrap;
  z-index: 1;
}
.slot-gen-btn:hover { background: var(--violet-mid, #7c3aed); }
.slot-gen-btn--sm { font-size: var(--t-mini); padding: var(--e-4) var(--e-10); }
.slot-import-btn {
  position: absolute;
  bottom: 28px; right: 6px;
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--text-3);
  cursor: pointer;
  transition: background var(--t-moyen), color var(--t-moyen);
  z-index: 2;
}
.slot-import-btn:hover { background: var(--surface-3); color: var(--text-2); }

/* Dress detail */
.dress-detail-body {
  display: flex;
  flex-direction: column;
  gap: var(--e-24);
}

/* ── Fiche détail robe : layout 2 colonnes (visuels · infos) ── */
/* ⚠️⚠️ LA COLONNE DES PHOTOS EST FIXE, ET C'EST CE QUI ALIGNE L'ÉCRAN. Amadou (20/08) :
   « réduis la taille des photos, l'espace est trop grand, je veux que la gauche et la
   droite soient alignées. »
   En parts (`5fr / 6fr`) la colonne gauche grandissait avec la fenêtre, donc les photos
   aussi, donc la hauteur de la carte : l'alignement tenait à la largeur de l'écran, ce
   qui revient à ne pas tenir. Mesuré à 1690 px : carte gauche 613 px contre 446 à droite,
   167 px de trop.
   288 px n'est pas choisi au jugé — c'est la largeur pour laquelle DEUX colonnes de
   photos en 3/4, plus l'en-tête du coloris et la ligne « Photos de référence », font
   exactement la hauteur du panneau de droite. Mesuré : 280 px → 435 (11 trop court),
   296 px → 456 (10 trop long), 288 px → 446 = la hauteur de l'onglet Fiche.
   ⭐ Et comme elle est fixe, la carte garde cette hauteur À TOUTES LES LARGEURS D'ÉCRAN :
   l'alignement ne dépend plus de la fenêtre. La droite récupère toute la place gagnée —
   le nom de la robe n'y est plus coupé.
   ⚠️ La hauteur du panneau droit dépend de l'onglet (mesuré : Fiche 446, Annonce 493,
   Santé 420, T. Produits 414, Popularité 289, Mesures 244, Infos produit 212,
   T. Vendeuses 174). On cale sur Fiche, qui est l'onglet d'ouverture. */
.dress-detail-2col {
  display: grid;
  grid-template-columns: minmax(0, 288px) minmax(0, 1fr);
  gap: var(--e-28);
  align-items: start;
}
/* ⚠️ LES DEUX COLONNES SONT COLLANTES ET BORNÉES À LA HAUTEUR DE L'ÉCRAN.
   Amadou (2026-07-30) : « l'effet où la robe reste bloquée — qui était beau — se casse
   quand on arrive vers Photos mannequin et Photos produit ».

   Deux défauts, mesurés :
   1) `top: 8px` ignorait l'en-tête, qui est collant lui aussi et mesure 93 px ici :
      85 px de la colonne se figeaient DERRIÈRE son verre dépoli.
   2) Surtout : la colonne des photos est PLUS HAUTE que la fenêtre (976 px à deux
      vendeuses, 1 703 px à neuf, contre 767 px réellement visibles). Or une étagère
      collante plus haute que la vitrine se colle par le HAUT : sa fin ne descend
      jamais jusqu'à l'œil, et une fois sa course épuisée elle se décroche d'un bloc.
      C'est exactement le « scroll à la fin qui casse tout ».

   Chaque colonne a donc désormais SA hauteur — celle de l'écran — et SON ascenseur.
   ⭐ Conséquence voulue, et c'est elle qui tient tout le reste : la page ne défile
   presque plus. Aucune colonne ne dépend donc plus de la longueur de l'AUTRE pour
   rester en place — ce qui permet de raccourcir la colonne de droite en sous-onglets
   sans faire tomber le collage de la gauche. */
.dress-detail-left,
.dress-detail-right {
  position: sticky;
  /* Jamais 8 px en dur : --topbar-h est MESURÉE par _stickyOffsets(), comme partout. */
  top: calc(var(--topbar-h, 76px) + 16px);
  align-self: start;
  /* ⚠️ PLUS DE HAUTEUR BORNEE. Je l'avais posée hier pour rattraper une colonne plus
     haute que l'écran — mais elle rendait le BAS inatteignable (Amadou : « je ne peux
     pas descendre pour voir les photos mannequin »). C'était pire que le mal.
     Ce qui rendait la colonne trop haute, c'étaient les photos générées : elles sont
     désormais derrière un bouton, en haut. La colonne tient donc dans l'écran d'elle-même,
     et le collage fonctionne sans qu'on ait à l'y forcer. */
  display: flex;
  flex-direction: column;
  gap: var(--e-22);
  min-width: 0;
}
/* ⚠️ INDISPENSABLE, et facile à oublier : dans une colonne flex à hauteur bornée, les
   enfants se COMPRESSENT par défaut au lieu de déborder. Sans cette ligne, les blocs
   de photos seraient écrasés pour tenir dans l'écran — et la colonne ne défilerait
   jamais. Vérifié : 1 482 px de défilement avec, 0 sans. */
.dress-detail-left > *,
.dress-detail-right > * { flex-shrink: 0; }

/* ══ L'ALIGNEMENT NE SE CALCULE PLUS, IL SE CONSTRUIT ════════════════════════
   Amadou, troisième passage : « toujours pas la même taille, il manque des pixels
   en bas ». Il a raison sur le fond, et mon erreur était de méthode : je réglais une
   LARGEUR de colonne (288 px) pour qu'une hauteur tombe juste. Ça marchait sur MA
   mesure — écart de 1 px — et pas chez lui : la hauteur du panneau droit dépend du
   contenu réel, du zoom du navigateur et de l'onglet ouvert. Un nombre figé ne peut
   pas suivre trois variables.
   La colonne de gauche S'ÉTIRE donc jusqu'au bas de celle de droite, et les rangées
   de photos (`grid-auto-rows: 1fr`) se partagent la place restante. L'écart n'est plus
   approché, il est nul par construction — mesuré à 0 sur Fiche, Annonce et T. Produits,
   les trois onglets où la droite est la plus haute.
   ⚠️ La DROITE, elle, garde `align-self: start` : si elle s'étirait aussi, un onglet
   court (T. Vendeuses fait 174 px) deviendrait une grande boîte vide pour rien.
   Sur ces onglets-là c'est la gauche qui dépasse — deux rangées de photos ne peuvent
   pas se réduire à 174 px, et les écraser serait pire que le décalage.
   ⚠️ `aspect-ratio` saute ici : c'est la RANGÉE qui donne sa hauteur à la vignette
   maintenant. L'image garde `object-fit: cover` (déjà posé), donc elle se recadre au
   lieu de se déformer. */
/* ⚠️⚠️⚠️ L'ÉTIREMENT EST RETIRÉ — ET C'ÉTAIT MA PROPRE RÉPARATION DU 20/08.
   Amadou (22/08) : « quand j'appuie sur la plupart des boutons dans la fiche, la taille
   des photos change. La taille des photos ne doit pas changer, elles doivent tout le
   temps rester en version petite. »
   IL A RAISON, ET VOICI CE QUE J'AVAIS FAIT. Le 20/08 il demandait que les photos
   « arrivent pile à la taille de la partie droite ». Pour aligner les deux bas, j'avais
   étiré la colonne gauche sur la hauteur de la rangée (`align-self: stretch`), fait
   grandir la grille avec (`flex: 1 1 auto`), donné aux rangées un `1fr` et ANNULÉ la
   proportion 3/4 des vignettes (`aspect-ratio: auto; height: 100%`).
   Conséquence, invisible pour moi à l'époque : la hauteur de la colonne gauche est celle
   du panneau de DROITE. Changer d'onglet change donc la taille des photos. « Mesures » et
   « T. Vendeuses » sont longs, « Fiche » est court — les vignettes respiraient à chaque
   clic.
   ⚠️ CE QUE ÇA COÛTE, ET QU'IL FAUT SAVOIR : les deux colonnes ne finissent plus ensemble.
   Sur un onglet long, la gauche s'arrête plus haut que la droite. C'est le troc qu'Amadou
   choisit — une taille de photo STABLE contre un bas de page aligné — et il a raison :
   l'alignement se remarque une fois, la photo qui change de taille se remarque à chaque
   clic. */
.dress-detail-2col > .dress-detail-left { align-self: start; }
.dress-color-block > .dress-photos-grid { flex: 0 0 auto; grid-auto-rows: auto; align-content: start; }
.dress-color-block > .dress-photos-grid > .dress-photo { aspect-ratio: 3 / 4; height: auto; }

/* ── Bloc par coloris (empilés dans la colonne gauche) ── */
.dress-color-block {
  background: linear-gradient(158deg, var(--cok-bg) 0%, rgba(var(--th-voile),0.01) 60%);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-16);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
  box-shadow: 0 5px 18px -12px rgba(var(--th-ombre),0.55), inset 0 1px 0 rgba(var(--th-voile),0.04);
}
.dress-color-block-head { display: flex; align-items: center; gap: var(--e-10); }
.dress-color-block-swatch {
  width: 18px; height: 18px; border-radius: 50%;
  border: 1px solid rgba(var(--th-voile),0.25); flex-shrink: 0;
}
/* ⚠️ Amadou (01/09) : « le coloris blanc, l'écriture dépasse sur l'étiquette actif ».
   `flex: 1; min-width: 0` laissait le nom RÉTRÉCIR mais pas se couper : sans
   `text-overflow`, il débordait sous la pastille voisine. Et les étiquettes ne doivent
   jamais céder leur place — c'est le nom qui s'abrège, pas le statut qui disparaît. */
.dress-color-block-name {
  font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text);
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dress-color-block-active, .dress-color-block-epuise { flex: 0 0 auto; }
.dress-color-block-active {
  font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase; letter-spacing: var(--ls-ample);
  color: var(--violet-soft); background: var(--violet-tint);
  border: 1px solid rgba(var(--th-accent-rgb),0.35); border-radius: var(--r-pilule); padding: var(--e-2) var(--e-8);
}
.dress-color-views-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: var(--e-8);
}
.dress-color-view-cell { display: flex; flex-direction: column; gap: var(--e-4); position: relative; }
.dress-color-view-cell img {
  width: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: var(--r-sm);
  cursor: zoom-in; border: 1px solid var(--border); transition: border-color var(--t-moyen);
}
.dress-color-view-cell img:hover { border-color: var(--violet-mid); }
.dress-color-view-label { font-size: var(--t-micro); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Tuile « Ajouter » des galeries de la fiche modèle (ajout manuel de photos) */
.model-add-tile {
  aspect-ratio: 3/4; border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center; color: var(--text-2);
  cursor: pointer; transition: border-color var(--t-moyen), color var(--t-moyen);
}
.model-add-tile:hover { border-color: var(--violet-mid); color: var(--violet-light); }
/* Regroupement : Vérifier + Nouvelle robe collés, léger espace avant Visuels seulement */
#btn-new-dress { margin-top: calc(var(--e-4) * -1); }
#btn-skip-text { margin-top: var(--e-6); }
/* Badge de vérification (sur demande) sur chaque visuel mannequin généré */
.gen-verify-badge { position: absolute; top: 8px; right: 8px; z-index: 3; font-size: var(--t-micro); font-weight: var(--fw-gras);
  padding: var(--e-4) var(--e-8); border-radius: var(--r-pilule); backdrop-filter: blur(4px); border: 1px solid transparent; }
.gen-verify-badge.pending { background: rgba(var(--th-ombre),.45); color: var(--text); }
.gen-verify-badge.ok   { background: rgba(99,214,176,.9); color: #052e22; }
.gen-verify-badge.bad  { background: rgba(240,176,85,.92); color: #3a2603; cursor: help; }
.gen-verify-badge.err  { background: rgba(var(--th-ombre),.5); color: var(--text); cursor: help; }
/* Mini spinner du badge « Vérification… » */
.gvb-spin { display:inline-block; width:9px; height:9px; margin-right:var(--e-6); vertical-align:-1px; border-radius:50%;
  border:2px solid rgba(var(--th-voile),.35); border-top-color: var(--sur-accent); animation:gvbSpin .7s linear infinite; }
@keyframes gvbSpin { to { transform:rotate(360deg); } }
/* Vérif EN COURS : léger dim + balayage lumineux (façon amélioration qualité Atelier) */
.image-card.gen-verifying { overflow:hidden; }
.image-card.gen-verifying img { opacity:.72; transition:opacity var(--t-moyen); }
.image-card.gen-verifying::after {
  content:""; position:absolute; inset:0; z-index:2; pointer-events:none;
  background:linear-gradient(180deg, transparent 0%, rgba(var(--th-accent-rgb),.04) 42%, var(--tier-premium-glow) 50%, rgba(var(--th-accent-rgb),.04) 58%, transparent 100%);
  transform:translateY(-100%); animation:genVfScan 1.5s ease-in-out infinite; }
@keyframes genVfScan { 0% { transform:translateY(-100%); } 100% { transform:translateY(100%); } }
/* Résultats : liseré vert bref (conforme) / liseré ambre persistant (non conforme) */
.image-card.verify-bad { box-shadow:inset 0 0 0 2px rgba(240,176,85,.9); }
.image-card.verify-ok  { animation:genVfOk 1.4s ease-out forwards; }
@keyframes genVfOk { 0% { box-shadow:inset 0 0 0 2px rgba(99,214,176,.95); } 100% { box-shadow:inset 0 0 0 0 rgba(99,214,176,0); } }
/* Relance (↻) sur échec de vérif */
.gen-verify-retry { position:absolute; bottom:8px; right:8px; z-index:4; width:24px; height:24px; border-radius:50%;
  border:0; background:rgba(var(--th-ombre),.55); color:var(--text); cursor:pointer; display:flex; align-items:center; justify-content:center; }
.gen-verify-retry:hover { background:rgba(var(--th-accent-rgb),.85); color: var(--sur-accent); }
/* « Photos mannequin » fiche robe : une carte par modèle (avatar, n° compte, complétion, vues) */
.dress-mvbm-head { display: flex; align-items: center; justify-content: space-between; gap: var(--e-10); margin: var(--e-6) 0 var(--e-10); }
.dress-mvbm-count { font-size: var(--t-micro); color: var(--text-2); margin-left: var(--e-8); }
.dress-mvbm-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(186px, 1fr)); gap: var(--e-12); }
.dress-mvbm-card { border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-10); }
.dress-mvbm-card-head { display: flex; align-items: center; gap: var(--e-8); margin-bottom: var(--e-8); }
.dress-mvbm-av { width: 28px; height: 28px; border-radius: 50%; overflow: hidden; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; background: var(--tier-premium-bg); color: var(--violet-light); }
.dress-mvbm-av img { width: 100%; height: 100%; object-fit: cover; }
.dress-mvbm-badge { font-size: var(--t-micro); font-weight: var(--fw-gras); padding: var(--e-1) var(--e-6); border-radius: var(--r-pilule);
  background: var(--bg-elevated); color: var(--text-2); flex-shrink: 0; }
.dress-mvbm-cname { font-size: var(--t-meta); font-weight: var(--fw-moyen); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Pastille coloris (robes multi-coloris : les cartes agrègent TOUS les coloris) */
.dress-mvbm-color { font-size: var(--t-micro); font-weight: var(--fw-fort); padding: var(--e-1) var(--e-6) var(--e-1) var(--e-4); border-radius: var(--r-pilule);
  background: var(--bg-hover); color: var(--text-2); flex-shrink: 0;
  display: inline-flex; align-items: center; gap: var(--e-4); max-width: 72px; }
.dress-mvbm-color span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dress-mvbm-color-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  background: #888; border: 1px solid rgba(var(--th-voile),.25); }
.dress-mvbm-pill { margin-left: auto; font-size: var(--t-micro); font-weight: var(--fw-gras); padding: var(--e-2) var(--e-8); border-radius: var(--r-pilule);
  display: inline-flex; align-items: center; gap: var(--e-4); flex-shrink: 0; }
.dress-mvbm-pill.ok { background: rgba(99,214,176,.15); color: var(--green); }
.dress-mvbm-pill.warn { background: rgba(240,176,85,.16); color: var(--amber); }
.dress-mvbm-rowx { width: 18px; height: 18px; line-height: 16px; text-align: center; border: 0; border-radius: 50%;
  background: transparent; color: var(--text-2); cursor: pointer; font-size: var(--t-small); padding: 0; }
.dress-mvbm-rowx:hover { background: rgba(var(--th-danger-rgb),.15); color: var(--red); }
.dress-mvbm-grid { grid-template-columns: repeat(3, 1fr); gap: var(--e-6); }
.dress-mvbm-grid .dress-color-view-label { font-size: var(--t-micro); }
.dress-mvbm-addcard { border: 1px dashed var(--border-strong); border-radius: var(--r-lg); background: transparent;
  color: var(--text-2); cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-6); min-height: 120px; font-size: var(--t-meta); }
.dress-mvbm-addcard:hover { border-color: var(--violet-mid); color: var(--violet-light); }

/* ── L'Arbre — batchs programmés (plans, jours, journal) ── */
.tree-plan-form { display: flex; flex-direction: column; gap: var(--e-8); }
.tree-form-row { display: flex; align-items: center; gap: var(--e-8); }
.tree-form-row .batch-input { flex: 1; }
.tree-days-row { gap: var(--e-6); }
.tree-day-chip { width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border-strong);
  background: transparent; color: var(--text-2); font-size: var(--t-mini); font-weight: var(--fw-gras); cursor: pointer; }
.tree-day-chip.active { background: var(--cok-accent-bg,var(--tier-volume-bg)); border-color: var(--violet-mid); color: var(--violet-light); }
.tree-plans-list { display: flex; flex-direction: column; gap: var(--e-6); }
.tree-plan-row { display: flex; align-items: center; gap: var(--e-8); padding: var(--e-8) var(--e-10);
  border: 1px solid var(--border); border-radius: var(--r-md); }
.tree-plan-info { flex: 1; min-width: 0; font-size: var(--t-base); }
.tree-plan-meta { display: block; font-size: var(--t-micro); color: var(--text-2); margin-top: var(--e-2); }
.tree-plan-off { opacity: .55; }
.tree-journal { display: flex; flex-direction: column; gap: var(--e-4); max-height: 260px; overflow-y: auto; }
.tree-journal-line { font-size: var(--t-mini); color: var(--text); line-height: var(--lh-normal); }
/* Interrupteur maître de l'arbre (kill switch) */
.tree-master-card { border: 1px solid var(--border-strong); }
.tree-master-card.tree-master-on { border-color: var(--violet-mid); background: rgba(var(--th-accent-rgb),.07); }
.tree-master-row { display: flex; align-items: center; justify-content: space-between; gap: var(--e-14); }
.tree-master-title { font-size: var(--t-small); display: flex; align-items: center; gap: var(--e-8); }
.tree-master-dot { width: 10px; height: 10px; border-radius: 50%; background: #6b7280; flex-shrink: 0;
  box-shadow: 0 0 0 3px rgba(107,114,128,.2); }
.tree-master-dot.on { background: var(--green); box-shadow: 0 0 0 3px rgba(52,211,153,.25); }

/* ══════════ ESPACE BROUILLONS ══════════ */
/* ⚠️ La bulle de nav était définie DEUX FOIS, ici et plus bas. Mêmes valeurs, mais c'est
   la même faute que partout ailleurs : une information écrite à deux endroits finit par se
   contredire. Il n'en reste qu'une — chercher « Badge nav ». */
.nav-item .nav-ic { position: relative; display: inline-flex; align-items: center; flex: 0 0 auto; }
.drafts-tabs { display: flex; gap: var(--e-4); margin-bottom: var(--e-14); border-bottom: 1px solid var(--border); }
.drafts-tab { background: transparent; border: 0; color: var(--text-2); font-size: var(--t-small); font-weight: var(--fw-fort);
  padding: var(--e-8) var(--e-14); cursor: pointer; border-bottom: 2px solid transparent; display: inline-flex; align-items: center; gap: var(--e-6); }
.drafts-tab.active { color: var(--text); border-bottom-color: var(--violet-mid); }
.drafts-tab-count { font-size: var(--t-micro); background: rgba(var(--th-voile),.08); color: var(--text-2);
  border-radius: var(--r-pilule); padding: var(--e-1) var(--e-8); }
.drafts-bulkbar { display: flex; align-items: center; gap: var(--e-12); margin-bottom: var(--e-12); padding: var(--e-8) var(--e-12);
  border: 1px solid var(--border); border-radius: var(--r-md); flex-wrap: wrap; }
.drafts-bulk-count { font-size: var(--t-meta); color: var(--violet-light); }
.drafts-list { display: flex; flex-direction: column; gap: var(--e-8); }
.draft-card { display: flex; align-items: center; gap: var(--e-12); padding: var(--e-10) var(--e-12);
  border: 1px solid var(--border); border-radius: var(--r-lg); }
/* En-tête de groupe par compte dans les Brouillons */
.draft-group-header { display: flex; align-items: center; gap: var(--e-8); margin: var(--e-14) var(--e-2) var(--e-6);
  font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text-2); letter-spacing: var(--ls-leger); }
.draft-group-header:first-child { margin-top: var(--e-2); }
.draft-group-name { text-transform: none; }
.draft-group-count { min-width: 20px; height: 18px; padding: 0 var(--e-6); border-radius: var(--r-pilule);
  background: var(--violet, var(--violet)); color: var(--sur-accent); font-size: var(--t-mini); display: inline-flex;
  align-items: center; justify-content: center; }
.draft-cb { width: 16px; height: 16px; flex-shrink: 0; accent-color: var(--violet-mid); }
.draft-thumb { width: 46px; height: 60px; border-radius: var(--r-sm); overflow: hidden; flex-shrink: 0;
  background: rgba(var(--th-voile),.04); position: relative; }
.draft-thumb img { width: 100%; height: 100%; object-fit: cover; }
.draft-thumb-count { position: absolute; bottom: 2px; right: 2px; background: rgba(var(--th-ombre),.6); color: var(--sur-sombre);
  font-size: var(--t-micro); border-radius: var(--r-micro); padding: 0 var(--e-4); }
.draft-info { flex: 1; min-width: 0; }
.draft-title { font-size: var(--t-base); font-weight: var(--fw-moyen); color: var(--text); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.draft-meta { font-size: var(--t-micro); color: var(--text-2); margin-top: var(--e-4); }
.draft-src { background: var(--violet-tint); color: var(--violet-light); border-radius: var(--r-pilule); padding: var(--e-1) var(--e-6); font-weight: var(--fw-fort); }
.draft-status.ok { color: var(--green); } .draft-status.bad { color: var(--amber); }
.draft-status.sched { color: var(--violet-soft); font-weight: var(--fw-fort); }
.draft-actions { display: flex; align-items: center; gap: var(--e-6); flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.draft-edit-lbl { font-size: var(--t-meta); color: var(--text-2); font-weight: var(--fw-fort); margin-top: var(--e-4); }
.draft-edit-photos { display: flex; flex-wrap: wrap; gap: var(--e-6); }
.draft-edit-ph { position: relative; width: 52px; height: 68px; border-radius: var(--r-sm); overflow: hidden; }
.draft-edit-ph img { width: 100%; height: 100%; object-fit: cover; }
.draft-edit-ph button { position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; line-height: 16px;
  border: 0; border-radius: 50%; background: rgba(var(--th-ombre),.65); color: var(--sur-sombre); cursor: pointer; font-size: var(--t-base); padding: 0; }
/* ── Centre de contrôle : la pyramide (Gérant + Second) + les organes de l'usine ── */
.ctrl-grouplabel { font-size: var(--t-mini); font-weight: var(--fw-fort); letter-spacing: var(--ls-large); text-transform: uppercase;
  color: var(--text-3); margin: var(--e-22) var(--e-2) var(--e-10); }
.ctrl-grouplabel:first-child { margin-top: var(--e-4); }
.ctrl-pyramid { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: var(--e-14); }
.ctrl-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--e-14); }
.ctrl-card { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-16) var(--e-18);
  display: flex; flex-direction: column; gap: var(--e-10); min-width: 0; }
.ctrl-card--gerant { border-color: rgba(var(--th-accent-rgb),.35); }
.ctrl-card-head { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap; }
.ctrl-card-title { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.ctrl-chip { font-size: var(--t-micro); color: var(--text-2); background: var(--bg-input); border-radius: var(--r-pilule); padding: var(--e-4) var(--e-10); }
.ctrl-chip--draft { color: var(--violet-light); background: var(--violet-tint); }
.ctrl-chip--fort { color: var(--amber); background: rgba(251,191,36,.12); }
.ctrl-card-body { font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal); display: flex; flex-direction: column; gap: var(--e-8); }
.ctrl-date { font-size: var(--t-micro); color: var(--text-3); }
.ctrl-resume { margin: 0; color: var(--text); }
.ctrl-action { display: flex; gap: var(--e-10); align-items: flex-start; }
.ctrl-prio { flex-shrink: 0; width: 26px; height: 26px; border-radius: var(--r-sm); background: var(--violet-tint);
  color: var(--violet-light); font-size: var(--t-micro); font-weight: var(--fw-gras); display: flex; align-items: center; justify-content: center; }
.ctrl-action-txt { min-width: 0; }
.ctrl-action-t { color: var(--text); font-weight: var(--fw-moyen); }
.ctrl-action-d { font-size: var(--t-meta); }
.ctrl-risques { font-size: var(--t-mini); color: var(--amber); }
.ctrl-verdict { font-weight: var(--fw-fort); font-size: var(--t-base); }
.ctrl-verdict.ok { color: var(--green); } .ctrl-verdict.warn { color: var(--amber); } .ctrl-verdict.idle { color: var(--text-3); }
/* ⚠️ `bad` MANQUAIT : trois teintes existaient, aucune pour « c'est cassé ». Un flux à
   l'arrêt affiché en ambre se confond avec un flux en retard — et c'est exactement la
   nuance qui compte ici. */
.ctrl-verdict.bad { color: var(--red); }
/* La santé des flux : l'âge à droite en gros, le détail en dessous, en petit. */
.ctrl-flux-l > span:last-child { display: flex; flex-direction: column; align-items: flex-end; gap: var(--e-1); }
.ctrl-flux-e { font-weight: var(--fw-fort); }
.ctrl-flux-e.g { color: var(--green); } .ctrl-flux-e.w { color: var(--amber); } .ctrl-flux-e.r { color: var(--red); }
.ctrl-flux-l i { font-style: normal; font-size: var(--t-mini); color: var(--text-3); }
.ctrl-contest { border-left: 2px solid rgba(251,191,36,.5); padding-left: var(--e-10); }
.ctrl-contest b { color: var(--text); }
.ctrl-alt { color: var(--green); font-size: var(--t-meta); }
.ctrl-conseil { font-style: italic; color: var(--text); border-top: 1px solid var(--border); padding-top: var(--e-8); }
.ctrl-empty { color: var(--text-3); font-size: var(--t-meta); }
.ctrl-kv { display: flex; justify-content: space-between; gap: var(--e-10); }
.ctrl-kv span:first-child { color: var(--text-3); }
.ctrl-kv span:last-child { color: var(--text); text-align: right; }
.ctrl-kv--sub span:first-child { padding-left: var(--e-10); }
.ctrl-card--wide { grid-column: 1 / -1; }
.ctrl-lesson { display: flex; align-items: flex-start; gap: var(--e-10); padding: var(--e-8) 0; border-bottom: 1px solid var(--border); }
.ctrl-lesson:last-child { border-bottom: 0; }
.ctrl-lesson-badge { flex-shrink: 0; font-size: var(--t-micro); color: var(--text-3); background: var(--bg-input); border-radius: var(--r-pilule); padding: var(--e-4) var(--e-8); white-space: nowrap; }
.ctrl-lesson-badge.on { color: var(--green); background: rgba(52,211,153,.12); }
.ctrl-lesson-txt { flex: 1; min-width: 0; color: var(--text); font-size: var(--t-meta); line-height: var(--lh-normal); }
.ctrl-lesson-del { flex-shrink: 0; border: 0; background: transparent; color: var(--text-3); cursor: pointer; font-size: var(--t-small); padding: 0 var(--e-4); }
.ctrl-lesson-del:hover { color: var(--amber); }
@media (max-width: 900px) { .ctrl-pyramid { grid-template-columns: 1fr; } }

/* ── Brouillons v3 : vue MAÎTRE-DÉTAIL — rail des comptes (gauche) + annonces (droite) ──
   Remplit l'écran, garde toujours le fil des comptes ; empile sur petit écran. */
.drafts-split { display: flex; gap: var(--e-18); align-items: flex-start; }
.drafts-rail { width: 230px; flex-shrink: 0; background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--e-8); position: sticky; top: 8px; }
.drafts-rail-head { font-size: var(--t-micro); letter-spacing: var(--ls-ample); text-transform: uppercase; color: var(--text-3); margin: var(--e-6) var(--e-8) var(--e-8); }
.drafts-rail-item { display: flex; align-items: center; gap: var(--e-10); padding: var(--e-10) var(--e-10); border-radius: var(--r-md);
  cursor: pointer; border: 1px solid transparent; margin-bottom: var(--e-4); transition: background var(--t-bref), border-color var(--t-bref); }
.drafts-rail-item:hover { background: var(--bg-hover); }
.drafts-rail-item.active { background: var(--violet-tint); border-color: rgba(var(--th-accent-rgb),.3); }
.drafts-rail-name { flex: 1; min-width: 0; font-size: var(--t-base); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drafts-rail-count { background: var(--bg-input); color: var(--text-2); border-radius: var(--r-pilule); padding: var(--e-1) var(--e-8); font-size: var(--t-micro); flex-shrink: 0; }
.drafts-rail-flag { border-radius: var(--r-pilule); padding: var(--e-1) var(--e-8); font-size: var(--t-micro); font-weight: var(--fw-gras); flex-shrink: 0; }
.drafts-rail-flag.err   { color: var(--amber); background: rgba(251,191,36,.14); }
.drafts-rail-flag.sched { color: var(--violet-soft); background: var(--violet-tint); }
.drafts-detail { flex: 1; min-width: 0; }
.dpack-av { width: 26px; height: 26px; border-radius: 50%; background: var(--violet-tint); color: var(--violet-light);
  display: inline-flex; align-items: center; justify-content: center; font-size: var(--t-micro); font-weight: var(--fw-gras); flex-shrink: 0; }
@media (max-width: 760px) {
  .drafts-split { flex-direction: column; }
  .drafts-rail { width: 100%; position: static; display: flex; gap: var(--e-6); overflow-x: auto; padding: var(--e-8); }
  .drafts-rail-head { display: none; }
  .drafts-rail-item { flex-shrink: 0; margin-bottom: 0; }
  .drafts-rail-name { max-width: 100px; }
}

.dcard-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(186px, 1fr)); gap: var(--e-14); }
.dcard { background: var(--bg-panel); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden;
  cursor: pointer; transition: border-color var(--t-moyen), transform var(--t-moyen); display: flex; flex-direction: column; }
.dcard:hover { border-color: var(--violet); transform: translateY(-2px); }
.dcard-ph { position: relative; aspect-ratio: 3 / 4; background: var(--bg-input); }
.dcard-ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dcard-count { position: absolute; bottom: 6px; right: 6px; background: rgba(var(--th-ombre),.6); color: var(--sur-sombre);
  font-size: var(--t-micro); border-radius: var(--r-micro); padding: var(--e-1) var(--e-6); }
.dcard-cb { position: absolute; top: 6px; left: 6px; width: 26px; height: 26px; display: flex; align-items: center;
  justify-content: center; background: rgba(var(--th-ombre),.45); border-radius: var(--r-sm); cursor: pointer; }
.dcard-cb input { width: 14px; height: 14px; accent-color: var(--violet); cursor: pointer; }
.dcard-quick { position: absolute; top: 6px; right: 6px; display: flex; gap: var(--e-6); opacity: 0; transition: opacity var(--t-moyen); }
.dcard:hover .dcard-quick, .dcard:focus-within .dcard-quick { opacity: 1; }
.dcard-qbtn { width: 26px; height: 26px; border: 0; border-radius: var(--r-sm); background: rgba(var(--th-ombre),.55); color: var(--sur-sombre);
  cursor: pointer; display: flex; align-items: center; justify-content: center; }
.dcard-qbtn:hover { background: rgba(var(--th-accent-rgb),.85); }
.dcard-qbtn svg { width: 12px; height: 12px; }
.dcard-body { padding: var(--e-10) var(--e-12) var(--e-12); display: flex; flex-direction: column; gap: var(--e-6); }
.dcard-title { font-size: var(--t-base); color: var(--text); line-height: var(--lh-serre); display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.15em; }
.dcard-price { display: flex; align-items: center; justify-content: space-between; font-size: var(--t-base); color: var(--text); }
.dcard-status { display: inline-flex; align-items: center; gap: var(--e-6); font-size: var(--t-micro); color: var(--text-2); }
.dcard-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.dcard-status.ok    { color: var(--green); }
.dcard-status.bad   { color: var(--amber); }
.dcard-status.sched { color: var(--violet-soft); }
.dcard-status.idle  { color: var(--text-3); }
.dcard-status svg { width: 11px; height: 11px; }

.de-ghostbtn { background: transparent; border: 1px solid var(--border-mid); color: var(--text); font-size: var(--t-small);
  font-family: inherit; padding: var(--e-12) var(--e-20); border-radius: var(--r-lg); cursor: pointer; transition: border-color var(--t-moyen); }
.de-ghostbtn:hover { border-color: var(--violet); }
.de-foot { flex-wrap: wrap; }

@media (max-width: 640px) {
  .dpack-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
  .dcard-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}

/* ── Modale « Éditer le brouillon » (refonte épurée & aérée) ──
   Colonne unique, dividers subtils au lieu de boîtes, champs hauts, padding généreux :
   la hiérarchie se lit par l'espace négatif, pas par des cadres. */
.de-modal { width: min(880px, 95vw); max-height: 90vh; overflow: auto;
  background: var(--bg-panel-solid); border: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: 0 24px 60px rgba(var(--th-ombre),.5); }
.de-head { display: flex; align-items: center; justify-content: space-between; padding: 30px var(--e-40) var(--e-6); }
.de-head-title { font-size: var(--t-lead); font-weight: var(--fw-moyen); letter-spacing: var(--ls-serre); color: var(--text); }
.de-badge { font-size: var(--t-meta); color: var(--violet-light); background: var(--violet-tint); padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule); }
.de-xbtn { width: 36px; height: 36px; border-radius: var(--r-md); border: none; background: transparent;
  color: var(--text-2); cursor: pointer; font-size: var(--t-lead); display: flex; align-items: center; justify-content: center; }
.de-xbtn:hover { background: var(--bg-hover); color: var(--text); }
/* ── Menu déroulant SOMBRE réutilisable (.de-dd) — remplace les <select> natifs macOS,
   même look que le reste du site (cohérence demandée par Amadou). ── */
.de-dd { position: relative; }
.de-dd-trigger { width: 100%; box-sizing: border-box; display: flex; align-items: center; justify-content: space-between; gap: var(--e-8); font-size: var(--t-small);
  color: var(--text); font-family: inherit; cursor: pointer; transition: border-color var(--t-moyen); text-align: left }
.de-dd-trigger:hover { border-color: var(--border-strong); }
.de-dd-val { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⚠️ LE DÉFILEMENT VIT SUR LA LISTE, PAS SUR LE PANNEAU. Avec le champ de recherche à
   l'intérieur, un panneau qui défile emporte le champ hors de vue dès la première
   molette — on cherche alors à l'aveugle. Le panneau tient la hauteur, la liste glisse
   dessous. */
.de-dd-panel { position: absolute; z-index: 10; top: calc(100% + 6px); left: 0; right: 0; max-height: 320px;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-panel-solid); border: 1px solid var(--border-strong); border-radius: var(--r-lg); padding: var(--e-6);
  box-shadow: 0 16px 40px rgba(var(--th-ombre),.5); }
.de-dd-liste { overflow-y: auto; min-height: 0; }
/* Le champ de recherche reprend l'habillage des champs du site, en plus discret :
   il sert à filtrer, pas à saisir une donnée. */
.de-dd-q { flex: 0 0 auto; width: 100%; box-sizing: border-box; margin-bottom: var(--e-6);
  background: var(--bg-input); border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: var(--e-10) var(--e-12); font-size: var(--t-base); font-family: inherit; color: var(--text); outline: none;
  transition: border-color var(--t-moyen); }
.de-dd-q::placeholder { color: var(--text-3); }
.de-dd-q:focus { border-color: rgba(var(--th-accent-rgb),.5); }
.de-dd-rien { padding: var(--e-14) var(--e-12); font-size: var(--t-base); color: var(--text-3); text-align: center; }
.de-dd-opt { padding: var(--e-10) var(--e-12); border-radius: var(--r-sm); cursor: pointer; font-size: var(--t-base); color: var(--text); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.de-dd-opt:hover { background: var(--bg-hover); }
/* ══ UNE OPTION QUI PORTE SON CHEMIN ════════════════════════════════════════
   Amadou (07/09) : « l'affichage n'est pas adapté, on ne voit rien » — puis, sur ce que
   devient le chemin : « le chemin doit être discret ».
   ⚠️⚠️ LA COUPURE PART DE LA LIGNE, ET C'EST TOUT LE CORRECTIF. `.de-dd-opt` coupait au
   bout (`nowrap` + `ellipsis`) : sur un chemin entier, c'est justement le bout qui
   distingue. Mesuré sur le catalogue Vinted : 2 392 rayons sur 2 493 devenaient identiques
   à l'écran. La feuille seule fait 18 caractères en médiane — elle n'a plus rien à perdre.
   ⚠️ SEULES LES OPTIONS QUI PORTENT UN CHEMIN changent de forme : les trois autres listes
   montées sur ce déroulant gardent leur ligne unique, au caractère près. */
.de-dd-opt--voie {
  display: flex; flex-direction: column; gap: var(--e-1);
  white-space: normal; overflow: visible; text-overflow: clip;
  line-height: var(--lh-serre);
}
.de-dd-feuille { color: inherit; }
/* Discret : plus petit, plus pâle, et il ne prend jamais le pas sur la feuille. */
.de-dd-voie { font-size: var(--t-micro); color: var(--text-3); }
.de-dd-opt.sel .de-dd-voie { color: var(--violet-light); }
.de-dd-opt.sel { background: var(--violet-tint); color: var(--violet-light); }
/* Cases à cocher : même accent violet PARTOUT sur le site (cohérence). */
input[type="checkbox"], input[type="radio"] { accent-color: var(--violet); }
/* Deux colonnes : photos (gauche) + contenu écrit & couleur (droite). Enroule sur mobile. */
.de-body { padding: var(--e-20) 36px var(--e-4); display: flex; flex-wrap: wrap; gap: 30px; }
.de-col-photos { width: 220px; flex-shrink: 0; }
.de-col-content { flex: 1; min-width: 300px; display: flex; flex-direction: column; gap: var(--e-22); }
.de-block { margin-bottom: 30px; }
.de-divider { height: 1px; background: var(--bg-elevated); margin: 0 0 30px; }
.de-fhead { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--e-12); }
.de-flabel { font-size: var(--t-base); color: var(--text-2); font-weight: var(--fw-normal); }
.de-chip { font-size: var(--t-meta); font-variant-numeric: tabular-nums; }
.de-chip.ok   { color: var(--green); }
.de-chip.warn { color: var(--amber); }
.de-input { width: 100%; box-sizing: border-box; background: var(--bg-input); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--e-14) var(--e-18); font-size: var(--t-small); color: var(--text); font-family: inherit; outline: none;
  transition: border-color var(--t-moyen); }
.de-input:focus { border-color: rgba(var(--th-accent-rgb),.5); }
textarea.de-input { min-height: 150px; resize: vertical; line-height: var(--lh-aere); padding: var(--e-16) var(--e-18); }
.de-tags { display: flex; flex-wrap: wrap; gap: var(--e-8); margin-top: var(--e-12); align-items: center; }
.de-tag { font-size: var(--t-base); color: var(--violet-light); background: var(--violet-tint); padding: var(--e-6) var(--e-6) var(--e-6) var(--e-14);
  border-radius: var(--r-pilule); display: inline-flex; align-items: center; gap: var(--e-6); }
.de-tag button { border: 0; background: transparent; color: var(--violet-light); cursor: pointer; font-size: var(--t-small);
  line-height: var(--lh-un); padding: 0 var(--e-4); opacity: .7; }
.de-tag button:hover { opacity: 1; }
.de-tag-add { min-width: 120px; flex: 1; background: transparent; border: 1px dashed var(--border-mid);
  border-radius: var(--r-pilule); padding: var(--e-6) var(--e-14); font-size: var(--t-base); color: var(--text); font-family: inherit; outline: none; }
.de-tag-add:focus { border-color: rgba(var(--th-accent-rgb),.5); border-style: solid; }
/* Sélecteur 2 coloris — pastilles + popover dans la DA du site */
.de-colors { display: flex; flex-wrap: wrap; gap: var(--e-8); align-items: center; }
.de-color-chip { display: inline-flex; align-items: center; gap: var(--e-8); background: var(--bg-input);
  border: 1px solid var(--border-mid); border-radius: var(--r-pilule); padding: var(--e-6) var(--e-10) var(--e-6) var(--e-8); font-size: var(--t-base); color: var(--text); }
.de-color-chip .cdot { width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0; border: 1px solid rgba(var(--th-voile),.18); }
.de-color-chip button { border: 0; background: transparent; color: var(--text-3); cursor: pointer; font-size: var(--t-small); line-height: var(--lh-un); padding: 0 var(--e-2); }
.de-color-chip button:hover { color: var(--text); }
.de-color-add { display: inline-flex; align-items: center; gap: var(--e-6); background: transparent; border: 1px dashed var(--border-mid);
  border-radius: var(--r-pilule); padding: var(--e-8) var(--e-14); font-size: var(--t-base); color: var(--violet-light); cursor: pointer; font-family: inherit; }
.de-color-add:hover { border-color: var(--violet); }
.de-color-pop { position: relative; }
.de-color-grid { position: absolute; z-index: 5; top: calc(100% + 6px); left: 0; width: 300px; max-height: 240px; overflow: auto;
  background: var(--bg-panel-solid); border: 1px solid var(--border-strong); border-radius: var(--r-lg); padding: var(--e-8);
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-4); box-shadow: 0 16px 40px rgba(var(--th-ombre),.5); }
.de-color-grid-head { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between;
  font-size: var(--t-mini); color: var(--text-3); padding: var(--e-2) var(--e-4) var(--e-6); border-bottom: 1px solid var(--border); margin-bottom: var(--e-4); }
.de-color-close { border: 0; background: transparent; color: var(--text-2); cursor: pointer; font-size: var(--t-small); line-height: var(--lh-un);
  padding: var(--e-2) var(--e-6); border-radius: var(--r-sm); }
.de-color-close:hover { background: var(--bg-hover); color: var(--text); }
.de-color-opt { display: flex; align-items: center; gap: var(--e-10); padding: var(--e-8) var(--e-10); border-radius: var(--r-sm); cursor: pointer; font-size: var(--t-base); color: var(--text); }
.de-color-opt:hover { background: var(--bg-hover); }
.de-color-opt .cdot { width: 16px; height: 16px; border-radius: 50%; flex-shrink: 0; border: 1px solid rgba(var(--th-voile),.18); }
.de-row { display: flex; gap: var(--e-32); flex-wrap: wrap; }
.de-price { position: relative; width: 150px; }
.de-price .de-input { padding-right: 34px; }
.de-price-cur { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); color: var(--text-3); font-size: var(--t-small); pointer-events: none; }
.de-acct { display: flex; align-items: center; gap: var(--e-14); width: 100%; box-sizing: border-box; background: var(--bg-input);
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-10) var(--e-16); cursor: pointer; text-align: left; transition: border-color var(--t-moyen); }
.de-acct:hover { border-color: var(--border-strong); }
.de-acct-av { width: 40px; height: 40px; border-radius: 50%; background: var(--violet-tint); color: var(--violet-light);
  display: flex; align-items: center; justify-content: center; font-size: var(--t-small); font-weight: var(--fw-moyen); flex-shrink: 0; }
.de-acct-av--empty { background: var(--bg-elevated); color: var(--text-3); }
.de-acct-name { flex: 1; min-width: 0; font-size: var(--t-small); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.de-acct-name--empty { color: var(--text-3); }
.de-acct-chg { font-size: var(--t-base); color: var(--violet); flex-shrink: 0; }
/* Galerie photos agrandie : 1re photo en grand, le reste en grille 2 colonnes, + tuile d'ajout. */
.de-lphotos { display: flex; flex-wrap: wrap; gap: var(--e-12); }
.de-ph { position: relative; width: calc(50% - 6px); height: 132px; border-radius: var(--r-lg); overflow: hidden; border: 1px solid var(--border); }
.de-ph--main { width: 100%; height: 248px; }
.de-ph img { width: 100%; height: 100%; object-fit: cover; }
.de-ph button { position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; line-height: 22px;
  border: 0; border-radius: 50%; background: rgba(var(--th-ombre),.6); color: var(--sur-sombre); cursor: pointer; font-size: var(--t-small); padding: 0; }
.de-add { width: calc(50% - 6px); height: 132px; border-radius: var(--r-lg); background: transparent; border: 1px dashed rgba(var(--th-voile),.16);
  color: var(--text-3); font-size: var(--t-base); font-weight: var(--fw-normal); cursor: pointer; display: flex; align-items: center; justify-content: center; gap: var(--e-6); }
.de-add:hover { border-color: var(--violet); color: var(--violet-light); }
/* Sélecteur de couleur Vinted (pastille + menu déroulant) */
.de-color { display: flex; align-items: center; gap: var(--e-12); }
.de-color-dot { width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0; border: 1px solid rgba(var(--th-voile),.18); }
.de-selwrap { position: relative; flex: 1; }
.de-select { width: 100%; box-sizing: border-box; appearance: none; -webkit-appearance: none; background: var(--bg-input);
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-14) 34px var(--e-14) var(--e-16); font-size: var(--t-small); color: var(--text);
  font-family: inherit; outline: none; cursor: pointer; transition: border-color var(--t-moyen); }
.de-select:focus { border-color: rgba(var(--th-accent-rgb),.5); }
.de-selchev { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); color: var(--text-3); pointer-events: none; font-size: var(--t-mini); }
.de-foot { display: flex; align-items: center; justify-content: flex-end; gap: var(--e-14); padding: 34px var(--e-40); }
.de-cancel { background: transparent; border: none; color: var(--text-2); font-size: var(--t-small); font-family: inherit; padding: var(--e-12) var(--e-20); border-radius: var(--r-lg); cursor: pointer; }
.de-cancel:hover { color: var(--text); }
.de-save { background: var(--violet); border: none; color: var(--sur-accent); font-size: var(--t-small); font-weight: var(--fw-moyen); font-family: inherit; padding: var(--e-12) 26px; border-radius: var(--r-lg); cursor: pointer; }
.de-save:hover { background: var(--violet-hover); }

/* ── Sélecteur d'horaire de publication (raccourcis + jour + heure en pastilles) ── */
.ds-pills { display: flex; flex-wrap: wrap; gap: var(--e-8); }
.ds-days { overflow-x: auto; flex-wrap: nowrap; padding-bottom: var(--e-4); }
.ds-pill { padding: var(--e-8) var(--e-14); border-radius: var(--r-pilule); font-size: var(--t-base); cursor: pointer; white-space: nowrap;
  flex: 0 0 auto; background: transparent; border: 1px solid var(--border-mid); color: var(--text);
  font-family: inherit; transition: border-color var(--t-moyen), background var(--t-moyen); }
.ds-pill:not(.active):hover { border-color: var(--border-strong); }
.ds-pill.active { background: var(--violet-tint); border-color: var(--violet); color: var(--violet-light); }
.ds-summary { display: flex; align-items: center; gap: var(--e-10); background: var(--violet-tint);
  border: 1px solid var(--violet-tint-strong); border-radius: var(--r-lg); padding: var(--e-12) var(--e-14); font-size: var(--t-base); color: var(--text); }
.ds-summary.empty { background: var(--bg-input); border-color: var(--border); color: var(--text-3); }
.ds-summary svg { color: var(--violet-light); flex-shrink: 0; }
.ds-custom-btn { align-self: flex-start; background: transparent; border: none; color: var(--violet-light);
  font-size: var(--t-meta); cursor: pointer; padding: 0; text-decoration: underline; font-family: inherit; }
.batch-aside-btn { background: rgba(var(--th-accent-rgb),.12); }
.tree-journal-time { color: var(--text-2); font-size: var(--t-micro); margin-right: var(--e-4); font-variant-numeric: tabular-nums; }
.tree-autodraft { display: inline-flex; align-items: center; gap: var(--e-6); font-size: var(--t-meta); color: var(--text-2); cursor: pointer; }
.tree-autodraft input { accent-color: var(--violet-mid); }
/* Revue des résultats d'un batch serveur */
.tree-results { width: 100%; display: flex; flex-direction: column; gap: var(--e-6); margin-top: var(--e-8);
  border-top: 1px solid var(--border); padding-top: var(--e-8); }
.tree-result-item { display: flex; align-items: center; gap: var(--e-10); }
.tree-result-thumb { width: 44px; height: 56px; border-radius: var(--r-sm); overflow: hidden; flex-shrink: 0;
  background: rgba(var(--th-voile),.04); }
.tree-result-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* Dans la colonne (étroite) gauche : mannequin/produit empilés au lieu de côte à côte */
.dress-detail-left .dual-views-wrapper { flex-direction: column; gap: var(--e-20); }
.dress-detail-left .dual-views-wrapper .views-col { width: 100%; padding: 0; }
.dress-detail-left .dual-views-wrapper .views-col:first-child {
  border-right: none;
  border-bottom: 1px solid rgba(var(--th-voile),0.07);
  padding-bottom: var(--e-20);
}
.dress-detail-left .dual-views-wrapper .views-col:last-child { padding-left: 0; margin-top: 0; }
@media (max-width: 980px) {
  .dress-detail-2col { grid-template-columns: 1fr; gap: var(--e-22); }
  /* En une seule colonne, ni collage ni ascenseur interne : la fiche se lit d'un trait. */
  .dress-detail-left,
  .dress-detail-right { position: static; }
  .dress-rtabs { top: 0; }
}
/* ⚠️⚠️ DEUX COLONNES, DÉCLARÉES. C'était un `flex-wrap` de vignettes de 120 px : le
   nombre de colonnes dépendait donc de la largeur de la fenêtre — trois chez Amadou,
   quatre sur mon écran, pour le même écran. Une mise en page qui change avec la fenêtre
   ne peut pas être « alignée » : il faut la DIRE.
   ⚠️ Le plafond de 470 px n'est pas décoratif. Sans lui, deux colonnes dans une colonne
   de 613 px donnent des vignettes de 285 × 380, soit 790 px pour deux rangées — le bloc
   passerait bien SOUS la colonne de droite, l'inverse de ce qui est demandé. À 470, les
   deux rangées tiennent en ~610 px et la carte finit à hauteur de sa voisine. */
/* ⚠️ PLUS DE PLAFOND EN LARGEUR : la grille remplit la colonne. Le plafond de 380 px
   laissait 237 px de vide à droite des photos dans une carte de 617 — « l'espace est trop
   grand », disait Amadou, et il parlait de ce vide-là autant que de la hauteur. C'est la
   COLONNE qui est bornée maintenant, pas la grille dedans. */
.dress-photos-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e-10);
}
/* L'étiquette à gauche, le bouton d'ajout à droite, sur la même ligne.
   ⚠️ `nowrap` sur l'étiquette : sans lui « Photos de référence » se cassait en deux lignes
   dès que le bouton lui prenait de la place — la ligne qu'on venait de gagner en hauteur
   était reperdue aussitôt. */
.dress-ref-row { display: flex; align-items: center; justify-content: space-between; gap: var(--e-10); }
.dress-ref-row .dress-ref-label { white-space: nowrap; }
.dress-photo {
  width: auto;
  aspect-ratio: 3 / 4;
  height: auto;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--border);
  cursor: grab;
  position: relative;
}
.dress-photo:active { cursor: grabbing; }
.dress-photo.dragging { opacity: 0.4; }
/* Indicateur de drop : box-shadow inset (visible malgré overflow:hidden du parent) */
.dress-photo.drop-before { box-shadow: inset 4px 0 0 var(--cyan), 0 0 8px var(--cyan-glow); }
.dress-photo.drop-after  { box-shadow: inset -4px 0 0 var(--cyan), 0 0 8px var(--cyan-glow); }
.dress-photo img { width: 100%; height: 100%; object-fit: cover; cursor: grab; }
.dress-photo:active img { cursor: grabbing; }
/* ══ LA FOURCHETTE DE REVENTE ════════════════════════════════════════════════
   ⚠️⚠️ UNE SEULE VALEUR, UN SEUL CADRE. « Je reposte entre 58 et 88 » était rendu par
   deux encadrés, deux paires de flèches natives et un tiret flottant : cinq objets pour
   une fourchette. Les deux nombres partagent maintenant une bordure, un filet les relie,
   l'unité est écrite une fois au bout.
   ⚠️ Les flèches natives disparaissent (`appearance: textfield`) : personne ne monte un
   prix de 1 en 1, on le tape. Elles ne servaient qu'à encombrer et à rétrécir le champ.
   ⚠️ Le même cadre habille le prix d'achat (`--seul`) : deux champs voisins de natures
   différentes se lisaient comme deux composants étrangers l'un à l'autre. */
/* ⚠️ BORNÉ, ET C'EST LE POINT. Étiré sur toute sa colonne, le cadre faisait 509 px pour
   deux nombres à deux chiffres : « 58 » se retrouvait à un bout, « 88 » à l'autre, et le
   filet censé les relier ne reliait plus rien. Un champ de prix n'a pas besoin de la
   largeur d'un titre. 210 px laissent la place à cinq chiffres de chaque côté. */
.dress-tranche {
  display: flex; align-items: center; gap: var(--e-8);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); padding: 0 var(--e-12); height: 38px;
  max-width: 210px;
  transition: border-color var(--t-moyen);
}
.dress-tranche--seul { max-width: 150px; }
.dress-tranche:focus-within { border-color: var(--violet); }
/* ⚠️⚠️ LA SPÉCIFICITÉ, PAS L'ORDRE. Premier jet : `.dress-tranche input`, soit
   exactement le même poids que `.dress-field input` — qui est écrit 600 lignes PLUS BAS
   et gagnait donc l'égalité. Résultat mesuré : le cadre unique était bien dans le DOM,
   et l'écran montrait toujours deux boîtes à flèches. On passe par le parent
   (`.dress-field .dress-tranche input`) pour ne plus dépendre de qui est écrit en
   dernier — un départage par l'ordre se casse au premier déplacement de bloc. */
.dress-field .dress-tranche input,
.dress-tranche input {
  flex: 1 1 0; min-width: 0; width: auto;
  background: none; border: 0; padding: 0; height: 100%;
  color: var(--text); font: inherit; font-size: var(--t-small);
  font-variant-numeric: tabular-nums; box-shadow: none;
}
.dress-field .dress-tranche input:focus,
.dress-tranche input:focus { outline: none; border: 0; box-shadow: none; }
/* Les flèches natives, dans les deux dialectes de navigateur. */
.dress-field .dress-tranche input[type=number],
.dress-tranche input[type=number] { -moz-appearance: textfield; appearance: textfield; }
.dress-field .dress-tranche input[type=number]::-webkit-outer-spin-button,
.dress-field .dress-tranche input[type=number]::-webkit-inner-spin-button,
.dress-tranche input[type=number]::-webkit-outer-spin-button,
.dress-tranche input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* Le second nombre se cale à droite : l'œil compare deux colonnes, pas deux mots. */
.dress-field .dress-tranche input + .dress-tranche-filet + input { text-align: right; }
.dress-tranche-filet { flex: 0 0 14px; height: 1px; background: var(--border-strong); }
.dress-tranche-unite { flex: 0 0 auto; font-size: var(--t-meta); color: var(--text-3); }
.dress-field .dress-tranche--seul input { text-align: left; }

/* ══ LA LIGNE DES PRIX ET DES ÉTIQUETTES VINTED ══════════════════════════════
   ⚠️⚠️ « Il ne doit pas y avoir d'espaces inégaux. » Un SEUL jeton d'écart à l'intérieur
   des groupes (--e-12), tous les champs à la même hauteur (38 px), toutes les étiquettes
   au même gabarit. Le seul écart variable est celui qui SÉPARE les deux groupes — c'est
   lui qui pousse Catégorie et Coloris à droite, et c'est voulu.
   ⚠️ `align-items: flex-end` : les étiquettes n'ont pas toutes la même hauteur (« Coloris
   (2 max) » est plus large), donc c'est le BAS des champs qui doit s'aligner, pas le haut.
   Sans ça, un champ dont l'étiquette passe sur deux lignes descend tout seul. */
.dress-prix-ligne { display: flex; align-items: flex-end; gap: var(--e-12); flex-wrap: wrap; }
.dress-prix-groupe { display: flex; align-items: flex-end; gap: var(--e-12); min-width: 0; }
/* Poussé à droite, et autorisé à se serrer : c'est la Catégorie qui cède, voir plus bas. */
.dress-prix-groupe--fin { margin-left: auto; flex: 0 1 auto; }
.dress-prix-ligne .dress-field { margin: 0; }
/* La catégorie est le SEUL champ au contenu long et variable : c'est donc lui qui se
   rétrécit et coupe proprement quand la place manque. Les prix, eux, ont une largeur
   connue — les laisser fondre n'aurait aucun sens. */
.dress-prix-ligne .dress-field:has(> select) { min-width: 0; }
/* ⚠️ MESURÉ : le menu de la catégorie faisait 43 px quand les deux cadres de prix en
   faisaient 38. Cinq pixels d'écart sur une ligne de quatre champs, c'est précisément
   le « pas aligné » qu'Amadou signale — et ça ne se voit pas en relisant le code, seul
   le contrôle des hauteurs le montre. Une seule hauteur pour toute la ligne. */
.dress-prix-ligne select { max-width: 100%; height: 38px; box-sizing: border-box; }

/* ══ LES DEUX CORLORIS DANS UNE SEULE CASE ═══════════════════════════════════
   Même dessin que la fourchette de revente : un encadré, deux contrôles qui le
   partagent, un filet vertical entre eux. */
.dress-coloris {
  display: flex; align-items: center; gap: var(--e-6);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); padding: 0 var(--e-10); height: 38px;
  transition: border-color var(--t-moyen);
}
.dress-coloris:focus-within { border-color: var(--violet); }
/* ⚠️ La spécificité passe par le parent : `.dress-gamme-select` est déclarée bien plus
   bas dans le fichier et gagnerait une égalité — le piège déjà payé sur la fourchette. */
.dress-field .dress-coloris select {
  background: none; border: 0; padding: 0 var(--e-2) 0 0; height: 100%;
  color: var(--text); font: inherit; font-size: var(--t-meta);
  min-width: 0; width: auto; max-width: 88px; cursor: pointer;
}
.dress-field .dress-coloris select:focus { outline: none; }
.dress-coloris-filet { flex: 0 0 1px; width: 1px; height: 16px; background: var(--border-strong); margin: 0 var(--e-4); }
.dress-coloris-pt {
  flex: 0 0 11px; width: 11px; height: 11px; border-radius: 50%;
  border: 1px solid rgba(var(--th-trait), .35);
}
/* Vide : en pointillés. Une place libre ne se déguise pas en couleur choisie. */
.dress-coloris-pt.vide { border-style: dashed; background: transparent; }
.dress-coloris-max { font-weight: var(--fw-moyen); color: var(--violet-light); letter-spacing: 0; }

/* ══ SES VOITURES, EN CARTES ═════════════════════════════════════════════════
   Un ruban de cartes plutôt qu'une liste : à dix comptes on CHOISIT, et choisir se
   fait à l'horizontale. La carte ouverte est marquée ; les autres s'ouvrent au clic. */
.model-voitures {
  display: flex; flex-wrap: wrap; gap: var(--e-8); margin-bottom: var(--e-4);
}
.model-voiture {
  display: flex; align-items: center; gap: var(--e-8);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--e-8) var(--e-12);
  font: inherit; font-size: var(--t-meta); color: var(--text-2); cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
}
.model-voiture:hover { border-color: var(--border-strong); color: var(--text); }
/* La voiture ouverte : le liseré violet dit « tu es ici », comme un onglet actif. */
.model-voiture.on {
  border-color: var(--violet); color: var(--text); background: var(--violet-tint);
  cursor: default;
}
.model-voiture-pt { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.model-voiture-nom { font-weight: var(--fw-moyen); }
.model-voiture-etat { color: var(--text-3); font-size: var(--t-micro); }
.model-voiture--plus { border-style: dashed; color: var(--text-3); }
.model-voiture--plus:hover { border-color: var(--violet-mid); color: var(--violet-light); }
/* Plus de place : le bouton reste LISIBLE mais ne prétend plus être cliquable. */
.model-voiture--plus.morte { opacity: .55; cursor: default; border-style: dashed; }
.model-voiture--plus.morte:hover { border-color: var(--border); color: var(--text-3); }

/* ══ LES PLACES D'UNE MODÈLE ═════════════════════════════════════════════════
   Amadou (21/08) : « une étiquette qui dira trois comptes sur dix occupés ».
   Une jauge en petits traits plutôt qu'une barre : à dix places, on COMPTE les sièges
   d'un coup d'œil, ce qu'une barre continue ne permet pas. */
.lib-vend-places {
  display: flex; align-items: center; gap: var(--e-6);
  margin-top: var(--e-4); font-size: var(--t-micro); color: var(--text-2);
}
.lib-vend-places-jauge { display: inline-flex; gap: var(--e-2); }
.lib-vend-places-jauge i {
  width: 4px; height: 9px; border-radius: 1px;
  background: rgba(var(--th-trait), .30);
}
.lib-vend-places-jauge i.prise { background: var(--violet-soft); }
/* Complète : le vert d'« en ligne » serait faux — elle n'est pas active, elle est
   PLEINE. L'ambre dit « ne compte plus dessus », c'est ce qu'on veut savoir. */
.lib-vend-places.pleine { color: var(--amber); }
.lib-vend-places.pleine .lib-vend-places-jauge i.prise { background: var(--amber); }
.lib-vend-note { margin-top: var(--e-2); font-size: var(--t-micro); color: var(--amber);
  letter-spacing: .12em; }

.dress-shein-input-row { display: flex; gap: var(--e-8); align-items: center; }
.dress-shein-input-row input { flex: 1; }
.dress-sku-row { display: flex; gap: var(--e-6); align-items: center; }
.dress-sku-row input { flex: 1; }
.sku-copy-btn {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--r-sm);
  background: rgba(var(--th-voile),0.07); border: 1px solid rgba(var(--th-voile),0.12);
  color: #aaa; cursor: pointer; transition: var(--transi);
}
.sku-copy-btn:hover { background: rgba(var(--th-voile),0.13); color: var(--text); }
.sku-copy-btn.copied { background: rgba(74,222,128,0.15); border-color: var(--safe-text); color: var(--safe-text); }
.btn-shein-open {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-2); text-decoration: none; transition: border-color var(--t-moyen), color var(--t-moyen);
}
.btn-shein-open:hover { border-color: var(--violet-mid); color: var(--violet-light); }
/* ⚠️ « +N » est POSÉ SUR la quatrième photo, pas à sa place : on garde quatre images
   visibles ET l'information qu'il y en a d'autres. Le voile vient de `--th-ombre`, jamais
   de `--th-voile` : sur les cinq thèmes clairs, un voile blanc n'assombrit rien et le
   chiffre deviendrait illisible.
   ⚠️⚠️ ET LE TEXTE EST EN `--sur-sombre`, PAS EN `--sur-plein`. Premier jet : `--sur-plein`,
   qui vaut #111111 — du noir sur un voile noir. Mesuré : contraste 1,22 sur DIX thèmes,
   c'est-à-dire un chiffre parfaitement invisible. `--sur-accent` tombait à 1,10 sur
   velours, `--text` à 1,01 sur les clairs : AUCUN jeton de texte n'est clair partout,
   parce qu'aucun n'est fait pour ça.
   ⭐ Celui qui l'est existait déjà, et le site s'en sert six fois pour exactement ce
   besoin — un compteur posé sur une photo (`.dcard-count`, `.draft-thumb-count`).
   Emprunté, pas inventé. Mesuré sur les 16 thèmes et trois robes types : 6,92 dans le
   PIRE cas (robe très claire), 20,01 dans le meilleur. */
.dress-photo-plus {
  position: absolute; inset: 0; border: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-2); background: rgba(var(--th-ombre), .62); color: var(--sur-sombre);
  font: inherit; transition: background var(--t-bref);
}
.dress-photo-plus:hover { background: rgba(var(--th-ombre), .72); }
.dress-photo-plus span  { font-size: var(--t-lead); font-weight: var(--fw-gras); }
.dress-photo-plus small { font-size: var(--t-mini); opacity: .85; }

/* « Ajouter » est une BARRE sous la grille, plus une case dedans : à deux colonnes elle
   mangeait un quart des photos visibles pour un bouton. */
.dress-photo-add {
  width: auto;
  height: auto;
  flex: none;
  padding: var(--e-4) var(--e-10);
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--border-strong);
  display: flex; flex-direction: row; align-items: center; justify-content: center; gap: var(--e-8);
  align-items: center; justify-content: center;
  gap: var(--e-8);
  cursor: pointer;
  color: var(--text-3);
  font-size: var(--t-meta);
  background: var(--surface);
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
.dress-photo-add:hover { border-color: var(--violet-mid); background: var(--surface-2); }

/* ── Vues produit dans la fiche robe — 3 slots fixes ─── */
.dress-product-views-section { margin-top: var(--e-20); }
.lib-dual-views { margin-top: var(--e-16); align-items: flex-start; }

/* Colonne mannequin élargie pour accueillir plusieurs cartes modèle */
.mann-col-wide { flex: 2; }

.mann-models-container {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--e-12);
  align-items: flex-start;
  overflow-x: auto;
  padding-bottom: var(--e-6);
  scroll-snap-type: x mandatory;
}
.mann-model-card { scroll-snap-align: start; flex-shrink: 0; }

.mann-model-card {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--e-10);
}

.mann-model-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-6);
}

.mann-model-card-name {
  font-size: var(--t-meta);
  font-weight: var(--fw-gras);
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mann-model-card-rm {
  flex-shrink: 0;
  width: 18px; height: 18px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: var(--t-small);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  line-height: var(--lh-un);
}
.mann-model-card-rm:hover { background: rgba(var(--th-danger-rgb),0.15); color: var(--red); }

.mann-add-model-btn {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  padding: var(--e-8) var(--e-14);
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-3);
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  cursor: pointer;
  white-space: nowrap;
  transition: var(--transi);
  flex-shrink: 0;
  align-self: flex-start;
  margin-top: var(--e-10);
}
.mann-add-model-btn:hover { border-color: var(--violet-mid); color: var(--violet-mid); }
.dress-ref-photos-section { margin-top: var(--e-20); }
.dress-ref-label {
  font-size: var(--t-meta); font-weight: var(--fw-gras); letter-spacing: var(--ls-caps);
  text-transform: uppercase; color: var(--text-3);
  margin-bottom: var(--e-10);
}
.dress-pack-model-sub {
  font-size: var(--t-mini); font-weight: var(--fw-fort); color: var(--text-2);
  margin: var(--e-8) 0 var(--e-4);
}
.dress-prodprice-row {
  display: flex; flex-direction: column; gap: var(--e-6); margin-top: var(--e-12);
}
.dress-prodprice-row label {
  font-size: var(--t-meta); font-weight: var(--fw-moyen); color: var(--text-2);
}
.dress-prodprice-row input {
  width: 120px; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--e-8) var(--e-10); color: var(--text);
  font-size: var(--t-base); outline: none;
}
.dress-prodprice-row input:focus { border-color: var(--violet-mid); }
.dress-prodviews-grid {
  display: flex;
  gap: var(--e-10);
  flex-wrap: wrap;
}
.dress-prodview-slot {
  width: 85px;
  height: 113px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1.5px dashed var(--border-strong);
  position: relative;
  cursor: pointer;
  transition: border-color var(--t-moyen), background var(--t-moyen);
  background: var(--surface);
}
.dress-prodview-slot:hover { border-color: var(--violet-mid); background: var(--surface-2); }
.dress-prodview-slot.filled { border-style: solid; border-color: var(--border); }
.dress-prodview-slot.drag-over { border-color: var(--violet); background: rgba(var(--th-accent-rgb),0.08); }
.dress-prodview-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dress-prodview-placeholder {
  width: 100%; height: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--e-8);
  color: var(--text-3);
  font-size: var(--t-mini);
  font-weight: var(--fw-fort);
  text-align: center;
  padding: var(--e-8);
}
.dress-prodview-label {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  padding: var(--e-4) var(--e-6);
  background: rgba(var(--th-panneau-rgb),0.75);
  font-size: var(--t-micro);
  color: var(--text-2);
  text-align: center;
}
.dress-prodview-action {
  position: absolute;
  top: 5px;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: none;
  background: rgba(var(--th-panneau-rgb),0.8);
  color: var(--text-2);
  font-size: var(--t-base);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-moyen), background var(--t-moyen);
  z-index: 2;
}
.dress-prodview-slot.filled:hover .dress-prodview-action { opacity: 1; }
.dress-prodview-action:hover { background: rgba(var(--th-accent-rgb),0.7) !important; }
.dress-prodview-slot--add {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  cursor: pointer;
  border-style: dashed;
}
.dress-prodview-slot--add:hover { color: var(--violet-mid); }

.dress-prodview-add-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-6); aspect-ratio: 3/4;
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--r-md);
  background: none;
  color: var(--text-3); font-size: var(--t-mini); cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen);
}
.dress-prodview-add-btn:hover { border-color: var(--violet); color: var(--violet-soft); }

/* ── Section Annonce dans la fiche robe biblio ──────────── */
.dress-annonce-section {
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
  margin-top: var(--e-28);
  padding-top: var(--e-24);
  border-top: 1px solid var(--border);
}
.dress-section-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.dress-section-toggle:hover { opacity: .8; }
.dress-section-chevron { color: var(--text-3); transition: transform var(--t-moyen); flex-shrink: 0; }
/* ⚠️ `.dress-annonce-gen-btn` retirée avec son bouton (05/09) : une classe que plus
   personne ne pose se relit en croyant qu'elle sert encore. */
/* ⚠️⚠️ TROIS ESPACEMENTS SE CUMULAIENT POUR UN SEUL ÉCART. Amadou (21/08) : « entre
   Annonce et Titre il y a trop d'espace ». Ce n'était pas un réglage trop généreux, c'était
   un EMPILEMENT : la marge basse du titre (14), l'écart de la section (14) et la marge
   haute de ce corps (10) se suivaient, plus le rembourrage du premier champ (8). Chacun
   était raisonnable tout seul ; les quatre bout à bout font un trou.
   L'écart de la section suffit — ce corps ne rajoute plus le sien. */
.dress-annonce-body { display: flex; flex-direction: column; gap: var(--e-12); }
.dress-prix-vente-row { display: flex; align-items: center; gap: var(--e-10); }
.dress-prix-vente-sep { color: var(--text-3); font-size: var(--t-small); font-weight: var(--fw-moyen); }
.dress-prix-vente-btn-wrap {
  display: flex; flex-direction: column; gap: var(--e-2);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); padding: var(--e-8) var(--e-12); min-width: 86px;
  position: relative; transition: border-color var(--t-moyen); cursor: text;
}
.dress-prix-vente-btn-wrap:focus-within { border-color: var(--violet); }
.dress-prix-vente-btn-lbl {
  font-size: var(--t-micro); font-weight: var(--fw-gras); letter-spacing: var(--ls-caps);
  color: var(--text-3); text-transform: uppercase;
}
.dress-prix-vente-btn-inp {
  background: none; border: none; outline: none;
  color: var(--text); font-size: var(--t-small); font-weight: var(--fw-fort);
  font-family: inherit; width: 100%; padding: 0; padding-right: var(--e-14);
}
.dress-prix-vente-btn-inp::placeholder { color: var(--text-3); font-weight: var(--fw-normal); font-size: var(--t-base); }
.dress-prix-vente-euro {
  position: absolute; right: 9px; bottom: 8px;
  font-size: var(--t-meta); color: var(--text-3); pointer-events: none;
}
.dress-annonce-field {
  display: flex;
  flex-direction: column;
  gap: var(--e-6);
}
/* Collapsible variant */
.dress-annonce-field--collapsible {
  gap: 0;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-2);
}
/* ⚠️⚠️ L'APERÇU ÉTAIT SUR LA MÊME LIGNE QUE LE LABEL, tronqué à 55 caractères et en
   gris secondaire. Amadou (15/08) : « elles disparaissent, c'est transparent, il faut
   appuyer pour que ça apparaisse ». Le texte ÉTAIT là — il était simplement illisible.
   Il descend donc sous le label, sur deux lignes, en couleur de texte pleine : on lit
   ce qui a été généré sans rien ouvrir, et le chevron ne sert plus qu'à corriger. */
.dress-annonce-field-header {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas: "lab chev" "apercu apercu";
  align-items: center;
  gap: var(--e-4) var(--e-8);
  padding: var(--e-8) var(--e-10);
  cursor: pointer;
  user-select: none;
  background: var(--surface-0);
  transition: background var(--t-bref);
}
.dress-annonce-field-header .dress-annonce-label   { grid-area: lab; }
.dress-annonce-field-header .dress-annonce-preview { grid-area: apercu; }
.dress-annonce-field-header .dress-annonce-chevron { grid-area: chev; }
/* Champ ouvert : l'extrait ferait doublon avec le texte complet juste en dessous. */
.dress-annonce-field--ouvert .dress-annonce-preview { display: none; }
.dress-annonce-field-header:hover { background: var(--surface-2); }
.dress-annonce-field-body {
  padding: 0 var(--e-10) var(--e-10);
  background: var(--surface-2);
}
.dress-annonce-field-body.hidden { display: none; }
.dress-annonce-preview {
  font-size: var(--t-base);
  color: var(--text);
  line-height: var(--lh-serre);
  /* Deux lignes pour la description : c'est ce qui la rend lisible d'un coup d'oeil.
     Le titre, lui, tient sur une ligne — c'est un titre. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  min-width: 0;
}
.dress-annonce-preview--titre { -webkit-line-clamp: 1; }
.dress-annonce-preview--empty { color: var(--text-3); font-style: italic; }
.dress-annonce-chevron {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--text-3);
  display: flex;
  align-items: center;
  flex-shrink: 0;
  transition: transform var(--t-moyen);
}
.dress-annonce-chevron.open { transform: rotate(180deg); }
.dress-annonce-field--collapsible .dress-annonce-input,
.dress-annonce-field--collapsible .dress-annonce-textarea {
  border: none;
  border-radius: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  padding-left: var(--e-10);
  padding-right: var(--e-10);
}
.dress-annonce-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
  flex-shrink: 0;
}
.dress-annonce-input {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-1);
  font-size: var(--t-small);
  padding: var(--e-10) var(--e-12);
  outline: none;
  transition: border-color var(--t-moyen);
}
.dress-annonce-input:focus { border-color: var(--violet-mid); }
.dress-annonce-textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-1);
  font-size: var(--t-base);
  line-height: var(--lh-aere);
  padding: var(--e-10) var(--e-12);
  outline: none;
  resize: vertical;
  transition: border-color var(--t-moyen);
  font-family: inherit;
  box-sizing: border-box;
}
.dress-annonce-textarea:focus { border-color: var(--violet-mid); }
.dress-annonce-prix-row {
  display: flex;
  gap: var(--e-10);
}
.dress-annonce-prix-card {
  flex: 1;
  padding: var(--e-12) var(--e-14);
  border-radius: var(--r-md);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
}
.dress-annonce-prix-val {
  font-size: var(--t-lead);
  font-weight: var(--fw-gras);
  color: var(--text-1);
  letter-spacing: var(--ls-serre);
}
.dress-annonce-prix-inp {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text-1);
  font-size: var(--t-lead);
  font-weight: var(--fw-gras);
  width: 100%;
  padding: var(--e-4) 0;
  outline: none;
  letter-spacing: var(--ls-serre);
  -moz-appearance: textfield;
}
.dress-annonce-prix-inp::-webkit-inner-spin-button,
.dress-annonce-prix-inp::-webkit-outer-spin-button { -webkit-appearance: none; }
.dress-annonce-prix-inp:focus { border-bottom-color: var(--violet-mid); }
.dress-annonce-prix-inp::placeholder { color: var(--text-3); font-weight: var(--fw-normal); font-size: var(--t-small); }
.dress-annonce-prix-hint {
  font-size: var(--t-mini);
  color: var(--text-3);
}
.dress-annonce-copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  color: var(--text-3);
  transition: color var(--t-moyen);
}
.dress-annonce-copy-btn:hover { color: var(--violet-light); }

.dress-fields {
  display: flex;
  flex-direction: column;
  gap: var(--e-22);
}
.dress-fields-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e-18);
  align-items: end;
}

/* ══ LE PANNEAU MESURES : LES PIÈCES ET LES CASES ATTENDUES ════════════════════
   Amadou (31/08) : « il faut que ça soit universel pour tout le site, il ne faut pas
   qu'un coup ça change. » Le panneau dessine une liste ; ces trois règles sont tout ce
   qu'il ajoute au champ existant.
   ⚠️ AUCUNE VALEUR BRUTE — tout vient des jetons (voir CLAUDE.md, LA BIBLIOTHÈQUE). */

/* Le titre d'une pièce. N'apparaît QUE si le produit en a plusieurs : un ensemble deux
   pièces a « Le haut » et « Le bas » ; une robe n'a aucun titre. */
.dress-mesures-piece {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--violet-soft);
  margin: var(--e-20) 0 var(--e-10);
}
.dress-mesures-piece:first-child { margin-top: 0; }

/* Une mesure que la niche ATTEND et que personne n'a remplie. Elle est nommée et vide :
   elle dit ce qui manque, elle n'invente rien. */
.dress-field--attendue input {
  border-style: dashed;
  background: transparent;
}
.dress-field--attendue label { color: var(--text-3); }
.dress-field--attendue input::placeholder { color: var(--text-3); }

/* Un nom que le vocabulaire ne reconnaît pas (« Cote 3 »). On le garde tel quel plutôt
   que de lui inventer un nom — mais on le signale, pour qu'il se corrige. */
/* Une mesure LUE SUR UNE PHOTO. Amadou (01/09) : « il doit juste y avoir une mention,
   trouve l'endroit ». La voici : sur la carte, pas dans un bloc à part.
   ⚠️ ELLE SE LIT SANS CRIER : c'est une mesure comme les autres, simplement pas saisie à
   la main. Le liseré doré suffit à la distinguer ; l'étiquette dit pourquoi. */
.dress-field--lue input {
  border-color: rgba(var(--th-accent-rgb), .38);
}
.dress-field--lue label::after {
  content: " · lue sur la photo";
  color: var(--violet-soft);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-zero);
  text-transform: none;
}
.dress-field--inconnu label::after {
  content: " ?";
  color: var(--amber);
  font-weight: var(--fw-gras);
}

/* ── Fiche vendeuse : les trois onglets ───────────────────────────────────────
   Son physique / Sa personnalité / Sa voiture. Évite la colonne unique où l'on
   descendait de « poids » à « mot de passe » sans transition. */
.model-tabs {
  display: flex; gap: var(--e-4); flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  padding-bottom: var(--e-10); margin: var(--e-2) 0 var(--e-18);
}
.model-tab {
  border: 0; background: transparent; color: var(--text-2);
  font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-moyen);
  padding: var(--e-8) var(--e-16); border-radius: var(--r-md); cursor: pointer; white-space: nowrap;
  transition: background var(--t-bref), color var(--t-bref);
}
.model-tab:not(.on):hover { background: var(--bg-hover); color: var(--text); }
/* Fond violet TRANSLUCIDE + texte clair : --violet-soft est une couleur de texte,
   la poser en fond rendrait l'onglet actif illisible (déjà corrigé sur le Sourcing). */
.model-tab.on { background: var(--tier-premium-bg); color: var(--violet-light); }
/* ⚠️⚠️ `--surface-1` N'A JAMAIS EXISTÉ — six règles la demandaient. Un `var()` sur une
   variable non déclarée n'est PAS une erreur : la déclaration est simplement JETÉE, en
   silence. Les six fonds concernés étaient donc transparents, dont l'input « Style
   personnalisé… » qui vient d'arriver au milieu du volet « Son physique », translucide
   entre deux champs opaques. Elles lisent `--surface-2`, la surface réellement définie.
   C'est le même piège que les 174 `color: var(--sur-accent)` du 13/08. */
.model-pane { display: flex; flex-direction: column; gap: var(--e-18); }

/* ⚠️ `.model-pane--dense` a été retiré : plus aucun volet ne le portait, et une règle
   qui ne s'applique à rien laisse croire qu'un écran est resserré quelque part. Les
   trois volets partagent maintenant le MÊME rythme — c'est ce qu'Amadou appelait
   « le même alignement que Sa voiture ». */
.model-pane[hidden] { display: none; }
.dress-field label {
  display: block;
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--e-10);
}
.dress-field input {
  width: 100%;
  box-sizing: border-box;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--t-small);
  padding: var(--e-12) var(--e-14);
  font-family: inherit;
  transition: border-color var(--t-moyen);
}
.dress-field input:focus { outline: none; border-color: var(--violet); }
.dress-field select {
  width: 100%;
  box-sizing: border-box;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--t-small);
  padding: var(--e-12) var(--e-14);
  font-family: inherit;
  transition: border-color var(--t-moyen);
  appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: var(--e-32);
}
.dress-field select:focus { outline: none; border-color: var(--violet); }
.dress-field textarea {
  width: 100%;
  box-sizing: border-box;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--t-small);
  padding: var(--e-12) var(--e-14);
  font-family: inherit;
  transition: border-color var(--t-moyen);
  resize: vertical;
  min-height: 60px;
}
.dress-field textarea:focus { outline: none; border-color: var(--violet); }
.dress-field--full { grid-column: 1/-1; }

/* ── Menu déroulant maison (charte sombre) — remplace les <select> natifs ── */
.velbo-dd { position: relative; display: block; }
.velbo-dd--compact { display: inline-flex; flex: 0 0 auto; }
.velbo-dd-trigger {
  display: inline-flex; align-items: center; gap: var(--e-8);
  box-sizing: border-box;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--t-small); font-family: inherit;
  padding: var(--e-12) var(--e-12) var(--e-12) var(--e-14);
  cursor: pointer; white-space: nowrap;
  transition: border-color var(--t-moyen);
}
.velbo-dd:not(.velbo-dd--compact) .velbo-dd-trigger { width: 100%; justify-content: space-between; }
.velbo-dd.is-open .velbo-dd-trigger { border-color: var(--violet); }
.velbo-dd-label--empty { color: var(--text-3); }
.velbo-dd-chev { display: inline-flex; color: var(--text-3); transition: transform var(--t-moyen); }
.velbo-dd.is-open .velbo-dd-chev { transform: rotate(180deg); }
.velbo-dd-menu {
  position: absolute; top: calc(100% + 6px); left: 0;
  min-width: 100%; z-index: 60;
  background: var(--bg-card-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: 0 18px 44px rgba(var(--th-ombre),0.55);
  padding: var(--e-6); max-height: 280px; overflow-y: auto;
  display: none;
}
.velbo-dd.is-open .velbo-dd-menu { display: block; }
.velbo-dd-opt {
  display: flex; align-items: center; gap: var(--e-4);
  padding: var(--e-10) var(--e-12); border-radius: var(--radius-xs);
  color: var(--text-2); font-size: var(--t-small); white-space: nowrap;
  cursor: pointer; transition: background var(--t-bref), color var(--t-bref);
}
.velbo-dd-opt-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.velbo-dd-opt:hover { background: var(--surface-2); color: var(--text); }
.velbo-dd-opt.is-selected { background: var(--violet-tint); color: var(--violet-soft); }
.velbo-dd-del {
  flex-shrink: 0; width: 18px; height: 18px; border-radius: var(--r-micro);
  border: none; background: transparent; color: var(--text-3);
  font-size: var(--t-small); line-height: var(--lh-un); cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
}
.velbo-dd-opt:hover .velbo-dd-del { opacity: 1; }
.velbo-dd-del:hover { color: var(--red); background: rgba(248,113,113,.15); }
.velbo-dd-star {
  flex-shrink: 0; background: none; border: none; cursor: pointer;
  font-size: var(--t-base); line-height: var(--lh-un); padding: 0; width: 16px;
  color: var(--text-3); transition: color var(--t-bref);
}
.velbo-dd-star:hover { color: var(--amber); }
.velbo-dd-star.active { color: var(--amber); }
.velbo-dd-sep { height: 1px; background: var(--border); margin: var(--e-4) var(--e-10); }
.velbo-dd-addbox {
  display: flex; gap: var(--e-6); padding: var(--e-8) var(--e-4) var(--e-2);
  border-top: 1px solid var(--border); margin-top: var(--e-4);
}
.velbo-dd-addinp {
  flex: 1; min-width: 0; box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-xs); color: var(--text);
  font-size: var(--t-base); padding: var(--e-8) var(--e-10); font-family: inherit;
}
.velbo-dd-addinp:focus { outline: none; border-color: var(--violet); }
.velbo-dd-addbtn {
  flex: 0 0 auto; width: 32px; border: none; cursor: pointer;
  background: var(--violet); color: var(--sur-accent); border-radius: var(--radius-xs);
  font-size: var(--t-body); font-weight: var(--fw-gras); line-height: var(--lh-un);
}
.velbo-dd-addbtn:hover { background: var(--violet-hover); }
/* Bulle déroulante rétractable (ellipsis) — laisse la place au champ + bouton copier */
.velbo-dd--shrink { flex: 0 1 auto; min-width: 0; max-width: 46%; }
.velbo-dd--shrink .velbo-dd-trigger { min-width: 0; overflow: hidden; }
.velbo-dd--shrink .velbo-dd-label { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* Bouton « copier » dans un champ modèle (même gabarit que le bouton génération) */
.model-field-copy-btn {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex-shrink: 0;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); color: var(--text-2); cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
}
.model-field-copy-btn:hover { border-color: var(--violet); color: var(--violet-soft); }
.model-field-copy-btn.copied { border-color: var(--green); color: var(--green); background: rgba(52,211,153,0.12); }

/* ── IDs Vinted liés (panneau robe) ── */

/* ── Multi-sélection chips ── */
.detail-multi-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
  margin-top: var(--e-4);
}
.detail-multi-chip {
  padding: var(--e-4) var(--e-12);
  border-radius: var(--r-pilule);
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  transition: var(--transi);
}
.detail-multi-chip:hover { border-color: var(--border-mid); color: var(--text); }
.detail-multi-chip.active {
  background: rgba(var(--th-accent-rgb),.15);
  border-color: var(--violet-mid);
  color: var(--violet-light);
}
.dress-save-row {
  display: flex;
  justify-content: flex-end;
  gap: var(--e-10);
}

/* ── Upload Section — Aurora ─────────────────────────── */
.upload-cols,
.upload-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e-14);
}

.upload-zone {
  background:
    radial-gradient(120% 80% at 100% 0%, rgba(var(--th-voile),0.04), transparent 55%),
    linear-gradient(158deg, rgba(var(--th-voile),0.04) 0%, rgba(var(--th-voile),0.012) 55%);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-22) var(--e-24);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow: 0 8px 26px -16px rgba(var(--th-ombre),0.6), inset 0 1px 0 var(--bg-hover);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
  transition: border-color var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
.upload-zone:hover { border-color: var(--border-strong); }

/* Bouton "Choisir une robe / une modèle" — violet-tint */
.upload-pick,
.btn-pick-pack {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-8);
  width: 100%;
  height: 38px;
  padding: 0 var(--e-18);
  border-radius: var(--r-md);
  border: none;
  background: var(--violet-tint);
  color: var(--violet-soft);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose);
}
.upload-pick:hover,
.btn-pick-pack:hover {
  background: var(--violet-tint-strong);
}

/* Séparateur "ou importer" */
.upload-or,
.zone-separator {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  font-size: var(--t-meta);
  color: var(--text-3);
}
.upload-or::before, .upload-or::after,
.zone-separator::before, .zone-separator::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* Dropzone (replace les anciens .drop-area + .drop-inner) */
.dropzone,
.drop-area {
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--e-22) var(--e-16);
  min-height: 0;
  text-align: center;
  font-size: var(--t-small);
  color: var(--text-3);
  background: rgba(var(--th-voile),0.015);
  cursor: pointer;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose);
  display: block;
  position: relative;
}
.dropzone:hover,
.drop-area:hover {
  border-color: var(--violet-glow);
  background: var(--violet-tint);
}
.dropzone.dragover,
.drop-area.dragover {
  border-color: var(--violet-light);
  border-style: solid;
  background: var(--violet-tint-strong);
}
.dropzone-link,
.dropzone .link-btn,
.drop-area .link-btn {
  color: var(--violet-soft);
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 2px;
  cursor: pointer;
  transition: text-decoration-color var(--d-fast) var(--c-pose);
}
.dropzone:hover .dropzone-link,
.dropzone:hover .link-btn,
.drop-area:hover .link-btn { text-decoration-color: var(--violet-soft); }

/* Anciens enfants de .drop-area (drop-inner, drop-icon, drop-title, drop-sub)
   — neutralisés ; le markup design n'utilise plus que .dropzone avec contenu inline. */
.drop-inner { padding: 0; gap: var(--e-4); display: contents; }
.drop-inner--compact { padding: 0; gap: 0; }
.drop-icon, .drop-title { display: none; }
.drop-sub { font-size: var(--t-small); color: var(--text-3); line-height: var(--lh-normal); }

/* Grille de previews — 4 colonnes carrées 3:4 */
.preview-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--e-8);
}

/* Dans une zone d'import, les photos passent EN HAUT et prennent toute la place :
   elles s'agrandissent avec la fenêtre au lieu de rester à quatre par ligne. */
/* ⚠️⚠️ UNE SEULE RANGÉE, QUI DÉFILE SUR LE CÔTÉ — ET C'EST OBLIGATOIRE.
   Sur un portable (≈ 820 px de haut utile), le réglage dispose d'environ 300 px pour
   une zone d'import. Une rangée de vignettes en coûte 254 : il en reste 47. DEUX
   rangées en coûtent 375 : impossible, quoi qu'on rogne ailleurs. Tant que la grille
   pouvait passer à la ligne, il suffisait d'une 6ᵉ photo pour que tout l'écran reparte
   vers le bas et qu'il faille descendre pour importer (constaté deux fois le 02/08).
   La bande garde donc la MÊME hauteur avec 3 photos comme avec 30 ; au-delà de ce qui
   tient à l'écran, on fait glisser la bande horizontalement. */
.upload-zone .preview-grid {
  display: flex;
  align-items: flex-start;
  gap: var(--e-8);
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: var(--e-2);      /* respire au-dessus de la barre de défilement */
  scrollbar-width: thin;
  /* ⚠️⚠️⚠️ `scrollbar-width` DÉBRANCHE L'HABILLAGE DU SITE. Depuis Chrome 121, dès qu'un
     élément déclare `scrollbar-width` ou `scrollbar-color`, le navigateur IGNORE ses
     `::-webkit-scrollbar` — donc la règle globale du fichier (`*::-webkit-scrollbar`,
     pouce en `--bg-hover`) ne s'applique plus, et la barre repart au gris clair du
     système. Amadou (01/09), sur la bande des photos produit : « la barre de slide doit
     être dans la DA du site » — les mots exacts du 26/08 sur le Studio, réparé là-bas,
     pas ici. On redit donc la même chose par la propriété standard. */
  scrollbar-color: var(--bg-hover) transparent;
  scroll-snap-type: x proximity;
}
.upload-zone .preview-thumb {
  flex: 0 0 88px;           /* largeur fixe : c'est elle qui fixe la hauteur (ratio 3/4) */
  scroll-snap-align: start;
}
/* La vignette est le seul poste de dépense réglable en hauteur : sur une fenêtre
   courte on la rétrécit, plutôt que de renvoyer le bouton « Générer » hors de l'écran.
   Sur une fenêtre haute, elle reste grande. */
@media (max-height: 800px) {
  .upload-zone .preview-thumb { flex-basis: 78px; }
}
@media (max-height: 720px) {
  .upload-zone .preview-thumb { flex-basis: 68px; }
}
.upload-zone .preview-grid:empty { display: none; }

/* Sous les photos : « choisir » et « glisser » sur une seule ligne discrète.
   ⚠️ PAS de `margin-top: auto` ici. Collé en bas d'une zone étirée à la hauteur de
   sa voisine, il creusait un vide de 250 px entre les photos et les boutons dès que
   l'une des deux colonnes passait sur deux rangées. La ligne suit les photos. */
.upload-actions {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: var(--e-10);
  align-items: stretch;
}
.upload-actions .dropzone {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-6);
  min-height: 38px;
  padding: 0 var(--e-14);
}
@media (max-width: 520px) {
  .upload-actions { grid-template-columns: minmax(0, 1fr); }
}
.preview-thumb {
  position: relative;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-3);
  display: flex;
  align-items: center;
  justify-content: center;
}
.preview-thumb img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* ⚠️⚠️ LE CLIC QUI AGRANDIT EXISTAIT DÉJÀ — un écouteur global ouvre le zoom sur toute
   `.preview-thumb`. Mais RIEN ne le disait : le curseur restait une flèche, et l'ancienne
   étiquette couvrait le tiers bas en avalant le clic. Amadou (07/09) : « quand j'appuie sur
   une des vues pour agrandir… » — son attente était juste, l'écran ne la tenait pas. */
#preview-templates .preview-thumb,
#preview-dress .preview-thumb { cursor: zoom-in; }
/* ⚠️⚠️ LA CROIX ÉTAIT INVISIBLE TANT QU'ON NE SURVOLAIT PAS, et large de 22 px sur une
   vignette de 88. Amadou : « elle n'est vraiment pas agréable d'usage ».
   ⚠️ ELLE SE VOIT TOUJOURS, mais discrètement : une croix qui n'apparaît qu'au survol est
   introuvable au doigt, et sur cet écran il n'y a pas d'autre moyen de retirer une photo. */
#preview-templates .remove-btn,
#preview-dress .remove-btn {
  opacity: 1;
  width: var(--e-24); height: var(--e-24);
  border-radius: var(--r-pilule);
  background: rgba(var(--th-ombre),0.72);
  /* ⚠️ MÊME RAISON QUE L'ÉTIQUETTE : la croix est sur la photo, pas sur le panneau. */
  color: var(--sur-sombre);
}
#preview-templates .remove-btn:hover,
#preview-dress .remove-btn:hover {
  background: rgba(var(--th-ombre),0.92);
  color: var(--sur-sombre);
}
.preview-thumb-add {
  border-style: dashed;
  cursor: pointer;
  color: var(--text-3);
}
.preview-thumb-add:hover {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: var(--tier-premium-glow);
}
.thumb-placeholder {
  width: 100%; height: 100%;
  background:
    linear-gradient(135deg, rgba(var(--th-voile),0.04) 0%, rgba(var(--th-voile),0.01) 100%),
    radial-gradient(80% 60% at 50% 30%, rgba(var(--th-accent-rgb),0.08), transparent 70%);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
}
/* ⚠️⚠️⚠️ CETTE RÈGLE ÉTAIT MORTE, ET ELLE AVAIT L'AIR JUSTE. Elle demandait 18 px ;
   `.btn-icon, .remove-btn, … { min-width: 32px; min-height: 32px }` — ajoutée bien plus
   bas pour empêcher les icônes d'être écrasées — l'emporte parce qu'un `min-` ne se
   laisse pas réduire par un `width`. Mesuré à l'écran : bouton 32 × 32 sur une vignette
   de 88 px, soit plus d'un TIERS de la photo, avec une croix de 14 px dedans.
   Amadou (01/09) : « le système de croix… c'est vraiment moche, mais vraiment moche ».
   ⚠️ On garde `.remove-btn` : c'est lui qui apporte la croix unique du site et le rouge
   au survol. On ne redéclare que la TAILLE, et en `min-` pour être entendu. */
.preview-thumb .remove-btn,
.preview-thumb-remove {
  position: absolute;
  top: var(--e-4); right: var(--e-4);
  width: 22px; height: 22px;
  min-width: 22px; min-height: 22px;
  border-radius: 50%;
  background: rgba(var(--th-panneau-rgb),0.9);
  border: none;
  color: var(--text-2);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: opacity var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose),
              background var(--d-fast) var(--c-pose);
  z-index: 3;
}
/* La croix suit son bouton : 12 px dans 22, cinq de marge de chaque côté. */
.preview-thumb .remove-btn .velbo-x,
.preview-thumb-remove .velbo-x {
  width: 12px; height: 12px;
  -webkit-mask-size: 12px 12px;
          mask-size: 12px 12px;
}
.preview-thumb:hover .remove-btn,
.preview-thumb:hover .preview-thumb-remove { opacity: 1; }
.preview-thumb .remove-btn:hover,
.preview-thumb-remove:hover { color: var(--text); }

/* Template label badge */
/* ══ LE NOM D'UNE VUE — DISCRET (07/09) ════════════════════════════════════
   Amadou : « c'est trop flashy, ça ne sert à rien… ça fait cheap. »
   ⚠️⚠️⚠️ CE QUI CRIAIT, RELEVÉ À L'ÉCRAN : graisse 700, MAJUSCULES, interlettrage 0,6 px,
   et un filet CYAN ÉCRIT EN DUR — `rgba(103,232,249,0.2)`, la seule couleur de ce coin
   d'écran qui n'appartienne à AUCUN des dix-sept thèmes. Le reste de la vignette est
   violet ; ce filet était le seul à hurler.
   ⚠️⚠️ ET LA BOÎTE MANGEAIT LE TIERS DE L'IMAGE. Sur 88 px de haut, un nom comme
   « Médaillon central et trame » prenait trois lignes — et il couvrait le clic qui
   agrandit la photo. Une ligne, coupée par trois points : Amadou n'a pas besoin du nom
   exact, il l'a au survol.
   ⚠️ PLUS AUCUNE ILLUMINATION AU SURVOL : « je ne vois pas pourquoi il s'illuminerait, je
   ne vois pas l'intérêt ». Le curseur suffit à dire que c'est cliquable. */
.template-label-btn {
  position: absolute;
  bottom: 0; left: 0; right: 0;
  /* Un dégradé qui monte du bas, pas une boîte posée dessus. */
  background: linear-gradient(to top, rgba(var(--th-ombre),0.88), rgba(var(--th-ombre),0));
  padding: var(--e-16) var(--e-6) var(--e-6);
  text-align: left;
  font-size: var(--t-micro);
  font-weight: var(--fw-normal);
  /* ⚠️⚠️⚠️ `--sur-sombre`, PAS `--text`. Ce texte est posé sur une plaque sombre AU-DESSUS
     D'UNE PHOTO : sur les six thèmes clairs (dune, medina, hanami, colza, cyclades,
     nimbe), `--text` est SOMBRE — du sombre sur du sombre, illisible. `--sur-sombre` est
     le jeton du projet pour exactement ce cas. Relevé par `verifier-contraste.py`. */
  color: var(--sur-sombre);
  cursor: pointer;
  letter-spacing: var(--ls-zero);
  border: 0;
  /* ⚠️ UNE LIGNE, ET TROIS POINTS. « Quand il y a trop de texte, mes trois petits
     points » — le nom entier reste accessible au survol (`title`). */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  z-index: 2;
}
/* ⚠️⚠️⚠️ LE SURVOL N'ILLUMINE PLUS RIEN. Amadou (07/09) : « je ne vois pas pourquoi il
   s'illuminerait, je ne vois pas l'intérêt… ça fait cheap. » Il s'allumait en violet plein
   avec un filet clair — sur une vignette de 88 px, c'était un flash.
   ⚠️ ON NE MET RIEN À LA PLACE : le curseur dit déjà que c'est cliquable, et le nom entier
   arrive dans l'infobulle. Un état de survol qui n'apprend rien est du bruit. */

/* Label picker */
.label-picker {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-card-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: var(--e-8);
  z-index: 50;
  box-shadow: 0 12px 32px rgba(var(--th-ombre),0.6);
  /* ⚠️ FONDU, PLUS DE SAUT D'ÉCHELLE. C'est ce qu'Amadou appelait « un petit pop » : le
     panneau grandissait de 94 % à 100 % à chaque clic. Il apparaît, il ne bondit pas. */
  /* ⚠️ `velbo-entree-fondu` EXISTE, `velbo-fondu` NON — je l'avais écrit de mémoire, et une
     animation au nom inconnu ne joue RIEN, en silence. Même piège que `--red-tint` ce
     matin : on n'invente pas un nom, on emprunte celui qui est déclaré. */
  animation: velbo-entree-fondu var(--t-moyen) var(--c-pose);
  white-space: nowrap;
}
.label-picker-inner {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
  max-width: 200px;
}
@keyframes popIn {
  from { opacity: 0; transform: translateX(-50%) scale(0.94) translateY(4px); }
  to   { opacity: 1; transform: translateX(-50%) scale(1) translateY(0); }
}
.label-picker button {
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
  white-space: nowrap;
}
.label-picker button:hover { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }
/* ⚠️⚠️ LE CYAN ÉTAIT ÉCRIT EN DUR, et c'était la SEULE couleur de ce coin d'écran à
   n'appartenir à aucun des dix-sept thèmes. On prend le violet du site, qui les suit tous.
   ⚠️ `--violet-tint` EST DÉJÀ LA TEINTE DE SÉLECTION du projet (`.de-dd-opt.sel`,
   `.ry-ligne.sel`) : on l'emprunte plutôt que d'en fabriquer une. */
.label-picker button.active { background: var(--violet-tint); border-color: var(--violet-mid); color: var(--violet-light); font-weight: var(--fw-fort); }

/* Pick pack button */
.btn-pick-pack {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-22);
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--violet-mid);
  background: rgba(var(--th-accent-rgb),0.1);
  color: var(--violet-light);
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: background var(--t-moyen), border-color var(--t-moyen), transform var(--t-moyen);
}
.btn-pick-pack:hover {
  background: var(--violet-tint-strong);
}
.drop-sub-secondary {
  margin-top: var(--e-10);
  font-size: var(--t-meta);
  color: var(--text-3);
}

/* ── Options Section ─────────────────────────────────── */
.options-card {
  padding: var(--e-28) var(--e-28) var(--e-24);
}

/* ── Nouvelle robe toggle ────────────────────────────── */
.btn-new-dress {
  display: flex;
  align-items: center;
  gap: var(--e-12);
  width: 100%;
  padding: var(--e-12) var(--e-14);
  margin-bottom: var(--e-14);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile),0.025);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
  text-align: left;
}
.btn-new-dress:hover { background: var(--bg-sidebar); }
.btn-new-dress.active {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
  box-shadow: none;
}

.new-dress-track {
  flex-shrink: 0;
  width: 30px;
  height: 18px;
  border-radius: var(--r-pilule);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  position: relative;
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
  order: 2;
}
.btn-new-dress.active .new-dress-track {
  background: var(--violet);
  border-color: transparent;
  box-shadow: 0 0 12px var(--violet-glow);
}
.new-dress-thumb {
  position: absolute;
  top: 1px; left: 1px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--text-2);
  box-shadow: none;
  transition: left var(--d-base) var(--c-pose), background var(--d-fast) var(--c-pose);
}
.btn-new-dress.active .new-dress-thumb { left: 13px; background: #fff; }

.new-dress-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
  order: 1;
  min-width: 0;
}
.new-dress-title {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
}
.new-dress-title svg { color: var(--text-3); flex-shrink: 0; }
.btn-new-dress.active .new-dress-title { color: var(--violet-soft); }
.btn-new-dress.active .new-dress-title svg { color: var(--violet-soft); }
.new-dress-sub {
  font-size: var(--t-meta);
  font-weight: var(--fw-normal);
  color: var(--text-3);
  line-height: var(--lh-serre);
}

/* ── Skip mannequin option ───────────────────────────── */
.skip-mannequin-row {
  margin: calc(var(--e-6) * -1) 0 var(--e-14);
  padding: 0 var(--e-4);
}
.skip-mannequin-row.hidden { display: none; }

/* Bouton toggle "Visuels seulement" */
/* ── Ligne des deux toggles de mode ─────────────────── */
.mode-toggles-row {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  margin-bottom: var(--e-14);
}
.mode-toggles-row .btn-mode-toggle {
  width: 100%;
}

/* Bouton toggle de mode (Visuels seulement / Texte & prix seulement) */
.btn-mode-toggle {
  display: flex;
  align-items: center;
  gap: var(--e-12);
  padding: var(--e-12) var(--e-14);
  border-radius: var(--r-lg);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile),0.025);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
  text-align: left;
}
.btn-mode-toggle:hover { background: var(--bg-sidebar); }
.btn-mode-toggle.active {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
  box-shadow: none;
}

.mode-toggle-track {
  flex-shrink: 0;
  width: 30px;
  height: 18px;
  border-radius: var(--r-pilule);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  position: relative;
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
  order: 2;
}
.btn-mode-toggle.active .mode-toggle-track {
  background: var(--violet);
  border-color: transparent;
  box-shadow: 0 0 12px var(--violet-glow);
}
.mode-toggle-thumb {
  position: absolute;
  top: 1px; left: 1px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--text-2);
  box-shadow: none;
  transition: left var(--d-base) var(--c-pose), background var(--d-fast) var(--c-pose);
}
.btn-mode-toggle.active .mode-toggle-thumb { left: 13px; background: #fff; }

.mode-toggle-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
  min-width: 0;
}
.mode-toggle-label { order: 1; }
.mode-toggle-title {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mode-toggle-title svg { color: var(--text-3); flex-shrink: 0; }
.btn-mode-toggle.active .mode-toggle-title { color: var(--violet-soft); }
.btn-mode-toggle.active .mode-toggle-title svg { color: var(--violet-soft); }
.mode-toggle-sub {
  font-size: var(--t-meta);
  font-weight: var(--fw-normal);
  color: var(--text-3);
  margin-top: var(--e-2);
  line-height: var(--lh-serre);
}

/* Alias pour la compatibilité avec les anciens ids */
#btn-skip-text, #btn-text-only { }

/* Bouton dl sur les thumbs du générateur */
/* ⚠️ LE BOUTON « TÉLÉCHARGER » DE LA VIGNETTE A ÉTÉ RETIRÉ. Amadou (01/09) :
   « enlève-moi les boutons pour télécharger l'image, ça doit être quand je fais un clic
   droit que ça va me proposer ». La vignette EST une <img> : le menu du navigateur offre
   déjà « Enregistrer l'image sous… », et rien n'intercepte le clic droit. Deux pastilles
   sur une vignette de 88 px, c'était une de trop. */
/* Bouton dl sur les photos de la biblio */
.dress-photo-dl {
  position: absolute;
  bottom: 4px;
  left: 4px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(var(--th-panneau-rgb),0.75);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity var(--t-moyen);
  color: var(--text);
  z-index: 3;
}
.dress-photo:hover .dress-photo-dl { opacity: 1; }

/* Bouton supprimer une photo de référence (était sans CSS → invisible) */
.dress-photo-rm {
  position: absolute; top: 4px; right: 4px;
  width: 22px; height: 22px; border-radius: 50%;
  background: rgba(var(--th-panneau-rgb),0.78); border: none; color: var(--text);
  font-size: var(--t-small); line-height: var(--lh-un); cursor: pointer; z-index: 3;
  display: flex; align-items: center; justify-content: center;
  opacity: 0.7; transition: opacity var(--t-moyen), background var(--t-moyen);
}
.dress-photo:hover .dress-photo-rm { opacity: 1; }
.dress-photo-rm:hover { background: var(--red); }

/* Bouton supprimer une vue générée (mannequin / produit) */
.dress-color-view-rm {
  position: absolute; top: 5px; right: 5px;
  width: 22px; height: 22px; border-radius: 50%;
  background: rgba(var(--th-panneau-rgb),0.78); border: none; color: var(--text);
  font-size: var(--t-small); line-height: var(--lh-un); cursor: pointer; z-index: 3;
  display: flex; align-items: center; justify-content: center;
  opacity: 0.7; transition: opacity var(--t-moyen), background var(--t-moyen);
}
.dress-color-view-cell:hover .dress-color-view-rm { opacity: 1; }
.dress-color-view-rm:hover { background: var(--red); }
.skip-mannequin-label {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  cursor: pointer;
  font-size: var(--t-base);
  color: var(--text-2);
  user-select: none;
}
.skip-mannequin-label input { display: none; }
.skip-mannequin-box {
  flex-shrink: 0;
  width: 15px; height: 15px;
  border-radius: var(--r-micro);
  border: 1.5px solid rgba(var(--th-voile),0.2);
  background: rgba(var(--th-voile),0.04);
  position: relative;
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
.skip-mannequin-label:hover .skip-mannequin-box { border-color: var(--violet-mid); }
.skip-mannequin-label input:checked + .skip-mannequin-box {
  background: var(--violet-mid);
  border-color: var(--violet-mid);
}
.skip-mannequin-label input:checked + .skip-mannequin-box::after {
  content: '';
  position: absolute;
  top: 1px; left: 4px;
  width: 4px; height: 7px;
  border: 2px solid #fff;
  border-top: none; border-left: none;
  transform: rotate(45deg);
}

/* ── Sélecteur de vues produit ───────────────────────── */
.prod-view-selector {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  margin: calc(var(--e-4) * -1) 0 var(--e-14);
  padding: 0 var(--e-2);
  flex-wrap: wrap;
}
.prod-view-selector.hidden { display: none; }
.prod-view-selector-label {
  font-size: var(--t-meta);
  color: var(--text-3);
  margin-right: var(--e-2);
}
.prod-view-chip {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  padding: var(--e-4) var(--e-12);
  border-radius: var(--r-xl);
  border: 1.5px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-3);
  cursor: pointer;
  transition: border-color var(--t-moyen), background var(--t-moyen), color var(--t-moyen);
  user-select: none;
}
.prod-view-chip:not(.active):hover { border-color: var(--violet-mid); color: var(--text); }
.prod-view-chip.active {
  border-color: var(--violet);
  background: rgba(var(--th-accent-rgb),0.15);
  color: var(--violet-light);
}

/* ⚠️⚠️⚠️ L'ANCIEN ÉCRAN « PRODUIT SEUL » A ÉTÉ RETIRÉ D'ICI (04/09), ET C'EST UNE
   RÉPARATION, PAS UN RANGEMENT. Il posait `.pv-view-grid`, `.pv-vue`, `.pv-vue-n`,
   `.pv-vue-s` et `.pv-vue-coche` — les MÊMES noms que le nouvel écran, avec la MÊME
   force (0,2,0), et PLUS HAUT dans la feuille. Les propriétés que le nouveau bloc ne
   redéclarait pas passaient donc au travers : `flex-direction: column` empilait la case
   à cocher AU-DESSUS du nom au lieu de la mettre en face, et `.pv-vue-coche` restait
   `position: absolute` — la coche se posait ailleurs que dans sa case.
   Le reste ne stylait plus rien : `.pv-setup-grid`, `.pv-vue-ap`, `.pv-levier` n'ont
   plus un seul lecteur dans index.html ni dans app.js (vérifié). Du CSS qui ne style
   plus rien se fait recopier par le suivant qui cherche un motif.
   ⚠️ `.prod-view-chip` et `.prod-view-selector` RESTENT : le ruban compact de l'en-tête
   des résultats mannequin (`#prod-view-selector-inline`) s'en sert toujours.
   Tout l'écran vit maintenant en un seul endroit, plus bas : « UN SEUL ÉTAGE ». */

/* ── Mannequin : réglages en 2 colonnes (Taille+Modes · Instructions) ── */
/* Depuis le 2026-08-02 la grille n'a plus que deux blocs : la taille (centrée, pleine
   largeur) puis les modes de génération en dessous. Le bloc « Instructions spéciales »
   a été retiré de l'écran. */
.gen-options-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--e-20);
  align-items: start;
}

/* Taille de la robe — libellé et tailles sur UNE ligne, centrés.
   Empilés, ces deux éléments coûtaient 63 px de haut pour cinq boutons ; sur une
   ligne ils en coûtent 34, et le bouton « Générer » remonte d'autant. */
.gen-size-block {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-14);
  flex-wrap: wrap;
}
.gen-size-block .field-label { margin-bottom: 0; }
.gen-size-block .size-row { justify-content: center; }

/* Les quatre leviers sur deux colonnes tant que la place le permet */
.gen-options-grid .mode-toggles-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e-10);
  margin-bottom: 0;
}
@media (max-width: 820px) {
  .gen-options-grid .mode-toggles-row { grid-template-columns: minmax(0, 1fr); }
}

/* Version inline dans le header de la section résultats */
.prod-view-selector--inline {
  margin: var(--e-4) 0 0;
  padding: 0;
}

/* ── Section Photos produit (Nouveau vêtement) ───────── */
.new-dress-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--e-18);
}
.dem-photos-results {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-14);
  padding: var(--e-4) 0;
}
.dem-photos-results .card-wrapper {
  flex: 1 1 160px;
  max-width: 240px;
}
.new-dress-footer {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--e-10);
  margin-top: var(--e-20);
}
/* Espace entre la config et les vues générées.
   ⚠️ LE FILET A ÉTÉ RETIRÉ (04/09) : la carte des réglages est maintenant une SURFACE à
   elle, avec son propre bord. Un trait juste en dessous doublait la séparation — deux
   lignes pour dire une seule chose. L'écart suffit.
   ⚠️ `36px` était une valeur brute, la seule de tout cet écran. */
#pv-results-section {
  margin-top: var(--e-32);
}
#pv-results-section .new-dress-footer {
  margin-top: var(--e-48);
}
#pv-results-section .results-header {
  margin-bottom: var(--e-20);
}
#pv-results-section #pv-results-grid {
  margin-bottom: var(--e-8);
}
.btn-reset-product {
  opacity: 0.6;
  font-size: var(--t-base);
}
.btn-reset-product:hover { opacity: 1; }
.new-dress-section-title {
  font-size: var(--t-body);
  font-weight: var(--fw-fort);
  color: var(--text-1);
  margin: 0 0 var(--e-2);
}
.new-dress-section-sub {
  font-size: var(--t-meta);
  color: var(--text-3);
}

/* ── Quick-text chips ────────────────────────────────── */
.chips-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
  margin-bottom: var(--e-8);
  min-height: 0;
}
.chips-bar--image {
  padding: var(--e-8) var(--e-12) 0;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
  padding: var(--e-4) var(--e-8) var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  font-size: var(--t-meta);
  color: var(--text-2);
  cursor: default;
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
.chip:hover {
  border-color: var(--violet-light);
  background: rgba(var(--th-accent-rgb),0.08);
  color: var(--text);
}
.chip-label {
  cursor: pointer;
  user-select: none;
}
.chip-remove {
  background: none;
  border: none;
  color: var(--text-3);
  cursor: pointer;
  font-size: var(--t-small);
  line-height: var(--lh-un);
  padding: 0 var(--e-1);
  opacity: 0.5;
  transition: opacity var(--t-moyen), color var(--t-moyen);
}
.chip-remove:hover { opacity: 1; color: var(--red); }

.chip-add {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  border: 1px dashed var(--border-strong);
  background: transparent;
  font-size: var(--t-meta);
  color: var(--text-3);
  cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen);
}
.chip-add:hover { border-color: var(--violet-light); color: var(--violet-light); }

.chip-add-row {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
}
.chip-add-input {
  padding: var(--e-4) var(--e-8);
  border-radius: var(--r-pilule);
  border: 1px solid var(--violet-light);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--t-meta);
  font-family: inherit;
  outline: none;
  width: 160px;
}
.chip-add-confirm {
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  border: none;
  background: var(--violet);
  color: var(--sur-accent);
  font-size: var(--t-meta);
  cursor: pointer;
  transition: background var(--t-moyen);
}
.chip-add-confirm:hover { background: var(--violet-light); }
.options-top {
  display: flex;
  flex-direction: column;
  gap: var(--e-20);
  margin-bottom: var(--e-24);
}
.size-chips {
  display: flex; flex-wrap: wrap; gap: var(--e-8);
}
.size-chip {
  /* ⚠️⚠️⚠️ LARGEUR FIXE DE 38 px : elle était taillée pour « S », « M », « XL » — et
     recouvrait ses voisines dès qu'une étiquette dépassait. Amadou (07/09), son tapis à
     l'écran : « ce n'est pas du tout adapté, on ne voit rien ». Sa mesure s'appelle
     « 80*120CM » : neuf caractères dans une case de trois.
     ⚠️ LE PLANCHER RESTE : sans lui, « S » et « M » deviendraient deux rectangles étroits
     de largeurs différentes, et la rangée des lettres perdrait son alignement — c'est
     justement ce que la largeur fixe protégeait. On garde le carré, on laisse déborder. */
  min-width: 38px; height: 34px;
  padding: 0 var(--e-8);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile),0.025);
  color: var(--text-2);
  font-size: var(--t-small); font-weight: var(--fw-moyen);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--t-bref) var(--c-rebond);
}
.size-chip:hover { background: var(--bg-hover); color: var(--text); }
.size-chip.active {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: rgba(var(--th-accent-rgb),0.30);
}

/* ── Barre Gamme dans le lib-picker ── */
.lib-picker-tier-bar {
  display: flex;
  gap: var(--e-8);
  margin-bottom: var(--e-14);
}
.lib-picker-tier-bar.hidden { display: none; }
.lib-picker-tier-tab {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-8);
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-md);
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  font-size: var(--t-base);
  font-weight: 800;
  letter-spacing: var(--ls-ample);
  cursor: pointer;
  transition: var(--transi);
}
.lib-picker-tier-range {
  font-size: var(--t-mini);
  font-weight: var(--fw-fort);
  opacity: .6;
  letter-spacing: var(--ls-zero);
}
.lib-picker-tier-tab:not(.active):hover { border-color: var(--violet); color: var(--violet); }
.lib-picker-tier-tab.active {
  background: linear-gradient(135deg, var(--violet), var(--violet-soft));
  border-color: var(--violet-soft);
  color: var(--sur-accent);
}
.lib-picker-tier-tab.active .lib-picker-tier-range { opacity: .85; color: var(--text); }

.lib-picker-style-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
  margin-bottom: var(--e-12);
}
.lib-picker-style-bar.hidden { display: none; }
/* ⚠️ Amadou (23/08) : « c'est trop serré, il n'y a pas assez d'air », et « toutes les
   niches / Robes est trop collé aux cartes des packs ». Le fil et la barre du lieu
   touchaient la première rangée. On respire ICI, dans le sélecteur — pas dans la
   Bibliothèque, dont la grille est pleine et où le même espacement ferait du vide. */
#lib-picker-fil { padding: var(--e-2) 0 var(--e-16); }
.lib-picker-size-bar { margin-top: var(--e-4); margin-bottom: var(--e-16); }
.lib-picker-size-label { align-self: center; font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-3, var(--text-3)); margin-right: var(--e-4); }
.lib-picker-style-chip {
  padding: var(--e-6) var(--e-12);
  border-radius: var(--r-xl);
  border: 1.5px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: var(--transi);
}
.lib-picker-style-chip:not(.active):hover { border-color: var(--border-mid); color: var(--violet); }
.lib-picker-style-chip.active {
  background: var(--violet);
  border-color: var(--violet);
  color: var(--sur-accent);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}
.field > label {
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  color: var(--text-2);
}
.optional {
  color: var(--text-3);
  font-weight: var(--fw-normal);
}
.field textarea,
.field input[type="password"],
.field input[type="text"] {
  background: rgba(var(--th-voile),0.04);
  border: 1px solid var(--border);
  border-radius: var(--radius-xs);
  color: var(--text);
  font-size: var(--t-small);
  padding: var(--e-12) var(--e-14);
  outline: none;
  transition: border-color var(--t-moyen), box-shadow var(--t-moyen);
  resize: vertical;
  width: 100%;
}
.field textarea:focus,
.field input:focus {
  border-color: var(--violet-mid);
  box-shadow: 0 0 0 3px rgba(var(--th-accent-rgb),0.15);
}
/* Panneau Objectif/Budget : inputs sombres lisibles + focus discret turquoise (pas de violet, pas de blanc) */
#modal-ovgoal input { background: var(--bg-hover); border: 1px solid var(--border-strong); border-radius: var(--radius-xs); color: var(--text); font-size: var(--t-small); padding: var(--e-12) var(--e-14); }
#modal-ovgoal input:focus { border-color: rgba(var(--th-second-rgb),0.55); box-shadow: none; }
#modal-ovgoal input::selection { background: rgba(var(--th-second-rgb),0.28); color: var(--text); }
.field textarea::placeholder,
.field input::placeholder { color: var(--text-3); }

.field-hint {
  font-size: var(--t-meta);
  color: var(--text-3);
  line-height: var(--lh-serre);
  transition: color var(--t-moyen);
}
.field-hint.key-ok    { color: var(--safe-text); }
.field-hint.key-error { color: var(--ose-text); }

.key-input-row {
  display: flex;
  gap: var(--e-8);
  align-items: stretch;
}
.key-input-row input { flex: 1; }

/* Volume des notifications (Réglages) */
.volume-row { display: flex; align-items: center; gap: var(--e-10); }
.volume-row input[type="range"] {
  flex: 1; height: 4px; -webkit-appearance: none; appearance: none;
  background: var(--border); border-radius: var(--r-micro); cursor: pointer; accent-color: var(--violet, var(--violet));
}
.volume-val { min-width: 42px; text-align: right; font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2); font-variant-numeric: tabular-nums; }

/* Jauge de stockage (Réglages) */
.storage-meter { display: flex; flex-direction: column; gap: var(--e-6); margin-bottom: var(--e-8); }
.storage-meter-track { width: 100%; height: 8px; background: var(--surface-2); border-radius: var(--r-pilule); overflow: hidden; }
.storage-meter-fill { height: 100%; width: 0%; background: var(--aurora); border-radius: var(--r-pilule); transition: width var(--t-long) var(--c-pose), background var(--t-long) var(--c-pose); }
.storage-actions { display: flex; gap: var(--e-8); flex-wrap: wrap; margin-bottom: var(--e-6); }
.btn-test-key {
  flex-shrink: 0;
  padding: 0 var(--e-14);
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-2);
  cursor: pointer;
  transition: var(--transi);
  white-space: nowrap;
}
.btn-test-key:hover { border-color: var(--violet-mid); color: var(--violet-light); }
.btn-test-key:disabled { opacity: 0.5; cursor: not-allowed; }

.checkbox-group {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
  max-height: 168px;
  overflow-y: auto;
  padding-right: var(--e-6);
  scroll-behavior: smooth;
}
.checkbox-group::-webkit-scrollbar {
  width: 3px;
}
.checkbox-group::-webkit-scrollbar-track {
  background: transparent;
}
.checkbox-group::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: var(--r-pilule);
}
.checkbox-group::-webkit-scrollbar-thumb:hover {
  background: var(--violet-mid);
}

.checkbox-item {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  cursor: pointer;
  font-size: var(--t-small);
  color: var(--text-2);
  user-select: none;
  transition: color var(--t-moyen);
}
.checkbox-item:hover { color: var(--text); }
.checkbox-item input { display: none; }
.checkbox-box {
  width: 18px; height: 18px;
  border-radius: var(--r-micro);
  border: 2px solid var(--border-strong);
  flex-shrink: 0;
  position: relative;
  transition: var(--transi);
}
.checkbox-item input:checked ~ .checkbox-box {
  background: var(--violet);
  border-color: var(--violet);
}
.checkbox-item input:checked ~ .checkbox-box::after {
  content: '';
  position: absolute;
  left: 4px; top: 1px;
  width: 6px; height: 10px;
  border: 2px solid #fff;
  border-top: none; border-left: none;
  transform: rotate(45deg);
}

/* ── Results Section ─────────────────────────────────── */
.results-section {
  display: flex;
  flex-direction: column;
  gap: var(--e-28);
  animation: fadeUp 0.5s var(--ease) both;
}
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

.results-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.results-title {
  font-size: var(--t-lead);
  font-weight: var(--fw-fort);
  letter-spacing: var(--ls-serre);
}
.results-actions-top { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap; }
.results-header-actions { display: flex; align-items: center; gap: var(--e-8); }

/* ── Bloc mesures (taille sélectionnée) ───────────────── */
.dress-measures-block {
  margin-top: var(--e-12);
  padding: var(--e-12) var(--e-14);
  border-radius: var(--r-md);
}
.dress-measures-head {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  margin-bottom: var(--e-8);
  color: var(--text-3);
}
.dress-measures-head .card-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
}
.dress-measures-size {
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-ample);
  color: var(--violet-light);
  margin-left: auto;
}
.dress-measures-list {
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
}
.dress-measure-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--e-4) 0;
  border-bottom: 1px solid var(--border);
}
.dress-measure-row:last-child { border-bottom: none; }
.dress-measure-label {
  font-size: var(--t-meta);
  color: var(--text-3);
}
.dress-measure-val {
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text-1);
  font-family: 'SF Mono', 'Fira Mono', monospace;
}

/* ── Bloc infos robe (SKU + prix d'achat) ─────────────── */
.dress-ref-block {
  margin-top: var(--e-12);
  padding: var(--e-12) var(--e-14);
  border-radius: var(--r-md);
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
}
/* Badge livraison (entrepôt UE = rapide / Chine = lent) */
.dress-ref-wh {
  align-self: flex-start; font-size: var(--t-meta); font-weight: var(--fw-fort); padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule);
  background: rgba(var(--th-danger-rgb), .14); color: var(--red); border: 1px solid rgba(var(--th-danger-rgb), .28);
}
.dress-ref-wh--fast {
  background: rgba(99,214,176, .15); color: var(--green); border-color: rgba(99,214,176, .3);
}
.dress-ref-wh.hidden { display: none; }
.dress-ref-block-head {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  margin-bottom: var(--e-2);
  color: var(--text-3);
}
.dress-ref-block-head .card-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
}
.dress-ref-row {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  min-height: 28px;
}
.dress-ref-row .dress-ref-label {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  color: var(--text-3);
  width: 90px;
  flex-shrink: 0;
  text-transform: none;
  letter-spacing: var(--ls-zero);
  margin-bottom: 0;
}
.dress-ref-row .dress-ref-value {
  flex: 1;
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text-1);
  font-family: 'SF Mono', 'Fira Mono', monospace;
  letter-spacing: var(--ls-large);
}

.btn-copy-ref {
  flex-shrink: 0;
  color: var(--text-3);
  transition: color var(--t-moyen);
}
.btn-copy-ref:hover { color: var(--violet-light); }

.save-all-row {
  display: flex;
  justify-content: center;
  gap: var(--e-12);
  flex-wrap: wrap;
  margin-top: var(--e-24);
}

/* Boutons d'action dans la colonne prix/mesures */
.action-btns-col {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
  margin-top: var(--e-12);
}
.action-btns-col.hidden { display: none; }
.action-btns-col.gated { opacity: .55; }
.action-btns-col.gated button { cursor: not-allowed; }
/* ── Panneau de conformité (contrôle qualité : corrections + validation manuelle) ── */
.conf-panel { background: var(--bg-panel); border: 1px solid rgba(251,191,36,.28); border-radius: var(--r-lg);
  padding: var(--e-16) var(--e-18); margin-bottom: var(--e-14); display: flex; flex-direction: column; gap: var(--e-10); }
.conf-head { display: flex; align-items: center; gap: var(--e-8); font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--amber); }
.conf-head svg { flex-shrink: 0; }
.conf-title { font-size: var(--t-mini); letter-spacing: var(--ls-ample); text-transform: uppercase; color: var(--text-3); margin-top: var(--e-4); }
.conf-view { background: var(--bg-input); border-radius: var(--r-md); padding: var(--e-10) var(--e-12); }
.conf-view-h { display: flex; align-items: center; gap: var(--e-8); font-size: var(--t-base); color: var(--text); margin-bottom: var(--e-6); }
.conf-badge { font-size: var(--t-micro); font-weight: var(--fw-gras); color: var(--amber); background: rgba(251,191,36,.14); border-radius: var(--r-pilule); padding: var(--e-2) var(--e-8); }
.conf-diffs { margin: 0; padding-left: var(--e-18); font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal); }
.conf-second-avis { margin-top: var(--e-6); font-size: var(--t-meta); color: #f0a; color: var(--text-3); border-top: 1px solid var(--border); padding-top: var(--e-6); }
.conf-extra { width: 100%; box-sizing: border-box; font-size: var(--t-base); color: var(--text); font-family: inherit; resize: vertical; outline: none }
.conf-extra:focus { border-color: rgba(var(--th-accent-rgb),.5); }
.conf-actions { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap; }
.conf-lock { display: flex; align-items: center; gap: var(--e-8); font-size: var(--t-mini); color: var(--text-3); }
.conf-lock svg { flex-shrink: 0; }
.btn-vinted {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-28);
  background: linear-gradient(135deg, #0ea5e9, #0284c7);
  color: var(--sur-accent);
  border: none;
  border-radius: var(--r-md);
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: opacity var(--t-moyen), transform var(--t-moyen);
  box-shadow: 0 4px 16px rgba(14,165,233,0.3);
}
.btn-vinted:hover { opacity: 0.9; transform: translateY(-1px); }
.btn-vinted:active { transform: translateY(0); }
.btn-vinted:disabled { opacity: 0.5; cursor: default; transform: none; }
/* « Publier » (mise en ligne directe) : vert = action live, distinct du brouillon bleu */
.btn-vinted-pub { background: linear-gradient(135deg, var(--green), #3FA98A); box-shadow: 0 4px 16px rgba(99,214,176,0.3); }
/* Boutons d'action « locaux » (Sauvegarder, Mettre de côté) : transparents, discrets. */
.btn-transp {
  display: flex; align-items: center; justify-content: center; gap: var(--e-8);
  padding: var(--e-12) var(--e-28); background: transparent; color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  font-size: var(--t-small); font-weight: var(--fw-fort); cursor: pointer;
  transition: background var(--t-moyen), border-color var(--t-moyen);
}
.btn-transp:hover { background: var(--bg-hover); border-color: var(--text-3); }
/* Espace entre le groupe « local » et le groupe « Vinted » (Brouillon / Publier). */
.action-btns-gap { height: 8px; }

.btn-stop-gen {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-28);
  background: rgba(var(--th-danger-rgb),0.15);
  color: var(--red);
  border: 1.5px solid rgba(var(--th-danger-rgb),0.4);
  border-radius: var(--r-md);
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: var(--transi);
}
.btn-stop-gen:hover { background: rgba(var(--th-danger-rgb),0.25); border-color: var(--red); }
.btn-stop-gen:active { transform: scale(0.97); }
.btn-save-all {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-28);
  background: linear-gradient(135deg, var(--violet-deep), var(--violet-mid));
  color: var(--sur-accent);
  border: none;
  border-radius: var(--r-md);
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: opacity var(--t-moyen), transform var(--t-moyen);
  box-shadow: 0 4px 16px rgba(var(--th-accent-rgb),0.3);
}
.btn-save-all:hover { opacity: 0.9; transform: translateY(-1px); }
.btn-save-all:active { transform: translateY(0); }

/* Bouton Enregistrer les vues (sélection mannequin) */
.btn-save-views {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-22);
  background: rgba(34,197,94,0.12);
  color: var(--green);
  border: 1.5px solid rgba(34,197,94,0.35);
  border-radius: var(--r-md);
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: var(--transi);
}
.btn-save-views:hover { background: rgba(34,197,94,0.22); border-color: var(--green); }
.btn-save-views:active { transform: scale(0.97); }
.btn-save-views.has-selection {
  background: linear-gradient(135deg, #16a34a, #15803d);
  color: var(--sur-accent);
  border-color: transparent;
  box-shadow: 0 4px 14px rgba(22,163,74,0.35);
}
.btn-save-views.has-selection:hover { opacity: 0.9; transform: translateY(-1px); }

/* ── Lightbox universelle ── */
#velbo-lightbox {
  position: fixed;
  inset: 0;
  z-index: 99999;
  background: rgba(var(--th-ombre),0.88);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
  backdrop-filter: blur(6px);
  animation: lb-in var(--t-moyen) ease;
}
#velbo-lightbox.hidden { display: none; }
#velbo-lightbox-img {
  max-width: 90vw;
  max-height: 90vh;
  object-fit: contain;
  border-radius: var(--r-md);
  box-shadow: 0 24px 80px rgba(var(--th-ombre),0.6);
  pointer-events: none;
}
@keyframes lb-in {
  from { opacity: 0; transform: scale(0.95); }
  to   { opacity: 1; transform: scale(1); }
}

.btn-add-account {
  font-size: var(--t-base); padding: var(--e-6) var(--e-12);
  color: var(--cyan-light); border-color: rgba(14,165,233,0.3);
}
.btn-add-account:hover { border-color: var(--cyan-light); background: rgba(14,165,233,0.08); }

/* Toggle sélection sur les cartes générées */
.btn-select-view {
  background: rgba(var(--th-voile),0.08) !important;
  border: 1px solid rgba(var(--th-voile),0.2) !important;
  color: rgba(var(--th-voile),0.7) !important;
}
.btn-select-view.selected {
  background: rgba(34,197,94,0.25) !important;
  border-color: var(--green) !important;
  color: var(--green) !important;
}
.btn-select-view:hover { opacity: 1 !important; }

.reset-row {
  display: flex;
  justify-content: center;
  margin-top: var(--e-32);
  padding-top: var(--e-24);
  border-top: 1px solid var(--border);
}
.btn-reset-session {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-12) var(--e-28);
  border-radius: var(--r-md);
  border: 1.5px solid var(--border);
  background: transparent;
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen), background var(--t-moyen);
}
.btn-reset-session:hover {
  border-color: var(--violet-light);
  color: var(--violet-light);
  background: rgba(var(--th-accent-rgb),0.06);
}
.btn-reset-session svg { opacity: 0.8; }

/* ── Dual views wrapper (mannequin + produit côte à côte) ── */
.dual-views-wrapper {
  display: flex;
  gap: 0;
  align-items: flex-start;
}
.views-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
  padding: 0 var(--e-24);
}
.views-col:first-child { padding-left: 0; border-right: 1px solid rgba(var(--th-voile),0.07); }
.views-col:last-child  { padding-right: 0; padding-left: var(--e-28); margin-top: var(--e-6); }
.views-col-label {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  font-size: var(--t-meta);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
  padding-bottom: var(--e-6);
}
.views-col-label svg { flex-shrink: 0; opacity: 0.7; }

/* Grille produit inline — images en rangée horizontale comme les vues mannequin */
/* !important pour overrider .dem-photos-results { display: grid } qui est aussi appliqué sur cet élément */
.inline-prod-grid {
  display: flex !important;
  flex-direction: row !important;
  gap: var(--e-10);
}
.inline-prod-grid .dem-result-card {
  flex: 1 1 0;
  min-width: 0;
}
.inline-prod-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--e-4);
}
.inline-prod-actions .btn-secondary {
  font-size: var(--t-base);
  padding: var(--e-6) var(--e-12);
}

/* ── Image Grid 2 + 3 ────────────────────────────────── */
.image-grid {
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
}
.grid-row {
  display: flex;
  gap: var(--e-14);
}
/* colonnes dynamiques via data-cols */
.grid-row[data-cols="1"] { justify-content: center; }
.grid-row[data-cols="1"] .card-wrapper { flex: 0 0 28%; max-width: 28%; }
.grid-row[data-cols="2"] .card-wrapper { flex: 1 1 0; max-width: 48%; }
.grid-row[data-cols="3"] .card-wrapper { flex: 1 1 0; }
.grid-row[data-cols="4"] .card-wrapper { flex: 1 1 0; }

/* Card wrapper: image + version strip stacked */
.card-wrapper {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
}
.card-wrapper[draggable="true"] { cursor: grab; }
.card-wrapper[draggable="true"]:active { cursor: grabbing; }

/* Version history strip */
.card-versions {
  display: flex;
  gap: var(--e-6);
  flex-wrap: wrap;
}
.card-versions:empty { display: none; }

.card-version-thumb {
  position: relative;
  width: 50px;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: border-color var(--t-moyen), transform var(--t-moyen);
  flex-shrink: 0;
}
.card-version-thumb:hover { border-color: var(--violet-light); transform: scale(1.05); }
.card-version-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.card-version-badge {
  position: absolute;
  bottom: 2px; left: 2px;
  background: rgba(var(--th-ombre),0.72);
  border-radius: var(--r-micro);
  padding: var(--e-1) var(--e-4);
  font-size: var(--t-nano);
  font-weight: var(--fw-gras);
  color: var(--cyan-light);
  letter-spacing: var(--ls-large);
  pointer-events: none;
}

.image-card {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  aspect-ratio: 3 / 4;
  transition: border-color var(--t-moyen);
}
.image-card:hover { border-color: var(--border-strong); }
.image-card img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--t-long) var(--c-pose);
  position: relative;
  z-index: 1; /* overlay est z-index:3 → reste toujours au-dessus */
}
.image-card:hover img { transform: scale(1.03); }

/* Download dropdown on card */
.card-dl-wrap {
  position: relative;
}
.card-dl-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  background: var(--bg-card-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
  min-width: 190px;
  z-index: 20;
  box-shadow: 0 8px 24px rgba(var(--th-ombre),0.6);
  animation: popIn var(--t-moyen) var(--ease);
}
.card-dl-menu button {
  display: block;
  width: 100%;
  padding: var(--e-10) var(--e-14);
  text-align: left;
  background: none;
  border: none;
  color: var(--text-2);
  font-family: var(--font);
  font-size: var(--t-base);
  cursor: pointer;
  transition: var(--transi);
}
.card-dl-menu button:hover { background: var(--violet); color: var(--sur-accent); }

/* Card label (overlay sur image — scopé pour ne pas entrer en collision avec le .card-label du système Aurora) */
.card-wrapper .card-label {
  position: absolute;
  top: 10px; left: 10px;
  background: rgba(var(--th-ombre),0.65);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--radius-xs);
  padding: var(--e-4) var(--e-10);
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  color: var(--cyan-light);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  z-index: 2;
}

/* Overlay actions */
.card-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(var(--th-ombre),0.72) 0%, transparent 55%);
  opacity: 0;
  transition: opacity var(--t-moyen);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  flex-wrap: wrap;          /* carte étroite → les boutons passent à la ligne au lieu d'être coupés */
  align-content: flex-end;
  padding: var(--e-8);
  gap: var(--e-6);
  z-index: 3;
}
.image-card:hover .card-overlay { opacity: 1; }
.card-overlay .btn-action {
  font-size: var(--t-mini);
  padding: var(--e-4) var(--e-8);
  gap: var(--e-4);
  white-space: nowrap;
  min-width: 0;
  background: rgba(var(--th-panneau-rgb),0.72);   /* lisible même hors du dégradé quand ça wrappe */
  backdrop-filter: blur(4px);
}
.card-overlay .card-dl-wrap { min-width: 0; }
.card-overlay .btn-action svg { width: 11px; height: 11px; flex-shrink: 0; }

/* Loading state */
.image-card.loading {
  display: flex; align-items: center; justify-content: center;
}
.card-loader {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-10);
  color: var(--text-3); font-size: var(--t-base); text-align: center; padding: var(--e-20);
  width: 100%;
}
.card-loader-label {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  letter-spacing: var(--ls-ample);
  text-transform: uppercase;
  color: var(--violet-light);
}
.card-loader-sub {
  font-size: var(--t-meta);
  color: var(--text-3);
  margin-bottom: var(--e-4);
}
.card-progress-track {
  width: 80%;
  height: 4px;
  background: var(--border);
  border-radius: var(--r-pilule);
  overflow: hidden;
}
.card-progress-bar {
  height: 100%;
  width: 0%;
  background: linear-gradient(90deg, var(--violet-light), var(--violet-light));
  border-radius: var(--r-pilule);
  transition: width 0.6s var(--c-pose);
}

/* Error state */
.image-card.card-error-state {
  display: flex; align-items: center; justify-content: center;
}
.card-error-content {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-10);
  color: var(--red); font-size: var(--t-base); text-align: center; padding: var(--e-20);
}
.card-error-content p { color: var(--text-3); font-size: var(--t-meta); line-height: var(--lh-normal); }

/* ── Listing Section ─────────────────────────────────── */
.listing-section {
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: var(--e-20);
  align-items: start;
}
.listing-col {
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
}

.listing-block {
  padding: var(--e-18) var(--e-22);
}
.listing-block-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--e-12);
  gap: var(--e-12);
}
.listing-block-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  color: var(--text-3);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}
.listing-block-actions { display: flex; gap: var(--e-8); }

/* ── Champ ID Velbo ── */
.listing-id-row {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  padding: var(--e-8) var(--e-12);
  background: var(--surface-2, rgba(var(--th-voile),0.04));
  border: 1px solid var(--border, rgba(var(--th-voile),0.08));
  border-radius: var(--r-md);
  margin-bottom: var(--e-8);
}
.listing-id-label {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  color: var(--text-2);
  white-space: nowrap;
  letter-spacing: var(--ls-large);
  text-transform: uppercase;
}
.listing-id-input {
  width: 110px;
  padding: var(--e-4) var(--e-8);
  background: var(--surface, rgba(var(--th-voile),0.07));
  border: 1px solid var(--border, rgba(var(--th-voile),0.12));
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--t-small);
  font-family: ui-monospace, monospace;
  outline: none;
}
.listing-id-input:focus {
  border-color: var(--accent, var(--violet-soft));
}
.listing-id-hint {
  font-size: var(--t-meta);
  color: var(--text-3, rgba(var(--th-voile),0.35));
}
/* Sélecteur couleur Vinted (2 max) habillé au thème */
.lc-multi { position: relative; }
.lc-multi-trigger { width: auto; min-width: 128px; max-width: 240px; display: inline-flex; align-items: center; gap: var(--e-6);
  justify-content: space-between; cursor: pointer; font-family: inherit; text-align: left; }
.lc-multi-trigger:hover { border-color: var(--violet-mid); }
.lc-multi-chips { display: inline-flex; align-items: center; gap: var(--e-14); flex-wrap: nowrap; overflow: hidden; }
/* Sélecteur Catégorie dans la ligne du générateur — compact, aligné avec Couleur. */
.listing-cat-dd { min-width: 160px; }
.listing-cat-dd .de-dd-trigger { padding: var(--e-8) var(--e-12); border-radius: var(--r-sm); font-size: var(--t-base); }
.listing-cat-dd .de-dd-panel { min-width: 220px; }
.lc-ph { color: var(--text-3, rgba(var(--th-voile),0.4)); }
.lc-chip { display: inline-flex; align-items: center; gap: var(--e-6); font-size: var(--t-base); color: var(--text); white-space: nowrap; }
.lc-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; border: 1px solid rgba(var(--th-voile),0.25); }
.lc-multi-caret { color: var(--text-3); flex-shrink: 0; }
.lc-multi-menu { position: absolute; z-index: 40; top: calc(100% + 5px); left: 0; min-width: 180px; max-height: 260px;
  overflow-y: auto; padding: var(--e-6); border-radius: var(--r-md); background: var(--bg-card-solid);
  border: 1px solid var(--border-strong, rgba(var(--th-voile),0.14)); box-shadow: 0 14px 34px rgba(var(--th-ombre),0.55); }
.lc-opt { display: flex; align-items: center; gap: var(--e-10); padding: var(--e-6) var(--e-10); border-radius: var(--r-sm); cursor: pointer; font-size: var(--t-base); color: var(--text-2); }
.lc-opt:hover { background: var(--bg-elevated); color: var(--text); }
.lc-opt-name { flex: 1; }
.lc-opt-chk { opacity: 0; color: var(--violet-light); flex-shrink: 0; display: inline-flex; }
.lc-opt.sel { color: var(--text); background: rgba(var(--th-accent-rgb),0.12); }
.lc-opt.sel .lc-opt-chk { opacity: 1; }
.listing-id-hint code {
  font-family: ui-monospace, monospace;
  color: var(--accent, var(--violet-soft));
}

.listing-title {
  font-size: var(--t-body);
  font-weight: var(--fw-fort);
  color: var(--text);
  line-height: var(--lh-normal);
}
.listing-desc {
  font-size: var(--t-small);
  color: var(--text-2);
  line-height: var(--lh-aere);
  white-space: pre-wrap;
}

/* Titre / description éditables à la main (contenteditable plaintext-only).
   Padding compensé par une marge négative → l'anneau de focus n'décale pas le texte. */
.listing-title[contenteditable],
.listing-desc[contenteditable] {
  cursor: text;
  outline: none;
  border-radius: var(--r-sm);
  padding: var(--e-6) var(--e-8);
  margin: calc(var(--e-6) * -1) calc(var(--e-8) * -1);
  transition: background var(--t-moyen) var(--c-pose), box-shadow var(--t-moyen) var(--c-pose);
}
.listing-title[contenteditable]:hover,
.listing-desc[contenteditable]:hover {
  background: var(--cok-bg);
}
.listing-title[contenteditable]:focus,
.listing-desc[contenteditable]:focus {
  background: var(--bg-elevated);
  box-shadow: inset 0 0 0 1px rgba(234, 88, 12, 0.5);
}

/* Prices */
/* ── Prix suggérés (Aurora) ─────────────────────────── */
.prices-panel {
  padding: var(--e-18);
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
}
.prices-head {
  display: flex;
  align-items: center;
  gap: var(--e-10);
}
.prices-head .card-label {
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
}
.prices-regen-btn {
  margin-left: auto;
  padding: var(--e-6) var(--e-8);
}
.gen-style-select {
  background: var(--bg-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--t-meta);
  font-family: inherit;
  padding: var(--e-4) var(--e-8);
  height: 26px;
  cursor: pointer;
  outline: none;
  max-width: 140px;
}
.gen-style-select:focus { border-color: var(--violet); color: var(--text); }

/* Pill de gamme courante (header du panneau) */
.tier-pill {
  display: inline-flex;
  align-items: center;
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  letter-spacing: 0.10em;
}
.tier-pill[data-tier="volume"]  { background: var(--tier-volume-bg);  color: var(--tier-volume-text); }
.tier-pill[data-tier="premium"] { background: var(--tier-premium-bg); color: var(--tier-premium-text); }
.tier-pill[data-tier="luxe"]    { background: var(--tier-luxe-bg);    color: var(--tier-luxe-text); }

.prices-list {
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
}
.price-row {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  padding: var(--e-14);
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile),0.025);
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
}
.price-row.recommended {
  border-color: rgba(110,210,168,0.35);
  background: var(--safe-bg);
}
.price-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-10);
}
.price-row-head .btn-icon {
  width: 28px; height: 28px;
}

.price-tag {
  display: inline-flex;
  align-items: center;
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  letter-spacing: 0.10em;
}
.price-tag.safe { background: var(--safe-bg); color: var(--safe-text); }
.price-tag.moy  { background: var(--moy-bg);  color: var(--moy-text);  }
.price-tag.ose  { background: var(--ose-bg);  color: var(--ose-text);  }

.price-amount-row {
  display: flex;
  align-items: baseline;
  gap: var(--e-10);
  flex-wrap: wrap;
}
.price-amount {
  display: inline-flex;
  align-items: baseline;
  gap: var(--e-2);
  font-size: var(--t-xl);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-serre);
  color: var(--text);
  white-space: nowrap;
  line-height: var(--lh-titre);
}
.price-amount-sym {
  font-size: var(--t-lead);
  font-weight: var(--fw-moyen);
  color: var(--text-2);
  margin-left: var(--e-2);
}

.delta {
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
  padding: var(--e-2) var(--e-8);
  border-radius: var(--r-pilule);
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  white-space: nowrap;
}
.delta.pos { background: var(--safe-bg); color: var(--safe-text); }
.delta.neg { background: var(--moy-bg);  color: var(--moy-text); }
.delta.hidden { display: none; }

.price-row-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-10);
}
.price-hint {
  font-size: var(--t-meta);
  color: var(--text-3);
}
.rec-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  color: var(--safe-text);
}
.rec-tag.hidden { display: none; }

.btn-copy-price { padding: 0; }

/* ── Modals ───────────────────────────────────────────── */
/* ⚠️ UN SEUL VOILE POUR TOUT LE SITE. Cinq fenêtres, cinq fonds : 0,55 · 0,65 · 0,75 ·
   0,86 · 0,92, certaines floutées, d'autres non. D'une fenêtre à l'autre le site
   changeait d'allure — Amadou : « des fois c'est foncé, des fois c'est transparent,
   trouve un entre-deux, là ça fait cheap ».
   L'entre-deux est à 0,78 : assez dense pour que la fenêtre se détache et que le texte
   dessous cesse de distraire, assez clair pour qu'on garde le contexte de ce qu'on est
   en train de faire. ⚠️ Et teinté violet-nuit plutôt que noir pur : sur cette palette,
   du noir franc lit comme un trou. Le flou fait le reste du travail.
   Toute nouvelle fenêtre prend `var(--voile)` — jamais sa propre valeur. */
:root {
  --voile: rgba(11, 9, 22, 0.78);
  --voile-flou: blur(14px) saturate(1.25);
}
.modal-overlay {
  position: fixed; inset: 0;
  background: var(--voile);
  backdrop-filter: var(--voile-flou);
  -webkit-backdrop-filter: var(--voile-flou);
  z-index: 200;
  display: flex; align-items: center; justify-content: center;
  animation: overlayIn var(--t-moyen) ease;
}
@keyframes overlayIn {
  from { opacity: 0; } to { opacity: 1; }
}

.modal-card {
  background: var(--bg-panel-solid);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--e-32);
  width: 460px;
  max-width: 90vw;
  position: relative;
  z-index: 1;
  animation: cardIn var(--t-moyen) var(--ease);
}
@keyframes cardIn {
  from { opacity: 0; transform: scale(0.94) translateY(8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--e-28);
}
.modal-header h2 {
  font-size: var(--t-body);
  font-weight: var(--fw-fort);
  background: linear-gradient(120deg, var(--violet-light), var(--cyan-light));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.modal-body { display: flex; flex-direction: column; gap: var(--e-18); margin-bottom: var(--e-28); }
.modal-footer { display: flex; justify-content: flex-end; gap: var(--e-10); }

/* Paramètres — grand panneau à onglets horizontaux */
.modal-card--settings { width: 760px; max-width: 94vw; padding: 0; display: flex; flex-direction: column; max-height: 86vh; }
.modal-card--settings .modal-header { padding: var(--e-18) var(--e-22) 0; margin-bottom: var(--e-12); }
.pa-tabs { display: flex; gap: var(--e-2); padding: 0 var(--e-16); border-bottom: 1px solid var(--border); overflow-x: auto; flex-shrink: 0; }
.pa-tab { display: flex; align-items: center; gap: var(--e-8); border: 0; background: transparent; color: var(--text-2); font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-fort); padding: var(--e-12) var(--e-14); cursor: pointer; border-bottom: 2px solid transparent; white-space: nowrap; transition: color var(--t-moyen); }
.pa-tab:not(.active):hover { color: var(--text); }
.pa-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
/* ⚠️⚠️⚠️ `flex: 1 1 0` ET `min-height: 0`, PAS `flex: 0 0 auto`. Amadou (24/08) : « le
   bouton Enregistrer dépasse de la bordure ».
   La fenêtre est une colonne flex avec une hauteur plafonnée. Le corps refusait de
   rétrécir : en-tête 52 + onglets 90 + corps 462 + pied 63 = 667 px pour 602 px
   disponibles, donc le pied était POUSSÉ DEHORS — 78 px sous la bordure, mesuré sur une
   fenêtre de 700 px de haut. Ça ne se voyait pas sur un grand écran : plus la fenêtre est
   basse, plus le bouton sort.
   ⚠️ `min-height: 0` est indispensable : un enfant flex vaut `min-height: auto` par
   défaut, ce qui l'empêche de descendre sous la hauteur de son contenu — `flex: 1 1 0`
   seul n'aurait rien changé.
   ⚠️ `height` et `max-height` partent avec : c'est le parent qui donne la place, et deux
   contraintes de hauteur sur le même élément finissent toujours par se contredire. */
/* ⚠️ `flex-basis: 540px`, PAS `0`. Avec une base à zéro le corps ne demandait plus rien :
   la fenêtre se refermait sur son contenu — 243 px au lieu des 643 du Journal (mesuré).
   La base dit la hauteur SOUHAITÉE, `1 1` autorise à grandir et à rétrécir, et
   `min-height: 0` lève le plancher que tout enfant flex porte par défaut. Les trois
   ensemble : la fenêtre garde sa taille, et le pied reste dedans quand l'écran est bas. */
.pa-body { padding: var(--e-20) var(--e-22); overflow-y: auto; flex: 1 1 540px; min-height: 0; }
/* Footer Paramètres : la variante --settings passe la carte en padding:0, donc le footer doit poser son propre padding sinon les boutons Annuler/Enregistrer collent au bord */
.modal-card--settings .modal-footer { padding: 14px 22px; border-top: 1px solid var(--border); flex-shrink: 0; }
.pa-pane { display: flex; flex-direction: column; gap: var(--e-16); }
.pa-pane.hidden { display: none; }
.pa-note { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-normal); margin: 0; }
.pa-conn-group { font-size: var(--t-micro); font-weight: var(--fw-gras); letter-spacing: var(--ls-ample); text-transform: uppercase; color: var(--text-3); margin: 0; }
.pa-conn-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: var(--e-10); }
.pa-conn-card { }
.pa-conn-top { display: flex; align-items: center; gap: var(--e-8); margin-bottom: var(--e-6); }
.pa-conn-name { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.pa-conn-top .pa-conn-badge { margin-left: auto; }
.pa-conn-desc { font-size: var(--t-meta); color: var(--text-2); margin-bottom: var(--e-12); line-height: var(--lh-serre); }
.pa-conn-badge { font-size: var(--t-micro); font-weight: var(--fw-fort); border-radius: var(--r-pilule); padding: var(--e-4) var(--e-10); white-space: nowrap; }
.pa-conn-badge.ok { background: rgba(63,209,155,.14); color: var(--green); }
.pa-conn-badge.todo { background: rgba(240,194,90,.14); color: var(--amber); }
.pa-conn-open { display: inline-block; border: 1px solid var(--border-strong); border-radius: var(--r-sm); padding: var(--e-6) var(--e-14); font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2); text-decoration: none; }
.pa-conn-open:hover { color: var(--text); border-color: var(--accent); }
.pa-autonomy { display: flex; align-items: center; gap: var(--e-12); }
.pa-autonomy-ic { width: 34px; height: 34px; border-radius: var(--r-md); background: var(--surface-2); color: var(--accent); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }

/* Modal générique Velbo (remplace confirm()/prompt() natifs) */
/* Une confirmation s'ouvre PAR-DESSUS ce qui la déclenche (ex. la fenêtre des domaines,
   z-index 400). Sans ça, elle se glisse derrière et l'écran paraît figé. */
.velbo-modal-overlay { z-index: 9600; }
.velbo-modal { width: 380px; }
.velbo-modal .modal-header { margin-bottom: var(--e-16); }
.velbo-modal .modal-body { margin-bottom: var(--e-20); gap: 0; }
.velbo-modal-msg { font-size: var(--t-small); color: var(--text-2); line-height: var(--lh-normal); margin: 0; }
.velbo-modal-input {
  width: 100%; height: 42px; margin-top: var(--e-14); padding: 0 var(--e-14);
  border-radius: var(--r-md); border: 1px solid var(--border-strong);
  background: var(--bg-input); color: var(--text);
  font-family: inherit; font-size: var(--t-small);
}
.velbo-modal-input:focus { outline: none; border-color: var(--violet); }
.velbo-modal .btn-primary.btn-danger { background: var(--red); border-color: transparent; color: var(--sur-accent); }
.velbo-modal .btn-primary.btn-danger:hover { background: var(--red); }

/* ── Titres et boutons génériques modal ── */
.modal-title {
  font-size: var(--t-body);
  font-weight: var(--fw-fort);
  background: linear-gradient(120deg, var(--violet-light), var(--cyan-light));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.modal-close {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: var(--t-body);
  cursor: pointer;
  padding: var(--e-4) var(--e-8);
  border-radius: var(--radius);
  transition: background var(--t-moyen), color var(--t-moyen);
}
.modal-close:hover { background: var(--surface-2); color: var(--text); }
.modal-hint { font-size: var(--t-base); color: var(--text-muted); margin: 0 0 var(--e-10); line-height: var(--lh-normal); }
.modal-textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: var(--t-small);
  padding: var(--e-10) var(--e-12);
  resize: vertical;
  font-family: inherit;
  box-sizing: border-box;
  transition: border-color var(--t-moyen);
}
.modal-textarea:focus { border-color: var(--violet-light); outline: none; }
.modal-card--seller { width: 520px; }

/* Zoom modal */
#modal-zoom { cursor: default; align-items: center; }
.zoom-backdrop { position: absolute; inset: 0; cursor: zoom-out; }

.zoom-wrapper {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: var(--e-16);
  max-height: 90vh;
  max-width: 92vw;
}

/* ── Left: large image + up/down arrows ── */
.zoom-left {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-10);
  flex-shrink: 0;
}

.zoom-track {
  cursor: grab;
  user-select: none;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 24px 64px rgba(var(--th-ombre),0.85);
  position: relative;
}
.zoom-track.dragging { cursor: grabbing; }

#zoom-img {
  display: block;
  max-width: 62vw;
  max-height: 76vh;
  object-fit: contain;
  border-radius: var(--radius);
  pointer-events: none;
  transition: opacity var(--t-long) var(--c-pose), transform var(--t-long) var(--c-pose);
}

.zoom-nav-arrow {
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: var(--transi);
  flex-shrink: 0;
}
.zoom-nav-arrow:hover  { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }
.zoom-nav-arrow:disabled { opacity: 0.2; cursor: default; pointer-events: none; }

.zoom-dots {
  display: flex;
  gap: var(--e-8);
  align-items: center;
}
.zoom-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(var(--th-voile),0.25);
  transition: var(--transi);
  cursor: pointer;
}
.zoom-dot.active {
  background: var(--violet-light);
  width: 18px;
  border-radius: var(--r-micro);
}
.zoom-hint {
  font-size: var(--t-mini);
  color: var(--text-3);
  letter-spacing: var(--ls-large);
}

.zoom-prompt-tag {
  background: rgba(var(--th-accent-rgb),0.12);
  border: 1px solid rgba(167,139,250,0.22);
  border-radius: var(--radius-xs);
  font-size: var(--t-meta); padding: var(--e-6) var(--e-12);
  color: var(--violet-light);
  font-style: italic;
  text-align: center;
  max-width: 60vw;
  word-break: break-word;
  line-height: var(--lh-serre);
}

.zoom-actions-bar {
  display: flex; gap: var(--e-8); justify-content: center;
  margin-top: var(--e-4);
}
.zoom-action-btn {
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-8) var(--e-14); border-radius: var(--radius-sm);
  font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer;
  background: rgba(var(--th-voile),0.07); border: 1px solid rgba(var(--th-voile),0.15);
  color: var(--text); transition: var(--transi);
}
.zoom-action-btn:hover { background: rgba(var(--th-accent-rgb),0.25); border-color: var(--violet); }

/* ── Right: reference sections stacked ── */
.zoom-right {
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
  width: 220px;
  flex-shrink: 0;
  min-height: 0;
}
/* Photo source repost dans le strip de référence */
.zoom-tpl-item {
  display: flex;
  flex-direction: column;
  gap: var(--e-6);
}
.zoom-tpl-img {
  width: 100%;
  max-height: 280px;
  object-fit: contain;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
}

/* ── Mode avec photo robe : deux colonnes de même taille ── */
.zoom-wrapper.with-ref {
  align-items: center;
  gap: var(--e-20);
}
.zoom-wrapper.with-ref .zoom-left {
  flex: 1;
  min-width: 0;
}
.zoom-wrapper.with-ref #zoom-img {
  max-width: 100%;
  max-height: 76vh;
}
.zoom-wrapper.with-ref .zoom-right {
  flex: 1;
  min-width: 0;
  width: auto;
  align-items: center;
  gap: var(--e-10);
}
.zoom-ref-nav {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  width: 100%;
}
.zoom-ref-arrow {
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; flex-shrink: 0;
  transition: background var(--t-moyen), color var(--t-moyen);
}
.zoom-ref-arrow:hover:not(:disabled) { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }
.zoom-ref-arrow:disabled { opacity: 0.2; cursor: default; }
.zoom-ref-big {
  flex: 1; min-width: 0;
  max-height: 76vh;
  object-fit: contain;
  border-radius: var(--radius);
  box-shadow: 0 24px 64px rgba(var(--th-ombre),0.85);
  display: block;
  transition: opacity var(--t-bref) var(--c-pose);
}
.zoom-ref-dots {
  display: flex;
  gap: var(--e-8);
  align-items: center;
}

/* ── Mode produit : visuel généré + photos robe côte à côte ── */
.zoom-wrapper.product-mode .zoom-actions-bar { display: none !important; }
.zoom-wrapper.product-mode .zoom-prompt-tag  { display: none !important; }
.zoom-wrapper.product-mode .zoom-left {
  flex-direction: row;
  align-items: center;
  gap: var(--e-14);
}
.zoom-wrapper.product-mode .zoom-nav-arrow {
  width: 44px; height: 44px;
  flex-shrink: 0;
}
.zoom-wrapper.product-mode #zoom-prev svg { transform: rotate(-90deg); }
.zoom-wrapper.product-mode #zoom-next svg { transform: rotate(90deg); }
.zoom-wrapper.product-mode #zoom-img {
  max-width: 52vw;
  max-height: 86vh;
}
.zoom-wrapper.product-mode .zoom-right {
  display: flex;
  width: 260px;
  flex-shrink: 0;
}
.zoom-wrapper.product-mode .zoom-ref-thumb {
  width: 100%;
  max-height: 40vh;
  aspect-ratio: unset;
  object-fit: contain;
}
.zoom-ref-section {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  flex: 1;
  min-height: 0;
}
.zoom-ref-section:empty { display: none; }
.zoom-ref-label {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  color: var(--text-3);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}

.zoom-ref-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  border-radius: var(--radius-sm);
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  scroll-behavior: smooth;
}
.zoom-ref-scroll::-webkit-scrollbar { display: none; }
.zoom-ref-scroll { scrollbar-width: none; }

.zoom-ref-thumb {
  width: 220px;
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-sm);
  object-fit: cover;
  border: 1px solid var(--border-strong);
  opacity: 0.85;
  transition: opacity var(--t-moyen), border-color var(--t-moyen);
  flex-shrink: 0;
  display: block;
}
.zoom-ref-thumb:hover { opacity: 1; border-color: var(--violet-light); }

/* ⚠️⚠️ RECETTE MORTE RETIRÉE. `.zoom-close` était décrite ici (34 px, ronde, fond sombre,
   collée au coin de l'image) PUIS deux fois plus bas dans le bloc d'harmonisation des
   croix — et les dernières gagnent. Le bouton qu'on lisait ici n'a jamais existé à
   l'écran. Sa position vit désormais avec le reste de la visionneuse, en fin de fichier ;
   sa forme reste celle de TOUTES les croix du site. */

/* ── Image regen panel ───────────────────────────────── */
.regen-panel {
  position: relative;
  z-index: 1;
  width: 560px;
  max-width: 96vw;
  height: 70vh;
  min-height: 420px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  border-radius: var(--radius);
  overflow: hidden;
}

/* Messages scroll area */
.regen-messages {
  flex: 1;
  overflow-y: auto;
  padding: var(--e-14) var(--e-18);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.regen-messages:empty::before {
  content: 'Décris ce que tu veux modifier sur ce visuel…';
  color: var(--text-3);
  font-size: var(--t-base);
  text-align: center;
  margin: auto;
  opacity: 0.6;
}

/* Input row */
.regen-claude-toggle {
  padding: var(--e-8) var(--e-14) var(--e-4);
  background: var(--surface);
}
.regen-claude-btn {
  width: 100%;
}
.regen-input-row {
  display: flex;
  align-items: flex-end;
  gap: var(--e-8);
  padding: var(--e-10) var(--e-14) var(--e-14);
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.regen-input { flex: 1;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  resize: none;
  line-height: var(--lh-normal);
  transition: border-color var(--t-moyen);
  max-height: 120px }
.regen-input:focus { outline: none; border-color: var(--violet); }
.regen-input::placeholder { color: var(--text-3); }
.regen-send {
  width: 40px; height: 40px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
}

/* ── Simple regen modal (titre / desc / prix) ─────────── */
.regen-simple-card {
  position: relative;
  z-index: 1;
  width: 420px;
  max-width: 94vw;
  border-radius: var(--radius);
  padding: 0;
  overflow: hidden;
}
.regen-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--e-14) var(--e-18) var(--e-12);
  border-bottom: 1px solid var(--border);
}
.regen-title {
  font-size: var(--t-base);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-ample);
  text-transform: uppercase;
  color: var(--violet-light);
}
.regen-close {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: transparent;
  border: 1px solid var(--border-strong);
  color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: var(--transi);
}
.regen-close:hover { background: var(--red); border-color: var(--red); color: var(--sur-accent); }

.regen-simple-hint {
  font-size: var(--t-meta);
  color: var(--text-3);
  padding: var(--e-12) var(--e-18) var(--e-4);
  margin: 0;
}
.regen-simple-input { display: block;
  width: 100%;
  box-sizing: border-box;
  color: var(--text);
  font-size: var(--t-small);
  resize: none;
  font-family: inherit;
  line-height: var(--lh-normal);
  margin: 0 var(--e-18);
  width: calc(100% - 36px);
  transition: border-color var(--t-moyen) }
.regen-simple-input:focus { outline: none; border-color: var(--violet); }
.regen-simple-input::placeholder { color: var(--text-3); }
.regen-simple-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-18) var(--e-16);
}
.regen-simple-actions .btn-primary {
  display: flex; align-items: center; gap: var(--e-6);
}
.regen-backdrop { position: absolute; inset: 0; cursor: pointer; }

/* ── Image regen chat extras ─────────────────────────── */
.img-regen-attach-btn {
  width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--text-3);
  cursor: pointer;
  flex-shrink: 0;
  transition: var(--transi);
}
.img-regen-attach-btn:hover { border-color: var(--violet); color: var(--violet-light); }

.img-regen-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-8);
  padding: 0 var(--e-18) var(--e-10);
}
.img-regen-attachments:empty { display: none; }
.img-regen-thumb-wrap {
  position: relative;
  width: 60px; height: 60px;
  border-radius: var(--radius-sm);
  overflow: visible;
}
.img-regen-thumb {
  width: 60px; height: 60px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  display: block;
}
.img-regen-thumb-remove {
  position: absolute;
  top: -6px; right: -6px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--red);
  border: none;
  color: var(--sur-accent);
  font-size: var(--t-mini);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  line-height: var(--lh-un);
}

/* ── Cost breakdown popover ──────────────────────────── */
.cost-display { position: relative; cursor: pointer; }
.cost-popover {
  position: fixed;
  z-index: 300;
  width: 320px;
  background: var(--bg-2, #0d0d1e);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(var(--th-ombre),0.7);
  padding: var(--e-18) var(--e-22) var(--e-20);
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
}
.cost-popover.hidden { display: none; }
.cost-popover-title {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--violet-light);
  padding-bottom: var(--e-6);
  border-bottom: 1px solid var(--border);
}
.cost-popover-rows { display: flex; flex-direction: column; gap: var(--e-8); }
.cost-popover-sep { height: 1px; background: var(--border); margin: var(--e-4) 0; }
.cost-popover-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: var(--t-base);
  color: var(--text-2);
  gap: var(--e-24);
}
.cost-popover-row span:last-child { font-variant-numeric: tabular-nums; color: var(--text); }
.cost-popover-total {
  display: flex;
  justify-content: space-between;
  font-size: var(--t-base);
  font-weight: var(--fw-gras);
  color: var(--text);
  padding-top: var(--e-8);
  border-top: 1px solid var(--border);
}
.cost-popover-total span:last-child { color: var(--violet-light); }

/* ── Alert modal ─────────────────────────────────────── */
/* ⚠️⚠️ UNE FENÊTRE POSÉE DANS UN RIDEAU DOIT ÊTRE OPAQUE — mesuré le 15/08.
   `.confirm-card` et `.alert-card` s'appuyaient sur `.glass-card`, donc sur
   `--bg-card` → `rgba(var(--th-voile), …)`. Or `--th-voile` s'INVERSE avec le thème :
   sur Dune et Nimbe il vaut `0,0,0`, et le voile devient un film NOIR. Posé sur
   `--voile` (le rideau, sombre dans tous les thèmes), ça donnait un panneau presque
   noir — pendant que `--text`, `--text-2` et `--ose-text` étaient, eux, passés au brun
   foncé pour un fond clair. Mesuré : « Annuler » à **1,30 de contraste** en Dune et
   1,60 en Nimbe, contre 4,5 exigés. Illisible, exactement la capture d'Amadou.
   La réparation est un EMPRUNT, pas une invention : `.modal-card` était déjà opaque
   avec `--bg-panel-solid`. Les trois fenêtres disent maintenant la même chose. */
.confirm-card {
  background: var(--bg-panel-solid);
  border: 1px solid var(--border-strong);
  position: relative; z-index: 1;
  width: 400px; max-width: 94vw;
  padding: var(--e-28) var(--e-32);
  border-radius: var(--radius-lg);
  display: flex; flex-direction: column; align-items: center;
  gap: var(--e-16); text-align: center;
  animation: cardIn var(--t-moyen) var(--ease);
}
.confirm-icon {
  width: 52px; height: 52px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(var(--th-danger-rgb),0.1); border: 1px solid rgba(var(--th-danger-rgb),0.2);
  color: var(--ose-text); flex-shrink: 0;
}
.confirm-body { display: flex; flex-direction: column; gap: var(--e-6); }
.confirm-title { font-size: var(--t-body); font-weight: var(--fw-gras); color: var(--text); }
/* pre-line : les messages de confirmation sont posés en textContent et comptent sur
   leurs sauts de ligne pour séparer l'objet visé de l'avertissement. */
.confirm-msg   { font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-aere); white-space: pre-line; }
.confirm-actions { display: flex; gap: var(--e-10); justify-content: center; }

.alert-card {
  background: var(--bg-panel-solid);
  border: 1px solid var(--border-strong);
  position: relative;
  z-index: 1;
  width: 460px;
  max-width: 94vw;
  padding: var(--e-32) 36px;
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-18);
  text-align: center;
  animation: cardIn var(--t-moyen) var(--ease);
}
.alert-icon-wrap {
  width: 58px; height: 58px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--danger-fond);
  border: 1px solid rgba(var(--th-danger-rgb),0.25);
  color: var(--ose-text);
  flex-shrink: 0;
}
.alert-icon-wrap.billing {
  background: rgba(234,179,8,0.12);
  border-color: rgba(234,179,8,0.3);
  color: var(--tier-luxe-text);
}
.alert-body { display: flex; flex-direction: column; gap: var(--e-8); }
.alert-title {
  font-size: var(--t-body);
  font-weight: var(--fw-gras);
  color: var(--text);
}
.alert-msg {
  font-size: var(--t-small);
  color: var(--text-2);
  line-height: var(--lh-aere);
  white-space: pre-wrap;
}

/* ── Toast ───────────────────────────────────────────── */
/* ══ LES NOTIFICATIONS : DES BULLES DE BANDE DESSINÉE ═══════════════════════
   Amadou (27/08) : « ça doit être sous forme de bulles, mais la bulle doit être belle.
   La bulle de BD que je t'ai envoyée — et les petites bulles doivent partir de la
   bordure du coin en bas à droite. » Variante retenue : D, bosses inégales, tracé qui a
   l'air fait à la main.

   ⚠️⚠️ LE NUAGE EST GÉNÉRÉ À LA BONNE TAILLE (`_nuageTrace`, app.js), il n'est pas étiré.
   Un dessin fixe mis à la largeur d'un message long voit ses bosses s'aplatir et ses
   cercles devenir des ovales : il cesse d'être un nuage. Chaque bosse est un arc de
   cercle recalculé pour la largeur réelle.
   ⚠️ LA MARGE DE 16 px SERT AUX BOSSES. Elles débordent du rectangle du contenu : sans
   cette réserve, elles seraient coupées par le bord de l'élément. */
#toast-container {
  position: fixed;
  bottom: var(--e-16); right: var(--e-16);
  z-index: 400;
  display: flex;
  flex-direction: column;
  gap: 0;
  pointer-events: none;
  /* ⚠️⚠️⚠️ SANS CECI, LE CONTENEUR NE S'ADAPTAIT PAS AU TEXTE. Mesuré : il restait planté
     à la `min-width` du bandeau, et TOUT message plus long passait à la ligne pour rien —
     « 24 produits classés sur Vinted » tenait sur une ligne en 244 px, il en occupait deux
     et le nuage montait à 75 px de haut au lieu de 56. C'est l'essentiel de ce qu'Amadou
     appelait « beaucoup trop grand » : ce n'était pas la police, c'était un retour à la
     ligne inutile. Le plafond garde les messages longs raisonnables, et laisse la place
     aux petits écrans. */
  width: max-content;
  /* ⚠️ PAS DE `vw` ICI. Écrit d'abord `min(340px, calc(100vw - 40px))` : mesuré, la règle
     tombait à 0 et le conteneur disparaissait. Le plafond en dur suffit — 340 px plus les
     16 px de marge tiennent dans le plus étroit des téléphones. */
  max-width: 340px;
}
.toast {
  position: relative;
  padding: var(--e-18) var(--e-20) var(--e-18) var(--e-18);   /* 15 px de réserve pour les bosses (_NUAGE_MARGE), plus le confort */
  font-size: var(--t-base);
  color: var(--text);
  /* ⚠️⚠️ LE POP PART DU COIN OÙ LES NUAGES VIVENT. `transform-origin` à 85 % / 60 %
     et non au centre : les notifications sont ancrées en bas à droite, une bulle qui
     grossit depuis son centre pousse vers la gauche et fait bouger la pile entière.
     Depuis ce point-là, elle gonfle sur place. C'est aussi le point d'où le coup de
     vent l'arrache. */
  transform-origin: 85% 60%;
  animation: toastPop var(--t-long) var(--c-rebond) both;
  pointer-events: all;
  display: flex;
  align-items: center;
  gap: var(--e-8);
  min-width: 200px; max-width: 100%;   /* c'est le conteneur qui plafonne, pas le bandeau */
  /* ⚠️⚠️ PAS DE CHEVAUCHEMENT — ET LE COMMENTAIRE MENTAIT. Il disait « pas de
     chevauchement » au-dessus d'un décalage de −20 px : mesuré à l'écran, les bosses du
     bas d'un nuage entraient de 12 px dans les bosses du haut du suivant, et trois
     messages empilés se lisaient comme un enchevêtrement. Les 15 px de réserve de chaque
     bord rapprochent DÉJÀ les nuages : il ne faut rien retirer en plus. */
  margin-bottom: 0;
}
.toast:last-child { margin-bottom: 0; }

.toast-nuage { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; }
.toast-nuage-t {
  fill: var(--th-carte);
  /* ⚠️⚠️ UN CONTOUR DE BD EST UN TRAIT D'ENCRE, PAS UN FILET DE CARTE. `--border-strong`
     vaut 23 % de `--th-trait` : mesuré, le nuage n'avait tout simplement pas de contour,
     il ne tenait que par son remplissage — et sur un thème clair, un remplissage clair
     sur un fond clair, c'est une silhouette qui disparaît. C'est le piège déjà consigné
     plus haut sur `--cok-inactif` : un même alpha ne vaut pas la même chose selon la
     clarté du fond. On prend donc le jeton de TEXTE le plus sourd, que le socle garantit
     lisible sur les dix-sept thèmes. */
  stroke: var(--text-3);
  stroke-width: 1.6;
  stroke-linejoin: round;
}
/* ⚠️ SUR UNE ERREUR, C'EST LE CONTOUR DU NUAGE QUI ROUGIT — pas une bande sur le côté.
   Amadou les a déjà refusées sur les blocs d'avis : « les petites bandes sur le côté de
   couleur, ce n'est pas beau visuellement. » */
/* ══ L'OMBRE PORTÉE, TEINTÉE PAR L'ÉTAT ══════════════════════════════════════
   ⚠️⚠️ `color-mix` AVEC `transparent`, ET NON UN ALPHA. Le projet n'a de canaux RVB
   que pour l'accent, le second et le danger : `rgba(var(--green), .26)` n'existe pas
   et ne peut pas exister. `color-mix` marche pour les QUATRE états avec une seule
   écriture — c'est déjà comme ça que le contour ambre est obtenu.
   ⚠️ 26 % et pas plus : au-delà l'ombre se lit comme un second nuage derrière le
   premier, et on ne voit plus une bulle en relief mais deux bulles mal calées. */
.toast              { --nuage-ombre: color-mix(in srgb, var(--th-accent) 26%, transparent); }
.toast.success      { --nuage-ombre: color-mix(in srgb, var(--green)     26%, transparent); }
.toast.warning      { --nuage-ombre: color-mix(in srgb, var(--amber)     26%, transparent); }
.toast.error        { --nuage-ombre: color-mix(in srgb, var(--red)       26%, transparent); }
/* ⚠️⚠️⚠️ LE FLOU N'EST PAS UNE COQUETTERIE, C'EST CE QUI FAIT L'ÉPAISSEUR. Posée nette,
   l'ombre montre son PROPRE feston de bosses à côté de celui du corps : on ne lit plus
   un nuage en relief, on lit deux nuages empilés et mal calés. Mesuré à l'écran le
   27/08 sur trois variantes — nette à 26 %, floutée, et pâle à 15 % : seule la floutée
   se lit comme une profondeur, les deux autres montrent leur contour.
   ⚠️ 3 px, pas plus : la zone de filtre par défaut d'un SVG déborde de 10 % de la boîte,
   et le corps ne laisse que 15 px de réserve. À 3 px, le bord flou s'arrête à 5 px du
   bord de la boîte — donc rien n'est recoupé, ce qui se verrait tout de suite sur les
   petites bulles de la traînée. */
.toast-nuage-o      { fill: var(--nuage-ombre); stroke: none; filter: blur(3px); }

.toast.error .toast-nuage-t { stroke: rgba(var(--th-danger-rgb), .55); }
/* ⚠️⚠️ L'ORANGE N'AVAIT JAMAIS SERVI. Relevé sur les 777 notifications : 437 rouges,
   258 vertes, 91 grises et ZÉRO orange — alors que l'icône ambre était déjà dessinée.
   Tout ce qui veut dire « il manque quelque chose à remplir » sortait donc en rouge
   alarmant. 61 consignes sont passées en orange ; il leur fallait aussi un contour, sinon
   seule l'icône changeait et le nuage restait muet.
   ⚠️ On ne peut pas diluer l'ambre à l'alpha : le projet n'a de canaux RVB que pour
   l'accent, le second et le danger. Et un alpha au jugé ne vaut pas la même chose selon la
   clarté du fond. On MÉLANGE donc l'ambre au jeton de texte sourd, que le socle garantit
   lisible sur les dix-sept thèmes. */
.toast.warning .toast-nuage-t { stroke: color-mix(in srgb, var(--amber) 68%, var(--text-3)); }

/* ⚠️ L'icône seule porte la couleur : le projet n'a de canaux RVB que pour l'accent, le
   second et le danger — aucun jeton n'existe pour teinter du vert ou de l'ambre. */
.toast-icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; }
.toast.success .toast-icon { color: var(--green); }
.toast.warning .toast-icon { color: var(--amber); }
.toast.error   .toast-icon { color: var(--red); }
/* (Les règles de `.toast-close` sont retirées : la croix n'existe plus, elle est
   remplacée par le glissement vers la droite. Deux autres listes de sélecteurs la
   nomment encore plus bas — inoffensif, mais c'est du poids mort à ne pas rallumer.) */

/* ══ CHASSER UNE BULLE À LA MAIN ══════════════════════════════════════════════
   ⚠️ `cursor: grab` sur toute la bulle : c'est la seule chose à l'écran qui annonce
   qu'on peut l'attraper, maintenant que la croix a disparu.
   ⚠️⚠️ `touch-action: pan-y` — SANS ÇA LE GESTE N'EXISTE PAS AU DOIGT. Le navigateur
   s'approprie le glissement horizontal pour son propre défilement et n'envoie jamais
   les `pointermove` : on garde le défilement vertical de la page, on prend l'horizontal.
   ⚠️ `user-select: none` pendant le geste seulement : hors geste, le texte d'une
   notification doit rester copiable. */
.toast { cursor: grab; touch-action: pan-y; }
.toast.glisse { cursor: grabbing; user-select: none; }
.toast.glisse, .toast.glisse * { user-select: none; }
/* ══ LE POP ET LE COUP DE VENT ═══════════════════════════════════════════════
   Amadou (27/08), après maquette : « qu'elles apparaissent avec un petit pop et
   qu'elles disparaissent comme s'il y avait eu un coup de vent ».
   ⚠️ LE DÉPASSEMENT FAIT LE POP, pas la durée. Une bulle qui va de 0 à 100 % en
   ligne droite n'a aucun ressort, si lente soit-elle ; celle-ci passe par 107 % à
   60 % du temps puis se repose. La courbe `--c-rebond` existait déjà pour ça.
   ⚠️ ET LE RECUL FAIT LE VENT. Sans les 14 px vers la GAUCHE au quart du temps, la
   bulle glisse vers la droite au lieu d'être emportée : c'est ce petit appel d'air
   qui fait croire au souffle. Le `skewX` la penche comme un tissu qui claque, et
   l'échelle qui tombe à 55 % l'éloigne au lieu de la faire simplement sortir. */
@keyframes toastPop {
  0%   { opacity: 0; transform: scale(.62); }
  60%  { opacity: 1; transform: scale(1.07); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes toastVent {
  0%   { opacity: 1; transform: translate(0, 0) rotate(0) scale(1); }
  25%  { transform: translate(-14px, 2px) rotate(-3deg) scale(1.03); }
  100% { opacity: 0; transform: translate(300px, -26px) rotate(16deg) scale(.55) skewX(-14deg); }
}
/* ⚠️ Pas de jeton pour cette durée : les trois du socle (.12 / .22 / .34) sont des
   durées d'INTERFACE, et un coup de vent est une scène — comme `--studio-coule`.
   On lui donne son nom plutôt que d'écrire un nombre au milieu d'une règle. */
.toast { --nuage-vent: .46s; }
.toast.out { animation: toastVent var(--nuage-vent) var(--c-sortie) forwards; }
@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
  .toast.out { animation: toastFondu var(--t-moyen) linear forwards; }
  @keyframes toastFondu { to { opacity: 0; } }
}

/* ── Spinner ─────────────────────────────────────────── */
.spin { animation: spin 0.9s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ═══════════════════════════════════════════════════════
   HISTORIQUE
   ═══════════════════════════════════════════════════════ */

/* Sticky bar wrapper.
   ⚠️ Elle était calée sur `top: 60px`, la hauteur de l'ancien en-tête. Depuis la
   refonte l'en-tête de l'Historique fait ~122 px (grand titre + chemin de retour) :
   la barre se figeait DERRIÈRE lui, invisible et non cliquable. Elle suit maintenant
   la hauteur réelle, mesurée par _stickyOffsets() (app.js), et porte enfin un fond —
   sans lui, les cartes défilaient à travers une fois la barre visible. */
.hist-sticky-bar {
  position: sticky;
  top: var(--topbar-h, 76px);
  z-index: 9;
  background: rgba(var(--th-panneau-rgb),0.78);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  border-bottom: 1px solid var(--border);
  margin: 0 calc(var(--e-32) * -1) var(--e-16);
  padding: var(--e-12) var(--e-32);
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}

/* Toolbar : search + date dropdown + Sélectionner */
.hist-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-10);
  align-items: center;
  margin-bottom: 0;
}

/* Le filtre packs est retiré du design — on le masque */
#hist-pack-filter { display: none; }

/* Search input — pill 38 px avec icône loupe à gauche */
.hist-search-wrap {
  flex: 1;
  min-width: 240px;
  display: flex;
  align-items: center;
  gap: var(--e-8);
  height: 38px;
  padding: 0 var(--e-12);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose);
  color: var(--text-3);
}
.hist-search-wrap:focus-within {
  border-color: var(--violet-glow);
  background: rgba(var(--th-voile),0.04);
}
.hist-search-wrap svg { flex-shrink: 0; }
.hist-search {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  height: 100%;
  padding: 0;
}
.hist-search::placeholder { color: var(--text-3); }

/* Sélecteur date — restyle natif <select> en bouton pill */
.hist-pack-select {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 var(--e-32) 0 var(--e-14);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  color: var(--text-2);
  font-size: var(--t-small);
  font-family: inherit;
  font-weight: var(--fw-normal);
  cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239AA0B5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px 12px;
  transition: background-color var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
}
.hist-pack-select:hover {
  background-color: var(--bg-sidebar);
  color: var(--text);
}
.hist-pack-select:focus { outline: none; border-color: var(--violet-glow); }

/* Bouton Sélectionner — pill ghost, devient violet-tint en mode actif */
.hist-mode-select-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  margin-left: auto;
  height: 38px;
  padding: 0 var(--e-14);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  white-space: nowrap;
  flex-shrink: 0;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--t-bref) var(--c-rebond);
}
.hist-mode-select-btn:hover { background: var(--bg-sidebar); color: var(--text); }
.hist-mode-select-btn.active {
  background: var(--violet-tint);
  color: var(--violet-soft);
  border-color: rgba(var(--th-accent-rgb),0.28);
}

/* Compteur "22 générations" sous la toolbar — scrolle avec le contenu (hors sticky) */
.hist-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-12);
  font-size: var(--t-meta);
  color: var(--text-3);
  margin: var(--e-14) var(--e-2) var(--e-8);
}
.hist-meta-count-em {
  color: var(--text-2);
  font-weight: var(--fw-moyen);
  font-variant-numeric: tabular-nums;
}

/* Groupes par date — la group-head est insérée comme enfant du .hist-grid
   en full-width via grid-column 1/-1, pour éviter de découper la grille. */
.hist-group {
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
}
.hist-grid .hist-group-head { grid-column: 1 / -1; }
.hist-group-head {
  display: flex;
  align-items: baseline;
  gap: var(--e-10);
  padding: var(--e-8) var(--e-2) 0;
}
.hist-load-more-wrap { grid-column: 1 / -1; display: flex; justify-content: center; padding: var(--e-16) 0 var(--e-4); }
.hist-load-more { font-size: var(--t-base); padding: var(--e-10) var(--e-20); }
.hist-grid .hist-group-head:first-child { padding-top: 0; }
.hist-group-title {
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
}
.hist-group-count {
  font-size: var(--t-mini);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}

/* Grid : 6 cols, responsive 6→5→4→3 */
.hist-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
  gap: var(--e-16);
}

.hist-empty {
  grid-column: 1/-1;
  text-align: center;
  padding: 80px 0;
  color: var(--text-3);
  font-size: var(--t-small);
}

/* Card — wrapper 6 px padding pour image légèrement enclavée */
.hist-card {
  display: flex;
  flex-direction: column;
  padding: var(--e-6);
  background: linear-gradient(158deg, rgba(var(--th-voile),0.042) 0%, rgba(var(--th-voile),0.012) 55%);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  cursor: pointer;
  position: relative;
  box-shadow: 0 5px 18px -12px rgba(var(--th-ombre),0.55), inset 0 1px 0 var(--bg-sidebar);
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
.hist-card:hover {
  border-color: var(--violet-mid);
  transform: translateY(-3px);
  box-shadow: 0 16px 34px -14px rgba(var(--th-accent-rgb),0.5), inset 0 1px 0 var(--bg-elevated);
}
.hist-card.selected {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.32);
}
.hist-card.selected .hist-card-cb {
  opacity: 1;
  background: var(--violet);
  border-color: var(--violet);
  color: var(--sur-accent);
}

/* Checkbox overlay (mode sélection) */
.hist-card-cb {
  position: absolute; top: 14px; left: 14px; z-index: 4;
  width: 18px; height: 18px; border-radius: var(--r-micro);
  background: rgba(var(--th-ombre),0.62);
  border: 1px solid rgba(var(--th-voile),0.22);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; color: transparent;
  transition: opacity var(--t-moyen), background var(--t-moyen), color var(--t-moyen), border-color var(--t-moyen);
  pointer-events: none;
}
.hist-card.select-mode .hist-card-cb { opacity: 1; }
.hist-card.select-mode:hover .hist-card-cb { border-color: var(--violet); }

/* Tier pill (top-left) + views badge (top-right) */
.hist-card-tier {
  position: absolute;
  top: 14px; left: 14px;
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 var(--e-8);
  border-radius: var(--r-micro);
  background: rgba(var(--th-ombre),0.62);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-ample);
  white-space: nowrap;
  line-height: var(--lh-un);
  z-index: 3;
}
.hist-card-tier[data-tier="volume"]  { color: var(--tier-volume-text); }
.hist-card-tier[data-tier="premium"] { color: var(--tier-premium-text); }
.hist-card-tier[data-tier="luxe"]    { color: var(--tier-luxe-text); }
.hist-card.select-mode .hist-card-tier { display: none; }

.hist-card-views {
  position: absolute;
  top: 14px; right: 14px;
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
  height: 18px;
  padding: 0 var(--e-6);
  border-radius: var(--r-micro);
  background: rgba(var(--th-ombre),0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  color: rgba(235,235,236,0.75);
  letter-spacing: var(--ls-zero);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-un);
  z-index: 3;
}
.hist-card-views svg { opacity: 0.85; }

/* Barre de sélection */
.hist-confirm-msg {
  font-size: var(--t-base); color: var(--text-2);
}
.hist-confirm-msg strong { color: var(--ose-text); }
.lib-confirm-warn { color: var(--amber); font-weight: var(--fw-fort); }
.hist-confirm-actions { display: flex; align-items: center; gap: var(--e-8); margin-left: auto; }

/* ⚠️ UNE BARRE D'OUTILS, PAS UN BANDEAU. Amadou (25/08) : « l'affichage est vraiment
   moche, il prend trop de place ». Elle occupait 80 px de haut sur toute la largeur, avec
   un cadre d'accent plein — pour un état de travail passager. Elle s'assagit : moins de
   hauteur, un filet plutôt qu'un cadre vif, et ses actions n'apparaissent qu'une fois
   quelque chose de coché (voir `updateLibSelectCount`). */
.hist-select-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-6) var(--e-12);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  margin-bottom: 0;
  gap: var(--e-10);
  flex-wrap: wrap;
}
/* Elle se distingue quand même de la grille : un liseré d'accent à gauche, pas un cadre
   qui crie. On est en train de choisir, ce n'est pas une alerte. */
.hist-select-bar { border-left: 2px solid var(--violet); }
.hist-select-right.hidden { display: none; }

/* ⚠️ LES TROIS BOUTONS DE LA BARRE ONT LE MÊME GABARIT. Amadou (25/08) : « les boutons
   utilisés ne sont vraiment pas beaux ». Ils venaient de trois familles différentes —
   `hist-select-all-btn`, `btn-danger-sm`, `btn-ghost` — donc trois hauteurs, trois rayons
   et trois graisses côte à côte. On aligne le gabarit ; seule la COULEUR distingue le
   geste destructeur, ce qui est le seul écart qui mérite d'être vu. */
#lib-select-bar .hist-select-all-btn,
#lib-select-bar #lib-delete-selected,
#lib-select-bar .hist-select-cancel,
/* ⚠️⚠️⚠️ « MIGRER » MANQUAIT DANS CETTE LISTE — et c'est la DEUXIÈME liste de cette même
   barre où il avait été oublié (l'autre est celle qui réveille les boutons). Amadou
   (07/09) : « le bouton doit être le même que le bouton supprimer, annuler. Là il est
   différent, ça doit avoir la même taille. » Mesuré à l'écran avant de corriger :
   Supprimer et Annuler à 34 px de haut et 12 px de texte, Migrer à 28 px et 13 px.
   ⚠️ ON L'AJOUTE ICI PLUTÔT QUE D'ÉCRIRE UNE SECONDE RÈGLE. Ma première correction en
   posait une à part — elle donnait 13 px là où la barre en veut 12 : deux règles pour un
   même gabarit, et c'est la mienne qui s'est trompée de sens. */
#lib-select-bar .lib-bulk-btn {
  /* ⚠️ `min-height` AUSSI. « Annuler » porte `btn-ghost`, dont la règle groupée pose
     `min-height: 34px` : une hauteur seule ne peut pas descendre sous un plancher, et il
     restait 4 px plus haut que ses deux voisins. Fixer la hauteur sans lever le plancher,
     c'est demander sans obtenir. */
  /* ⚠️ 34 px, LA TAILLE DE « Filtres » ET « Sélectionner » (Amadou, 25/08 : « les boutons
     sélectionnés devraient faire la même taille que le bouton filtre »). Trois boutons
     d'une même barre plus petits que ceux de la barre du dessus, ça se voit : l'œil lit
     deux rangées qui ne s'accordent pas. */
  height: 34px; min-height: 34px;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--e-6);
  padding: 0 var(--e-12);
  border-radius: var(--r-sm);
  font-size: var(--t-meta); font-weight: var(--fw-moyen);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  transition: border-color var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
#lib-select-bar .hist-select-all-btn:hover,
#lib-select-bar .hist-select-cancel:hover { border-color: var(--border-strong); color: var(--text); }
/* Le geste sans retour se dit par la couleur du TEXTE, pas par un pavé rouge — même règle
   que dans les menus. */
#lib-select-bar #lib-delete-selected {
  color: var(--red); border-color: rgba(var(--th-danger-rgb), .34); background: transparent;
}
#lib-select-bar #lib-delete-selected:hover:not(:disabled) {
  border-color: var(--red); background: rgba(var(--th-danger-rgb), .1);
}
#lib-select-bar #lib-delete-selected:disabled { opacity: .4; cursor: default; }
/* Le compte se lit, il ne se clique pas : il n'a pas à porter un cadre de bouton. */
#lib-select-bar .hist-select-count { font-size: var(--t-meta); color: var(--text-3); }
.hist-select-left { display: flex; align-items: center; gap: var(--e-12); }
/* ⚠️ LES ACTIONS SE COLLENT À DROITE, contre « Annuler ». Amadou (25/08) : « Supprimer doit
   être tout à droite à côté du bouton Annuler, là il est beaucoup trop loin ».
   La barre est en `space-between` : avec trois blocs, celui du milieu se retrouvait au
   centre d'une barre de 1600 px, à mi-chemin de tout et près de rien. Un geste et sa
   sortie se tiennent côte à côte. */
.hist-select-right { display: flex; align-items: center; gap: var(--e-8); margin-left: auto; }
.lib-bulk-btn {
  display: inline-flex; align-items: center; gap: var(--e-4);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--t-meta);
  font-family: inherit;
  padding: 0 var(--e-10);
  height: 28px;
  cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen);
}
.lib-bulk-btn:not(:disabled):hover { border-color: var(--violet); color: var(--text); }
.lib-bulk-btn:disabled { opacity: .35; cursor: not-allowed; }
.lib-bulk-sep { width: 1px; height: 18px; background: var(--border); margin: 0 var(--e-2); flex-shrink: 0; }
.lib-bulk-scope-commun:not(:disabled):hover { border-color: var(--violet); background: rgba(var(--th-accent-rgb),.08); color: var(--violet); }
.lib-bulk-scope-perso:not(:disabled):hover  { border-color: var(--border-strong); background: var(--surface-2); }
.hist-select-all-btn {
  display: flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-xl); cursor: pointer; padding: var(--e-4) var(--e-12);
  transition: var(--transi); white-space: nowrap;
}
.hist-select-all-btn:hover {
  border-color: var(--violet-mid); color: var(--violet-light);
  background: rgba(var(--th-accent-rgb),0.1);
}
.hist-select-count { font-size: var(--t-base); color: var(--text-3); }
.btn-danger-sm {
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-12); font-size: var(--t-base); font-weight: var(--fw-fort);
  background: var(--danger-fond); color: var(--ose-text);
  border: 1px solid rgba(var(--th-danger-rgb),0.3); border-radius: var(--radius-sm);
  cursor: pointer; transition: var(--transi);
}
.btn-danger-sm:hover:not(:disabled) { background: rgba(var(--th-danger-rgb),0.2); border-color: var(--ose-text); }
.btn-danger-sm:disabled { opacity: 0.4; cursor: not-allowed; }
.hist-select-cancel { font-size: var(--t-base); padding: var(--e-6) var(--e-12); }
.hist-card-cover {
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
  overflow: hidden;
  background:
    linear-gradient(135deg, var(--bg-hover) 0%, rgba(var(--th-voile),0.015) 100%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.hist-card-cover img { width: 100%; height: 100%; object-fit: cover; }
.hist-card-cover-placeholder { color: var(--text-3); opacity: 0.5; }

/* Couverture 3 colonnes Face/Biais/Dos (mode "trois vues" si dispo) */
.hist-card-three-col {
  display: flex;
  width: 100%;
  height: 100%;
  gap: var(--e-1);
  background: rgba(var(--th-voile),0.04);
}
.hist-card-col-cell {
  flex: 1;
  overflow: hidden;
  background: rgba(var(--th-panneau-rgb),0.6);
}
.hist-card-col-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hist-card-col-cell.empty { opacity: 0.25; }
.hist-card-status {
  position: absolute;
  top: 8px;
  left: 8px;
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  padding: var(--e-2) var(--e-8);
  border-radius: var(--r-xl);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  cursor: pointer;
  transition: opacity var(--t-moyen);
  user-select: none;
}
.hist-card-status:hover { opacity: 0.8; }
.hist-card-status.draft     { background: rgba(148,163,184,0.18); color: var(--text-2); border: 1px solid rgba(148,163,184,0.3); }
.hist-card-status.published { background: var(--tier-premium-bg);  color: var(--violet-light); border: 1px solid rgba(var(--th-accent-rgb),0.35); }
.hist-card-status.sold      { background: rgba(34,197,94,0.15);   color: var(--safe-text); border: 1px solid rgba(34,197,94,0.3); }
.hist-card-status.withdrawn { background: rgba(251,146,60,0.15);  color: var(--moy-text); border: 1px solid rgba(251,146,60,0.3); }
.hist-card-quick {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  opacity: 0;
  transition: opacity var(--t-moyen);
}
.hist-card:hover .hist-card-quick { opacity: 1; }
.hist-quick-btn {
  width: 28px;
  height: 28px;
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-voile),0.12);
  background: rgba(var(--th-panneau-rgb),0.75);
  backdrop-filter: blur(4px);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background var(--t-moyen);
}
.hist-quick-btn:hover { background: rgba(var(--th-accent-rgb),0.6); }
.hist-quick-btn.danger:hover { background: rgba(var(--th-danger-rgb),0.55); }
.hist-card-info {
  padding: var(--e-10) var(--e-8) var(--e-6);
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  min-width: 0;
}
.hist-card-name {
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: var(--lh-serre);
  margin-bottom: 0;
}
.hist-card-meta {
  display: flex;
  align-items: center;
  gap: var(--e-6);
  font-size: var(--t-mini);
  color: var(--text-3);
  flex-direction: row;
  line-height: var(--lh-serre);
  min-width: 0;
}
.hist-card-meta > span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.hist-card-meta-sep {
  opacity: 0.6;
  flex-shrink: 0;
}
.hist-card-actions {
  display: flex;
  gap: var(--e-6);
  margin-top: var(--e-8);
}
.hist-action-btn {
  flex: 1;
  padding: var(--e-6) 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-4);
}
.hist-action-btn:hover { border-color: var(--violet-mid); color: var(--violet-light); background: var(--surface); }

/* Detail view */
.hist-detail-layout {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: var(--e-28);
  align-items: start;
}
@media (max-width: 860px) {
  .hist-detail-layout { grid-template-columns: 1fr; }
}
.hist-detail-visuals {}
.hist-detail-visuals-title {
  font-size: var(--t-meta);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-ample);
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--e-12);
}
.hist-visuals-title-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--e-12);
}
.hist-visuals-title-row .hist-detail-visuals-title { margin-bottom: 0; }
.hist-dl-all-btn {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--t-meta); font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
}
.hist-dl-all-btn:hover {
  border-color: var(--violet);
  background: rgba(var(--th-accent-rgb),0.1);
  color: var(--violet-light);
}
.hist-visual-dl-btn {
  position: absolute;
  top: 6px;
  left: 6px;
  width: 24px; height: 24px;
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-voile),0.15);
  background: rgba(var(--th-panneau-rgb),0.75);
  backdrop-filter: blur(4px);
  color: var(--text-2);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-moyen), background var(--t-moyen);
  z-index: 2;
}
.hist-visual-item:hover .hist-visual-dl-btn { opacity: 1; }
.hist-visual-dl-btn:hover { background: rgba(var(--th-second-rgb),0.55); color: var(--text); }
.hist-visuals-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--e-10);
  margin-bottom: var(--e-16);
}
.hist-visual-item {
  aspect-ratio: 3/4;
  border-radius: var(--r-sm);
  overflow: hidden;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: border-color var(--t-moyen);
  position: relative;
}
.hist-visual-item:hover { border-color: var(--violet-mid); }
.hist-visual-item img { width: 100%; height: 100%; object-fit: cover; }
.hist-visual-regen-btn {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-voile),0.15);
  background: rgba(var(--th-panneau-rgb),0.75);
  backdrop-filter: blur(4px);
  color: var(--text-2);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-moyen), background var(--t-moyen);
  z-index: 2;
}
.hist-visual-item:hover .hist-visual-regen-btn { opacity: 1; }
.hist-visual-regen-btn:hover { background: rgba(var(--th-accent-rgb),0.6); color: var(--sur-accent); }
.hist-visual-label {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: var(--e-4) var(--e-6);
  background: rgba(var(--th-panneau-rgb),0.7);
  font-size: var(--t-micro);
  color: var(--text-2);
  text-align: center;
}
.hist-versions-bar {
  display: flex;
  gap: var(--e-6);
  margin-bottom: var(--e-16);
  flex-wrap: wrap;
}
.hist-version-btn {
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-3);
  font-size: var(--t-meta);
  cursor: pointer;
  transition: var(--transi);
}
.hist-version-btn.active { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }
.hist-detail-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-20);
  display: flex;
  flex-direction: column;
  gap: var(--e-16);
  position: sticky;
  top: 20px;
}
.hist-panel-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-8);
}
.hist-panel-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  color: var(--text-3);
  margin-bottom: var(--e-4);
}
.hist-panel-status-wrap { display: flex; align-items: center; gap: var(--e-8); }
.hist-status-select {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  font-size: var(--t-base);
  font-family: inherit;
  padding: var(--e-6) var(--e-10);
  cursor: pointer;
}
.hist-status-select:focus { outline: none; border-color: var(--violet); }
.hist-vinted-url-wrap { display: flex; flex-direction: column; gap: var(--e-6); }
.hist-vinted-url-input {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--t-base);
  font-family: inherit;
  padding: var(--e-8) var(--e-10);
  width: 100%;
  box-sizing: border-box;
  transition: border-color var(--t-moyen);
}
.hist-vinted-url-input:focus { outline: none; border-color: var(--violet); }
.hist-vinted-url-link {
  font-size: var(--t-meta);
  color: var(--violet-light);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
}
.hist-vinted-url-link:hover { color: var(--violet); }
.hist-text-block {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--e-10) var(--e-12);
  font-size: var(--t-base);
  color: var(--text);
  line-height: var(--lh-normal);
  white-space: pre-wrap;
  word-break: break-word;
}
.hist-notes-wrap { display: flex; flex-direction: column; gap: var(--e-6); }
.hist-notes-area {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--e-10) var(--e-12);
  font-size: var(--t-base);
  color: var(--text);
  line-height: var(--lh-normal);
  resize: vertical;
  outline: none;
  width: 100%;
  box-sizing: border-box;
  transition: border-color var(--t-moyen);
}
.hist-notes-area:focus { border-color: var(--violet-mid); }
.hist-notes-area::placeholder { color: var(--text-3); }

.hist-prices-row {
  display: flex;
  gap: var(--e-8);
}
.hist-price-chip {
  flex: 1;
  text-align: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--e-8) var(--e-4);
}
.hist-price-val {
  font-size: var(--t-small);
  font-weight: var(--fw-gras);
  color: var(--text);
}
.hist-price-lbl {
  font-size: var(--t-micro);
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: var(--ls-large);
  margin-top: var(--e-1);
}
.hist-panel-actions {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
}
.hist-panel-actions .btn-primary,
.hist-panel-actions .btn-secondary,
.hist-panel-actions .btn-ghost { width: 100%; justify-content: center; }
.hist-meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
  font-size: var(--t-meta);
  color: var(--text-3);
}
.hist-meta-chip {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-micro);
  padding: var(--e-2) var(--e-8);
}

/* ── LE POINT À DROITE D'UN ONGLET : UN SEUL DESSIN, TROIS SENS ──────────────
   Amadou (24/08) : une lueur pour dire que ça travaille, VERTE quand c'est fini, et sur
   Machines un signal de PROBLÈME — « c'est vraiment important ».
   ⚠️ Un seul jeu de règles pour les trois : le point d'« en cours » existait déjà pour la
   Génération, avec son propre nom (`generating`). Deux dessins du même point auraient
   fini par diverger — c'est exactement ce qui vient d'arriver trois fois ailleurs.
   `generating` reste comme SYNONYME d'« en cours » : huit endroits l'écrivent encore. */
/* ⚠️ NI LE NOM NI L'ICÔNE NE CHANGENT DE COULEUR POUR « EN COURS » NI POUR « FINI ».
   Amadou (24/08) : « la couleur où c'est juste pour informer que c'est fini ou que ça
   court, ça n'a pas besoin d'accentuer au point de mettre le nom de la couleur, et pareil
   pour le logo ». Ces deux-là racontent le travail du logiciel : le point suffit.
   Repeindre le nom leur donnerait le poids d'une alerte, et une colonne où plusieurs
   onglets sont colorés en même temps ne signale plus rien. Le rouge, lui, est seul et
   doit rester lisible d'un coup d'œil — c'est à cette condition qu'il garde sa force. */
.nav-item.nav--encours::after,
.nav-item.generating::after,
.nav-item.nav--fini::after,
.nav-item.nav--probleme::after {
  content: '';
  display: block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-left: auto;
  flex-shrink: 0;
}
.nav-item.nav--encours::after, .nav-item.generating::after {
  background: var(--violet-light);
  animation: genPulse 1.2s ease-in-out infinite;
}
/* FINI : vert, fixe, et il le reste jusqu'à ce qu'on ouvre l'onglet (Amadou : « non, il
   reste vert tant que je n'ai pas ouvert l'onglet »). Il ne bat pas : ce n'est plus un
   travail en cours, c'est un résultat qui attend d'être vu. */
.nav-item.nav--fini::after { background: var(--green); }
/* PROBLÈME : rouge, et il se signale sans clignoter — un halo qui respire lentement.
   Un point rouge qui clignote vite devient un décor au bout de dix minutes ; celui-ci
   doit encore attirer l'œil au bout d'une heure. */
.nav-item.nav--probleme { color: var(--red); }
.nav-item.nav--probleme::after {
  background: var(--red);
  animation: navHalo 2.4s ease-in-out infinite;
}
/* ⚠️⚠️ L'ONGLET OUVERT REPEIGNAIT L'ICÔNE PAR-DESSUS L'ALERTE. Amadou (24/08) : « quand
   j'appuie sur l'onglet machine, le logo doit rester rouge ». `.nav-item.active svg` est
   plus PRÉCIS que `.nav-item.nav--probleme` (il vise l'icône, pas le bouton) : il gagnait
   donc, et l'icône redevenait violette au moment même où l'on venait voir la panne.
   Il fallait une règle aussi précise, écrite après. */
.nav-item.nav--probleme svg { color: var(--red); }
/* ⚠️⚠️⚠️ ET LE SURVOL AUSSI REPEIGNAIT L'ALERTE. Amadou (27/08) : « quand je survole
   l'onglet Machines, le texte doit rester rouge — et pareil pour tous les onglets qui
   seront en rouge ». C'est EXACTEMENT le piège documenté six lignes plus haut, une
   seconde fois, par une autre porte. L'arithmétique, parce qu'elle ne se devine pas :
   `.nav-item:hover:not(:disabled)` compte TROIS sélecteurs simples — une classe, la
   pseudo-classe `:hover`, et `:disabled` qui compte À TRAVERS le `:not()`. En face,
   `.nav-item.nav--probleme` n'en compte que deux. Le survol gagnait donc, et l'alerte
   s'effaçait au moment précis où l'on venait la regarder.
   ⚠️ La règle est écrite sur `.nav--probleme` seul, JAMAIS sur « Machines » : n'importe
   quel onglet peut recevoir cette classe, et le jour où un deuxième la reçoit il doit se
   comporter pareil sans qu'on y repense. Le fond du survol, lui, reste — il dit « ta
   souris est ici », ce qui n'a rien à voir avec l'alerte. */
.nav-item.nav--probleme:hover:not(:disabled),
.nav-item.nav--probleme:hover:not(:disabled) svg { color: var(--red); }
/* Et le liseré de gauche suit : sur l'onglet ouvert, il marque « tu es ici » — en rouge,
   il dit aussi « et ça ne va pas ». Il reste réservé à l'onglet ACTIF : rouge sur un
   onglet qu'on n'a pas ouvert, il ferait croire qu'on s'y trouve. */
.nav-item.active.nav--probleme::before {
  background: var(--red);
  box-shadow: 0 0 12px rgba(var(--th-danger-rgb), .6);
}
@keyframes genPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%       { opacity: 0.3; transform: scale(0.6); }
}
@keyframes navHalo {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--th-danger-rgb), .55); }
  70%      { box-shadow: 0 0 0 5px rgba(var(--th-danger-rgb), 0); }
}

/* ═══════════════════════════════════════════════════════
   DASHBOARD — Aurora
   ═══════════════════════════════════════════════════════ */

/* Ancien header inline (.dash-greeting / .dash-title) — neutralisé,
   remplacé par la sticky topbar Aurora. On garde la règle au cas où
   le markup ne serait pas encore migré. */
.dash-greeting { display: none; }
.dash-title, .dash-subtitle { display: none; }

/* Bouton refresh icon (utilisé dans la topbar maintenant) */
.btn-icon-ghost {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border-radius: var(--r-sm);
  background: transparent;
  border: none;
  color: var(--text-3);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
  flex-shrink: 0;
}
.btn-icon-ghost:hover { background: var(--bg-elevated); color: var(--text); }
.btn-icon-ghost:disabled { opacity: 0.5; cursor: default; }
.btn-icon-ghost.spinning svg {
  animation: spin-once 0.6s var(--c-pose) forwards;
}
@keyframes spin-once {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* En-tête de section (ex : "Dernières générations") */
.dash-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: var(--e-4);
  gap: var(--e-12);
}
.dash-section-title {
  font-size: var(--t-body);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-serre);
  color: var(--text);
}
.dash-section-sub {
  font-size: var(--t-meta);
  color: var(--text-3);
}

/* ── KPI strip ──────────────────────────────────────── */
.dash-kpis {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--e-12);
}
@media (max-width: 980px) { .dash-kpis { grid-template-columns: repeat(2, 1fr); } }

.dash-kpi {
  background:
    radial-gradient(120% 90% at 100% 0%, var(--surface-2), transparent 55%),
    linear-gradient(158deg, var(--bg-sidebar) 0%, rgba(var(--th-voile),0.012) 55%);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-20);
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
  min-width: 0;
  position: relative;
  overflow: hidden;
  transition: transform var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
  box-shadow: 0 6px 24px -14px rgba(var(--th-ombre),0.6), inset 0 1px 0 var(--bg-hover);
}
/* Filet coloré lumineux en haut de chaque carte (selon la couleur du KPI) */
.dash-kpi::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  opacity: 0.75; pointer-events: none;
}
.dash-kpi--violet::before { background: linear-gradient(90deg, transparent, var(--violet-light), transparent); }
.dash-kpi--cyan::before   { background: linear-gradient(90deg, transparent, var(--cyan-soft), transparent); }
.dash-kpi--green::before  { background: linear-gradient(90deg, transparent, var(--safe-text), transparent); }
.dash-kpi--orange::before { background: linear-gradient(90deg, transparent, var(--moy-text), transparent); }

.dash-kpi:hover { transform: translateY(-2px); box-shadow: 0 14px 34px -16px rgba(var(--th-ombre),0.7), inset 0 1px 0 var(--bg-elevated); }
/* KPI actionnable : cliquable, va au bon endroit */
.dash-kpi--action { cursor: pointer; }
.dash-kpi--action:hover { border-color: var(--violet-mid); }
.dash-kpi--action:focus-visible { outline: 2px solid var(--violet-light); outline-offset: 2px; }
.dash-kpi--action .dash-kpi-sub { color: var(--violet-light); font-weight: var(--fw-fort); }
/* Emphase quand il y a quelque chose à traiter : halo de la couleur de la carte */
.dash-kpi--urgent.dash-kpi--violet {
  border-color: rgba(var(--th-accent-rgb),0.5);
  box-shadow: 0 0 0 1px var(--tier-premium-bg), 0 10px 34px -12px rgba(var(--th-accent-rgb),0.42), inset 0 1px 0 var(--bg-elevated);
}
.dash-kpi--urgent.dash-kpi--cyan {
  border-color: var(--rp-blue-mid);
  box-shadow: 0 0 0 1px var(--cyan-tint), 0 10px 34px -12px var(--cyan-glow), inset 0 1px 0 var(--bg-elevated);
}
.dash-kpi--urgent.dash-kpi--orange {
  border-color: rgba(229,194,138,0.45);
  box-shadow: 0 0 0 1px rgba(229,194,138,0.16), 0 10px 34px -12px rgba(229,194,138,0.38), inset 0 1px 0 var(--bg-elevated);
}
.dash-kpi--urgent.dash-kpi--violet .dash-kpi-value { color: var(--violet-light); }
.dash-kpi--urgent.dash-kpi--cyan   .dash-kpi-value { color: var(--cyan-soft); }
.dash-kpi--urgent.dash-kpi--orange .dash-kpi-value { color: var(--moy-text); }

/* Icône colorée — badge lumineux en haut-droite */
.dash-kpi-icon {
  position: absolute;
  top: 16px; right: 16px;
  width: 38px; height: 38px;
  border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.dash-kpi-icon svg { width: 18px; height: 18px; }
.dash-kpi-icon.violet { background: var(--violet-tint); color: var(--violet-light); box-shadow: 0 0 22px -6px rgba(var(--th-accent-rgb),0.5); }
.dash-kpi-icon.cyan   { background: var(--rp-blue-tint); color: var(--cyan-soft);   box-shadow: 0 0 22px -6px rgba(var(--th-second-rgb),0.4); }
.dash-kpi-icon.green  { background: rgba(110,210,168,0.14); color: var(--safe-text);   box-shadow: 0 0 22px -6px rgba(110,210,168,0.4); }
.dash-kpi-icon.orange { background: rgba(229,194,138,0.14); color: var(--moy-text);    box-shadow: 0 0 22px -6px rgba(229,194,138,0.4); }

/* Corps du KPI : label haut, value, sub (foot) bas — ordre via flex order
   car le rendu JS sort value/label/sub dans cet ordre DOM. */
.dash-kpi-body {
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  min-width: 0;
  padding-right: 50px;
}
.dash-kpi-label {
  order: 1;
  font-size: var(--t-mini);
  color: var(--text-3);
  letter-spacing: var(--ls-large);
  text-transform: uppercase;
  font-weight: var(--fw-moyen);
  line-height: var(--lh-serre);
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
.dash-kpi-value {
  order: 2;
  font-size: var(--t-2xl);
  font-weight: var(--fw-gras);
  letter-spacing: -0.025em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-un);
  margin-top: var(--e-8);
}
.dash-kpi-sub {
  order: 3;
  font-size: var(--t-mini);
  color: var(--text-3);
  margin-top: var(--e-6);
}
.dash-kpi-sub span { color: var(--violet-soft); font-weight: var(--fw-moyen); }

/* ── Quick actions ──────────────────────────────────── */
.dash-quickactions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--e-12);
  margin-bottom: 0;
}

.dash-qa-chip {
  background: linear-gradient(158deg, rgba(var(--th-voile),0.04) 0%, rgba(var(--th-voile),0.01) 55%);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-18) var(--e-20);
  display: flex;
  align-items: center;
  gap: var(--e-14);
  cursor: pointer;
  text-align: left;
  transition: transform var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
  width: 100%;
  min-width: 0;
  box-shadow: 0 6px 24px -14px rgba(var(--th-ombre),0.6), inset 0 1px 0 var(--bg-hover);
}
.dash-qa-chip:hover {
  transform: translateY(-2px);
  border-color: var(--violet-mid);
  box-shadow: 0 14px 32px -16px var(--tier-premium-glow), inset 0 1px 0 var(--bg-elevated);
}

.dash-qa-icon {
  width: 36px; height: 36px;
  border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  background: var(--violet-tint);
  color: var(--violet-soft);
}
.dash-qa-violet .dash-qa-icon { background: var(--violet-tint); color: var(--violet-soft); }
.dash-qa-cyan   .dash-qa-icon { background: var(--cyan-tint);   color: var(--cyan-soft); }
.dash-qa-neutral .dash-qa-icon { background: rgba(229,194,138,0.13); color: var(--moy-text); }

.dash-qa-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
}
.dash-qa-label {
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
}
.dash-qa-sub {
  font-size: var(--t-meta);
  color: var(--text-3);
  line-height: var(--lh-serre);
  max-width: none;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

/* ── Block (Dernières générations / À terminer) ─────── */
.dash-block {
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
  border-radius: 0;
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}
.dash-block-title {
  font-size: var(--t-body);
  font-weight: var(--fw-moyen);
  text-transform: none;
  letter-spacing: var(--ls-serre);
  color: var(--text);
  margin-bottom: 0;
}

/* Status block */
.dash-status-bar-track {
  height: 8px;
  border-radius: var(--r-pilule);
  background: var(--border);
  overflow: hidden;
  display: flex;
  margin-bottom: var(--e-16);
}
.dash-status-bar-seg {
  height: 100%;
  transition: width 0.6s var(--c-pose);
}
.dash-status-bar-seg.draft     { background: #6B7184; }
.dash-status-bar-seg.published { background: var(--violet-light); }
.dash-status-bar-seg.sold      { background: var(--safe-text); }
.dash-status-bar-seg.withdrawn { background: var(--moy-text); }

.dash-status-pills {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}
.dash-status-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-10);
}
.dash-status-pill-left {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  font-size: var(--t-base);
  color: var(--text-2);
}
.dash-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.dash-status-dot.draft     { background: #6B7184; }
.dash-status-dot.published { background: var(--violet-light); }
.dash-status-dot.sold      { background: var(--safe-text); }
.dash-status-dot.withdrawn { background: var(--moy-text); }
.dash-status-pill-count {
  font-size: var(--t-base);
  font-weight: var(--fw-gras);
  color: var(--text);
}
.dash-status-pill-bar {
  flex: 1;
  height: 4px;
  border-radius: var(--r-pilule);
  background: var(--border);
  overflow: hidden;
  max-width: 100px;
}
.dash-status-pill-fill {
  height: 100%;
  border-radius: var(--r-pilule);
  transition: width 0.6s var(--c-pose);
}
.dash-status-pill-fill.draft     { background: #6B7184; }
.dash-status-pill-fill.published { background: var(--violet-light); }
.dash-status-pill-fill.sold      { background: var(--safe-text); }
.dash-status-pill-fill.withdrawn { background: var(--moy-text); }

/* ── Recent generations — grille 6 colonnes (gen-card) ── */
.dash-recent-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--e-12);
  overflow: visible;
  padding-bottom: 0;
}

.dash-recent-card {
  flex: none;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose);
}
.dash-recent-card:hover {
  background: rgba(var(--th-voile),0.04);
  border-color: var(--border);
  transform: none;
  box-shadow: none;
}
.dash-recent-cover {
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  background:
    linear-gradient(135deg, rgba(var(--th-voile),0.04) 0%, rgba(var(--th-voile),0.01) 100%),
    radial-gradient(80% 60% at 50% 35%, rgba(var(--th-accent-rgb),0.10), transparent 70%);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.dash-recent-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dash-recent-cover-ph { color: var(--text-3); opacity: 0.5; }
.dash-recent-info {
  padding: var(--e-10) var(--e-12) var(--e-12);
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  min-width: 0;
}
.dash-recent-name {
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0;
}
.dash-recent-date,
.dash-recent-cost {
  font-size: var(--t-mini);
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  margin-top: 0;
}
.dash-recent-empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: var(--e-40) 0;
  color: var(--text-3);
  font-size: var(--t-small);
}

/* ── Incomplete (À terminer) ────────────────────────── */
.dash-incomplete-list {
  display: flex;
  flex-direction: column;
  gap: var(--e-6);
}
.dash-incomplete-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-12);
  padding: var(--e-10) var(--e-14);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose);
}
.dash-incomplete-item:hover { background: var(--bg-sidebar); }
.dash-incomplete-name {
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  color: var(--text);
}
.dash-incomplete-tags {
  display: flex;
  gap: var(--e-6);
  flex-wrap: wrap;
}
.dash-incomplete-tag {
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  padding: var(--e-2) var(--e-8);
  border-radius: var(--r-micro);
  text-transform: uppercase;
  letter-spacing: var(--ls-large);
  background: rgba(229,194,138,0.13);
  color: var(--moy-text);
  border: none;
}
.dash-incomplete-arrow { color: var(--text-3); flex-shrink: 0; }
.dash-incomplete-empty {
  text-align: center;
  padding: var(--e-32) 0;
  color: var(--text-3);
  font-size: var(--t-small);
}
.dash-incomplete-empty span { color: var(--safe-text); font-weight: var(--fw-moyen); }

/* ═══════════════════════════════════════════════════════
   STEP SLIDER
   ═══════════════════════════════════════════════════════ */
.dress-section { margin-top: var(--e-22); }
/* ── Infos produit : tableau + toggle ── */
.dress-infos-toggle-btn {
  align-self: flex-start;
  margin-top: var(--e-6);
  padding: var(--e-6) var(--e-14);
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  border-radius: var(--r-sm);
  background: rgba(var(--th-accent-rgb),0.15);
  border: 1px solid rgba(var(--th-accent-rgb),0.35);
  color: var(--violet-light);
  cursor: pointer;
  transition: var(--transi);
}
.dress-infos-toggle-btn:hover { background: rgba(var(--th-accent-rgb),0.28); }

.dress-infos-table {
  width: 100%;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid rgba(var(--th-voile),0.07);
  margin-top: var(--e-4);
}
.dress-info-row {
  display: grid;
  grid-template-columns: 160px 1fr;
  border-bottom: 1px solid var(--bg-hover);
}
.dress-info-row:last-child { border-bottom: none; }
.dress-info-label {
  padding: var(--e-10) var(--e-12);
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  color: #888;
  background: var(--surface);
  border-right: 1px solid var(--bg-hover);
}
.dress-info-value {
  padding: var(--e-10) var(--e-12);
  font-size: var(--t-base);
  color: var(--text);
  line-height: var(--lh-normal);
}
.dress-info-empty {
  padding: var(--e-16) var(--e-12);
  font-size: var(--t-meta);
  color: #555;
  font-style: italic;
}
.dress-info-row--empty .dress-info-value { color: #555; font-style: italic; }
.dress-info-row--header .dress-info-label { color: var(--violet-light); font-weight: var(--fw-gras); }
.dress-info-mesures-header,
.dress-info-mesures-row {
  display: grid;
  grid-template-columns: 60px repeat(4, 1fr);
  border-bottom: 1px solid var(--bg-hover);
}
.dress-info-mesures-header { background: rgba(var(--th-voile),0.04); }
.dress-info-mesures-header > div,
.dress-info-mesures-row > div {
  padding: var(--e-8) var(--e-10);
  font-size: var(--t-meta);
}
.dress-info-mesures-header > div { color: #888; font-weight: var(--fw-fort); }
.dress-info-mesures-row > div { color: var(--text); }
.dress-info-mesures-row > div:first-child { font-weight: var(--fw-gras); color: var(--violet-light); }

/* Cellules de mesure éditables inline (cliquer pour saisir / ajouter une mesure manquante) */
.dress-info-mes-cell { cursor: pointer; border-radius: var(--r-micro); transition: background var(--t-bref); }
.dress-info-mes-cell:hover { background: rgba(var(--th-accent-rgb),0.14); }
.dress-info-mes-cell.empty span { opacity: 0.5; font-weight: var(--fw-gras); color: var(--violet-soft); }
.dress-info-mes-input {
  width: 100%; box-sizing: border-box;
  background: var(--bg-2); border: 1px solid var(--violet);
  border-radius: var(--r-micro); color: var(--text); font-size: var(--t-meta); padding: var(--e-2) var(--e-6);
  outline: none; font-family: inherit;
}

/* ⚠️ La marge HAUTE du titre sert quand il s'intercale entre deux blocs. Quand il OUVRE
   un panneau, elle double le rembourrage du panneau : 20 px payés deux fois. */
.dress-section-title-row:first-child > .dress-section-title,
.dress-annonce-section > .dress-section-title-row .dress-section-title { margin-top: 0; }
/* ⚠️⚠️ UN TITRE DE SECTION NE PORTE PAS UNE COULEUR D'ÉTAT. Amadou (21/08) : « la partie
   information a la même couleur que la partie orpheline ». Mesuré : le titre était en
   `--violet-light` (#D6D0FF) et la pastille « Orpheline » en #8B78FF — même famille de
   teinte, deux niveaux de clarté seulement (rapport 2,3). Sur la fiche d'une orpheline,
   « INFOS MODÈLE » et son état se lisaient donc comme la même information.
   Le violet du site SIGNIFIE quelque chose dans cet écran : c'est l'état « orpheline ».
   Un libellé qui NOMME une section n'a rien à y voir — il devient neutre.
   ⚠️ `--text-2`, pas `--text-3` : les étiquettes de champ portent déjà `--text-3`, et un
   titre au même ton que ses champs ne serait plus un titre. Mesuré sur les 16 thèmes :
   7,01 au pire (nimbe), 10,0 au mieux — largement au-dessus du seuil de 4,5. */
.dress-section-title {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-2);
  padding-bottom: var(--e-10);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--e-14);
  margin-top: var(--e-20);
}

.dress-vinted-section { margin-top: var(--e-8); }

/* ── Ruban coloris (fiche robe) ───────────────────────── */
.dress-colors-row { margin-bottom: var(--e-16); }
.dress-colors-row .dress-section-title { margin-top: 0; }
.dress-colors-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-8);
  align-items: center;
}
.dress-color-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-6) var(--e-10) var(--e-6) var(--e-6);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
}
/* Pastille couleur cliquable */
.dress-color-chip-swatch-wrap {
  position: relative;
  cursor: pointer;
  flex-shrink: 0;
}
.dress-color-chip-swatch {
  display: block;
  width: 14px; height: 14px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(var(--th-voile),0.15) inset;
  transition: transform var(--t-moyen), box-shadow var(--t-moyen);
  overflow: hidden;
}
.dress-color-chip-swatch-wrap:hover .dress-color-chip-swatch { transform: scale(1.15); box-shadow: 0 0 0 2px rgba(var(--th-voile),0.35) inset; }
.dress-color-chip-input { display: none; }
.dress-color-chip-name { color: var(--text); }

/* Popup multi-hex */
.dress-color-chip:hover { border-color: var(--border-mid); }
.dress-color-chip.active {
  border-color: var(--violet-mid);
  box-shadow: 0 0 0 2px rgba(var(--th-accent-rgb),0.25);
  color: var(--violet-light);
}
.dress-color-chip.active .dress-color-chip-name { color: var(--violet-light); }
.dress-color-chip--add {
  padding: var(--e-6) var(--e-12);
  color: var(--text-2);
}
.dress-color-chip--add::before { display: none; }
.dress-color-chip--add:hover { color: var(--violet-light); }

/* Bouton ⋯ dans les chips coloris */
.dress-color-chip-menu-btn {
  display: flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 0 var(--e-2);
  color: var(--text-3); font-size: var(--t-small); line-height: var(--lh-un);
  cursor: pointer; border-radius: var(--r-micro); transition: color var(--t-moyen);
  flex-shrink: 0;
}
.dress-color-chip:hover .dress-color-chip-menu-btn,
.dress-color-chip.active .dress-color-chip-menu-btn { color: var(--text-2); }
.dress-color-chip-menu-btn:hover { color: var(--text) !important; background: rgba(var(--th-voile),.08); }

/* Drag & drop coloris */
.dress-color-chip[draggable] { cursor: grab; }
.dress-color-chip.dragging { opacity: .4; }
.dress-color-chip.drag-over { border-color: var(--violet); box-shadow: 0 0 0 2px rgba(var(--th-accent-rgb),.35); }

/* Menu contextuel coloris */
/* ⚠️ Il était INVISIBLE. Son fond était `var(--surface)` — qui valait un gris plein
   avant la refonte, mais vaut désormais rgba(var(--th-voile),0.03) : une teinte faite pour
   se poser SUR du verre, pas pour faire panneau. Le menu était donc à 3 % d'opacité sur
   le fond cosmique (Amadou, 2026-07-31 : « c'est trop transparent, on ne voit rien »).
   Un panneau flottant doit être OPAQUE : on ne lit pas au travers. */
.dress-color-menu {
  position: fixed;
  z-index: 9999;
  background: rgba(var(--th-panneau-rgb),0.97);
  backdrop-filter: blur(16px) saturate(1.3);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-md);
  box-shadow: 0 16px 40px rgba(var(--th-ombre),0.6);
  padding: var(--e-4);
  display: flex;
  flex-direction: column;
  min-width: 170px;
}
/* L'entrée visée au CLAVIER. ⚠️ Elle emprunte exactement l'apparence du survol : deux
   marques différentes pour « ce qui va partir » feraient hésiter. */
.dress-color-menu-item.vise { background: rgba(var(--th-accent-rgb),0.15); color: var(--violet-light); }
.dress-color-menu-item.danger.vise { background: rgba(var(--th-danger-rgb),0.15); color: var(--ose-text); }

/* L'apparition : brève, et depuis le point cliqué. Un menu qui surgit sans transition
   paraît sec ; un menu qui prend son temps paraît lent. `--t-bref` est fait pour ça. */
.velbo-menu-entree { animation: velbo-menu-pose var(--t-bref) var(--c-pose); transform-origin: top left; }
@keyframes velbo-menu-pose {
  from { opacity: 0; transform: scale(.96) translateY(-2px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .velbo-menu-entree { animation: none; } }

/* La recherche d'un menu long. ⚠️ Elle est COLLANTE en haut : sur quarante comptes, le
   menu défile, et un champ qui disparaît en défilant oblige à remonter pour corriger sa
   frappe. */
.velbo-menu-recherche {
  position:sticky; top:0; z-index:1;
  font:inherit; font-size:var(--t-meta); color:var(--text);
  background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--r-xs);
  padding:var(--e-6) var(--e-8);
  margin:var(--e-2) var(--e-2) var(--e-6);
  width:calc(100% - var(--e-4));
}
.velbo-menu-recherche:focus { outline:none; border-color:var(--violet); }
.velbo-menu-vide { padding:var(--e-8) var(--e-10); font-size:var(--t-meta); color:var(--text-3); }
/* ⚠️ Le menu se borne en hauteur DÈS qu'il porte une recherche : quarante comptes le
   feraient sortir de l'écran, et sa mesure d'ouverture le collerait en haut. */
.velbo-menu-ctx:has(.velbo-menu-recherche) { max-height:min(60vh, 420px); overflow-y:auto; }

/* Le filet d'un menu contextuel : il isole l'action dangereuse du reste, pour
   qu'elle ne se clique pas dans l'élan. */
.velbo-menu-filet {
  height: var(--e-1);
  background: var(--border-mid);
  margin: var(--e-4) var(--e-6);
}
.dress-color-menu-item {
  text-align: left;
  background: transparent;
  border: none;
  color: var(--text);
  padding: var(--e-8) var(--e-12);
  font-size: var(--t-base);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.dress-color-menu-item:hover { background: rgba(var(--th-accent-rgb),0.15); color: var(--violet-light); }
.dress-color-menu-item.danger:hover { background: rgba(var(--th-danger-rgb),0.15); color: var(--ose-text); }
/* ⚠️ UNE LISTE DÉROULANTE PLUS HAUTE QUE LA FENÊTRE DÉBORDE. Le recadrage la remonte, mais
   ne la raccourcit pas : on la borne et on la fait défiler. En pixels et non en `vh` :
   mesuré, `vh` vaut zéro dans un onglet que le navigateur ne compose pas — une hauteur
   écrite en `vh` y tomberait à rien. */
.lib-bulk-dropdown { max-height: 420px; overflow-y: auto; }

/* ⚠️ LA NICHE OÙ LES PRODUITS SONT DÉJÀ. On la MONTRE — savoir d'où l'on part fait partie
   du choix, et une grille où la niche actuelle manque se lit comme une grille incomplète —
   mais éteinte et non cliquable. Le premier essai la proposait comme destination : on
   pouvait « ranger » un produit là où il était, et rien ne se passait. */
.lib-niche--ici { opacity: .45; cursor: default; }
.lib-niche--ici:hover { transform: none; }
/* ⚠️⚠️ UNE ENTRÉE DE MENU N'EST PAS UN BOUTON D'ACTION. Amadou (24/08) : « je ne veux pas
   que "supprimer la niche" soit entourée, mais juste que l'écriture soit rouge ».
   La règle générale `.danger` — celle des boutons — pose un fond ET un cadre : posée sur
   une entrée de menu, elle dessinait un bouton encadré au milieu d'une liste de mots.
   Ici le rouge se dit par le TEXTE, et il se dit tout le temps : on doit voir que le geste
   est destructeur avant de le survoler, pas au moment où l'on est déjà dessus.
   ⚠️ Le fond du survol reste : c'est le repère qui dit ce qu'on vise, il est commun à
   toutes les entrées, et il n'entoure rien. */
.dress-color-menu-item.danger {
  background: transparent;
  border: none;
  color: var(--red);
}

/* Bouton "Importer JSON" dans le ruban coloris */
.dress-color-import-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  padding: var(--e-6) var(--e-12);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-2);
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
  margin-left: auto;
}
.dress-color-import-btn:hover {
  border-color: var(--cyan, var(--cyan));
  color: var(--cyan-light, var(--cyan-light));
}

/* Modale d'import JSON */
.dress-import-modal {
  position: fixed;
  inset: 0;
  z-index: 10000;
  background: var(--voile);
  backdrop-filter: var(--voile-flou);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--e-20);
}
.dress-import-modal-card {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  width: 100%;
  max-width: 640px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 24px 64px rgba(var(--th-ombre), 0.5);
}
.dress-import-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--e-16) var(--e-20);
  border-bottom: 1px solid var(--border);
}
.dress-import-modal-header h3 {
  margin: 0;
  font-size: var(--t-body);
  color: var(--text);
}
.dress-import-modal-close {
  background: transparent;
  border: none;
  color: var(--text-2);
  font-size: var(--t-title);
  line-height: var(--lh-un);
  cursor: pointer;
  padding: var(--e-4) var(--e-8);
}
.dress-import-modal-close:hover { color: var(--text); }
.dress-import-modal-hint {
  padding: var(--e-12) var(--e-20);
  font-size: var(--t-base);
  color: var(--text-3);
  background: var(--cok-bg-2);
  border-bottom: 1px solid var(--border);
}
.dress-import-modal-hint code {
  display: block;
  margin-top: var(--e-6);
  padding: var(--e-6) var(--e-8);
  background: rgba(var(--th-ombre),0.3);
  border-radius: var(--r-micro);
  font-size: var(--t-meta);
  color: var(--text-2);
  word-break: break-all;
}
.dress-import-modal-textarea {
  margin: var(--e-16) var(--e-20) 0;
  padding: var(--e-12);
  background: rgba(var(--th-ombre),0.3);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  font-family: 'SF Mono', Menlo, Consolas, monospace;
  font-size: var(--t-small);
  resize: vertical;
  min-height: 280px;
  outline: none;
}
.dress-import-modal-textarea:focus { border-color: var(--violet-mid); }
.dress-import-modal-textarea:disabled { opacity: 0.5; }
.dress-import-modal-status {
  padding: var(--e-8) var(--e-20);
  font-size: var(--t-base);
  color: var(--text-2);
  min-height: 1.4em;
}
.dress-import-modal-status.error { color: var(--ose-text); }
.dress-import-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--e-8);
  padding: var(--e-12) var(--e-20) var(--e-16);
  border-top: 1px solid var(--border);
}

/* Mini-pastilles sur la card bibliothèque */
.lib-card-colors {
  position: absolute;
  left: 6px; bottom: 6px;
  display: flex;
  gap: var(--e-4);
  align-items: center;
  padding: var(--e-4) var(--e-6);
  background: rgba(var(--th-panneau-rgb),0.7);
  border-radius: var(--r-pilule);
  backdrop-filter: blur(4px);
}
.lib-card-color-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(var(--th-voile),0.2) inset;
}
.lib-card-color-more {
  font-size: var(--t-micro);
  font-weight: var(--fw-fort);
  color: var(--text-2);
  margin-left: var(--e-2);
}

.step-slider-group {
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
  margin-bottom: var(--e-20);
}
.step-slider-name {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  color: var(--text-2);
}
.step-slider-outer { display: flex; flex-direction: column; gap: var(--e-8); border-radius: var(--r-sm); padding: var(--e-4); margin: calc(var(--e-4) * -1); }
.step-slider-outer:focus .step-slider-track { box-shadow: 0 0 0 2px rgba(var(--th-accent-rgb),0.25); }
.step-slider-track-wrap { padding: 0 var(--e-2); }
.step-slider-labels {
  position: relative;
  height: 1.4em;
  font-size: var(--t-mini);
  color: var(--text-3);
}
.step-slider-labels span {
  position: absolute;
  transform: translateX(-50%);
  white-space: nowrap;
  transition: color var(--t-moyen), font-weight var(--t-moyen);
}
.step-slider-labels span:first-child { transform: translateX(0); }
.step-slider-labels span:last-child  { transform: translateX(-100%); }
.step-slider-labels span.empty-step  { pointer-events: none; }
.step-slider-labels span.active { color: var(--violet-light); font-weight: var(--fw-gras); }
.step-slider-track {
  position: relative;
  height: 4px;
  background: var(--border-strong);
  border-radius: 2px;
  cursor: pointer;
}
.step-slider-fill {
  position: absolute;
  left: 0; top: 0; height: 100%;
  background: var(--violet);
  border-radius: 2px;
  transition: width var(--t-moyen), opacity var(--t-moyen);
  pointer-events: none;
}
.step-slider-thumb {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 13px; height: 13px;
  background: var(--violet-light);
  border-radius: var(--r-micro);
  transition: left var(--t-moyen), opacity var(--t-moyen);
  pointer-events: none;
  box-shadow: 0 2px 6px rgba(var(--th-ombre),0.4);
}
.step-slider-tick {
  position: absolute;
  top: 50%; transform: translate(-50%, -50%);
  width: 2px; height: 8px;
  background: var(--bg);
  border-radius: 1px;
  pointer-events: none;
}
.step-slider-reset {
  align-self: flex-start;
  font-size: var(--t-micro);
  color: var(--text-3);
  background: none;
  border: 1px solid transparent;
  border-radius: var(--r-xl);
  padding: var(--e-2) var(--e-8);
  cursor: pointer;
  transition: var(--transi);
}
.step-slider-reset:hover, .step-slider-reset.active {
  color: var(--text);
  border-color: var(--border-mid);
  background: var(--bg-hover);
}

/* ── Model info fields ── */
/* ⚠️⚠️ CES TROIS LIGNES ÉTAIENT UN RESTE, ET ELLES COÛTAIENT L'ALIGNEMENT DE L'ÉCRAN.
   Le filet et ses 68 px séparaient l'avatar des champs À L'ÉPOQUE OÙ L'AVATAR VIVAIT
   DANS CETTE COLONNE. Il est passé à gauche depuis ; il ne restait qu'un trait qui
   barrait le haut de la colonne droite sans rien séparer, et 68 px qui la faisaient
   commencer plus bas que sa voisine. C'est ça, la diagonale. */
.model-info-fields {
  display: flex;
  flex-direction: column;
  gap: var(--e-22);
}
.model-info-avatar-section {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--e-18);
}
.model-info-avatar {
  width: 104px;
  height: 104px;
  flex: none;
  border-radius: 50%;
  background: var(--surface-2);
  border: 3px solid var(--border-strong);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  cursor: pointer;
  box-shadow: 0 2px 12px rgba(var(--th-ombre),0.25);
  transition: border-color var(--t-moyen), transform var(--t-moyen);
}
.model-info-avatar:hover {
  border-color: var(--violet);
  transform: scale(1.05);
}
.model-info-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.model-info-avatar-hint {
  font-size: var(--t-mini);
  color: var(--text-3);
  letter-spacing: var(--ls-leger);
}

/* ── Boutons générer individuels (modèle infos) ───────── */
.model-field-gen-row {
  display: flex; align-items: center; gap: var(--e-6);
}
/* ⚠️ La bio grandit : ses deux boutons restent EN HAUT. Centrés, ils descendaient au
   milieu d'un pavé de douze lignes, loin du champ qu'ils servent. */
.model-bio-row { align-items: flex-start; }
/* ── LA BIO SE DÉPLIE ─────────────────────────────────────────────────────────
   ⚠️ `pre-wrap` était déjà là et fait le travail : la ligne vide entre deux
   paragraphes est conservée. Ce qui manquait, c'est de la VOIR — trois rangées
   fixes coupaient le texte avant sa première coupure, donc la bio se lisait comme
   un bloc. On aère aussi l'interligne : deux paragraphes serrés se lisent comme un.
   ⚠️ Pas de `resize` : la hauteur est calculée sur le contenu, une poignée de
   redimensionnement se battrait contre elle à chaque frappe. */
/* ⚠️ La bio EMPRUNTE `.listing-desc` à Génération — police, couleur, interligne aéré et
   `pre-wrap` viennent de là, donc les lignes vides entre paragraphes se voient. Ne
   restent ici que les trois choses qui lui sont propres : sa largeur dans la rangée,
   son texte d'attente, et le pli. */
.model-bio-area { flex: 1; min-width: 0; overflow: hidden; }
/* Un bloc modifiable n'a pas de `placeholder` : on l'écrit nous-mêmes, et seulement
   quand il est VRAIMENT vide. */
.model-bio-area:empty::before {
  content: attr(data-vide); color: var(--text-3); pointer-events: none;
}
/* ⚠️ LE VOILE ET LE BOUTON « DÉPLIER » SONT PARTIS AVEC LE PLI (Amadou, 04/09 : « enlève
   le bouton déplier qui ne sert à rien »). Une bio Vinted fait quatre paragraphes courts
   par construction : le pli cachait 53 px et posait un bouton pour aller les rechercher.
   ⚠️ Les règles partent AVEC lui. Une classe `.plie` que plus personne ne pose est du
   poids mort qu'on relit pour rien — et pire, une fausse piste : on la voit dans la
   feuille et on croit que l'écran plie encore. */
.model-field-gen-row input,
.model-field-gen-row textarea { flex: 1; min-width: 0; }
.model-field-gen-btn {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; flex-shrink: 0;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); color: var(--text-2); cursor: pointer;
  transition: border-color var(--t-moyen), color var(--t-moyen);
}
.model-field-gen-btn:hover:not(:disabled) { border-color: var(--violet); color: var(--violet-soft); }
.model-field-gen-btn:disabled { opacity: .4; cursor: not-allowed; }

/* ── Avatar viewer modal ─────────────────────────────── */
.avatar-modal-backdrop {
  position: absolute; inset: 0;
  z-index: 0;
  cursor: default;
}
.avatar-modal-card {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-16);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-20);
  max-width: 360px;
  width: 90vw;
  box-shadow: 0 24px 60px rgba(var(--th-ombre),0.5);
}
.avatar-modal-close {
  position: absolute;
  top: 12px; right: 12px;
  background: var(--surface-2);
  border: none; border-radius: 50%;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-2);
  transition: background var(--t-moyen), color var(--t-moyen);
}
.avatar-modal-close:hover { background: var(--border-strong); color: var(--text); }
#avatar-modal-img {
  width: 220px;
  height: 220px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid var(--border-strong);
  box-shadow: 0 8px 32px rgba(var(--th-ombre),0.4);
}
.avatar-modal-actions {
  display: flex;
  gap: var(--e-10);
  width: 100%;
}
.avatar-modal-actions .btn-secondary,
.avatar-modal-actions .btn-primary {
  flex: 1;
  justify-content: center;
}
.model-info-textarea { display: block;
  width: 100%;
  box-sizing: border-box;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  resize: none;
  transition: border-color var(--t-moyen) }
.model-info-textarea:focus { outline: none; border-color: var(--violet); }
.model-field-hint {
  display: block;
  font-size: var(--t-meta);
  color: var(--text-3);
  margin-bottom: var(--e-6);
  line-height: var(--lh-serre);
}

/* dress select */
.dress-select { display: block;
  width: 100%;
  color: var(--text);
  font-size: var(--t-small);
  cursor: pointer;
  transition: border-color var(--t-moyen);
  -webkit-appearance: none }
.dress-select:focus { outline: none; border-color: var(--violet); }

/* ── Mesures par taille ───────────────────────────────── */
/* ⚠️ Une niche sans version (la caisse à outils : une seule) doit dire pourquoi la
   rangée est vide, pas laisser un trou. Un vide muet se lit comme un bug. */
.dress-mesures-vide {
  font-size: var(--t-meta);
  color: var(--text-3);
  padding: var(--e-8) 0 0;
}
/* Une photo empruntee a un autre coloris : elle s'affiche, mais elle ne s'efface pas
   d'ici — et elle le dit. */
.dress-photo--empruntee { opacity: .72; }
.dress-taille-row {
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  margin-bottom: var(--e-12);
}
.dress-taille-row label {
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  color: var(--text-2);
}
.dress-taille-btns {
  display: flex;
  /* ⚠️ Amadou (24/08) : « l'interface est mal faite, ça déborde ». Cinq tailles de robe
     tenaient sur une ligne ; « Noir violet » ou « 1 ensemble/115 pièces » non. Une
     rangée qui déborde sort du panneau au lieu de passer à la ligne. */
  flex-wrap: wrap;
  gap: var(--e-8);
}
/* ⚠️ UNE MESURE LIBRE N'A PAS LA LARGEUR D'UNE TAILLE. Les boutons de taille sont des
   carrés de 44 px — parfait pour « XS », absurde pour « 115 pièces ». En mesure libre
   ils prennent la largeur de leur texte, sans jamais descendre sous le carré. */
.dress-taille-btns--libre .dress-taille-btn {
  width: auto;
  min-width: 44px;
  padding: 0 var(--e-12);
}

.dress-taille-btn {
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  border: 1.5px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-gras);
  cursor: pointer;
  transition: var(--transi);
}
.dress-taille-btn:hover { border-color: var(--border-mid); color: var(--text); }
/* ⚠️ UN LIBELLÉ ÉCRIT EN TOUTES LETTRES NE TIENT PAS DANS UN CARRÉ DE 44 px. « Taille
   unique » y passait à la ligne et débordait de son cadre. Même réponse que pour les
   valeurs libres ci-dessus, appliquée au SEUL bouton concerné plutôt qu'à toute la
   rangée : « M » doit rester carré à côté de lui. */
.dress-taille-btn--mot { width: auto; min-width: 44px; padding: 0 var(--e-12); white-space: nowrap; }
/* ⚠️ QUAND LA TAILLE UNIQUE EST CHOISIE, LES AUTRES N'ONT PLUS DE SENS. On les masque
   plutôt que de les retirer : re-cliquer « Taille unique » les fait revenir. */
.dress-taille-btns--unique .dress-taille-btn:not(.dress-taille-btn--mot) { display: none; }

/* La porte pour ajouter une version, à la place de l'échelle XS→XL qu'on posait d'office.
   ⚠️ Elle reste VISIBLE quand « Taille unique » est choisie : c'est justement le moment où
   Amadou veut nommer la vraie taille. La règle ci-dessus ne la masque pas — elle ne porte
   pas la classe `dress-taille-btn`, et c'est voulu (voir app.js). */
.dress-taille-ajout {
  /* ⚠️ `align-self: stretch` PLUTÔT QU'UNE HAUTEUR À LUI. La rangée est un flex et les
     boutons de taille font 44 px ; poser --e-40 (40 px) l'aurait laissé 4 px plus court
     que ses voisins, avec un jeton qui a pourtant l'air juste. Il prend la hauteur de la
     rangée, et il la gardera si elle change. */
  align-self: stretch;
  min-height: var(--e-40);
  padding: 0 var(--e-12);
  border-radius: var(--r-sm);
  border: 1.5px dashed var(--border-strong);
  background: transparent;
  color: var(--text-3);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  line-height: var(--lh-un);
  cursor: pointer;
  transition: var(--transi);
}
.dress-taille-ajout:hover { border-color: var(--violet-mid); color: var(--text); }

/* ══ UN COLORIS ÉPUISÉ ═════════════════════════════════════════════════════════
   Amadou (01/09) : « ce n'est pas parce qu'il est épuisé qu'il ne faut pas le mettre ».
   Il est là, il est juste barré — et le bloc l'écrit en toutes lettres à côté.
   ⚠️ PAS UNE SIMPLE TRANSPARENCE : une pastille un peu plus pâle ne se remarque pas. */
.coloris--epuise {
  position: relative;
  opacity: .55;
}
.coloris--epuise::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(to bottom right, transparent 45%,
              var(--text-3) 45%, var(--text-3) 55%, transparent 55%);
}
.dress-color-block-epuise {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--amber);
  background: rgba(var(--th-accent-rgb), .12);
  border-radius: var(--r-pilule);
  padding: var(--e-2) var(--e-8);
  line-height: var(--lh-un);
}
.dress-taille-btn.active {
  background: var(--tier-premium-bg);
  border-color: var(--violet-mid);
  color: var(--violet-light);
}
.dress-taille-btn:disabled {
  opacity: 0.3;
  cursor: not-allowed;
  border-style: dashed;
}
.dress-taille-btn:disabled:hover { border-color: var(--border-strong); color: var(--text-2); }
/* ⚠️ Les règles « .dress-taille-models* » ont été retirées avec leur bloc (15/08).
   Une famille de styles qui ne vise plus aucun élément est du poids mort : elle
   fait grossir la feuille et laisse croire que l'écran existe encore. */
.dress-mesures-hint {
  font-size: var(--t-meta);
  color: var(--text-3);
  font-style: italic;
  padding: var(--e-8) 0 var(--e-4);
}
.dress-mesures-container { display: flex; flex-direction: column; gap: var(--e-16); }
.dress-mesures-toggle {
  display: inline-flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-mini); color: var(--text-3);
  background: none; border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: var(--e-4) var(--e-10);
  cursor: pointer; transition: var(--transi);
  align-self: flex-start; margin-top: calc(var(--e-4) * -1);
}
.dress-mesures-toggle:hover { color: var(--violet-light); border-color: var(--violet); background: rgba(var(--th-accent-rgb),0.07); }

/* ══ CE QUI A ÉTÉ LU SUR LES PHOTOS ══════════════════════════════════════════
   Amadou (31/08) : les cotes de sa sculpture n'existent que dans les images.
   ⚠️ AUCUNE VALEUR BRUTE : la carte, la pastille et le bouton viennent de la
   bibliothèque (`.v-carte`, `.v-pastille`, `.v-btn`) — on ne pose ici que la
   disposition, et uniquement avec des jetons. */
.dress-cotes-lues { margin-top: var(--e-16); display: flex; flex-direction: column; gap: var(--e-10); }
.dress-cotes-tete { display: flex; align-items: center; justify-content: space-between; gap: var(--e-10); }
.dress-cotes-titre { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2);
  letter-spacing: var(--ls-leger); line-height: var(--lh-un); }
.dress-cotes-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--e-10); }
.dress-cote { display: flex; flex-direction: column; gap: var(--e-4); padding: var(--e-10);
  border: var(--e-1) solid var(--border); border-radius: var(--r-sm); background: var(--surface-2); }
.dress-cote-axe { font-size: var(--t-micro); font-weight: var(--fw-moyen); color: var(--text-3);
  text-transform: uppercase; letter-spacing: var(--ls-caps); line-height: var(--lh-un); }
/* ⚠️ Le CHIFFRE porte la carte : c'est lui qu'on vient lire. */
.dress-cote-val { font-size: var(--t-lead); font-weight: var(--fw-fort); color: var(--text);
  line-height: var(--lh-un); font-variant-numeric: tabular-nums; }
.dress-cotes-sous { font-size: var(--t-mini); font-weight: var(--fw-moyen); color: var(--text-3);
  text-transform: uppercase; letter-spacing: var(--ls-caps); line-height: var(--lh-un);
  margin-top: var(--e-6); }
.dress-cotes-infos { display: flex; flex-direction: column; gap: var(--e-6); }
.dress-cote-info { font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-serre);
  padding-left: var(--e-10); border-left: var(--e-2) solid var(--border); }
/* ⚠️ LA PROVENANCE SE LIT. Une cote lue par une machine sur une image n'a pas le même
   statut qu'une cote donnée par la boutique — et Amadou publie sur la foi de ce chiffre. */
.dress-cotes-pied { font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-serre); }
/* ══ SÉLECTIONNER DES NICHES ══════════════════════════════════════════════════
   Amadou (31/08) : « je dois pouvoir sélectionner des niches pour les supprimer ».
   ⚠️ MÊME LANGAGE QUE LES CARTES DE PRODUIT (`.lib-card.select-mode`) : deux façons de
   cocher dans le même écran, ce serait deux choses à apprendre pour un seul geste. */
.lib-niche.select-mode { cursor: pointer; }
.lib-niche.selected { border-color: var(--violet-mid); }
.lib-niche-cb {
  position: absolute; top: var(--e-8); left: var(--e-8);
  width: var(--e-20); height: var(--e-20); border-radius: 50%;
  background: var(--surface-2); border: var(--e-2) solid var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; opacity: 0; transition: opacity var(--t-moyen);
}
.lib-niche.select-mode .lib-niche-cb { opacity: 1; }
.lib-niche.selected .lib-niche-cb { background: var(--violet-mid); border-color: var(--violet-mid); }
.lib-niche.selected .lib-niche-cb::after {
  content: ''; display: block; width: var(--e-6); height: var(--e-10);
  border: var(--e-2) solid var(--sur-accent); border-top: none; border-left: none;
  transform: rotate(45deg) translate(calc(var(--e-1) * -1), calc(var(--e-1) * -1));
}

/* Un coloris qui n'a presque pas de photos — il faut le savoir AVANT de générer. */
.dress-coloris-pauvre { display: flex; align-items: flex-start; gap: var(--e-6);
  margin: var(--e-6) 0 var(--e-10); font-size: var(--t-mini); color: var(--text-3);
  line-height: var(--lh-serre); }
.dress-coloris-pauvre svg { flex: none; margin-top: var(--e-2); color: var(--amber); }

/* Le titre d'un groupe dans le tableau des infos produit — « Lu sur les visuels ». */
.dress-info-sep { font-size: var(--t-micro); font-weight: var(--fw-moyen); color: var(--text-3);
  text-transform: uppercase; letter-spacing: var(--ls-caps); line-height: var(--lh-un);
  margin-top: var(--e-14); padding-top: var(--e-10); border-top: var(--e-1) solid var(--border); }
.dress-mesures-manches { display: flex; flex-direction: column; gap: var(--e-16); }
.dress-mesures-manches.hidden { display: none; }

/* ═══════════════════════════════════════════════════════
   DEMANDES
   ═══════════════════════════════════════════════════════ */
.section-top-bar { display:none; }

/* ── Chaîne pleine hauteur ─────────────────────────── */
#section-demandes:not(.hidden) { display: flex; flex-direction: column; }
#section-demandes .section-canvas {
  max-width: 1200px;
  margin: 0 auto;
  width: 100%;
  padding: var(--e-20) var(--e-32) var(--e-20);
  display: flex; flex-direction: column;
  height: calc(100vh - 36px - 56px);
  box-sizing: border-box;
  gap: 0;
}
.dem-panel { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* ═══════════════════════════════════════════════════
   CENTRE DE CONTRÔLE BOT
   ═══════════════════════════════════════════════════ */

/* Barre de stats */
.ctrl-stats {
  display: flex; align-items: center; gap: var(--e-6);
  width: 100%; margin-bottom: var(--e-14);
  padding: var(--e-10) var(--e-16);
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  flex-wrap: wrap;
}
.ctrl-stat {
  display: flex; flex-direction: column; align-items: center;
  padding: var(--e-4) var(--e-14); border-right: 1px solid var(--border);
  min-width: 80px;
}
.ctrl-stat:last-of-type { border-right: none; }
.ctrl-stat--urgent { background: rgba(255,80,80,.08); border-radius: var(--r-sm); border-right: none; margin-right: var(--e-4); }
.ctrl-stat--urgent .ctrl-stat-val { color: var(--red); }
.ctrl-stat-val { font-size: var(--t-title); font-weight: var(--fw-gras); color: var(--text); line-height: var(--lh-un); }
.ctrl-stat-lbl { font-size: var(--t-micro); color: var(--text-3); text-transform: uppercase; letter-spacing: var(--ls-large); margin-top: var(--e-2); }
.ctrl-refresh {
  margin-left: auto; background: none; border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--e-6) var(--e-8); color: var(--text-3);
  cursor: pointer; transition: var(--transi);
}
.ctrl-refresh:hover { border-color: var(--violet); color: var(--violet-soft); }

/* ── Onglets centre de contrôle ── */
.ctrl-tabs {
  display: flex; gap: 0;
  width: 100%; margin-bottom: 0;
  border-bottom: 1px solid var(--border);
}
.ctrl-tab {
  position: relative; padding: var(--e-12) var(--e-20);
  background: transparent; border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-3); font-size: var(--t-base); font-weight: var(--fw-fort);
  cursor: pointer; white-space: nowrap;
  transition: color var(--t-moyen), border-color var(--t-moyen), background var(--t-moyen);
  margin-bottom: calc(var(--e-1) * -1); display: flex; align-items: center; gap: var(--e-8);
}
.ctrl-tab:hover { color: var(--text); background: var(--surface-2); }
.ctrl-tab.active { color: var(--violet-soft); border-bottom-color: var(--violet); background: var(--surface); }
.ctrl-tab svg { opacity: .75; flex-shrink: 0; }
.ctrl-tab.active svg { opacity: 1; }

.ctrl-tab-badge {
  padding: var(--e-1) var(--e-8); border-radius: var(--r-xl); font-size: var(--t-mini); font-weight: var(--fw-gras);
  background: rgba(255,80,80,.15); color: var(--red); border: 1px solid rgba(255,80,80,.3);
}

/* Panneaux d'onglet */
.ctrl-panel {
  width: 100%;
  display: flex; flex-direction: column; gap: var(--e-14);
  padding-top: var(--e-16); /* overridden by grid panels */
}
.ctrl-panel.hidden { display: none; }

/* ── Section canvas ctrl (layout flex column) ── */
.section-canvas--ctrl {
  display: flex; flex-direction: column; gap: 0;
}

/* Layout 2 colonnes du panneau Manuel sur grand écran */
#ctrl-panel-manual {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  grid-template-rows: auto 1fr;
  gap: var(--e-14);
  align-items: start;
  padding-top: var(--e-16);
}
/* Col gauche : composeur occupe toute la hauteur */
#dem-panel-written  { grid-column: 1; grid-row: 1 / 3; }
/* Col droite : instructions en haut, exemples en bas */
#dem-panel-instr    { grid-column: 2; grid-row: 1; }
#dem-panel-examples { grid-column: 2; grid-row: 2; }

@media (max-width: 860px) {
  #ctrl-panel-manual {
    grid-template-columns: 1fr;
  }
  #dem-panel-written  { grid-column: 1; grid-row: auto; }
  #dem-panel-instr    { grid-column: 1; grid-row: auto; }
  #dem-panel-examples { grid-column: 1; grid-row: auto; }
}

/* Wrap feed + esc dans leurs panneaux */
.ctrl-feed-wrap {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  overflow: hidden; display: flex; flex-direction: column;
  flex: 1; min-height: 0; max-height: calc(100vh - 260px);
}
#ctrl-panel-activity, #ctrl-panel-escalations {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
}
/* Compat ancien badge */
.ctrl-badge {
  padding: var(--e-2) var(--e-8); border-radius: var(--r-xl); font-size: var(--t-mini); font-weight: var(--fw-gras);
  background: rgba(255,80,80,.15); color: var(--red); border: 1px solid rgba(255,80,80,.3);
}
.ctrl-badge {
  padding: var(--e-2) var(--e-8); border-radius: var(--r-xl); font-size: var(--t-mini); font-weight: var(--fw-gras);
  background: rgba(255,80,80,.15); color: var(--red); border: 1px solid rgba(255,80,80,.3);
}
.ctrl-live-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--green); box-shadow: 0 0 6px var(--green);
  animation: livePulse 2.5s infinite;
}
.ctrl-live-dot.pulse { animation: livePulse var(--t-long) ease; }
@keyframes livePulse { 0%,100% { opacity: 1; } 50% { opacity: .4; } }

/* ── Liste À traiter : redesign card-based ── */
#ctrl-esc-list {
  overflow-y: auto; flex: 1; padding: var(--e-8);
  display: flex; flex-direction: column; gap: var(--e-6);
}
.ctrl-empty { font-size: var(--t-base); color: var(--text-3); text-align: center; padding: var(--e-20) var(--e-10); }

/* Carte escalade : style "card" avec bordure et rayon */
.ctrl-esc-card { display: flex; align-items: flex-start; gap: var(--e-10); cursor: pointer;
  transition: border-color var(--t-moyen), background var(--t-moyen), opacity var(--t-long);
  position: relative }
.ctrl-esc-card:hover  { background: var(--surface-2); border-color: var(--border-strong); }
.ctrl-esc-card.active {
  background: rgba(var(--th-accent-rgb),.08);
  border-color: var(--violet-glow);
  border-left: 3px solid var(--violet);
}
.ctrl-esc-card--done { opacity: 0; pointer-events: none; }

/* Avatar circulaire avec couleur par catégorie */
.ctrl-esc-av {
  width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0;
  background: rgba(var(--th-accent-rgb),.2); color: var(--violet-soft);
  font-size: var(--t-small); font-weight: var(--fw-gras);
  display: flex; align-items: center; justify-content: center;
}
.ctrl-esc-card:has(.ctrl-esc-cat--litige) .ctrl-esc-av            { background: rgba(255,80,80,.18);  color:var(--red); }
.ctrl-esc-card:has(.ctrl-esc-cat--negociation_texte) .ctrl-esc-av { background: rgba(167,139,250,.2);  color:var(--violet-soft); }
.ctrl-esc-card:has(.ctrl-esc-cat--taille) .ctrl-esc-av            { background: rgba(96,165,250,.18);  color:var(--cyan-light); }
.ctrl-esc-card:has(.ctrl-esc-cat--rupture) .ctrl-esc-av           { background: rgba(255,165,0,.15);   color:var(--amber); }

.ctrl-esc-body { display: flex; flex-direction: column; gap: var(--e-4); flex: 1; min-width: 0; }
.ctrl-esc-top  { display: flex; align-items: center; gap: var(--e-8); min-width: 0; }
.ctrl-esc-name {
  font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--text);
  flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ctrl-esc-sub  {
  font-size: var(--t-meta); color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ctrl-esc-prev {
  font-size: var(--t-meta); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-style: italic;
}

/* Badges catégorie */
.ctrl-esc-cat {
  flex-shrink: 0; white-space: nowrap; font-size: var(--t-micro); font-weight: var(--fw-gras);
  padding: var(--e-2) var(--e-10); border-radius: var(--r-pilule);
  background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border);
}
.ctrl-esc-cat--litige            { background: rgba(255,80,80,.18);  color:var(--red); border-color:rgba(255,80,80,.4); }
.ctrl-esc-cat--rupture           { background: rgba(255,165,0,.18);  color:var(--amber); border-color:rgba(255,165,0,.4); }
.ctrl-esc-cat--compte_deconnecte { background: rgba(96,165,250,.18); color:var(--cyan-light); border-color:rgba(96,165,250,.4); }
.ctrl-esc-cat--cloture           { background: rgba(52,211,153,.18); color:var(--green); border-color:rgba(52,211,153,.4); }
.ctrl-esc-cat--negociation_texte { background: rgba(167,139,250,.2); color:var(--violet-soft); border-color:var(--survol-bord); }
.ctrl-esc-cat--photos_ia         { background: rgba(236,72,153,.18); color:#ec4899; border-color:rgba(236,72,153,.4); }
.ctrl-esc-cat--taille            { background: rgba(96,165,250,.18); color:var(--cyan-light); border-color:rgba(96,165,250,.4); }
.ctrl-esc-cat--description       { background: rgba(52,211,153,.15); color:var(--green); border-color:rgba(52,211,153,.35); }
.ctrl-esc-link {
  color: var(--text-3); padding: var(--e-2) var(--e-4); border-radius: var(--r-micro);
  transition: color var(--t-moyen);
}
.ctrl-esc-link:hover { color: var(--violet-soft); }

.ctrl-esc-msg {
  display: flex; gap: var(--e-6); align-items: flex-start;
  padding: var(--e-8) var(--e-10); font-size: var(--t-base); border-bottom: 1px solid var(--border);
}
.ctrl-esc-who { flex-shrink: 0; font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase; color: var(--text-3); padding-top: var(--e-2); width: 52px; }
.ctrl-esc-text { color: var(--text-2); flex: 1; line-height: var(--lh-normal); }

.ctrl-esc-draft-wrap { padding: var(--e-8) var(--e-10); border-bottom: 1px solid var(--border); }
.ctrl-esc-draft-lbl { font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase; color: var(--text-3); margin-bottom: var(--e-4); }
.ctrl-esc-draft {
  width: 100%; resize: none; background: var(--bg-2);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  color: var(--text); font-size: var(--t-base); padding: var(--e-6) var(--e-8);
  font-family: inherit; line-height: var(--lh-normal);
}
.ctrl-esc-draft:focus { outline: none; border-color: var(--violet); }

.ctrl-esc-actions { display: flex; gap: var(--e-6); padding: var(--e-8) var(--e-10); }
.ctrl-esc-btn {
  flex: 1; padding: var(--e-6) var(--e-10); border-radius: var(--r-sm); font-size: var(--t-meta); font-weight: var(--fw-fort);
  cursor: pointer; border: 1px solid var(--border); transition: var(--transi);
}
.ctrl-esc-btn--primary { background: var(--violet-tint); border-color: var(--violet); color: var(--violet-soft); }
.ctrl-esc-btn--primary:hover { background: var(--violet); color: var(--sur-accent); }
.ctrl-esc-btn--ghost  { background: var(--surface-2); color: var(--text-2); }
.ctrl-esc-btn--ghost:hover { background: var(--surface-3); color: var(--text); }

/* Feed activité */
.ctrl-feed {
  overflow-y: auto; flex: 1; padding: var(--e-8);
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 0; align-content: start;
  min-height: 300px;
}
@media (max-width: 760px) { .ctrl-feed { grid-template-columns: 1fr; } }
.ctrl-feed-row { transition: background var(--t-moyen), border-color var(--t-moyen);
  margin: var(--e-4) }
.ctrl-feed-row:hover { background: var(--surface-2); border-color: var(--border-strong); }
.ctrl-feed-meta {
  display: flex; align-items: center; gap: var(--e-6); margin-bottom: var(--e-4); flex-wrap: wrap;
}
.ctrl-feed-time    { font-size: var(--t-mini); color: var(--text-3); font-variant-numeric: tabular-nums; }
.ctrl-feed-icon    { font-size: var(--t-small); }
.ctrl-feed-account { font-size: var(--t-meta); font-weight: var(--fw-gras); color: var(--text-2); }
.ctrl-feed-cat {
  font-size: var(--t-micro); padding: var(--e-1) var(--e-6); border-radius: var(--r-md);
  background: var(--surface-3); color: var(--text-3); border: 1px solid var(--border);
}
.ctrl-feed-dress { font-size: var(--t-meta); color: var(--text-3); margin-bottom: var(--e-4); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ctrl-feed-buyer,
.ctrl-feed-bot   { display: flex; gap: var(--e-6); font-size: var(--t-meta); margin-bottom: var(--e-2); line-height: var(--lh-serre); }
.ctrl-feed-who   { flex-shrink: 0; font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase; color: var(--text-3); padding-top: var(--e-1); width: 44px; }
.ctrl-feed-who--bot { color: var(--violet-soft); }
.ctrl-feed-txt   { color: var(--text-2); flex: 1; }
.ctrl-feed-link  { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-4); display: inline-block; }
.ctrl-feed-link:hover { color: var(--violet-soft); }

/* ══ SPLIT LAYOUT (Activité + À traiter) ════════════════════════════════════ */

/* Conteneur principal : flex row, prend toute la hauteur restante du panel */
.ctrl-split {
  display: flex; flex: 1; min-height: 0;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  overflow: hidden;
}

/* Colonne liste (gauche) : barre de filtres figée + liste verticale scrollable */
.ctrl-split-list {
  flex: 1; min-width: 0; overflow: hidden;
  display: flex; flex-direction: column;
  transition: flex var(--t-moyen) var(--c-pose);
}
.ctrl-esc-filters {
  flex-shrink: 0; padding: var(--e-12); display: flex; flex-direction: column; gap: var(--e-10);
  border-bottom: 1px solid var(--border); background: var(--surface);
}
.ctrl-esc-search-wrap { position: relative; display: flex; align-items: center; }
.ctrl-esc-search-wrap svg { position: absolute; left: 11px; color: var(--text-3); pointer-events: none; }
.ctrl-esc-search {
  width: 100%; padding: var(--e-8) var(--e-12) var(--e-8) var(--e-32); border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
  font-size: var(--t-base); font-family: inherit;
}
.ctrl-esc-search:focus { outline: none; border-color: var(--violet); }
.ctrl-esc-cats { display: flex; flex-wrap: wrap; gap: var(--e-6); }
.ctrl-esc-cat-chip {
  font-size: var(--t-meta); padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule); cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-2);
  transition: background var(--t-bref), border-color var(--t-bref), color var(--t-bref); white-space: nowrap;
}
.ctrl-esc-cat-chip:not(.active):hover { border-color: var(--border-strong); }
.ctrl-esc-cat-chip.active { background: var(--violet-tint); border-color: var(--violet); color: var(--text); }
.ctrl-esc-cat-chip-count { opacity: .55; margin-left: var(--e-4); }

/* Quand le panneau détail est ouvert : la liste rétrécie */
.ctrl-split.split--open .ctrl-split-list {
  flex: 0 0 320px; min-width: 200px; max-width: 340px;
  border-right: 1px solid var(--border);
}

/* Panneau détail (droite) : caché par défaut */
.ctrl-split-detail {
  display: flex; flex-direction: column;
  width: 0; overflow: hidden;
  transition: width var(--t-moyen) var(--c-pose);
  background: var(--bg);
}
.ctrl-split-detail.open {
  width: auto; flex: 1; min-width: 0; overflow: visible;
}
/* Fallback hidden/open via .hidden class */
.ctrl-split-detail.hidden { display: none; }
.ctrl-split-detail:not(.hidden) { display: flex; flex: 1; min-width: 0; }

/* ── « À traiter » : même look que l'onglet Conversations ── */
/* Supprime la bordure/rayon du conteneur — déjà géré par le panel parent */
#ctrl-split-esc {
  border: none;
  border-radius: 0;
}
/* Liste gauche : largeur fixe comme msg-list */
#ctrl-split-esc .ctrl-split-list {
  flex: 0 0 340px; min-width: 340px; max-width: 340px;
  border-right: 1px solid var(--border);
}
/* Filtres : fond légèrement distinct */
#ctrl-esc-filters {
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  padding: var(--e-10) var(--e-10) var(--e-8);
}
.ctrl-esc-search-wrap { margin-bottom: var(--e-8); }
.ctrl-esc-search {
  width: 100%; padding: var(--e-8) var(--e-10) var(--e-8) var(--e-32);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font-size: var(--t-base); font-family: inherit;
}
.ctrl-esc-search:focus { outline: none; border-color: var(--violet); }
.ctrl-esc-cats { display: flex; flex-wrap: wrap; gap: var(--e-6); }
.ctrl-esc-cat-chip {
  font-size: var(--t-meta); font-weight: var(--fw-fort); padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule);
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-2); cursor: pointer; transition: var(--transi);
}
.ctrl-esc-cat-chip:not(.active):hover { border-color: var(--border-strong); color: var(--text); }
.ctrl-esc-cat-chip.active {
  background: var(--violet); border-color: var(--violet); color: var(--sur-accent);
}
.ctrl-esc-cat-chip-count { opacity: .7; margin-left: var(--e-4); font-weight: var(--fw-normal); }
.ctrl-esc-items { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; }

/* ── Panel gauche À traiter : filtres épinglés en haut, liste défilante en dessous ── */
.ctrl-esc-list-panel { overflow-y: hidden; }
#ctrl-esc-list { flex: 1; min-height: 0; overflow-y: auto; }
/* Thread bulles : même comportement que msg-bubbles, gap légèrement plus large */
#ctrl-esc-chat.msg-bubbles { min-height: 0; gap: var(--e-8); }
/* Compose : note contextuelle spécifique À traiter */
.ctrl-compose-note {
  font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--e-10) var(--e-12);
}
/* Textarea reply caché si pas de réponse attendue */
#ctrl-esc-reply-input.hidden { display: none; }
/* Badge catégorie dans l'en-tête de détail */
#ctrl-esc-thread-head .ctrl-esc-cat { flex-shrink: 0; }

/* ── Sous-onglets À traiter (Escalades / Litiges / Annulations) ── */
.ctrl-esc-subtabs {
  display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.ctrl-esc-subtab {
  flex: 1; padding: var(--e-8) var(--e-4); border: none; background: transparent;
  color: var(--text-3); font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer;
  border-bottom: 2px solid transparent; transition: color var(--t-moyen), border-color var(--t-moyen);
  white-space: nowrap;
}
.ctrl-esc-subtab:not(.active):hover  { color: var(--text); }
.ctrl-esc-subtab.active { color: var(--text); border-bottom-color: var(--violet); }
.ctrl-esc-subtab-count  { opacity: .6; font-weight: var(--fw-normal); margin-left: var(--e-4); }

/* ── Chip compte vendeur (droite de la ligne titre dans les items) ── */
.msg-item-acct-chip {
  margin-left: auto; flex-shrink: 0; padding-left: var(--e-6);
  font-size: var(--t-mini); color: var(--text-3); white-space: nowrap;
}
/* nom acheteur doit s'écrêter pour laisser la place au chip et au badge */
.msg-item-top .msg-item-name { min-width: 0; flex-shrink: 1; }

#ctrl-esc-detail,
#ctrl-esc-detail.hidden {
  display: flex; width: auto; flex: 1; min-width: 0; overflow: hidden;
}
.ctrl-split-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-12); padding: var(--e-24); text-align: center; color: var(--text-3);
}
.ctrl-split-empty svg { opacity: .4; }
.ctrl-split-empty span { font-size: var(--t-base); max-width: 260px; line-height: var(--lh-normal); }
#ctrl-split-esc.split--open #ctrl-esc-detail-empty { display: none; }
#ctrl-split-esc:not(.split--open) #ctrl-esc-detail > .ctrl-split-bar,
#ctrl-split-esc:not(.split--open) #ctrl-esc-detail > .ctrl-chat,
#ctrl-split-esc:not(.split--open) #ctrl-esc-detail > .ctrl-compose { display: none; }

/* ── Barre détail redesignée ── */
.ctrl-split-bar {
  display: flex; align-items: center; gap: var(--e-10);
  padding: var(--e-12) var(--e-16); background: var(--surface-2);
  border-bottom: 1px solid var(--border); flex-shrink: 0; min-height: 52px;
}
.ctrl-split-back {
  width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface);
  color: var(--text-2); cursor: pointer; transition: var(--transi); flex-shrink: 0;
}
.ctrl-split-back:hover { color: var(--text); border-color: var(--border-strong); }
.ctrl-split-info {
  font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--text); flex: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ctrl-split-link {
  display: flex; align-items: center; gap: var(--e-6); flex-shrink: 0;
  padding: var(--e-6) var(--e-10); border-radius: var(--r-sm); border: 1px solid var(--border);
  background: transparent; color: var(--text-2);
  font-size: var(--t-meta); font-weight: var(--fw-fort); text-decoration: none;
  transition: var(--transi);
}
.ctrl-split-link:hover { color: var(--violet-soft); border-color: var(--violet); }
.ctrl-split-link.hidden { display: none; }

/* ── Widget "Contexte de l'annonce" — panneau droit À traiter ── */
.ctrl-esc-widget { display: none; }

/* Racine du widget */
.esc-widget {
  display: flex; flex-direction: column; gap: 0;
  font-size: var(--t-base); width: 100%; min-width: 0;
}

/* Header : compte + badge */
.esc-widget-hdr {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-10) var(--e-14) var(--e-8);
  border-bottom: 1px solid var(--border);
  background: linear-gradient(to bottom, rgba(var(--th-panneau-rgb),0.45) 0%, rgba(var(--th-panneau-rgb),0.92) 100%);
  position: sticky; top: 0; z-index: 1;
}
.esc-widget-acct { flex: 1; min-width: 0; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.esc-widget-acct-label { color: var(--text-3); margin-right: var(--e-4); }
.esc-widget-acct strong { color: var(--text); font-weight: var(--fw-fort); }

/* Section générique */
.esc-widget-section { display: flex; flex-direction: column; gap: var(--e-8); padding: var(--e-12) var(--e-14); }

/* Photos annonce — grille adaptative ratio 3:4 */
.esc-widget-photos { overflow: hidden; }
/* 1 photo : centrée avec marges */
.esc-widget-photos--1 { display: flex; justify-content: center; padding: var(--e-10) var(--e-20) 0; }
.esc-widget-photos--1 .esc-widget-photo-img { width: 100%; aspect-ratio: 3/4; object-fit: cover; display: block; border-radius: var(--r-md); }
/* 2 photos : côte à côte centrées */
.esc-widget-photos--2 { display: flex; justify-content: center; gap: var(--e-6); padding: var(--e-10) var(--e-14) 0; }
.esc-widget-photos--2 .esc-widget-photo-img { flex: 1; min-width: 0; aspect-ratio: 3/4; object-fit: cover; display: block; border-radius: var(--r-sm); }
/* 3 photos : triptique 3 colonnes égales */
.esc-widget-photos--3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e-4); padding: var(--e-8) 0 0; }
.esc-widget-photos--3 .esc-widget-photo-img { width: 100%; object-fit: cover; display: block; aspect-ratio: 3/4; border-radius: var(--r-micro); }

/* Carousel annonce */
.esc-widget-carousel { position: relative; overflow: hidden; background: var(--surface-2); }
.esc-widget-carousel-img { width: 100%; aspect-ratio: 3/4; object-fit: cover; display: block; transition: opacity var(--t-moyen); }
.esc-widget-carousel-img.loading { opacity: 0; }
.esc-widget-carousel-btn {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: rgba(var(--th-panneau-rgb),.4); border: none; color: var(--text);
  width: 20px; height: 32px; border-radius: var(--r-micro); cursor: pointer;
  font-size: var(--t-body); line-height: var(--lh-un); display: flex; align-items: center; justify-content: center;
  z-index: 2; transition: background var(--t-bref), opacity var(--t-moyen); padding: 0;
  opacity: 0;
}
.esc-widget-carousel:hover .esc-widget-carousel-btn { opacity: 1; }
.esc-widget-carousel-btn:hover { background: rgba(var(--th-panneau-rgb),.75); }
.esc-widget-carousel-btn--prev { left: 4px; }
.esc-widget-carousel-btn--next { right: 4px; }
.esc-widget-carousel-counter {
  position: absolute; bottom: 8px; right: 10px;
  background: rgba(var(--th-panneau-rgb),.6); color: var(--text);
  font-size: var(--t-micro); padding: var(--e-2) var(--e-8); border-radius: var(--r-md); pointer-events: none;
}

/* Loading placeholder */
.esc-widget-loading { display: flex; align-items: center; justify-content: center; height: 72px; gap: var(--e-6); }
.esc-widget-loading span { width: 5px; height: 5px; border-radius: 50%; background: var(--text-3); animation: esc-dot-pulse 1.1s ease infinite; }
.esc-widget-loading span:nth-child(2) { animation-delay: var(--t-moyen); }
.esc-widget-loading span:nth-child(3) { animation-delay: var(--t-long); }
@keyframes esc-dot-pulse { 0%,100% { opacity: .2; transform: scale(.8) } 50% { opacity: 1; transform: scale(1) } }

/* Titre */
.esc-widget-title { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); line-height: var(--lh-serre); }

/* Description dépliable */
.esc-widget-desc { font-size: var(--t-meta); color: var(--text-2); }
.esc-widget-desc summary { cursor: pointer; color: var(--text-3); user-select: none; padding: var(--e-2) 0; list-style: none; }
.esc-widget-desc summary::before { content: '▸ Description'; font-size: var(--t-meta); }
.esc-widget-desc[open] summary::before { content: '▾ Description'; }
.esc-widget-desc-body { padding-top: var(--e-6); line-height: var(--lh-normal); white-space: pre-wrap; color: var(--text-2); }

/* Ligne de prix */
.esc-widget-prices { display: flex; gap: var(--e-8); }
.esc-widget-price {
  flex: 1; display: flex; flex-direction: column; gap: var(--e-2);
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--e-8) var(--e-10);
}
.esc-widget-price--cost .esc-widget-price-val { color: var(--red); }
.esc-widget-price-label { font-size: var(--t-mini); text-transform: uppercase; letter-spacing: var(--ls-large); color: var(--text-3); }
.esc-widget-price-val { font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--violet-soft); }

/* Séparateur + label section */
.esc-widget-sep { border-top: 1px solid var(--border); margin: 0 var(--e-14); }
.esc-widget-section-label {
  font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase;
  letter-spacing: var(--ls-ample); color: var(--text-3);
  padding: var(--e-10) var(--e-14) 0;
}

/* Grille photos SHEIN (3 colonnes) */
.esc-widget-ref-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e-6); }
.esc-widget-ref-img { width: 100%; aspect-ratio: 3/4; object-fit: cover; border-radius: var(--r-sm); border: 1px solid var(--border); }

/* Card SKU + bouton SHEIN — verticale */
.esc-widget-info-card {
  background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--r-sm); overflow: hidden;
}
/* Ligne SKU : label + valeur tronquée, cliquable pour copier */
.esc-widget-sku-line {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-8) var(--e-10); cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.esc-widget-sku-line:only-child { border-bottom: none; }
.esc-widget-sku-line:hover .esc-widget-sku-val { color: var(--violet-soft); }
.esc-widget-sku-label { font-size: var(--t-micro); font-weight: var(--fw-fort); text-transform: uppercase; letter-spacing: var(--ls-large); color: var(--text-3); flex-shrink: 0; }
.esc-widget-sku-label::after { content: ' ⎘'; opacity: 0.45; }
.esc-widget-sku-val { flex: 1; min-width: 0; font-size: var(--t-meta); font-family: monospace; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: color var(--t-bref); }
/* Bouton SHEIN — pleine largeur */
.esc-widget-shein-btn {
  display: flex; align-items: center; justify-content: center; gap: var(--e-6);
  width: 100%; box-sizing: border-box;
  padding: var(--e-8) var(--e-12); text-decoration: none;
  font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--violet-soft);
  transition: background var(--t-bref), color var(--t-bref);
}
.esc-widget-shein-btn:hover { background: rgba(var(--th-accent-rgb),.12); }

/* ── Thread bulles ── */
.ctrl-chat {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: var(--e-16); display: flex; flex-direction: column; gap: var(--e-10);
}
.chat-row { display: flex; }
.chat-row--buyer { justify-content: flex-start; }
.chat-row--bot   { justify-content: flex-end; }
.chat-bubble {
  max-width: 78%; padding: var(--e-10) var(--e-14); border-radius: var(--r-xl);
  font-size: var(--t-base); line-height: var(--lh-normal); word-break: break-word;
}
.chat-bubble-role {
  font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase;
  opacity: .5; margin-bottom: var(--e-6); display: block; letter-spacing: var(--ls-large);
}
.chat-bubble--buyer {
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-bottom-left-radius: 4px;
}
/* Bot — droite, violet */
.chat-bubble--bot {
  background: rgba(var(--th-accent-rgb),0.12); color: var(--violet-soft);
  border: 1px solid rgba(var(--th-accent-rgb),0.28); border-bottom-right-radius: 4px;
}

/* Chat vide */
.ctrl-chat .ctrl-empty { grid-column: 1 / -1; }

/* ── Zone de composition (panneau escalation) ── */
.ctrl-compose {
  flex-shrink: 0; border-top: 1px solid var(--border);
  padding: var(--e-10) var(--e-14) var(--e-12); display: flex; flex-direction: column; gap: var(--e-8);
}
.ctrl-compose-area {
  width: 100%; resize: none;
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font-size: var(--t-base); padding: var(--e-8) var(--e-10); font-family: inherit;
  line-height: var(--lh-normal); box-sizing: border-box; transition: border-color var(--t-moyen);
}
.ctrl-compose-area:focus { outline: none; border-color: var(--violet); }
.ctrl-compose-area.hidden { display: none; }

.ctrl-compose-note {
  font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--e-10) var(--e-12);
}

.ctrl-compose-row { display: flex; gap: var(--e-8); }

.ctrl-compose-done {
  flex: 1; padding: var(--e-8) var(--e-10); border-radius: var(--r-sm); font-size: var(--t-meta);
  font-weight: var(--fw-fort); cursor: pointer; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text-2); transition: var(--transi);
}
.ctrl-compose-done:hover { background: var(--surface-3,var(--surface-2)); color: var(--text); }
.ctrl-compose-done:disabled { opacity: .5; cursor: not-allowed; }

.ctrl-compose-send {
  flex: 2; padding: var(--e-8) var(--e-14); border-radius: var(--r-sm); font-size: var(--t-meta);
  font-weight: var(--fw-fort); cursor: pointer; border: 1px solid var(--violet);
  background: var(--violet-tint); color: var(--violet-soft);
  transition: var(--transi); display: flex; align-items: center; justify-content: center; gap: var(--e-6);
}
.ctrl-compose-send:hover { background: var(--violet); color: var(--sur-accent); }
.ctrl-compose-send:disabled { opacity: .5; cursor: not-allowed; }
.ctrl-compose-send.sent { background: rgba(74,222,128,.15); border-color: var(--green); color: var(--green); }

/* ── Lien direct Vinted sur carte d'escalade ── */
.ctrl-esc-card { position: relative; }
.ctrl-esc-card-link {
  position: absolute; top: 8px; right: 8px;
  display: none; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-3); transition: var(--transi);
}
.ctrl-esc-card:hover .ctrl-esc-card-link,
.ctrl-esc-card.active .ctrl-esc-card-link { display: flex; }
.ctrl-esc-card-link:hover { color: var(--violet-soft); border-color: var(--violet); }
.ctrl-esc-buyer { color: var(--violet-soft); font-weight: var(--fw-fort); }

/* ── Widget contextuel par catégorie ── */
.ctrl-esc-widget { flex-shrink: 0; border-top: 1px solid var(--border); }
.ctrl-esc-widget.hidden { display: none; }
/* widget visible dès qu'il n'a pas la classe hidden — géré par JS */

.esc-widget-litige {
  border-left: 3px solid rgba(255,80,80,.5);
  background: rgba(255,80,80,.04);
  padding: var(--e-10) var(--e-14); display: flex; flex-direction: column; gap: var(--e-8);
}
.esc-widget-nego {
  border-left: 3px solid rgba(167,139,250,.5);
  background: rgba(167,139,250,.06);
  padding: var(--e-10) var(--e-14);
}
.esc-widget-rupture {
  border-left: 3px solid rgba(255,165,0,.4);
  background: rgba(255,165,0,.04);
  padding: var(--e-10) var(--e-14);
}
.esc-widget-head {
  font-size: var(--t-mini); font-weight: var(--fw-gras); text-transform: uppercase;
  letter-spacing: var(--ls-large); color: var(--text-2); display: flex; align-items: center; gap: var(--e-6);
}
.esc-widget-head svg { flex-shrink: 0; }
.esc-widget-photos { display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
.esc-widget-photo-col { padding: 0 var(--e-8) 0 0; }
.esc-widget-photo-col + .esc-widget-photo-col {
  border-left: 1px solid var(--border); padding: 0 0 0 var(--e-8);
}
.esc-widget-photo-label {
  font-size: var(--t-micro); font-weight: var(--fw-fort); text-transform: uppercase; color: var(--text-3);
  margin-bottom: var(--e-6); letter-spacing: var(--ls-leger);
}
.esc-widget-photo-row { display: flex; gap: var(--e-6); flex-wrap: wrap; }
.esc-widget-thumb {
  width: 52px; height: 52px; border-radius: var(--r-sm); overflow: hidden;
  border: 1px solid var(--border); background: var(--surface-2);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.esc-widget-thumb img { width: 100%; height: 100%; object-fit: cover; }
.esc-widget-thumb--ph { color: var(--text-3); font-size: var(--t-micro); text-align: center; padding: var(--e-4); }
.esc-widget-price-row {
  display: flex; justify-content: space-between; align-items: center;
  font-size: var(--t-base); padding: var(--e-4) 0;
}
.esc-widget-price-row .esc-widget-price-label { color: var(--text-3); text-transform: none; letter-spacing: var(--ls-zero); font-size: inherit; }
.esc-widget-price-row .esc-widget-price-val { font-weight: var(--fw-fort); color: var(--text); font-size: inherit; }
.esc-widget-price-row .esc-widget-price-val.danger { color: var(--red); }
.esc-widget-price-row .esc-widget-price-val.safe { color: var(--green); }
.esc-widget-note { font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-normal); }

/* ── Cartes d'activité (grille gauche) ── */
.ctrl-feed-card { cursor: pointer; transition: background var(--t-moyen), border-color var(--t-moyen);
  display: flex; flex-direction: column; gap: var(--e-6) }
.ctrl-feed-card:hover  { background: var(--surface-2); border-color: var(--border-strong); }
.ctrl-feed-card.active { border-color: var(--violet); background: var(--violet-tint); }

.ctrl-feed-card-meta {
  display: flex; align-items: center; gap: var(--e-6); flex-wrap: wrap;
}
.ctrl-feed-card-icon    { font-size: var(--t-base); }
.ctrl-feed-card-account { font-size: var(--t-mini); font-weight: var(--fw-gras); color: var(--text-2); }
.ctrl-feed-card-time    { font-size: var(--t-micro); color: var(--text-3); margin-left: auto;
                           font-variant-numeric: tabular-nums; }
.ctrl-feed-card-dress   { font-size: var(--t-meta); color: var(--text-3);
                           white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ctrl-feed-card-preview { font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-serre);
                           display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
                           overflow: hidden; }
.ctrl-feed-card-cat {
  font-size: var(--t-micro); padding: var(--e-1) var(--e-6); border-radius: var(--r-sm);
  background: var(--surface-3, var(--surface-2)); color: var(--text-3);
  border: 1px solid var(--border);
}

/* Media : grille 1 col sur écran étroit */
@media (max-width: 820px) {
  .ctrl-split.split--open .ctrl-split-list { flex: 0 0 240px; }
  .ctrl-split-list { grid-template-columns: 1fr; }
}

/* ── Panneaux collapsibles (Instructions bot + Exemples) ── */
.dem-panel--instr,
.dem-panel--examples {
  flex: none;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.dem-panel-toggle {
  width: 100%; display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-14) var(--e-16);
  background: var(--surface); border: none;
  color: var(--text-2); font-size: var(--t-base); font-weight: var(--fw-fort);
  cursor: pointer; text-align: left;
  transition: background var(--t-moyen), color var(--t-moyen);
}
.dem-panel-toggle:hover { background: var(--surface-2); color: var(--text); }
.dem-panel-chevron { flex-shrink: 0; transition: transform var(--t-moyen) var(--c-pose); }
.dem-panel-chevron.open { transform: rotate(90deg); }
.dem-panel-icon { flex-shrink: 0; opacity: .6; }
.dem-panel-toggle:hover .dem-panel-icon { opacity: 1; }
.dem-panel-toggle span:nth-child(3) { flex: 1; }
.dem-panel-body {
  padding: var(--e-14) var(--e-16) var(--e-16);
  border-top: 1px solid var(--border);
  background: var(--bg-2);
  display: flex; flex-direction: column; gap: var(--e-10);
}
.dem-instr-badge {
  padding: var(--e-2) var(--e-8); border-radius: var(--r-xl);
  background: var(--violet-tint); border: 1px solid var(--violet);
  color: var(--violet-soft); font-size: var(--t-mini); font-weight: var(--fw-gras);
}
.dem-instr-hint {
  font-size: var(--t-base); color: var(--text-3); margin: 0; line-height: var(--lh-normal);
}
.dem-instr-area {
  width: 100%; resize: vertical;
  background: var(--bg); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); color: var(--text); font-size: var(--t-base);
  padding: var(--e-10) var(--e-12); line-height: var(--lh-normal); font-family: inherit;
  transition: border-color var(--t-moyen);
  min-height: 100px;
}
.dem-instr-area:focus { outline: none; border-color: var(--violet); }
.dem-instr-foot {
  display: flex; justify-content: flex-end; gap: var(--e-8); align-items: center;
}
.dem2-go--sm {
  padding: var(--e-8) var(--e-14); font-size: var(--t-base); gap: var(--e-6);
  border-radius: var(--r-md);
}

/* ── Exemples mémorisés ── */
.dem-examples-count {
  padding: var(--e-2) var(--e-8); border-radius: var(--r-xl);
  background: var(--surface-3); border: 1px solid var(--border-strong);
  color: var(--text-3); font-size: var(--t-mini); font-weight: var(--fw-gras);
}
.dem-examples-empty { font-size: var(--t-base); color: var(--text-3); text-align: center; padding: var(--e-12) 0; }
.dem-example-card {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
}
.dem-example-buyer,
.dem-example-reply {
  display: flex; gap: var(--e-8); align-items: flex-start;
  padding: var(--e-8) var(--e-10); font-size: var(--t-base); line-height: var(--lh-normal);
}
.dem-example-buyer { background: var(--surface-2); }
.dem-example-lbl {
  flex-shrink: 0; width: 58px;
  font-size: var(--t-mini); font-weight: var(--fw-gras); text-transform: uppercase;
  color: var(--text-3); padding-top: var(--e-2);
}
.dem-example-txt { color: var(--text-2); flex: 1; }
.dem-example-del {
  position: absolute; top: 7px; right: 7px;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--e-4) var(--e-6);
  color: var(--text-3); cursor: pointer;
  transition: var(--transi);
}
.dem-example-del:hover { background: rgba(255,80,80,.15); border-color: rgba(255,80,80,.4); color: var(--red); }

/* ── Bouton Pin (épingler comme exemple) ── */
.dem2-act--pin { }
.dem2-act--pinned { color: var(--violet-soft); border-color: var(--violet); pointer-events: none; }

/* ═══════════════ INBOX DEMANDES ═══════════════ */

/* ── Colonne inbox (gauche) ── */

/* ── Config commune ── */

/* ── Bouton générer tout + progression ── */

/* ── Recherche + filtres ── */

/* ── Liste des demandes ── */

/* ── Panneau détail (droite) ── */

/* ── Modale coller des messages ── */

/* Mode chat — colonne gauche masquée */

/* Bouton retour (affiché en mode chat) */

/* ── Colonne gauche — cartes empilées ───────────────── */

/* Carte générique */

/* Message client — style "reçu" distinct */

/* Consigne — style "action" distinct */

/* Textarea message — fixe 3 lignes */

/* ── Carte Robe ─────────────────────────────────────── */

/* Coloris pills dans la carte robe */

/* ── Carte Options (taille + ton côte à côte) ────────── */

/* Pills taille & ton */
.dem-pills { display: flex; gap: var(--e-6); flex-wrap: wrap; }
.dem-pill {
  height: 28px; padding: 0 var(--e-14); border-radius: var(--r-xl);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-2); font-size: var(--t-base); font-weight: var(--fw-moyen);
  cursor: pointer; transition: var(--transi);
}
.dem-pill:not(.active):hover { border-color: var(--violet-mid); color: var(--text); background: var(--surface-2); }
.dem-pill.active { background: var(--violet-tint); border-color: var(--violet); color: var(--violet-soft); font-weight: var(--fw-fort); }

/* ═══ Demandes v2 — composeur rapide épuré ═══ */
.dem2 { width: 100%; display: flex; flex-direction: column; gap: var(--e-16); }

.dem2-composer {
  background: linear-gradient(158deg, rgba(var(--th-voile),0.04), rgba(var(--th-voile),0.012));
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-18);
  display: flex; flex-direction: column; gap: var(--e-12);
  box-shadow: 0 6px 22px -14px rgba(var(--th-ombre),0.55), inset 0 1px 0 rgba(var(--th-voile),0.04);
}
.dem2-label { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-2); }
.dem2-msg {
  width: 100%; resize: vertical; min-height: 78px;
  background: var(--bg-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); padding: var(--e-12) var(--e-14);
  color: var(--text); font-size: var(--t-small); line-height: var(--lh-normal); font-family: inherit;
}
.dem2-msg:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px var(--violet-tint); }

.dem2-context {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--e-8) var(--e-10);
}
.dem2-ctx-lbl { font-size: var(--t-mini); font-weight: var(--fw-fort); color: var(--text-3); text-transform: uppercase; letter-spacing: var(--ls-large); }
.dem2-ctx-sep { width: 1px; align-self: stretch; background: var(--border); margin: var(--e-2) var(--e-2); }
.dem2-dress-btn {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-12); border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-2); font-size: var(--t-base); font-weight: var(--fw-moyen); cursor: pointer;
  transition: var(--transi-vif);
}
.dem2-dress-btn:hover { border-color: var(--violet); color: var(--text); background: var(--violet-tint); }
.dem2-dress-chip {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-4) var(--e-6) var(--e-4) var(--e-12); border-radius: var(--r-sm);
  background: var(--violet-tint); border: 1px solid var(--violet-mid);
  color: var(--violet-soft); font-size: var(--t-base); font-weight: var(--fw-fort);
}
.dem2-dress-rm {
  border: none; background: rgba(var(--th-voile),0.08); color: var(--text-2);
  width: 18px; height: 18px; border-radius: 50%; cursor: pointer; line-height: var(--lh-un); font-size: var(--t-small);
}
.dem2-dress-rm:hover { background: var(--danger); color: var(--text); }

.dem2-go {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: var(--e-8);
  padding: 0 var(--e-22); height: 42px; border: none; border-radius: var(--r-md);
  background: var(--aurora); color: var(--sur-accent); font-size: var(--t-small); font-weight: var(--fw-fort); cursor: pointer;
  box-shadow: 0 10px 26px -10px rgba(var(--th-accent-rgb),0.6);
  transition: filter var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.dem2-go:hover { filter: brightness(1.08); }
.dem2-go:active { transform: translateY(1px); }
.dem2-go:disabled { opacity: 0.5; cursor: not-allowed; filter: none; box-shadow: none; }

/* Fil */
.dem2-thread { display: flex; flex-direction: column; gap: var(--e-14); }
.dem2-turn { display: flex; flex-direction: column; gap: var(--e-4); max-width: 88%; }
.dem2-turn--buyer { align-self: flex-start; align-items: flex-start; }
.dem2-turn--ai    { align-self: flex-end;   align-items: flex-end; }
.dem2-turn-who { font-size: var(--t-mini); font-weight: var(--fw-fort); color: var(--text-3); text-transform: uppercase; letter-spacing: var(--ls-large); padding: 0 var(--e-4); }
.dem2-bubble {
  padding: var(--e-10) var(--e-14); border-radius: var(--r-lg); font-size: var(--t-small); line-height: var(--lh-normal);
  white-space: pre-wrap; word-break: break-word;
}
.dem2-turn--buyer .dem2-bubble {
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
  border-bottom-left-radius: 4px;
}
.dem2-turn--ai .dem2-bubble {
  background: var(--violet); color: var(--sur-accent); border-bottom-right-radius: 4px;
}
.dem2-bubble--typing { display: inline-flex; gap: var(--e-4); align-items: center; }
.dem2-bubble--typing span { width: 6px; height: 6px; border-radius: 50%; background: rgba(var(--th-voile),0.8); animation: demTyping 1.2s infinite ease-in-out; }
.dem2-bubble--typing span:nth-child(2) { animation-delay: var(--t-moyen); }
.dem2-bubble--typing span:nth-child(3) { animation-delay: var(--t-long); }
@keyframes demTyping { 0%,60%,100% { opacity: 0.3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }
.dem2-turn-actions { display: flex; gap: var(--e-6); padding: 0 var(--e-4); }
.dem2-act {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-2); font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer;
  transition: var(--transi-vif);
}
.dem2-act:hover { border-color: var(--violet); color: var(--violet-soft); background: var(--violet-tint); }

/* Affiner */
.dem2-refine { display: flex; gap: var(--e-8); align-items: center; margin-top: var(--e-2); }
.dem2-refine-input {
  flex: 1; background: var(--bg-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); padding: var(--e-10) var(--e-14); color: var(--text); font-size: var(--t-base); font-family: inherit;
}
.dem2-refine-input:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px var(--violet-tint); }
.dem2-refine-go {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: var(--r-md); border: none;
  background: var(--violet-tint); color: var(--violet-soft); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: var(--transi-vif);
}
.dem2-refine-go:hover { background: var(--violet); color: var(--sur-accent); }

/* Récents */
.dem2-recents { border-top: 1px solid var(--border); padding-top: var(--e-12); }
.dem2-recents-head {
  display: inline-flex; align-items: center; gap: var(--e-8);
  background: none; border: none; cursor: pointer;
  color: var(--text-2); font-size: var(--t-base); font-weight: var(--fw-fort);
}
.dem2-recents-head:hover { color: var(--text); }
.dem2-recents-chevron { transition: transform var(--d-fast) var(--c-pose); }
.dem2-recents.open .dem2-recents-chevron { transform: rotate(90deg); }
.dem2-recents-count {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: 0 var(--e-8); font-size: var(--t-mini); color: var(--text-3);
}
.dem2-recents-list { display: flex; flex-direction: column; gap: var(--e-6); margin-top: var(--e-10); }
.dem2-recent {
  display: flex; align-items: center; gap: var(--e-4);
  border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border);
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose);
}
.dem2-recent:hover { border-color: var(--border-strong); }
.dem2-recent.active { border-color: var(--violet); background: var(--violet-tint); }
.dem2-recent-main {
  flex: 1; min-width: 0;
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-10);
  background: none; border: none; cursor: pointer; text-align: left;
  padding: var(--e-10) var(--e-4) var(--e-10) var(--e-12); color: var(--text-2); font-size: var(--t-base);
  transition: color var(--d-fast) var(--c-pose);
}
.dem2-recent:hover .dem2-recent-main { color: var(--text); }
.dem2-recent-txt { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dem2-recent-meta {
  flex-shrink: 0; max-width: 42%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: var(--t-mini); color: var(--violet-soft);
}
.dem2-recent-del {
  flex-shrink: 0; width: 30px; height: 30px; margin-right: var(--e-6);
  border-radius: var(--r-sm); border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text-2); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 1; transition: var(--transi-vif);
}
.dem2-recent-del:hover { background: rgba(var(--th-danger-rgb),0.16); border-color: rgba(var(--th-danger-rgb),0.45); color: var(--red); }

/* Contexte robe — vignettes photos cliquables */
.dem2-dress-photos { display: inline-flex; align-items: center; gap: var(--e-6); }
.dem2-dress-thumb {
  width: 38px; height: 38px; border-radius: var(--r-sm); overflow: hidden;
  border: 1px solid var(--border-strong); background: var(--surface-2);
  cursor: zoom-in; padding: 0; flex-shrink: 0;
  transition: border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.dem2-dress-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dem2-dress-thumb:hover { border-color: var(--violet); transform: translateY(-1px); }

/* Barre du bas — nouveau message de l'acheteur (aller-retour) */
.dem2-followup {
  display: flex; flex-direction: column; gap: var(--e-8);
  background: linear-gradient(158deg, var(--cok-bg), rgba(var(--th-voile),0.01));
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-12) var(--e-14);
}
.dem2-followup-label { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-3); text-transform: uppercase; letter-spacing: var(--ls-large); }
.dem2-followup-row { display: flex; gap: var(--e-8); align-items: center; }
.dem2-followup-input {
  flex: 1; background: var(--bg-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); padding: var(--e-10) var(--e-14); color: var(--text); font-size: var(--t-small); font-family: inherit;
}
.dem2-followup-input:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px var(--violet-tint); }
.dem2-followup-go {
  flex-shrink: 0; width: 42px; height: 40px; border-radius: var(--r-md); border: none;
  background: var(--aurora); color: var(--sur-accent); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 20px -10px rgba(var(--th-accent-rgb),0.6);
  transition: filter var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.dem2-followup-go:hover { filter: brightness(1.08); }
.dem2-followup-go:active { transform: translateY(1px); }

/* Consigne */

/* Bouton générer — ancré en bas de la colonne */

/* Compat ancien code */

/* ── Colonne droite — pleine hauteur ────────────────── */

/* Barre d'onglets */

/* Fil de messages */

/* Zone réponse compat (cachée) */

/* État vide */

/* Texte réponse */

/* Barre copier sous la réponse */

/* Compat JS */

/* Chat affinement — ancré en bas */

/* Compat textarea générique */

/* ═══════════════════════════════════════════════════════
   ATELIER
   ═══════════════════════════════════════════════════════ */
/* Ancien header inline neutralisé (remplacé par la sticky topbar Aurora) */
.atelier-header { display: none; }
.atelier-title { display: none; }
.atelier-subtitle { display: none; }

/* Stepper Aurora — 7 pastilles 28 px reliées par une ligne violette progressive */
.atelier-progress {
  display: grid;
  /* ⚠️⚠️⚠️ SEPT COLONNES ÉCRITES EN DUR (corrigé le 05/09). Le parcours en comptait sept
     quand cette ligne a été écrite ; il en a TROIS depuis que Niche, Source, Sujet, Décor
     et Identité sont partis. Les trois étapes se tassaient donc sur la moitié gauche et
     laissaient un grand vide à droite — Amadou : « les étapes au-dessus doivent prendre
     tout l'espace de la frise ».
     C'est le même défaut qu'`atelierVisibleSteps()[3]` et que la borne `step > 7` : un
     nombre en dur dans un parcours qui se DÉDUIT. Le compte est maintenant posé par le
     dessinateur, qui le connaît. Le 3 n'est qu'un repli si la variable manque. */
  grid-template-columns: repeat(var(--at-etapes, 3), minmax(0, 1fr));
  gap: 0;
  padding: var(--e-20) var(--e-8);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  position: relative;
  overflow: visible;
  margin-bottom: 0;
}
.atelier-prog-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-8);
  position: relative;
  text-align: center;
  padding: 0 var(--e-4);
  background: transparent;
  border: none;
  color: inherit;
  font-family: inherit;
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  min-width: 0;
  flex: none;
}
.atelier-prog-dot {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: rgba(var(--th-voile),0.04);
  border: 1px solid var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  position: relative;
  z-index: 2;
  flex-shrink: 0;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
/* ⚠️⚠️⚠️ « TERMINÉE » ET « COURANTE » PEUVENT ÊTRE VRAIES ENSEMBLE (05/09). Depuis que la
   frise dit ce qui est FAIT et non plus où l'on est, l'étape où l'on se trouve est souvent
   terminée aussi — c'est le cas normal juste après une génération.
   ⚠️ ET `.active` NE REDÉCLARE PAS `font-size`. La règle « terminée » met le chiffre à 0
   pour laisser la place au ✓ ; sur une étape à la fois terminée et courante, le violet
   revenait mais le CHIFFRE restait invisible, remplacé par un ✓ sur fond violet. C'est le
   piège connu de ce projet : une propriété qu'une règle ne REDÉCLARE pas passe quand même.
   Le vert et le ✓ sont donc réservés aux étapes terminées qu'on a QUITTÉES. */
.atelier-prog-step.done:not(.active) .atelier-prog-dot {
  background: var(--green);
  color: transparent;
  border-color: transparent;
  font-size: 0;
}
.atelier-prog-step.done:not(.active) .atelier-prog-dot::after {
  content: '✓';
  color: var(--text);
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
}
.atelier-prog-step.active .atelier-prog-dot {
  background: var(--violet);
  color: var(--sur-accent);
  border-color: transparent;
  box-shadow: 0 0 0 4px var(--tier-premium-bg), 0 8px 22px -8px var(--violet-glow);
}
.atelier-prog-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-zero);
  text-transform: none;
  color: var(--text-3);
  margin-top: 0;
  line-height: var(--lh-titre);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.atelier-prog-step.active .atelier-prog-label,
.atelier-prog-step.done   .atelier-prog-label { color: var(--text); }

/* Ligne de liaison entre pastilles : violette jusqu'à la dernière étape "done"
   ou "active", neutre après. */
.atelier-prog-line {
  position: absolute;
  top: 14px;
  left: 50%;
  right: -50%;
  height: 1px;
  background: var(--border-strong);
  z-index: 1;
  transition: background var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
.atelier-prog-step.done .atelier-prog-line {
  background: var(--violet);
  box-shadow: 0 0 8px var(--violet-glow);
}
.atelier-prog-step:last-child .atelier-prog-line { display: none; }
/* Pendant un basculement de mode : pas d'animation des pastilles (évite tout flash). */
.atelier-prog-noanim .atelier-prog-dot,
.atelier-prog-noanim .atelier-prog-line { transition: none !important; }

/* Steps container — gap entre stepper et step actif */
.atelier-steps {
  display: flex;
  flex-direction: column;
  gap: var(--e-16);
  margin-top: var(--e-16);
}

/* Step (carte d'étape) — accordéon */
.atelier-step {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  min-width: 0;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: border-color var(--t-moyen), opacity var(--t-moyen), box-shadow var(--t-moyen);
}
.atelier-step.step-active  { border-color: var(--violet-mid); box-shadow: 0 0 0 1px rgba(var(--th-accent-rgb),.15), var(--shadow-card); }
.atelier-step.step-done    { border-color: var(--border); opacity: 1; }
.atelier-step.step-locked  { opacity: .38; pointer-events: none; }
.atelier-step.step-invalidated { border-color: rgba(var(--th-danger-rgb),.3); }

/* Header cliquable */
.atelier-step-header {
  display: flex; align-items: center; gap: var(--e-12);
  padding: var(--e-14) var(--e-20); cursor: pointer; user-select: none;
  transition: background var(--t-moyen);
}
.atelier-step.step-active .atelier-step-header  { cursor: default; }
.atelier-step.step-locked .atelier-step-header  { cursor: not-allowed; }
.atelier-step:not(.step-active):not(.step-locked) .atelier-step-header:hover { background: var(--surface); }

/* Numéro d'étape */
.atelier-step-num {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--bg-2); border: 1.5px solid var(--border-strong);
  color: var(--text-3); font-size: var(--t-meta); font-weight: var(--fw-gras);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  transition: var(--transi);
}
.atelier-step.step-active .atelier-step-num,
.atelier-step.step-done   .atelier-step-num { background: var(--violet); border-color: var(--violet); color: var(--sur-accent); }
.atelier-step.step-done   .atelier-step-num::after { content: '✓'; font-size: var(--t-micro); }
.atelier-step.step-done   .atelier-step-num span  { display: none; }

/* Infos titre + résumé */
.atelier-step-header-info  { flex: 1; min-width: 0; }
.atelier-step-header-title { font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--text); }
.atelier-step-header-summary {
  font-size: var(--t-meta); color: var(--text-3); margin-top: var(--e-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 420px;
}
.atelier-step-header-chevron { color: var(--text-3); transition: transform var(--t-moyen); flex-shrink: 0; margin-left: var(--e-4); }
.atelier-step.step-active .atelier-step-header-chevron { transform: rotate(180deg); }

/* Corps — fade + glissement vers le bas */
.atelier-step-body {
  overflow: hidden; opacity: 0; max-height: 0;
  transform: translateY(-10px);
  transition: opacity var(--t-long) var(--c-pose), transform var(--t-long) var(--c-pose), max-height var(--t-long) var(--c-pose), padding var(--t-long) var(--c-pose);
  padding: 0 var(--e-24);
  display: flex; flex-direction: column; gap: var(--e-18);
}
.atelier-step-body.open {
  opacity: 1;
  transform: translateY(0);
  padding: 0 var(--e-24) var(--e-24);
}

/* Titre interne (conservé mais masqué — le header le remplace) */
.atelier-step-title { display: none; }
.atelier-optional {
  font-size: var(--t-meta);
  font-weight: var(--fw-normal);
  color: var(--text-3);
  background: rgba(var(--th-voile),0.04);
  border-radius: var(--r-micro);
  padding: var(--e-1) var(--e-6);
  text-transform: none;
  letter-spacing: var(--ls-zero);
  margin-left: var(--e-6);
}

/* Params grid — 5 sous-cartes pills */
/* .atelier-params-grid retiré le 05/09 avec le bloc « Paramètres du pack ». */

.atelier-param-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-large);
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 0;
}
.atelier-param-btn:not(.active):hover { background: var(--bg-sidebar); color: var(--text); }

/* Two-col layout — gap 16 matchant le design (au lieu de 20) */
.atelier-two-col {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--e-16); align-items: start;
}
@media (max-width: 980px) { .atelier-two-col { grid-template-columns: 1fr; } }
.atelier-col { display: flex; flex-direction: column; gap: var(--e-14); min-width: 0; }

/* Blocks — fond transparent (la carte parente gère le glass) */
.atelier-block {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
}
.atelier-block-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-large);
  text-transform: uppercase;
  color: var(--text-3);
}

/* Décor presets */
.atelier-decor-presets {
  display: flex; flex-wrap: wrap; gap: var(--e-8);
}
.atelier-decor-step1-block {
  margin-top: var(--e-28);
  padding-top: var(--e-22);
  border-top: 1px solid var(--border);
}
.atelier-decor-presets-step1 {
  display: flex; flex-wrap: wrap; gap: var(--e-8);
  margin-bottom: var(--e-10);
}
.atelier-preset-desc {
  font-size: var(--t-base);
  color: var(--text-3);
  font-style: italic;
  line-height: var(--lh-serre);
  min-height: 18px;
  transition: opacity var(--t-moyen);
}
.atelier-preset-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile),0.025);
  color: var(--text-2);
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--t-bref) var(--c-rebond);
}
.atelier-preset-chip:not(.active):hover {
  background: var(--bg-sidebar);
  color: var(--text);
  border-color: var(--border);
}
.atelier-preset-chip.active {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
  color: var(--violet-soft);
}

/* ══ LE GABARIT DE LA MODÈLE ══════════════════════════════════════════════════
   ⚠️ ON EMPRUNTE `atelier-preset-chip` — la pilule de l'Atelier, avec son actif et son
   survol — et on ne pose ici que la mise en page. Redessiner une pilule à côté d'une
   pilule, c'est deux apparences à tenir d'accord. */
.atelier-gabarit { margin-bottom: var(--e-16); }
.atelier-gabarit-rang { display: flex; flex-wrap: wrap; gap: var(--e-8); margin-top: var(--e-8); }
/* ⚠️ Une taille tient en deux caractères : la pilule large de l'Atelier ferait cinq boutons
   étirés. On resserre le rembourrage et on impose une largeur MINIMALE, pour que « XS » et
   « L » aient la même. */
.atelier-gabarit-rang .atelier-preset-chip {
  padding: var(--e-8) var(--e-12); min-width: 52px; justify-content: center;
  font-variant-numeric: tabular-nums;
}
.atelier-gabarit-aide { margin-top: var(--e-8); font-size: var(--t-meta); color: var(--text-3); }

/* Inputs / Textarea — Aurora */
.atelier-textarea { display: block;
  width: 100%;
  box-sizing: border-box;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  resize: vertical;
  min-height: 78px;
  line-height: var(--lh-normal);
  outline: none;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose) }
.atelier-textarea:focus {
  border-color: rgba(var(--th-accent-rgb),0.5);
  background: rgba(var(--th-voile),0.04);
}
.atelier-textarea::placeholder { color: var(--text-3); }
.atelier-textarea--sm { font-size: var(--t-meta); min-height: 48px; }
.atelier-input { display: block;
  width: 100%;
  box-sizing: border-box;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  outline: none;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose) }
.atelier-input:focus {
  border-color: rgba(var(--th-accent-rgb),0.5);
  background: rgba(var(--th-voile),0.04);
}
.atelier-input::placeholder { color: var(--text-3); }

/* Image zones */
/* L'ETIQUETTE DE DERIVE D'ECHELLE, posee sur une vue generee.
   /!\ ELLE SE DIT PAR LA COULEUR D'ALERTE, PAS PAR L'ACCENT : l'ambre et l'accent sont le
   meme dore sur certains themes, et un accent se lirait « selectionne » au lieu de
   « regarde ca ».
   /!\ `pointer-events: none` : elle est posee SUR la photo, et la photo se clique pour
   l'agrandir. Une etiquette qui avale le clic ferait un bouton mort. */
.at-echelle {
  position: absolute; left: var(--e-8); bottom: var(--e-8); z-index: 2;
  padding: var(--e-2) var(--e-10); border-radius: var(--r-pilule);
  background: rgba(var(--th-ombre), 0.78); color: var(--amber);
  font-size: var(--t-mini); line-height: var(--lh-un);
  pointer-events: none;
}

.atelier-img-zone {
  width: 100%; aspect-ratio: 4/5;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  position: relative;
}
/* Overlay « amélioration IA en cours » sur la carte Face */
.atelier-face-enhancing {
  position: absolute; inset: 0; z-index: 5; overflow: hidden;
  background: rgba(var(--th-panneau-rgb),0.55);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--e-10);
  color: var(--text); font-size: var(--t-base); text-align: center; padding: var(--e-10);
}
/* ⚠️⚠️ LE CONTENU PASSE AU-DESSUS DU BALAYAGE. Il vivait dans `> .atelier-spinner` et
   `> span` ; depuis le 05/09 c'est la MÊME carte que la génération (`.card-loader`), pour
   qu'attendre une amélioration et attendre une image se ressemblent. Amadou : « les mêmes
   caractères, la même police, la même barre de chargement ».
   ⚠️ On garde les deux anciens sélecteurs : le voile sert aussi à la fabrication d'un
   visage, qui pose encore une roue. */
.atelier-face-enhancing > .atelier-spinner,
.atelier-face-enhancing > span,
.atelier-face-enhancing > .card-loader { position: relative; z-index: 2; }
/* ⚠️ Posée SUR le voile, la carte ne doit rien peindre ni rien pousser. */
.atelier-face-enhancing > .card-loader { padding: 0; width: 100%; }
/* Barre de balayage « scan » qui descend en boucle sur la card pendant l'amélioration IA */
.atelier-enh-scan {
  position: absolute; left: 0; right: 0; height: 36%; top: -36%; z-index: 1;
  /* ⚠️⚠️ TROIS VALEURS DE VIOLET ÉCRITES EN DUR. Amadou (02/09) : « la ligne de scan doit
     être dans la DA du thème » — sur un thème ambre, un balayage violet vient d'ailleurs.
     Le halo juste en dessous (`atelierEnhGlow`) lisait DÉJÀ `--th-accent-rgb` : les deux
     moitiés de la même animation ne parlaient pas la même langue. */
  background: linear-gradient(to bottom, transparent 0%, rgba(var(--th-accent-rgb),0.30) 45%,
              rgba(var(--th-accent-rgb),0.72) 50%, rgba(var(--th-accent-rgb),0.30) 55%,
              transparent 100%);
  filter: blur(1px); pointer-events: none;
  animation: atelierEnhScan 1.4s ease-in-out infinite;
}
@keyframes atelierEnhScan {
  0%   { top: -36%; opacity: 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { top: 100%;  opacity: 0; }
}
/* Bordure violette pulsée autour de la card Face pendant l'amélioration */
.atelier-zone-enhancing { animation: atelierEnhGlow 1.6s ease-in-out infinite; }
@keyframes atelierEnhGlow {
  0%, 100% { box-shadow: inset 0 0 0 2px rgba(var(--th-accent-rgb),0.40); }
  50%      { box-shadow: inset 0 0 0 2px rgba(var(--th-accent-rgb),0.85); }
}
.atelier-img-placeholder {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-8); color: var(--text-3); font-size: var(--t-meta); text-align: center; padding: var(--e-20);
}
.atelier-result-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.atelier-view-err { color: var(--red); gap: var(--e-6); padding: var(--e-14); }
.atelier-view-err-t { font-size: var(--t-base); font-weight: var(--fw-gras); }
.atelier-view-err-m { font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-serre); word-break: break-word; max-height: 6.5em; overflow: hidden; }
.atelier-img-overlay {
  position: absolute; bottom: 0; left: 0; right: 0;
  padding: var(--e-12) var(--e-10) var(--e-10);
  background: linear-gradient(to top, rgba(var(--th-ombre),0.65) 0%, transparent 100%);
  display: flex; justify-content: center; gap: var(--e-8);
  /* ⚠️ POSÉ, PAS RÉVÉLÉ AU SURVOL. Amadou (02/09) : « déjà les boutons, je ne les vois
     pas ». Ils n'apparaissaient qu'au passage de la souris — invisibles pour qui ne sait
     pas qu'ils sont là, et introuvables au doigt. */
  opacity: 1;
  pointer-events: auto;
}
.atelier-overlay-btn {
  width: 34px; height: 34px; border-radius: var(--r-sm);
  background: rgba(var(--th-voile),0.15); border: 1px solid rgba(var(--th-voile),0.25);
  color: var(--text); display: flex; align-items: center; justify-content: center;
  cursor: pointer; backdrop-filter: blur(4px);
  transition: background var(--t-moyen);
}
.atelier-overlay-btn:hover { background: rgba(var(--th-voile),0.32); }
/* ⚠️⚠️ CENTRÉ POUR DE VRAI (05/09). Amadou : « il faudra que tu centres un peu plus cette
   partie ». `justify-content: center` ne centre rien tant que le conteneur n'a pas la
   hauteur de la zone : il faisait la hauteur de son contenu, donc le texte s'appuyait en
   haut de la carte. On lui donne toute la place, et le rembourrage de `.card-loader` s'en
   va — il décalait le centre vers le bas. */
.atelier-loading {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 100%; width: 100%;
  gap: var(--e-10); color: var(--text-3); font-size: var(--t-base);
}
.atelier-loading > .card-loader { padding: 0; }
.atelier-spinner {
  width: 26px; height: 26px; border: 2px solid var(--border-strong);
  border-top-color: var(--violet); border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* Buttons — Generate CTA Aurora pleine largeur */
.atelier-gen-btn {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: var(--e-8);
  height: 38px;
  padding: 0 var(--e-18);
  border: none;
  border-radius: var(--r-md);
  background: var(--aurora);
  color: var(--sur-accent);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-serre);
  cursor: pointer;
  box-shadow: 0 8px 22px -10px rgba(var(--th-accent-rgb),0.55);
  transition: filter var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.atelier-gen-btn:hover { filter: brightness(1.08); }
.atelier-gen-btn:active { transform: translateY(1px); }
.atelier-gen-btn:disabled { opacity: 0.45; cursor: not-allowed; filter: none; box-shadow: none; }

/* Badge coût estimé dans les CTA de génération */
/* ⚠️⚠️⚠️ « ON N'EN VOIT PAS » — ET C'ÉTAIT VRAI SUR LES VINGT THÈMES.
   Amadou (22/08), sur « ≈ 1 image » dans le bouton « Générer la PP ». Mesuré avec
   `outils/verifier-contraste.py` : de 1,03 à 1,86 de contraste selon le thème, pour un
   seuil de 4,5. Le pire, basalte, à 1,03 — c'est-à-dire RIEN. Pas un défaut de son
   thème : le texte était invisible partout.
   LA CAUSE EST LA LEÇON DÉJÀ APPRISE — « les fonds mentent selon la clarté ». Cette
   pastille vit TOUJOURS dans un `.btn-primary`, donc sur l'accent PLEIN. Or elle écrivait
   en `--text-2` (le gris discret prévu pour le fond de PAGE) sur un voile `--th-voile`
   qui ÉCLAIRCIT. Du gris clair sur du clair : les deux se sont rejoints.
   ⚠️ ET ASSOMBRIR N'ÉTAIT PAS LA SOLUTION — mesuré aussi : un voile `--th-ombre` à 0,16
   laisse 2 thèmes en échec, et à 0,28 il en laisse 6. Sur les thèmes clairs `--sur-plein`
   vaut du BLANC, et noircir le fond du badge le rapproche du texte au lieu de l'en
   éloigner. Le fond lui-même était le problème.
   LA RÉPARATION : aucun fond, et l'encre du bouton. La pastille devient exactement aussi
   lisible que le mot « Générer » à côté d'elle — 6,37 sur le thème d'Amadou, 19 thèmes
   sur 20 au-dessus du seuil. Le seul restant (colza, 3,94) est le contraste du LIBELLÉ
   du bouton lui-même : un défaut de ce thème, pas de ce badge. */
.atelier-cost { letter-spacing: var(--ls-zero);
  background: none;
  border: none;
  padding-left: 0; padding-right: 0;
  color: inherit;
  /* ⚠️ AUCUNE OPACITÉ, ET C'EST MESURÉ. J'avais écrit 0,72 pour la rendre discrète :
     9 thèmes sur 20 repassaient sous le seuil. Baisser l'opacité d'un texte, c'est
     exactement rapprocher son encre de son fond — le défaut qu'on vient de réparer, sous
     un autre nom. La hiérarchie se fait par la TAILLE, qui ne coûte aucun contraste. */
  font-size: var(--t-mini); }
.atelier-cost--text { background: none; font-style: italic; }

/* Hint explicatif (ex : décor optionnel) */
.atelier-hint {
  font-size: var(--t-meta);
  line-height: var(--lh-normal);
  color: var(--text-3);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12);
  margin-bottom: var(--e-10);
}
.atelier-hint strong { color: var(--text-2); font-weight: var(--fw-fort); }
.atelier-hint .atelier-optional { margin-left: 0; margin-right: var(--e-6); }

/* Bandeau clés API manquantes */
.atelier-keys-warning {
  display: flex; align-items: center; gap: var(--e-10);
  padding: var(--e-10) var(--e-14);
  margin-bottom: var(--e-16);
  border-radius: var(--r-lg);
  background: rgba(var(--th-danger-rgb),0.08);
  border: 1px solid rgba(var(--th-danger-rgb),0.25);
  color: var(--ose-text);
  font-size: var(--t-base);
}
.atelier-keys-warning svg { flex-shrink: 0; color: var(--red); }
.atelier-keys-warning span { flex: 1; }
.atelier-keys-warning-btn {
  flex-shrink: 0;
  padding: var(--e-6) var(--e-12);
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-danger-rgb),0.35);
  background: var(--danger-fond);
  color: var(--text-2);
  font-size: var(--t-meta); font-weight: var(--fw-fort);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose);
}
.atelier-keys-warning-btn:hover { background: rgba(var(--th-danger-rgb),0.2); }

.atelier-regen-btn {
  display: inline-flex; align-items: center; gap: var(--e-6);
  height: 32px;
  padding: 0 var(--e-12);
  border-radius: var(--r-sm);
  background: var(--violet-tint);
  border: none;
  color: var(--violet-soft);
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose);
}
.atelier-regen-btn:hover { background: var(--violet-tint-strong); }

/* Prompt preview */
.atelier-prompt-preview {
  background: rgba(var(--th-accent-rgb),0.06); border: 1px solid rgba(var(--th-accent-rgb),0.2);
  border-radius: var(--radius-sm); padding: var(--e-12);
}
.atelier-prompt-label {
  font-size: var(--t-micro); font-weight: var(--fw-gras); letter-spacing: var(--ls-caps); text-transform: uppercase;
  color: var(--violet-light); margin-bottom: var(--e-6);
}
.atelier-prompt-text { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-normal); }

/* Character sheet */
.atelier-sheet-wrap {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--e-14); margin-bottom: var(--e-16);
}
.atelier-sheet-label {
  font-size: var(--t-micro); font-weight: var(--fw-gras); letter-spacing: var(--ls-caps); text-transform: uppercase;
  color: var(--violet-light); margin-bottom: var(--e-8);
}
.atelier-sheet-text { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-aere); white-space: pre-wrap; }

/* Views row */
/* ⚠️⚠️ UNE ÉTAPE DOIT TENIR DANS UN ÉCRAN. Amadou (23/08) : « une étape doit faire la
   taille de l'écran, là c'est démesuré ». Deux causes mesurées, pas une :

   1· LA RANGÉE SE CASSAIT EN DEUX. `flex-wrap` + `min-width: 190px` : à 555 px de large,
      Face et Biais tenaient sur une ligne et Dos passait à la suivante — la rangée
      passait de 452 à 874 px, soit le double, sans que rien ne l'annonce. Une grille de
      trois colonnes ne se casse jamais : les vues d'un modèle vont ensemble.

   2· RIEN NE RELIAIT LEUR TAILLE À LA HAUTEUR DE L'ÉCRAN. `aspect-ratio: 4/5` déduit la
      hauteur de la LARGEUR : sur un écran large les cartes prenaient 340 px de large,
      donc 425 de haut, et l'étape dépassait de 302 px. On borne donc la colonne par une
      part de la HAUTEUR (26vh) : la zone fait alors 32vh de haut au plus, et l'étape
      entière tient sans qu'on touche au ratio des photos. */
.atelier-views-row {
  display: grid;
  /* ⚠️ 340px/26vh ne changeait RIEN sur un grand écran : `min()` y retenait 338 px, soit
     la taille d'origine. Amadou demandait précisément de « baisser la taille ». 260px
     plafonne les grands écrans, 22vh protège les écrans bas. */
  grid-template-columns: repeat(3, minmax(0, min(260px, 21vh)));
  justify-content: center;
  gap: var(--e-16);
  align-items: start;
}
/* Sous 720 px il n'y a plus la place pour trois colonnes : on empile, et la hauteur n'est
   plus le facteur limitant puisqu'on fait défiler de toute façon. */
@media (max-width: 720px) {
  .atelier-views-row { grid-template-columns: minmax(0, 1fr); max-width: 340px; margin-inline: auto; }
}
.atelier-view-card { display: flex; flex-direction: column; gap: var(--e-10); min-width: 0; }
.atelier-view-import-btn { width: 100%; justify-content: center; display: flex; align-items: center; gap: var(--e-6); font-size: var(--t-meta); padding: var(--e-8); }
/* ⚠️⚠️⚠️ LA HAUTEUR D'UNE LIGNE EST RÉSERVÉE, ET CE N'EST PAS COSMÉTIQUE. Le titre est le
   PREMIER enfant de la carte : dès qu'il passe sur deux lignes, il pousse la photo vers le
   bas et cette carte-là seule se décale. Mesuré le 05/09 : 33 px contre 17, soit 17 px
   d'écart sur la vue du milieu. Le nom d'une vue vient de la recette — Amadou peut en
   écrire un long demain — donc on ne se contente pas d'avoir raccourci le texte : on pose
   le plancher pour que le cas ne puisse plus décaler la rangée. */
/* ⚠️⚠️⚠️ LE TITRE D'UNE VUE N'EST PLUS UN MOT, C'EST UNE PHRASE (06/09). Il valait « Face »,
   « Biais », « Dos » — trois lettres à quatre. Depuis que l'analyse le déduit du produit, il
   vaut « SOCLE ET INTERRUPTEUR » ou « ABAT-JOUR ET AMPOULE » : vingt caractères, en
   majuscules, avec 0,14 em d'interlettrage. Il passait donc à la ligne — et la carte qui
   avait deux lignes de titre descendait plus bas que ses voisines. Amadou : « le texte est
   trop gros, ça fait un décalage ».
   ⚠️ DEUX CORRECTIONS, ET IL FAUT LES DEUX. Réduire (--t-micro, moitié moins d'interlettrage)
   fait tenir la plupart des noms sur une ligne. Mais « la plupart » n'est pas « tous » : on
   RÉSERVE deux lignes pour que l'alignement ne dépende plus de la longueur du mot. Sans la
   réserve, le premier nom un peu long re-décalerait tout. */
.atelier-view-card-label {
  font-size: var(--t-micro); font-weight: var(--fw-gras); letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--violet-light); text-align: center;
  line-height: var(--lh-serre); min-height: 2lh;
  display: flex; align-items: center; justify-content: center;
  text-wrap: balance;
}
/* ⚠️⚠️ SEULS `transform` ET `opacity` NE REPEIGNENT PAS. Mesuré sur la bulle de version :
   animer `filter` ou `box-shadow` rendait le mouvement saccadé. Le nom déduit apparaît donc
   en montant de quatre pixels, sans rien d'autre.
   ⚠️ ET L'ANIMATION EST PORTÉE PAR UNE CLASSE, pas par le changement de texte : une carte
   repeinte pour une autre raison ne doit pas rejouer l'entrée. */
@keyframes atl-nom-parait {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.atelier-view-card-label--neuf {
  /* ⚠️ ON EMPRUNTE LES JETONS QUI EXISTENT : `--d-slow` et `--c-pose`. J'avais écrit
     `--d-pose`, qui n'existe nulle part — la valeur de repli aurait sauvé l'apparence et
     masqué l'invention. Une variable inexistante ne prévient pas. */
  animation: atl-nom-parait var(--d-slow) var(--c-pose) both;
}
@media (prefers-reduced-motion: reduce) {
  .atelier-view-card-label--neuf { animation: none; }
}
.atelier-view-regen { display: flex; flex-direction: column; gap: var(--e-6); }
.atelier-prompt-toggle {
  background: none; border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: var(--e-4) var(--e-10); margin-top: var(--e-6);
  font-size: var(--t-micro); font-weight: var(--fw-fort); color: var(--text-3);
  cursor: pointer; display: flex; align-items: center; gap: var(--e-6);
  transition: color var(--t-moyen), border-color var(--t-moyen);
}
.atelier-prompt-toggle:hover { color: var(--text); border-color: var(--border-strong); }
.atelier-prompt-box {
  margin-top: var(--e-6); padding: var(--e-8) var(--e-10);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-normal);
  white-space: pre-wrap; max-height: 120px; overflow-y: auto;
}

/* Identity grid */
.atelier-identity-grid {
  display: flex; flex-direction: column; gap: var(--e-14); margin-top: var(--e-16);
}
.atelier-identity-row {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-14);
}
.atelier-identity-field { display: flex; flex-direction: column; gap: var(--e-6); }
.atelier-identity-input-row { display: flex; gap: var(--e-6); align-items: flex-start; }
.atelier-identity-input-row .atelier-input,
.atelier-identity-input-row .atelier-textarea { flex: 1; }
.atelier-field-regen {
  flex-shrink: 0; width: 32px; height: 32px; margin-top: var(--e-1);
  border-radius: var(--radius-xs);
}

/* Avatar upload */
.atelier-profile-upload-wrap {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-10);
}
/* Avatar upload zone — maintenant en rectangle dans le two-col */
.atelier-avatar-zone {
  width: 100%; height: 120px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 2px dashed var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; overflow: hidden; transition: border-color var(--t-moyen);
  position: relative;
}
.atelier-avatar-zone:hover, .atelier-avatar-zone.dragover { border-color: var(--violet); }
.atelier-avatar-ph {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-6);
  color: var(--text-3); font-size: var(--t-meta); text-align: center; padding: var(--e-12);
}
.atelier-avatar-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.atelier-avatar-hint { font-size: var(--t-mini); color: var(--text-3); }

/* ── Atelier : sélecteur de mode (de zéro / à partir d'une photo) ── */
.atelier-step-hidden { display: none !important; }
.atelier-mode-switch { display: flex; gap: var(--e-10); margin: 0 0 var(--e-18); }
.atelier-mode-btn {
  flex: 1; display: flex; flex-direction: column; gap: var(--e-4); align-items: flex-start;
  padding: var(--e-12) var(--e-14); border-radius: var(--radius-sm); text-align: left;
  background: var(--surface-2); border: 1.5px solid var(--border-strong);
  cursor: pointer; transition: border-color var(--t-moyen), background var(--t-moyen);
}
.atelier-mode-btn:hover { border-color: var(--border-mid); }
.atelier-mode-btn.active { border-color: var(--violet); background: rgba(var(--th-accent-rgb),0.12); }
.atelier-mode-btn-title { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text-1); display: flex; align-items: center; gap: var(--e-6); }
.atelier-mode-btn-title svg { flex-shrink: 0; }
.atelier-mode-btn-sub { font-size: var(--t-meta); color: var(--text-3); }

/* ── Atelier mode photo : zone d'upload de la Face (3:4) ── */
.atelier-photo-source { margin-bottom: var(--e-16); }
.atelier-photo-zone {
  width: 100%; max-width: 260px; aspect-ratio: 3 / 4; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 2px dashed var(--border-strong);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; overflow: hidden; transition: border-color var(--t-moyen); position: relative; margin-top: var(--e-8);
}
.atelier-photo-zone:hover, .atelier-photo-zone.dragover { border-color: var(--violet); }
.atelier-photo-ph {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-8);
  color: var(--text-3); font-size: var(--t-meta); text-align: center; padding: var(--e-16);
}
.atelier-photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Bouton « retirer la photo » sur la carte Face (mode photo) */
.atelier-photo-rm {
  position: absolute; top: 8px; right: 8px; width: 28px; height: 28px;
  border-radius: 50%; border: none; cursor: pointer; z-index: 4;
  background: rgba(var(--th-ombre),0.62); color: var(--sur-sombre); font-size: var(--t-lead); line-height: var(--lh-un);
  display: flex; align-items: center; justify-content: center; transition: background var(--t-moyen);
}
.atelier-photo-rm:hover { background: rgba(220,38,38,0.92); }
/* ⚠️ Le coin haut-DROIT est réservé à l'étiquette du degré (Amadou, 02/09) : la croix de
   retrait s'y superposait. */
.atelier-photo-rm--gauche { right: auto; left: var(--e-8); }

/* ── Recadrage manuel de la Face (modale) ── */
.atl-crop-modal {
  position: fixed; inset: 0; z-index: 1000;
  background: var(--voile); backdrop-filter: var(--voile-flou); -webkit-backdrop-filter: var(--voile-flou);
  display: flex; align-items: center; justify-content: center; padding: var(--e-20);
}
.atl-crop-card {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--e-18); display: flex; flex-direction: column; gap: var(--e-14); max-width: 92vw;
}
.atl-crop-title { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.atl-crop-stage {
  position: relative; overflow: hidden; border-radius: var(--radius);
  margin: 0 auto; background: var(--surface-2); touch-action: none;
  width: 300px; height: 400px;
}
.atl-crop-img { display: block; user-select: none; -webkit-user-drag: none; pointer-events: none; }
.atl-crop-box {
  position: absolute; box-sizing: border-box;
  border: 2px solid #fff; cursor: grab; touch-action: none;
  box-shadow: 0 0 0 1600px rgba(var(--th-ombre),0.5);
}
.atl-crop-box:active { cursor: grabbing; }
.atl-crop-ctrls { display: flex; align-items: center; gap: var(--e-12); }
.atl-crop-zlabel { font-size: var(--t-base); color: var(--text-3); }
.atl-crop-zoom { flex: 1; accent-color: var(--violet); }
.atl-crop-foot { display: flex; justify-content: flex-end; gap: var(--e-10); }

/* Choix rogner à la main / régénérer par IA (clic sur le ciseau de la Face) */
/* ⚠️ Les règles `.atl-crop-choice*` sont parties avec leur fenêtre (02/09) : le ciseau a
   fusionné dans « Améliorer », et le choix « rogner / régénérer » vit au clic droit. */
/* PP Style grid */
.pp-style-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e-8);
}
.pp-style-chip {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e-2);
  padding: var(--e-10) var(--e-12);
  background: var(--surface-2);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color var(--t-moyen), background var(--t-moyen);
  text-align: left;
}
.pp-style-chip:hover { border-color: var(--border-mid); background: rgba(var(--th-accent-rgb),0.07); }
.pp-style-chip.active { border-color: var(--violet); background: rgba(var(--th-accent-rgb),0.12); }
.pp-style-icon { font-size: var(--t-lead); line-height: var(--lh-un); color: var(--violet); }
.pp-style-label { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text); }
.pp-style-sub   { font-size: var(--t-micro); color: var(--text-3); }

/* PP result zone — avatar rond compact */
.pp-result-col { display: flex; flex-direction: column; align-items: center; gap: var(--e-14); padding-top: var(--e-4); }
.pp-result-zone {
  width: 340px; height: 340px;
  aspect-ratio: auto;
  margin: 0; flex: 0 0 auto;
  border-radius: 50%;
  border: 3px solid rgba(var(--th-accent-rgb),0.6);
}
.pp-result-zone .atelier-img-placeholder { padding: var(--e-16); }
.pp-result-actions {
  display: flex;
  gap: var(--e-8);
  margin-top: var(--e-4);
  flex-wrap: wrap;
  justify-content: center;
}

/* Vinted profile preview */
.atelier-preview-wrap { display: flex; justify-content: center; }
.vinted-profile-card {
  width: 100%; max-width: 480px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); overflow: hidden; padding: var(--e-24);
  display: flex; flex-direction: column; gap: var(--e-16);
}
.vinted-profile-top { display: flex; align-items: center; gap: var(--e-16); }
.vinted-avatar-wrap {
  width: 72px; height: 72px; border-radius: 50%;
  background: var(--surface-2); flex-shrink: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--border);
}
.vinted-avatar { width: 100%; height: 100%; object-fit: cover; }
.vinted-avatar-ph { color: var(--text-3); }
.vinted-profile-name { font-size: var(--t-body); font-weight: var(--fw-gras); color: var(--text); }
.vinted-profile-stats { display: flex; gap: var(--e-12); margin-top: var(--e-4); }
.vinted-stat {
  display: flex; align-items: center; gap: var(--e-4);
  font-size: var(--t-base); color: var(--text-3);
}
.vinted-stat svg { color: var(--tier-luxe-text); }
.vinted-profile-bio { font-size: var(--t-small); color: var(--text-2); line-height: var(--lh-normal); white-space: pre-wrap; }
.vinted-profile-measures { display: flex; gap: var(--e-6); flex-wrap: wrap; }
.vinted-measure-chip {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: var(--e-4) var(--e-10); font-size: var(--t-meta); color: var(--text-2);
}
.vinted-views-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e-6); margin-top: var(--e-4); }
.vinted-view-thumb {
  aspect-ratio: 3/4; border-radius: var(--r-sm); overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-micro); color: var(--text-3);
}
.vinted-view-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Save step.
   ⚠️ ONZE RÈGLES RETIRÉES LE 03/09 avec l'étape qu'elles habillaient : la bande de
   vignettes carrées, l'avatar rond, la pastille orange et la grille des « mannequins
   similaires ». Elles ne servaient plus rien — vérifié classe par classe, zéro emploi
   dans le HTML comme dans le JS. Une feuille de style qui garde l'habit d'un écran mort
   finit par l'habiller de nouveau, au premier nom réutilisé par hasard.
   ⚠️ `.atelier-similarity-wrap` était de toute façon un SÉLECTEUR DE CLASSE posé sur un
   élément qui ne portait qu'un identifiant du même nom : elle n'a jamais rien peint. */
.atelier-save-btn {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-14) var(--e-24); font-size: var(--t-small);
}

/* ══════════════════════════════════════════════════════
   MODIFICATIONS
   ══════════════════════════════════════════════════════ */

/* Header */
/* ══════════════════════════════════════════════════════
   MODIFICATIONS — Redesign
   ══════════════════════════════════════════════════════ */

/* Ancien header inline neutralisé (remplacé par la sticky topbar Aurora) */
.mod-header,
.mod-header-top,
.mod-title,
.mod-subtitle { display: none; }

.section-top-bar { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--e-16); }

.btn-actualiser { display: inline-flex; align-items: center; gap: var(--e-6); }

/* ── Badge numéro d'étape (flux guidé Démasquer) ──────── */
.mod-step-num {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--aurora);
  color: var(--sur-accent);
  font-size: var(--t-base); font-weight: var(--fw-gras);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 6px 16px -7px rgba(var(--th-accent-rgb),0.65), inset 0 1px 0 rgba(var(--th-voile),0.25);
}

/* Titre + badge icône à côté */
.mods-card-title-icon {
  width: 28px; height: 28px;
  border-radius: var(--r-sm);
  background: var(--violet-tint);
  color: var(--violet-soft);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}

/* ── Panel ── */
.mod-panel {
  display: flex; flex-direction: column;
  gap: var(--e-16);
  max-width: 1040px;
  margin: 0 auto;
  width: 100%;
}

/* ── Studio v2 — AI-style interface ── */
/* ── Studio Chat ── */
/* Dans la section Studio standalone, le chat prend toute la hauteur disponible */
.studio-section-canvas {
  padding: var(--e-14) var(--e-28) var(--e-16) !important;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
/* Studio : fond plat (opaque) + tient en UNE fois (scroll interne seulement) */
/* `position: relative` : le rideau noir se pose EN ABSOLU dans cet écran, pas dans la
   page — sinon il couvrirait aussi la barre latérale. */
#section-studio { background: var(--bg-base); height: 100%; overflow: hidden; position: relative; }

.studio-layout {
  display: flex;
  flex: 1;
  gap: 0;
  overflow: hidden;
  height: 100%;
  min-height: 0;
}
#section-studio .studio-chat {
  height: 100%;
  flex: 1;
  min-width: 0;
  border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
  border-left: none;

  /* ⚠️⚠️ LES ADAPTATIONS ÉCOUTAIENT LA FENÊTRE, PAS LA COLONNE — et c'est pour ça
     que le Studio étouffait. Mesuré à 900 px de fenêtre : la colonne de discussion
     tombe à 266 px (barre de gauche 208 + panneau des conversations 230), et la
     phrase d'accueil s'étalait sur TROIS lignes pendant que la seule media query
     utile n'était déclenchée qu'à 720 px de FENÊTRE — jamais atteints.
     Et la fenêtre ne suffira jamais : replier la barre de gauche change la place
     disponible sans changer d'un pixel la largeur de la fenêtre.
     La colonne se mesure donc elle-même. */
  container-type: inline-size;
  container-name: studiochat;
}

/* ── Panneau historique ── */
.studio-history-panel {
  width: 230px;
  min-width: 230px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-right: 1px solid var(--border);
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  background: var(--bg-panel-solid);   /* opaque : pas d'étoiles dans le Studio */
  overflow: hidden;
  padding: var(--e-12) var(--e-10) var(--e-6);   /* aère le bouton "Nouveau chat" (espace au-dessus + côtés) */
}
.studio-history-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--e-14) var(--e-12) var(--e-12);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.studio-history-label {
  font-size: var(--t-mini);
  font-weight: var(--fw-fort);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
}
/* ⚠️⚠️ IL ÉTAIT CENTRÉ, ET C'EST CE QUI LE RENDAIT LAID. Amadou (26/08) : « la
   croix et le nouveau chat, c'est au milieu, il faut le mettre vers la gauche ».
   Un bouton pleine largeur dont le contenu flotte au centre n'a aucun rapport avec
   la colonne qu'il coiffe : dessous, la recherche et les conversations commencent
   toutes à gauche, et lui seul est décalé. Aligné à gauche, il tient la même
   marge qu'elles et la colonne redevient droite.
   ⚠️ Le violet PLEIN est remplacé par un violet en voile : à pleine force il
   pesait plus lourd que tout ce qu'il surmonte — alors que c'est un point de
   départ, pas l'action principale de l'écran. */
.studio-new-chat-btn {
  width: 100%;
  height: 36px;
  border-radius: var(--r-md);
  /* ⚠️ NI `background` NI `border` NI `color` ICI : la famille des boutons pleins,
     écrite plus bas, les repose tous les trois et gagne. Les laisser ici donnait
     l'illusion que ce bouton était translucide — et c'est cette illusion qui avait
     produit le survol gris. */
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--e-8);
  padding: 0 var(--e-10);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  font-family: inherit;
  cursor: pointer;
  margin-bottom: var(--e-6);
  flex-shrink: 0;
  transition: filter var(--t-bref) var(--c-pose),
              box-shadow var(--t-bref) var(--c-pose),
              transform var(--t-bref) var(--c-rebond);
}
/* ⚠️⚠️⚠️ DEUX PORTES SUR LE MÊME BOUTON, ET LE SURVOL PRENAIT LA MAUVAISE.
   Amadou (27/08) : « quand je passe dessus il devient gris, ce n'est pas
   esthétique ». Le fond du bouton ne vient PAS de sa propre règle : plus bas dans
   la feuille, la famille des boutons pleins (`.btn-primary, .btn-generate, …,
   .studio-new-chat-btn`) lui pose `background: var(--aurora)` — un dégradé — et
   cette règle-là gagne, puisqu'elle est écrite après.
   Le survol, lui, était resté écrit pour l'ANCIEN bouton translucide : il
   remplaçait le dégradé par un aplat à 20 % d'opacité. D'où le gris. Ce n'était
   pas une couleur mal choisie, c'était un survol qui EFFAÇAIT le fond au lieu de
   le rehausser.
   ⚠️ On suit donc la convention de la maison, celle de `.btn-primary` et de
   `.btn-generate` : on ne touche PAS au fond, on l'éclaire d'un cran et on pose le
   halo d'accent. Un bouton plein ne change pas de matière quand on le vise. */
.studio-new-chat-btn:hover {
  filter: brightness(1.06);
  box-shadow: 0 0 0 1px rgba(var(--th-accent-rgb), .22),
              0 14px 40px -14px rgba(var(--th-accent-rgb), .55);
}
.studio-new-chat-btn:active { transform: translateY(1px); filter: brightness(1.02); }
/* ⚠️ C'ÉTAIT LE SURVOL QUI FONÇAIT (`--violet-hover`), écrit APRÈS le nouveau et
   qui gagnait donc à chaque fois. Retiré — la règle au-dessus est la seule. */
.studio-sidesep { height: 1px; background: var(--border); margin: var(--e-12) var(--e-2) var(--e-8); flex-shrink: 0; }
.studio-history-list {
  flex: 1;
  overflow-y: auto;
  padding: var(--e-4) 0 var(--e-8);
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
  /* ⚠️⚠️ TROISIÈME ASCENSEUR DU MÊME ÉCRAN, ET LE PLUS VOYANT. J'avais traité celui
     du fil et celui du champ, pas celui de la liste des conversations — qui longe
     toute la colonne de gauche, sur un fond sombre, avec le pouce clair du réglage
     global : un trait blanc franc du haut en bas de l'écran.
     ⭐ La leçon vaut au-delà de ce cas : un défaut de style se répète sur TOUS les
     porteurs de la même propriété. Chercher `overflow-y: auto` dans l'écran, pas
     seulement corriger celui qu'on a sous les yeux. */
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--th-voile), .06) transparent;
}
.studio-history-empty {
  font-size: var(--t-meta);
  color: var(--text-muted);
  text-align: center;
  padding: var(--e-24) var(--e-12);
  line-height: var(--lh-normal);
}
/* Groupes par date */
.studio-history-group-label {
  font-size: var(--t-micro);
  font-weight: var(--fw-fort);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  padding: var(--e-12) var(--e-6) var(--e-6);
}
.studio-history-sep {
  height: 1px;
  background: var(--border);
  margin: var(--e-6) var(--e-8);
}
.studio-history-item {
  padding: var(--e-10) var(--e-28) var(--e-10) var(--e-12);
  border-radius: var(--r-md);
  cursor: pointer;
  position: relative;
  transition: background var(--t-bref);
  /* ⚠️ La réserve du liseré part avec lui : la garder décalerait toutes les lignes
     de 2 px pour rien. */
}
.studio-history-item:hover {
  background: var(--surface-2);
}
/* ⚠️⚠️ LE VIOLET ÉTAIT ÉCRIT EN DUR. Amadou (26/08) : « quand j'appuie sur un chat,
   la couleur est bizarre, ça fait une sorte de violet, ça fait hors thème ». Et pour
   cause : `rgba(139,127,255,.12)` et `var(--violet, #7c5cbf)` sont des couleurs
   FIXES, qui ne bougent pas d'un thème à l'autre. Sur le thème doré, la conversation
   ouverte restait violette au milieu d'un écran ambré.
   ⚠️ Le repli `var(--violet, #7c5cbf)` est le pire des deux : il donne l'illusion
   d'un jeton, mais retombe sur un violet en dur dès que la variable manque. */
/* ⚠️ PLUS DE LISERÉ À GAUCHE. Amadou (26/08) : « enlève cet effet lumineux sur le
   côté gauche de la carte, ce n'est pas beau ». Le fond teinté dit déjà laquelle est
   ouverte ; le trait vertical ajoutait un second signal pour la même information, et
   sur une colonne étroite il coupe la ligne au lieu de la souligner. */
.studio-history-item.active {
  background: rgba(var(--th-accent-rgb), .12);
}
.studio-history-item.active .studio-history-item-title {
  font-weight: var(--fw-fort);
  color: var(--text);
}
.studio-history-item-title {
  font-size: var(--t-meta);
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: var(--lh-serre);
}
.studio-history-item-date {
  font-size: var(--t-micro);
  color: var(--text-muted);
  margin-top: var(--e-2);
}
.studio-history-item-del {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  border-radius: var(--r-micro);
  border: none;
  background: transparent;
  color: var(--text-muted);
  display: none;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.studio-history-item:hover .studio-history-item-del { display: flex; }
.studio-history-item-del:hover { background: var(--danger-fond); color: var(--red); }

/* ── Avatar compact dans les bulles ── */
/* ⚠️ `.studio-msg-avatar-v` (la lettre « V ») n'existe plus — c'est le logo qui
   prend sa place. La règle est retirée plutôt que laissée à dormir : une classe
   sans porteur finit toujours par être recopiée quelque part. */
.studio-msg-avatar .velbo-marque { display: block; }

.studio-chat {
  display: flex;
  flex-direction: column;
  min-height: 0;
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--bg-panel-solid);   /* opaque : fond plat, pas d'étoiles */
  overflow: hidden;
}

/* Messages area */
.studio-chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: var(--e-20) var(--e-16) var(--e-12);
  display: flex;
  flex-direction: column;
  gap: var(--e-16);
  scrollbar-width: thin;
}
/* Chat centré en colonne lisible (comme un vrai messager) au lieu de s'étirer dans le
   vide sur grand écran — le conteneur reste pleine largeur, seul le contenu est borné. */
.studio-chat-messages > * { width: 100%; max-width: 820px; margin-left: auto; margin-right: auto; }
.studio-chat-inputbar { width: 100%; }
/* ⚠️ LA BORNE EST SUR LA BARRE, PLUS SUR CHAQUE ENFANT. Tant que le cadre vivait
   sur la rangée intérieure, c'était l'enfant qu'il fallait borner ; maintenant que
   le cadre EST la barre, la borner elle évite qu'un enfant déborde du filet. */
.studio-chat-inputbar { width: 100%; max-width: 760px; margin-left: auto; margin-right: auto; }

/* Welcome state */
.studio-chat-welcome {
  display: flex;
  flex-direction: column;
  align-items: center;              /* le bloc interne reste centré horizontalement */
  justify-content: flex-start;      /* REMONTÉ : démarre en haut (fini le vide au-dessus) */
  flex: 1;
  padding: 46px var(--e-32) var(--e-32);
  text-align: left;
  user-select: none;
}
/* Rampe de lancement : badge + accueil + cartes de démarrage (remplit le vide). */
.studio-welcome-inner { display: flex; flex-direction: column; align-items: flex-start; width: 100%; max-width: 680px; }
.studio-welcome-badge { width: 60px; height: 60px; border-radius: var(--r-xl); background: var(--violet-tint);
  color: var(--violet-light); display: flex; align-items: center; justify-content: center; margin-bottom: var(--e-20); }
.studio-welcome-hint { font-size: var(--t-small); color: var(--text-3); margin-top: var(--e-6); margin-bottom: 26px; }
/* ⚠️ LES CARTES DE DÉMARRAGE SONT SUPPRIMÉES (Amadou, 26/08 : « les pré-messages
   sont trop gros… franchement tu peux les enlever »). Grille, dessin, paliers
   étroits : tout part. Laisser des règles orphelines derrière une classe qui
   n'existe plus, c'est promettre à la prochaine lecture qu'il suffit d'ajouter le
   HTML pour que ça remarche — alors que le JS qui les posait est parti aussi. */
.studio-chat-welcome-greeting {
  /* ⚠️⚠️ LE CORPS SUIT LA PLACE DISPONIBLE. Mesuré : à 1100 px de fenêtre le bloc
     d'accueil fait 574 px et tout tient sur une ligne ; à 900 px il tombe à 266 px et
     la même phrase s'étale sur TROIS lignes en --t-2xl. Un titre d'accueil qui déborde
     rate son effet — il rétrécit plutôt que de se casser.
     Les deux bornes sont des barreaux de l'échelle, jamais des tailles inventées. */
  font-size: clamp(var(--t-title), 7cqw, var(--t-2xl));
  font-weight: var(--fw-fort);
  color: var(--text);
  letter-spacing: var(--ls-serre);
  line-height: var(--lh-titre);
  max-width: 100%;
  /* ⚠️⚠️ LA BRIDE ÉTAIT À 560 px POUR 657 DISPONIBLES, et c'était la moitié du
     « ça met un paragraphe ». Mesuré à --t-2xl : les huit phrases d'accueil
     demandent de 469 à 801 px ; à 560 px, CINQ sur huit se cassaient en deux.
     Elles prennent maintenant toute la largeur du bloc d'accueil.
     ⚠️ `text-wrap: balance` est le filet : sur une fenêtre étroite la phrase finira
     par passer à la ligne, et deux lignes de longueur égale se lisent comme un choix,
     pas comme un débordement. */
  text-wrap: balance;
}
.studio-chat-welcome-chips {
  display: flex; flex-wrap: wrap; gap: var(--e-8);
  justify-content: center;
  margin-top: var(--e-8);
  max-width: 460px;
}

/* Chips */
.studio-chip {
  flex-shrink: 0;
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-14);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--t-meta); font-weight: var(--fw-moyen);
  cursor: pointer;
  white-space: nowrap;
  transition: var(--transi);
}
.studio-chip:hover {
  border-color: var(--violet);
  background: rgba(var(--th-accent-rgb),0.1);
  color: var(--violet-light);
}

/* Chat messages */
.studio-msg {
  display: flex;
  gap: var(--e-10);
  max-width: 86%;
}
.studio-msg-user {
  align-self: flex-end;
  flex-direction: row-reverse;
}
.studio-msg-velbo {
  align-self: flex-start;
}
/* ⚠️ PLUS DE CADRE NI DE FOND. Ils servaient à poser une initiale ; sous un logo
   qui a déjà sa forme, ils l'enferment dans une vignette et le rapetissent. */
.studio-msg-avatar {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  border: 0;
  background: none;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: var(--e-4);
}
.studio-msg-bubble {
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-xl);
  font-size: var(--t-small); line-height: var(--lh-normal);
  word-break: break-word;
}
.studio-msg-user .studio-msg-bubble {
  background: var(--violet);
  color: var(--sur-accent);
  border-bottom-right-radius: 4px;
}
.studio-msg-velbo .studio-msg-bubble {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-bottom-left-radius: 4px;
}
.studio-msg-bubble-text { max-width: 600px; }
.studio-msg-text { line-height: var(--lh-aere); }
.studio-msg-bubble-photos {
  display: flex; gap: var(--e-6); flex-wrap: wrap;
  margin-bottom: var(--e-6);
}
.studio-msg-thumb {
  width: 52px; height: 52px;
  border-radius: var(--r-sm); overflow: hidden;
  border: 1px solid rgba(var(--th-voile),0.2);
  cursor: zoom-in;
  flex-shrink: 0;
}
.studio-msg-thumb img { width: 100%; height: 100%; object-fit: cover; }

.studio-msg-img-wrap {
  margin-top: var(--e-6);
}
.studio-msg-img-wrap img {
  max-width: 240px;
  border-radius: var(--r-lg);
  cursor: zoom-in;
  display: block;
  border: 1px solid var(--border);
}
/* ⚠️ Règle remplacée plus bas (§ LES ACTIONS, LA VOIX, LES MENTIONS) : les actions
   n'apparaissent plus qu'au survol. Laissée vide ici pour ne pas rouvrir un écart
   entre deux définitions du même bloc. */
.studio-msg-action-btn {
  display: inline-flex; align-items: center; gap: var(--e-6);
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-2);
  font-size: var(--t-meta); font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: var(--transi);
}
.studio-msg-action-btn:hover {
  border-color: var(--violet);
  color: var(--violet-light);
  background: rgba(var(--th-accent-rgb),0.08);
}

/* ── Galerie de résultats (centre, façon maquette) ── */
.studio-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: var(--e-14);
  align-content: start;
  width: 100%;
}
.studio-card {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface-2);
  aspect-ratio: 4 / 5;
}
.studio-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  cursor: zoom-in;
}
.studio-card-actions {
  position: absolute;
  right: 8px;
  bottom: 8px;
  display: flex;
  gap: var(--e-6);
  opacity: 0;
  transition: opacity var(--t-moyen) var(--c-pose);
}
.studio-card:hover .studio-card-actions { opacity: 1; }
.studio-card-btn {
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  border: none;
  background: rgba(var(--th-panneau-rgb),0.62);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  backdrop-filter: blur(4px);
  transition: background var(--t-bref);
}
.studio-card-btn:hover { background: rgba(var(--th-panneau-rgb),0.85); }
.studio-card-loading { opacity: 0.5; pointer-events: none; }

/* Generating bubble */
.studio-msg-typing {
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-10) var(--e-14);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-xl); border-bottom-left-radius: 4px;
}
.studio-msg-typing-dot {
  width: 7px; height: 7px;
  background: var(--violet-light);
  border-radius: 50%;
  animation: typingBounce 1.2s ease-in-out infinite;
}
.studio-msg-typing-dot:nth-child(2) { animation-delay: var(--t-moyen); }
.studio-msg-typing-dot:nth-child(3) { animation-delay: var(--t-long); }
@keyframes typingBounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
  30% { transform: translateY(-5px); opacity: 1; }
}

/* Input bar */
/* ⚠️ Cette règle règle l'ESPACE AUTOUR de la barre, pas la barre elle-même (son
   cadre est plus bas). Le `margin-bottom` la décolle du bord : Amadou (26/08) :
   « la barre, il faut que tu la remontes ». Collée en bas, elle donne l'impression
   d'être tombée au fond de la fenêtre. */
.studio-chat-inputbar {
  flex-shrink: 0;
  padding: var(--e-10) var(--e-16);
  margin-bottom: var(--e-28);
  display: flex; flex-direction: column; gap: var(--e-8);
}

/* Attached thumbnails */
.studio-attached {
  display: flex; gap: var(--e-8);
  overflow-x: auto; scrollbar-width: none;
  padding: var(--e-2) 0;
}
.studio-attached::-webkit-scrollbar { display: none; }
.studio-attached-inner { display: flex; gap: var(--e-8); }

.studio-thumb {
  position: relative; flex-shrink: 0;
  width: 58px; height: 58px;
  border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--border-strong);
}
.studio-thumb img { width: 100%; height: 100%; object-fit: cover; }
.studio-thumb-rm {
  position: absolute; top: 3px; right: 3px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: rgba(var(--th-ombre),0.72);
  border: none; color: var(--sur-sombre);
  font-size: var(--t-mini); line-height: var(--lh-un);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; opacity: 0;
  transition: opacity var(--t-moyen);
  padding: 0;
}
.studio-thumb:hover .studio-thumb-rm { opacity: 1; }

/* ⚠️⚠️ `.studio-input-row` N'EXISTE PLUS DANS LE HTML. C'était la rangée unique
   « joindre + texte + envoyer » : écrire trois phrases y repoussait les boutons et
   faisait sauter toute la barre à chaque retour à la ligne. Le texte a désormais sa
   propre ligne et les commandes sont en dessous — donc le CADRE, qui vivait ici,
   remonte sur la barre elle-même. Sans ce déplacement, la saisie n'aurait plus ni
   fond, ni filet, ni ombre. */
/* ⚠️⚠️ LE FOND ÉTAIT `--bg-2`, PLUS SOMBRE QUE LA PAGE. Amadou (26/08) : « le fait
   que ce soit trop foncé comme ça, ce n'est pas beau ». Un champ de saisie plus
   foncé que ce qui l'entoure se lit comme un TROU : l'œil comprend « creux », alors
   qu'on veut « surface où l'on écrit ». Toutes les interfaces qu'il cite font
   l'inverse — la barre est plus CLAIRE que le fond, posée dessus.
   ⚠️ Le voile est en `--th-voile`, pas en blanc : sur les six thèmes clairs, un
   voile blanc ne produirait aucun écart avec le fond et la barre disparaîtrait. */
.studio-chat-inputbar {
  background: rgba(var(--th-voile), .055);
  /* ⚠️⚠️ PAS `var(--th-trait)` : ce jeton est défini EN CANAUX (« 148,150,172 »),
     pas en couleur. `border: 1px solid 148,150,172` est invalide, et CSS jette
     alors la déclaration ENTIÈRE — la bordure ne devient pas grise, elle DISPARAÎT
     (mesuré : border-style calculé « none »). Les jetons `--border*` sont
     précisément ces canaux déjà passés en rgba. */
  border: 1px solid var(--border-strong);
  border-radius: var(--r-xl);
  padding: var(--e-12) var(--e-14) var(--e-10);
  box-shadow: 0 var(--e-4) var(--e-18) rgba(var(--th-ombre), .18);
  transition: border-color var(--t-bref) var(--c-pose),
              background var(--t-bref) var(--c-pose),
              box-shadow var(--t-bref) var(--c-pose);
}
/* ⚠️⚠️ LE CONTOUR S'ILLUMINE À LA SAISIE — et c'est un CHANGEMENT D'AVIS ASSUMÉ.
   Une note plus haut dans ce fichier disait « aucune surbrillance violette au focus
   de la barre Studio (demande utilisateur) ». Amadou (26/08) : « quand j'appuie
   dessus, le contour doit s'illuminer ». Ce n'est pas la même barre qu'alors : elle
   ne porte plus une seule ligne mais un texte, des modes et deux boutons — savoir
   si l'on est dedans ou dehors a cessé d'être évident.
   ⚠️ Le halo est un `box-shadow` DIFFUS, pas un `outline` : un trait net de 2 px
   sur un coin très arrondi laisse un angle qui bave. */
/* ⚠️⚠️ LA BORDURE NE CHANGE PLUS DE COULEUR AU FOCUS — et c'est le correctif.
   Amadou (26/08) : « il y a deux animations en une… ça ne marche pas trop ». Elle
   passait au violet INSTANTANÉMENT pendant que l'anneau, lui, mettait 1,5 s à faire
   le tour : on voyait donc un contour déjà entièrement allumé, et par-dessus un
   segment plus clair qui le parcourait. Deux tracés superposés au lieu d'un.
   Le contour violet vient désormais de l'ANNEAU SEUL, qui reste posé à la fin
   (`forwards`). Ce qui accompagne le focus se limite à ce qui ne dessine pas de
   trait : le fond qui s'éclaircit d'un souffle, et le halo diffus.
   ⚠️ Le halo est ralenti à la durée de l'écoulement : apparu d'un coup, il annonçait
   l'arrivée de l'eau avant qu'elle ne soit là. */
.studio-chat-inputbar:focus-within {
  background: rgba(var(--th-voile), .075);
  box-shadow: 0 0 0 var(--e-2) rgba(var(--th-accent-rgb), .16),
              0 var(--e-4) var(--e-18) rgba(var(--th-ombre), .2);
  transition: background var(--t-moyen) var(--c-pose),
              box-shadow var(--studio-coule) var(--c-pose);
}
/* Aucune surbrillance violette au focus de la barre Studio (demande utilisateur). */
.studio-attach-btn {
  flex-shrink: 0;
  width: 38px; height: 38px;
  border-radius: var(--r-md);
  background: transparent; border: none;
  color: var(--text-3);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: color var(--t-moyen), background var(--t-moyen);
  padding: 0;
}
.studio-attach-btn:hover { color: var(--violet-light); background: rgba(var(--th-accent-rgb),0.1); }

.studio-prompt-input {
  /* ⚠️⚠️ `flex: 1` ÉTAIT JUSTE, PUIS EST DEVENU FAUX EN CHANGEANT DE PARENT. Il
     datait de `.studio-input-row`, une RANGÉE : là il servait à prendre la largeur
     restante entre le bouton joindre et le bouton envoyer. Depuis que le champ est
     l'enfant direct de la barre, qui est une COLONNE, le même `flex: 1` s'applique
     à la HAUTEUR — et il écrase la hauteur en ligne que le redimensionnement
     automatique calcule à chaque frappe.
     Symptôme mesuré : `style.height` posé à « 71px » pour trois lignes de texte,
     et une hauteur réelle qui reste à 29 px avec un ascenseur. Amadou (26/08) :
     « ça ne rentre pas dans le cadre… la bulle doit augmenter de taille en
     fonction du message, comme ChatGPT ».
     ⚠️ `0 0 auto` et non `none` : la largeur reste pleine par l'étirement de la
     colonne, mais la hauteur redevient celle qu'on lui donne. */
  flex: 0 0 auto;
  width: 100%;
  background: transparent; border: none; outline: none;
  color: var(--text);
  font-size: var(--t-small); font-family: inherit;
  line-height: var(--lh-normal); resize: none;
  max-height: 160px; overflow-y: auto;
  /* ⚠️⚠️ L'ASCENSEUR ÉTAIT CELUI DE TOUT LE SITE, ET IL DÉTONNE ICI. Amadou
     (26/08) : « la barre pour slide est vraiment moche, elle n'est pas dans la DA
     du site, elle est trop visible ». Le réglage global (`*::-webkit-scrollbar`,
     8 px, pouce en `--bg-hover`) convient à un panneau qui défile ; posé dans un
     champ de saisie de trois lignes, il devient un trait pâle qui coupe la barre
     en deux. Ici on le veut discret : plus fin, et un pouce en voile du thème qui
     ne se révèle qu'au survol.
     ⚠️ `scrollbar-color` (Firefox) ET `::-webkit-scrollbar` (Chrome/Brave) : les
     deux moteurs ne lisent pas le même. N'en poser qu'un laisse l'autre au style
     par défaut du système — c'est-à-dire au trait clair d'origine. */
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--th-voile), .07) transparent;
  padding: var(--e-4) 0;
}
.studio-prompt-input::-webkit-scrollbar-thumb {
  background: rgba(var(--th-voile), .06);
  border-radius: var(--r-pilule);
}
.studio-prompt-input::-webkit-scrollbar-thumb:hover { background: rgba(var(--th-voile), .13); }
/* Pas d'anneau de focus violet sur le textarea studio : la règle globale
   « :focus-visible { outline: violet } » (accessibilité, plus bas dans le fichier,
   même spécificité) écrasait le outline:none ci-dessus. On le ré-annule ici. */
.studio-prompt-input:focus,
.studio-prompt-input:focus-visible { outline: none; }
.studio-prompt-input::placeholder { color: var(--text-3); }

.studio-send-btn {
  flex-shrink: 0;
  width: 40px; height: 40px;
  border-radius: var(--r-lg);
  background: var(--violet); border: none; outline: none; color: var(--sur-accent);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background var(--t-moyen), transform var(--t-moyen), opacity var(--t-moyen);
  padding: 0;
}
.studio-send-btn:hover:not(:disabled) { background: var(--violet-mid); transform: scale(1.06); }
.studio-send-btn:disabled { opacity: 0.3; cursor: not-allowed; transform: none; }

/* ⚠️⚠️ LE MÊME BOUTON, DEUX MÉTIERS. Pendant la réponse il arrête au lieu d'envoyer.
   Il garde sa place et sa taille — seul le dessin change — pour que la main sache
   déjà où viser. Le fond passe en teinte de danger atténuée : assez pour dire « ce
   n'est plus le même geste », pas assez pour crier à l'erreur. */
.studio-send-btn.stop {
  background: rgba(var(--th-danger-rgb), .18);
  color: var(--th-danger);
}
.studio-send-btn.stop:hover:not(:disabled) {
  background: rgba(var(--th-danger-rgb), .28);
  transform: scale(1.06);
}
/* Le carré d'arrêt respire doucement : sans ça, un bouton immobile pendant une
   réponse longue ne dit pas qu'il y a encore quelque chose en cours. */
.studio-send-btn.stop svg { animation: studioStopSouffle 1.8s ease-in-out infinite; }
@keyframes studioStopSouffle {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

/* ── Bandeau « Modifier » ─────────────────────────────────────────────────────
   ⚠️ Il vit DANS la barre d'entrée, au-dessus du texte : posé ailleurs, il faudrait
   regarder à deux endroits pour comprendre ce qu'on est en train de faire. */
/* ⚠️⚠️ IL NE DOIT PAS PESER PLUS QUE CE QU'IL ANNONCE. Amadou (27/08) : « la mention
   modifier est bien, mais beaucoup trop grosse, il faut que ce soit plus discret ».
   Première version : pleine largeur, cadre, fond teinté — elle avait l'air d'un
   avertissement alors qu'elle dit seulement dans quel mode on écrit.
   ⚠️ `align-self: flex-start` est le cœur du correctif : la barre de saisie est une
   colonne, donc SANS lui l'étiquette s'étire d'un bord à l'autre quel que soit son
   texte. Elle ne fait plus que la largeur de ses trois mots.
   ⚠️ Et plus de cadre : le fond léger suffit à la détacher, le trait ajoutait une
   deuxième ligne horizontale juste au-dessus de celle du champ. */
.studio-modif {
  align-self: flex-start;
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-2) var(--e-6) var(--e-2) var(--e-8);
  border-radius: var(--r-pilule);
  background: rgba(var(--th-accent-rgb), .10);
  animation: velbo-entree var(--t-moyen) var(--c-pose) both;
}
.studio-modif.hidden { display: none; }
.studio-modif-icone { color: var(--th-accent); flex-shrink: 0; opacity: .85; }
.studio-modif-titre {
  font-size: var(--t-micro); font-weight: 600;
  color: var(--th-accent);
  letter-spacing: .02em;
  white-space: nowrap;
}
.studio-modif-fermer {
  flex-shrink: 0;
  width: 16px; height: 16px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; cursor: pointer;
  border-radius: 50%;
  color: var(--th-accent);
  opacity: .7;
  transition: opacity var(--t-bref), background var(--t-bref);
}
.studio-modif-fermer:hover { opacity: 1; background: rgba(var(--th-accent-rgb), .18); }

/* La bulle reprise s'estompe pendant qu'on récrit : elle est encore là (rien n'est
   détruit tant qu'on n'a pas validé) mais elle n'est plus la version en cours. */
.studio-msg.en-modif {
  opacity: .45;
  transition: opacity var(--t-moyen);
}

/* Badge contextuel Claude / OpenAI dans la barre d'input */
.studio-mode-badge {
  flex-shrink: 0; align-self: center;
  font-size: var(--t-mini); font-weight: var(--fw-fort); letter-spacing: var(--ls-leger);
  padding: var(--e-2) var(--e-8); border-radius: var(--r-xl);
  border: 1px solid rgba(var(--th-accent-rgb),0.22);
  color: var(--violet-light); background: rgba(var(--th-accent-rgb),0.08);
  transition: color var(--t-moyen), border-color var(--t-moyen), background var(--t-moyen);
  pointer-events: none; user-select: none;
}
.studio-mode-badge.mode-openai {
  color: var(--green); border-color: rgba(74,222,128,0.28); background: rgba(74,222,128,0.07);
}

.studio-bar-hint { display: none; }
.spin-icon { animation: spin 0.7s linear infinite; display: block; }

/* Drop overlay */
.studio-drop-overlay {
  position: absolute; inset: 0;
  background: rgba(var(--th-accent-rgb),0.1);
  border: 2px dashed var(--violet);
  border-radius: var(--radius-lg);
  display: flex; align-items: center; justify-content: center;
  z-index: 10;
  backdrop-filter: blur(3px);
  pointer-events: none;
}
.studio-drop-overlay::after {
  content: 'Déposer les photos ici';
  font-size: var(--t-small); font-weight: var(--fw-fort);
  color: var(--violet-light); letter-spacing: var(--ls-serre);
}

/* ── Cards (mods-card pattern) ── */
.mod-section {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-22) var(--e-24);
  display: flex;
  flex-direction: column;
  gap: var(--e-14);
  min-width: 0;
  transition: border-color var(--d-fast) var(--c-pose);
}
.mod-section-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 0;
}
.mod-section-title {
  font-size: var(--t-body);
  font-weight: var(--fw-moyen);
  color: var(--text);
  letter-spacing: var(--ls-serre);
  margin-bottom: 0;
  display: flex;
  align-items: center;
  gap: var(--e-10);
}
.mod-section-title svg { color: var(--violet-soft); flex-shrink: 0; }
.mod-section-title .mods-card-title-icon svg { color: var(--violet-soft); }
.mod-section-header .mod-section-title { margin-bottom: 0; }
.mod-optional {
  font-size: var(--t-mini); color: var(--text-3); font-weight: var(--fw-normal);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-xl); padding: var(--e-1) var(--e-8); margin-left: var(--e-4);
}

/* Bouton "Depuis la biblio" dans repost/démasquer */
.mod-from-lib-btn {
  width: 100%;
  margin-top: var(--e-8);
  justify-content: center;
  font-size: var(--t-base);
  padding: var(--e-8) var(--e-14);
  gap: var(--e-6);
}

/* ── Drop zone (mods-dropzone) ── */
.mod-drop-full {
  width: 100%;
  box-sizing: border-box;
  min-height: 180px;
  flex-direction: column;
  gap: var(--e-10);
  padding: var(--e-32) var(--e-20);
}
.mod-drop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-8);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
  background: rgba(var(--th-voile),0.015);
  color: var(--text-3);
  font-size: var(--t-small);
  cursor: pointer;
  text-align: center;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.mod-drop:hover,
.mod-drop.dragover {
  border-color: var(--violet-glow);
  color: var(--text);
  background: var(--violet-tint);
}
.mod-drop .link-btn { color: var(--violet-soft); font-weight: var(--fw-moyen); }

/* ── Toggle btn (masquer/afficher texte) ── */
.mod-toggle-btn {
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-12); border-radius: var(--r-pilule);
  font-size: var(--t-meta); font-weight: var(--fw-moyen);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-3); cursor: pointer;
  transition: var(--transi); white-space: nowrap; flex-shrink: 0;
}
.mod-toggle-btn:hover { border-color: var(--violet-mid); color: var(--text); }
.mod-toggle-btn.open { color: var(--violet-light); border-color: var(--violet-mid); background: rgba(var(--th-accent-rgb),0.08); }

/* ── Loaded strip ── */
.mod-loaded-strip {
  display: flex; gap: var(--e-8); flex-wrap: wrap;
  margin-top: var(--e-14); padding-top: var(--e-14);
  border-top: 1px solid var(--border);
}
.mod-thumb {
  position: relative; width: 64px; height: 80px;
  border-radius: var(--r-sm); overflow: hidden;
  border: 1px solid var(--border); flex-shrink: 0;
  box-shadow: 0 2px 8px rgba(var(--th-ombre),0.15);
}
.mod-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mod-thumb-rm {
  position: absolute; top: 3px; right: 3px;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(var(--th-ombre),0.65); border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--sur-sombre); font-size: var(--t-micro); opacity: 0;
  transition: opacity var(--t-moyen);
}
.mod-thumb:hover .mod-thumb-rm { opacity: 1; }

/* Source meta */
.mod-source-meta {
  margin-top: var(--e-10); font-size: var(--t-base); color: var(--text-3);
  display: flex; align-items: center; gap: var(--e-8);
}
.mod-source-badge {
  background: rgba(var(--th-accent-rgb),0.12); border: 1px solid var(--violet-mid);
  border-radius: var(--r-xl); padding: var(--e-2) var(--e-10); font-size: var(--t-meta);
  color: var(--violet-light); font-weight: var(--fw-fort);
}

/* ── Motifs (mods-pill pattern) ── */
.mod-motifs-row {
  display: flex; gap: var(--e-8); flex-wrap: wrap; margin-bottom: 0;
}
.mod-motif-btn {
  display: inline-flex; align-items: center; gap: var(--e-8);
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-pilule);
  font-size: var(--t-small);
  font-weight: var(--fw-normal);
  background: rgba(var(--th-voile),0.025);
  border: 1px solid var(--border);
  color: var(--text-2);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose), transform var(--t-bref) var(--c-rebond);
}
.mod-motif-btn:not(.active):hover { background: var(--bg-sidebar); color: var(--text); border-color: var(--border); }
.mod-motif-btn.active {
  background: var(--violet-tint);
  border-color: rgba(var(--th-accent-rgb),0.28);
  color: var(--violet-soft);
  box-shadow: none;
}
.mod-motif-hint {
  font-size: var(--t-meta);
  color: var(--text-3);
  line-height: var(--lh-normal);
  padding: 0;
  background: transparent;
  border-radius: 0;
  border-left: none;
  margin-top: 0;
}

/* ── Démasquage auto : scan + liste des annonces masquées ── */
.unmask-scan-row { display: flex; gap: var(--e-10); align-items: center; flex-wrap: wrap; margin-bottom: var(--e-10); }
.unmask-scan-row #unmask-account { flex: 1; min-width: 200px; }
.unmask-results { display: flex; flex-direction: column; gap: var(--e-10); margin-top: var(--e-14); }
.unmask-empty { font-size: var(--t-small); color: var(--text-3); padding: var(--e-14); text-align: center; }
.unmask-card {
  display: flex; align-items: center; gap: var(--e-12); padding: var(--e-12) var(--e-14);
  border-radius: var(--r-lg); border: 1px solid var(--border); background: var(--cok-bg-2);
}
.unmask-card.done { opacity: .6; }
.unmask-card-info { flex: 1; min-width: 0; }
.unmask-card-title { font-size: var(--t-small); font-weight: var(--fw-moyen); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.unmask-card-meta { font-size: var(--t-meta); color: var(--text-3); margin-top: var(--e-4); display: flex; gap: var(--e-8); flex-wrap: wrap; align-items: center; }
.unmask-badge { border-radius: var(--r-pilule); padding: var(--e-1) var(--e-8); font-weight: var(--fw-fort); font-size: var(--t-mini); }
.unmask-badge.motif { background: var(--violet-tint); color: var(--violet-light); }
.unmask-badge.fav-lo { background: rgba(52,211,153,.14); color: var(--green); }
.unmask-badge.fav-hi { background: rgba(251,191,36,.16); color: var(--amber); }
.unmask-badge.state-done { background: rgba(52,211,153,.14); color: var(--green); }
.unmask-badge.state-err { background: rgba(248,113,113,.16); color: var(--red); }
.unmask-card-actions { flex-shrink: 0; display: flex; gap: var(--e-6); }
/* Aperçu avant/après d'une réparation */
.unmask-prev-grid { display: flex; flex-wrap: wrap; gap: var(--e-8); }
.unmask-prev-ph { width: 66px; height: 84px; border-radius: var(--r-sm); overflow: hidden; position: relative; border: 1px solid var(--border); }
.unmask-prev-ph img { width: 100%; height: 100%; object-fit: cover; }
.unmask-prev-ph span { position: absolute; bottom: 0; left: 0; right: 0; font-size: var(--t-micro); text-align: center;
  background: rgba(var(--th-ombre),.6); color: var(--sur-sombre); padding: var(--e-1) 0; }
.unmask-prev-text { font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-normal); }
.unmask-prev-text b { color: var(--text); }

/* ── Text fields (Aurora inputs) ── */
.mod-text-grid { display: flex; flex-direction: column; gap: var(--e-10); }
.mod-input { width: 100%; box-sizing: border-box;
  color: var(--text);
  font-size: var(--t-small);
  font-family: inherit;
  outline: none;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose) }
.mod-input:focus {
  border-color: rgba(var(--th-accent-rgb),0.5);
  background: rgba(var(--th-voile),0.04);
  box-shadow: none;
}
.mod-input::placeholder { color: var(--text-3); }
.mod-textarea { width: 100%; box-sizing: border-box;
  color: var(--text);
  font-size: var(--t-small);
  resize: vertical;
  min-height: 200px;
  line-height: var(--lh-normal);
  font-family: inherit;
  outline: none;
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose) }
.mod-textarea:focus {
  border-color: rgba(var(--th-accent-rgb),0.5);
  background: rgba(var(--th-voile),0.04);
  box-shadow: none;
}
.mod-textarea::placeholder { color: var(--text-3); }

/* ── Schedule ── */
.mod-sched-row { display: flex; gap: var(--e-8); flex-wrap: wrap; }
.mod-sched-btn {
  padding: var(--e-8) var(--e-18); border-radius: var(--r-pilule); font-size: var(--t-base); font-weight: var(--fw-moyen);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-2); cursor: pointer;
  transition: var(--transi);
}
.mod-sched-btn:hover { border-color: var(--violet-mid); color: var(--text); }
.mod-sched-btn.active {
  background: rgba(var(--th-accent-rgb),0.12); border-color: var(--violet);
  color: var(--violet-light);
  box-shadow: 0 0 0 3px rgba(var(--th-accent-rgb),0.1);
}

/* ── Go button (mods-cta : aurora pleine largeur) ── */
.mod-go-btn {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: var(--e-10);
  height: 48px;
  padding: 0 var(--e-28);
  border: none;
  border-radius: var(--r-lg);
  background: var(--aurora);
  color: var(--sur-accent);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-serre);
  cursor: pointer;
  box-shadow:
    0 0 0 1px rgba(var(--th-voile),0.04) inset,
    0 12px 32px -12px rgba(var(--th-accent-rgb),0.55),
    0 6px 18px -8px rgba(var(--th-second-rgb),0.32);
  transition: filter var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.mod-go-btn:hover { filter: brightness(1.08); }
.mod-go-btn:active { transform: translateY(1px); }
.mod-go-btn:disabled { opacity: 0.45; cursor: not-allowed; filter: none; box-shadow: none; }

/* ── Results ── */
.mod-results { display: flex; flex-direction: column; gap: var(--e-14); margin-top: var(--e-4); }

/* Loading animation */
.mod-loading-wrap {
  display: flex; justify-content: center; align-items: center;
  padding: var(--e-32) 0 var(--e-24);
}
.mod-loading-inner {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-14);
}
.rp-loading-dot {
  display: inline-block;
  color: var(--text-3);
  animation: rp-pulse 1.2s ease-in-out infinite;
}
@keyframes rp-pulse { 0%,100%{opacity:.3} 50%{opacity:1} }

.mod-loading-dots {
  display: flex; align-items: center; gap: var(--e-8);
}
.mod-loading-dots span {
  display: block; width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--violet-light);
  animation: mod-dot-wave 1.2s ease-in-out infinite;
}
.mod-loading-dots span:nth-child(1) { animation-delay: var(--t-bref); }
.mod-loading-dots span:nth-child(2) { animation-delay: var(--t-moyen); }
.mod-loading-dots span:nth-child(3) { animation-delay: var(--t-long); }
.mod-loading-dots span:nth-child(4) { animation-delay: 0.54s; }
@keyframes mod-dot-wave {
  0%, 100% { opacity: 0.2; transform: translateY(0); }
  40%       { opacity: 1;   transform: translateY(-6px); }
}
.mod-loading-label {
  font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-3);
  letter-spacing: var(--ls-leger);
}

/* Before/after */
.mod-ba-section {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--e-18);
}
.mod-ba-title {
  font-size: var(--t-meta); font-weight: var(--fw-gras); color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.1em;
  margin-bottom: var(--e-14);
}
.mod-ba-row { display: flex; gap: var(--e-14); flex-wrap: wrap; }
.mod-ba-pair { display: flex; align-items: center; gap: var(--e-10); }
.mod-ba-card { display: flex; flex-direction: column; gap: var(--e-6); align-items: center; }
.mod-ba-label {
  font-size: var(--t-micro); font-weight: var(--fw-gras); color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.1em;
}
.mod-ba-img {
  width: 96px; height: 120px; object-fit: cover;
  border-radius: var(--r-md); border: 1px solid var(--border);
  cursor: zoom-in;
  box-shadow: 0 4px 12px rgba(var(--th-ombre),0.2);
  transition: transform var(--t-moyen);
}
.mod-ba-img:hover { transform: scale(1.03); }
.mod-ba-arrow { color: var(--violet-light); font-size: var(--t-lead); flex-shrink: 0; margin-top: var(--e-18); }

/* ── Modal comparaison avant/après ── */
#modal-compare { z-index: 1100; }
.compare-backdrop {
  position: fixed; inset: 0;
  background: rgba(var(--th-ombre),0.93);
  backdrop-filter: blur(12px);
}
.compare-card {
  position: relative;
  display: flex; flex-direction: column; gap: 0;
  background: var(--bg);
  border: 1px solid rgba(var(--th-voile),0.07);
  border-radius: var(--r-xl);
  padding: var(--e-28) var(--e-28) var(--e-24);
  max-width: 88vw;
  max-height: 92vh;
  overflow: hidden;
  z-index: 1;
}
.compare-close-btn {
  position: absolute; top: 14px; right: 14px;
  background: var(--bg-elevated); border: 1px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-sm); width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: var(--text-2);
  transition: color var(--t-moyen), background var(--t-moyen);
}
.compare-close-btn:hover { color: var(--text); background: rgba(var(--th-voile),0.12); }
.compare-cols {
  display: flex; align-items: flex-start; gap: var(--e-20);
  overflow: hidden; flex: 1;
}
.compare-col {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-12);
  flex: 1; min-width: 0;
}
.compare-col-label {
  font-size: var(--t-micro); font-weight: var(--fw-gras); text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--violet-light);
}
.compare-col > img {
  width: 100%; max-height: 80vh;
  object-fit: contain; border-radius: var(--r-lg);
}
/* Conteneur après : 1 ou 2 images */
.compare-after-container {
  display: flex; gap: var(--e-10); width: 100%;
}
.compare-after-container img {
  flex: 1; min-width: 0;
  max-height: 80vh; object-fit: contain; border-radius: var(--r-lg);
}

/* Summary badge */
.mod-ba-summary { margin-bottom: var(--e-14); }
.mod-summary-badge {
  display: inline-flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-meta); font-weight: var(--fw-gras); letter-spacing: var(--ls-ample);
  padding: var(--e-6) var(--e-12); border-radius: var(--r-xl);
}
.mod-summary-badge.ia {
  background: rgba(var(--th-accent-rgb),0.15); color: var(--violet-light);
  border: 1px solid rgba(var(--th-accent-rgb),0.35);
}
.mod-summary-badge.ia::before {
  content: '✦'; font-size: var(--t-mini);
}
.mod-summary-manual {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--e-6);
  font-size: var(--t-meta); color: var(--text-3);
}
.mod-summary-tag {
  background: var(--surface-2, var(--bg-elevated));
  border: 1px solid var(--border);
  color: var(--text-2);
  font-size: var(--t-mini); font-weight: var(--fw-fort);
  padding: var(--e-2) var(--e-10); border-radius: var(--r-lg);
  text-transform: capitalize;
}

/* Skeleton loading */
.mod-text-skeleton {
  display: flex; flex-direction: column; gap: var(--e-8);
  padding: var(--e-4) 0;
}
.mod-sk-label {
  height: 10px; width: 60px; border-radius: var(--r-sm);
  background: var(--border);
  animation: sk-pulse 1.4s ease-in-out infinite;
}
.mod-sk-block {
  height: 14px; width: 100%; border-radius: var(--r-sm);
  background: var(--border);
  animation: sk-pulse 1.4s ease-in-out infinite;
}
.mod-sk-block.mid   { width: 78%; animation-delay: var(--t-moyen); }
.mod-sk-block.short { width: 50%; animation-delay: var(--t-long);  }
@keyframes sk-pulse {
  0%, 100% { opacity: 0.4; }
  50%       { opacity: 0.9; }
}

/* Text result blocks */
.mod-text-result-wrap { display: flex; flex-direction: column; gap: var(--e-12); }
.mod-text-result-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  animation: result-pop var(--t-long) cubic-bezier(0.34,1.56,0.64,1) both;
}
@keyframes result-pop {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.mod-text-result-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-10) var(--e-14);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.mod-text-result-lbl {
  font-size: var(--t-mini); font-weight: var(--fw-gras);
  text-transform: uppercase; letter-spacing: var(--ls-caps);
  color: var(--violet-light);
}
.mod-text-copy-btn {
  display: flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-mini); font-weight: var(--fw-fort); color: var(--text-3);
  background: none; border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--e-4) var(--e-10);
  cursor: pointer; transition: color var(--t-moyen), border-color var(--t-moyen);
}
.mod-text-copy-btn:hover { color: var(--violet-light); border-color: var(--violet-mid); }
.mod-text-result-body {
  padding: var(--e-14);
  font-size: var(--t-base); line-height: var(--lh-aere);
  color: var(--text);
  white-space: pre-wrap;
}

/* Text comparison (legacy) */
.mod-text-compare {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: var(--e-18);
}
.mod-text-compare-title {
  font-size: var(--t-meta); font-weight: var(--fw-gras); color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.1em; margin-bottom: var(--e-14);
}
.mod-text-row {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--e-12); align-items: start;
  margin-bottom: var(--e-12);
}
.mod-text-col-label {
  font-size: var(--t-micro); color: var(--text-3); font-weight: var(--fw-fort);
  text-transform: uppercase; letter-spacing: var(--ls-caps);
  margin-bottom: var(--e-4);
}
.mod-text-val {
  font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal);
  background: var(--surface-2); border-radius: var(--radius-xs);
  padding: var(--e-8) var(--e-10); white-space: pre-wrap;
}
.mod-text-val.after { color: var(--cyan-light); }
.mod-text-arrow { color: var(--violet-light); align-self: center; font-size: var(--t-body); }

/* Copy result btn */
.mod-copy-btn {
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-14); border-radius: var(--r-pilule);
  font-size: var(--t-meta); background: var(--surface-2);
  border: 1px solid var(--border); color: var(--text-2);
  cursor: pointer; transition: var(--transi);
}
.mod-copy-btn:hover { border-color: var(--cyan); color: var(--cyan-light); }

/* Footer nav */
/* Nav 3 zones (Précédent / Actualiser / Suivant) — pattern atl-nav du design */
.atelier-footer-nav {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--e-12);
  align-items: center;
  margin-top: 0;
  padding-top: var(--e-16);
  border-top: none;
}
.atelier-footer-nav .atl-nav-l { justify-self: start; }
.atelier-footer-nav .atl-nav-c { justify-self: center; }
.atelier-footer-nav .atl-nav-r { justify-self: end; }
/* Le btn-primary du Suivant reçoit .atl-next pour matcher la pill design (38 px, radius 10) */
.atl-next {
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  height: 38px;
  padding: 0 var(--e-18);
  border: none;
  border-radius: var(--r-md);
  background: var(--aurora);
  color: var(--sur-accent);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  box-shadow: 0 8px 22px -10px rgba(var(--th-accent-rgb),0.55);
  transition: filter var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.atl-next:hover { filter: brightness(1.08); }
.atl-next:active { transform: translateY(1px); }
.atl-next:disabled { opacity: 0.45; cursor: not-allowed; filter: none; box-shadow: none; }

/* ══════════════════════════════════════════════════
   BATCH
══════════════════════════════════════════════════ */
.batch-wrap { max-width: 980px; margin: 0 auto; }

/* Page header */
.batch-page-header { display:flex; align-items:flex-start; justify-content:space-between; margin-bottom:var(--e-28); }
.batch-page-title { font-size:var(--t-title); font-weight:800; letter-spacing:-.03em; }
.batch-title-gradient { color: var(--text); -webkit-text-fill-color: var(--sur-accent); }
.batch-page-sub { font-size:var(--t-base); color:var(--text-3); margin-top:var(--e-4); }

/* Card base */
.batch-card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:var(--e-20); margin-bottom:var(--e-16); }
.batch-card-title { font-size:var(--t-meta); font-weight:var(--fw-gras); letter-spacing:var(--ls-ample); text-transform:uppercase; color:var(--text-3); display:flex; align-items:center; gap:var(--e-8); }

/* Top row */
.batch-top-row { display:grid; grid-template-columns:1fr 280px; gap:var(--e-14); margin-bottom:var(--e-16); }
.batch-field { display:flex; flex-direction:column; gap:var(--e-6); }
.batch-label { font-size:var(--t-meta); font-weight:var(--fw-fort); color:var(--text-2); letter-spacing:var(--ls-large); text-transform:uppercase; }
.batch-input { background:var(--bg-2); border:1px solid var(--border-strong); border-radius: var(--r-md); color:var(--text); font-size:var(--t-small); font-family:inherit; padding:var(--e-10) var(--e-12); outline:none; transition:border-color var(--t-moyen); }
.batch-input:focus { border-color:var(--violet); }
.batch-input::placeholder { color:var(--text-3); }
.batch-select { cursor:pointer; }
.batch-textarea { resize:vertical; min-height:64px; line-height:var(--lh-normal); }

/* Two-column zones */
.batch-zones-row { display:grid; grid-template-columns:1fr 1fr; gap:var(--e-16); margin-bottom:var(--e-16); }

/* Zone header */
.batch-zone-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--e-14); }

/* Empty state zone */
.batch-pick-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-10); padding: var(--e-32) var(--e-16);
  color: var(--text-3); font-size: var(--t-base); text-align: center;
  border: 1.5px dashed var(--border); border-radius: var(--r-md); margin-top: var(--e-12);
}

/* Batch picker overlay */
.batch-picker-overlay {
  position: fixed; inset: 0;
  background: rgba(var(--th-ombre),.65); backdrop-filter: blur(6px);
  z-index: 200;
  display: flex; align-items: center; justify-content: center;
}
.batch-picker-panel {
  background: var(--bg-2); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  width: min(680px, 95vw); max-height: 82vh;
  display: flex; flex-direction: column;
  overflow: hidden;
  box-shadow: 0 24px 80px rgba(var(--th-ombre),.6);
}
.batch-picker-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-18) var(--e-20) var(--e-14); border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.batch-picker-title { font-size: var(--t-small); font-weight: var(--fw-gras); letter-spacing: var(--ls-serre); }
.batch-picker-close {
  width: 30px; height: 30px; border-radius: var(--r-sm);
  border: 1px solid var(--border-strong); background: transparent;
  color: var(--text-2); cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: var(--transi);
}
.batch-picker-close:hover { background: var(--surface-2); color: var(--text); }
.batch-picker-grid {
  flex: 1; overflow-y: auto; padding: var(--e-16) var(--e-20);
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--e-12);
  scrollbar-width: thin;
  /* Même raison que `.upload-zone .preview-grid` : sans elle, Chrome redessine la
     barre au gris du système et l'habillage global du fichier ne s'applique plus. */
  scrollbar-color: var(--bg-hover) transparent;

}
.batch-picker-card {
  background: var(--surface);
  border: 2px solid var(--border);
  border-radius: var(--radius);
  overflow: visible;
  cursor: pointer; position: relative;
  transition: border-color var(--t-moyen), transform var(--t-moyen);
}
.batch-picker-card:hover { border-color: var(--violet-mid); transform: translateY(-2px); }
.batch-picker-card.selected { border-color: var(--violet); background: rgba(var(--th-accent-rgb),.08); }
.batch-picker-card-cover {
  width: 100%; border-radius: var(--radius) var(--radius) 0 0;
  overflow: hidden; aspect-ratio: 3/4;
  background: var(--surface-2); position: relative;
}
.batch-picker-card-cover img { width: 100%; height: 100%; object-fit: cover; }
.batch-picker-card-info { padding: var(--e-8) var(--e-10) var(--e-10); }
.batch-picker-card-name { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.batch-picker-card-meta { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-2); }
.batch-picker-check {
  position: absolute; top: 7px; right: 7px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--violet); border: 2px solid #fff;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transition: opacity var(--t-moyen);
}
.batch-picker-card.selected .batch-picker-check { opacity: 1; }
.batch-picker-footer {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-14) var(--e-20); border-top: 1px solid var(--border); flex-shrink: 0;
  background: var(--bg-2);
}
.batch-picker-count { font-size: var(--t-base); color: var(--text-2); font-weight: var(--fw-moyen); }
.batch-picker-confirm {
  padding: var(--e-10) var(--e-22); border-radius: var(--r-md); border: none;
  background: var(--violet); color: var(--sur-sombre); font-size: var(--t-small); font-weight: var(--fw-fort);
  cursor: pointer; transition: var(--transi);
}
.batch-picker-confirm:hover:not(:disabled) { background: var(--violet-mid); }
.batch-picker-confirm:disabled { opacity: .35; cursor: not-allowed; }
.batch-picker-empty { font-size: var(--t-base); color: var(--text-3); text-align: center; padding: var(--e-40); grid-column: 1/-1; }

/* Drop zone */
.batch-drop-zone { border:1.5px dashed var(--border-strong); border-radius: var(--r-md); padding:var(--e-18) var(--e-14); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--e-8); color:var(--text-3); font-size:var(--t-base); cursor:pointer; transition: var(--transi); text-align:center; }
.batch-drop-zone:hover, .batch-drop-zone.dragover { border-color:var(--violet); background:rgba(var(--th-accent-rgb),.05); color:var(--text-2); }
.batch-drop-sub { font-size:var(--t-micro); color:var(--text-3); }

/* Dresses grid */
.batch-dresses-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--e-8); margin-top:var(--e-12); }
.batch-dress-thumb { position:relative; aspect-ratio:3/4; border-radius: var(--r-sm); overflow:hidden; border:1px solid var(--border); cursor:grab; }
.batch-dress-thumb img { width:100%; height:100%; object-fit:cover; }
.batch-dress-lbl { position:absolute; bottom:0; left:0; right:0; padding:var(--e-4) var(--e-6); background:rgba(var(--th-panneau-rgb),.78); font-size:var(--t-micro); color:rgba(var(--th-voile),.85); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.batch-dress-rm { position:absolute; top:3px; right:3px; width:17px; height:17px; border-radius:50%; background:rgba(var(--th-ombre),.75); border:none; color: var(--sur-sombre); font-size:var(--t-micro); display:flex; align-items:center; justify-content:center; cursor:pointer; opacity:0; transition:opacity var(--t-moyen); padding:0; }
.batch-dress-thumb:hover .batch-dress-rm { opacity:1; }

/* Zone counter */
.batch-zone-counter { font-size:var(--t-meta); color:var(--text-2); font-weight:var(--fw-moyen); margin-top:var(--e-10); }

/* Models list */
.batch-models-list { display:flex; flex-direction:column; gap:var(--e-8); }
.batch-models-empty { font-size:var(--t-base); color:var(--text-3); padding:var(--e-20); text-align:center; }
.batch-model-item { display:flex; align-items:center; gap:var(--e-10); padding:var(--e-10) var(--e-10); border-radius: var(--r-md); border:1px solid var(--border); cursor:pointer; transition: var(--transi); }
.batch-model-item:hover { border-color:var(--violet-mid); background:rgba(var(--th-accent-rgb),.04); }
.batch-model-item.selected { border-color:var(--violet); background:rgba(var(--th-accent-rgb),.1); }
.batch-model-check { width:18px; height:18px; border-radius:var(--r-micro); border:1.5px solid var(--border-strong); flex-shrink:0; display:flex; align-items:center; justify-content:center; transition: var(--transi); }
.batch-model-item.selected .batch-model-check { background:var(--violet); border-color:var(--violet); }
.batch-model-avatar { width:34px; height:34px; border-radius: var(--r-sm); object-fit:cover; flex-shrink:0; border:1px solid var(--border); background:var(--surface-2); }
.batch-model-name { font-size:var(--t-base); font-weight:var(--fw-moyen); color:var(--text); }
.batch-model-sub { font-size:var(--t-mini); color:var(--text-3); }

/* Config rows */
.batch-config-row3 { display:grid; grid-template-columns:1fr 1fr 1fr; gap:var(--e-14); margin-bottom:var(--e-14); }
.batch-config-row2 { display:grid; grid-template-columns:2fr 1fr; gap:var(--e-14); margin-bottom:var(--e-14); }

/* Views chips */
.batch-views-chips { display:flex; gap:var(--e-8); flex-wrap:wrap; }
.batch-view-chip { display:inline-flex; align-items:center; gap:var(--e-6); padding:var(--e-6) var(--e-12); border-radius: var(--r-pilule); border:1px solid var(--border-strong); background:transparent; color:var(--text-2); font-size:var(--t-meta); font-weight:var(--fw-moyen); cursor:pointer; transition: var(--transi); }
.batch-view-chip.active { border-color:var(--violet); background:rgba(var(--th-accent-rgb),.12); color:var(--violet-light); }

/* Parallelism */
.batch-para-btns { display:flex; gap:var(--e-6); }
.batch-para-btn { flex:1; padding:var(--e-8) var(--e-4); border-radius: var(--r-sm); border:1px solid var(--border-strong); background:transparent; color:var(--text-2); font-size:var(--t-base); font-weight:var(--fw-moyen); cursor:pointer; text-align:center; transition: var(--transi); }
.batch-para-btn.active { border-color:var(--violet); background:rgba(var(--th-accent-rgb),.12); color:var(--violet-light); }

/* Estimate card */
.batch-estimate-card { background:linear-gradient(135deg,rgba(var(--th-accent-rgb),.07),rgba(var(--th-second-rgb),.04)); border:1px solid rgba(var(--th-accent-rgb),.2); border-radius:var(--radius); padding:var(--e-20); margin-bottom:var(--e-4); }
.batch-estimate-grid { display:grid; grid-template-columns:repeat(4,1fr); margin-bottom:var(--e-18); }
.batch-estimate-item { padding:var(--e-12) var(--e-16); border-right:1px solid var(--bg-elevated); }
.batch-estimate-item:last-child { border-right:none; }
.batch-estimate-val { font-size:var(--t-title); font-weight:800; letter-spacing:-.03em; color:var(--text); }
.batch-estimate-val.violet { color:var(--violet-light); }
.batch-estimate-val.cyan { color:var(--cyan-light); }
.batch-estimate-val.amber { color:var(--tier-luxe-text); }
.batch-estimate-lbl { font-size:var(--t-micro); color:var(--text-3); margin-top:var(--e-2); text-transform:uppercase; letter-spacing:var(--ls-ample); font-weight:var(--fw-fort); }
.batch-launch-row { display:flex; gap:var(--e-10); align-items:center; }
.batch-btn-launch { display:flex; align-items:center; gap:var(--e-8); padding:var(--e-14) 26px; border-radius: var(--r-lg); border:none; background:linear-gradient(135deg,var(--violet),var(--violet-soft)); color: var(--sur-accent); font-size:var(--t-small); font-weight:var(--fw-gras); cursor:pointer; transition: var(--transi); box-shadow:0 4px 22px rgba(var(--th-accent-rgb),.3); }
.batch-btn-launch:hover:not(:disabled) { transform:translateY(-2px); box-shadow:0 8px 30px rgba(var(--th-accent-rgb),.42); }
.batch-btn-launch:disabled { opacity:.35; cursor:not-allowed; transform:none; box-shadow:none; }
.batch-btn-test { display:inline-flex; align-items:center; gap:var(--e-8); padding:var(--e-12) var(--e-18); border-radius: var(--r-lg); border:1px solid rgba(var(--th-accent-rgb),.35); background:rgba(var(--th-accent-rgb),.07); color:var(--violet-light); font-size:var(--t-base); font-weight:var(--fw-fort); cursor:pointer; transition: var(--transi); }
.batch-btn-test:hover { background:rgba(var(--th-accent-rgb),.14); }
.batch-estimate-note { font-size:var(--t-mini); color:var(--text-3); margin-left:auto; line-height:var(--lh-normal); text-align:right; max-width:220px; }

/* btn-xs variants */
.btn-xs { display:inline-flex; align-items:center; gap:var(--e-4); padding:var(--e-4) var(--e-10); border-radius: var(--r-sm); border:1px solid var(--border-strong); background:transparent; color:var(--text-3); font-size:var(--t-mini); font-weight:var(--fw-moyen); cursor:pointer; transition: var(--transi); }
.btn-xs:hover { border-color:var(--violet); color:var(--violet-light); }
.btn-xs-danger:hover { border-color:var(--red) !important; color:var(--red) !important; }

/* ── PROGRESS VIEW ── */
.batch-prog-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--e-22); }
.batch-prog-title { font-size:var(--t-body); font-weight:var(--fw-gras); }
.batch-prog-sub { font-size:var(--t-base); color:var(--text-2); margin-top:var(--e-2); }
.batch-btn-pause { display:inline-flex; align-items:center; gap:var(--e-6); padding:var(--e-8) var(--e-16); border-radius: var(--r-md); border:1px solid rgba(240,176,85,.35); background:rgba(240,176,85,.08); color:var(--tier-luxe-text); font-size:var(--t-base); font-weight:var(--fw-fort); cursor:pointer; transition: var(--transi); }
.batch-btn-stop { display:inline-flex; align-items:center; gap:var(--e-6); padding:var(--e-8) var(--e-16); border-radius: var(--r-md); border:1px solid var(--danger-bord); background:var(--danger-fond); color:var(--red); font-size:var(--t-base); font-weight:var(--fw-fort); cursor:pointer; transition: var(--transi); }

.batch-prog-bar-wrap { margin-bottom:var(--e-20); }
.batch-prog-bar-top { display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--e-8); }
.batch-prog-bar-label { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--text); }
.batch-prog-bar-pct { font-size:var(--t-base); color:var(--text-2); }
.batch-prog-bar-bg { height:6px; background:var(--bg-hover); border-radius:var(--r-micro); overflow:hidden; }
.batch-prog-bar-fill { height:100%; background:linear-gradient(90deg,var(--violet),var(--cyan)); border-radius:var(--r-micro); transition:width .6s var(--c-pose); }
.batch-prog-bar-sub { font-size:var(--t-meta); color:var(--text-3); margin-top:var(--e-6); }

.batch-current-combo { display:grid; grid-template-columns:1fr 1fr; gap:var(--e-14); margin-bottom:var(--e-16); }
.batch-combo-card { display:flex; align-items:center; gap:var(--e-12); padding:var(--e-14); background:var(--surface); border:1px solid var(--border); border-radius: var(--r-lg); }
.batch-combo-thumb-wrap { flex-shrink:0; }
.batch-combo-thumb-placeholder { width:48px; height:64px; border-radius: var(--r-sm); background:var(--surface-2); border:1px solid var(--border); overflow:hidden; }
.batch-combo-thumb-placeholder img { width:100%; height:100%; object-fit:cover; }
.batch-combo-info-lbl { font-size:var(--t-micro); text-transform:uppercase; letter-spacing:var(--ls-ample); color:var(--text-3); font-weight:var(--fw-gras); margin-bottom:var(--e-4); }
.batch-combo-info-name { font-size:var(--t-small); font-weight:var(--fw-fort); color:var(--text); }
.batch-combo-info-sub { font-size:var(--t-mini); color:var(--text-2); margin-top:var(--e-2); }
.batch-combo-badge { display:inline-flex; align-items:center; gap:var(--e-4); padding:var(--e-4) var(--e-8); margin-top:var(--e-6); border-radius: var(--r-pilule); font-size:var(--t-micro); font-weight:var(--fw-gras); letter-spacing:var(--ls-large); text-transform:uppercase; background:rgba(var(--th-accent-rgb),.14); border:1px solid rgba(var(--th-accent-rgb),.28); color:var(--violet-light); }

.batch-visuals-card { background:var(--surface); border:1px solid var(--border); border-radius: var(--r-lg); padding:var(--e-16); margin-bottom:var(--e-16); }
.batch-visuals-row { display:flex; gap:var(--e-12); }
.batch-visual-slot { flex:1; aspect-ratio:3/4; border-radius: var(--r-md); overflow:hidden; border:1px solid var(--border); position:relative; background:var(--cok-bg-2); display:flex; align-items:center; justify-content:center; }
.batch-visual-slot img { width:100%; height:100%; object-fit:cover; }
.batch-visual-slot-lbl { position:absolute; bottom:0; left:0; right:0; padding:var(--e-6) var(--e-8); background:rgba(var(--th-panneau-rgb),.8); font-size:var(--t-micro); color:rgba(var(--th-voile),.85); display:flex; align-items:center; justify-content:space-between; }
.batch-visual-spinner { width:22px; height:22px; border:2.5px solid rgba(var(--th-accent-rgb),.2); border-top-color:var(--violet); border-radius:50%; animation:spin .75s linear infinite; }
.batch-visual-done { width:18px; height:18px; border-radius:50%; background:rgba(99,214,176,.18); display:flex; align-items:center; justify-content:center; color:var(--green); font-size:var(--t-micro); }
.batch-visual-error { width:18px; height:18px; border-radius:50%; background:rgba(var(--th-danger-rgb),.18); display:flex; align-items:center; justify-content:center; color:var(--red); font-size:var(--t-micro); }

.batch-stats-row { display:flex; gap:var(--e-10); }
.batch-stat-pill { display:flex; align-items:center; gap:var(--e-8); font-size:var(--t-base); flex:1 }
.batch-stat-val { font-weight:var(--fw-gras); }
.batch-stat-val.green { color:var(--green); }
.batch-stat-val.red { color:var(--red); }
.batch-stat-val.amber { color:var(--tier-luxe-text); }
.batch-stat-val.cyan { color:var(--cyan-light); }
.batch-stat-lbl { color:var(--text-3); }

/* ── RESULTS VIEW ── */
.batch-results-recap { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--e-12); margin-bottom:var(--e-18); }
.batch-recap-card { }
.batch-recap-card.ok { border-color:rgba(99,214,176,.22); background:rgba(99,214,176,.04); }
.batch-recap-card.warn { border-color:rgba(240,176,85,.3); background:rgba(240,176,85,.05); }
.batch-recap-card.err { border-color:rgba(var(--th-danger-rgb),.22); background:rgba(var(--th-danger-rgb),.04); }
.batch-recap-val { font-size:var(--t-xl); font-weight:800; letter-spacing:-.04em; }
.batch-recap-val.g { color:var(--green); }
.batch-recap-val.o { color:var(--amber); }
.batch-recap-val.r { color:var(--red); }
.batch-recap-val.v { color:var(--violet-light); }
.batch-recap-val.c { color:var(--cyan-light); }
.batch-recap-lbl { font-size:var(--t-micro); color:var(--text-3); text-transform:uppercase; letter-spacing:var(--ls-ample); font-weight:var(--fw-fort); margin-top:var(--e-2); }

.batch-results-toolbar { display:flex; gap:var(--e-8); margin-bottom:var(--e-20); align-items:center; flex-wrap:wrap; }
.batch-export-btn { display:inline-flex; align-items:center; gap:var(--e-8); padding:var(--e-10) var(--e-16); border-radius: var(--r-md); border:1px solid var(--border-strong); background:var(--surface-2); color:var(--text-2); font-size:var(--t-base); font-weight:var(--fw-moyen); cursor:pointer; transition: var(--transi); }
.batch-export-btn:hover { border-color:var(--violet); color:var(--violet-light); background:rgba(var(--th-accent-rgb),.08); }
.batch-export-btn.primary { border-color:var(--tier-premium-glow); background:rgba(var(--th-accent-rgb),.1); color:var(--violet-light); }
.batch-btn-retry { display:inline-flex; align-items:center; gap:var(--e-8); padding:var(--e-10) var(--e-16); border-radius: var(--r-md); border:1px solid var(--danger-bord); background:var(--danger-fond); color:var(--red); font-size:var(--t-base); font-weight:var(--fw-moyen); cursor:pointer; transition: var(--transi); margin-left:auto; }

.batch-result-dress-row { background:var(--surface); border:1px solid var(--border); border-radius: var(--r-lg); margin-bottom:var(--e-10); overflow:hidden; }
.batch-result-dress-header { display:flex; align-items:center; gap:var(--e-12); padding:var(--e-12) var(--e-14); cursor:pointer; transition:background var(--t-moyen); }
.batch-result-dress-header:hover { background:var(--cok-bg-2); }
.batch-result-dress-thumb { width:36px; height:48px; border-radius: var(--r-sm); object-fit:cover; border:1px solid var(--border); flex-shrink:0; background:var(--surface-2); }
.batch-result-dress-name { font-size:var(--t-small); font-weight:var(--fw-fort); flex:1; }
.batch-result-dress-count { font-size:var(--t-meta); color:var(--text-2); }
.batch-result-badge { padding:var(--e-4) var(--e-10); border-radius: var(--r-pilule); font-size:var(--t-micro); font-weight:var(--fw-gras); }
.batch-result-badge.ok { background:rgba(99,214,176,.1); border:1px solid rgba(99,214,176,.25); color:var(--green); }
.batch-result-badge.err { background:rgba(var(--th-danger-rgb),.1); border:1px solid rgba(var(--th-danger-rgb),.25); color:var(--red); }
.batch-result-dress-posts { padding:var(--e-10) var(--e-14) var(--e-14); display:grid; grid-template-columns:repeat(auto-fill,minmax(130px,1fr)); gap:var(--e-8); border-top:1px solid var(--border); }
.batch-post-mini { border-radius: var(--r-sm); overflow:hidden; border:1px solid var(--border); }
.batch-post-mini-img { aspect-ratio:3/4; background:var(--surface-2); overflow:hidden; position:relative; }
.batch-post-mini-img img { width:100%; height:100%; object-fit:cover; cursor:zoom-in; }
.batch-post-mini-info { padding:var(--e-6) var(--e-8); background:var(--bg-2); }
.batch-post-mini-model { font-size:var(--t-micro); color:var(--text-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.batch-post-mini-price { font-size:var(--t-mini); font-weight:var(--fw-gras); color:var(--violet-light); margin-top:var(--e-2); }
.batch-post-mini.failed { border-color:rgba(var(--th-danger-rgb),.35); }
.batch-post-mini.flagged { border-color:rgba(240,176,85,.45); }
.batch-post-mini-error { aspect-ratio:3/4; background:var(--danger-fond); display:flex; align-items:center; justify-content:center; font-size:var(--t-mini); color:var(--red); padding:var(--e-8); text-align:center; }
.batch-post-flag-why { font-size:var(--t-micro); color:var(--amber); margin-top:var(--e-4); line-height:var(--lh-serre); max-height:2.6em; overflow:hidden; }
.batch-post-flag-acts { display:flex; gap:var(--e-6); margin-top:var(--e-6); }
.batch-flag-btn { flex:1; font-size:var(--t-micro); font-weight:var(--fw-fort); padding:var(--e-4) var(--e-6); border-radius: var(--r-sm); cursor:pointer; border:1px solid var(--border-strong); background:transparent; color:var(--text-2); }
.batch-flag-btn:hover { background:var(--bg-elevated); color:var(--text); }
.batch-flag-btn.ok { border-color:rgba(99,214,176,.4); color:var(--green); }
.batch-flag-btn.ok:hover { background:rgba(99,214,176,.12); }
.batch-flag-btn:disabled { opacity:.5; cursor:default; }

/* ── HISTORY VIEW ── */
.batch-history-topbar {
  display: flex; align-items: center;
  margin-bottom: var(--e-24);
}
.batch-history-topbar #batch-history-back { margin-right: var(--e-20); }
.batch-history-topbar .batch-page-title { margin: 0; }
.batch-history-row { display:flex; align-items:center; gap:var(--e-14); margin-bottom:var(--e-8); cursor:pointer; transition:border-color var(--t-moyen) }
.batch-history-row:hover { border-color:var(--violet-mid); }
.batch-history-name { font-size:var(--t-small); font-weight:var(--fw-fort); flex:1; }
.batch-history-meta { font-size:var(--t-meta); color:var(--text-2); }
.batch-history-badge { padding:var(--e-4) var(--e-10); border-radius: var(--r-pilule); font-size:var(--t-micro); font-weight:var(--fw-gras); }
.batch-history-badge.done { background:rgba(99,214,176,.1); border:1px solid rgba(99,214,176,.25); color:var(--green); }
.batch-history-badge.partial { background:rgba(240,176,85,.1); border:1px solid rgba(240,176,85,.25); color:var(--tier-luxe-text); }
.batch-history-actions { display:flex; gap:var(--e-6); }
.batch-history-empty { font-size:var(--t-small); color:var(--text-3); text-align:center; padding:var(--e-40); }

/* ── Batch extra ── */
.batch-pick-empty { font-size:var(--t-base); color:var(--text-3); text-align:center; padding:var(--e-24) var(--e-12); border:1.5px dashed var(--border); border-radius: var(--r-md); line-height:var(--lh-normal); }
.btn-danger { display:inline-flex; align-items:center; gap:var(--e-6); padding:var(--e-8) var(--e-14); border-radius: var(--r-md); border:1px solid var(--danger-bord); background:rgba(var(--th-danger-rgb),.08); color:var(--red); font-size:var(--t-base); font-weight:var(--fw-moyen); cursor:pointer; transition: var(--transi); }
.btn-danger:hover { background:rgba(var(--th-danger-rgb),.15); border-color:rgba(var(--th-danger-rgb),.5); }
.btn-xs { font-size:var(--t-micro); padding:var(--e-4) var(--e-8); border-radius: var(--r-sm); cursor:pointer; }
.btn-xs-danger { border:1px solid var(--danger-bord); background:transparent; color:var(--red); }
.btn-xs-danger:hover { background:rgba(var(--th-danger-rgb),.1); }

/* SKU loader */
.batch-sku-match-info { font-size:var(--t-meta); font-weight:var(--fw-fort); padding:var(--e-4) var(--e-10); border-radius: var(--r-pilule); }
.batch-sku-match-info.ok { background:rgba(99,214,176,.1); border:1px solid rgba(99,214,176,.25); color:var(--green); }
.batch-sku-match-info.partial { background:rgba(240,176,85,.1); border:1px solid rgba(240,176,85,.25); color:var(--tier-luxe-text); }
.batch-sku-match-info.hidden { display:none; }

/* Prog header controls */
.batch-prog-header { display:flex; align-items:flex-start; justify-content:space-between; margin-bottom:var(--e-18); gap:var(--e-14); }

/* ══════════════════════════════════════════════════════
   COLORIS / DÉCLINAISONS
   ══════════════════════════════════════════════════════ */

/* ── Dress detail panel — management UI ── */
.dress-coloris-section { margin-top: 0; }

/* ── Onglets coloris ── */
.dress-coloris-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-6);
  margin-bottom: var(--e-12);
  align-items: center;
}
.dress-coloris-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  padding: var(--e-6) var(--e-12);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  cursor: pointer;
  transition: var(--transi);
}
.dress-coloris-tab:not(.active):hover { border-color: var(--border-mid); color: var(--text); }
.dress-coloris-tab.active {
  border-color: var(--violet);
  background: rgba(236,72,153,.12);
  color: var(--text);
}
.dress-coloris-tab-dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px solid rgba(var(--th-voile),.2);
}
.dress-coloris-tab-add {
  padding: var(--e-6) var(--e-10);
  color: var(--text-3);
  opacity: .7;
}
.dress-coloris-tab-add:hover { opacity: 1; border-color: var(--violet-mid); color: var(--violet-light); }

/* Contenu onglet actif */
.dress-coloris-content {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-14);
  display: flex;
  flex-direction: column;
  gap: var(--e-10);
}
.dress-coloris-empty {
  color: var(--text-3);
  font-size: var(--t-base);
  text-align: center;
  padding: var(--e-16) 0;
}

/* Zone photo coloris */
.dress-coloris-photo-wrap { display: flex; flex-direction: column; gap: var(--e-6); }
.dress-coloris-photo-wrap > label { font-size: var(--t-meta); color: var(--text-muted); font-weight: var(--fw-moyen); }
.dress-coloris-photo-zone {
  width: 100px; height: 100px;
  border: 2px dashed var(--border);
  border-radius: var(--r-md);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--e-6);
  cursor: pointer;
  color: var(--text-3);
  font-size: var(--t-mini);
  overflow: hidden;
  transition: border-color var(--t-moyen);
}
.dress-coloris-photo-zone:hover { border-color: var(--violet-mid); color: var(--violet-light); }
.dress-coloris-thumb-lg { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Bouton supprimer coloris */
.dress-coloris-delete-btn {
  display: inline-flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-meta); color: var(--ose-text);
  background: none; border: 1px solid rgba(248,113,113,.3);
  border-radius: var(--r-sm); padding: var(--e-6) var(--e-12); cursor: pointer;
  transition: background var(--t-moyen);
  align-self: flex-start;
}
.dress-coloris-delete-btn:hover { background: rgba(248,113,113,.1); }

/* ── Library card — hover slideshow dots ── */
.lib-card-coloris-dots {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: var(--e-6);
  align-items: center;
  pointer-events: none;
  z-index: 3;
}

.lib-card-coloris-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid rgba(var(--th-voile), 0.6);
  flex-shrink: 0;
  transition: transform var(--t-moyen), border-color var(--t-moyen), border-width var(--t-moyen);
  box-shadow: 0 1px 3px rgba(var(--th-ombre),0.5);
}

.lib-card-coloris-dot.active {
  transform: scale(1.3);
  border: 2px solid var(--text);
}

/* ═══════════════════════════════════════════════════
   ONGLETS POST / REPOST
═══════════════════════════════════════════════════ */
.gen-tabs { display:flex; gap:var(--e-6); margin-bottom:var(--e-22); }
.gen-tab {
  display:flex; align-items:center; gap:var(--e-8);
  padding:var(--e-8) var(--e-20); border-radius: var(--r-md);
  border:1px solid var(--border); background:var(--surface);
  color:var(--text-2); font-size:var(--t-base); font-weight:var(--fw-fort);
  cursor:pointer; transition: var(--transi);
}
.gen-tab:not(.active):hover { border-color:var(--violet-mid); color:var(--text); }
.gen-tab.active { background:var(--violet); border-color:var(--violet); color: var(--sur-accent); }

/* Sélecteur Posts | Reposts dans l'onglet Batch */
.batch-mode-switch { display:inline-flex; gap:var(--e-4); margin-bottom:var(--e-18) }
/* En-tête onglet batch : Posts|Reposts à gauche, boutons Programmés/Historique à droite */
.batch-mount-header { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); flex-wrap:wrap; }
.batch-mount-header .batch-mode-switch { margin-bottom:0; }
.batch-mounted-actions { display:flex; gap:var(--e-8); margin-bottom:var(--e-18); }
.batch-mode-btn { display:inline-flex; align-items:center; gap:var(--e-6); font-size:var(--t-base); font-weight:var(--fw-fort);
  padding:var(--e-8) var(--e-16); border-radius: var(--r-sm); border:0; background:transparent; color:var(--text-2); cursor:pointer; }
.batch-mode-btn.active { background:var(--violet); color: var(--sur-accent); }
.batch-mode-soon { font-size:var(--t-micro); font-weight:var(--fw-gras); padding:var(--e-1) var(--e-6); border-radius: var(--r-pilule);
  background:rgba(240,176,85,.16); color:var(--amber); }

/* Sous-onglets Mannequin / Vues produit */
.gen-subtabs { display:flex; gap:var(--e-6); margin-bottom:var(--e-18); margin-top:calc(var(--e-6) * -1); }
.gen-subtab {
  display:flex; align-items:center; gap:var(--e-6);
  padding:var(--e-6) var(--e-16); border-radius: var(--r-sm);
  border:1px solid var(--border); background:transparent;
  color:var(--text-3); font-size:var(--t-base); font-weight:var(--fw-fort);
  cursor:pointer; transition: var(--transi);
}
.gen-subtab:not(.active):hover { border-color:var(--border-mid); color:var(--text-2); }
.gen-subtab.active { background:var(--violet-tint); border-color:var(--violet-mid); color:var(--violet-light); }

.upload-zone--full { width:100%; }

#pv-preview-dress {
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: var(--e-6);
}
#pv-preview-dress .preview-thumb {
  aspect-ratio: 3 / 4;
  border-radius: var(--r-sm);
}

/* ═══════════════════════════════════════════════════
   REPOST — variables bleu + delta minimal sur classes Post
═══════════════════════════════════════════════════ */

/* Le bleu du Repost — refonte 2026-07-30 : c'était un bleu ciel étranger à la palette
   (#6E8BFF), il devient le BLEU du couple violet-bleu. Il sert aussi aux barres de
   sous-onglets (.an-so), qui affichaient donc une troisième couleur sur l'écran. */
:root {
  --rp-blue: var(--cyan);
  --rp-blue-mid:   rgba(var(--th-second-rgb),.45);
  --rp-blue-tint:  rgba(var(--th-second-rgb),.14);
  --rp-aurora:     linear-gradient(120deg, #8B7FFF 0%, #7286FF 60%, #6E8BFF 100%);
}

/* Bouton pick robe/modèle en bleu au lieu de violet */
.rp-pick-btn { background:var(--rp-blue-tint) !important; color:var(--rp-blue) !important; }
.rp-pick-btn:hover { background:rgba(var(--th-second-rgb),.22) !important; }

/* Bouton generate bleu */
.rp-btn-generate {
  background: var(--rp-aurora) !important;
  box-shadow: 0 8px 32px -8px rgba(var(--th-second-rgb),.55) !important;
}
.rp-btn-generate:hover { box-shadow: 0 0 0 1px rgba(var(--th-second-rgb),.3), 0 18px 50px -14px rgba(var(--th-second-rgb),.6) !important; }

/* ══ LA BARRE D'ACTION DU REPOST ══════════════════════════════════════════════
   ⚠️⚠️ C'EST LE MÊME BLOC AUX TROIS MOMENTS. Amadou (05/09) a choisi cette mise en page :
   avant il porte le bouton, pendant il porte la jauge et le compte, après il se tait. Un
   bloc qui apparaît et un autre qui disparaît, c'est la page qui saute sous les yeux.
   ⚠️ LA DALLE A DISPARU : `.rp-action-section` était une carte à elle seule, teintée
   d'accent au milieu d'un écran vert — Amadou l'a montrée du doigt. La barre n'a plus ni
   fond ni cadre : c'est le BOUTON qu'on doit voir, pas son support. */
.rp-barre { display: flex; flex-direction: column; gap: var(--e-10); padding: 0 !important;
            background: none !important; border: 0 !important; box-shadow: none !important; }

.rp-progres {
  display: flex; flex-direction: column; gap: var(--e-8);
  padding: var(--e-12) var(--e-14);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
}
.rp-progres-tete { display: flex; align-items: baseline; justify-content: space-between; gap: var(--e-10); }
.rp-progres-quoi { font-size: var(--t-base); color: var(--text-2); }
.rp-progres-n { font-size: var(--t-base); color: var(--text); font-variant-numeric: tabular-nums; }
/* ⚠️ LE RAIL GARDE SA HAUTEUR MÊME À ZÉRO : une jauge qui naît à 0 px puis grandit fait
   sauter la barre à la première image. */
.rp-progres-rail {
  height: var(--e-4); border-radius: var(--r-pilule); overflow: hidden;
  background: rgba(var(--th-voile), 0.08);
}
.rp-progres-jauge {
  width: 0; height: 100%; border-radius: inherit;
  background: var(--violet);
  transition: width var(--t-moyen) var(--c-pose);
}

/* ══ LES TROIS ÉTAPES ══════════════════════════════════════════════════════════
   Elles remplacent `.upload-cols` sur ce seul écran : trois colonnes égales, un numéro
   par carte. ⚠️ `minmax(0, 1fr)` — le défaut d'une colonne de grille est `min-width:auto`,
   et un nom de produit long la pousse au-delà du conteneur. */
.rp-etapes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--e-14); }
.rp-etape-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--e-18); height: var(--e-18); margin-right: var(--e-8);
  border-radius: 50%; background: var(--violet-tint); color: var(--violet-light);
  font-size: var(--t-micro); line-height: var(--lh-un); font-variant-numeric: tabular-nums;
}
/* ⚠️⚠️ L'ÉTAPE QUI ATTEND SE DIT PAR SA FORME, jamais par une teinte : l'ambre et l'accent
   sont le même doré sur certains thèmes, et une carte ambrée se lirait « en alerte ». Le
   retrait dit « pas encore », et rien d'autre. */
.rp-etape--attente { opacity: 0.55; }
.rp-etape--attente .rp-etape-n { background: rgba(var(--th-voile), 0.08); color: var(--text-3); }

@media (max-width: 980px) { .rp-etapes { grid-template-columns: 1fr; } }
.rp-reset-btn { flex-shrink: 0; }

/* Nom + bouton changer sous le preview-grid */
.rp-dress-name-bar {
  display: flex; align-items: center; justify-content: space-between;
  padding-top: var(--e-6);
}
.rp-dress-name-label { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--text); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.rp-change-link { font-size:var(--t-meta); color:var(--rp-blue); background:none; border:none; cursor:pointer; flex-shrink:0; padding:0 var(--e-4); text-decoration:underline; }
.rp-change-link:hover { opacity:.75; }

/* Hint "choisissez d'abord une robe" */
.rp-packs-hint {
  display:flex; align-items:center; gap:var(--e-10);
  padding:var(--e-22) 0; color:var(--text-3); font-size:var(--t-base);
}

/* Liste des packs mannequins */
/* ══ LA CARTE D'UNE VENDEUSE, dans le Repost ═════════════════════════════════
   ⚠️ C'ÉTAIT UNE LIGNE DE TEXTE. La colonne s'appelait « Mannequin » et n'affichait que
   le nom technique de la fiche — pas de visage, pas de pseudo, aucune idée de ce que
   chacune apporte. Or c'est LE choix de cet écran. Amadou (15/08) : « ce n'est pas très
   beau visuellement ».
   Même vocabulaire que les cartes du Sourcing (photo ronde, nom en gras, pseudo en
   dessous) pour qu'on reconnaisse ses vendeuses d'un écran à l'autre. */
.rp-packs-list { display:flex; flex-direction:column; gap:var(--e-8); }
.rp-vend {
  display: flex; align-items: center; gap: var(--e-12);
  padding: var(--e-10);
  border-radius: var(--r-md);
  border: 1.5px solid var(--border);
  background: transparent;
  cursor: pointer; text-align: left; width: 100%;
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
.rp-vend:hover { border-color: var(--violet-soft); }
.rp-vend.selected { border-color: var(--violet); background: var(--tier-premium-bg); }
.rp-vend-ph {
  width: var(--e-40); height: var(--e-40); border-radius: 50%;
  overflow: hidden; flex-shrink: 0;
  background: var(--surface); border: 1px solid var(--border);
}
.rp-vend-ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rp-vend-txt { display: flex; flex-direction: column; gap: var(--e-2); flex: 1; min-width: 0; }
.rp-vend-txt b {
  font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rp-vend-txt i {
  font-style: normal; font-size: var(--t-mini); color: var(--text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rp-vend-etat { font-size: var(--t-mini); color: var(--text-3); flex-shrink: 0; }
.rp-vend.selected .rp-vend-etat { color: var(--violet-light); }

.rp-pack-item {
  display:flex; align-items:center; gap:var(--e-12);
  padding:var(--e-10) var(--e-12); border-radius: var(--r-md);
  border:1.5px solid var(--border); background:transparent;
  cursor:pointer; transition: var(--transi); width:100%; text-align:left;
}
.rp-pack-item:hover { border-color:var(--rp-blue-mid); background:var(--rp-blue-tint); }
.rp-pack-item.selected { border-color:var(--rp-blue); background:var(--rp-blue-tint); }
.rp-pack-thumb {
  width:44px; height:58px; object-fit:cover; flex-shrink:0;
  border-radius: var(--r-sm); border:1px solid var(--border); background:var(--surface-2);
}
.rp-pack-info { flex:1; display:flex; flex-direction:column; gap:var(--e-2); min-width:0; }
.rp-pack-name { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.rp-pack-meta { font-size:var(--t-mini); color:var(--text-3); }
.rp-pack-check {
  width:20px; height:20px; border-radius:50%; flex-shrink:0;
  border:1.5px solid var(--border-strong);
  display:flex; align-items:center; justify-content:center; transition: var(--transi);
}
.rp-pack-item.selected .rp-pack-check { background:var(--rp-blue); border-color:var(--rp-blue); }

.rp-empty { font-size:var(--t-base); color:var(--text-3); padding:var(--e-10) 0; }

/* Chips modèle compacts — remplacent les rp-pack-item */
.rp-packs-list { display:flex; flex-wrap:wrap; gap:var(--e-8); }
.rp-model-chip {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-6) var(--e-12) var(--e-6) var(--e-6);
  border: 1.5px solid var(--border);
  border-radius: var(--r-xl);
  background: transparent;
  cursor: pointer;
  font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-2);
  transition: var(--transi);
}
.rp-model-chip:hover { border-color: var(--violet-mid); color: var(--violet-mid); }
.rp-model-chip.selected { border-color: var(--violet); background: rgba(var(--th-accent-rgb),.12); color: var(--violet); }
.rp-model-chip-avatar {
  width: 22px; height: 22px; border-radius: 50%;
  object-fit: cover; flex-shrink: 0;
  border: 1px solid var(--border);
}

/* ── Modal Save Views ── */
.modal-save-views-card { max-width: 700px; width: 95%; }
.save-views-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--e-12);
  max-height: 55vh;
  overflow-y: auto;
}
.save-views-item {
  position: relative;
  border: 2px solid rgba(var(--th-voile),0.1);
  border-radius: var(--r-md);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--t-moyen);
}
.save-views-item.selected { border-color: #22c55e; }
.save-views-cb {
  position: absolute; top: 8px; left: 8px;
  width: 18px; height: 18px;
  accent-color: #22c55e;
  cursor: pointer;
  z-index: 2;
}
.save-views-label { display: block; cursor: pointer; }
.save-views-img { width: 100%; aspect-ratio: 3/4; object-fit: cover; display: block; }
.save-views-name {
  display: block;
  text-align: center;
  padding: var(--e-6);
  font-size: var(--t-base);
  color: var(--text-muted);
}

.save-views-options {
  display: flex;
  gap: var(--e-20);
  margin-top: var(--e-16);
  padding-top: var(--e-14);
  border-top: 1px solid rgba(var(--th-voile),0.07);
}
.save-views-opt-label {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  font-size: var(--t-small);
  color: var(--text-2);
  cursor: pointer;
  user-select: none;
}
.save-views-opt-label input[type="checkbox"] {
  width: 16px; height: 16px;
  accent-color: var(--violet-light);
  cursor: pointer;
}

/* ═══════════════════════════════════════════════════════
   MOBILE & TABLETTE — rend l'app utilisable sous 760px
   (avant : aucune adaptation, app inutilisable au téléphone)
   ═══════════════════════════════════════════════════════ */
.mobile-hamburger { display: none; }
.mobile-nav-backdrop { display: none; }

/* Accessibilité clavier : anneau de focus visible (était absent partout).
   ⚠️ Il était en `--violet-light` (#D6D0FF) — un lavande si pâle qu'il passe pour du
   BLANC sur notre fond sombre. C'était le « rectangle lumineux » de la barre de
   recherche (Amadou, 2026-07-31), et il apparaissait sur n'importe quel élément qui
   prend le focus. Il passe au violet du site. */
:focus-visible {
  outline: 2px solid var(--violet-soft);
  outline-offset: 2px;
}
/* Sur un champ de saisie, un rectangle qui l'entoure fait tache : le champ a déjà une
   bordure, on l'allume plutôt que d'en dessiner une deuxième par-dessus. */
input:focus-visible, textarea:focus-visible, .lib-search-input:focus-visible {
  outline: none;
}
.lib-search-wrap:focus-within, .hist-search-wrap:focus-within {
  border-color: var(--violet-soft);
  box-shadow: 0 0 0 3px var(--violet-tint);
}
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; } /* libre : couper le mouvement, ce n est pas une duree d interface */
}

@media (max-width: 760px) {
  .app-shell { padding: 0; gap: 0; height: 100vh; height: 100dvh; }

  /* Bouton hamburger flottant */
  .mobile-hamburger {
    display: flex; align-items: center; justify-content: center;
    position: fixed; top: 12px; left: 12px; z-index: 220;
    width: 44px; height: 44px; border-radius: var(--r-lg);
    background: rgba(var(--th-ombre),0.92); border: 1px solid var(--border);
    color: var(--text); cursor: pointer;
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  }

  /* Sidebar : overlay coulissant hors-écran par défaut */
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: 270px !important; min-width: 270px !important;
    height: 100%; border-radius: 0;
    transform: translateX(-100%);
    transition: transform var(--t-long) var(--c-pose);
    z-index: 240;
  }
  .sidebar.collapsed { width: 270px !important; min-width: 270px !important; } /* ignore le collapse desktop */
  .sidebar.collapsed .sidebar-logo-img { opacity: 1; pointer-events: auto; }
  .app-shell.mobile-nav-open .sidebar { transform: translateX(0); }

  /* Backdrop derrière la sidebar ouverte */
  .mobile-nav-backdrop { position: fixed; inset: 0; z-index: 230; background: rgba(var(--th-ombre),0.55); }
  .app-shell.mobile-nav-open .mobile-nav-backdrop { display: block; }

  /* Contenu pleine largeur */
  .app-content { border-radius: 0; border-left: none; border-right: none; }
  .app-section { padding: 64px var(--e-14) 90px; }
  .section-canvas { padding: 64px var(--e-14) 90px; }

  /* Topbar : laisser la place au hamburger */
  .topbar { padding-left: 64px; padding-right: var(--e-14); }
  .topbar-title { font-size: var(--t-body); }

  /* Grilles → 2 colonnes max */
  .lib-grid { grid-template-columns: repeat(2, minmax(0,1fr)) !important; }
  .hist-grid { grid-template-columns: repeat(2, minmax(0,1fr)) !important; }
  .dash-recent-grid { grid-template-columns: repeat(2, minmax(0,1fr)) !important; }
  .dash-kpis { grid-template-columns: repeat(2, 1fr) !important; }

  /* Layouts 2 colonnes → empilés */
  .listing-section { grid-template-columns: 1fr !important; }
  .dual-views-wrapper { flex-direction: column; }
    .atelier-two-col { grid-template-columns: 1fr !important; }

  /* Modales contenues dans l'écran (avant : débordaient, X inaccessible) */
  .modal-card { width: 92% !important; max-width: 92% !important; max-height: 88vh; overflow-y: auto; padding: var(--e-22); }
  .modal-overlay { padding: var(--e-12); }

  /* Cibles tactiles plus confortables */
  .nav-item { padding: var(--e-12) var(--e-14); }
}

@media (max-width: 480px) {
  .lib-grid, .hist-grid, .dash-recent-grid { grid-template-columns: 1fr !important; }
  .dash-kpis { grid-template-columns: 1fr !important; }
  .app-section, .section-canvas { padding-left: var(--e-10); padding-right: var(--e-10); }
  .topbar-subtitle { display: none; }
}

/* Sélecteur de coloris dans les modales d'import (choisir quels coloris importer / ajouter) */
.dress-import-colorpick { margin: var(--e-10) 0; }
.dress-import-colorpick-head { font-size: var(--t-meta); color: var(--text-3); margin-bottom: var(--e-6); }
.dress-import-colorpick-list {
  display: flex; flex-wrap: wrap; gap: var(--e-6) var(--e-16);
  max-height: 170px; overflow: auto;
  padding: var(--e-8) var(--e-10); border: 1px solid var(--text); border-radius: var(--r-sm); background: var(--text);
}
.dress-import-colorpick-item { display: inline-flex; align-items: center; gap: var(--e-6); font-size: var(--t-base); cursor: pointer; }
.dress-import-colorpick-item input { cursor: pointer; margin: 0; }

/* ═══════════════════════════════════════════════════════
   SECTION MESSAGES UNIFIÉE — onglets + conversations + à traiter
   ═══════════════════════════════════════════════════════ */

/* Canvas spécial : occupe toute la hauteur dispo, flex colonne */
.section-canvas--msg-unified {
  display: flex; flex-direction: column;
  padding: 0; height: 100%; overflow: hidden;
  max-width: none;   /* Messages exploite toute la largeur (layout 3 colonnes) */
}

/* ── Onglets ── */
.msg-tabs {
  display: flex; gap: 0; flex-shrink: 0;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.msg-tab {
  position: relative; padding: var(--e-12) var(--e-22);
  background: transparent; border: none;
  border-bottom: 2px solid transparent;
  color: var(--text-3); font-size: var(--t-base); font-weight: var(--fw-fort);
  cursor: pointer; white-space: nowrap;
  transition: color var(--t-moyen), border-color var(--t-moyen), background var(--t-moyen);
  margin-bottom: calc(var(--e-1) * -1); display: flex; align-items: center; gap: var(--e-8);
}
.msg-tab:not(.active):hover { color: var(--text); background: var(--surface-2); }
.msg-tab.active { color: var(--violet-soft); border-bottom-color: var(--violet); }
.msg-tab svg { opacity: .7; flex-shrink: 0; }
.msg-tab.active svg { opacity: 1; }
.msg-tab-badge {
  min-width: 18px; height: 18px; padding: 0 var(--e-6);
  background: var(--violet); color: var(--sur-accent);
  border-radius: var(--r-md); font-size: var(--t-micro); font-weight: var(--fw-gras);
  display: inline-flex; align-items: center; justify-content: center;
  line-height: var(--lh-un);
}
.msg-tab-badge.hidden { display: none; }

/* ── Panels (conteneurs des deux onglets) ── */
.msg-panel { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
.msg-panel.hidden { display: none; }

/* ── État vide conversations ── */
.msg-empty-state {
  flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--e-12); color: var(--text-3); text-align: center; padding: var(--e-40) var(--e-20);
}
.msg-empty-state p { margin: 0; font-size: var(--t-small); line-height: var(--lh-normal); }

/* ── Layout conversations : liste gauche + fil droite ── */
.msg-layout {
  display: flex; flex: 1; overflow: hidden; min-height: 0;
}
.msg-list {
  width: 340px; flex-shrink: 0; border-right: 1px solid var(--border);
  overflow-y: auto; display: flex; flex-direction: column;
}
.msg-thread {
  flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0;
}

/* ── Items de la liste ── */
.msg-item {
  display: flex; align-items: flex-start; gap: var(--e-10);
  padding: var(--e-12) var(--e-14); border: none; background: transparent;
  width: 100%; text-align: left; cursor: pointer;
  border-bottom: 1px solid var(--border);
  transition: background var(--t-bref);
}
.msg-item:hover { background: var(--surface-2); }
.msg-item.active { background: rgba(var(--th-accent-rgb),.08); }
.msg-item.unread .msg-item-name { font-weight: var(--fw-gras); color: var(--text); }
.msg-item-thumb {
  width: 38px; height: 38px; border-radius: var(--r-sm); object-fit: cover; flex-shrink: 0;
}
.msg-item-thumb--ph {
  background: var(--violet); color: var(--sur-accent);
  font-size: var(--t-small); font-weight: var(--fw-gras);
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm);
}
.msg-item-body { display: flex; flex-direction: column; gap: var(--e-2); flex: 1; min-width: 0; }
.msg-item-top  { display: flex; align-items: center; gap: var(--e-6); }
.msg-item-name { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.msg-item-acc  { font-size: var(--t-mini); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.msg-item-prev { font-size: var(--t-meta); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.msg-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--violet); flex-shrink: 0; }
.msg-list-empty { padding: var(--e-20); color: var(--text-3); font-size: var(--t-base); text-align: center; }

/* ── En-tête du fil ── */
.msg-thread-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-12) var(--e-16); border-bottom: 1px solid var(--border);
  background: var(--surface); flex-shrink: 0;
}
.msg-thread-head-l { display: flex; align-items: center; gap: var(--e-10); }
.msg-thread-head-r { display: flex; align-items: center; gap: var(--e-8); }
.msg-thread-avatar {
  width: 36px; height: 36px; border-radius: 50%; object-fit: cover; flex-shrink: 0;
}
.msg-thread-avatar--ph {
  background: var(--violet); color: var(--sur-accent); font-size: var(--t-small); font-weight: var(--fw-gras);
  display: flex; align-items: center; justify-content: center; border-radius: 50%;
}
.msg-thread-titles { display: flex; flex-direction: column; gap: var(--e-1); }
.msg-thread-name { font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--text); }
.msg-thread-acc  { font-size: var(--t-mini); color: var(--text-3); }

.msg-thread-item {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-8) var(--e-16); border-bottom: 1px solid var(--border);
  background: var(--surface-2); flex-shrink: 0; font-size: var(--t-base); color: var(--text-2);
}
.msg-thread-item img { width: 28px; height: 28px; border-radius: var(--r-sm); object-fit: cover; }

/* ── Boutons en-tête fil ── */
.msg-translate, .msg-conv-del {
  background: transparent; border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: var(--e-6) var(--e-10); font-size: var(--t-meta);
  color: var(--text-2); cursor: pointer; transition: background var(--t-bref), color var(--t-bref);
}
.msg-translate:hover, .msg-conv-del:hover { background: var(--surface-2); color: var(--text); }

/* ── Bulles de conversation ── */
.msg-bubbles {
  flex: 1; overflow-y: auto; padding: var(--e-14) var(--e-16);
  display: flex; flex-direction: column; gap: var(--e-8);
}
/* Barres de défilement bien visibles pour la liste des gens (gauche) et la conversation (droite) */
.msg-list, .msg-bubbles { scrollbar-width: thin; scrollbar-color: rgba(var(--th-voile),0.22) transparent; }
.msg-list::-webkit-scrollbar,
.msg-bubbles::-webkit-scrollbar { width: 10px; }
.msg-list::-webkit-scrollbar-thumb,
.msg-bubbles::-webkit-scrollbar-thumb { background: rgba(var(--th-voile),0.20); border-radius: var(--r-micro); }
.msg-list::-webkit-scrollbar-thumb:hover,
.msg-bubbles::-webkit-scrollbar-thumb:hover { background: rgba(var(--th-voile),0.34); }
.msg-bubble {
  max-width: min(72%, 560px); padding: var(--e-10) var(--e-14); border-radius: var(--r-lg);
  font-size: var(--t-small); line-height: var(--lh-normal); word-break: break-word;
  position: relative;
}
.msg-bubble.mine   { align-self: flex-end; background: rgba(var(--th-accent-rgb),.15); color: var(--text); border-bottom-right-radius: 4px; }
.msg-bubble.theirs { align-self: flex-start; background: var(--surface-2); color: var(--text); border-bottom-left-radius: 4px; }
.msg-bubble.pending { opacity: .65; }
.msg-bubble.error   { background: var(--danger-fond); }

/* ── Panneau « Taille de la commande » (saisie manuelle + conversation inline) ── */
.cmd-size-modal { max-width: 540px; width: 92vw; }
.cmd-size-warn {
  font-size: var(--t-base); line-height: var(--lh-normal); color: var(--amber);
  background: rgba(240,176,85,.12); border: 1px solid rgba(240,176,85,.28);
  border-radius: var(--r-md); padding: var(--e-10) var(--e-12); margin-bottom: var(--e-12);
}
.cmd-size-item {
  display: flex; align-items: center; gap: var(--e-10);
  padding-bottom: var(--e-10); margin-bottom: var(--e-10); border-bottom: 1px solid var(--border);
}
.cmd-size-thumb { width: 40px; height: 52px; object-fit: cover; border-radius: var(--r-sm); flex: 0 0 auto; }
.cmd-size-title { font-size: var(--t-base); color: var(--text); font-weight: var(--fw-fort); flex: 1 1 auto; line-height: var(--lh-serre); }
.cmd-size-vinted { font-size: var(--t-meta); color: var(--violet-soft); text-decoration: none; white-space: nowrap; flex: 0 0 auto; }
.cmd-size-vinted:hover { text-decoration: underline; }
.cmd-size-thread {
  display: flex; flex-direction: column; gap: var(--e-6);
  max-height: 240px; overflow-y: auto; padding: var(--e-4) var(--e-2);
  margin-bottom: var(--e-12); scrollbar-width: thin;
  /* Même raison que `.upload-zone .preview-grid` : sans elle, Chrome redessine la
     barre au gris du système et l'habillage global du fichier ne s'applique plus. */
  scrollbar-color: var(--bg-hover) transparent;

}
.cmd-size-empty { font-size: var(--t-base); color: var(--text-muted); text-align: center; padding: var(--e-18) var(--e-8); }
.cmd-size-bubble {
  max-width: 82%; padding: var(--e-8) var(--e-12); border-radius: var(--r-lg);
  font-size: var(--t-base); line-height: var(--lh-normal); word-break: break-word; color: var(--text);
}
.cmd-size-bubble.mine   { align-self: flex-end;   background: rgba(var(--th-accent-rgb),.15); border-bottom-right-radius: 4px; }
.cmd-size-bubble.theirs { align-self: flex-start; background: var(--bg-elevated);   border-bottom-left-radius: 4px; }
.cmd-size-who { display: block; font-size: var(--t-micro); color: var(--text-muted); margin-bottom: var(--e-2); font-weight: var(--fw-fort); }
.cmd-size-label { display: block; font-size: var(--t-base); color: var(--text-muted); margin-bottom: var(--e-6); }
.cmd-size-input { width: 100%; }
.msg-tag { font-size: var(--t-mini); color: var(--text-3); display: block; margin-top: var(--e-4); }
.msg-tag-tr { color: var(--violet-soft); }
.msg-act { color: var(--violet-soft); cursor: pointer; text-decoration: underline; }

.msg-thread-empty {
  flex: 1; display: flex; align-items: center; justify-content: center;
  color: var(--text-3); font-size: var(--t-base);
}

/* ── Zone de réponse ── */
.msg-reply {
  border-top: 1px solid var(--border); padding: var(--e-12) var(--e-14);
  display: flex; flex-direction: column; gap: var(--e-8); flex-shrink: 0;
  background: var(--surface);
}
.msg-reply-text { width: 100%; resize: none; color: var(--text);
  font: 13.5px/1.5 inherit; box-sizing: border-box;
  transition: border-color var(--t-moyen) }
.msg-reply-text:focus { outline: none; border-color: var(--violet); }
.msg-reply-actions { display: flex; gap: var(--e-8); justify-content: flex-end; }

/* ── Badge nav ── */
.nav-badge {
  position: absolute; top: -5px; right: -6px;
  min-width: 13px; height: 13px; padding: 0 var(--e-4);
  background: var(--violet); color: var(--sur-accent);
  border-radius: var(--r-pilule); font-size: var(--t-nano); font-weight: var(--fw-fort); line-height: var(--lh-un);
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 0 0 2px var(--bg-sidebar-solid);
  transform-origin: center;
  transition: opacity var(--t-bref) var(--c-sortie), transform var(--t-moyen) var(--c-pose);
}
/* ⚠️⚠️ ELLE SURGISSAIT PARCE QU'ELLE PASSAIT PAR `display`. Amadou (24/08) : « j'aimerais
   qu'elles apparaissent d'une façon douce et fluide, là c'est trop brusque ».
   `display` NE S'ANIME PAS : le navigateur n'a aucun état intermédiaire à dessiner, il
   affiche ou il n'affiche pas. Aucune animation n'a jamais pu s'y accrocher.
   La bulle reste donc TOUJOURS affichée — elle est en `position:absolute`, elle ne pousse
   rien — et c'est son opacité et sa taille qui la font venir et partir.
   ⚠️ `.hidden` du site est en `!important` ; entre deux `!important`, c'est la règle la
   plus précise qui gagne, et `.nav-badge.hidden` l'est davantage. D'où le `!important`
   ici : sans lui, `display:none` reprend la main et on revient au surgissement. */
.nav-badge.hidden {
  display: inline-flex !important;
  opacity: 0; transform: scale(.4); pointer-events: none;
}
/* Le chiffre qui CHANGE (5 → 6) se remplaçait sans rien : un battement, et on le voit. */
@keyframes navBadgeBat {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.28); }
  100% { transform: scale(1); }
}
.nav-badge.bat { animation: navBadgeBat var(--t-moyen) var(--c-pose); }

/* ═══════════════════ TOP DAY ═══════════════════ */
/* ── Hub VIVIER : sous-onglets Robes / Modèles / Photos de profil + rayon Modèles ── */
.src-subtabs { display: flex; gap: var(--e-6); margin: 0 0 var(--e-18); flex-wrap: wrap; border-bottom: 1px solid var(--border); padding-bottom: var(--e-12); }
.src-stab { border: 0; background: transparent; color: var(--text-2); font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-moyen); padding: var(--e-8) var(--e-14); border-radius: var(--r-md); cursor: pointer; white-space: nowrap; transition: var(--transi-vif); }
.src-stab:not(.on):hover { background: var(--surface-2, rgba(var(--th-voile),0.04)); color: var(--text); }
/* Onglet actif : fond VIOLET TRANSLUCIDE + texte clair (le motif de tout le logiciel).
   Avant, le fond prenait --violet-soft (#9A8DFF) — une couleur de TEXTE : on se retrouvait
   avec du #D6D0FF sur du #9A8DFF, donc un onglet sélectionné illisible. */
.src-stab.on { background: var(--tier-premium-bg); color: var(--violet-light); font-weight: var(--fw-fort); }
.src-robes-tools { display: flex; justify-content: flex-end; gap: var(--e-8); margin-bottom: var(--e-14); }
.src-mod-head { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); margin-bottom: var(--e-16); flex-wrap: wrap; }
.src-gab-filter { display: flex; gap: var(--e-6); flex-wrap: wrap; }
.src-gab { display: inline-flex; align-items: center; gap: var(--e-6); border: 1px solid var(--border-strong, rgba(var(--th-voile),0.12)); background: transparent; color: var(--text-2); font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-fort); padding: var(--e-6) var(--e-12); border-radius: var(--r-xl); cursor: pointer; transition: var(--transi-vif); }
.src-gab:not(.on):hover { color: var(--text); border-color: var(--violet-light, #b3a1ff); }
.src-gab.on { background: var(--tier-premium-bg); color: var(--violet-light); border-color: var(--violet-glow); }
.src-gab .n { font-size: var(--t-mini); opacity: .7; }
/* `.src-mod-grid` / `.src-mod-card` retirées le 2026-08-03 : le rayon emploie désormais
   `.lib-res-grille` / `.lib-res-v`, celles de la Bibliothèque. Plus rien ne les portait. */
.src-mod-gab { position: absolute; top: 7px; left: 7px; background: rgba(var(--th-ombre),0.62); color: var(--sur-sombre); font-size: var(--t-mini); font-weight: var(--fw-gras); padding: var(--e-2) var(--e-8); border-radius: var(--r-xl); backdrop-filter: blur(2px); }

/* ── Rayon Modèles / Profils ────────────────────────────────────────────────────
   ⚠️ Les cartes n'ont PAS de style ici : elles empruntent `.lib-res-grille` /
   `.lib-res-v` / `.coche` / `.choisi` à « Le stock » de la Bibliothèque, ainsi que
   `.hist-select-bar` et `.lib-bulk-btn` pour la barre de sélection. Amadou (03/08) :
   « il faut vraiment reprendre la bibliothèque, mais pour le Sourcing. » Deux versions
   antérieures avaient inventé leur propre vocabulaire (barre de boutons sous la photo,
   puis ronds au survol) — les deux sonnaient faux. On n'ajoute donc que le strict
   nécessaire : la pastille de taille et l'atténuation des photos pas encore jugées. */
.src-etat-filter { display: flex; gap: var(--e-6); flex-wrap: wrap; }
.src-mod-head .btn-ghost--sm:first-of-type { margin-left: auto; }
#src-gab-filter { margin: calc(var(--e-6) * -1) 0 var(--e-14); }

/* La taille se pose à DROITE : en mode sélection, la coche occupe le coin haut gauche. */
.lib-res-v .src-mod-gab { top: 7px; right: 7px; left: auto; }
/* Pas encore jugée par l'IA : on ne la présente pas comme un template valide. */
.lib-res-v.src-attente .ph { filter: grayscale(1); opacity: .55; }
.src-gab.vide { opacity: .45; }
.src-hint { font-size: var(--t-base); color: var(--text-3); }
.src-placeholder { text-align: center; color: var(--text-2); padding: 50px var(--e-20); font-size: var(--t-small); line-height: var(--lh-aere); }
.src-placeholder span { color: var(--text-3); font-size: var(--t-base); }

/* ── Rayon COMPTES GOOGLE (4e rayon du Sourcing) ───────────────────────────── */
#srcg-filter { margin: calc(var(--e-4) * -1) 0 var(--e-16); }
/* Pastille de stock sur les onglets du Sourcing — on voit ce qu'on a sans cliquer. */
.src-stab .n { margin-left: var(--e-8); padding: var(--e-1) var(--e-8); border-radius: var(--r-pilule); font-size: var(--t-mini); font-weight: var(--fw-fort);
  background: rgba(var(--th-voile),.09); color: var(--text-2); }
.src-stab.on .n { background: rgba(var(--th-voile),.16); color: var(--text); }
.srcg-form { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-14); margin-bottom: var(--e-16); }
.srcg-form label { display: block; font-size: var(--t-base); color: var(--text-2); }
.srcg-form textarea { width: 100%; margin-top: var(--e-8); padding: var(--e-10) var(--e-12); border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: ui-monospace, Menlo, monospace; font-size: var(--t-base); line-height: var(--lh-aere); resize: vertical; }
.srcg-form-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); margin-top: var(--e-10); flex-wrap: wrap; }
.srcg-lab { font-size: var(--t-base); color: var(--text-2); }

/* ── Panneau de dépôt : deux champs, un bouton, on remplit tranquillement ────── */
.srcg-panneau { width: 480px; }
.srcg-p-body { display: flex; flex-direction: column; gap: var(--e-14); }
.srcg-p-lab { display: flex; flex-direction: column; gap: var(--e-6); font-size: var(--t-base); color: var(--text-2); }
.srcg-p-lab input { width: 100%; padding: var(--e-12) var(--e-14); border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-family: inherit; font-size: var(--t-small); transition: border-color var(--t-bref); }
.srcg-p-lab input:focus { outline: none; border-color: var(--violet); }
.srcg-p-lab input::placeholder { color: var(--text-3); }
#srcg-p-mail { font-family: ui-monospace, Menlo, monospace; font-size: var(--t-base); }
.srcg-p-mdp { position: relative; display: block; }
.srcg-p-mdp input { padding-right: 42px; }
.srcg-p-oeil { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center; border: 0; background: transparent;
  color: var(--text-3); cursor: pointer; border-radius: var(--r-sm); }
.srcg-p-oeil:hover { color: var(--text); background: var(--surface-2); }
.srcg-p-erreur { padding: var(--e-8) var(--e-12); border-radius: var(--r-sm); font-size: var(--t-base);
  background: rgba(248,113,113,.10); border: 1px solid rgba(248,113,113,.30); color: var(--red); }
.srcg-p-add { display: flex; align-items: center; justify-content: center; gap: var(--e-8); width: 100%; padding: var(--e-12); }

/* Ce qui vient d'être déposé — la preuve immédiate, sous les champs */
.srcg-p-faits { border-top: 1px solid var(--border); padding-top: var(--e-12); }
.srcg-p-faits-tete { font-size: var(--t-meta); color: var(--green); font-weight: var(--fw-fort); margin-bottom: var(--e-8); }
.srcg-p-fait { display: flex; align-items: center; gap: var(--e-8); padding: var(--e-4) 0; }
.srcg-p-fait-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--green); flex: none; }
.srcg-p-fait-mail { font-family: ui-monospace, Menlo, monospace; font-size: var(--t-meta); color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Le collage d'une liste : replié, pour qui en a une */
.srcg-p-liste { margin-top: var(--e-18); border-top: 1px solid var(--border); padding-top: var(--e-14); }
.srcg-p-liste > summary { cursor: pointer; font-size: var(--t-base); color: var(--text-3); list-style: none; }
.srcg-p-liste > summary::-webkit-details-marker { display: none; }
.srcg-p-liste > summary::before { content: '+ '; font-weight: var(--fw-fort); }
.srcg-p-liste[open] > summary::before { content: '– '; }
.srcg-p-liste > summary:hover { color: var(--text); }
.srcg-p-liste .srcg-form { background: transparent; border: 0; padding: var(--e-12) 0 0; margin: 0; }
.srcg-panneau .modal-footer { margin-top: var(--e-20); padding-top: var(--e-16); border-top: 1px solid var(--border);
  align-items: center; justify-content: space-between; gap: var(--e-12); flex-wrap: wrap; }

/* Le bilan : UNE phrase qui dit ce que le serveur va comprendre, avant l'envoi.
   Vert quand tout est propre (le cas courant), ambre dès qu'il y a à relire. */
.srcg-bilan { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); flex-wrap: wrap;
  margin-top: var(--e-10); padding: var(--e-10) var(--e-14); border-radius: var(--r-md); font-size: var(--t-base); border: 1px solid transparent; }
.srcg-bilan.ok { background: rgba(52,211,153,.10); border-color: rgba(52,211,153,.28); color: var(--green); }
.srcg-bilan.attention { background: rgba(251,191,36,.10); border-color: rgba(251,191,36,.30); color: var(--amber); }
.srcg-bilan b { color: inherit; }
.srcg-voir { border: 0; background: transparent; color: inherit; font-family: inherit; font-size: var(--t-meta);
  font-weight: var(--fw-fort); text-decoration: underline; cursor: pointer; padding: 0; opacity: .9; }
.srcg-voir:hover { opacity: 1; }

/* Le détail : uniquement les lignes douteuses. Le mot de passe n'y figure JAMAIS —
   on nomme ce qui cloche, Amadou corrige dans sa liste. */
.srcg-detail { margin-top: var(--e-10); border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.srcg-detail-tete { padding: var(--e-8) var(--e-14); font-size: var(--t-meta); color: var(--text-3); background: var(--surface); border-bottom: 1px solid var(--border); }
.srcg-detail-row { display: flex; align-items: center; gap: var(--e-10); padding: var(--e-8) var(--e-14); font-size: var(--t-base); flex-wrap: wrap; }
.srcg-detail-row + .srcg-detail-row { border-top: 1px solid var(--border); }
.srcg-detail-no { font-size: var(--t-mini); color: var(--text-3); white-space: nowrap; }
.srcg-detail-mail { font-family: ui-monospace, Menlo, monospace; font-size: var(--t-meta); color: var(--text); }
.srcg-detail-pq { font-size: var(--t-meta); color: var(--amber); }
.srcg-grid { display: flex; flex-direction: column; gap: var(--e-8); }
.srcg-card { display: flex; align-items: center; gap: var(--e-10); padding: var(--e-10) var(--e-14); border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border); font-size: var(--t-base); }
.srcg-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.srcg-mail { font-family: ui-monospace, Menlo, monospace; font-size: var(--t-base); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.srcg-etat { font-size: var(--t-meta); font-weight: var(--fw-fort); white-space: nowrap; }
.srcg-note { font-size: var(--t-meta); color: var(--text-3); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.srcg-card .srcg-libre { margin-left: auto; flex: none; padding: var(--e-4) var(--e-10); border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid var(--border); background: transparent; color: var(--text-2); font-size: var(--t-mini); font-weight: var(--fw-fort); white-space: nowrap; }
.srcg-card .srcg-libre:hover { background: var(--rp-blue-tint); color: var(--rp-blue, var(--cyan)); border-color: rgba(var(--th-second-rgb),.4); }
.srcg-card .srcg-libre:disabled { opacity: .5; cursor: default; }
.srcg-card .srcg-del { margin-left: auto; flex: none; width: 24px; height: 24px; border-radius: var(--r-sm); border: none; cursor: pointer;
  background: transparent; color: var(--text-3); font-size: var(--t-body); line-height: var(--lh-un); }
.srcg-card .srcg-del:hover { background: rgba(248,113,113,.14); color: var(--red); }
.srcg-card .srcg-mail { min-width: 0; }
.srcg-card .srcg-cp { flex: none; min-width: 22px; height: 22px; padding: 0 var(--e-6); display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm); border: 1px solid var(--border); background: transparent; color: var(--text-2, #9aa7c2); cursor: pointer; font-size: var(--t-micro); }
.srcg-card .srcg-cp:hover { background: var(--rp-blue-tint); color: var(--rp-blue, var(--cyan)); border-color: rgba(var(--th-second-rgb),.4); }
.srcg-card .srcg-cp.ok { color: var(--green); border-color: rgba(52,211,153,.5); }
.srcg-card .srcg-mdp-dots { flex: none; font-family: ui-monospace, Menlo, monospace; font-size: var(--t-base); color: var(--text-2, #9aa7c2);
  letter-spacing: 1px; cursor: pointer; user-select: none; white-space: nowrap; }
.srcg-card .srcg-mdp-dots:hover { color: var(--text); }
.topday-empty { text-align: center; color: var(--text-3); padding: 60px var(--e-20); }
.topday-empty svg { display: none; }
.topday-empty p { margin: var(--e-4) 0; font-size: var(--t-small); color: var(--text-2); }
.topday-empty-sub { font-size: var(--t-base); color: var(--text-3); max-width: 440px; margin: var(--e-8) auto 0; line-height: var(--lh-aere); }
/* ════════ LE SOURCEUR (rayon Robes du Sourcing) ════════
   Il emprunte tout ce qu'il peut : le bandeau reprend la grille de `.src-stock`, les
   cartes de robes sont celles de `.topday-card`, les boutons et pastilles sont ceux de
   la bibliothèque (`.v-btn`, `.v-pastille`). Ce qui suit ne pose donc QUE la mise en
   page propre au bandeau — aucune couleur, aucune taille de texte inventée. */
.srcv { margin-bottom: var(--e-16); }
/* ══ LA RONDE — le Sourceur nouvelle manière ═══════════════════════════════════════
   ⚠️⚠️ LA CARTE EST CELLE DE LA BIBLIOTHÈQUE, classes comprises : `.lib-card`,
   `.lib-card-cover`, `.lib-card-coin`, `.lib-card-info`, `.lib-card-text`. Ce bloc ne
   contient donc QUE ce qui diffère — et c'est très peu, ce qui est le signe qu'on a bien
   emprunté. Amadou (03/09) : « inspire-toi des cards de la bibliothèque ».
   Les filtres et les deux sous-boutons du stock reprennent `.an-so` + `.an-so-n`.

   L'écran ne juge RIEN : le degré, la force et l'ordre viennent du serveur
   (velbo_ronde.py). Deux endroits qui jugeraient le même produit finiraient par diverger. */
/* ⚠️⚠️ UN BLOC VIDE GARDE SA MARGE, ET CREUSE. Depuis que la ligne des chiffres est
   partie, `#ronde` ne porte plus qu'une phrase d'alerte — c'est-à-dire RIEN la plupart du
   temps. Sa marge de 18 px, elle, restait : dix-huit pixels de vide au-dessus de la
   frise, sans un pixel de contenu pour les justifier. C'est le symétrique du défaut déjà
   consigné (« un élément vide n'a pas de hauteur ») : ici il n'a pas de hauteur mais il a
   toujours sa marge. */
.ronde { margin-bottom: var(--e-18); }
.ronde:empty { margin-bottom: 0; }
/* ⚠️ `center`, PLUS `baseline` (06/09). Le titre « Le Sourceur » est parti : il n'y a
   plus de grande lettre sur quoi caler une ligne de base, et le point de vie comme le
   bouton se retrouvaient pendus au bas des chiffres. */
/* ⚠️⚠️ L'EN-TÊTE À CHIFFRES A ÉTÉ RETIRÉ (07/09). Amadou : « la ligne métrique,
   honnêtement, tu peux la supprimer ». Partent `.ronde-tete`, `.ronde-pouls`, le point
   `.ronde-vie` et son battement. L'état de la machine n'a pas disparu avec eux : il est
   passé dans la FORME du symbole de marche, plus bas (`.ronde-ic--veille`). */
.ronde-souci { margin: var(--e-8) 0 0; font-size: var(--t-meta); color: var(--amber);
               line-height: var(--lh-serre); }
/* ⚠️ LE SQUELETTE N'EST PAS UN ORNEMENT : il occupe la place que les vraies cartes vont
   prendre. Sans lui, tout ce qui suit le panneau remonte pendant le chargement puis
   redescend — la page « saute », et ce saut se lit comme un défaut. Il respire doucement
   pour qu'on comprenne que ça travaille, sur `opacity` seule : c'est la seule propriété,
   avec `transform`, qui n'oblige pas le navigateur à repeindre. */
/* ⚠️⚠️⚠️ LA RESPIRATION NE DOIT JAMAIS PORTER SUR LA CARTE ELLE-MÊME. Amadou, 05/09,
   capture à l'appui : « il y a des endroits transparents qui après redeviennent
   visibles ». Ce n'était pas le fond de la carte — que j'avais rendu opaque au coup
   précédent, sans effet — c'était SON OPACITÉ : `rondeRespire` la faisait descendre à
   45 %. Un fond opaque à 45 % d'opacité laisse passer ce qu'il y a derrière, c'est-à-dire
   le décor de la page et ses étoiles, qui apparaissent puis s'effacent à chaque battement.
   ⚠️ LA RÈGLE : la respiration se joue sur ce qui est POSÉ SUR une surface opaque — les
   barres, un voile dans le cadre photo — jamais sur la surface elle-même. */
.ronde-sq { pointer-events: none; box-shadow: none; background: var(--th-carte); }
/* Le voile qui bat dans le cadre de la photo. Il est posé SUR un fond opaque : il ne
   révèle que la couleur de la carte, jamais la page. */
.ronde-sq .lib-card-cover::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  /* ⚠️ TRÈS FAIBLE, ET C'EST VOULU : le squelette doit avoir la MÊME teinte que les
     cartes qui vont le remplacer, sinon la grille s'assombrit d'un coup au moment de
     l'échange — un saut de plus là où on essaie justement d'en supprimer. */
  background: rgba(var(--th-voile), .022);
  animation: rondeRespire 1.6s var(--c-pose) infinite; }
.ronde-sq:hover { transform: none; border-color: var(--border); }
/* Le squelette aussi : sinon il montre le décor qui dérive, et sa respiration ferait
   scintiller ce qu'on voit à travers au lieu de battre sur une surface unie. */
.ronde-sq .lib-card-cover { background: var(--th-carte); }
.ronde-sq-i { display: block; padding: var(--e-10) var(--e-8) var(--e-4); }
.ronde-sq-b { display: block; height: var(--e-10); border-radius: var(--r-micro);
              background: rgba(var(--th-voile), .07);
              animation: rondeRespire 1.6s var(--c-pose) infinite; }
.ronde-sq-b--court { width: 62%; height: var(--e-8); margin-top: var(--e-6); }
/* Une tuile en attente : la carte n'a pas de photo, ses deux barres suffisent. */
/* Un onglet de filtre en attente : la hauteur d'un vrai `.an-so`, sans son texte. */
.ronde-sq-f { display: inline-block; width: var(--e-48); height: var(--e-32);
              border-radius: var(--r-pilule); background: rgba(var(--th-voile), .06); }
.ronde-sq-f:nth-child(2) { width: calc(var(--e-48) * 2.2); }
.ronde-sq-f:nth-child(3) { width: calc(var(--e-48) * 1.5); }
.ronde-sq-f:nth-child(4) { width: calc(var(--e-48) * 1.3); }
.ronde-sq-f:nth-child(5) { width: calc(var(--e-48) * 1.4); }
/* Le décalage suit ce qui respire maintenant : les barres et le voile, pas la carte. */
/* ⚠️⚠️ LES BLOCS DU HAUT NE SE DESSINENT PAS — Amadou, 05/09 : « les blocs au-dessus des
   cartes ne doivent pas apparaître, mais le contenu dedans si ». Les quatre tuiles et la
   barre de filtres en attente montraient de gros rectangles gris qui n'apprennent rien :
   au-dessus des cartes, ils occupent le premier regard pour ne rien dire.
   ⚠️ `visibility: hidden`, PAS `display: none` : la place doit rester réservée au
   millimètre, sinon la page saute quand les vraies tuiles arrivent — c'est exactement ce
   que ce squelette a été écrit pour éviter. On garde la place, on ne peint rien.
   ⚠️ Les cartes, elles, GARDENT leur squelette : c'est là qu'on regarde, et c'est le seul
   endroit où « ça travaille » vaut d'être montré. */
.ronde-squelette .ronde-sq-f { visibility: hidden; }

.ronde-squelette > .ronde-sq:nth-child(2n) .ronde-sq-b,
.ronde-squelette > .ronde-sq:nth-child(2n) .lib-card-cover::after { animation-delay: .18s; }
.ronde-squelette > .ronde-sq:nth-child(3n) .ronde-sq-b,
.ronde-squelette > .ronde-sq:nth-child(3n) .lib-card-cover::after { animation-delay: .36s; }
@keyframes rondeRespire { 0%, 100% { opacity: .45; } 50% { opacity: .85; } }

.ronde-hs { padding: var(--e-10) var(--e-12); border-radius: var(--r-sm);
            background: rgba(var(--th-accent-rgb), 0.10); border: 1px solid var(--border);
            font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-serre); }
/* La raison exacte, en petit : « le serveur ne répond pas » n'aide personne à chercher. */
.ronde-hs-d { display: inline-block; margin-top: var(--e-4); font-size: var(--t-meta);
              color: var(--text-3); }

/* ⚠️⚠️⚠️ LES CINQ TUILES ONT ÉTÉ RETIRÉES LE 06/09, PUIS LA LIGNE QUI LES REMPLAÇAIT
   LE 07/09. Elles occupaient tout le premier écran pour dire quatre choses qui ne se
   décident pas : combien d'annonces parcourues, de sources, de marques, de refus. Elles
   sont devenues une ligne, puis Amadou a tranché — « la ligne métrique, honnêtement, tu
   peux la supprimer ». Le cinquième chiffre, le seul qui décide, est le compteur de
   l'étage dans la frise. Le compteur à rouleaux qui les faisait défiler est parti avec.
   ⚠️ Ces quatre nombres restent lisibles dans le Journal : rien n'a été perdu, seulement
   déplacé là où on les lit quand on les cherche, au lieu de les subir en permanence. */

/* ⚠️ LE ROULEMENT DE CASINO EST PARTI AVEC LES CHIFFRES : plus rien à faire rouler. */

/* ⚠️ DEUX MENUS, PLUS DIX PASTILLES (04/09). Amadou : « il y a trop de boutons là ».
   Quinze boutons s'affichaient avant le premier produit : deux onglets de rayon, deux de
   stock, un interrupteur, cinq degrés, cinq tranches de prix. Les menus empruntent
   `.an-so` pour leur forme et `openBulkDropdown` pour leur ouverture. */
/* ⚠️ ELLE REMONTE. Amadou (07/09) : « remonte un peu cette ligne, au-dessus il y a de
   l'espace ». Il y en avait 68 px sous les onglets : 28 de canevas, 18 de marge d'un
   `#ronde` devenu vide, et 22 ici. Les deux premiers étaient de la place perdue ; celle-ci
   descend à 10 — « un peu », pas « collée ». */
.ronde-filtres { display: flex; gap: var(--e-8); align-items: center; flex-wrap: wrap;
                 margin: var(--e-10) 0 var(--e-16); }
/* ⚠️ LE NOMBRE DE PRODUITS EST MONTÉ EN TITRE. Il était ici, en petit, en bout de barre,
   et répétait la tuile « qui décollent » — deux endroits pour un fait, et ils divergeaient
   déjà (total brut contre nombre filtré). Le titre porte le filtré : c'est ce qu'on voit. */
/* ⚠️ LE BOUTON QUI APPELLE À L'AIDE. Une boutique qui attend une vérification n'est ni
   une panne ni un succès : c'est une demande, et elle s'ouvre d'un clic.
   ⚠️⚠️ PAS DE FOND AMBRE, ET C'EST MESURÉ. Dans plusieurs thèmes l'accent EST orange
   (#EE9B3F) là où l'ambre vaut #F0B055 : un fond ambré s'y lirait « sélectionné », pas
   « on t'attend ». La règle du projet le dit déjà — un état se distingue par la FORME,
   jamais par la teinte. On garde donc le patron de `.ronde-b-src--doute` : rien de
   plein, un filet, et c'est le TEXTE qui porte l'urgence. */
.ronde-b-verif { background: transparent; color: var(--amber);
                 box-shadow: inset 0 0 0 var(--e-1) var(--amber); border-color: transparent; }
.ronde-b-verif:hover { background: var(--surface-2); }

/* ══ LA VUE DU NAVIGATEUR DU SERVEUR ═════════════════════════════════════════════
   Amadou y voit l'écran du Chrome qui tourne sur le VPS, et il y clique. C'est par là
   qu'il donne la preuve humaine que SHEIN et Temu réclament — le puzzle à faire glisser,
   la connexion. Rien n'est résolu par la machine : on relaie son geste.
   ⚠️ L'IMAGE GARDE SA PROPORTION. L'écran du serveur fait 1280×900 ; si le cadre
   l'étirait, un clic arriverait décalé — et sur un puzzle, décalé veut dire raté. */
/* ⚠️⚠️ LA FENÊTRE DOIT TENIR DANS L'ÉCRAN, ET ELLE N'Y TENAIT PAS. Amadou (07/09) :
   « c'est coupé en haut, ça prend trop de place ». La cause : la carte n'avait qu'une
   LARGEUR, et l'image se dimensionnait sur elle (`width: 100%`). À 1180 px de large,
   une capture en 1280×900 s'affiche sur 795 px de haut — plus l'en-tête, la barre des
   boutiques et l'aide, la carte demandait 950 px. Sur un portable, le haut sortait par
   le plafond, en emportant le titre et la croix de fermeture.
   ⚠️ C'est donc la HAUTEUR qui commande maintenant : la carte se plafonne, l'image prend
   la place qui reste, et sa largeur en découle. Elle ne peut plus déborder. */
.nav-c { width: 1080px; max-width: 96vw; max-height: 92vh;
         display: flex; flex-direction: column; }
.nav-barre { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap;
             margin-bottom: var(--e-12); }
.nav-url { font-size: var(--t-mini); color: var(--text-3); margin-left: auto;
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
           max-width: 46%; }
/* ⚠️ `min-height: 0` : sans lui, un enfant de colonne `flex` refuse de descendre sous
   sa taille de contenu, et le plafond de la carte ne servirait à rien.
   ⚠️ L'image se cale sur la HAUTEUR disponible et garde son rapport ; `margin: auto` la
   centre au lieu de l'étirer. */
.nav-cadre { flex: 1 1 auto; min-height: 0; display: flex;
             background: var(--surface-2); border-radius: var(--r-md);
             overflow: hidden; }
.nav-img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto;
           margin: auto; cursor: crosshair;
           user-select: none; -webkit-user-drag: none; }
.nav-aide { margin: var(--e-10) 0 0; font-size: var(--t-meta); color: var(--text-3);
            line-height: var(--lh-serre); }
/* Le bouton de la vue reste discret : il n'est pas l'action principale du panneau. */

/* ══ LES TROIS ÉTAGES ════════════════════════════════════════════════════════════
   Amadou (06/09) : « fais 3 onglets pour les 3 étages de performance ». Ils remplacent
   le menu déroulant des degrés — un onglet dit où l'on est sans qu'on l'ouvre.
   ⚠️ RIEN N'EST DESSINÉ ICI : la forme, la couleur, l'état allumé et la pastille de
   compte viennent tous de `.an-so` / `.an-so.on` / `.an-so-n`, l'onglet du site. On ne
   pose que la rangée. Un onglet neuf aurait fait une quatrième famille de boutons sur
   un écran dont tout le travail du jour consistait à en retirer. */
/* ── LA FRISE DES ÉTAGES ──────────────────────────────────────────────────────
   Amadou (07/09) : « trop de boutons tue le bouton. Là au moins ça va être une frise. »
   Les trois boutons `.an-so` sont devenus le rail des Commandes — EMPRUNTÉ, pas
   redessiné : `.cmd-rail-fil`, `.cmd-e`, `.cmd-rail-a` sont à eux et le restent.

   ⚠️⚠️ TOUT CE QUE LA BRIQUE EXIGE ET QU'ELLE NE PORTE PAS ELLE-MÊME EST ICI.
   `--cmd-pas` n'est déclaré que sur `.cok-cmd-subtabs.cok-cmd-rail` : sans lui, la
   largeur du chemin devient `calc(3 * )`, une déclaration invalide jetée en silence —
   le parent se dimensionne alors sur le contenu et les libellés se coupent. C'est le
   défaut que la frise des Commandes a déjà payé une fois, en dur.
   ⚠️ On ne prend PAS `.cok-cmd-subtabs` avec : son `flex-basis: 100%` et son
   `margin-bottom` renverraient le menu des prix à la ligne suivante.

   ⚠️ 148 px et non 184 : le pas des Commandes est réglé pour « Bon à déposer » sur neuf
   étapes. Ici le plus long libellé est « Exceptionnel » (78 px mesurés en --t-meta) et
   il n'y en a que trois — à 184 le chemin s'étirait en guirlande, ce qu'Amadou avait
   déjà fait corriger sur les rails courts. 148 laisse l'air sans tendre le fil.
   ⚠️ Il reste au-dessus du seuil de 108 px du conteneur `etape`, en dessous duquel la
   frise efface les libellés. */
.ronde-rail { --cmd-pas: 148px; display: flex; align-items: stretch;
              gap: 0; flex-wrap: nowrap; min-width: 0; }
/* ⚠️ « LE TABLEAU » N'EST PLUS LA QUATRIÈME PLACE DU RAIL. Amadou l'a d'abord voulu
   dedans pour supprimer le décalage, puis à côté du symbole du navigateur. Les deux
   corrigent le même défaut : une pastille se cale au MILIEU de la hauteur alors que la
   frise aligne sur ses points, donc son texte tombait entre le nombre et le libellé.
   À droite, tout est déjà calé au milieu — le décalage n'a plus lieu d'être, et la frise
   ne porte que ce qui est vraiment sur son axe. */

/* ── LES TROIS SYMBOLES ───────────────────────────────────────────────────────
   Amadou (07/09) : « voir le navigateur, la mettre en veille, tu peux mettre un symbole
   pour gagner de la place. Pareil pour tous les prix. Et tu mets les trois à la ligne. »
   Trois carrés de 32 px là où trois boutons écrits en prenaient 320.
   ⚠️ Ils se centrent sur la hauteur de la frise : `align-self` et non `align-items`, pour
   ne pas décider à la place des autres enfants de la rangée. */
/* ⚠️ « À CÔTÉ », PAS « COLLÉ ». Amadou : « il ne colle pas aux trois boutons ». L'écart
   entre « Le tableau » et les trois symboles vaut le triple de celui qui les sépare
   entre eux : c'est ce qui les lit comme DEUX paquets — ce qu'on regarde d'un côté, la
   machine et le filtre de l'autre — au lieu d'une file de quatre boutons. */
.ronde-ics { display: flex; align-items: center; gap: var(--e-18);
             margin-left: auto; flex: 0 0 auto; align-self: center; }
.ronde-ics-g { display: flex; align-items: center; gap: var(--e-6); flex: 0 0 auto; }
.ronde-b-tab { flex: 0 0 auto; }
.ronde-ic { position: relative; width: 32px; height: 32px; padding: 0; flex: 0 0 auto;
            display: inline-flex; align-items: center; justify-content: center;
            border-radius: var(--r-sm); background: transparent; color: var(--text-2);
            border: 1px solid var(--border-strong, rgba(var(--th-voile), .12));
            cursor: pointer;
            transition: color var(--t-bref) var(--c-pose),
                        border-color var(--t-bref) var(--c-pose); }
.ronde-ic:hover { color: var(--text); border-color: var(--survol-bord); }
/* ⚠️⚠️ LA PASTILLE DIT CE QUE L'ICÔNE NE PEUT PAS ÉCRIRE. « Tous les prix » écrit disait
   QUEL filtre était posé ; un entonnoir seul, non — et on chercherait longtemps pourquoi
   la liste est courte. Elle n'apparaît que lorsqu'un plancher est actif. */
.ronde-ic-pt { position: absolute; top: -3px; right: -3px; width: 8px; height: 8px;
               border-radius: 50%; background: var(--accent);
               border: 2px solid var(--bg-panel-solid); }
.ronde-ic--pose { color: var(--violet-light); }
/* ⚠️⚠️⚠️ L'ÉTAT DE LA MACHINE VIT ICI DEPUIS QUE LA LIGNE DES CHIFFRES EST PARTIE. Le
   symbole change de FORME (deux barres / triangle) ET de teinte. Un écran qui ne dit plus
   quand la machine est arrêtée, c'est le défaut qui a laissé trois tableaux de bord
   afficher onze jours les chiffres d'ouvriers débranchés. */
.ronde-ic--veille { color: var(--amber); }
.ronde-ic--veille .ronde-ic-pt { background: var(--amber); }

/* ── QUAND UNE BOUTIQUE T'ATTEND ──────────────────────────────────────────────
   Amadou (07/09) : « quand je dois faire une action dans l'ordinateur, ça doit avoir un
   symbole orange sur le logo télévision ».
   ⚠️ C'EST LE SEUL BATTEMENT DE L'ÉCRAN, et c'est ce qui lui donne sa valeur : un écran
   où trois choses respirent n'attire l'œil sur aucune. Il s'arrête dès que la boutique
   est réglée, parce qu'un signal permanent n'est plus un signal. */
.ronde-ic--appel { color: var(--amber); border-color: rgba(var(--th-voile), .28); }
.ronde-ic-pt--appel { background: var(--amber); animation: rondeAppel 1.8s ease-in-out infinite; }
@keyframes rondeAppel { 0%, 100% { transform: scale(1); opacity: 1; }
                        50% { transform: scale(.72); opacity: .45; } }
/* ── OÙ SUIS-JE ───────────────────────────────────────────────────────────────
   Amadou (07/09) : « il faut que le bouton sur lequel je suis soit éclairé, sinon je ne
   sais pas sur quelle plateforme je suis ». Les trois boutons se ressemblaient trait pour
   trait ; il fallait lire l'adresse en petit, en bout de barre, pour le deviner.
   ⚠️ `.an-so.on` fait déjà ce travail partout dans le site : il est EMPRUNTÉ tel quel,
   on ne dessine pas un second « bouton allumé ». Rien à écrire ici.
   ⚠️ ET IL RESTE DISTINCT DE L'AMBRE : une boutique peut être celle qu'on REGARDE et
   celle qui ATTEND. Deux faits, deux signes — le fond allumé dit où l'on est, la pastille
   ambre dit où il faut aller. */

/* ── LE BOUTON QUI CHARGE ─────────────────────────────────────────────────────
   Amadou (07/09) : « le switch met trop de temps, le bouton doit être animé pour
   indiquer que ça charge ». Une navigation vers SHEIN prend plusieurs secondes pendant
   lesquelles l'écran montre encore la page PRÉCÉDENTE : le bouton avait l'air mort.
   ⚠️ UN TRAIT QUI COURT SOUS LE BOUTON, pas un texte qui change ni une roue. Le texte
   ferait sauter la largeur du bouton et décalerait les deux autres ; une roue ajouterait
   une forme de plus dans une barre qui n'en veut pas. Le trait vit SOUS le bouton, ne
   pousse rien, et s'arrête net quand la page est là. */
.nav-go--charge { position: relative; }
.nav-go--charge::after { content: ''; position: absolute; left: var(--e-8);
                         right: var(--e-8); bottom: 3px; height: 2px;
                         border-radius: var(--r-micro); background: var(--violet-light);
                         transform-origin: left;
                         animation: navCharge 1.1s ease-in-out infinite; }
@keyframes navCharge { 0% { transform: scaleX(0); opacity: .35; }
                       50% { transform: scaleX(1); opacity: 1; }
                       100% { transform: scaleX(0); opacity: .35;
                              transform-origin: right; } }
@media (prefers-reduced-motion: reduce) {
  .nav-go--charge::after { animation: none; transform: scaleX(1); opacity: .6; }
}
[data-anim="off"] .nav-go--charge::after { animation: none; transform: scaleX(1); }

/* Le mot d'attente, le temps de la première trame. Il disparaît avec elle. */
.nav-attente { margin: auto; padding: var(--e-40) 0; font-size: var(--t-meta);
               color: var(--text-3); }

/* Dans la fenêtre, la boutique concernée porte le même ambre : on la retrouve sans
   lire, et on sait qu'on est au bon endroit. */
/* ⚠️⚠️⚠️ LA BOULE NE DOIT RIEN DÉCALER (Amadou, 07/09) : « la boule orange doit
   [être] à l'extrémité droite du bouton, car le changement provoque un décalage ».
   Elle était en FLUX, avec `margin-left` : le bouton s'élargissait de 12 px quand elle
   apparaissait, et comme elle passe d'une boutique à l'autre, TOUTE la rangée sautait
   à chaque changement — visible sur ses deux captures, où « Temu » et « AliExpress »
   se déplacent d'un cran.
   Deux gestes, et il faut les DEUX :
     · la place est réservée sur TOUS les boutons, pas seulement celui qui l'affiche —
       sinon le décalage revient, simplement déplacé ;
     · la boule est posée en absolu à droite, donc elle ne pousse plus rien.
   ⚠️ ON CENTRE PAR `margin-top`, PAS PAR `transform: translateY(-50%)`. L'appui commun
   du site écrase `transform` au clic (spécificité 0,2,1) : la boule tomberait au fond
   du bouton à chaque appui. C'est déjà arrivé sur la flèche des niches. */
.nav-go { position: relative; padding-right: calc(var(--e-14) + 12px); }
.nav-go--appel { color: var(--amber); }
.nav-go--appel::after { content: ''; position: absolute; right: var(--e-10);
                        top: 50%; margin-top: -3px;
                        width: 6px; height: 6px; border-radius: 50%;
                        background: var(--amber);
                        animation: rondeAppel 1.8s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .ronde-ic-pt--appel, .nav-go--appel::after { animation: none; }
}
[data-anim="off"] .ronde-ic-pt--appel,
[data-anim="off"] .nav-go--appel::after { animation: none; }
/* ⚠️ PAS D'OVERRIDE SUR LA PASTILLE, et c'est une correction. J'avais écrit
   `background: var(--bg-panel-solid)` pour « masquer le trait », sans mesurer. Relevé
   dans le navigateur : ce jeton vaut #0E2630 quand le fond de page vaut #03090C — la
   pastille vide serait devenue un disque PLUS CLAIR que son entourage, l'inverse du but.
   Et les pleines n'étaient pas concernées : `.cmd-e-pt.plein` est déclarée plus bas à
   spécificité égale, donc elle gagnait. La frise garde son fond : elle avait raison. */

/* ⚠️⚠️ LE TEXTE DE LA CARTE PORTE L'ANALYSE. Le bouton « Analyse » a été retiré le
   06/09 ; la photo mène à Vinted, les flèches changent l'image, le texte était le seul
   geste encore libre. Il doit donc SE DONNER L'AIR cliquable — sans devenir un bouton,
   sinon on réintroduit ce qu'on vient d'enlever. Un survol qui éclaircit suffit. */
.ronde-c-tx { cursor: pointer; display: block;
              transition: color var(--t-bref) var(--c-pose); }
.ronde-c-tx:hover .ronde-c-nom { color: var(--violet-light); }
.ronde-c-tx:focus-visible { outline: var(--e-2) solid var(--violet);
                            outline-offset: var(--e-2); border-radius: var(--r-xs); }
/* La grille de la Bibliothèque, une maille plus large : ses cartes n'ont qu'une ligne de
   texte, les nôtres en ont trois plus un pied. */
.ronde-grille { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
/* ⚠️ LA MAIN DU CURSEUR MENTIRAIT. `.lib-card` la pose parce que ses cartes sont des
   liens ; celle-ci ne l'est plus — seuls les deux boutons agissent. Un curseur qui
   annonce un clic là où il ne se passe rien, c'est un bouton mort qui s'ignore. */
/* ⚠️⚠️⚠️ LA CARTE ELLE-MÊME EST UNE SURFACE PLEINE. Amadou, trois fois : « il y a des
   endroits plus opaques, d'autres plus foncés ». Mesuré : le cadre de la photo est
   opaque (`--th-carte`), mais la CARTE autour a un fond `rgba(0,0,0,0)` — totalement
   transparent — recouvert d'un dégradé en diagonale de 4,3 % à 1 % de blanc. Deux
   densités dans une même carte, et le décor de la page qui dérive sous la bordure : la
   couleur ne pouvait pas être unie.
   ⚠️ On pose donc le MÊME aplat que le cadre photo, en `background` court : le raccourci
   efface aussi le dégradé, sinon la bordure resterait plus claire que la photo qu'elle
   entoure. La carte devient une seule matière, du bord au pied.
   ⚠️ Scopé à `.ronde-c` : la Bibliothèque garde ses cartes telles quelles. */
.ronde-c { text-decoration: none; cursor: default; background: var(--th-carte); }
/* La photo, elle, ouvre l'annonce sur Vinted : là, la main ne ment pas. */
.ronde-c-cover[data-ph] { cursor: pointer; }
/* ⚠️ L'IMAGE SORT DU FLUX. Dans une colonne flex, une image en flux impose sa hauteur
   naturelle au conteneur et `aspect-ratio` est ignoré : les cartes d'une même rangée
   prennent alors des hauteurs différentes. Invisible dans la Bibliothèque, dont les
   photos sont déjà en 3/4 ; criant ici, où Vinted rend de tout. */
.ronde-c-cover > img { position: absolute; inset: 0; }
/* ⚠️⚠️⚠️ LE CADRE DE LA PHOTO DOIT ÊTRE OPAQUE. Amadou, 05/09 : « à l'intérieur des
   cartes la couleur saccade ; ce n'est pas une couleur unie, à certains endroits ça
   s'étend, ça se rallume ». Ce n'était pas un défaut de rendu : `.lib-card` et
   `.lib-card-cover` sont TRANSLUCIDES (rgba à 4 % et 5 %), et le décor de la page dérive
   dessous en permanence — deux couches de halos violets animées sur 260 s et 440 s,
   plus la poussière d'étoiles. Tant qu'une photo ne couvre pas le cadre, on regarde donc
   le décor bouger à travers, et une couleur qui bouge lentement se lit comme un défaut.
   ⚠️ Un fond OPAQUE, pris au thème (`--th-carte` existe dans les dix-sept), ferme la
   fenêtre : le cadre vide devient une surface unie, immobile, quel que soit le thème. */
.ronde-c-cover { background: var(--th-carte); }

/* ⚠️⚠️ LE DEGRÉ EST UN POINT, PAS UN MOT SUR LA PHOTO. La Bibliothèque a déjà tranché :
   « l'état écrit posait un voile sur la photo — vraiment moche, dit deux fois. Le point
   ne recouvre rien, le mot reste au SURVOL. » Même forme que `.lib-card-etat-pt`.
   Une seule teinte, quatre intensités : le degré se lit comme une gradation, pas comme
   quatre familles sans rapport. */
.ronde-pt { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto;
            background: currentColor; pointer-events: auto;
            box-shadow: 0 0 0 2.5px rgba(var(--th-ombre), .45); }
.ronde-pt--exceptionnel { color: var(--violet-light); }
.ronde-pt--fort         { color: var(--violet); }
.ronde-pt--bon          { color: var(--violet-soft); }
.ronde-pt--piste        { color: var(--text-3); }
/* Creux quand la certitude est faible : la forme dit « pas encore prouvé » sans un mot. */
.ronde-pt--flou { background: transparent; box-shadow: 0 0 0 2.5px rgba(var(--th-ombre), .45),
                                                       inset 0 0 0 2px currentColor; }
.ronde-pale { opacity: .62; }

/* Deux lignes de titre, pas une : un nom coupé au tiers ne dit plus quel produit c'est,
   et c'est la seule chose qu'on vient lire. La hauteur est réservée pour que les cartes
   d'une rangée s'alignent, avec ou sans deuxième ligne. */
/* ⚠️ LA VITESSE SE POSE EN PIED D'IMAGE. Amadou (03/09) : « ce n'est pas assez épuré,
   c'est entassé » — puis il a choisi cette forme entre trois. Elle supprime UNE LIGNE
   ENTIÈRE sous la photo en occupant une place qui était perdue, et laisse au titre toute
   la largeur de la carte.
   ⚠️ Ce n'est PAS la faute refusée deux fois (l'état écrit posait un voile sur la photo) :
   un chiffre calé en pied sur un dégradé se lit comme une légende, pas comme une étiquette
   collée en travers du produit.
   ⚠️ `--sur-sombre`, jamais `--text` : c'est le jeton du texte posé sur une plaque sombre
   par-dessus une photo. `--sur-accent` serait faux ici, il vaut #0B0C0E sur les thèmes
   sombres et disparaîtrait. */
.ronde-c-vitesse { position: absolute; left: 0; right: 0; bottom: 0; display: flex;
                   align-items: baseline; gap: var(--e-4);
                   padding: var(--e-22) var(--e-10) var(--e-8);
                   background: linear-gradient(transparent, rgba(var(--th-ombre), .74));
                   transition: opacity var(--d-fast) var(--c-pose); }
/* ⚠️⚠️⚠️ CE VOILE NOIR EXISTE POUR RENDRE LE CHIFFRE LISIBLE SUR UNE PHOTO. Tant que la
   photo n'est pas là, il n'a rien à assombrir : il devient une TACHE SOMBRE en dégradé
   sur un cadre uni. C'est la dernière des « parties plus foncées » qu'Amadou signale
   depuis quatre fois — et la seule que je n'avais pas regardée, parce que je cherchais
   une transparence alors que celle-ci est un aplat noir posé par nous.
   ⚠️ Il n'apparaît donc qu'avec la photo, et se fond avec elle. `:has` couvre les DEUX
   cas : la photo pas encore chargée, et l'annonce qui n'a aucune photo. */
.ronde-c-cover:not(:has(img.ronde-img-vue)) .ronde-c-vitesse { opacity: 0; }
/* ⚠️ L'ACCENT VA SUR LA VITESSE, ET SUR ELLE SEULE. C'est la raison d'être de la carte :
   tout le reste (le nom, la marque, l'âge) sert à identifier le produit, elle seule dit
   POURQUOI il est là. Amadou (04/09) : « le contenu des cards manque de couleurs
   d'accentuation, mets-en pour les choses principales ».
   ⚠️ Le prix reste blanc, délibérément : deux accents côte à côte ne s'accentuent plus,
   ils se neutralisent. Le prix est un fait qu'on lit après avoir été attiré, pas ce qui
   attire. */
.ronde-c-vitesse b { font-size: var(--t-title); font-weight: var(--fw-fort);
                     color: var(--violet-light); line-height: var(--lh-un);
                     font-variant-numeric: tabular-nums; }
.ronde-c-vitesse em { font-size: var(--t-mini); font-style: normal;
                      color: rgba(var(--th-voile), .78); }
/* Le prix ferme la bande, à l'autre bout : la vitesse à gauche, ce qu'il coûte à droite.
   Il est plus affirmé que l'unité « fav/h » — c'est un fait, pas une légende. */
.ronde-c-prix { margin-left: auto; font-size: var(--t-base); font-weight: var(--fw-fort);
                color: var(--sur-sombre); font-variant-numeric: tabular-nums;
                white-space: nowrap; }

/* Une seule ligne de titre : il a désormais toute la largeur, plus rien ne la lui dispute.
   Coupée proprement, elle en dit plus que deux lignes serrées à côté d'un nombre. */
.ronde-c-nom { display: block; font-size: var(--t-base); font-weight: var(--fw-moyen);
               color: var(--text); line-height: var(--lh-serre);
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ronde-c-sous { display: block; font-size: var(--t-meta); color: var(--text-3);
                line-height: var(--lh-serre); margin-top: var(--e-4);
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── LES DEUX GESTES DE LA CARTE ───────────────────────────────────────────────
   Amadou (04/09) : « deux boutons, un pour l'annonce Vinted, un pour son produit ».
   ⚠️ Ils REMPLACENT la pastille de marge : le bouton de source PORTE le multiple, donc
   rien n'est perdu et rien n'est ajouté. « Il y a trop de boutons là » vaut toujours.
   ⚠️ La carte n'est plus un lien : un bouton DANS un lien, c'est du HTML invalide et un
   clic qui part sur Vinted au lieu d'ouvrir le panneau — la famille du « bouton mort ». */
/* ⚠️⚠️ LA BANDE EST TOUJOURS LÀ, MÊME VIDE. Amadou (04/09) : « ça rentre sur les données
   de la carte, il faudrait un espace dédié, allonger un peu la carte ». Les boutons ne
   recouvrent donc plus la marque ni les favoris : ils ont leur propre étage, réservé au
   repos et rempli au survol. La carte grandit de trente pixels, une fois pour toutes —
   et RIEN ne bouge quand la souris arrive, ce qui est tout l'intérêt. */
/* ⚠️⚠️⚠️ CETTE RANGÉE PORTE DE L'INFORMATION, ELLE NE PEUT PAS ÊTRE UN SURVOL.
   Elle était en `opacity: 0`, révélée au seul `:hover`. Amadou (08/09), devant l'écran :
   « le bouton importer, où est-ce qu'on en est, rien n'a changé ». Le bouton était en
   ligne depuis la veille — invisible tant qu'on ne passait pas la souris sur la carte.
   Et ce n'est pas qu'un bouton qui se cachait : le multiple (« Source ×2,4 »), « Source
   introuvable », « Moins de 20 € de marge » vivent tous ici. Toute la lecture de l'écran
   était derrière un survol, donc absente des captures, et absente sur tout écran tactile
   — où le survol n'existe pas.
   ⚠️ LA PLACE ÉTAIT DÉJÀ PRISE : `min-height` et `padding-top` réservaient la hauteur au
   repos. Rendre la rangée visible ne déplace donc AUCUNE carte — seul le contenu paraît.
   La transition reste : elle sert encore au passage d'un état à l'autre. */
.ronde-actes { display: flex; gap: var(--e-6); margin-top: auto;
               padding-top: var(--e-8); min-height: 30px;
               transition: opacity var(--d-fast) var(--c-pose); }
.ronde-actes > * { text-align: center; }

/* ── FEUILLETER LES PHOTOS ─────────────────────────────────────────────────────
   ⚠️ Elles n'existent que s'il y a plusieurs photos : deux flèches sur une annonce
   qui n'en a qu'une, ce sont deux boutons morts. */
/* ⚠️ `z-index` : elles doivent passer DEVANT la photo ET devant la bande de vitesse,
   qui sont toutes deux en `absolute` dans le même cadre. Sans lui, elles se retrouvent
   derrière selon l'ordre du DOM — un bouton qu'on voit et qui ne se clique pas. */
/* ⚠️⚠️⚠️ 30 px SUR UNE PHOTO QUI OUVRE VINTED, C'EST UN PIÈGE. Amadou, 05/09 : « les
   flèches ne sont toujours pas cliquables, ça ouvre Vinted ». Un clic qui glisse d'un
   cheveu tombe sur la photo — et depuis que la photo mène à l'annonce, une quasi-touche
   coûte un onglet. On passe à 36 px, la taille des flèches de l'agrandissement, qui
   elles n'ont jamais posé de problème.
   ⚠️⚠️ ET ELLES PRENNENT LA MATIÈRE DU SITE au lieu d'un disque noir inventé : le fond
   des panneaux, le trait des panneaux, le flou des voiles. Amadou : « les deux éléments
   doivent être dans la DA du site ». Un disque noir opaque sur une palette violette,
   c'est une pièce rapportée — même bien contrastée. */
/* ⚠️⚠️⚠️ NE JAMAIS CENTRER UNE FLÈCHE AVEC `transform`. Amadou, 05/09 : « la flèche va
   encore en dessous, et quand j'appuie dessus une fois sur deux ça ouvre Vinted ». Les
   deux symptômes n'en font qu'UN. Le site pose à TOUT bouton un enfoncement au clic —
   `button:not(:disabled):active { transform: scale(var(--appui-echelle)) }`, plus haut
   dans ce fichier. Son poids (0,2,1) écrase le mien (0,2,0) : à l'appui, le
   `translateY(-50%)` DISPARAÎT et la flèche tombe de la moitié de sa hauteur. Elle n'est
   plus sous le curseur, et le clic suivant touche la photo — qui ouvre Vinted.
   ⚠️ On centre donc par `margin-top`, et `transform` reste LIBRE pour l'appui commun.
   C'est aussi mieux ainsi : le pop devient celui du site, pas un que j'aurais inventé. */
.ronde-fl { position: absolute; top: 50%; margin-top: calc(-1 * var(--e-18)); z-index: 3;
            width: 36px; height: 36px; display: flex; align-items: center;
            justify-content: center; cursor: pointer; padding: 0;
            border-radius: 50%; color: var(--text);
            background: rgba(var(--th-panneau-rgb), .88);
            border: 1px solid var(--border-strong);
            backdrop-filter: var(--voile-flou);
            -webkit-backdrop-filter: var(--voile-flou);
            box-shadow: 0 4px 14px -4px rgba(var(--th-ombre), .7);
            opacity: 0; transition: opacity var(--d-fast) var(--c-pose),
                                    transform var(--t-bref) var(--c-pose),
                                    background var(--d-fast) var(--c-pose),
                                    border-color var(--d-fast) var(--c-pose); }
/* ⚠️⚠️ LE DESSIN NE DOIT PAS RECEVOIR LE CLIC. Sans cette ligne, `e.target` est le
   `<polyline>` du chevron et non le bouton : le test qui distingue « flèche » de
   « photo » ne reconnaît plus rien, et changer de photo OUVRAIT le panneau d'analyse.
   Un bouton dont l'icône intercepte le clic est un bouton mort qui a l'air vivant. */
.ronde-fl > svg { pointer-events: none; }
/* La bande de vitesse, la pastille de degré et le compteur ne sont pas cliquables :
   le clic doit traverser jusqu'à la photo, qui ouvre l'analyse. */
.ronde-c-vitesse, .ronde-cpt, .ronde-c .lib-card-coin { pointer-events: none; }
/* ⚠️ PAS D'ARRIVÉE PAR LE BAS. Amadou : « les flèches qui vont vers le bas, je n'aime
   pas trop ». Elles apparaissent en fondu, sans glissement. Au clic, un petit pop —
   léger : un bouton qui rebondit trop attire l'œil à chaque photo qu'on feuillette. */
/* ⚠️ PAS DE RÈGLE D'APPUI ICI. Celle du site s'applique désormais telle quelle, et
   `scale(.965)` est déjà le « petit pop très léger » demandé. Une règle à moi ne ferait
   que rouvrir la porte au défaut ci-dessus. */
.ronde-fl--g { left: var(--e-6); }
.ronde-fl--d { right: var(--e-6); }
.ronde-c-cover:hover .ronde-fl { opacity: 1; }
.ronde-fl:hover { background: rgba(var(--th-panneau-rgb), .98);
                  border-color: var(--accent); color: var(--accent); }
/* ⚠️ EN HAUT À DROITE. À gauche, il tombait sur le coin où la Bibliothèque pose déjà
   ses marques — et Amadou l'a lu comme une pièce mal posée. Même matière que les
   flèches : c'est la même famille de commandes, elles doivent se ressembler. */
.ronde-cpt { position: absolute; top: var(--e-6); right: var(--e-6); z-index: 3;
             font-size: var(--t-mini); color: var(--text-2);
             background: rgba(var(--th-panneau-rgb), .88);
             border: 1px solid var(--border-strong);
             backdrop-filter: var(--voile-flou);
             -webkit-backdrop-filter: var(--voile-flou);
             border-radius: var(--r-pilule);
             padding: var(--e-1) var(--e-8); opacity: 0;
             transition: opacity var(--d-fast) var(--c-pose); }
.ronde-c-cover:hover .ronde-cpt { opacity: 1; }
.ronde-actes > * { flex: 1 1 0; justify-content: center; text-decoration: none;
                   min-width: 0; }
.ronde-b-src { background: rgba(var(--th-accent-rgb), .14); color: var(--accent);
               border-color: transparent; }
/* ⚠️ LE BOUTON QUI CHERCHE EST DISCRET, PAS ACCENTUÉ. L'accent violet dit « voici ce que
   tu cherchais » ; ici on propose un travail, on n'annonce pas un résultat. Deux accents
   côte à côte ne s'accentuent plus, ils se neutralisent — la leçon du prix et de la
   vitesse sur la carte. */
.ronde-b-cherche { background: var(--surface-2); color: var(--text-2);
                   border-color: transparent; }
.ronde-b-cherche:hover:not(:disabled) { background: var(--bg-hover); color: var(--text); }
.ronde-b-cherche:disabled { color: var(--text-3); cursor: default; }
.ronde-b-src:hover:not(:disabled) { background: rgba(var(--th-accent-rgb), .22);
                                    border-color: transparent; }
/* Creux quand le rapprochement demande vérification — mots, écart énorme, ou matière
   que l'image ne voit pas. Même bouton, moins d'assurance. */
.ronde-b-src--doute { background: transparent; color: var(--text-2);
                      box-shadow: inset 0 0 0 1px var(--border); }
/* Pas encore de source : la place est tenue, mais rien ne se clique. */
.ronde-b-vide { background: transparent; color: var(--text-3); border-color: transparent;
                cursor: default; opacity: .7; }

/* ── LA FENÊTRE : d'où vient ce produit ───────────────────────────────────────
   Elle emprunte `.modal-overlay` / `.modal-card`. Rien n'est redessiné ici : seules
   la largeur et la liste des produits sont propres au Sourceur. */
/* ⚠️ `position: relative` N'EST PAS DÉCORATIF : l'agrandissement est en `absolute`
   dans cette carte. Sans ça il se calerait sur la fenêtre entière et déborderait. */
.ronde-fen-c { width: 680px; max-width: 94vw; max-height: 88vh; position: relative;
               overflow-y: auto; display: flex; flex-direction: column; }

/* ══════════════════════════════════════════════════════════════════════════════
   LE TABLEAU DES GAGNANTS
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (07/09) : « un tableau analyse, mais général, de tous les produits ». Il
   remplace les cartes quand on l'ouvre — ce n'est pas un quatrième étage, c'est une
   autre façon de lire les mêmes trouvailles.

   ⚠️ AUCUNE COULEUR NEUVE. L'accent reste l'unique accent ; le vert, l'ambre et le
   gris ne disent qu'un ÉTAT (ça tourne / ça ralentit / c'est éteint) et ne servent
   nulle part ailleurs comme décoration. Le piège de l'ambre-qui-ressemble-à-l'accent
   est évité parce qu'il ne porte ici ni fond ni cadre : il ne teinte qu'un trait. */

/* Le filet qui sépare les trois étages du tableau : deux questions différentes. */
.rtab { display: flex; flex-direction: column; gap: var(--e-12); }
.rtab-barre { display: flex; align-items: flex-start; justify-content: space-between;
              gap: var(--e-16); flex-wrap: wrap; }
.rtab-quoi { margin: 0; font-size: var(--t-meta); color: var(--text-3);
             line-height: var(--lh-normal); max-width: 72ch; }
.rtab-quoi b { color: var(--text-2); font-weight: var(--fw-fort); }

/* ── LE BARÈME ────────────────────────────────────────────────────────────────
   Replié par défaut : quatre curseurs en permanence, c'est un réglage qui se met en
   travers d'une lecture. Le réglage se retient d'une fois sur l'autre. */
.rtab-bareme { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
               gap: var(--e-20); align-items: start;
               padding: var(--e-16) var(--e-18); border-radius: var(--r-md);
               background: var(--surface-2); }
.rtab-rg-c { display: flex; flex-direction: column; gap: var(--e-6); min-width: 0;
             cursor: pointer; }
.rtab-rg-h { display: flex; align-items: baseline; justify-content: space-between;
             gap: var(--e-8); }
.rtab-rg-n { font-size: var(--t-mini); font-weight: var(--fw-moyen); color: var(--text-2);
             letter-spacing: var(--ls-leger); text-transform: uppercase; }
.rtab-rg-v { font-size: var(--t-mini); color: var(--violet-light);
             font-variant-numeric: tabular-nums; }
.rtab-rg-d { font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-serre); }
.rtab-bareme .v-btn { grid-column: 1 / -1; justify-self: start; }

/* ⚠️ LE CURSEUR SE DESSINE DES DEUX CÔTÉS. `-webkit-` seul laisse Firefox rendre le
   curseur natif du système, qui n'a ni la couleur ni la taille du reste. */
.rtab-slider { -webkit-appearance: none; appearance: none; width: 100%; height: var(--e-16);
               background: transparent; cursor: pointer; margin: 0; }
.rtab-slider::-webkit-slider-runnable-track { height: 3px; border-radius: var(--r-micro);
               background: rgba(var(--th-voile), .18); }
.rtab-slider::-moz-range-track { height: 3px; border-radius: var(--r-micro);
               background: rgba(var(--th-voile), .18); }
.rtab-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 13px; height: 13px;
               border-radius: 50%; background: var(--accent); border: 0; margin-top: -5px; }
.rtab-slider::-moz-range-thumb { width: 13px; height: 13px; border-radius: 50%;
               background: var(--accent); border: 0; }
.rtab-slider:focus-visible { outline: 2px solid var(--violet-light); outline-offset: 3px;
               border-radius: var(--r-micro); }

/* ── LES LIGNES ───────────────────────────────────────────────────────────────
   ⚠️ LA GRILLE EST DÉCLARÉE UNE SEULE FOIS, pour l'en-tête ET pour les lignes : deux
   déclarations qui doivent rester d'accord finissent toujours par diverger. */
.rtab-defile { overflow-x: auto; }
.rtab-l { display: grid;
          grid-template-columns: 62px minmax(0, 1fr) 74px 118px 88px 46px 52px;
          gap: var(--e-12); align-items: center; min-width: 780px;
          padding: var(--e-8) var(--e-4); border-top: 1px solid var(--border); }
.rtab-tete { padding-top: 0; padding-bottom: var(--e-8); border-top: 0;
             border-bottom: 1px solid var(--border);
             font-size: var(--t-micro); color: var(--text-3);
             text-transform: uppercase; letter-spacing: var(--ls-leger); }
.rtab-r { text-align: right; }

/* L'en-tête classe. ⚠️ Un vrai `<button>`, pas un `<span>` cliquable : il doit
   s'atteindre au clavier et s'annoncer comme actionnable. */
.rtab-tri { background: transparent; border: 0; padding: 0; cursor: pointer;
            font: inherit; color: var(--text-3); text-transform: uppercase;
            letter-spacing: var(--ls-leger); text-align: inherit;
            transition: color var(--t-bref) var(--c-pose); }
.rtab-tri:hover { color: var(--text-2); }
.rtab-tri.on { color: var(--violet-light); }

.rtab-l[data-src] { cursor: pointer; transition: background var(--t-bref) var(--c-pose); }
.rtab-l[data-src]:hover { background: var(--surface-2); }
.rtab-l[data-src]:focus-visible { outline: 2px solid var(--violet-light);
                                  outline-offset: -2px; border-radius: var(--r-sm); }

/* Le rang, et le mouvement contre le classement à la vitesse seule. */
.rtab-rg { display: flex; align-items: baseline; gap: var(--e-4); }
.rtab-rg > b { font-size: var(--t-small); font-weight: var(--fw-moyen); color: var(--text);
               font-variant-numeric: tabular-nums; }
.rtab-mo { display: inline-flex; align-items: center; gap: var(--e-1); font-style: normal;
           font-size: var(--t-micro); font-variant-numeric: tabular-nums; }
.rtab-mo--h { color: var(--green); }
.rtab-mo--b { color: var(--text-3); }

.rtab-pr { display: flex; align-items: center; gap: var(--e-10); min-width: 0; }
.rtab-img { width: 36px; height: 36px; flex: 0 0 auto; border-radius: var(--r-sm);
            object-fit: cover; background: var(--surface-2); }
.rtab-pr-t { min-width: 0; }
.rtab-n { display: block; font-size: var(--t-meta); color: var(--text);
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rtab-s { display: block; font-size: var(--t-mini); color: var(--text-3);
          margin-top: var(--e-1); overflow: hidden; text-overflow: ellipsis;
          white-space: nowrap; }
/* Les deux mises en garde de la fiche, en un mot. ⚠️⚠️ NI CADRE NI FOND, et pour deux
   raisons. Un contour ambre se lit « sélectionné » dans les thèmes dont l'accent EST
   orange — le piège est déjà consigné. Et il n'existe pas de `--th-alerte-rgb` : le
   dessiner demandait d'écrire une couleur en dur, qui aurait menti dans 18 thèmes sur
   19. Le mot coloré suffit ; c'est la même retenue que le panneau de la source. */
.rtab-fl { display: inline-block; font-size: var(--t-nano); color: var(--amber);
           margin-left: var(--e-6); vertical-align: 1px;
           letter-spacing: var(--ls-leger); text-transform: uppercase; }
.rtab-fl--a { color: var(--red); }

.rtab-d { font-size: var(--t-base); color: var(--text); text-align: right;
          font-variant-numeric: tabular-nums; }
.rtab-d em, .rtab-ga em { font-style: normal; font-size: var(--t-micro);
                          color: var(--text-3); margin-left: var(--e-2); }

/* L'élan : la part du rythme que l'annonce tient ENCORE. La barre porte l'état, le
   chiffre le confirme — on lit la colonne sans lire un seul nombre. */
.rtab-el { display: flex; align-items: center; gap: var(--e-8); }
.rtab-el-b { flex: 1 1 auto; height: 4px; border-radius: var(--r-micro);
             background: rgba(var(--th-voile), .18); overflow: hidden; }
.rtab-el-b > i { display: block; height: 100%; border-radius: var(--r-micro); }
.rtab-el-v { font-size: var(--t-mini); width: 30px; text-align: right;
             font-variant-numeric: tabular-nums; }
.rtab-v--vif { background: var(--green); }
.rtab-v--tiede { background: var(--amber); }
.rtab-v--eteint { background: var(--text-3); }
.rtab-t--vif { color: var(--green); }
.rtab-t--tiede { color: var(--amber); }
.rtab-t--eteint { color: var(--text-3); }

.rtab-ga { font-size: var(--t-base); color: var(--text); text-align: right;
           font-variant-numeric: tabular-nums; }

/* La fiabilité : quatre pastilles, une par doute. Le détail est au survol — quatre
   phrases écrites dans la ligne l'auraient rendue illisible. */
.rtab-cf { display: flex; gap: var(--e-2); justify-content: flex-end; }
.rtab-cf > span { width: 6px; height: 6px; border-radius: 50%;
                  background: rgba(var(--th-voile), .20); }
.rtab-cf > span.on { background: var(--text-3); }
.rtab-cf > span.ko { background: var(--red); }

.rtab-no { font-size: var(--t-body); font-weight: var(--fw-moyen); color: var(--text);
           text-align: right; font-variant-numeric: tabular-nums; }
.rtab-no--tete { color: var(--violet-light); }

/* ⚠️ AUX DEUX LARGEURS. Le tableau garde sa largeur minimale et défile dans SON cadre :
   c'est la page qui ne doit jamais partir de côté. Le barème, lui, passe à deux
   colonnes plutôt que d'écraser quatre curseurs sous 80 px chacun. */
@media (max-width: 900px) {
  .rtab-bareme { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--e-16); }
}

/* ── LE BOUTON D'IMPORT ───────────────────────────────────────────────────────
   Amadou (07/09) : « un bouton relié au Sourceur — j'appuie, et le produit est importé
   dans la bibliothèque ».
   ⚠️ UNE ICÔNE, PAS UN SECOND BOUTON ÉCRIT : deux boutons de même largeur se
   disputeraient le regard sur une carte de 240 px. Il garde son nom au survol et pour un
   lecteur d'écran — une icône muette n'existe pas pour qui ne voit pas l'écran.
   ⚠️ Il PORTE UN COMPTEUR pendant la lecture (dix à trente secondes) : le texte change,
   donc la largeur aussi. `min-width` l'empêche de faire sauter la rangée à chaque
   seconde qui passe. */
.ronde-b-imp { flex: 0 0 auto; min-width: 42px; padding-left: var(--e-10);
               padding-right: var(--e-10); display: inline-flex; align-items: center;
               justify-content: center; }
/* Déjà en bibliothèque : vert, et plus cliquable. Sans cet état on importerait deux fois
   le même produit sans que rien ne le dise. */
.ronde-b-imp--faite { color: var(--green);
                      border-color: rgba(var(--th-voile), .16); opacity: 1; }
.ronde-b-imp--faite:disabled { cursor: default; }

/* ── LE PANNEAU DE LA SOURCE ──────────────────────────────────────────────────
   Amadou (07/09) : « vraiment moche, vraiment moche moche […] le meilleur widget
   possible, qui prend vraiment en compte la DA du site », puis « c'est trop chargé,
   épure le widget ».

   ⚠️ LE PRINCIPE, ET IL SE TIENT À LA RÈGLE PRÈS : UN SEUL PANNEAU, ET C'EST L'ESPACE
   QUI SÉPARE. Plus de fond, plus de bordure, plus de rayon autour de chaque chose —
   les caisses empilées étaient exactement ce qui faisait « chargé ». Il ne reste qu'UN
   élément coloré sur toute la fenêtre : le bouton de commande. Si une règle ajoute ici
   un `background` ou un `border` autour d'un bloc, elle défait le travail.

   ⚠️ ET UNE SEULE COLONNE. Les deux colonnes ne serraient rien : une carte ne peut pas
   tenir la hauteur d'une liste, alors elle creusait une bande vide de 600 px à droite.
   La largeur descend de 1250 à 960 px pour la même raison. */
/* ⚠️ 1080 px, et le même principe : l'air va dans les écarts. Le panneau ne porte que
   six blocs — les élargir sans les espacer aurait juste étiré la liste. */
.ronde-fen-c--src { width: 1080px; max-width: 94vw; gap: var(--e-24);
                    padding: var(--e-28) var(--e-32) var(--e-24); }
/* ⚠️⚠️⚠️ `flex-shrink: 0`, ET CE N'EST PAS UNE PRÉCAUTION. La carte est une colonne
   `flex` à hauteur plafonnée (88vh) : dès que le contenu déborde, flexbox ÉCRASE les
   enfants à hauteur définie. Mesuré : l'échelle des prix, haute de 40 px, était réduite
   à ZÉRO — ses étiquettes tombaient sur la première ligne de la liste et le rail
   n'existait plus. Rien ne le signalait : la règle `height: 40px` était bien là. */
.ronde-fen-c--src > * { flex: 0 0 auto; }

/* ⚠️ `.modal-header` pose `margin-bottom: var(--e-28)`. La carte est en `flex` avec un
   `gap` : la marge s'ADDITIONNE au gap et creuse un trou sous le titre seul. */
.rsrc-tete { align-items: flex-start; margin-bottom: 0; gap: var(--e-12); }
.rsrc-tete-tx { display: flex; align-items: baseline; gap: var(--e-10);
                flex-wrap: wrap; min-width: 0; }
.rsrc-tete-tx > b { font-size: var(--t-lead); font-weight: var(--fw-fort);
                    color: var(--text); line-height: var(--lh-titre); }
/* La voie, le prix Vinted et la vitesse tiennent ici : ils situent l'annonce sans
   réclamer la ligne de texte qu'ils occupaient au-dessus des produits. */
.rsrc-tete-tx > span { font-size: var(--t-meta); color: var(--text-3); }

/* Les mises en garde — matière invisible, écart invraisemblable, aucun fournisseur.
   ⚠️ SANS CADRE NI FOND. Un encadré ambre se lit « sélectionné » dans plusieurs thèmes,
   où l'accent EST orange : c'est le piège déjà consigné. Le TEXTE porte l'alerte. */
.rsrc-avert { margin: 0; font-size: var(--t-meta); color: var(--text-2);
              line-height: var(--lh-normal); }
.rsrc-avert b { color: var(--text); font-weight: var(--fw-fort); }

/* ── LA DÉCISION, EN UNE SEULE LIGNE ──────────────────────────────────────────
   Trois chiffres et deux signes. Le multiple sort de l'addition — il la brouillait —
   pour devenir un suffixe : c'est un indice, pas un terme de l'opération. */
.rsrc-deal { margin: 0; display: flex; align-items: baseline; gap: var(--e-10);
             flex-wrap: wrap; font-size: var(--t-small); color: var(--text-3);
             font-variant-numeric: tabular-nums; }
.rsrc-deal b { font-size: var(--t-xl); font-weight: var(--fw-fort); color: var(--text);
               line-height: var(--lh-titre); }
.rsrc-deal .rsrc-gain { color: var(--green); }
.rsrc-deal em { font-style: normal; font-size: var(--t-meta); color: var(--text-3); }

/* ── LE RETENU ────────────────────────────────────────────────────────────────
   Il n'a plus de cadre d'accent : c'est le SEUL produit montré en grand, et la taille
   suffit à dire lequel on prend. Le cadre doré, lui, le faisait lire « sélectionné ». */
/* ⚠️ `align-items: center` ET NON `flex-start` : le bloc n'a plus que deux lignes de
   texte depuis que la raison du conseil est au survol. Calé en haut, il laissait la photo
   dépasser de trente pixels sous elles. */
.rsrc-pick { display: flex; gap: var(--e-16); align-items: center; }

/* ── LA PHOTO SE FOND, ELLE NE CLAQUE PAS ────────────────────────────────────
   Amadou (07/09) : « quand j'appuie sur un autre fournisseur, la photo doit s'afficher
   avec une animation douce, agréable ».
   ⚠️⚠️ LE CADRE GARDE SA TAILLE, TOUJOURS. C'est lui qui tient la place pendant que
   l'image arrive : sans lui le bloc se replierait puis se rouvrirait à chaque clic, et
   tout ce qui est dessous sauterait de soixante-dix pixels. */
.rsrc-cad { position: relative; width: 96px; height: 96px; flex: 0 0 auto;
            border-radius: var(--r-md); overflow: hidden; background: var(--surface-2);
            cursor: zoom-in; }
.rsrc-cad .rsrc-pick-img { position: absolute; inset: 0; width: 100%; height: 100%;
            object-fit: cover; opacity: 0;
            transition: opacity var(--t-long) var(--c-pose); }
.rsrc-cad .rsrc-pick-img.rsrc-vu { opacity: 1; }
/* Le voile d'attente : il RESPIRE, il ne tourne pas. Un compteur qui tourne annonce une
   attente longue ; une photo, c'est une demi-seconde — on veut dire « ça vient », pas
   « installe-toi ». */
.rsrc-cad::after { content: ''; position: absolute; inset: 0; opacity: 0;
            pointer-events: none; transition: opacity var(--t-bref) var(--c-pose);
            background: linear-gradient(100deg, rgba(var(--th-voile), 0) 30%,
                        rgba(var(--th-voile), .09) 50%, rgba(var(--th-voile), 0) 70%);
            background-size: 220% 100%; }
.rsrc-cad.rsrc-att::after { opacity: 1; animation: rsrcVague 1.1s linear infinite; }
@keyframes rsrcVague { from { background-position: 120% 0; }
                       to { background-position: -120% 0; } }
/* Le texte s'estompe avec elle : les deux appartiennent au même produit, ils changent
   ensemble. Voir le nouveau nom à côté de l'ancienne photo, c'est le défaut qu'on corrige. */
.rsrc-pick-tx { transition: opacity var(--t-moyen) var(--c-pose); }
.rsrc-pick-tx.rsrc-att { opacity: .42; }
@media (prefers-reduced-motion: reduce) {
  .rsrc-cad::after { animation: none; }
  .rsrc-cad .rsrc-pick-img, .rsrc-pick-tx { transition: none; }
}
[data-anim="off"] .rsrc-cad::after { animation: none; }
[data-anim="off"] .rsrc-cad .rsrc-pick-img,
[data-anim="off"] .rsrc-pick-tx { transition: none; }

/* ── LA LISTE SE REPLIE ──────────────────────────────────────────────────────
   Amadou (07/09) : « il doit être dépliable, là il prend trop de place ». Dix lignes de
   fournisseurs occupaient les deux tiers du panneau alors qu'on vient y lire UN prix et
   UNE marge.
   ⚠️ `grid-template-rows: 0fr → 1fr` : une hauteur en `auto` ne s'anime pas, et une
   hauteur en pixels demanderait de la mesurer — donc de la remesurer chaque fois que la
   liste change de contenu. */
/* Le bouton et son tiroir forment UN bloc : sans lui, l'écart de la carte se glisserait
   entre la ligne et ce qu'elle ouvre — et le tiroir ne semblerait plus lui appartenir. */
.rsrc-tiroir-bloc { display: block; }
/* Le libellé cède la place à la fourchette plutôt que de la pousser dehors. */
.rsrc-plier-t { min-width: 0; overflow: hidden; text-overflow: ellipsis;
                white-space: nowrap; }
.rsrc-plier { display: flex; align-items: center; gap: var(--e-8); width: 100%;
              padding: var(--e-8) var(--e-6); background: transparent; border: 0;
              border-top: 1px solid var(--border); border-radius: var(--r-sm);
              color: var(--text-3); font: inherit; font-size: var(--t-meta);
              cursor: pointer; text-align: left;
              transition: background var(--t-bref) var(--c-pose),
                          color var(--t-bref) var(--c-pose); }
.rsrc-plier:hover { background: var(--surface-2); color: var(--text-2); }
.rsrc-plier:focus-visible { outline: var(--e-2) solid var(--violet-light);
                            outline-offset: calc(var(--e-2) * -1); }
.rsrc-plier > svg { flex: 0 0 auto; transition: transform var(--t-moyen) var(--c-pose); }
.rsrc-plier[aria-expanded="true"] > svg { transform: rotate(180deg); }
/* La fourchette se range à l'autre bout : on lit « 9 autres fournisseurs » d'un côté et
   « de tant à tant » de l'autre, sans que les deux se disputent le même endroit. */
.rsrc-plier-p { margin-left: auto; font-size: var(--t-mini);
                font-variant-numeric: tabular-nums; }
.rsrc-tiroir { display: grid; grid-template-rows: 0fr;
               transition: grid-template-rows var(--t-long) var(--c-pose); }
.rsrc-tiroir--ouv { grid-template-rows: 1fr; }
.rsrc-tiroir > div { overflow: hidden; min-height: 0; }
@media (prefers-reduced-motion: reduce) {
  .rsrc-tiroir { transition: none; } .rsrc-plier > svg { transition: none; }
}
[data-anim="off"] .rsrc-tiroir, [data-anim="off"] .rsrc-plier > svg { transition: none; }
.rsrc-pick-tx { min-width: 0; display: flex; flex-direction: column; gap: var(--e-4); }
/* Le seul mouvement de l'écran : le haut se renouvelle, il ne saute pas. */
.rsrc-chg { animation: rsrcEntre var(--t-moyen) var(--c-pose); }
@keyframes rsrcEntre { from { opacity: 0; transform: translateY(var(--e-4)); }
                       to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .rsrc-chg { animation: none; } }
[data-anim="off"] .rsrc-chg { animation: none; }
/* Les deux mises en garde : DEUX MOTS en bout de titre, la phrase au survol.
   ⚠️ L'alerte de doute naît VIDE et se remplit selon le fournisseur choisi : `:empty` la
   fait disparaître sans laisser son écart. */
.rsrc-tag { font-size: var(--t-nano); color: var(--amber); text-transform: uppercase;
            letter-spacing: var(--ls-leger); cursor: help; align-self: center; }
.rsrc-tag--doute { color: var(--red); }
.rsrc-tag:empty { display: none; }

.rsrc-pick-in { min-width: 0; display: flex; flex-direction: column; gap: var(--e-6); }
/* ⚠️ UNE SEULE LIGNE, coupée net. Un titre AliExpress fait quarante mots et n'en dit pas
   plus que les six premiers — deux lignes doublaient la hauteur du bloc pour du bruit. */
.rsrc-pick-n { font-size: var(--t-small); line-height: var(--lh-serre); color: var(--text);
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rsrc-pick-m { display: flex; align-items: center; gap: var(--e-12); flex-wrap: wrap;
               font-size: var(--t-meta); color: var(--text-3);
               font-variant-numeric: tabular-nums; }
.rsrc-pick-m > span { display: inline-flex; align-items: center; gap: var(--e-4); }
.rsrc-pick-m b { color: var(--text-2); font-weight: var(--fw-moyen); }
.rsrc-pick-p { margin: var(--e-2) 0 0; font-size: var(--t-meta); color: var(--text-2);
               line-height: var(--lh-normal); max-width: 62ch; }
/* L'entrepôt : le seul vert de l'écran, et il ne dit QUE ce qu'on sait. Une absence de
   pastille n'écrit rien — surtout pas « depuis la Chine ». */
.rsrc-ue { color: var(--green); }
/* ⚠️ `display: inline-block` N'EST PAS DÉCORATIF : la feuille pose `svg { display:
   block }` bien plus haut. Sans ça l'étoile prend sa propre ligne et double la hauteur
   de chaque ligne de la liste — mesuré à 27,5 px pour un texte de 11 px. */
.rsrc-et { display: inline-block; color: var(--accent); vertical-align: -1px;
           margin-right: var(--e-2); }

/* ── L'ÉCHELLE DES PRIX ───────────────────────────────────────────────────────
   Deux points pâles aux bords, la zone claire au milieu, le retenu en gros. Elle
   remplace les quarante mots qui expliquaient la médiane : on VOIT si le prix retenu
   est représentatif, ou s'il vient d'une queue de distribution. */
/* ⚠️ ELLE DOIT SE LIRE DE LOIN, SINON ELLE NE SERT À RIEN. Première mesure à
   `rgba(accent, .15)` : la zone et les points disparaissaient dans le panneau, et une
   échelle qu'on ne voit pas coûte sa place sans rien rendre. */
.rsrc-rail { position: relative; height: 40px; margin: var(--e-2) var(--e-12) 0; }
.rsrc-rail-l { position: absolute; left: 0; right: 0; top: 8px; height: 2px;
               background: rgba(var(--th-voile), .20); }
/* La zone couvre EXACTEMENT les cinq premiers résultats — ceux dont on prend la
   médiane. Ce n'est pas une décoration : c'est la fourchette qui a fixé le prix. */
.rsrc-rail-z { position: absolute; top: 4px; height: 10px; border-radius: var(--r-sm);
               background: rgba(var(--th-accent-rgb), .24); }
.rsrc-pt { position: absolute; top: 4px; width: 10px; height: 10px; border-radius: 50%;
           background: var(--text-2); transform: translateX(-5px); }
/* Hors de la fourchette qui a fixé le prix : présent, mais pas au même titre. */
.rsrc-pt--hors { opacity: .45; }
.rsrc-pt--pris { width: 16px; height: 16px; top: 1px; transform: translateX(-8px);
                 background: var(--accent);
                 box-shadow: 0 0 0 4px rgba(var(--th-accent-rgb), .16); }
.rsrc-lab { position: absolute; top: 21px; font-size: var(--t-mini); color: var(--text-3);
            transform: translateX(-50%); white-space: nowrap;
            font-variant-numeric: tabular-nums; }
.rsrc-lab--pris { color: var(--violet-light); }
/* ⚠️ AUX EXTRÉMITÉS, ON ANCRE AU LIEU DE CENTRER. `translateX(-50%)` sur un prix posé à
   0 % en sort la moitié : mesuré, « 5,65 € » débordait de 16 px à gauche du rail. */
.rsrc-lab--g { transform: none; }
.rsrc-lab--d { left: auto !important; right: 0; transform: none; }

/* ── LES AUTRES : LA BOUTIQUE EST UNE ÉTIQUETTE DE LIGNE ──────────────────────
   ⚠️ C'EST CE QUI A REMPLACÉ LE BLOC « LE MEILLEUR DE CHAQUE BOUTIQUE ». Il avait sa
   section, et redisait des produits déjà listés juste en dessous. Écrite devant chaque
   ligne, la boutique fait le même travail pour zéro pixel de plus.
   ⚠️ PAS DE VIGNETTE ICI, et c'est voulu : cinq images de 44 px alignées ramenaient la
   grille de la page dans une fenêtre qui doit se lire en une seconde. Le clic ouvre
   l'agrandissement, qui montre toutes les photos du fournisseur. */
/* ⚠️ PAS DE SECOND ASCENSEUR. La carte défile déjà (`max-height: 88vh`) : un
   `overflow` ici coupait la dernière ligne par le milieu, ce qui se lit comme un
   défaut d'affichage plutôt que comme « il y en a d'autres plus bas ». */
.rsrc-liste { display: flex; flex-direction: column; }
/* ⚠️⚠️ LES TROIS COLONNES SONT ALIGNÉES, ET LA TROISIÈME A UNE LARGEUR FIXE. Amadou
   (07/09) : « les 3 datas doivent être alignés ». En `auto`, la colonne des prix prenait
   la largeur de son contenu : « 6,42 € » et « 29,39 € » ne commençaient pas au même
   pixel, et la liste ondulait sur son bord droit. 78 px tiennent « 999,99 € ». */
.rsrc-l { display: grid; grid-template-columns: 76px minmax(0, 1fr) 78px;
          gap: var(--e-12); align-items: center; padding: var(--e-8) var(--e-2);
          border-top: 1px solid var(--border); cursor: zoom-in;
          transition: background var(--t-bref) var(--c-pose); }
.rsrc-l:hover { background: var(--surface-2); }
/* ⚠️ CHAQUE LIGNE EST UN VRAI `<button>` : elle choisit le fournisseur montré en haut.
   Un `<div>` cliquable ne s'atteint pas au clavier et ne s'annonce pas comme actionnable. */
.rsrc-l { width: 100%; background: transparent; border-left: 0; border-right: 0;
          border-bottom: 0; color: inherit; font: inherit; text-align: left; }
.rsrc-l:focus-visible { outline: var(--e-2) solid var(--violet-light);
                        outline-offset: calc(var(--e-2) * -1); border-radius: var(--r-sm); }
.rsrc-l-b { font-size: var(--t-mini); color: var(--text-3); letter-spacing: .04em;
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Le choisi s'éclaire — il ne sort pas de la liste. */
.rsrc-l.on .rsrc-l-b, .rsrc-l.on .rsrc-l-p { color: var(--violet-light); }
.rsrc-l.on .rsrc-l-n { color: var(--text); }
/* La mention du conseillé, pour y revenir après avoir regardé ailleurs. */
.rsrc-l-c { flex: 0 0 auto; font-size: var(--t-nano); text-transform: uppercase;
            letter-spacing: var(--ls-leger); color: var(--text-3); }
/* Le meilleur de sa boutique : une teinte, pas un cadre. */
.rsrc-l-b--pris { color: var(--violet-light); }
/* ⚠️ LE TITRE TRONQUE, PAS LA LIGNE. La mention « conseillé » vivait DANS le texte
   coupé à l'ellipse : elle disparaissait avec la fin du titre, donc exactement sur les
   lignes longues — celles où l'on cherche le plus à s'y retrouver. */
.rsrc-l-n { min-width: 0; display: flex; align-items: baseline; gap: var(--e-8);
            font-size: var(--t-meta); color: var(--text-2); }
.rsrc-l-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rsrc-l-m { display: block; font-size: var(--t-mini); color: var(--text-3);
            margin-top: var(--e-1); font-variant-numeric: tabular-nums; }
.rsrc-l-p { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text);
            font-variant-numeric: tabular-nums; text-align: right; }
/* Une boutique qui n'a rien rendu se dit AUSSI : sans cette ligne, son absence
   ressemble à un oubli et on ne sait pas si elle a seulement été interrogée. */
.rsrc-vide { font-size: var(--t-mini); color: var(--text-3);
             padding: var(--e-8) var(--e-2); border-top: 1px solid var(--border); }

/* ⚠️ LE BOUTON DE COMMANDE NE DOIT PAS DEMANDER UN DÉFILEMENT. Mesuré sur une fiche à
   dix fournisseurs : la carte fait 957 px pour 880 de haut — le seul geste de l'écran
   tombait 77 px sous le bord. Le pied colle au bas de la carte et laisse le reste
   défiler dessous ; le fond opaque est là pour ça, ce n'est pas une caisse de plus. */
.rsrc-pied { position: sticky; bottom: calc(var(--e-24) * -1); margin-top: 0;
             padding-top: var(--e-14); padding-bottom: var(--e-24);
             background: var(--bg-panel-solid);
             border-top: 1px solid var(--border); }
.rsrc-pied .v-btn { text-decoration: none; }

/* ⚠️ AUX DEUX LARGEURS. Sous 780 px la fenêtre occupe l'écran : l'étiquette de boutique
   se resserre et le retenu passe sous sa photo plutôt que de la comprimer. */
@media (max-width: 780px) {
  .ronde-fen-c--src { padding: var(--e-18) var(--e-16) var(--e-16); gap: var(--e-18); }
  .rsrc-l { grid-template-columns: 62px minmax(0, 1fr) 70px; gap: var(--e-8); }
  .rsrc-cad { width: 76px; height: 76px; }
  .rsrc-deal b { font-size: var(--t-title); }
}

/* ⚠️⚠️ L'AGRANDISSEMENT MAISON A ÉTÉ RETIRÉ (07/09). Amadou : « quand j'agrandis
   l'image, ça doit juste agrandir normalement, comme l'agrandissement classique ». Il
   posait une seconde fiche par-dessus la première — nom, note, avis, prix, flèches de
   photo ET de fournisseur — et l'image y était PLUS PETITE qu'avant le clic. Le panneau
   appelle maintenant `_rondeVisionneuse` et ses classes `.ronde-vis-*`, celles des photos
   de la Bibliothèque. On n'entretient pas deux agrandissements. */

/* ── L'ANALYSE D'UNE ANNONCE ───────────────────────────────────────────────────
   Quatre blocs, pas un de plus. Ce qui en est absent compte autant : ni vues (Vinted
   rend toujours zéro), ni historique minute par minute (on ne le garde pas). */
/* ── L'ANALYSE D'UNE ANNONCE : « LA LIGNE DE VIE » ─────────────────────────────
   Amadou a choisi ce dosage entre quatre : la photo devient un MÉDAILLON dans l'en-tête,
   et la courbe prend toute la largeur du panneau. Elle est le sujet ; la photo n'est
   qu'un rappel — pour la juger en grand il y a déjà les flèches de la carte et
   l'agrandissement du panneau des fournisseurs.
   ⚠️ Une photo étirée sur toute la hauteur écrasait le reste : c'est le défaut qu'il a
   signalé (« ça empiète sur le reste »). */
/* ⚠️ 760 px, PLUS 1250. La largeur d'avant était celle de la COURBE : elle avait besoin
   de place pour étaler 37 heures. Sans elle, il reste une note, une phrase et quatre
   barres — étalées sur 1250 px, les barres devenaient des fils de 600 px de long qu'on
   ne compare plus, et le panneau était surtout du vide. */
/* ⚠️ 880 px, et l'air va DANS les rangées, pas autour. Amadou (07/09) : « augmente la
   taille des deux panneaux, comme ça tu auras plus de place et ce sera plus épuré ».
   Élargir sans desserrer ne rend pas plus épuré : ça allonge les barres et laisse le
   texte au même endroit. Les cent vingt pixels gagnés sont donc rendus en marges
   intérieures et en écart entre les mesures. */
.ana-c { width: 880px; max-width: 94vw; padding: var(--e-32) var(--e-40); }
.ana-tete { display: flex; align-items: flex-start; gap: var(--e-12);
            margin-bottom: var(--e-10); }
.ana-med { width: 72px; flex: 0 0 auto; aspect-ratio: 3 / 4; border-radius: var(--r-sm); }
.ana-med { cursor: zoom-in; }
.ana-med > img { position: absolute; inset: 0; width: 100%; height: 100%;
                 object-fit: cover; }

/* ── LE FONDU AU CHANGEMENT D'IMAGE ────────────────────────────────────────────
   ⚠️ La même respiration que l'agrandissement : la photo s'efface légèrement et revient,
   au lieu de sauter d'un coup. Sur `opacity` et `transform` UNIQUEMENT — ce sont les
   deux seules propriétés qui ne repeignent pas la page, la leçon de la bulle de version. */
.ronde-c-cover > img, .ana-med > img, .ronde-vis-img {
  transition: opacity var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose); }
.ronde-img-part { opacity: 0; transform: scale(.985); }
/* ⚠️⚠️⚠️ SUR LES CARTES, LE FONDU N'EXISTAIT PAS. `.lib-card-cover img`, écrite PLUS BAS
   dans le fichier et de même poids, REMPLACE la transition par `transform` seul :
   l'opacité ne s'animait plus du tout et la photo sautait d'un coup. On la redit ici,
   plus précisément, pour les cartes du Sourcing.
   ⚠️ Le `transform` garde SA durée d'origine : c'est le zoom de survol des cartes
   (« l'image s'approche »), pas le fondu. Le retrait de `.ronde-img-part` ne se voit
   d'ailleurs pas ici — il faut survoler pour atteindre les flèches, et le survol
   agrandit déjà l'image. Ce qu'on voit, et c'est le geste demandé, c'est le fondu. */
.lib-card .ronde-c-cover > img {
  transition: opacity var(--d-fast) var(--c-pose), transform var(--t-long) var(--c-pose); }

/* ── L'ARRIVÉE DE L'ÉCRAN ET DES PHOTOS ────────────────────────────────────────
   ⚠️ `velbo-entree` est l'animation d'arrivée DU SITE — on l'emprunte, on n'en invente
   pas une autre. Elle porte sur la GRILLE, pas sur chaque carte : le site a déjà tranché
   qu'une seule surface glisse, sinon trois cents cartes qui montent chacune de quatre
   pixels font une vague, pas une arrivée. */
.ronde-grille.ronde-entree { animation: velbo-entree var(--t-moyen) var(--c-pose) both; }

/* ⚠️⚠️ ET LES PHOTOS QUI ARRIVENT APRÈS SE FONDENT. En `:not()`, jamais en posant
   `opacity: 1` sur la classe : une règle qui FORCE l'opacité à 1 écraserait celle du
   glissement ci-dessous (poids 0,2,1 contre 0,1,0) et le changement de photo ne se
   verrait plus. Ici, une fois l'image vue, plus aucune règle ne parle de son opacité. */
.ronde-c-cover > img:not(.ronde-img-vue) { opacity: 0; }

/* ── LE GLISSEMENT AU CHANGEMENT DE PHOTO ──────────────────────────────────────
   Amadou, 05/09 : « quand je change de photo, il doit y avoir une animation de slide,
   tout comme l'agrandissement ». La photo sortante part du côté OPPOSÉ à la flèche, la
   nouvelle arrive du côté de la flèche : le geste et l'image vont dans le même sens.

   ⚠️⚠️ DEUX PIÈGES, LES DEUX DÉJÀ PAYÉS ICI.
   1. `.lib-card:hover .lib-card-cover img { transform: scale(1.06) }` (poids 0,3,1)
      ÉCRASERAIT la translation (poids 0,1,0). On redit donc les deux états survolés,
      translation ET zoom composés — sinon rien ne bougerait, exactement comme le fondu
      qui n'existait pas sur les cartes.
   2. Le `transform` des cartes est lent (--t-long) : c'est le zoom de survol, « l'image
      s'approche ». Un glissement à cette vitesse serait mou. `.ronde-img-anim`, posée
      le temps du geste, lui rend une vitesse de geste. */
.ronde-img-anim { transition: opacity var(--d-fast) var(--c-pose),
                              transform var(--d-fast) var(--c-pose) !important; }
.ronde-img-muet { transition: none !important; }
.ronde-img-g { opacity: 0; transform: translateX(-14px); }
.ronde-img-d { opacity: 0; transform: translateX(14px); }
.lib-card:hover .ronde-c-cover > img.ronde-img-g,
.lib-card:focus-within .ronde-c-cover > img.ronde-img-g {
  transform: translateX(-14px) scale(1.06); }
.lib-card:hover .ronde-c-cover > img.ronde-img-d,
.lib-card:focus-within .ronde-c-cover > img.ronde-img-d {
  transform: translateX(14px) scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .ronde-img-g, .ronde-img-d { transform: none; }
}

/* ── LA VISIONNEUSE : un clic agrandit, les flèches vivent dedans ──────────────
   ⚠️ Sur un médaillon de 72 px, deux flèches de 30 px couvriraient la photo entière. */
/* ⚠️⚠️⚠️ ELLE PASSAIT DERRIÈRE LE PANNEAU D'ANALYSE. `.modal-overlay` monte à 200 ;
   cette règle la redescendait à 60, donc la photo s'agrandissait SOUS la fenêtre qui
   venait de l'ouvrir. Elle doit passer au-dessus de toutes les fenêtres du Sourcing. */
.ronde-vis { z-index: 260; }
.ronde-vis-c { position: relative; display: flex; flex-direction: column;
               align-items: center; gap: var(--e-10); }
.ronde-vis-scene { position: relative; display: flex; }
.ronde-vis-img { max-width: 76vw; max-height: 76vh; border-radius: var(--r-md);
                 background: var(--surface-2); }
/* Les flèches de la visionneuse sont plus grandes et toujours visibles : ici on
   feuillette, on ne survole pas. ⚠️ `.ronde-vis-fl--g` n'existait nulle part dans le
   code — une règle qui vise une classe que personne ne pose ne sert à rien. */
.ronde-vis-fl { opacity: 1; width: 38px; height: 38px; }
.ronde-vis .ronde-fl--g { left: var(--e-12); }
.ronde-vis .ronde-fl--d { right: var(--e-12); }
.ronde-vis-cpt { margin: 0; font-size: var(--t-meta); color: var(--text-2); }
.ronde-vis-x { position: absolute; top: calc(-1 * var(--e-16)); right: calc(-1 * var(--e-16));
               z-index: 2; }
.ana-titres { min-width: 0; }
.ana-t { font-size: var(--t-lead); font-weight: var(--fw-moyen); color: var(--text);
         line-height: var(--lh-serre); margin: 0; }
.ana-pill { font-size: var(--t-mini); color: var(--accent); margin-left: var(--e-8);
            background: rgba(var(--th-accent-rgb), .16); padding: var(--e-2) var(--e-8);
            border-radius: var(--r-pilule); vertical-align: 2px; }
.ana-meta { font-size: var(--t-meta); color: var(--text-3); margin: var(--e-6) 0 0; }

/* ── LA NOTE, ET LES QUATRE MESURES QUI LA JUSTIFIENT ─────────────────────────
   Amadou (07/09), devant quatre mises en page : « D ». L'analyse commence par le
   VERDICT ; les mesures existent pour l'expliquer, pas pour le remplacer.

   ⚠️ CE QUI EST PARTI AVEC : la courbe du rythme (`.ana-svg`, `.ana-cd`, son infobulle
   `.ana-tip`), les pastilles de prix (`.ana-chip*`), le fournisseur conseillé recopié en
   petit (`.ana-sim`, `.ana-st`) et l'encadré d'alerte (`.ana-al`). Six blocs pour dire
   ce que quatre barres disent mieux — c'est le « c'est bruyant » d'Amadou.
   ⚠️ La courbe était le seul dessin de l'écran : si elle manque un jour, c'est ce
   commentaire qu'il faut lire avant de la remettre. Elle disait la FORME de
   l'emballement ; l'élan dit la même chose en un chiffre, et se compare. */
.ana-note { display: flex; align-items: baseline; gap: var(--e-16); flex-wrap: wrap; }
/* ⚠️ Le seul grand chiffre de l'écran. Il porte l'accent parce qu'il EST la conclusion —
   rien d'autre ici ne doit le lui disputer. */
.ana-n { font-size: var(--t-2xl); font-weight: var(--fw-moyen); color: var(--violet-light);
         line-height: var(--lh-un); font-variant-numeric: tabular-nums; }
.ana-q { font-size: var(--t-small); color: var(--text-2); line-height: var(--lh-normal);
         max-width: 56ch; }

/* ⚠️ LE DÉTAIL DES QUATRE DOUTES EST AU SURVOL du bloc, pas sous la barre : quatre
   phrases écrites, c'est exactement le bruit qu'on vient de retirer. */
.ana-bs { display: flex; flex-direction: column; gap: var(--e-14); cursor: help; }
/* Les colonnes des bords s'élargissent avec le panneau : le mot et le chiffre ne se
   serrent plus contre le filet. */
.ana-b { display: grid; grid-template-columns: 96px minmax(0, 1fr) 96px;
         gap: var(--e-16); align-items: center; }
.ana-b-k { font-size: var(--t-meta); color: var(--text-3); }
/* Un filet, pas une jauge : il donne la proportion sans réclamer le regard. */
.ana-b-j { height: var(--e-4); border-radius: var(--r-micro); overflow: hidden;
           background: rgba(var(--th-voile), .12); }
.ana-b-j > i { display: block; height: 100%; border-radius: var(--r-micro);
               background: var(--accent); }
/* ⚠️ À DROITE, LA VALEUR RÉELLE — PAS LA NOTE SUR CENT. Une barre se lit d'un coup
   d'œil, mais c'est « 215 fav/h » qu'on retient et qu'on compare d'une annonce à l'autre. */
.ana-b-v { font-size: var(--t-base); font-weight: var(--fw-moyen); color: var(--text);
           text-align: right; font-variant-numeric: tabular-nums; }
.ana-bt { margin: 0 0 var(--e-10); font-size: var(--t-mini); color: var(--text-3);
          text-transform: uppercase; letter-spacing: .06em; }

/* Le pied de fenêtre : il avait perdu sa règle en cours de route, les boutons collaient
   au bloc au-dessus. */
.ronde-fen-pieds { margin-top: var(--e-14); padding-top: var(--e-12);
                   border-top: 1px solid var(--border); }
.ronde-fen-pieds .v-btn { text-decoration: none; }

.srcv-tete { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); flex-wrap: wrap; }
.srcv-titres { display: flex; align-items: center; gap: var(--e-10); }
.srcv-t { font-size: var(--t-lead); font-weight: var(--fw-fort); color: var(--text); line-height: var(--lh-titre); }
.srcv-actions { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap; }
.srcv-phrase { margin: var(--e-6) 0 0; font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-serre); }
.srcv-chiffres { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--e-12); margin-top: var(--e-16); }
.srcv-ch { display: flex; flex-direction: column; gap: var(--e-2); }
.srcv-ch .v { font-size: var(--t-title); font-weight: var(--fw-fort); color: var(--text);
              line-height: var(--lh-un); font-variant-numeric: tabular-nums; }
.srcv-ch .l { font-size: var(--t-base); color: var(--text-2); margin-top: var(--e-4); }
.srcv-ch .s { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-serre); }
/* Une tournée qui échoue le DIT. Un sourceur muet passe pour un sourceur qui n'a rien
   trouvé — c'est la confusion que tout cet écran cherche à empêcher. */
.srcv-hs { margin-top: var(--e-12); padding: var(--e-10) var(--e-12); border-radius: var(--r-sm);
           background: rgba(var(--th-accent-rgb), 0.10); border: 1px solid var(--border);
           font-size: var(--t-base); color: var(--text-2); }

.srcv-reglages { margin-bottom: var(--e-16); padding: var(--e-16) var(--e-18);
                 background: var(--cok-card); border: 1px solid var(--cok-border); border-radius: var(--r-lg); }
.srcv-aide { margin: 0 0 var(--e-12); font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-aere); }
.srcv-ajout { display: flex; gap: var(--e-8); flex-wrap: wrap; }
.srcv-input { flex: 1 1 260px; min-width: 0; font: inherit; font-size: var(--t-base); color: var(--text);
              background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm);
              padding: var(--e-8) var(--e-10); }
.srcv-input--court { flex: 0 1 140px; }
.srcv-liens { display: flex; flex-direction: column; gap: var(--e-8); margin-top: var(--e-14); }
.srcv-lien { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap;
             padding: var(--e-10) var(--e-12); background: var(--surface-2);
             border: 1px solid var(--border); border-radius: var(--r-sm); }
.srcv-lien.off { opacity: .55; }
.srcv-lien-nom { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); }
/* L'adresse peut être très longue : elle cède la place aux boutons au lieu de les pousser
   hors de l'écran (vérifié à 1440 px et à 900 px). */
.srcv-lien-url { flex: 1 1 200px; min-width: 0; font-size: var(--t-meta); color: var(--text-3);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Une tuile qui porte un MOT (« il y a 3 h ») et non un nombre : à la taille des
   chiffres, elle criait plus fort qu'eux — mesuré à 900 px, où elle passe seule à la
   ligne. */
.srcv-ch--texte .v { font-size: var(--t-body); font-weight: var(--fw-moyen); }
/* Les deux boutons d'une recherche ne se séparent jamais : avec un nom long, « Retirer »
   descendait seul à la ligne suivante. */
.srcv-lien-actions { display: flex; align-items: center; gap: var(--e-8); flex: 0 0 auto; margin-left: auto; }
.srcv-vide-liens { margin-top: var(--e-14); font-size: var(--t-base); color: var(--text-3); }
/* ⚠️ `.topday-date` porte `text-transform: capitalize` — juste pour une date seule
   (« 18 Août »), faux dès qu'on ajoute des mots : « 3 Ventes Constatées ». L'intertitre
   du sourceur reprend donc son allure mais pas sa transformation. */
/* ⚠️ `.topday-date.srcv-list-date` et pas `.srcv-list-date` seul : à poids égal, c'est
   la règle écrite EN DERNIER qui gagne — et ce bloc-ci est déclaré AVANT `.topday-date`.
   La classe seule ne changeait donc rien, en silence. */
.topday-date.srcv-list-date { text-transform: none; }
.srcv-vide { padding: var(--e-32) var(--e-20); text-align: center; }
.srcv-vide p { margin: var(--e-4) 0; font-size: var(--t-small); color: var(--text-2); }
.srcv-vide-sub { max-width: 460px; margin: var(--e-8) auto 0 !important;
                 font-size: var(--t-base) !important; color: var(--text-3) !important; line-height: var(--lh-aere); }

.topday-date { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text-2); text-transform: capitalize; margin: var(--e-20) var(--e-2) var(--e-10); }
.topday-card { background: var(--bg-card-solid); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-14) var(--e-16); margin-bottom: var(--e-12); }
.td-head { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); margin-bottom: var(--e-10); }
.td-title { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.td-marge { flex: 0 0 auto; background: rgba(47,158,99,.16); color: var(--green); font-size: var(--t-meta); font-weight: var(--fw-gras); padding: var(--e-4) var(--e-10); border-radius: var(--r-sm); }
.td-row { display: flex; align-items: flex-start; gap: var(--e-14); overflow-x: auto; padding-bottom: var(--e-4); }
.td-vinted, .td-shein { flex: 0 0 auto; text-decoration: none; display: flex; flex-direction: column; align-items: center; }
.td-vinted img { width: 130px; height: 180px; object-fit: cover; border-radius: var(--r-md); border: 2px solid var(--violet); }
.td-vprice { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text); margin-top: var(--e-6); }
.td-meta { font-size: var(--t-mini); color: var(--text-3); }
.td-arrow { color: var(--text-3); align-self: center; flex: 0 0 auto; }
.td-sheins { display: flex; gap: var(--e-10); }
.td-shein img { width: 120px; height: 166px; object-fit: cover; border-radius: var(--r-md); border: 1px solid var(--border-mid); transition: border-color var(--t-moyen); }
.td-shein:hover img { border-color: var(--violet); }
.td-price { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--green); margin-top: var(--e-6); }
.td-name { font-size: var(--t-micro); color: var(--text-3); max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.td-nosrc { align-self: center; color: var(--text-3); font-size: var(--t-base); font-style: italic; }
.td-head-right { display: flex; align-items: center; gap: var(--e-8); flex: 0 0 auto; }
.td-del { width: 24px; height: 24px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(224,85,107,0.42); border-radius: var(--r-sm); background: rgba(224,85,107,0.12);
  color: var(--red); font-size: var(--t-base); line-height: var(--lh-un); cursor: pointer; padding: 0; transition: background var(--t-bref); }
.td-del:hover { background: rgba(224,85,107,0.28); }

/* ════════ Couleurs d'ambiance personnelles (regreffées par-dessus la version d'Amadou) ════════ */
.ambient-blob {
  position: fixed;
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
  filter: blur(80px);
}
.blob-violet {
  width: 700px; height: 700px;
  top: -180px; right: -180px;
  background: radial-gradient(circle, rgba(124,58,237,0.1) 0%, transparent 70%);
}
.blob-cyan {
  width: 500px; height: 500px;
  bottom: -100px; left: -100px;
  background: radial-gradient(circle, rgba(6,182,212,0.07) 0%, transparent 70%);
}

/* ════════ Bibliothèque : switch Perso / Commun + partage robe ════════ */
.lib-scope-switch {
  display: inline-flex;
  gap: var(--e-2);
  padding: var(--e-4);
  border-radius: var(--r-pilule);
  background: var(--bg-hover);
  border: 1px solid var(--border);
  margin: 0 auto 0 var(--e-16);
}
.lib-scope-btn {
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  padding: var(--e-6) var(--e-16);
  border-radius: var(--r-pilule);
  cursor: pointer;
  transition: background var(--t-moyen), color var(--t-moyen);
}
.lib-scope-btn:hover { color: var(--text); }
.lib-scope-btn.active {
  background: var(--violet);
  color: var(--sur-accent);
  box-shadow: 0 2px 8px -2px var(--violet-glow);
}

.lib-scope-badge {
  display: inline-block;
  color: var(--red);
  font-size: var(--t-nano);
  margin-left: var(--e-4);
  vertical-align: middle;
  line-height: var(--lh-un);
  animation: pulse-dot 1.5s ease-in-out infinite;
}
@keyframes pulse-dot {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}
.dress-scope-row { margin: var(--e-4) 0 var(--e-14); }
.dress-scope-btn {
  display: inline-flex; align-items: center; gap: var(--e-8);
  padding: var(--e-8) var(--e-14);
  border-radius: var(--r-md);
  border: 1px solid var(--violet-tint-strong);
  background: var(--violet-tint);
  color: var(--violet-light);
  font-size: var(--t-base); font-weight: var(--fw-fort);
  cursor: pointer;
  transition: background var(--t-moyen), border-color var(--t-moyen);
}
.dress-scope-btn:hover { background: var(--violet-tint-strong); }
.dress-scope-btn.is-commun {
  border-color: rgba(99,214,176,0.35);
  background: rgba(99,214,176,0.12);
  color: var(--green);
}
.dress-scope-btn.is-commun:hover { background: rgba(99,214,176,0.2); }

/* ════════ Sélecteur de compte (Messages) — habillage sombre, fin du surlignage bleu ════════ */
/* ── Filtre compte Messages : dropdown custom Velbo ── */
.msg-filter-dd-wrap { position: relative; }
.msg-filter-dd-btn {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--t-base);
  font-family: inherit;
  padding: var(--e-6) var(--e-10);
  cursor: pointer;
  white-space: nowrap;
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: border-color var(--t-moyen), color var(--t-moyen);
}
.msg-filter-dd-btn:hover { border-color: var(--violet-mid); color: var(--text); }
.msg-filter-dd-btn.has-filter { border-color: var(--violet); color: var(--violet-soft); }
/* Menu déroulant (positionné en fixed via JS) */
.msg-filter-dd-menu {
  background: var(--bg-card-solid, #161A2A);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm, 10px);
  box-shadow: 0 8px 28px rgba(var(--th-ombre),.45);
  overflow: hidden;
  max-height: 360px;
  overflow-y: auto;
}
.msg-filter-dd-group {
  display: block;
  padding: var(--e-8) var(--e-14) var(--e-2);
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  text-transform: uppercase;
  color: var(--text-3);
  letter-spacing: var(--ls-ample);
}
.msg-filter-dd-opt {
  padding: var(--e-8) var(--e-14);
  font-size: var(--t-small);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--t-bref), color var(--t-bref);
  white-space: nowrap;
}
.msg-filter-dd-opt:hover { background: var(--surface-2); color: var(--text); }
.msg-filter-dd-opt.active { background: rgba(var(--th-accent-rgb),.12); color: var(--violet-soft); }

/* ════════ Messagerie : carte d'offre + panneau Détails (réplique Vinted) ════════ */
/* Carte d'offre dans le fil */
.msg-offer {
  align-self: flex-start; max-width: 78%;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: var(--e-12) var(--e-14); background: var(--surface-2);
  display: flex; flex-direction: column; gap: var(--e-10);
}
.msg-offer.mine { align-self: flex-end; }
.msg-offer-prices { display: flex; align-items: baseline; gap: var(--e-10); }
.msg-offer-price { font-size: var(--t-lead); font-weight: 800; color: var(--text); }
.msg-offer-orig  { font-size: var(--t-small); color: var(--text-3); text-decoration: line-through; }
.msg-offer-status { font-size: var(--t-base); color: var(--text-3); font-weight: var(--fw-fort); }
.msg-offer-actions { display: flex; flex-direction: column; gap: var(--e-8); }
/* Dernier îlot turquoise de l'interface : le remplacement global n'avait attrapé que
   la ligne de survol, si bien que le bouton était vert d'eau au repos et bleu au survol. */
.msg-offer-btn {
  padding: var(--e-10) var(--e-14); border-radius: var(--r-md); font-size: var(--t-small); font-weight: var(--fw-gras);
  cursor: pointer; border: 1px solid var(--cyan); background: transparent; color: var(--cyan-soft);
  transition: background var(--t-bref), color var(--t-bref);
}
.msg-offer-btn:hover { background: var(--rp-blue-tint); color: var(--text); }
.msg-offer-btn.accept { background: var(--cyan); color: var(--sur-plein); border-color: var(--cyan); }
.msg-offer-btn.accept:hover { background: var(--cyan); }

/* Bouton « i » dans l'en-tête */
.msg-details-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: transparent; color: var(--text-2);
  cursor: pointer; transition: background var(--t-bref), color var(--t-bref);
}
.msg-details-btn:hover { background: var(--surface-2); color: var(--text); }

/* Panneau Détails (slide-over à droite) */
.msg-details-panel {
  position: absolute; top: 0; right: 0; bottom: 0; width: 360px; max-width: 90%;
  background: var(--bg-2); border-left: 1px solid var(--border);
  box-shadow: -10px 0 40px -16px rgba(var(--th-ombre),0.6);
  z-index: 40; display: flex; flex-direction: column;
  animation: msgDetIn var(--t-moyen) ease;
}
@keyframes msgDetIn { from { transform: translateX(20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
.msg-details-panel.hidden { display: none; }
.msg-details-head {
  display: flex; align-items: center; justify-content: center; position: relative;
  padding: var(--e-16); border-bottom: 1px solid var(--border); font-weight: var(--fw-gras); color: var(--text);
}
.msg-details-close {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  border: none; background: transparent; color: var(--text-2); font-size: var(--t-lead); cursor: pointer;
}
.msg-details-body { flex: 1; overflow-y: auto; padding: var(--e-6) 0; }
.msg-det-row {
  display: flex; align-items: center; gap: var(--e-12); width: 100%;
  padding: var(--e-14) var(--e-18); background: transparent; border: none; border-bottom: 1px solid var(--border);
  color: var(--text); font-size: var(--t-small); text-align: left; cursor: pointer; text-decoration: none;
  transition: background var(--t-bref);
}
.msg-det-row:hover { background: var(--surface); }
.msg-det-row.danger { color: var(--red); }
.msg-det-ico { width: 22px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.flag-img { display: inline-block; vertical-align: middle; border-radius: 2px; object-fit: cover; }
.msg-det-thumb { width: 40px; height: 40px; border-radius: var(--r-sm); object-fit: cover; flex-shrink: 0; }
.msg-det-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-det-chev { color: var(--text-3); font-size: var(--t-lead); }

/* ═══════════════════════════ PLAYGROUND ══════════════════════════ */
.pg-layout {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 0;
  flex: 1;
  overflow: hidden;
  min-height: 0;
}

/* ── Sidebar ── */
.pg-sidebar {
  border-right: 1px solid var(--border);
  background: var(--bg-panel);
  overflow-y: auto;
  padding: var(--e-18) var(--e-14);
  display: flex;
  flex-direction: column;
  gap: var(--e-22);
}

.pg-sidebar-label {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-3);
  margin-bottom: var(--e-10);
}

/* Simulateur de notifications (Playground) */
.pg-sim-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e-8);
}
.pg-sim-btn {
  display: flex; align-items: center; justify-content: center; gap: var(--e-6);
  padding: var(--e-10) var(--e-6);
  font-size: var(--t-meta); font-weight: var(--fw-fort);
  color: var(--text); font-family: inherit;
  background: rgba(var(--th-voile),0.04);
  border: 1px solid var(--border);
  border-radius: var(--r-md); cursor: pointer;
  transition: border-color var(--t-bref), background var(--t-bref), transform var(--t-bref);
}
.pg-sim-btn:hover { border-color: var(--border-h, rgba(var(--th-accent-rgb),0.55)); background: rgba(var(--th-accent-rgb),0.10); }
.pg-sim-btn:active { transform: scale(.96); }
.pg-sim-btn.pg-sim-fired { border-color: var(--green, #2fbf71); background: rgba(47,191,113,0.14); }
.pg-sim-hint { margin-top: var(--e-8); font-size: var(--t-micro); line-height: var(--lh-serre); color: var(--text-3); }

/* Scénarios bot (une colonne — libellés plus longs) */
.pg-scn-grid { display: flex; flex-direction: column; gap: var(--e-6); }
.pg-scn-btn {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-10) var(--e-12); text-align: left;
  font-size: var(--t-meta); font-weight: var(--fw-fort);
  color: var(--text); font-family: inherit;
  background: rgba(var(--th-voile),0.04);
  border: 1px solid var(--border);
  border-radius: var(--r-md); cursor: pointer;
  transition: border-color var(--t-bref), background var(--t-bref), transform var(--t-bref);
}
.pg-scn-btn:hover  { border-color: var(--border-h, rgba(var(--th-accent-rgb),0.55)); background: rgba(var(--th-accent-rgb),0.10); }
.pg-scn-btn:active { transform: scale(.97); }

.pg-dress-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-8);
  padding: var(--e-22) var(--e-10);
  color: var(--text-3);
  font-size: var(--t-meta);
  text-align: center;
  border: 1px dashed var(--border-mid);
  border-radius: var(--r-lg);
  margin-bottom: var(--e-10);
}
.pg-dress-empty[hidden] { display: none; }

.pg-dress-card {
  background: var(--bg-card);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-lg);
  overflow: hidden;
  margin-bottom: var(--e-10);
}

.pg-dress-thumb {
  width: 100%;
  height: 190px;
  background: var(--surface-2) center/cover no-repeat;
}

.pg-dress-thumbs {
  display: flex;
  gap: var(--e-6);
  padding: var(--e-8);
  overflow-x: auto;
  border-top: 1px solid var(--border);
}
.pg-dress-thumbs:empty { display: none; }

.pg-dress-thumb-mini {
  width: 38px;
  height: 50px;
  flex-shrink: 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-mid);
  background: var(--surface-2) center/cover no-repeat;
  cursor: pointer;
  padding: 0;
  opacity: .5;
  transition: opacity var(--t-bref), border-color var(--t-bref), transform var(--t-bref);
}
.pg-dress-thumb-mini:not(.active):hover { opacity: 1; transform: translateY(-1px); }
.pg-dress-thumb-mini.active { opacity: 1; border-color: var(--violet); }

.pg-dress-info {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-8);
  padding: var(--e-10) var(--e-12);
  border-top: 1px solid var(--border);
}

.pg-dress-name {
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}

.pg-dress-rm {
  background: none;
  border: none;
  cursor: pointer;
  font-size: var(--t-lead);
  color: var(--text-3);
  padding: 0 var(--e-2);
  line-height: var(--lh-un);
  flex-shrink: 0;
  transition: color var(--t-bref);
}
.pg-dress-rm:hover { color: var(--red); }

.pg-pick-btn { width: 100%; justify-content: center; font-size: var(--t-meta); }

/* Prix de l'annonce */
.pg-price-field {
  display: flex;
  align-items: center;
  border: 1px solid var(--border-mid);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--bg-card);
}
.pg-price-field:focus-within { border-color: var(--violet); }

.pg-price-input {
  flex: 1;
  border: none;
  background: transparent;
  font-size: var(--t-small);
  font-weight: var(--fw-gras);
  color: var(--text);
  padding: var(--e-10) var(--e-12);
  outline: none;
  width: 100%;
  -moz-appearance: textfield;
}
.pg-price-input::-webkit-outer-spin-button,
.pg-price-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.pg-price-cur {
  padding: 0 var(--e-14);
  font-size: var(--t-base);
  font-weight: var(--fw-gras);
  color: var(--text-2);
  border-left: 1px solid var(--border);
  align-self: stretch;
  display: flex;
  align-items: center;
}

/* ── Chat ── */
.pg-chat {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: transparent;
}

/* Barre produit (contexte testé) */
.pg-prodbar {
  display: flex;
  align-items: center;
  gap: var(--e-12);
  padding: var(--e-12) var(--e-16);
  border-bottom: 1px solid var(--border);
  background: var(--bg-panel);
  flex-shrink: 0;
}
.pg-prodbar[hidden] { display: none; }
.pg-prodbar-thumb {
  width: 36px;
  height: 44px;
  border-radius: var(--r-sm);
  background: var(--bg-card) center/cover no-repeat;
  border: 1px solid var(--border-mid);
  flex-shrink: 0;
}
.pg-prodbar-texts { min-width: 0; flex: 1; }
.pg-prodbar-name {
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pg-prodbar-sub { font-size: var(--t-meta); color: var(--text-2); margin-top: var(--e-2); }

.pg-sandbox-badge {
  margin-left: auto;
  flex-shrink: 0;
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-large);
  text-transform: uppercase;
  color: var(--cyan-soft);
  background: var(--cyan-tint);
  border: 1px solid rgba(var(--th-second-rgb),.3);
  border-radius: var(--r-xl);
  padding: var(--e-4) var(--e-12);
}

.pg-messages {
  flex: 1;
  overflow-y: auto;
  padding: var(--e-18) var(--e-16);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
}

.pg-empty-hint {
  margin: auto;
  text-align: center;
  color: var(--text-3);
  font-size: var(--t-base);
  max-width: 280px;
  line-height: var(--lh-aere);
}

.pg-msg-wrap { display: flex; gap: var(--e-10); max-width: min(84%, 620px); }
.pg-msg-buyer { align-self: flex-start; }
.pg-msg-bot   { align-self: flex-end; flex-direction: row-reverse; }

.pg-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--t-mini);
  font-weight: var(--fw-gras);
  flex-shrink: 0;
  margin-top: var(--e-2);
}
.pg-avatar-buyer { background: var(--bg-card); color: var(--text-2); border: 1px solid var(--border-mid); }
.pg-avatar-bot   { background: var(--violet-tint); color: var(--violet-soft); border: 1px solid rgba(var(--th-accent-rgb),.3); font-size: var(--t-micro); }

.pg-bubble-col { display: flex; flex-direction: column; min-width: 0; }

.pg-bubble {
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-xl);
  font-size: var(--t-small);
  line-height: var(--lh-normal);
  white-space: pre-wrap;
  word-break: break-word;
}
.pg-bubble-buyer {
  background: var(--bg-card);
  border: 1px solid var(--border-mid);
  color: var(--text);
  border-bottom-left-radius: 5px;
}
.pg-bubble-bot {
  background: var(--violet);
  color: var(--sur-accent);
  border-bottom-right-radius: 5px;
}

.pg-bubble-time { font-size: var(--t-micro); color: var(--text-3); margin-top: var(--e-4); }
.pg-msg-bot .pg-bubble-time { text-align: right; }

.pg-bubble-actions { display: flex; gap: var(--e-6); margin-top: var(--e-6); justify-content: flex-end; }
.pg-action-btn {
  display: flex;
  align-items: center;
  gap: var(--e-4);
  font-size: var(--t-micro);
  color: var(--text-3);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--e-4) var(--e-10);
  background: transparent;
  cursor: pointer;
  transition: background var(--t-bref), color var(--t-bref);
}
.pg-action-btn:hover { background: var(--surface-2); color: var(--text-2); }

/* typing */
.pg-typing {
  display: flex;
  gap: var(--e-4);
  align-items: center;
  padding: var(--e-12) var(--e-16);
  background: var(--bg-card);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-xl);
  border-bottom-left-radius: 5px;
}
.pg-typing span {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--text-3);
  animation: pg-dot 1.2s infinite;
  display: block;
}
.pg-typing span:nth-child(2) { animation-delay: var(--t-moyen); }
.pg-typing span:nth-child(3) { animation-delay: var(--t-long); }
@keyframes pg-dot {
  0%, 60%, 100% { transform: scale(1); opacity: .5; }
  30%            { transform: scale(1.3); opacity: 1; }
}

/* ── Carte d'offre (réplique Vinted) ── */
.pg-offer {
  border: 1px solid var(--border-mid);
  border-radius: var(--r-xl);
  padding: var(--e-14) var(--e-16);
  background: var(--bg-card);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
  min-width: 206px;
}
.pg-msg-bot .pg-offer { border-bottom-right-radius: 5px; }
.pg-msg-buyer .pg-offer { border-bottom-left-radius: 5px; }

.pg-offer-head {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  color: var(--text-3);
}
.pg-offer-prices { display: flex; align-items: baseline; gap: var(--e-10); }
.pg-offer-price { font-size: var(--t-title); font-weight: 800; color: var(--text); }
.pg-offer-orig  { font-size: var(--t-small); color: var(--text-3); text-decoration: line-through; }
.pg-offer-status { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-3); }

.pg-offer-actions { display: flex; flex-direction: column; gap: var(--e-8); }
.pg-offer-btn {
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-md);
  font-size: var(--t-small);
  font-weight: var(--fw-gras);
  cursor: pointer;
  border: 1px solid var(--cyan);
  background: transparent;
  color: var(--cyan-soft);
  transition: background var(--t-bref);
}
.pg-offer-btn:hover { background: var(--cyan-tint); }
.pg-offer-btn.accept { background: var(--cyan); color: #062b30; border-color: var(--cyan); }
.pg-offer-btn.accept:hover { background: var(--cyan-soft); }

/* ── Ligne de statut (acceptée / refusée) ── */
.pg-status-line {
  align-self: center;
  font-size: var(--t-meta);
  font-weight: var(--fw-fort);
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  padding: var(--e-6) var(--e-16);
}
.pg-status-accept { color: var(--green); border-color: rgba(34,197,94,.35); background: rgba(34,197,94,.12); }
.pg-status-decline { color: var(--red); border-color: rgba(var(--th-danger-rgb),.35); background: var(--danger-fond); }

/* Événement système (favori reçu, achat…) */
.pg-sys-line {
  align-self: center; max-width: 90%; text-align: center;
  font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-3);
  background: var(--surface-2); border: 1px dashed var(--border);
  border-radius: var(--r-md); padding: var(--e-6) var(--e-14); margin: var(--e-2) 0;
}
/* Action concrète du bot (offre envoyée, prolongation, escalade…) */
.pg-action-line {
  align-self: stretch;
  display: flex; align-items: flex-start; gap: var(--e-10); flex-wrap: wrap;
  font-size: var(--t-base); font-weight: var(--fw-fort); line-height: var(--lh-normal); color: var(--text);
  background: rgba(var(--th-accent-rgb),0.10);
  border: 1px solid rgba(var(--th-accent-rgb),0.40);
  border-radius: var(--r-lg); padding: var(--e-10) var(--e-14);
}
.pg-action-tag {
  flex: none; font-size: var(--t-micro); font-weight: 800; letter-spacing: var(--ls-large); text-transform: uppercase;
  color: var(--sur-accent); background: var(--accent, var(--violet));
  border-radius: var(--r-sm); padding: var(--e-4) var(--e-8);
}
/* Note explicative (gris, discret) */
.pg-note-line {
  align-self: stretch; font-size: var(--t-mini); line-height: var(--lh-normal); font-style: italic;
  color: var(--text-3); padding: var(--e-2) var(--e-4);
}

/* ── Barre d'offre acheteur ── */
.pg-offer-bar {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  padding: var(--e-10) var(--e-14);
  border-top: 1px solid var(--border);
  background: var(--bg-panel);
  flex-shrink: 0;
}
.pg-offer-bar-ico { color: var(--cyan-soft); flex-shrink: 0; }
.pg-offer-bar-label { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2); flex-shrink: 0; }

.pg-offer-input {
  width: 92px;
  border: 1px solid var(--border-mid);
  border-radius: var(--r-md);
  background: var(--bg-card);
  font-size: var(--t-base);
  color: var(--text);
  padding: var(--e-8) var(--e-12);
  outline: none;
  -moz-appearance: textfield;
}
.pg-offer-input::-webkit-outer-spin-button,
.pg-offer-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pg-offer-input:focus { border-color: var(--cyan); }

.pg-offer-send-btn {
  margin-left: auto;
  border: 1px solid var(--cyan);
  background: var(--cyan);
  color: #062b30;
  font-size: var(--t-meta);
  font-weight: var(--fw-gras);
  border-radius: var(--r-md);
  padding: var(--e-8) var(--e-16);
  cursor: pointer;
  transition: background var(--t-bref);
  flex-shrink: 0;
}
.pg-offer-send-btn:hover { background: var(--cyan-soft); }

/* ── Composer ── */
.pg-composer {
  border-top: 1px solid var(--border);
  padding: var(--e-12) var(--e-14);
  display: flex;
  gap: var(--e-10);
  align-items: flex-end;
  flex-shrink: 0;
  background: var(--bg-panel);
}
.pg-composer-inner {
  flex: 1;
  border: 1px solid var(--border-mid);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--bg-card);
}
.pg-composer-inner:focus-within { border-color: var(--violet); }
.pg-composer-label { font-size: var(--t-micro); color: var(--text-3); padding: var(--e-8) var(--e-12) 0; font-weight: var(--fw-moyen); }
.pg-composer-label kbd {
  font-family: inherit;
  font-size: var(--t-micro);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-micro);
  padding: 0 var(--e-4);
}
.pg-input {
  width: 100%;
  border: none;
  background: transparent;
  font-size: var(--t-small);
  color: var(--text);
  resize: none;
  padding: var(--e-4) var(--e-12) var(--e-10);
  outline: none;
  font-family: inherit;
  box-sizing: border-box;
}

.pg-composer-actions { display: flex; flex-direction: column; gap: var(--e-8); }
.pg-reset-btn {
  width: 38px;
  height: 38px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-mid);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background var(--t-bref), color var(--t-bref);
}
.pg-reset-btn:hover { background: var(--surface-2); color: var(--text-2); }

.pg-send-btn {
  width: 38px;
  height: 38px;
  border-radius: var(--r-md);
  background: var(--violet);
  border: none;
  color: var(--sur-accent);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background var(--t-moyen);
}
.pg-send-btn:hover { background: var(--violet-hover); }

/* ════════ Sélecteur d'identité (sidebar) — sépare les espaces (Messages/coûts) ════════ */
.identity-row {
  display: flex; align-items: center; gap: var(--e-8);
  /* Resserré avec le reste de la barre (refonte 2026-07-30) : la marge de 8 px sous
     ce bloc poussait la Fabrique hors de l'écran sur un portable. */
  padding: var(--e-6) var(--e-10); margin-bottom: var(--e-4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); color: var(--text-2);
}
.identity-row svg { flex-shrink: 0; color: var(--violet-light); }
.identity-select {
  flex: 1; min-width: 0; color-scheme: dark;
  background: transparent; border: none; outline: none;
  color: var(--text); font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-fort); cursor: pointer;
}
.identity-select option { background: var(--bg-panel-solid); color: var(--text); }
.sidebar.collapsed .identity-row { display: none; }

/* ═══════════ CONTEXTE ANNONCE — panneau droit (Conversations + À traiter) ═══════════ */
.anc-panel {
  width: 360px;
  flex-shrink: 0;
  border-left: 1px solid var(--border);
  background: var(--bg-panel);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.anc-panel.hidden { display: none; }

.anc-head {
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--text-3);
  padding: var(--e-12) var(--e-14) var(--e-10);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.anc-placeholder {
  margin: auto;
  padding: var(--e-24) var(--e-18);
  text-align: center;
  font-size: var(--t-base);
  color: var(--text-3);
  line-height: var(--lh-aere);
}

.anc-body {
  padding: var(--e-14);
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
}

.anc-photo {
  width: 100%;
  height: 230px;
  border-radius: var(--r-lg);
  background: var(--bg-card) center/cover no-repeat;
  border: 1px solid var(--border-mid);
  display: flex;
  align-items: center;
  justify-content: center;
}
.anc-photo-ph { font-size: var(--t-meta); color: var(--text-3); }

.anc-thumbs {
  display: flex;
  gap: var(--e-6);
  flex-wrap: wrap;
}
.anc-thumb {
  width: 40px;
  height: 52px;
  flex-shrink: 0;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-mid);
  background: var(--bg-card) center/cover no-repeat;
  cursor: pointer;
  padding: 0;
  opacity: .55;
  transition: opacity var(--t-bref), border-color var(--t-bref), transform var(--t-bref);
}
.anc-thumb:hover { opacity: 1; transform: translateY(-1px); }
.anc-thumb.active { opacity: 1; border-color: var(--violet); }

.anc-title {
  font-size: var(--t-small);
  font-weight: var(--fw-fort);
  color: var(--text);
  line-height: var(--lh-serre);
}

.anc-price {
  font-size: var(--t-body);
  font-weight: var(--fw-gras);
  color: var(--text);
}

.anc-sku {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  background: var(--bg-card);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-md);
  padding: var(--e-8) var(--e-12);
}
.anc-sku-l { min-width: 0; flex: 1; }
.anc-sku-lab {
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  color: var(--text-3);
}
.anc-sku-val {
  font-size: var(--t-base);
  font-weight: var(--fw-fort);
  color: var(--text);
  font-family: var(--font-mono, monospace);
  margin-top: var(--e-1);
  word-break: break-all;
}
.anc-sku-copy {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-mid);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--t-bref), color var(--t-bref);
}
.anc-sku-copy:hover { background: var(--surface-2); color: var(--text-2); }

.anc-sec {}
.anc-sec-lab {
  font-size: var(--t-micro);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  color: var(--text-3);
  margin-bottom: var(--e-4);
}
.anc-desc {
  font-size: var(--t-base);
  color: var(--text-2);
  line-height: var(--lh-normal);
  white-space: pre-wrap;
}
.anc-kv {
  font-size: var(--t-base);
  color: var(--text-2);
  line-height: var(--lh-normal);
}

.anc-empty-note {
  font-size: var(--t-meta);
  color: var(--text-3);
  line-height: var(--lh-normal);
  background: var(--surface);
  border: 1px dashed var(--border-mid);
  border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12);
}
.anc-link-btn {
  margin-top: var(--e-12);
  width: 100%;
  padding: var(--e-10) var(--e-12);
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  /* ⚠️ Violet en dur remplacé par l'accent du thème : sur les thèmes dorés
     ou terre, ce bouton restait violet au milieu d'un écran ambré. */
  background: rgba(var(--th-accent-rgb), .12);
  color: var(--th-accent-clair);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: background var(--t-moyen) var(--c-pose), border-color var(--t-moyen) var(--c-pose);
}
.anc-link-btn:hover { background: rgba(var(--th-accent-rgb), .2); border-color: var(--violet); }

/* À traiter : panneau contexte droit — visible dès qu'il n'est pas hidden */
.ctrl-split #ctrl-esc-context { border-left: 1px solid var(--border); }
.ctrl-split.split--open #ctrl-esc-context:not(.hidden) { flex: 0 0 360px; min-width: 300px; max-width: 400px; }
/* msg-layout (ctrl-split-esc) : même comportement sans split--open */
#ctrl-split-esc #ctrl-esc-context:not(.hidden) {
  flex: 0 0 300px;
  min-width: 240px;
  max-width: 360px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

/* ═══════════ Bibliothèque — menu d'actions regroupées (⋯) ═══════════ */
.lib-actions { position: relative; display: inline-flex; }
.lib-actions-trigger {
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: transparent; color: var(--text-2); cursor: pointer;
  transition: background var(--t-bref), color var(--t-bref), border-color var(--t-bref), transform var(--t-bref) var(--c-rebond);
}
.lib-actions-trigger:hover,
.lib-actions-trigger.active { background: var(--surface-2); color: var(--text); border-color: var(--border-mid); }

.lib-actions-menu {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  min-width: 230px; padding: var(--e-6);
  background: rgba(var(--th-panneau-rgb),0.82);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border: 1px solid var(--border-mid); border-radius: var(--r-lg);
  box-shadow: 0 16px 40px -12px rgba(var(--th-ombre),.45);
  display: flex; flex-direction: column; gap: var(--e-2);
  animation: libMenuIn var(--t-bref) ease;
}
.lib-actions-menu.hidden { display: none; }
@keyframes libMenuIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }

.lib-menu-item {
  display: flex; align-items: center; gap: var(--e-10); width: 100%;
  padding: var(--e-10) var(--e-12); border: none; background: transparent;
  border-radius: var(--r-sm); cursor: pointer; text-align: left;
  font-size: var(--t-base); color: var(--text); font-family: inherit;
  transition: background var(--t-bref);
}
.lib-menu-item:hover { background: var(--surface-2); }
.lib-menu-item svg { color: var(--text-3); flex-shrink: 0; }
.lib-menu-item.hidden { display: none; }

/* ═══════════ Génération — 2 panneaux : réglages (gauche) / résultat (droite) ═══════════ */
/* Réglage puis résultat, l'un sous l'autre, sur toute la largeur (2026-08-02).
   Avant, le réglage était coincé dans un rail de 400 px avec un panneau vide à droite :
   les photos étaient minuscules et la moitié de l'écran ne servait à rien. */
.gen-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--e-22);
  align-items: start;
  min-width: 0;
}
.gen-inputs { display: flex; flex-direction: column; gap: var(--e-18); min-width: 0; }
.gen-output { min-width: 0; display: flex; flex-direction: column; gap: var(--e-18); }

/* Les deux zones photos côte à côte, mais PAS à parts égales : les templates de pose,
   c'est toujours trois vues (Face, Biais, Dos), jamais plus. La largeur rendue par la
   colonne de gauche va aux photos de la robe, dont le nombre varie — c'est là qu'on a
   besoin de voir sans faire glisser.
   `align-items: start` : chacune prend sa hauteur réelle. Étirées à la même hauteur,
   celle qui avait le moins de photos se retrouvait avec un grand vide au milieu. */
.gen-inputs .upload-cols {
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  align-items: start;
}
.gen-inputs .gen-options-grid { grid-template-columns: minmax(0, 1fr); }

/* ── Écran de réglage compact ──────────────────────────────────────────────
   Objectif tenu à l'œil : sur un MacBook (≈ 820 px de haut utile), le bouton
   « Générer les visuels » doit être visible SANS descendre, avec 3 templates et
   5 photos de robe chargés. Chaque valeur ci-dessous a été rognée pour ça.
   Tout est limité au panneau Mannequin : Repost et Vues produit gardent leurs
   espacements d'origine. */
#section-generator .section-canvas { padding-top: var(--e-16); }   /* 28 px de vide pur */
#section-generator .gen-subtabs { margin-bottom: var(--e-12); }
#gen-subpanel-mannequin .gen-inputs,
#gen-subpanel-mannequin .card-stack { gap: var(--e-12); }
#gen-subpanel-mannequin .upload-zone { padding: var(--e-16) var(--e-18); gap: var(--e-10); }
#gen-subpanel-mannequin .options-card { padding: var(--e-16) var(--e-20); }
#gen-subpanel-mannequin .gen-options-grid { gap: var(--e-12); }
#gen-subpanel-mannequin .gen-options-grid .field-label { margin-bottom: var(--e-8); }
#gen-subpanel-mannequin .mode-row { padding: var(--e-8) var(--e-14); border-radius: var(--r-md); }

/* Placeholder résultat avant génération */
.gen-output-ph {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-12); min-height: 380px;
  color: var(--text-3); font-size: var(--t-base); text-align: center; line-height: var(--lh-normal);
  border: 1px dashed var(--border-mid); border-radius: var(--r-lg);
  background: var(--surface);
}
.gen-output-ph svg { color: var(--text-3); opacity: .65; }
.gen-output:has(#results-section:not(.hidden)) .gen-output-ph,
.gen-output:has(#new-dress-section:not(.hidden)) .gen-output-ph { display: none; }

/* Le panneau d'attente à droite n'a plus lieu d'être : le résultat s'affiche dessous. */
.gen-output-ph { display: none; }

/* ── Vues interrompues par le Stop ─────────────────────────────────────────
   Le moteur met parfois quelques secondes à rendre la main : ces styles disent
   immédiatement que la vue ne viendra pas, au lieu de laisser tourner une barre
   qui ne correspond plus à rien. */
.card-loader-sub--stoppe { color: var(--text-3); opacity: .8; }
.card-progress-bar--stoppe {
  background: var(--text-3) !important;
  opacity: .35;
  transition: none;
}
.btn-stop-gen:disabled { opacity: .55; cursor: default; }

/* Une vue arrêtée ne recevra pas d'image : inutile de lui garder la place d'une
   photo (3/4 de sa largeur, soit près de 500 px de haut à trois colonnes). Elle
   se replie sur sa seule ligne de texte. Elle reprendra sa taille toute seule si
   on relance, puisque la classe part avec la carte. */
.image-card.card-stoppe {
  aspect-ratio: auto;
  min-height: 0;
}
.image-card.card-stoppe .card-loader { padding: var(--e-16) var(--e-14); gap: var(--e-8); }

/* ── Reprendre après un arrêt ─────────────────────────────────────────────── */
.btn-reprendre-gen {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-8);
  width: 100%;
  height: 40px;
  border-radius: var(--r-md);
  border: 1px solid color-mix(in srgb, var(--violet-light) 45%, transparent);
  background: var(--violet-tint);
  color: var(--violet-soft);
  font-size: var(--t-small);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose);
}
.btn-reprendre-gen:hover { background: var(--violet-tint-strong); border-color: var(--violet-light); }
.btn-reprendre-gen:disabled { opacity: .55; cursor: default; }

/* ═══════════ Génération en deux temps ═══════════
   Temps 1 : on règle. Temps 2 : les réglages s'effacent, un récapitulatif prend leur
   place et l'annonce se fabrique juste en dessous — sans avoir à faire défiler la page. */
#section-generator.gen-en-cours #gen-subpanel-mannequin .upload-section,
#section-generator.gen-en-cours #gen-subpanel-mannequin .gen-options-grid { display: none; }

.gen-recap {
  padding: var(--e-20) var(--e-22);
  animation: gen-recap-entree var(--d-mid, var(--t-long)) var(--ease, ease) both;
}
@keyframes gen-recap-entree {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .gen-recap { animation: none; }
}

.gen-recap-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--e-16);
  margin-bottom: var(--e-18);
}
.gen-recap-title { font-size: var(--t-body); font-weight: var(--fw-fort); color: var(--text); }
.gen-recap-sub   { font-size: var(--t-meta); color: var(--text-3); margin-top: var(--e-4); }

.gen-recap-back {
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  height: 32px;
  padding: 0 var(--e-14);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-2);
  font-size: var(--t-meta);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose);
}
.gen-recap-back:hover { border-color: var(--border-strong); color: var(--text); }

/* ⚠️⚠️ UNE SEULE LIGNE, LE COÛT DÉTACHÉ. Amadou (01/09) : « le résumé, c'est vraiment
   mal fait » — puis, sur six propositions, il a choisi la version 1.
   Ce qui n'allait pas était mesurable : trois colonnes de largeur libre (`auto auto 1fr`)
   qui ne s'alignaient sur rien, et le COÛT rangé parmi les faits alors que c'est le seul
   chiffre qui décide de cliquer. Tout passe sur une rangée, alignée par le bas, et le
   coût part à droite derrière un filet. */
.gen-recap-body {
  display: flex;
  align-items: flex-end;
  gap: var(--e-18);
  flex-wrap: wrap;
}
/* ⚠️ Les photos gardent leur étiquette au-dessus : `.gen-recap-photos` est aussi une
   colonne, sinon l'étiquette et les vignettes se mettraient côte à côte dans la rangée. */
.gen-recap-photos { display: flex; flex-direction: column; }
/* Le ressort : il pousse le coût contre le bord droit, et disparaît quand la rangée se
   replie sur un écran étroit. */
.gen-recap-body > .gen-recap-faits { flex: 1 1 auto; }
@media (max-width: 900px) {
  .gen-recap-body { align-items: flex-start; }
}

.gen-recap-label {
  font-size: var(--t-meta);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  color: var(--text-3);
  margin-bottom: var(--e-10);
}
/* ⚠️ LES VIGNETTES SE CHEVAUCHENT — un jeu de photos, pas une grille. Le liseré prend
   la couleur du panneau pour détacher chaque photo de sa voisine. */
.gen-recap-vignettes { display: flex; }
.gen-recap-vignettes > * + * { margin-left: -14px; }
.gen-recap-vignettes img,
.gen-recap-vignettes .gen-recap-vide {
  box-shadow: 0 0 0 2px var(--th-panneau);
  transition: transform var(--d-fast) var(--c-pose);
}
.gen-recap-vignettes img:hover { transform: translateY(-3px); z-index: 2; }
.gen-recap-vignettes img {
  width: 52px;
  height: 69px;
  object-fit: cover;
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  display: block;
}
.gen-recap-vide { font-size: var(--t-meta); color: var(--text-3); }

/* Les paramètres retenus, en paires libellé / valeur */
/* Les faits : côte à côte sur la rangée, jamais étirés — c'est le ressort au-dessus qui
   occupe la place restante. */
.gen-recap-faits {
  display: flex;
  gap: var(--e-14) var(--e-22);
  flex-wrap: wrap;
  align-items: flex-end;
}
.gen-recap-fait-cle {
  font-size: var(--t-meta);
  text-transform: uppercase;
  letter-spacing: var(--ls-ample);
  color: var(--text-3);
  margin-bottom: var(--e-6);
}
.gen-recap-fait-val {
  font-size: var(--t-small);
  color: var(--text);
  line-height: var(--lh-normal);
}
.gen-recap-fait-val.muet { color: var(--text-3); }

/* ── LE COÛT ─────────────────────────────────────────────────────────────────
   Détaché derrière un filet, et le seul chiffre du bandeau à changer de taille.
   ⚠️ `tabular-nums` : le montant se réévalue à chaque réglage, et sans chiffres de
   largeur fixe il tressaute d'un pixel à chaque changement — 87 endroits du site le
   posent déjà pour cette raison. */
.gen-recap-cout {
  margin-left: auto;
  padding-left: var(--e-20);
  border-left: 1px solid var(--border);
  text-align: right;
  align-self: flex-end;
}
.gen-recap-cout-val {
  font-size: var(--t-lead);
  font-weight: var(--fw-fort);
  color: var(--violet-light);
  line-height: var(--lh-titre);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 900px) {
  .gen-recap-cout {
    margin-left: 0; padding-left: 0; border-left: none;
    text-align: left; width: 100%;
    padding-top: var(--e-12); border-top: 1px solid var(--border);
  }
}

/* Écran étroit (MacBook en petite fenêtre) : les deux zones photos s'empilent */
@media (max-width: 820px) {
  .gen-inputs .upload-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ═══════════ Studio — centre en GALERIE quand des images sont générées ═══════════ */
.studio-chat-messages:has(.studio-msg-img-wrap) {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--e-14);
  align-content: start;
}
/* texte / prompts / accueil / typing : pleine largeur, comportement chat conservé */
.studio-chat-messages:has(.studio-msg-img-wrap) .studio-msg-user {
  grid-column: 1 / -1; justify-self: end;
}
.studio-chat-messages:has(.studio-msg-img-wrap) .studio-msg-velbo:not(:has(.studio-msg-img-wrap)) {
  grid-column: 1 / -1; justify-self: start;
}
.studio-chat-messages:has(.studio-msg-img-wrap) .studio-chat-welcome { grid-column: 1 / -1; }

/* carte galerie pour une image générée */
.studio-msg-velbo:has(.studio-msg-img-wrap) { max-width: none; display: block; }
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-avatar { display: none; }
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-bubble {
  padding: 0;
  background: var(--bg-card);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-text {
  padding: var(--e-10) var(--e-12) 0; margin: 0; font-size: var(--t-base); color: var(--text-2);
}
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-img-wrap { margin: 0; }
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-img-wrap img {
  width: 100%; display: block; cursor: zoom-in;
}
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-actions {
  margin: 0; padding: var(--e-8) var(--e-10); justify-content: flex-end; gap: var(--e-6);
  border-top: 1px solid var(--border); background: var(--surface);
}
/* actions en icônes seules dans la carte (façon maquette : télécharger / régénérer) */
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-action-btn {
  font-size: 0; padding: var(--e-8); border-radius: var(--r-sm);
}
.studio-msg-velbo:has(.studio-msg-img-wrap) .studio-msg-action-btn svg { margin: 0; }

/* ═══════════ Bibliothèque — recherche + tri dans la barre du haut ═══════════ */
.lib-search-top {
  width: 280px;
  flex: 0 1 280px;
  height: 34px;
}
.lib-search-top .lib-search-input { font-size: var(--t-base); }
.lib-sort { position: relative; display: inline-flex; }
.lib-sort .lib-actions-menu { min-width: 190px; }
.lib-sort-opt { justify-content: flex-start; }
.lib-sort-opt.active { color: var(--violet-soft); font-weight: var(--fw-moyen); }
@media (max-width: 880px) {
  .lib-search-top { width: 160px; flex: 0 1 160px; }
}

/* Boutons révéler/copier les clés API (Paramètres) */
.btn-key-act {
  flex: 0 0 auto; width: 34px; height: 34px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--text-2);
  cursor: pointer; font-size: var(--t-small); line-height: var(--lh-un);
  display: flex; align-items: center; justify-content: center;
  transition: background var(--t-bref), border-color var(--t-bref);
}
.btn-key-act:hover { background: var(--surface); border-color: var(--violet); color: var(--text); }

/* ════════ Bibliothèque : flèche de repli des filtres + onglet « Tous » ════════ */
.lib-filters-row-right { display: flex; align-items: center; gap: var(--e-8); }
.lib-filters-collapse {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-2);
  cursor: pointer; transition: background var(--t-bref), color var(--t-bref), transform var(--t-moyen);
}
.lib-filters-collapse:hover { background: var(--surface); color: var(--text); }
.lib-filters-collapse svg { transition: transform var(--t-moyen); }
/* Replié : on masque toutes les barres de filtres, la flèche pointe vers le bas */
/* ⚠️⚠️⚠️ CE REPLI EST SUPPRIMÉ — IL RENDAIT LE BOUTON « FILTRES » MUET POUR TOUJOURS.
   Il masquait `#lib-adv-filters` en `!important` selon une préférence gardée dans le
   navigateur. Tant que la flèche existait, on pouvait déplier ; elle est partie le 25/08
   (elle ne repliait plus que des barres retirées), mais la PRÉFÉRENCE, elle, est restée
   dans le navigateur d'Amadou. Chez lui, le clic ouvrait bien le panneau — un `!important`
   l'effaçait juste après, sans rien dire.
   Je ne le reproduisais pas : mon navigateur n'avait jamais eu la clé. Et je l'avais
   qualifié de « code mort sans effet » la veille : il ne l'était pas, il attendait.
   ⚠️ La leçon vaut au-delà d'ici : retirer une commande sans retirer l'ÉTAT qu'elle
   posait, c'est laisser un réglage que plus personne ne peut défaire.
   La clé `lib_filters_collapsed` est nettoyée au démarrage (voir app.js). */
/* ⚠️ EXCEPTION — dans « Le stock », #lib-size-bar n'est PAS un filtre : c'est le
   sélecteur de RAYON (Visages / Voitures / En chantier), donc de la navigation. Replié
   avec les filtres, il disparaissait et on ne pouvait plus changer de rayon : on restait
   coincé sur Visages sans comprendre pourquoi les autres fiches manquaient (Amadou,
   04/08 : « j'ai rien »). On le garde visible. */
/* (les deux dernières règles du repli, retirées avec lui le 25/08) */

/* ═══════════════════════════════ FINANCE ═══════════════════════════════ */
.fin-period { display: flex; gap: var(--e-4) }
.fin-period-btn { border: 0; background: transparent; color: var(--text-2); font: inherit; font-size: var(--t-base); font-weight: var(--fw-fort); padding: var(--e-8) var(--e-14); border-radius: var(--r-sm); cursor: pointer; transition: background var(--t-moyen), color var(--t-moyen); }
.fin-period-btn:not(.active):hover { color: var(--text-1); }
.fin-period-btn.active { background: var(--violet-tint); color: var(--violet-light); }

/* Limite de vente du jour */
.fin-limit { margin-bottom: var(--e-18); }
.fin-limit-card { background: var(--surface-2); border: 1px solid var(--border-mid); border-radius: var(--radius); padding: var(--e-18) var(--e-20); }
.fin-limit-card--reached { border-color: rgba(232,109,109,0.4); }
.fin-limit-head { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); margin-bottom: var(--e-14); flex-wrap: wrap; }
.fin-limit-titles { display: flex; align-items: center; gap: var(--e-10); }
.fin-limit-title { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text-1); }
.fin-limit-status { font-size: var(--t-mini); font-weight: var(--fw-fort); padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule); white-space: nowrap; }
.fin-limit-status--open    { background: var(--safe-bg); color: var(--safe-text); }
.fin-limit-status--reached { background: var(--ose-bg); color: var(--ose-text); }
.fin-limit-status--off     { background: var(--surface); color: var(--text-3); }
.fin-limit-actions { display: flex; align-items: center; gap: var(--e-14); }
.fin-limit-reset { font-size: var(--t-meta); color: var(--text-3); }
.fin-limit-edit { border: 0; background: transparent; color: var(--violet-light); font: inherit; font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer; padding: 0; }
.fin-limit-edit:hover { text-decoration: underline; }
/* Durée de la limite : case jours (gauche) + Indéterminé (droite) */
.fin-limit-dur { display: flex; align-items: center; gap: var(--e-10); margin-bottom: var(--e-14); flex-wrap: wrap; }
.fin-limit-dur-label { font-size: var(--t-mini); color: var(--text-3); margin-right: var(--e-2); }
.fin-limit-dur-input {
  width: 64px; text-align: center; font: inherit; font-size: var(--t-small);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-sm); color: var(--text-1); padding: var(--e-8) var(--e-8);
}
.fin-limit-dur-input:focus { outline: none; border-color: var(--violet); }
.fin-limit-dur-input:disabled { opacity: 0.4; }
.fin-limit-dur-unit { font-size: var(--t-base); color: var(--text-2); }
.fin-limit-dur-indet {
  font: inherit; font-size: var(--t-base); cursor: pointer; padding: var(--e-8) var(--e-12); border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-2); transition: var(--transi);
}
.fin-limit-dur-indet:hover { border-color: var(--border-strong); color: var(--text-1); }
.fin-limit-dur-indet.active { background: var(--violet-tint); border-color: var(--violet); color: var(--violet-soft); }
.fin-limit-main { display: flex; align-items: baseline; gap: var(--e-8); margin-bottom: var(--e-10); }
.fin-limit-cost { font-size: var(--t-display); font-weight: var(--fw-gras); color: var(--text-1); }
.fin-limit-card--reached .fin-limit-cost { color: var(--red); }
.fin-limit-thr { font-size: var(--t-small); color: var(--text-2); }
.fin-limit-bar { height: 10px; border-radius: var(--r-pilule); background: var(--bg-elevated); overflow: hidden; }
.fin-limit-bar-fill { height: 100%; border-radius: var(--r-pilule); background: var(--green); transition: width var(--t-long); }
.fin-limit-card--reached .fin-limit-bar-fill { background: var(--red); }
.fin-limit-card--off .fin-limit-bar-fill { background: var(--text-3); }
.fin-limit-accs { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--e-10); margin-top: var(--e-14); }
.fin-lim-acc { background: var(--surface); border-radius: var(--radius-sm); padding: var(--e-10) var(--e-12); }
.fin-lim-acc-top { display: flex; justify-content: space-between; gap: var(--e-8); font-size: var(--t-meta); color: var(--text-2); margin-bottom: var(--e-8); }
.fin-lim-acc-bar { height: 5px; border-radius: var(--r-pilule); background: var(--bg-elevated); overflow: hidden; }
.fin-lim-acc-bar > div { height: 100%; border-radius: var(--r-pilule); background: var(--green); }
.fin-lim-acc--reached .fin-lim-acc-bar > div { background: var(--red); }
.fin-lim-acc--reached .fin-lim-acc-top { color: var(--ose-text); }
/* Modale réglage seuil */
.fin-lim-hint { font-size: var(--t-meta); color: var(--text-3); margin: 0 0 var(--e-14); line-height: var(--lh-normal); }
.fin-lim-sub { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2); margin: var(--e-16) 0 var(--e-8); }
.fin-lim-row { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); margin-bottom: var(--e-8); }
.fin-lim-row label { font-size: var(--t-base); color: var(--text-1); }
.fin-lim-row input { width: 120px; padding: var(--e-8) var(--e-10); background: var(--surface); border: 1px solid var(--border-mid); border-radius: var(--radius-sm); color: var(--text-1); font: inherit; font-size: var(--t-base); text-align: right; }
.fin-lim-row input:focus { outline: none; border-color: var(--violet); }
.fin-lim-row--global input { font-weight: var(--fw-gras); }

.fin-balance { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--e-14); margin-bottom: var(--e-18); }
@media (max-width: 900px) { .fin-balance { grid-template-columns: 1fr; } }
.fin-bal-card { background: var(--surface-2); border: 1px solid var(--border-mid); border-radius: var(--radius); padding: var(--e-24) 26px; position: relative; overflow: hidden; }
.fin-bal-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; }
.fin-bal-card--total::before   { background: var(--violet-light, var(--violet-soft)); }
.fin-bal-card--avail::before   { background: var(--green); }
.fin-bal-card--pending::before { background: var(--amber); }
.fin-bal-label { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text-2); margin-bottom: var(--e-12); }
.fin-bal-val { font-size: 36px; /* libre : le solde du compte, seul chiffre de cette taille du site — le tasser sur 32 ou l'étirer sur 40 changerait l'équilibre de l'écran pour un unique élément */ font-weight: var(--fw-gras); line-height: var(--lh-un); }
.fin-bal-card--total   .fin-bal-val { color: var(--text-1); }
.fin-bal-card--avail   .fin-bal-val { color: var(--green); }
.fin-bal-card--pending .fin-bal-val { color: var(--amber); }
.fin-bal-hint { font-size: var(--t-meta); color: var(--text-3); margin-top: var(--e-10); }

.fin-kpis { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--e-14); margin-bottom: var(--e-18); }
@media (max-width: 1200px) { .fin-kpis { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 680px)  { .fin-kpis { grid-template-columns: repeat(2, 1fr); } }
.fin-kpi { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--e-16) var(--e-18); }
.fin-kpi-label { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-3); text-transform: uppercase; letter-spacing: var(--ls-large); margin-bottom: var(--e-8); }
.fin-kpi-val { font-size: var(--t-xl); font-weight: var(--fw-gras); color: var(--text-1); line-height: var(--lh-un); }
.fin-kpi--green  .fin-kpi-val { color: var(--green); }
.fin-kpi--violet .fin-kpi-val { color: var(--violet-light); }
.fin-kpi--amber  .fin-kpi-val { color: var(--amber); }
.fin-kpi--red    .fin-kpi-val { color: var(--red); }

.fin-cols { display: grid; grid-template-columns: 1.6fr 1fr; gap: var(--e-14); margin-bottom: var(--e-14); align-items: start; }
.fin-cols--half { grid-template-columns: 1fr 1fr; }
@media (max-width: 900px) { .fin-cols { grid-template-columns: 1fr; } }
.fin-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--e-18); }
/* Effet de survol identique aux cards du Dashboard (lift + ombre) */
.fin-kpi, .fin-card, .fin-bal-card { transition: transform var(--t-moyen) var(--c-pose), box-shadow var(--t-moyen) var(--c-pose), border-color var(--t-moyen) var(--c-pose); }
.fin-kpi:hover, .fin-card:hover, .fin-bal-card:hover { transform: translateY(-2px); box-shadow: 0 14px 34px -16px rgba(var(--th-ombre),0.7), inset 0 1px 0 var(--bg-elevated); }
.fin-card-title { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text-2); margin-bottom: var(--e-16); }

/* Graphe « Ventes au fil du temps » — aire dégradée + ligne lissée + survol */
.fin-chart { position: relative; }
.fin-chart-plot { position: relative; width: 100%; height: 200px; }
.fin-svg { width: 100%; height: 100%; display: block; }
.fin-chart-yl { position: absolute; inset: 0; pointer-events: none; }
.fin-chart-yl span { position: absolute; left: 0; transform: translateY(-50%); font-size: var(--t-micro); color: var(--text-3, rgba(var(--th-voile),0.4)); }
.fin-chart-cursor { position: absolute; inset: 0; pointer-events: none; }
.fin-chart-vline { position: absolute; top: 0; bottom: 0; width: 1px; background: rgba(var(--th-voile),0.22); }
.fin-chart-dot { position: absolute; width: 10px; height: 10px; border-radius: 50%; background: var(--cyan); border: 2px solid var(--surface, #14141e); transform: translate(-50%, -50%); box-shadow: 0 0 0 4px rgba(96,165,250,0.22); }
.fin-chart-tip { position: absolute; pointer-events: none; z-index: 4; background: rgba(var(--th-panneau-rgb),0.96); border: 1px solid rgba(var(--th-voile),0.12); border-radius: var(--r-sm); padding: var(--e-6) var(--e-10); white-space: nowrap; display: flex; flex-direction: column; gap: var(--e-1); }
.fin-chart-tip-d { font-size: var(--t-micro); color: var(--text-2); }
.fin-chart-tip-v { font-size: var(--t-meta); font-weight: var(--fw-gras); color: var(--text); }
.fin-chart-x { position: relative; height: 16px; margin-top: var(--e-6); }
.fin-chart-x span { position: absolute; transform: translateX(-50%); font-size: var(--t-micro); color: var(--text-3, rgba(var(--th-voile),0.4)); white-space: nowrap; }

.fin-row { display: flex; justify-content: space-between; align-items: center; gap: var(--e-12); padding: var(--e-10) 0; border-bottom: 1px solid var(--border); font-size: var(--t-base); }
.fin-row:last-child { border-bottom: 0; }
.fin-row-name { color: var(--text-1); font-weight: var(--fw-moyen); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fin-row-meta { color: var(--text-2); white-space: nowrap; flex-shrink: 0; }

/* Par compte — mini-widget */
.fin-acc { padding: var(--e-14) 0; border-bottom: 1px solid var(--border); }
.fin-acc:first-child { padding-top: 0; }
.fin-acc:last-child { border-bottom: 0; padding-bottom: 0; }
.fin-acc-head { display: flex; align-items: center; gap: var(--e-10); margin-bottom: var(--e-12); }
.fin-acc-avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--violet-tint); color: var(--violet-light); display: flex; align-items: center; justify-content: center; font-size: var(--t-base); font-weight: var(--fw-gras); flex-shrink: 0; }
.fin-acc-name { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }
.fin-acc-badge { margin-left: auto; flex-shrink: 0; font-size: var(--t-mini); font-weight: var(--fw-gras); color: var(--green); background: rgba(34,197,94,0.14); padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule); }
.fin-acc-wallet { margin-left: auto; flex-shrink: 0; font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--violet-soft);
  background: var(--violet-tint); border: 1px solid rgba(var(--th-accent-rgb),0.3); padding: var(--e-4) var(--e-10); border-radius: var(--r-sm);
  cursor: pointer; white-space: nowrap; transition: background var(--t-bref), border-color var(--t-bref), color var(--t-bref); }
.fin-acc-wallet:hover { background: var(--violet-tint-strong); border-color: rgba(var(--th-accent-rgb),0.5); color: var(--violet-light); }
.fin-acc--withdraw .fin-acc-avatar { background: rgba(34,197,94,0.16); color: var(--green); }
.fin-acc-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e-10); }
.fin-acc-metric { background: var(--surface-2); border-radius: var(--radius-sm); padding: var(--e-10) var(--e-12); }
.fin-acc-m-label { display: block; font-size: var(--t-mini); color: var(--text-3); margin-bottom: var(--e-6); }
.fin-acc-m-val { font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--text-1); }
.fin-acc-m-val--avail { color: var(--green); }
.fin-acc-m-val--pos { color: var(--green); }
.fin-acc-m-val--neg { color: var(--red); }

/* Listes scrollables (top articles, par compte, historique) */
.fin-top      { max-height: 220px; overflow-y: auto; margin: calc(var(--e-4) * -1) calc(var(--e-6) * -1) 0; padding: 0 var(--e-6); }
.fin-accounts { max-height: 360px; overflow-y: auto; margin: calc(var(--e-4) * -1) calc(var(--e-6) * -1) 0; padding: 0 var(--e-6); }

/* Historique des ventes */
.fin-sales { max-height: 360px; overflow-y: auto; margin: calc(var(--e-4) * -1) calc(var(--e-6) * -1) 0; padding: 0 var(--e-6); }
.fin-sale { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); padding: var(--e-10) 0; border-bottom: 1px solid var(--border); }
.fin-sale:last-child { border-bottom: 0; }
.fin-sale-main { min-width: 0; display: flex; flex-direction: column; gap: var(--e-2); }
.fin-sale-title { font-size: var(--t-base); font-weight: var(--fw-moyen); color: var(--text-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fin-sale-sub { font-size: var(--t-mini); color: var(--text-3); }
.fin-sale-right { display: flex; align-items: center; gap: var(--e-12); flex-shrink: 0; }
.fin-sale-price { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-1); min-width: 64px; text-align: right; }
.fin-sale-badge { font-size: var(--t-mini); font-weight: var(--fw-fort); padding: var(--e-4) 0; border-radius: var(--r-pilule); white-space: nowrap; min-width: 92px; text-align: center; }
.fin-sale-badge--pending { background: var(--moy-bg); color: var(--moy-text); }
.fin-sale-badge--done    { background: var(--safe-bg); color: var(--safe-text); }
.fin-sale-badge--cancel  { background: var(--ose-bg); color: var(--ose-text); }

.fin-empty { color: var(--text-3); font-size: var(--t-base); padding: var(--e-22) 0; text-align: center; width: 100%; }

/* ════════ Badge stock SHEIN sur les cartes robe ════════ */
.lib-card-stock-badge {
  position: absolute; top: 8px; left: 8px; z-index: 3;
  width: 22px; height: 22px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-base); font-weight: 900; line-height: var(--lh-un); color: var(--text);
  box-shadow: 0 2px 6px rgba(var(--th-ombre),0.35);
}
.lib-card-stock-badge.in      { background: var(--green); }
.lib-card-stock-badge.partial { background: var(--amber); }
.lib-card-stock-badge.out     { background: var(--red); }

/* Pastille stock par coloris (fiche robe) */
.dress-color-stock-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: 0 0 auto; margin-left: var(--e-2); }
.dress-color-stock-dot.in      { background: var(--green); box-shadow: 0 0 0 2px rgba(99,214,176,0.25); }
.dress-color-stock-dot.partial { background: var(--amber); box-shadow: 0 0 0 2px rgba(240,176,85,0.25); }
.dress-color-stock-dot.out     { background: var(--red); box-shadow: 0 0 0 2px rgba(224,85,107,0.25); }

/* Bouton de taille en rupture SHEIN (coloris actif) */
.dress-taille-btn.size-out {
  position: relative; color: var(--red); border-color: rgba(224,85,107,0.5);
}
.dress-taille-btn.size-out::after {
  content: ''; position: absolute; left: 12%; right: 12%; top: 50%; height: 1.5px;
  background: var(--red); transform: rotate(-12deg);
}

/* Animation du bouton refresh bibliothèque */
.lib-actions-trigger.spinning svg { animation: libSpin 0.8s linear; }
@keyframes libSpin { from { transform: rotate(0); } to { transform: rotate(360deg); } }

/* Badge ID #VB sur les cartes de la bibliothèque */
.lib-vb-badge {
  display: inline-flex; align-items: center;
  font-family: ui-monospace, monospace; font-size: var(--t-micro); font-weight: var(--fw-gras);
  letter-spacing: .3px; color: var(--accent, #8b7bf0);
  background: rgba(139,123,240,.14); border: 1px solid rgba(139,123,240,.30);
  border-radius: var(--r-micro); padding: var(--e-1) var(--e-6); line-height: var(--lh-normal);
}
/* Badge entrepôt : EU = vert (rapide 3-5 j) · CN = rouge (~1,5 sem) */
.lib-wh-badge { display: inline-flex; align-items: center; font-size: var(--t-micro); font-weight: 800;
  letter-spacing: .4px; border-radius: var(--r-micro); padding: var(--e-1) var(--e-6); line-height: var(--lh-normal); }
.lib-wh-badge--eu { color: var(--green); background: rgba(99,214,176,.16); border: 1px solid rgba(99,214,176,.34); }
.lib-wh-badge--cn { color: var(--red); background: rgba(var(--th-danger-rgb),.15); border: 1px solid var(--danger-bord); }

/* Menus déroulants de la fiche robe (catégorie, couleur, gamme) : options LISIBLES
   (texte noir sur fond blanc) quand le menu natif s'ouvre — sinon texte clair illisible. */
.dress-gamme-select option { color: #14141a; background: var(--text); }

/* Chips de taille (génération) : rupture SHEIN (barré) + taille absente du produit */
.size-chip.size-out {
  position: relative; color: var(--red); border-color: rgba(224,85,107,0.5);
}
.size-chip.size-out::after {
  content: ''; position: absolute; left: 12%; right: 12%; top: 50%; height: 1.5px;
  background: var(--red); transform: rotate(-12deg);
}
.size-chip.size-unavail { opacity: 0.32; }

/* ═══════════════════ SECTION BATCH ═══════════════════ */
.batch-view { width: 100%; margin: 0 auto; }  /* remplit la largeur comme Post/Repost : .section-canvas est en flex, un bloc simple ne s'étirait pas (restait ~822px) → width:100% le fait remplir l'espace sur grand écran */
.batch-config-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-16); }
@media (max-width: 760px){ .batch-config-grid{ grid-template-columns:1fr; } }
.batch-card {
  background: var(--surface-2, var(--surface));
  border: 1px solid var(--border, rgba(var(--th-voile),0.08));
  border-radius: var(--r-lg); padding: var(--e-16); margin-bottom: var(--e-16);
}
.batch-card-head { display:flex; align-items:center; justify-content:space-between; gap:var(--e-10); margin-bottom:var(--e-12); }
.batch-card-title { font-weight:var(--fw-gras); font-size:var(--t-small); color: var(--text, var(--text)); }
.batch-counter { font-size:var(--t-meta); color: var(--violet-light,#b9a8ff); background:rgba(139,123,240,.14); border-radius: var(--r-sm); padding:var(--e-2) var(--e-8); }
.batch-pick-btn { width:100%; justify-content:center; }
.batch-empty { margin-top:var(--e-12); text-align:center; color: var(--text-3,var(--text-3)); font-size:var(--t-base); padding:var(--e-14); border:1px dashed var(--border,rgba(var(--th-voile),.1)); border-radius: var(--r-md); }
.batch-thumb-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(84px,1fr)); gap:var(--e-8); margin-top:var(--e-12); }
.batch-dress-thumb { position:relative; border-radius: var(--r-md); overflow:hidden; aspect-ratio:3/4; background:rgba(var(--th-ombre),.25); }
.batch-dress-thumb img { width:100%; height:100%; object-fit:cover; display:block; }
.batch-dress-lbl { position:absolute; left:0; right:0; bottom:0; font-size:var(--t-micro); padding:var(--e-4) var(--e-6); background:linear-gradient(transparent,rgba(var(--th-ombre),.8)); color: var(--sur-sombre); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.batch-dress-rm { position:absolute; top:3px; right:3px; width:18px; height:18px; border:none; border-radius:50%; background:rgba(var(--th-ombre),.6); color: var(--sur-sombre); cursor:pointer; font-size:var(--t-base); line-height:var(--lh-un); }
.batch-sku-row { display:flex; gap:var(--e-8); margin-top:var(--e-12); }
.batch-input { flex:1; background:rgba(var(--th-ombre),.25); border:1px solid var(--border,rgba(var(--th-voile),.1)); border-radius: var(--r-md); padding:var(--e-8) var(--e-12); color:var(--text,var(--text)); font-size:var(--t-base); }
.batch-input::placeholder { color: var(--text-3,var(--text-3)); }
.batch-name-input { flex:0 0 200px; }
.batch-sku-info { font-size:var(--t-meta); color:var(--text-3,var(--text-3)); margin-top:var(--e-6); }
.batch-est-row { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--e-10); margin-bottom:var(--e-14); }
.batch-est-cell { text-align:center; background:rgba(var(--th-ombre),.2); border-radius: var(--r-md); padding:var(--e-10) var(--e-6); }
.batch-est-val { font-size:var(--t-lead); font-weight:800; color:var(--violet-light,#b9a8ff); }
.batch-est-lbl { font-size:var(--t-mini); color:var(--text-3,var(--text-3)); margin-top:var(--e-2); }
.batch-budget-row { display:flex; align-items:center; gap:var(--e-10); margin-bottom:var(--e-12); }
.batch-budget-row label { font-size:var(--t-base); color:var(--text-2,var(--text)); }
.batch-budget-row .batch-input { flex:0 0 120px; }
.batch-note { font-size:var(--t-base); color:var(--text-2,var(--text)); margin-bottom:var(--e-14); }
.batch-launch-row { display:flex; gap:var(--e-10); justify-content:flex-end; }
.batch-prog-head { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--e-12); margin-bottom:var(--e-16); }
.batch-prog-title { font-weight:var(--fw-gras); font-size:var(--t-body); color:var(--text,var(--text)); }
.batch-prog-sub { font-size:var(--t-base); color:var(--text-3,var(--text-3)); margin-top:var(--e-4); }
.batch-prog-controls { display:flex; gap:var(--e-8); }
.batch-btn-danger { color:var(--red) !important; }
.batch-progbar { margin-bottom:var(--e-16); }
.batch-progbar-track { height:10px; background:rgba(var(--th-ombre),.3); border-radius: var(--r-sm); overflow:hidden; }
.batch-progbar-fill { height:100%; width:0%; background:linear-gradient(90deg,var(--violet),#b9a8ff); transition:width var(--t-long) var(--c-pose); }
.batch-progbar-row { display:flex; justify-content:space-between; font-size:var(--t-base); color:var(--text-2,var(--text)); margin-top:var(--e-6); }
.batch-progbar-sub { font-size:var(--t-meta); color:var(--text-3,var(--text-3)); margin-top:var(--e-4); }
.batch-stats { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--e-10); margin-bottom:var(--e-16); }
.batch-stat { text-align:center; background:rgba(var(--th-ombre),.2); border-radius: var(--r-md); padding:var(--e-10); }
.batch-stat-val { font-size:var(--t-title); font-weight:800; color:var(--text,var(--text)); }
.batch-stat-lbl { font-size:var(--t-mini); color:var(--text-3,var(--text-3)); }
.batch-combo { display:flex; align-items:center; justify-content:center; gap:var(--e-18); background:rgba(var(--th-ombre),.2); border-radius: var(--r-lg); padding:var(--e-14); margin-bottom:var(--e-14); }
.batch-combo-side { display:flex; align-items:center; gap:var(--e-10); }
.batch-combo-thumb { width:48px; height:60px; border-radius: var(--r-sm); overflow:hidden; background:var(--bg-elevated); }
.batch-combo-thumb img { width:100%; height:100%; object-fit:cover; }
.batch-combo-name { font-weight:var(--fw-fort); font-size:var(--t-small); color:var(--text,var(--text)); }
.batch-combo-sub { font-size:var(--t-meta); color:var(--text-3,var(--text-3)); }
.batch-visuals-row { display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); gap:var(--e-10); }
.batch-visual-slot { position:relative; aspect-ratio:3/4; border-radius: var(--r-md); overflow:hidden; background:rgba(var(--th-ombre),.25); border:1px solid var(--border,rgba(var(--th-voile),.08)); display:flex; align-items:center; justify-content:center; }
.batch-visual-slot img { width:100%; height:100%; object-fit:cover; }
.batch-visual-slot-lbl { position:absolute; left:0; right:0; bottom:0; display:flex; align-items:center; justify-content:space-between; padding:var(--e-4) var(--e-8); font-size:var(--t-mini); color: var(--sur-sombre); background:linear-gradient(transparent,rgba(var(--th-ombre),.75)); }
.batch-visual-spinner { width:12px; height:12px; border:2px solid rgba(var(--th-voile),.3); border-top-color: var(--sur-accent); border-radius:50%; animation:bspin 0.7s linear infinite; }
.batch-visual-done { color:var(--green); font-weight:var(--fw-gras); }
.batch-visual-error { color:var(--red); font-weight:var(--fw-gras); }
@keyframes bspin { to { transform:rotate(360deg); } }
.spin-icon { animation:bspin 0.7s linear infinite; }
.batch-results-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--e-16); }
.batch-results-title { font-weight:var(--fw-gras); font-size:var(--t-body); color:var(--text,var(--text)); }
.batch-results-sub { font-size:var(--t-base); color:var(--text-3,var(--text-3)); margin-top:var(--e-2); }
.batch-recap-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--e-12); margin-bottom:var(--e-16); }
.batch-recap-card { background:var(--surface-2,var(--surface)); border:1px solid var(--border,rgba(var(--th-voile),.08)); border-radius: var(--r-lg); padding:var(--e-14); text-align:center; }
.batch-recap-card.err { border-color:rgba(var(--th-danger-rgb),.3); }
.batch-recap-val { font-size:var(--t-xl); font-weight:800; }
.batch-recap-val.g{color:var(--green);} .batch-recap-val.r{color:var(--red);} .batch-recap-val.v{color:var(--violet-soft);} .batch-recap-val.c{color:var(--amber);}
.batch-recap-lbl { font-size:var(--t-meta); color:var(--text-3,var(--text-3)); margin-top:var(--e-4); }
.batch-results-actions { display:flex; flex-wrap:wrap; gap:var(--e-8); margin-bottom:var(--e-16); }
.batch-results-list { display:flex; flex-direction:column; gap:var(--e-10); }
.batch-result-dress-row { border:1px solid var(--border,rgba(var(--th-voile),.08)); border-radius: var(--r-lg); overflow:hidden; }
.batch-result-dress-header { display:flex; align-items:center; gap:var(--e-10); padding:var(--e-10) var(--e-12); cursor:pointer; background:var(--cok-bg-2); }
.batch-result-dress-thumb { width:38px; height:48px; border-radius: var(--r-sm); object-fit:cover; }
.batch-result-dress-name { font-weight:var(--fw-fort); font-size:var(--t-small); color:var(--text,var(--text)); flex:1; }
.batch-result-dress-count { font-size:var(--t-meta); color:var(--text-3,var(--text-3)); }
.batch-result-badge { font-size:var(--t-mini); padding:var(--e-2) var(--e-8); border-radius: var(--r-sm); }
.batch-result-badge.ok { background:rgba(74,222,128,.15); color:var(--green); }
.batch-result-badge.err { background:rgba(248,113,113,.15); color:var(--red); }
.batch-result-dress-posts { display:grid; grid-template-columns:repeat(auto-fill,minmax(110px,1fr)); gap:var(--e-8); padding:var(--e-12); }
.batch-post-mini { border-radius: var(--r-md); overflow:hidden; background:rgba(var(--th-ombre),.25); }
.batch-post-mini-img img { width:100%; display:block; }
.batch-post-mini.failed { border:1px solid rgba(248,113,113,.3); }
.batch-post-mini-error { padding:var(--e-14) var(--e-8); text-align:center; color:var(--red); font-size:var(--t-meta); }
.batch-history-list { display:flex; flex-direction:column; gap:var(--e-10); }
.batch-model-item { display:flex; align-items:center; gap:var(--e-10); padding:var(--e-8); border-radius: var(--r-md); cursor:pointer; border:1px solid transparent; }
.batch-model-item.selected { border-color:var(--cok-accent,var(--cyan)); background:rgba(var(--th-accent-rgb),.1); }
.batch-model-check { width:18px; height:18px; border-radius:50%; background:var(--cok-accent,var(--cyan)); display:flex; align-items:center; justify-content:center; }
.batch-model-avatar { width:40px; height:50px; border-radius: var(--r-sm); object-fit:cover; background:var(--bg-elevated); }
.batch-model-name { font-size:var(--t-small); color:var(--text,var(--text)); }
.batch-model-sub { font-size:var(--t-meta); color:var(--text-3,var(--text-3)); }
.batch-picker-overlay { position:fixed; inset:0; z-index:9000; background:rgba(var(--th-ombre),.6); display:flex; align-items:center; justify-content:center; padding:var(--e-20); }
.batch-picker-panel { width:min(820px,96vw); max-height:88vh; display:flex; flex-direction:column; background:var(--surface,#141826); border:1px solid var(--border,rgba(var(--th-voile),.1)); border-radius: var(--r-xl); overflow:hidden; }
.batch-picker-header { display:flex; align-items:center; gap:var(--e-12); padding:var(--e-14) var(--e-18); border-bottom:1px solid var(--border,rgba(var(--th-voile),.08)); }
.batch-picker-title { font-weight:var(--fw-gras); font-size:var(--t-small); color:var(--text,var(--text)); flex:1; }
.batch-picker-count { font-size:var(--t-base); color:var(--violet-light,#b9a8ff); }
.batch-picker-close { background:none; border:none; color:var(--text-3,var(--text-3)); font-size:var(--t-lead); cursor:pointer; }
.batch-picker-grid { display:grid !important; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)) !important; gap:var(--e-14) !important; padding:var(--e-18) !important; overflow-y:auto; }
.batch-picker-card { position:relative; border-radius: var(--r-lg); overflow:hidden !important; cursor:pointer; border:2px solid transparent; background:rgba(var(--th-voile),.04); }
.batch-picker-card.selected { border-color:var(--cok-accent,var(--cyan)); }
/* image portrait GARANTIE (img en absolu dans un conteneur 3:4) → plus de vignettes écrasées */
.batch-picker-card-cover { position:relative !important; width:100%; aspect-ratio:3/4 !important; height:auto !important; background:var(--bg-hover); }
.batch-picker-card-cover img { position:absolute !important; inset:0 !important; width:100% !important; height:100% !important; object-fit:cover !important; display:block; }
.batch-picker-card-info { padding:var(--e-8) var(--e-10); }
.batch-picker-card-name { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--text,var(--text)); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.batch-picker-card-meta { font-size:var(--t-mini); color:var(--text-3,var(--text-3)); margin-top:var(--e-2); }
.batch-picker-check { position:absolute; top:7px; right:7px; width:20px; height:20px; border-radius:50%; background:var(--cok-accent,var(--cyan)); display:none; align-items:center; justify-content:center; }
.batch-picker-card.selected .batch-picker-check { display:flex; }
.batch-picker-footer { padding:var(--e-14) var(--e-18); border-top:1px solid var(--border,rgba(var(--th-voile),.08)); display:flex; justify-content:flex-end; }
.batch-autodraft-row { display:flex; align-items:center; gap:var(--e-10); margin-bottom:var(--e-14); font-size:var(--t-base); color:var(--text-2,var(--text)); cursor:pointer; }
.batch-autodraft-row input { width:16px; height:16px; accent-color:var(--cok-accent,var(--cyan)); cursor:pointer; }
.batch-autodraft-row b { color:var(--violet-light,#b9a8ff); }
.batch-post-draft { font-size:var(--t-micro); padding:var(--e-2) var(--e-6); border-radius:var(--r-micro); margin-top:var(--e-4); display:inline-block; }
.batch-post-draft.ok { background:rgba(74,222,128,.15); color:var(--green); }
.batch-post-draft.err { background:rgba(248,113,113,.15); color:var(--red); }

/* Picker de génération réutilisé en MULTI-SÉLECTION (batch) */
.lib-picker-footer { display:flex; align-items:center; justify-content:space-between; gap:var(--e-14); padding:var(--e-14) var(--e-18); border-top:1px solid var(--border,rgba(var(--th-voile),.08)); background:var(--bg-2,rgba(var(--th-ombre),.2)); }
.lib-picker-mcount { font-size:var(--t-base); color:var(--violet-light,#b9a8ff); font-weight:var(--fw-fort); }
.lib-picker-card { position:relative; }
.lib-picker-card--sel { outline:2px solid var(--cok-accent,var(--cyan)); outline-offset:-2px; }
.lib-picker-mcheck { position:absolute; top:8px; right:8px; width:22px; height:22px; border-radius:50%; background:rgba(var(--th-ombre),.45); border:2px solid #fff; display:flex; align-items:center; justify-content:center; opacity:.5; transition:opacity var(--t-bref), background var(--t-bref); z-index:2; }
.lib-picker-card--sel .lib-picker-mcheck { opacity:1; background:var(--cok-accent,var(--cyan)); }
/* Pastille du coloris choisi (multi-sélection robes) */
.lib-picker-coloris-tag { position:absolute; left:6px; bottom:6px; z-index:2; background:rgba(var(--th-ombre),.6); backdrop-filter:blur(3px); color: var(--sur-sombre); max-width:calc(100% - 12px); }
.lib-picker-coloris-tag span:last-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.lib-picker-coloris-tag .coloris-dot { width:9px; height:9px; border-radius:50%; flex-shrink:0; }
/* Plusieurs coloris choisis (robe multi-coloris) : pile de pastilles en bas de la carte */
.lib-picker-coloris-tags { position:absolute; left:6px; right:6px; bottom:6px; z-index:2; display:flex; flex-wrap:wrap; gap:var(--e-4); }
.lib-picker-coloris-tags .lib-picker-coloris-tag { position:static; left:auto; right:auto; bottom:auto; max-width:100%; }

/* Batch — divers ajouts */
.batch-results-hint { font-size:var(--t-base); color:var(--text-3,var(--text-3)); font-style:italic; }
.batch-post-mini-noimg { aspect-ratio:3/4; display:flex; align-items:center; justify-content:center; color:var(--text-3,var(--text-3)); font-size:var(--t-meta); background:rgba(var(--th-ombre),.25); }

/* Aperçu type annonce Vinted (clic sur un post du batch) */
.batch-preview-overlay { position:fixed; inset:0; z-index:9200; background:var(--voile); backdrop-filter:var(--voile-flou); -webkit-backdrop-filter:var(--voile-flou); display:flex; align-items:flex-start; justify-content:center; padding:var(--e-28) var(--e-16); overflow-y:auto; }
.batch-preview-panel { width:min(720px,96vw); background:var(--surface,#141826); border:1px solid var(--border,rgba(var(--th-voile),.1)); border-radius: var(--r-xl); overflow:hidden; position:relative; }
.batch-preview-close { position:absolute; top:10px; right:12px; z-index:3; width:30px; height:30px; border-radius:50%; border:none; background:rgba(var(--th-ombre),.5); color: var(--sur-sombre); font-size:var(--t-body); cursor:pointer; }
.batch-preview-photos { display:flex; gap:var(--e-6); overflow-x:auto; background:var(--bg); padding:var(--e-8); scroll-snap-type:x mandatory; }
.batch-preview-photos img { height:360px; border-radius: var(--r-sm); object-fit:cover; scroll-snap-align:center; flex:0 0 auto; }
.batch-preview-photos--empty { height:120px; align-items:center; justify-content:center; color:var(--text-3,var(--text-3)); font-size:var(--t-base); }
.batch-preview-flag { padding:var(--e-10) var(--e-14); background:rgba(251,191,36,.12); color:var(--amber); font-size:var(--t-base); border-bottom:1px solid rgba(251,191,36,.2); }
.batch-preview-body { display:flex; gap:var(--e-18); padding:var(--e-18); }
@media (max-width:560px){ .batch-preview-body{ flex-direction:column; } .batch-preview-photos img{ height:260px; } }
.batch-preview-main { flex:1; min-width:0; }
.batch-preview-title { font-size:var(--t-body); font-weight:var(--fw-gras); color:var(--text,var(--text)); margin-bottom:var(--e-10); }
.batch-preview-desc { font-size:var(--t-small); line-height:var(--lh-normal); color:var(--text-2,var(--text)); white-space:pre-wrap; }
.batch-preview-side { flex:0 0 180px; border-left:1px solid var(--border,rgba(var(--th-voile),.08)); padding-left:var(--e-16); }
.batch-preview-price { font-size:var(--t-xl); font-weight:800; color:var(--green); margin-bottom:var(--e-14); }
.batch-preview-meta { font-size:var(--t-base); color:var(--text,var(--text)); margin-bottom:var(--e-10); }
.batch-preview-meta-lbl { display:block; font-size:var(--t-mini); text-transform:uppercase; letter-spacing:.4px; color:var(--text-3,var(--text-3)); margin-bottom:var(--e-2); }

/* ═══ Génération sur PORTABLE : plus de débordement horizontal (annonce rognée aux 2 bouts) ═══
   Cause : grid 1fr+300px de .listing-section dont le min-content remontait jusqu'au body →
   scrollbar horizontale. Fix : min-width:0 partout + wrap + empilement sous 1560px. */
.gen-output, .results-section, .listing-section { min-width: 0; }
.listing-section > * { min-width: 0; }
.listing-col { min-width: 0; overflow-wrap: break-word; }
.listing-id-row { flex-wrap: wrap; row-gap: var(--e-8); }
@media (max-width: 1560px) {
  /* L'annonce s'empile : panneau Prix/Infos/Mesures SOUS le titre/description, pleine largeur */
  .listing-section { grid-template-columns: 1fr !important; }
}

/* ═══════════ Batch — RESPONSIVITÉ (chantier A, 2026-07-10) ═══════════
   Champs élastiques + grilles 4 col qui se replient (2 puis 1) + rien qui déborde.
   Ajouté en fin de cascade → override propre des largeurs fixes, sans toucher l'existant. */
.batch-sku-row, .batch-budget-row { flex-wrap: wrap; }
.batch-sku-row > *, .batch-budget-row > *, .batch-launch-row > *,
.batch-est-cell, .batch-stat, .batch-recap-card { min-width: 0; }
@media (max-width: 760px) {
  .batch-est-row, .batch-stats, .batch-recap-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .batch-preview-side { flex: 1 1 auto; min-width: 0; border-left: none;
    border-top: 1px solid var(--border, rgba(var(--th-voile),.08)); padding-left: 0; padding-top: var(--e-16); }
}
@media (max-width: 480px) {
  .batch-name-input { flex: 1 1 100%; }
  .batch-budget-row .batch-input { flex: 1 1 100%; }
  .batch-combo { flex-direction: column; gap: var(--e-10); }
  .batch-launch-row, .batch-prog-controls, .batch-results-actions { flex-wrap: wrap; }
  .batch-result-dress-posts { grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: var(--e-6); }
}

/* ═══════════ Vues produit — REFONTE (chantier B) + VÉRIF AUTO/GATE (chantier C), 2026-07-10 ═══════════ */
/* Grille de résultats responsive, scoppée à #pv-results-grid pour NE PAS toucher les vues Demandes.
   Vise ~4 GRANDES cartes sur grand écran (clamp 23% ≈ 1/4), 2 sur petit écran — utilise la place
   dispo sans forcer le scroll. */
#pv-results-grid.dem-photos-results {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(clamp(230px, 23%, 340px), 1fr));
  gap: var(--e-16);
}
#pv-results-grid .card-wrapper { flex: none; max-width: none; }
@media (max-width: 620px) {
  #pv-results-grid.dem-photos-results { grid-template-columns: repeat(2, 1fr); gap: var(--e-10); }
}
/* Badge de conformité en bas à droite, plus grand/lisible (adapté au grand écran) */
#pv-results-grid .gen-verify-badge {
  top: auto; bottom: 10px; right: 10px;
  font-size: var(--t-base); padding: var(--e-6) var(--e-12); font-weight: var(--fw-fort); border-radius: var(--r-pilule);
}
#pv-results-grid .gvb-spin { width: 11px; height: 11px; }
/* Bouton d'annulation sous la CTA — MÊME taille que « Générer » (pleine largeur, même gabarit) */
.pv-cancel-row { margin-top: var(--e-10); }
#pv-btn-cancel {
  width: 100%;
  justify-content: center;
  padding: var(--e-14) var(--e-28);
  border-radius: var(--r-md);
  font-size: var(--t-body);
  font-weight: var(--fw-moyen);
}
/* L'état vide et la rangée de pastilles ont ete retires avec l'ecran qui les portait
   (04/09) : plus un seul lecteur dans index.html ni dans app.js. */
/* Compteur de progression X/N dans le header résultats */
.pv-progress { font-size: var(--t-meta); font-weight: var(--fw-moyen); color: var(--text-3); margin-left: var(--e-10); }
/* Blocage de la sauvegarde tant qu'une vue reste non conforme non confirmée */
.results-header-actions.gated { opacity: .6; }
.results-header-actions.gated #pv-btn-save-lib { cursor: not-allowed; }

/* Vue manquante : l'étiquette s'estompe pour qu'on repère le trou d'un coup d'œil. */
.model-slot-label.vide { color: var(--text-3); opacity: .75; }

/* ── Bandeau « ventes vers le plafond » (onglet Sa voiture) ───────────────────
   Hors de la grille des champs : celui-ci se CALCULE, il ne se remplit pas. */
.model-plafond {
  display: flex; align-items: center; gap: var(--e-16); flex-wrap: wrap;
  margin-top: var(--e-4); padding: var(--e-14) var(--e-16);
  border: 1px solid rgba(var(--th-second-rgb),.28); border-radius: var(--r-md);
  background: rgba(var(--th-second-rgb),.06);
}
.model-plafond-texte { display: flex; flex-direction: column; gap: var(--e-4); min-width: 0; }
.model-plafond-titre { font-size: var(--t-base); color: var(--text); font-weight: var(--fw-moyen); }
.model-plafond-chiffres { font-size: var(--t-meta); color: var(--text-2); }
.model-plafond-piste {
  flex: 1; min-width: 120px; height: 6px; border-radius: var(--r-micro);
  background: rgba(var(--th-voile),.09); overflow: hidden;
}
.model-plafond-piste > i { display: block; height: 100%; width: 0; border-radius: var(--r-micro); background: var(--cyan); transition: width var(--t-long); }
.model-plafond-note { font-size: var(--t-mini); color: var(--text-3); white-space: nowrap; }
.model-plafond.proche { border-color: rgba(224,164,59,.4); background: rgba(224,164,59,.07); }
.model-plafond.proche .model-plafond-piste > i { background: var(--amber); }
.model-plafond.plein  { border-color: rgba(248,113,113,.4); background: rgba(248,113,113,.07); }
.model-plafond.plein  .model-plafond-piste > i { background: var(--red); }

/* ══ LA VIE DU COMPTE, EN HAUT DE LA COLONNE (04/09) ═════════════════════════
   Amadou : « en haut avec le petit bouton "son espace modèle" ça fait vide, trouve une
   solution ». Un compte meurt à 29 ventes ou 2 000 € ; le chiffre dormait dans l'onglet
   « Son activité ». Il monte à côté du visage.
   ⚠️ MÊMES COULEURS QUE LA JAUGE D'ORIGINE (`.model-plafond`) : ambre à l'approche,
   rouge au plafond. C'est le même fait, il ne peut pas se dire de deux façons.
   ⚠️ EMPILÉE, PAS EN LIGNE. La colonne fait ~4/13 de la fiche : la version en ligne
   (texte | piste | note) s'y serait cassée en trois. Trois étages tiennent dans la
   largeur qui reste à droite du rond. */
/* ⚠️ PLUS DE MARGE BASSE (04/09). Elle écartait la jauge du bouton « Son espace
   modèle » ; celui-ci est descendu en pied de panneau, et la marge décalait alors la
   jauge vers le haut au lieu de la centrer sur le rond. Seule dans sa colonne, elle se
   centre d'elle-même — `.model-info-avatar-section` est déjà en `align-items: center`. */
.model-vie { width: 100%; }
.model-vie-tete { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--e-8); margin-bottom: var(--e-6); }
.model-vie-t { font-size: var(--t-mini); color: var(--text-3); }
.model-vie-n { font-size: var(--t-meta); font-weight: var(--fw-moyen); color: var(--text); }
.model-vie-piste { height: var(--e-4); border-radius: var(--r-micro);
  background: rgba(var(--th-voile), .09); overflow: hidden; }
.model-vie-piste > i { display: block; height: 100%; width: 0;
  border-radius: var(--r-micro); background: var(--green); transition: var(--transi); }
.model-vie-sous { margin-top: var(--e-6); font-size: var(--t-mini); color: var(--text-3); }
.model-vie.proche .model-vie-piste > i { background: var(--amber); }
.model-vie.proche .model-vie-n { color: var(--amber); }
.model-vie.plein  .model-vie-piste > i { background: var(--red); }
.model-vie.plein  .model-vie-n { color: var(--red); }

/* ⚠️ LA SORTIE EN PIED DE PANNEAU — la place qu'occupait « Détacher ce compte ». Elle
   s'en sépare par un filet : ce n'est plus une donnée du compte, c'est un départ. */
.model-sortie { margin-top: var(--e-20); padding-top: var(--e-14);
  border-top: var(--e-1) solid var(--border); }

/* ══ LE CHOIX DE LA FAMILLE, DÉPLIABLE (04/09) ═══════════════════════════════
   Amadou : « la partie choix de la famille doit être optionnel ». Huit tuiles pleine
   largeur pour filtrer deux comptes prenaient plus de place que la liste elle-même.
   ⚠️ La bascule reste toujours visible : un filtre qu'on ne voit pas est un filtre qu'on
   oublie, et c'est ainsi qu'un écran finit par mentir sur ce qu'il montre. Quand un
   filtre est posé, elle le NOMME (« Famille : Vêtements ») au lieu de dire « Filtrer ». */
.cp-fam-bascule {
  display: inline-flex; align-items: center; gap: var(--e-6);
  margin-bottom: var(--e-12); padding: var(--e-6) var(--e-10);
  font: inherit; font-size: var(--t-meta); cursor: pointer;
  color: var(--text-3); background: transparent;
  border: var(--e-1) solid var(--border); border-radius: var(--r-pilule);
  transition: var(--transi);
}
.cp-fam-bascule:hover { color: var(--text); border-color: var(--border-strong); }
.cp-fam-bascule.on { color: var(--th-accent-clair); border-color: var(--cok-accent); }
.cp-fam-fl { display: flex; }
.cp-fam-fl svg { width: var(--e-12); height: var(--e-12); transition: var(--transi); }
.cp-fam-bascule.on .cp-fam-fl svg { transform: rotate(180deg); }

/* ⚠️ LE COMPTEUR DE VUES A REJOINT LE TIROIR. La ligne « Ses vues · 3 sur 3 » répétait
   ce que le tiroir dit deux lignes plus haut, mais sa COULEUR ne se répétait pas :
   l'ambre est le seul signal qui dise « ce pack est incomplet ». */
/* ⚠️ `.pk-tir-s--manque` retirée avec le tiroir : le signal « pack incomplet » vit
   maintenant dans la FORME : un emplacement en pointillés (`.pk-l-v--vide`). */

/* ── En-tête de la fiche vendeuse : son NOM, puis son code de compte ────────── */
.model-detail-code {
  font-size: var(--t-meta); font-weight: var(--fw-fort); letter-spacing: var(--ls-large);
  padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule); white-space: nowrap; align-self: center;
  background: rgba(var(--th-voile),.07); color: var(--text-2);
}
.model-detail-statut {
  font-size: var(--t-meta); font-weight: var(--fw-fort); padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule);
  white-space: nowrap; align-self: center;
}

/* ── Détacher la voiture + ses anciennes voitures (onglet Sa voiture) ───────── */
.model-detacher { align-self: flex-start; margin-top: var(--e-2); }
.model-detacher:hover { border-color: rgba(248,113,113,.45); color: var(--red); }
.model-anciennes {
  margin-top: var(--e-4); padding-top: var(--e-14); border-top: 1px solid var(--border);
}
.model-anciennes-titre { font-size: var(--t-meta); color: var(--text-3); margin-bottom: var(--e-8); }
.model-ancienne {
  display: flex; align-items: center; gap: var(--e-12); flex-wrap: wrap;
  padding: var(--e-8) 0; border-bottom: 1px solid var(--border);
}
.model-ancienne:last-child { border-bottom: 0; }
.model-ancienne-nom { font-size: var(--t-base); color: var(--text-2); flex: 1; min-width: 0;
  font-family: ui-monospace, Menlo, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.model-ancienne-motif { font-size: var(--t-meta); white-space: nowrap; }
.model-ancienne-date { font-size: var(--t-meta); color: var(--text-3); white-space: nowrap; }

/* Vendeuse en formation dans le Batch : verrouillée, pas seulement grisée. */
.batch-model-item.en-formation { opacity: .55; cursor: not-allowed; }
.batch-model-item.en-formation:hover { background: transparent; border-color: var(--border); }
.batch-model-item.en-formation .batch-model-check { visibility: hidden; }

/* Vendeuse en formation dans le sélecteur : visible mais non sélectionnable. */
.lib-picker-card--verrou { opacity: .5; cursor: not-allowed; }
.lib-picker-card--verrou:hover { transform: none; border-color: var(--border); }

/* Code de compte sur la carte d'une vendeuse : discret, à côté de son nom. */
.lib-card-code { letter-spacing: var(--ls-large); margin-left: var(--e-6); flex: none;
  background: rgba(var(--th-voile),.08); color: var(--text-3); }

/* Filtre dont le compteur tombe à 0 sous l'autre filtre : visible mais éteint. */
.lib-tier-tab.vide { opacity: .38; }

/* ── Pastilles « case à renseigner » ──────────────────────────────────────────
   Même ambre que le statut « À compléter » : on relie l'onglet, la case et le statut
   d'un seul coup d'œil. */
.champ-manque, .model-tab-manque {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--amber); flex: none; vertical-align: middle;
}
.champ-manque { margin-left: var(--e-6); }
.model-tab-manque { margin-left: var(--e-8); }

/* ══ ASSISTANT DE CRÉATION GOOGLE (mode assistance pure) ══════════════════════ */
.srcg-asst { max-width: 560px; width: 92vw; }
.srcg-asst-note {
  display: flex; gap: var(--e-10); align-items: flex-start;
  margin: 0 var(--e-22) var(--e-4); padding: var(--e-12) var(--e-14);
  background: rgba(110,210,168,0.07); border: 1px solid rgba(110,210,168,0.22);
  border-radius: var(--radius-sm); color: var(--text-1); font-size: var(--t-base); line-height: var(--lh-normal);
}
.srcg-asst-note svg { flex: 0 0 auto; margin-top: var(--e-1); color: var(--green); }
.srcg-asst-note b { font-weight: var(--fw-fort); }
.srcg-asst-body { padding: var(--e-6) var(--e-22) var(--e-4); display: flex; flex-direction: column; gap: var(--e-10); }
.srcg-asst-block-tt {
  margin-top: var(--e-8); font-size: var(--t-mini); letter-spacing: var(--ls-large); text-transform: uppercase;
  color: var(--text-3); font-weight: var(--fw-fort);
}
.srcg-asst-row { display: flex; align-items: center; gap: var(--e-10); }
.srcg-asst-lab { flex: 0 0 138px; font-size: var(--t-base); color: var(--text-2); }
.srcg-asst-val { flex: 1; display: flex; align-items: center; gap: var(--e-6); }
.srcg-asst-inp {
  flex: 1; min-width: 0; padding: var(--e-8) var(--e-10); font-size: var(--t-base);
  background: var(--bg-input); border: 1px solid var(--border-mid);
  border-radius: var(--radius-xs); color: var(--text-1);
}
.srcg-asst-inp:focus { outline: none; border-color: var(--border-strong); }
.srcg-asst-inp--sm { flex: 0 0 120px; }
.srcg-asst-mini, .srcg-asst-copy {
  display: inline-flex; align-items: center; gap: var(--e-4); cursor: pointer;
  background: var(--bg-elevated); border: 1px solid var(--border-mid);
  border-radius: var(--radius-xs); color: var(--text-2);
}
.srcg-asst-mini { padding: var(--e-8); }
.srcg-asst-copy { padding: var(--e-8) var(--e-10); font-size: var(--t-meta); white-space: nowrap; }
.srcg-asst-mini:hover, .srcg-asst-copy:hover { color: var(--text-1); border-color: var(--border-strong); }
.srcg-asst-copy.ok { color: var(--green); border-color: rgba(110,210,168,0.4); }
.srcg-asst-open { width: 100%; justify-content: center; gap: var(--e-8); margin-top: var(--e-2); }
.srcg-asst-steps { list-style: none; margin: var(--e-4) 0 var(--e-2); padding: 0; display: flex; flex-direction: column; gap: var(--e-8); }
.srcg-asst-step { display: flex; gap: var(--e-10); align-items: flex-start; }
.srcg-asst-tag {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--e-4);
  padding: var(--e-4) var(--e-8); border-radius: var(--r-pilule); font-size: var(--t-mini); font-weight: var(--fw-fort);
  background: rgba(251,191,36,0.12); color: var(--amber); border: 1px solid rgba(251,191,36,0.28);
}
.srcg-asst-step-txt { display: flex; flex-direction: column; gap: var(--e-1); font-size: var(--t-base); }
.srcg-asst-step-txt b { color: var(--text-1); font-weight: var(--fw-fort); }
.srcg-asst-step-txt span { color: var(--text-2); line-height: var(--lh-serre); }
.srcg-asst-dep { width: 100%; justify-content: center; margin-top: var(--e-2); }
.srcg-asst-dep-hint { display: block; margin: var(--e-2) 0; }

/* ── Lanceur de batch (Cockpit › Annonces) ────────────────────────────────────
   L'ecran etait presque vide au repos. On montre CE QU'ON A CHOISI, pas seulement
   combien : vignettes de robes (on reconnait une robe a l'oeil), pastilles de
   modeles avec leur visage, et retrait a la croix sans rouvrir le selecteur. */
.an-launch2 { background:var(--cok-card); border:1px solid var(--cok-border); border-radius: var(--r-lg); padding:var(--e-24) 26px; }
.an-launch2-h { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--e-14);
                flex-wrap:wrap; margin-bottom:var(--e-18); }
.an-launch2-t { font-size:var(--t-body); font-weight:650; letter-spacing:var(--ls-serre); }
.an-launch2-s { font-size:var(--t-base); color:var(--cok-text-2); margin-top:var(--e-4); }
.an-tot { font-size:var(--t-base); font-weight:var(--fw-fort); padding:var(--e-6) var(--e-14); border-radius: var(--r-pilule);
          background:var(--cok-bg); color:var(--cok-text-2); border:1px solid var(--cok-border);
          white-space:nowrap; font-variant-numeric:tabular-nums; }
.an-tot.on { background:var(--cok-accent); color: var(--sur-accent); border-color:var(--cok-accent); }

.an-sec { background:var(--cok-bg); border:1px solid var(--cok-border); border-radius: var(--r-lg);
          padding:var(--e-16) var(--e-18); margin-bottom:var(--e-12); }
.an-sec-h { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); margin-bottom:var(--e-12); }
.an-sec-t { display:flex; align-items:center; gap:var(--e-8); font-size:var(--t-small); font-weight:var(--fw-fort); }
.an-sec-t em { font-style:normal; font-weight:var(--fw-moyen); color:var(--cok-text-2); }
.an-sempty { font-size:var(--t-base); color:var(--cok-text-3); padding:var(--e-6) 0; }

.an-sec-b { display:flex; flex-wrap:wrap; gap:var(--e-10); }
.an-sv { width:82px; text-align:center; background:none; border:0; padding:0; font:inherit; color:inherit; }
/* ⚠️ Même raison que pour les vignettes de modèles : un liseré blanc à 9 % autour
   d'une photo de robe se voit et salit la grille. Le fond `--cok-card` tient la case
   quand la robe n'a pas d'image. */
/* ⚠️ Ne reste ici que ce qui lui est PROPRE : le fond de la case vide. La forme
   (ratio, rayon, cadrage) vient du composant. Le jeton local suffit à la changer
   sans redéclarer quoi que ce soit. */
.an-sv-i { --photo-fond: var(--cok-card); border:0; }
.an-sv-x { position:absolute; top:4px; right:4px; width:19px; height:19px; border-radius:50%; cursor:pointer;
           border:1px solid var(--cok-border); background:var(--cok-card); color:var(--cok-text-2);
           font-size:var(--t-base); line-height:var(--lh-un); padding:0; display:flex; align-items:center; justify-content:center; }
.an-sv-x:hover { background:var(--cok-red, var(--red)); border-color:transparent; color: var(--sur-accent); }
/* ⚠️ LA LOUPE A ÉTÉ RETIRÉE (Amadou, 13/08 : « tu n'as pas à mettre de loupe,
   quand je clique ça agrandit »). Je l'avais posée pour ne pas voler le clic au
   sélecteur — mais le sélecteur s'ouvre par son bouton d'en-tête, pas par la
   vignette. J'avais ajouté un bouton pour résoudre un conflit qui n'existait pas. */
.an-sv-i[data-zoomd], .an-sv-i[data-zoomm] { cursor: zoom-in; }
.an-sv-i[data-zoomd]:focus-visible, .an-sv-i[data-zoomm]:focus-visible {
  outline: 2px solid var(--cok-accent); outline-offset: 2px; }
.an-sv-x:focus-visible, .an-sp-x:focus-visible { outline:2px solid var(--cok-accent); outline-offset:1px; }
/* ⚠️ Le nom est centré sous la vignette et coupé à SA largeur : « Daniela Mirel » fait
   plus de 82 px et débordait sur ses voisines. `max-width` en plus de `overflow` — sans
   lui, un mot insécable élargit la boîte au lieu d'être coupé. */
.an-sv-n { font-size:var(--t-meta); color:var(--cok-text-2); margin-top:var(--e-6); overflow:hidden;
           text-overflow:ellipsis; white-space:nowrap; max-width:100%; text-align:center; }
.an-sv-plus { cursor:pointer; }
.an-sv-more { display:flex; align-items:center; justify-content:center;
              border:1px dashed var(--cok-border-2);
              color:var(--cok-text-2); font-size:var(--t-small); font-weight:var(--fw-fort); }
.an-sv-plus:hover .an-sv-more { border-color:var(--cok-accent); color:var(--cok-accent); }

.an-sp { display:inline-flex; align-items:center; gap:var(--e-8); padding:var(--e-6) var(--e-10) var(--e-6) var(--e-6);
         border:1px solid var(--cok-border); border-radius: var(--r-pilule); font-size:var(--t-base); }
.an-sp-a { width:26px; height:26px; border-radius:50%; flex:none; background:var(--cok-card) center/cover no-repeat;
           display:flex; align-items:center; justify-content:center; font-style:normal;
           font-size:var(--t-mini); font-weight:var(--fw-fort); color:var(--cok-text-2); }
.an-sp b { font-weight:var(--fw-moyen); }
.an-sp-x { width:17px; height:17px; border-radius:50%; cursor:pointer; border:0; background:none;
           color:var(--cok-text-3); font-size:var(--t-small); line-height:var(--lh-un); padding:0; }
.an-sp-x:hover { background:var(--cok-red, var(--red)); color: var(--sur-accent); }

.an-les { display:flex; gap:var(--e-10); flex-wrap:wrap; margin-top:var(--e-16); }
.an-le { flex:1 1 130px; background:var(--cok-bg); border:1px solid var(--cok-border);
         border-radius: var(--r-md); padding:var(--e-14) var(--e-16); }
.an-le .v { font-size:var(--t-body); font-weight:650; font-variant-numeric:tabular-nums; letter-spacing:var(--ls-serre); }
.an-le .l { font-size:var(--t-meta); color:var(--cok-text-2); margin-top:var(--e-2); }

.an-los { display:flex; gap:var(--e-10); flex-wrap:wrap; margin-top:var(--e-16); }
.an-lo { flex:1 1 250px; display:flex; align-items:flex-start; gap:var(--e-12); text-align:left; cursor:pointer;
         font:inherit; color:inherit; background:var(--cok-bg); border:1px solid var(--cok-border);
         border-radius: var(--r-md); padding:var(--e-14) var(--e-16); }
.an-lo:hover { border-color:var(--border-mid); }
.an-lo:focus-visible { outline:2px solid var(--cok-accent); outline-offset:2px; }
.an-lo.on { border-color:var(--cok-accent); }
.an-lo-b { width:17px; height:17px; border-radius:var(--r-micro); border:1.5px solid var(--cok-border);
           flex:none; margin-top:var(--e-1); position:relative; }
.an-lo.on .an-lo-b { background:var(--cok-accent); border-color:var(--cok-accent); }
.an-lo.on .an-lo-b::after { content:""; position:absolute; left:5px; top:1px; width:5px; height:10px;
                            border:solid #fff; border-width:0 2px 2px 0; transform:rotate(42deg); }
.an-lo-x b { display:block; font-size:var(--t-small); font-weight:var(--fw-fort); }
.an-lo-x i { display:block; font-style:normal; font-size:var(--t-meta); color:var(--cok-text-2); margin-top:var(--e-2); line-height:var(--lh-serre); }

.an-launch2-f { display:flex; align-items:center; justify-content:space-between; gap:var(--e-14);
                flex-wrap:wrap; margin-top:var(--e-22); padding-top:var(--e-18); border-top:1px solid var(--cok-border); }
.an-launch2-note { font-size:var(--t-base); color:var(--cok-text-2); }
/* Le bouton de lancement suit la taille standard du site : il n'a pas besoin
   d'etre plus gros que les autres pour qu'on le trouve. */
.an-lgo { padding:var(--e-8) var(--e-16); }

/* ── Sous-onglets d'Annonces ──────────────────────────────────────────────────
   Alignés sur le langage du site (.cok-chip) : pastille neutre, et l'onglet actif
   prend une teinte DOUCE, pas un aplat plein. Mes premiers boutons etaient plus
   gros et plus criards que tout le reste de l'interface. */
.an-souso { display:flex; gap:var(--e-6); flex-wrap:wrap; align-items:center;
            padding:var(--e-10) var(--e-28) var(--e-12); margin:0;
            background:rgba(var(--th-panneau-rgb),0.55); border-bottom:1px solid var(--border); }
.an-so { display:inline-flex; align-items:center; gap:var(--e-8); cursor:pointer;
         font-family:inherit; font-size:var(--t-base); font-weight:var(--fw-normal);
         color:var(--cok-text-2); background:var(--cok-card);
         border:1px solid var(--cok-border); border-radius: var(--r-pilule); padding:var(--e-8) var(--e-14); }
.an-so:not(.on):hover { background:var(--bg-elevated); }
.an-so:focus-visible { outline:2px solid var(--cok-accent); outline-offset:2px; }
.an-so.on { background:var(--cok-accent-bg); color:var(--cok-accent);
            font-weight:var(--fw-moyen); border-color:transparent; }
.an-so-n { min-width:17px; height:17px; padding:0 var(--e-6); border-radius: var(--r-md); font-size:var(--t-micro);
           line-height:17px; text-align:center; background:var(--cok-accent-bg);
           color:var(--cok-accent); font-weight:var(--fw-moyen); font-variant-numeric:tabular-nums; }
.an-so.on .an-so-n { background:rgba(var(--th-voile),.16); color:inherit; }
.an-so-n.hidden { display:none; }

/* ── Sous-onglets (Annonces · Matière) ────────────────────────────────────────
   La barre prolonge l'en-tête (même fond, même retrait) : sans ça le fond de page
   passait entre les deux bordures et dessinait une bande claire.
   ⚠️ Refonte 2026-07-30 : l'onglet ÉTEINT était lui aussi rempli et bordé de bleu —
   sur la barre Bibliothèque / Sourcing, les deux avaient l'air allumés et on ne savait
   plus où on était. Éteint = neutre, allumé = plein. Un seul bouton se voit. */
.an-souso { display:flex; gap:var(--e-6); flex-wrap:wrap; align-items:center;
            padding:var(--e-10) var(--e-32) var(--e-12); margin:0;
            background:linear-gradient(180deg, var(--surface), rgba(var(--th-voile),0.015));
            border-bottom:1px solid var(--border); }
.an-so { display:inline-flex; align-items:center; gap:var(--e-8); cursor:pointer; font:inherit;
         font-size:var(--t-base); font-weight:var(--fw-moyen); color:var(--text-2);
         background:rgba(var(--th-voile),.04);
         border:1px solid var(--border); border-radius: var(--r-sm);
         padding:var(--e-8) var(--e-16); transition:background var(--t-bref), border-color var(--t-bref), color var(--t-bref); }
.an-so:not(.on):hover { background:rgba(var(--th-voile),.08); color:var(--text); }
.an-so:focus-visible { outline:2px solid var(--violet-soft); outline-offset:2px; }
.an-so.on { background:linear-gradient(135deg, var(--violet-soft), var(--cyan));
            border-color:transparent; color: var(--sur-plein); font-weight:var(--fw-fort);
            box-shadow:0 4px 16px rgba(var(--th-accent-rgb),.30); }
.an-so-n { min-width:19px; height:19px; padding:0 var(--e-6); border-radius: var(--r-md); font-size:var(--t-mini);
           line-height:19px; text-align:center; background:rgba(var(--th-ombre),.20); color:inherit;
           font-weight:var(--fw-fort); font-variant-numeric:tabular-nums; }
.an-so:not(.on) .an-so-n { background:var(--violet-tint); color:var(--violet-light); }
.an-so-n.hidden { display:none; }
@media (prefers-reduced-motion:reduce) { .an-so { transition:none; } }

/* Masquage d'un champ mot de passe SANS type=password (sinon Chrome/Brave proposent le
   trousseau). Les points remplacent les caractères ; l'œil retire la classe pour lire. */
.champ-masque { -webkit-text-security: disc; text-security: disc; }

/* ── Rayon Proxys / IP (Vivier) ───────────────────────────────────────────────
   Le reservoir d IP ou la migration pioche. Sobre, aligne sur le reste du vivier. */
.src-px-add { display:flex; flex-direction:column; gap:var(--e-10); margin:var(--e-4) 0 var(--e-14); }
.src-px-ta { width:100%; font-family:var(--mono,ui-monospace,Menlo,monospace); font-size:var(--t-base);
             line-height:var(--lh-aere); padding:var(--e-12) var(--e-14); border-radius: var(--r-md); resize:vertical;
             background:var(--cok-bg,#12151b); color:var(--cok-text,var(--text));
             border:1px solid var(--cok-border,#282d38); }
.src-px-ta:focus-visible { outline:2px solid var(--rp-blue,var(--cyan)); outline-offset:1px; }
.src-px-actions { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); flex-wrap:wrap; }
.src-px-stats { display:flex; gap:var(--e-8); flex-wrap:wrap; margin-bottom:var(--e-12); }
.src-px-pill { font-size:var(--t-meta); padding:var(--e-4) var(--e-12); border-radius: var(--r-pilule); font-variant-numeric:tabular-nums;
               background:var(--cok-card,#171a21); border:1px solid var(--cok-border,#282d38); color:var(--cok-text-2,#93a3c4); }
.src-px-pill.libre { color:var(--green); border-color:#63D6B044; }
.src-px-pill.prise { color:var(--amber); border-color:#F0B05544; }
.src-px-pill.grillee { color:var(--red); border-color:#F0787A44; }
/* Séparation par identité dans le Sourcing : chacun retrouve SES IP d'un coup d'œil.
   La section de l'identité active est mise en avant (barre accentuée). */
.src-px-sep { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12);
              margin:var(--e-18) 0 var(--e-8); padding:0 var(--e-2) var(--e-8); border-bottom:1px solid var(--cok-border,#282d38); }
.src-px-sep:first-child { margin-top:var(--e-4); }
.src-px-sep-nom { font-size:var(--t-base); font-weight:var(--fw-moyen); color:var(--cok-text-2,#93a3c4); letter-spacing:var(--ls-leger); }
.src-px-sep.moi .src-px-sep-nom { color:var(--green); }
.src-px-sep.moi { border-bottom-color:#63D6B055; }
.src-px-sep-cnt { font-size:var(--t-mini); color:var(--cok-text-3,#6b7184); }
/* Sélection multiple : une case par ligne + une par section. */
.src-px-pick { display:flex; align-items:center; cursor:pointer; }
.src-px-pick input { width:15px; height:15px; cursor:pointer; accent-color:var(--green); margin:0; }
.src-px-danger { color:var(--red); border-color:#F0787A55; }
.src-px-danger:hover:not(:disabled) { background:rgba(248,113,113,.12); }
.src-px-sep { gap:var(--e-10); }
.src-px-row { display:grid; grid-template-columns:auto 1fr auto auto auto; gap:var(--e-12); align-items:center;
              padding:var(--e-10) var(--e-14); border:1px solid var(--cok-border,#282d38); border-radius: var(--r-md); margin-bottom:var(--e-6); }
.src-px-adr { font-family:var(--mono,ui-monospace,Menlo,monospace); font-size:var(--t-base); color:var(--cok-text,var(--text)); }
.src-px-cpt { font-size:var(--t-meta); color:var(--cok-text-2,#93a3c4); }
.src-px-badge { font-size:var(--t-mini); padding:var(--e-2) var(--e-10); border-radius: var(--r-pilule); border:1px solid; white-space:nowrap; }

.src-px-fia { font-size:var(--t-mini); padding:var(--e-2) var(--e-10); border-radius: var(--r-pilule); border:1px solid; white-space:nowrap;
              font-variant-numeric:tabular-nums; }

/* ── Assistant Google : ligne de titre avec bouton Recharger ─────────────────── */
.srcg-asst-tt-row { display:flex; align-items:center; justify-content:space-between; gap:var(--e-12); }
.srcg-asst-tt-row .srcg-asst-mini { display:inline-flex; align-items:center; gap:var(--e-6); width:auto;
  padding:var(--e-4) var(--e-10); font-size:var(--t-meta); border-radius: var(--r-sm); white-space:nowrap; }

/* ═══ LE MANDATAIRE — mon double qui répond à l'IA à ma place ═══════════════════ */
/* Réutilise .ctrl-card / .ctrl-grouplabel du Centre de contrôle : même famille visuelle. */

.mand-modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e-10); }
.mand-mode { display: flex; flex-direction: column; gap: var(--e-4); align-items: flex-start; cursor: pointer; text-align: left; color: var(--text-2);
  transition: border-color var(--t-bref), background var(--t-bref) }
.mand-mode:hover { background: var(--bg-hover); border-color: var(--border-mid); }
.mand-mode b { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.mand-mode small { font-size: var(--t-micro); color: var(--text-2); line-height: var(--lh-serre); }
.mand-mode.active { border-color: var(--violet); background: var(--violet-tint); }
.mand-mode.active b { color: var(--violet-light); }
.mand-mode[data-mode="auto"].active { border-color: var(--green); background: rgba(110,210,168,.12); }
.mand-mode[data-mode="auto"].active b { color: var(--green); }
.mand-mode[data-mode="off"].active { border-color: var(--border-strong); background: var(--bg-elevated); }

.mand-etatline { display: flex; align-items: center; gap: var(--e-22); flex-wrap: wrap;
  padding-top: var(--e-4); border-top: 1px solid var(--border); margin-top: var(--e-2); }
.mand-stat { display: flex; flex-direction: column; gap: var(--e-1); }
.mand-stat b { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); font-variant-numeric: tabular-nums; }
.mand-stat small { font-size: var(--t-micro); color: var(--text-2); }
.mand-note { font-size: var(--t-meta); color: var(--red); }

.mand-champ { display: flex; flex-direction: column; gap: var(--e-6); }
.mand-champ > span { font-size: var(--t-mini); color: var(--text-2); font-weight: var(--fw-moyen); }
.mand-champ textarea, .mand-liste, .mand-ajout input {
  width: 100%; box-sizing: border-box; resize: vertical;
  padding: var(--e-10) var(--e-12); border-radius: var(--r-md); font-family: inherit; font-size: var(--t-meta); line-height: var(--lh-normal);
  color: var(--text); background: var(--bg-input); border: 1px solid var(--border); outline: none; }
.mand-champ textarea:focus, .mand-liste:focus, .mand-ajout input:focus { border-color: var(--violet); }
.mand-liste { display: block; margin-top: var(--e-2); }

.mand-reglages { display: flex; align-items: center; gap: var(--e-18); flex-wrap: wrap; padding-top: var(--e-4); }
.mand-mini { display: flex; align-items: center; gap: var(--e-8); font-size: var(--t-mini); color: var(--text-2); }
.mand-mini input { width: 68px; padding: var(--e-6) var(--e-8); border-radius: var(--r-sm); font-size: var(--t-meta);
  color: var(--text); background: var(--bg-input); border: 1px solid var(--border); outline: none; }
.mand-mini em { font-style: normal; }

.mand-regles { display: flex; flex-direction: column; gap: var(--e-6); max-height: 340px; overflow-y: auto; }
.mand-regle { display: flex; align-items: flex-start; gap: var(--e-10); padding: var(--e-8) var(--e-10);
  border-radius: var(--r-sm); background: var(--bg-input); border: 1px solid var(--border); }
.mand-regle-sujet { flex: none; font-size: var(--t-micro); color: var(--violet-light); background: var(--violet-tint);
  border-radius: var(--r-pilule); padding: var(--e-2) var(--e-8); margin-top: var(--e-1); }
.mand-regle-texte { flex: 1; font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-normal); min-width: 0; }
.mand-regle-x { flex: none; background: none; border: none; cursor: pointer; font-size: var(--t-body);
  line-height: var(--lh-un); color: var(--text-muted); padding: 0 var(--e-2); }
.mand-regle-x:hover { color: var(--red); }
.mand-ajout { display: flex; gap: var(--e-8); align-items: center; flex-wrap: wrap; }
.mand-ajout input:first-of-type { flex: 0 0 190px; }
.mand-ajout input:nth-of-type(2) { flex: 1; min-width: 220px; }
.mand-vide { font-size: var(--t-meta); color: var(--text-2); padding: var(--e-6) var(--e-2); }

.mand-journal { display: flex; flex-direction: column; gap: var(--e-8); max-height: 560px; overflow-y: auto; }
.mand-ligne { border-left: 3px solid var(--border-strong) }
.mand-ligne[data-etat="auto"]     { border-left-color: var(--green); }
.mand-ligne[data-etat="propose"]  { border-left-color: var(--violet); }
.mand-ligne[data-etat="alerte"]   { border-left-color: var(--red); }
.mand-ligne[data-etat="calme"]    { border-left-color: var(--text-muted); }
.mand-ligne-tete { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap; margin-bottom: var(--e-6); }
.mand-ligne-quand { font-size: var(--t-micro); color: var(--text-muted); }
.mand-ligne-mot { font-size: var(--t-micro); color: var(--text-2); }
.mand-ligne-sujet { font-size: var(--t-micro); color: var(--text-2); background: var(--bg-elevated);
  border-radius: var(--r-pilule); padding: var(--e-2) var(--e-8); }
.mand-ligne-conf { font-size: var(--t-micro); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.mand-ligne-verdict { font-size: var(--t-micro); border-radius: var(--r-pilule); padding: var(--e-2) var(--e-8); }
.mand-v-bon  { color: var(--green); background: rgba(110,210,168,.12); }
.mand-v-faux { color: var(--amber); background: rgba(229,194,138,.12); }
.mand-ligne-q { font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-normal); }
.mand-ligne-r { font-size: var(--t-meta); color: var(--text); line-height: var(--lh-normal); margin-top: var(--e-6);
  padding-left: var(--e-10); border-left: 2px solid var(--border-mid); }
.mand-ligne-raison { font-size: var(--t-mini); color: var(--amber); margin-top: var(--e-6); line-height: var(--lh-normal); }
.mand-ligne-actions { display: flex; gap: var(--e-8); margin-top: var(--e-8); }
.mand-b { padding: var(--e-4) var(--e-10); border-radius: var(--r-sm); cursor: pointer; font-size: var(--t-micro);
  color: var(--text-2); background: var(--bg-elevated); border: 1px solid var(--border); }
.mand-b:hover { background: var(--bg-hover); color: var(--text); }
.mand-b-faux:hover { color: var(--amber); border-color: rgba(229,194,138,.35); }

/* ── Guetteur de la voie Google (carte « Créer un compte Google ») ───────────── */
.cok-cp-sonde { display:flex; align-items:center; gap:var(--e-14); padding:var(--e-12) var(--e-14); border-radius: var(--r-md);
  background:var(--cok-card); border:1px solid var(--cok-border); margin-bottom:var(--e-16); }
.cok-cp-sonde-txt { display:flex; flex-direction:column; gap:var(--e-4); flex:1; min-width:0; }
.cok-cp-sonde-txt b { font-size:var(--t-base); color:var(--cok-text-1); font-weight:var(--fw-fort); }
.cok-cp-sonde-txt span { font-size:var(--t-meta); color:var(--cok-text-3); line-height:var(--lh-serre); }
.cok-cp-sonde-etat { color:var(--cok-text-2) !important; font-weight:var(--fw-moyen); }
.cok-cp-sonde .cok-btn { flex:none; }

/* ── Fusion : donner le visage d'une orpheline à une fiche compte ───────────── */
.fusion-fond { position:fixed; inset:0; z-index:9000; background:rgba(var(--th-panneau-rgb),.72);
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px); display:flex;
  align-items:center; justify-content:center; padding:var(--e-24); }
.fusion-boite { background:var(--cok-card,#161a2a); border:1px solid var(--cok-border,rgba(var(--th-voile),.09));
  border-radius: var(--r-xl); padding:var(--e-22) var(--e-24); max-width:640px; width:100%; max-height:82vh; overflow-y:auto; }
.fusion-titre { font-size:var(--t-body); font-weight:var(--fw-fort); margin-bottom:var(--e-6); }
.fusion-intro { font-size:var(--t-base); color:var(--cok-text-2,#b9c0d4); line-height:var(--lh-normal); margin-bottom:var(--e-16); }
.fusion-note  { font-size:var(--t-meta); color:var(--cok-text-3,#7f879c); }
.fusion-grille { display:grid; grid-template-columns:repeat(auto-fill,minmax(112px,1fr)); gap:var(--e-12); margin-bottom:var(--e-18); }
.fusion-carte { display:flex; flex-direction:column; align-items:center; gap:var(--e-8); padding:var(--e-10);
  background:transparent; border:1px solid var(--cok-border,rgba(var(--th-voile),.09)); border-radius: var(--r-lg);
  cursor:pointer; color:inherit; transition:border-color var(--t-moyen), transform var(--t-moyen); }
.fusion-carte:hover { border-color:var(--cok-accent,var(--cyan)); transform:translateY(-2px); }
.fusion-carte img { width:88px; height:110px; object-fit:cover; border-radius: var(--r-sm); }
.fusion-noface { width:88px; height:110px; border-radius: var(--r-sm); display:flex; align-items:center;
  justify-content:center; background:var(--bg-hover); color:var(--cok-text-3,#7f879c); font-size:var(--t-title); }
.fusion-carte span { font-size:var(--t-meta); text-align:center; line-height:var(--lh-serre); }
.fusion-annuler { width:100%; }

/* ── Migrer une vendeuse (Comptes › Créer) ──────────────────────────────────── */
.cok-migr-liste { display:flex; flex-direction:column; gap:var(--e-8); }
.cok-migr-ligne { display:flex; align-items:center; gap:var(--e-10); width:100%; padding:var(--e-12) var(--e-14);
  background:transparent; border:1px solid var(--cok-border); border-radius: var(--r-md); cursor:pointer;
  color:inherit; text-align:left; transition:border-color var(--t-moyen), background var(--t-moyen); }
.cok-migr-ligne:hover { border-color:var(--cok-accent,var(--cyan)); background:var(--surface); }
.cok-migr-nom { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text-1); }
.cok-migr-sous { font-size:var(--t-meta); color:var(--cok-text-3); flex:1; }
.cok-migr-fleche { color:var(--cok-text-3); }
.cok-migr-tete { display:flex; align-items:center; gap:var(--e-10); margin-bottom:var(--e-12); }
.cok-migr-tete b { font-size:var(--t-small); flex:1; }
.cok-migr-etapes { margin:0 0 var(--e-16); padding-left:var(--e-20); display:flex; flex-direction:column; gap:var(--e-8); }
.cok-migr-etapes li { font-size:var(--t-base); color:var(--cok-text-2); line-height:var(--lh-normal); }
.cok-migr-cp { font-family:ui-monospace,Menlo,monospace; font-size:var(--t-meta); padding:var(--e-2) var(--e-8); margin:0 var(--e-2);
  border-radius: var(--r-sm); border:1px solid var(--cok-border-2); background:var(--bg-hover);
  color:var(--cok-text-1); cursor:pointer; }
.cok-migr-cp:hover { border-color:var(--cok-accent,var(--cyan)); }
.cok-migr-vide { color:var(--cok-text-3); }
.cok-migr-form { display:grid; grid-template-columns:1fr 1fr; gap:var(--e-12); margin-bottom:var(--e-16); }
.cok-migr-form label { display:flex; flex-direction:column; gap:var(--e-6); font-size:var(--t-meta); color:var(--cok-text-3); }
.cok-migr-form input, .cok-migr-form select { padding:var(--e-8) var(--e-10); border-radius: var(--r-sm);
  border:1px solid var(--cok-border); background:rgba(var(--th-voile),.04); color:var(--cok-text-1); font-size:var(--t-base); }
@media (max-width:640px){ .cok-migr-form { grid-template-columns:1fr; } }

/* ── Bandeau des 3 temps (Comptes) ──────────────────────────────────────────── */
.cok-tunnel { display:flex; align-items:stretch; gap:0; margin-bottom:var(--e-22); }
.cok-tunnel-pas { display:flex; align-items:center; gap:var(--e-10); flex:1;
  cursor:pointer; color:inherit; text-align:left; transition:border-color var(--t-moyen), background var(--t-moyen) }
.cok-tunnel-pas:hover { border-color:var(--cok-border-2); }
.cok-tunnel-pas.on { border-color:var(--cok-accent,var(--cyan)); background:rgba(91,140,255,.10);
  box-shadow:0 0 0 1px rgba(91,140,255,.25); }
/* Le bandeau EST la navigation du tunnel : l'étape en cours doit sauter aux yeux, et
   les autres rester cliquables sans crier. */
.cok-tunnel-pas.on .cok-tunnel-txt b { color:var(--cok-accent,var(--cyan)); }
.cok-tunnel-num { width:22px; height:22px; flex:none; border-radius:50%; display:flex;
  align-items:center; justify-content:center; font-size:var(--t-mini); font-weight:var(--fw-fort);
  background:rgba(var(--th-voile),.07); color:var(--cok-text-2); }
.cok-tunnel-pas.on .cok-tunnel-num { background:var(--cok-accent,var(--cyan)); color: var(--sur-accent); }
.cok-tunnel-txt { display:flex; flex-direction:column; gap:var(--e-1); flex:1; min-width:0; }
.cok-tunnel-txt b { font-size:var(--t-base); font-weight:var(--fw-fort); color:var(--cok-text-1); }
.cok-tunnel-txt i { font-style:normal; font-size:var(--t-mini); color:var(--cok-text-3); }
.cok-tunnel-val { font-size:var(--t-body); font-weight:var(--fw-fort); color:var(--cok-text-3); min-width:18px; text-align:right; }
.cok-tunnel-val.actif { color:var(--cok-accent,var(--cyan)); }
.cok-tunnel-lien { width:14px; flex:none; align-self:center; height:1px; background:var(--cok-border); }
.cok-migr-main { display:flex; flex-direction:column; gap:var(--e-10); padding:var(--e-12) var(--e-2) var(--e-2); font-size:var(--t-base); color:var(--cok-text-2); }
@media (max-width:760px){ .cok-tunnel { flex-direction:column; gap:var(--e-8); } .cok-tunnel-lien { display:none; } }

/* Numéro imposé pour la vérification Google */
.cok-tel-libre { display:flex; flex-direction:column; gap:var(--e-6); margin-bottom:var(--e-14);
  font-size:var(--t-meta); color:var(--cok-text-3); }
.cok-tel-libre i { font-style:normal; color:var(--cok-text-3); opacity:.75; }
.cok-tel-libre input { padding:var(--e-10) var(--e-12); border-radius: var(--r-sm); border:1px solid var(--cok-border);
  background:rgba(var(--th-voile),.04); color:var(--cok-text-1); font-size:var(--t-base); }
.cok-tel-libre input:focus { outline:none; border-color:var(--cok-accent,var(--cyan)); }

/* Ce qu'on a mesuré sur les numéros (carte Google) */
.cok-sms-lignes { display:flex; flex-direction:column; gap:var(--e-6); }
.cok-sms-ligne { display:flex; align-items:center; gap:var(--e-10); font-size:var(--t-meta); color:var(--cok-text-2); }
.cok-sms-ligne > span:first-child { width:88px; flex:none; }
.cok-sms-barre { flex:1; height:6px; border-radius:var(--r-micro); background:var(--bg-elevated); overflow:hidden; }
.cok-sms-barre i { display:block; height:100%; border-radius:var(--r-micro); }
.cok-sms-ligne b { width:44px; text-align:right; color:var(--cok-text-1); font-weight:var(--fw-fort); }
.cok-sms-ligne i { width:48px; text-align:right; font-style:normal; font-size:var(--t-mini); color:var(--cok-text-3); }

/* ── 2 · La vendeuse : donner un visage (écran « visuellement parlant ») ────── */
.cok-vend-autres { display:flex; align-items:center; gap:var(--e-8); flex-wrap:wrap; font-size:var(--t-meta);
  color:var(--cok-text-3); margin-bottom:var(--e-14); }
.cok-vend-onglet { padding:var(--e-6) var(--e-10); border-radius: var(--r-sm); border:1px solid var(--cok-border);
  background:transparent; color:var(--cok-text-2); font-size:var(--t-meta); cursor:pointer; }
.cok-vend-onglet.on { border-color:var(--cok-accent,var(--cyan)); color:var(--cok-text-1);
  background:rgba(91,140,255,.10); }

.cok-vend-fiche { display:flex; flex-direction:column; gap:var(--e-1); margin-bottom:var(--e-18);
  border:1px solid var(--cok-border); border-radius: var(--r-md); overflow:hidden; }
.cok-vend-champ { display:flex; align-items:center; gap:var(--e-10); padding:var(--e-10) var(--e-12); font-size:var(--t-base);
  background:var(--cok-bg-2); transition:background var(--t-long); }
.cok-vend-champ .k { width:104px; flex:none; color:var(--cok-text-3); font-size:var(--t-meta); }
.cok-vend-champ .v { flex:1; color:var(--cok-text-3); font-family:ui-monospace,Menlo,monospace; font-size:var(--t-meta); }
.cok-vend-champ.plein .v { color:var(--cok-text-1); }
.cok-vend-champ .src { font-size:var(--t-micro); color:var(--cok-text-3); opacity:.6; }
.cok-vend-champ.arrive { background:rgba(61,220,151,.12); }

.cok-vend-grille { display:grid; grid-template-columns:repeat(auto-fill,minmax(104px,1fr)); gap:var(--e-12); margin-bottom:var(--e-12); }
.cok-vend-orph { display:flex; flex-direction:column; align-items:center; gap:var(--e-6); padding:var(--e-10);
  border:1px solid var(--cok-border); border-radius: var(--r-md); background:transparent; color:inherit;
  cursor:pointer; position:relative; transition:border-color var(--t-moyen), opacity var(--t-long), transform var(--t-long); }
.cok-vend-orph img { width:82px; height:102px; object-fit:cover; border-radius: var(--r-sm); }
.cok-vend-noface { width:82px; height:102px; border-radius: var(--r-sm); display:flex; align-items:center;
  justify-content:center; background:var(--bg-hover); color:var(--cok-text-3); font-size:var(--t-lead); }
.cok-vend-orph .nom { font-size:var(--t-meta); text-align:center; line-height:var(--lh-titre); }
.cok-vend-orph.retenue { border-color:var(--cok-accent,var(--cyan)); background:rgba(91,140,255,.09); }
.cok-vend-orph .pastille { position:absolute; top:-7px; right:-6px; font-size:var(--t-micro); padding:var(--e-2) var(--e-8);
  border-radius: var(--r-xl); background:var(--cok-accent,var(--cyan)); color: var(--sur-accent); }
.cok-vend-orph.efface { opacity:.12; transform:scale(.94); }
.cok-vend-pourquoi { font-size:var(--t-meta); color:var(--cok-text-3); line-height:var(--lh-normal); margin-bottom:var(--e-14); }

/* ── Les profils (Comptes › 4ᵉ onglet) ──────────────────────────────────────── */
/* Le bandeau de filtres était COLLÉ à l'en-tête « Les profils » (Amadou, 2026-07-27) :
   on le détache, et on le pose sur une ligne à lui avec un filet de séparation. */
.cok-prof-filtres { display:flex; gap:var(--e-8); flex-wrap:wrap; margin:var(--e-20) 0 var(--e-16);
  padding-top:var(--e-16); border-top:1px solid var(--cok-border); }
.cok-prof-f { padding:var(--e-6) var(--e-12); border-radius: var(--r-sm); border:1px solid var(--cok-border);
  background:transparent; color:var(--cok-text-2); font-size:var(--t-meta); cursor:pointer; }
.cok-prof-f.on { border-color:var(--cok-accent,var(--cyan)); color:var(--cok-text-1); background:rgba(91,140,255,.10); }
.cok-prof-f b { font-weight:var(--fw-fort); }
.cok-prof-liste { display:flex; flex-direction:column; gap:var(--e-6); max-height:520px; overflow-y:auto; }
.cok-prof-l { display:grid; grid-template-columns:92px 72px minmax(120px,1fr) 168px 104px 132px; align-items:center;
  gap:var(--e-10); padding:var(--e-8) var(--e-12); border-radius: var(--r-md); border:1px solid var(--cok-border);
  background:var(--cok-bg-2); font-size:var(--t-meta); }
.cok-prof-l.grille { border-color:rgba(240,113,90,.35); background:rgba(240,113,90,.06); }
.cok-prof-l .n { font-weight:var(--fw-fort); color:var(--cok-text-1); }
.cok-prof-l .c, .cok-prof-l .ip, .cok-prof-l .h { color:var(--cok-text-3); font-size:var(--t-meta);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cok-prof-l .ip { font-family:ui-monospace,Menlo,monospace; }
.cok-prof-p { font-size:var(--t-micro); padding:var(--e-2) var(--e-8); border-radius: var(--r-xl); text-align:center; }
.cok-prof-p.libre { background:rgba(61,220,151,.14); color:var(--cok-green,#3ddc97); }
.cok-prof-p.occupe { background:rgba(91,140,255,.14); color:var(--cok-accent,var(--cyan)); }
.cok-prof-p.grille { background:rgba(240,113,90,.16); color:var(--red); }
.cok-prof-b { font-size:var(--t-mini); padding:var(--e-6) var(--e-10); }
@media (max-width:900px){ .cok-prof-l { grid-template-columns:1fr 74px; } .cok-prof-l .ip,.cok-prof-l .h { display:none; } }
.cok-prof-b.danger { border-color:rgba(240,113,90,.4); color:var(--red); }
.cok-prof-b.danger:hover { background:rgba(240,113,90,.12); }
.cok-prof-l .a { display:flex; gap:var(--e-6); justify-content:flex-end; }

/* ── Le Vendeur : ses réglages / ce qu'on lui apprend ────────────────────────
   Deux onglets dans le panneau de l'ouvrier. L'apprentissage n'existe que pour lui :
   c'est le seul à qui on parle en français plutôt qu'en réglages. */
.cok-wtabs{display:flex;gap:var(--e-6);margin:var(--e-22) 0 var(--e-14);border-bottom:1px solid rgba(var(--th-voile),.08)}
.cok-wtab{background:none;border:none;border-bottom:2px solid transparent;color:var(--txt-dim,var(--text-3));
  font:inherit;font-size:var(--t-base);font-weight:var(--fw-fort);padding:var(--e-8) var(--e-14);cursor:pointer;margin-bottom:calc(var(--e-1) * -1)}
.cok-wtab:not(.on):hover{color:var(--txt,var(--text))}
.cok-wtab.on{color:var(--cok-accent,var(--cyan));border-bottom-color:var(--cok-accent,var(--cyan))}

.cok-cons-add{display:flex;gap:var(--e-8);align-items:flex-start;margin-bottom:var(--e-14)}
.cok-cons-add textarea{flex:1;background:rgba(var(--th-voile),.04);border:1px solid rgba(var(--th-voile),.1);
  border-radius: var(--r-md);color:inherit;font:inherit;font-size:var(--t-base);padding:var(--e-10) var(--e-12);resize:vertical;min-height:44px}
.cok-cons-add textarea:focus{outline:none;border-color:var(--cok-accent,var(--cyan))}
.cok-cons-add .cok-btn{white-space:nowrap;align-self:stretch}

.cok-cons-list{display:flex;flex-direction:column;gap:var(--e-8)}
.cok-cons{ display:flex;align-items:center;gap:var(--e-10) }
.cok-cons.off{opacity:.45}
.cok-cons-sw{flex:0 0 auto;border:none;border-radius: var(--r-xl);cursor:pointer;font:inherit;font-size:var(--t-mini);
  font-weight:var(--fw-gras);padding:var(--e-4) var(--e-10);background:var(--cok-accent-bg,var(--tier-volume-bg));color:var(--cok-accent,var(--cyan))}
.cok-cons.off .cok-cons-sw{background:rgba(var(--th-voile),.08);color:var(--txt-dim,var(--text-3))}
.cok-cons-txt{flex:1;font-size:var(--t-base);line-height:var(--lh-normal)}
.cok-cons-date{flex:0 0 auto;font-size:var(--t-mini);color:var(--txt-dim,var(--text-3))}
.cok-cons-x{flex:0 0 auto;background:none;border:none;color:var(--txt-dim,var(--text-3));cursor:pointer;
  font-size:var(--t-base);padding:var(--e-2) var(--e-4);line-height:var(--lh-un)}
.cok-cons-x:hover{color:var(--red)}

.cok-appr{position:relative;padding:var(--e-10) 30px var(--e-10) var(--e-12);border-radius: var(--r-md);
  background:var(--surface);border:1px solid rgba(var(--th-voile),.07)}
.cok-appr-q{font-size:var(--t-meta);color:var(--txt-dim,var(--text-3));margin-bottom:var(--e-6)}
.cok-appr-r{font-size:var(--t-base);line-height:var(--lh-normal)}
.cok-appr .cok-cons-x{position:absolute;top:8px;right:8px}

/* ── Les vrais réglages du Vendeur (chiffres garantis, pas des étiquettes) ─── */
.cok-regl{display:flex;flex-direction:column;gap:var(--e-8)}
.cok-regl-row{ display:flex;align-items:center;gap:var(--e-14);cursor:pointer }
.cok-regl-lbl{flex:1;font-size:var(--t-base);display:flex;flex-direction:column;gap:var(--e-2)}
.cok-regl-lbl i{font-style:normal;font-size:var(--t-mini);color:var(--txt-dim,var(--text-3));line-height:var(--lh-serre)}
.cok-regl-in{flex:0 0 auto;display:flex;align-items:center;gap:var(--e-6)}
.cok-regl-in input{width:78px;background:var(--bg-hover);border:1px solid rgba(var(--th-voile),.12);
  border-radius: var(--r-sm);color:inherit;font:inherit;font-size:var(--t-base);font-weight:var(--fw-fort);padding:var(--e-6) var(--e-10);text-align:right}
.cok-regl-in input:focus{outline:none;border-color:var(--cok-accent,var(--cyan))}
.cok-regl-in em{font-style:normal;font-size:var(--t-meta);color:var(--txt-dim,var(--text-3));min-width:12px}
/* (.cok-btn--ghost : passé dans le composant, sous `.v-btn--fantome`.) */

/* ── Les identifiants d'une vendeuse, copiables — pour installer à la main quand la
   machine coince (Amadou : « je ne dois vraiment pas perdre de temps ») ────────── */
.cok-ident{ margin:var(--e-10) 0 var(--e-14) }
.cok-ident summary{cursor:pointer;font-size:var(--t-base);color:var(--txt-dim,var(--text-3));font-weight:var(--fw-fort)}
.cok-ident-l{display:flex;align-items:center;gap:var(--e-10);margin-top:var(--e-10)}
.cok-ident-k{flex:0 0 108px;font-size:var(--t-meta);color:var(--txt-dim,var(--text-3))}
.cok-ident-v{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--t-base);
  background:rgba(var(--th-ombre),.25);border-radius: var(--r-sm);padding:var(--e-6) var(--e-10);word-break:break-all;user-select:all}
.cok-ident-c{flex:0 0 auto;font-size:var(--t-meta);padding:var(--e-4) var(--e-10)}
.cok-ident-c.ok{background:var(--cok-accent-bg,var(--tier-volume-bg));color:var(--cok-accent,var(--cyan))}

/* ── Créer des comptes à la chaîne ───────────────────────────────────────────
   Un compte après l'autre, sans pause. L'écran doit dire à tout moment où on en est :
   sans ça, on regarde une machine tourner sans savoir si elle avance. */
/* la marge haute est passée au `gap` du parent (voir .cpl-lancer) */
.cok-raf-reglages{display:flex;gap:var(--e-12);margin:0;flex-wrap:wrap}
.cok-raf-champ{ flex:0 0 150px;display:block }
.cok-raf-champ.large{flex:1;min-width:170px}
.cok-raf-champ>span{display:block;font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-bottom:var(--e-6)}
.cok-raf-champ>b{font-size:var(--t-small);font-weight:var(--fw-fort)}
.cok-raf-champ input{width:100%;background:none;border:none;color:var(--cok-accent,var(--cyan));
  font:inherit;font-size:var(--t-lead);font-weight:var(--fw-fort);padding:0}
.cok-raf-champ input:focus{outline:none}
.cok-raf-go{width:100%;margin-top:var(--e-16);padding:var(--e-14);font-size:var(--t-small);
  background:linear-gradient(120deg,var(--violet-soft),var(--cok-accent,var(--cyan)));color:#08131A;border:none}
.cok-raf-stop{width:100%;margin-top:var(--e-14);padding:var(--e-12);background:rgba(240,113,90,.10);
  border:1px solid rgba(240,113,90,.35);color:var(--cok-red,var(--red))}

.cok-raf-suivi{margin-top:var(--e-18)}
.cok-raf-ligne1{display:flex;justify-content:space-between;align-items:baseline;font-size:var(--t-small)}
.cok-raf-ligne1 span{font-size:var(--t-base);color:var(--text-muted,var(--text-2))}
.cok-raf-barre{height:6px;border-radius:var(--r-micro);background:rgba(var(--th-voile),.07);margin:var(--e-12) 0 var(--e-16);overflow:hidden}
.cok-raf-barre i{display:block;height:100%;background:var(--cok-accent,var(--cyan));border-radius:var(--r-micro);transition:width var(--t-long)}
.cok-raf-captcha{display:flex;align-items:center;gap:var(--e-10);background:rgba(240,194,90,.10);
  border:1px solid rgba(240,194,90,.25);border-radius: var(--r-md);padding:var(--e-10) var(--e-12);color:var(--cok-warn,#F0C25A);font-size:var(--t-base)}

.cok-raf-liste{display:flex;flex-direction:column;gap:var(--e-6);margin-top:var(--e-14)}
.cok-raf-l{display:flex;align-items:center;gap:var(--e-10);padding:var(--e-8) var(--e-12);border-radius: var(--r-sm);
  background:var(--surface);font-size:var(--t-base)}
.cok-raf-l.ok{color:var(--cok-green,#3FD19B)}
.cok-raf-l.ko{background:rgba(240,113,90,.08);color:var(--cok-red,var(--red))}
.cok-raf-l .n{flex:1;color:var(--text,var(--text))}
.cok-raf-l .m{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));max-width:44%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cok-raf-l .e{font-size:var(--t-mini)}

/* ── Bibliothèque vendeuses : les trois mondes ───────────────────────────────
   Ils étaient mélangés dans une seule grille — un visage sans compte et un compte
   sans visage n'ont rien à faire côte à côte. */
.lib-vend-onglets{display:flex;gap:var(--e-4);border-bottom:1px solid rgba(var(--th-voile),.08);margin:0 0 var(--e-14)}
.lib-vend-onglets.hidden{display:none}
.lib-vend-onglet{background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted,var(--text-2));
  font:inherit;font-size:var(--t-small);font-weight:var(--fw-moyen);padding:var(--e-8) var(--e-14);margin-bottom:calc(var(--e-1) * -1);cursor:pointer;
  display:inline-flex;align-items:center;gap:var(--e-6)}
.lib-vend-onglet:not(.on):hover{color:var(--text,var(--text))}
.lib-vend-onglet.on{color:var(--violet-soft,var(--violet-soft));border-bottom-color:var(--violet,var(--violet))}
.lib-vend-n{font-size:var(--t-meta);opacity:.75}
.lib-vend-n.attente{background:rgba(224,164,59,.18);color:var(--amber);border-radius: var(--r-md);padding:var(--e-1) var(--e-8);opacity:1}

/* ── L'écran « À allier » : un compte à gauche, un visage à droite ───────────── */
.lib-allier{padding:var(--e-2) 0 var(--e-10)}
.lib-allier.hidden{display:none}
.lib-allier-tete{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--e-12)}
.lib-allier-tete span{font-size:var(--t-base);color:var(--text-muted,var(--text-2))}
.lib-allier-manque{font-size:var(--t-base);padding:var(--e-10) var(--e-12);border-radius: var(--r-md);margin-bottom:var(--e-12);
  background:rgba(224,164,59,.10);border:1px solid rgba(224,164,59,.25);color:var(--amber)}
.lib-allier-corps{display:flex;gap:var(--e-14);align-items:flex-start}
/* Sur écran étroit, deux colonnes côte à côte deviennent illisibles : elles passent
   l'une sous l'autre, et la flèche se couche. */
@media (max-width:980px){
  .lib-allier-corps{flex-direction:column}
  .lib-allier-col{width:100%}
  .lib-allier-fleche{padding-top:0;align-self:center;transform:rotate(90deg)}
}
.lib-allier-col{flex:1;min-width:0}
.lib-allier-titre{font-size:var(--t-mini);color:var(--text-muted,var(--text-2));letter-spacing:var(--ls-ample);
  text-transform:uppercase;margin-bottom:var(--e-8)}
.lib-allier-fleche{flex:0 0 auto;padding-top:46px;color:var(--violet-soft,var(--violet-soft));opacity:.8}

.lib-allier-c{display:flex;align-items:center;gap:var(--e-10);width:100%;text-align:left;margin-bottom:var(--e-6);
  padding:var(--e-10) var(--e-12);border-radius: var(--r-md);background:var(--surface);
  border:1px solid transparent;color:inherit;font:inherit;cursor:pointer}
.lib-allier-c:hover{background:var(--surface-2)}
.lib-allier-c.on{border-color:var(--violet-glow);background:rgba(var(--th-accent-rgb),.10)}
.lib-allier-c .ref{flex:0 0 auto;width:30px;height:26px;border-radius: var(--r-sm);display:flex;
  align-items:center;justify-content:center;font-size:var(--t-micro);background:var(--bg-elevated);
  color:var(--text-muted,var(--text-2))}
.lib-allier-c.on .ref{background:var(--cok-accent-bg);color:var(--violet-soft,var(--violet-soft))}
.lib-allier-c .txt{flex:1;min-width:0;display:flex;flex-direction:column}
.lib-allier-c .txt b{font-size:var(--t-base);font-weight:var(--fw-moyen)}
.lib-allier-c .txt i{font-style:normal;font-size:var(--t-mini);color:var(--text-muted,var(--text-2));
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-allier-c .pick{font-size:var(--t-micro);color:var(--violet-soft,var(--violet-soft))}

.lib-allier-visages{display:grid;grid-template-columns:repeat(auto-fill,minmax(84px,1fr));gap:var(--e-8)}
.lib-allier-v{padding:0;border:1px solid rgba(var(--th-voile),.07);border-radius: var(--r-md);overflow:hidden;
  background:none;color:inherit;font:inherit;cursor:pointer;text-align:left}
.lib-allier-v:hover{border-color:rgba(var(--th-voile),.16)}
.lib-allier-v.on{border-color:rgba(var(--th-accent-rgb),.55)}
.lib-allier-v .ph{display:block;height:70px;background-size:cover;background-position:center top;
  background-color:rgba(var(--th-voile),.04)}
.lib-allier-v .ph.vide{background-image:none}
.lib-allier-v .n{display:block;font-size:var(--t-micro);padding:var(--e-6) var(--e-8);background:var(--surface);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-allier-plus{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-top:var(--e-8)}
.lib-allier-go{width:100%;margin-top:var(--e-14);padding:var(--e-12);border:none;
  background:linear-gradient(120deg,var(--violet),var(--violet-soft));color: var(--sur-accent);font-size:var(--t-small)}
.lib-allier-aide{text-align:center;font-size:var(--t-base);color:var(--text-muted,var(--text-2));margin-top:var(--e-14)}
.lib-allier-vide{text-align:center;font-size:var(--t-base);color:var(--text-muted,var(--text-2));padding:34px var(--e-12)}

/* ── La réserve : deux rayons, visages et voitures ───────────────────────────
   Amadou : « dans la réserve il doit y avoir une partie visage et une partie voiture ».
   Les mélanger était le défaut d'origine — on ne les regarde pas de la même façon. */
.lib-reserve{padding:var(--e-2) 0 var(--e-10)}
.lib-reserve.hidden{display:none}
.lib-res-bloc{margin-bottom:var(--e-22)}
.lib-res-titre{display:flex;align-items:baseline;gap:var(--e-10);font-size:var(--t-small);font-weight:var(--fw-moyen);margin-bottom:var(--e-10)}
.lib-res-titre span{font-size:var(--t-meta);background:rgba(var(--th-voile),.07);border-radius: var(--r-md);padding:var(--e-1) var(--e-8);
  color:var(--text-muted,var(--text-2))}
.lib-res-titre i{font-style:normal;font-size:var(--t-meta);color:var(--text-muted,var(--text-2))}
/* ⚠️ LA MÊME GRILLE QUE LA BIBLIOTHÈQUE, PAS UNE VARIANTE. Elle était en 110 px
   d'espacement 9 : presque deux fois plus petite que les cartes vendeuses (186 px,
   espacement 16). Amadou, 05/08 : « je ne comprends pas pourquoi vouloir faire un truc
   différent là ». Il a raison — choisir un visage pour une vendeuse, c'est le même geste
   que parcourir la Bibliothèque, donc la même grille. À 110 px on ne juge pas un
   cadrage. Les valeurs sont copiées de .lib-grid, pas réinventées. */
.lib-res-grille{display:grid;grid-template-columns:repeat(auto-fill,minmax(186px,1fr));gap:var(--e-16)}

/* ── L'ÉTAPE ENREGISTRER : DEUX COLONNES DE MÊME HAUTEUR ───────────────────────
   Amadou (03/09) : « essaie de bien aligner la partie gauche et la partie droite, ce
   qu'on a enregistré et où il va, car ça fait un moment une zone vide en dessous qui
   n'est pas très esthétique ».
   ⚠️ `align-items:stretch` sur la grille NE SUFFIT PAS : ce sont les CARTES qu'il faut
   étirer, pas les colonnes. Sans `height:100%` sur la carte, la colonne s'étire et la
   carte reste courte — c'est exactement le creux qu'il décrit. */
/* ══ ENREGISTRER : UNE SEULE COLONNE, CENTRÉE ═════════════════════════════════
   Amadou (06/09) : « il y a beaucoup de vide, je trouve — vraiment, utilisez l'espace ».

   ⚠️⚠️⚠️ LE VIDE VENAIT DE LA COLONNE DE DROITE, et l'étirement des deux cartes à la même
   hauteur (03/09) ne pouvait rien pour lui : elle ne portait qu'un champ de 36 px. On
   égalisait la hauteur du creux au lieu de retirer le creux.
   ⚠️ CE QUI A DISPARU AVEC : `atl-save-haut`, `atl-save-col`, `atl-save-carte`,
   `atl-save-nomdupack`, `atl-save-pied`, et le bloc d'identité (`atl-save-qui`,
   `atl-save-avatar`, `atl-save-nom`, `atl-save-sous`, `atl-save-mention`). Plus
   `atl-save-note` et `atl-save-rangee*`, qui n'avaient DÉJÀ plus aucun lecteur — vérifié
   dans app.js et index.html avant de les retirer. */
/* ⚠️ AMADOU (06/09) : « il y a de la place, donc plus d'espace entre les parties, un tout
   petit peu plus, pour que ce soit plus épuré. » Un cran sur l'échelle, pas deux : la
   colonne est bornée à 520 px et l'écran ne défile pas — c'est de l'air entre les parties
   qu'il demande, pas une page plus longue.
   ⚠️ ET ON MONTE SUR L'ÉCHELLE, on n'invente pas un nombre : 16 → 24. */
.atl-save-colonne{max-width:520px;margin:0 auto;display:flex;flex-direction:column;
  gap:var(--e-24)}
/* La ligne qui dit ce qu'on enregistre respire un peu au-dessus des vues. */
.atl-save-ligne{text-align:center;font-size:var(--t-meta);color:var(--text-3);
  margin-bottom:calc(var(--e-4) * -1)}
/* ⚠️ ON EMPRUNTE `vd-vues` (grille de trois portraits) ET ON REDIT CE QU'ON CHANGE : elle
   porte une marge verticale faite pour la fiche d'une vendeuse, que le `gap` de la colonne
   rend ici en double. Une brique empruntée impose ses propriétés — on les nomme. */
.atl-save-vues{margin:0}
.atl-save-aide{margin-top:var(--e-8);font-size:var(--t-meta);color:var(--text-3)}
/* ⚠️ LE LABEL COLLAIT À SON CHAMP : le titre « Nom du pack » et l'entrée forment un bloc,
   et c'est ce bloc qui doit être séparé du reste, pas ses deux moitiés l'une de l'autre. */
.atl-save-champ .atelier-block-label{margin-bottom:var(--e-8)}
/* Le geste de l'étape : pleine largeur de la colonne, il n'y a rien d'autre à faire ici. */
.atl-save-colonne .atelier-save-btn{width:100%;justify-content:center}

/* L'AVERTISSEMENT. Deux tons : une remarque, et un vrai risque. */
.atl-save-alerte{border:var(--e-1) solid var(--border);border-radius:var(--r-md);
  padding:var(--e-12) var(--e-14);background:var(--surface-2)}
.atl-save-alerte--grave{border-color:var(--amber)}
.atl-save-alerte-t{font-size:var(--t-small);color:var(--text);margin-bottom:var(--e-6)}
.atl-save-alerte--grave .atl-save-alerte-t{color:var(--amber)}
.atl-save-alerte-l{margin:0;padding-left:var(--e-18);font-size:var(--t-base);
  color:var(--text-2);line-height:var(--lh-normal)}
.atl-save-alerte-p{margin-top:var(--e-8);font-size:var(--t-base);color:var(--text-2);
  line-height:var(--lh-normal)}
.atl-save-alerte-b{margin-top:var(--e-10)}

/* ⚠️ EN ÉTROIT, LES TROIS VUES PASSENT EN DEUX RANGS. `vd-vues` est figée à trois colonnes
   — c'est bon dans la fiche d'une vendeuse, qui occupe toute la largeur ; ici la colonne
   plafonne à 520 px, et trois portraits 3:4 y deviennent des timbres. */
@media (max-width:640px){
  .atl-save-vues{grid-template-columns:repeat(2,1fr)}
}

/* ── L'IDENTITÉ : DEUX COLONNES, PUIS LA BIO ───────────────────────────────────
   Amadou (03/09) : « il y a tout à gauche alors qu'à droite, c'est un espace monstre ».
   La bande des visages prenait toute la largeur pendant que les quatre champs se
   serraient dans la moitié gauche. Le visage tient dans une colonne fixe, les champs
   remplissent le reste, et la bio — le seul champ qui a vraiment besoin de la largeur —
   passe dessous. */
/* ⚠️ CINQUANTE-CINQUANTE. Amadou (03/09) : « ça doit faire cinquante cinquante […] les
   bulles de texte sont trop longues, ce qui fait que la partie photo de profil est
   entassée ». Une colonne fixe de 250 px laissait les champs manger tout le reste :
   sur un large écran, quatre champs étirés sur 1 500 px contre des visages à l'étroit. */
/* ⚠️ LES DEUX COLONNES FONT LA MÊME HAUTEUR, PAS SEULEMENT LA MÊME LARGEUR.
   Un plafond en pixels sur la grille des visages ne vaut que pour une largeur d'écran :
   mesuré, 220 contre 225 à 1280 px mais 217 contre 144 à 1600, parce que les champs se
   replient différemment. C'est la GRILLE qui prend la hauteur qui reste — elle défile si
   les visages débordent. Un `min-height` garde une rangée visible même quand la colonne
   de droite est courte (une niche d'objet n'a ni taille ni poids). */
.atl-ident-haut{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:var(--e-18);align-items:stretch;margin-bottom:var(--e-16)}
/* ⚠️ LES DEUX COLONNES COMMENCENT À LA MÊME LIGNE. `.atelier-identity-grid` porte un
   `margin-top` de 16 px, hérité du temps où elle suivait un bouton : mesuré à l'écran,
   son premier libellé tombait 16 px sous celui de la photo. */
.atl-ident-haut > .atelier-identity-grid{margin-top:0}
.atl-ident-photo{min-width:0;display:flex;flex-direction:column}
/* Fabriquer, importer et prendre sont trois façons d'obtenir la même chose : même
   format, même grille, et la tuile retenue porte l'anneau. */
/* LA GRILLE DES VISAGES.
   ⚠️ `auto-fit`, PAS `auto-fill` : `auto-fill` crée les colonnes vides ET LEUR GARDE LA
   PLACE — cinq tuiles dans six pistes laissaient un trou au bout de la rangée, juste
   avant la colonne des champs (Amadou, 03/09 : « un espace au milieu béant »).
   ⚠️ MAIS `auto-fit` REPLIE LES PISTES VIDES, et une tuile SEULE prend alors toute la
   largeur : Sourcing vide, le bouton « + » mesurait 486 px de côté. Le plafond de largeur
   borne ce cas sans rien changer aux autres — mesuré, les tuiles font 69 à 90 px dès
   qu'il y en a plusieurs.
   ⚠️⚠️ ET LE SURVOL SOULÈVE LA CARTE DE 3 px, que `overflow-y` coupait en haut — le même
   défaut que sur les cartes de niches. La réserve de hauteur se prend DANS le conteneur
   qui défile, sinon elle ne sert à rien.
   Une photo de profil est un CARRÉ, pas un portrait en pied : c'est la vignette ronde
   qu'un acheteur voit sur Vinted. Deux rangées tiennent la hauteur des champs de droite. */
.atl-visages{display:grid;grid-template-columns:repeat(auto-fit,minmax(64px,1fr));
  gap:var(--e-6);margin-top:var(--e-4);padding-top:var(--e-4);
  flex:1 1 auto;min-height:96px;overflow-y:auto;align-content:start}
/* ⚠️ UNE PASTILLE RONDE, PAS UNE CARTE DE BIBLIOTHÈQUE. On empruntait `.lib-res-v` — la
   carte rectangulaire qui présente une modèle en pied. Ici on choisit ce qui s'affichera
   en petit rond sur un profil Vinted : deux objets différents, et les faire se ressembler
   entretenait la confusion qu'Amadou a relevée (« ça ne me propose pas des photos de
   profil, mais des templates de modèle »). */
.atl-vis{position:relative;aspect-ratio:1;padding:0;border:none;background:none;
  cursor:pointer;display:block;border-radius:50%}
.atl-vis .ph{display:block;width:100%;height:100%;border-radius:50%;
  background-size:cover;background-position:center 22%;background-color:var(--surface);
  box-shadow:0 0 0 var(--e-1) rgba(var(--th-voile),.10);
  transition:box-shadow var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose)}
.atl-vis:not(.choisi):hover .ph{transform:scale(1.06);
  box-shadow:0 0 0 var(--e-2) var(--violet-mid)}
.atl-vis.choisi .ph{box-shadow:0 0 0 var(--e-2) var(--violet-light)}
/* La tuile qui travaille : elle occupe LA PLACE du résultat à venir. */
.atl-vis--travail{cursor:progress}
.atl-vis--travail .ph{display:flex;align-items:center;justify-content:center;
  border:var(--e-1) dashed var(--border)}
/* Le plafond qui borne le cas dégénéré : une tuile seule ne prend pas la colonne. */
.atl-visages > *{max-width:96px}
/* LA DERNIÈRE TUILE, VIDE. Même format qu'un visage — c'en est une place — mais elle
   n'en montre aucun : elle ouvre la fenêtre qui les montre tous. */
.atl-visage-plus{display:flex;align-items:center;justify-content:center;
  aspect-ratio:1;background:none;color:var(--text-3);cursor:pointer;
  border:var(--e-1) dashed var(--border);border-radius:var(--r-md);
  transition:border-color var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose)}
.atl-visage-plus:hover{border-color:var(--violet-mid);color:var(--text)}
/* La fenêtre : la même vignette, en plus grand, et tout le stock. */
.mvis-corps{padding:var(--e-20);overflow-y:auto;max-height:60vh}
.mvis-grille{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:var(--e-10)}
.mvis-grille .atl-vis{width:auto}

.atl-visage-sep{display:none}
/* Deux boutons LARGES, côte à côte, au-dessus des visages. Au format d'une tuile ils
   étaient hauts et fins et on lisait mal ce qu'ils font. */
.atl-visages-gestes{display:grid;grid-template-columns:1fr 1fr;gap:var(--e-8);margin-top:var(--e-6)}
.atl-visage-geste{display:flex;align-items:center;justify-content:center;
  gap:var(--e-8);padding:var(--e-8) var(--e-12);
  background:none;color:var(--text-2);font:inherit;font-size:var(--t-base);cursor:pointer;
  border:var(--e-1) dashed var(--border);border-radius:var(--r-md);
  transition:border-color var(--d-fast) var(--c-pose), color var(--d-fast) var(--c-pose)}
.atl-visage-geste:hover{border-color:var(--violet-mid);color:var(--text)}
.atl-visage-geste.occupe{opacity:.55;cursor:progress}
/* L'ENTONNOIR. Amadou (03/09) : « la description, on la mettra au milieu pour que ça
   fasse un peu un entonnoir ». Le haut tient sur deux colonnes pleines, la bio se
   resserre au centre — l'œil descend des choix vers le texte au lieu de repartir sur
   toute la largeur. ⚠️ L'ENTONNOIR EST LÉGER : à 72 % la bio devenait une colonne de
   texte étroite alors que c'est le champ le plus long de l'étape. Elle reprend toute la
   place quand l'écran ne permet plus deux colonnes — à cette largeur, resserrer ne
   ferait que la rendre illisible. */
/* ⚠️⚠️ `width`, PAS `max-width`. Le corps d'une étape est un conteneur FLEX en colonne :
   une marge `auto` sur un élément flex ANNULE l'étirement, et la bio retombait à la
   largeur de son contenu — 230 px mesurés là où on en attendait 1552. Un `max-width`
   seul ne dit rien de la largeur voulue ; il faut la poser. */
.atl-ident-bio{margin:0 auto var(--e-8);width:88%}
/* ── LE PIED : la note à gauche, « Tout refaire » à droite ── */
.atl-ident-pied{display:flex;align-items:center;gap:var(--e-8);margin-top:var(--e-12);
  padding-top:var(--e-12);border-top:var(--e-1) solid var(--border)}
.atl-ident-note{font-size:var(--t-meta);color:var(--text-3)}
.atl-ident-pied .btn-secondary{margin-left:auto}
@media (max-width:900px){
  .atl-ident-haut{grid-template-columns:1fr}
  .atl-ident-bio{width:100%}
  .atl-visages{flex:0 0 auto;max-height:200px}
}
@media (max-width:640px){
  .lib-res-grille{grid-template-columns:repeat(auto-fill,minmax(96px,1fr))}
  .lib-res-liste{grid-template-columns:1fr}
  .lib-vend-onglets{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .lib-vend-onglet{white-space:nowrap;padding:var(--e-8) var(--e-12)}
}
.lib-res-v{padding:0;border:1px solid rgba(var(--th-voile),.07);border-radius: var(--r-md);overflow:hidden;
  background:none;color:inherit;font:inherit;cursor:pointer;text-align:left}
/* ⚠️ LE MÊME GESTE QUE DANS LA BIBLIOTHÈQUE. La carte ne faisait que changer de
   bordure : elle restait plate là où une robe ou une vendeuse se soulève. Amadou,
   05/08 : « ça doit s'élever un tout petit peu, comme dans la partie robe ». Les
   valeurs sont COPIÉES de .lib-card:hover — même recul de 3 px, même ombre allégée,
   même durée. Deux cartes qui font le même métier doivent réagir pareil sous le doigt. */
.lib-res-v{transition:border-color var(--d-fast) var(--c-pose),
  transform var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose)}
.lib-res-v:hover{border-color:var(--violet-mid);transform:translateY(-3px);
  box-shadow:0 5px 18px -12px rgba(var(--th-ombre),.55), inset 0 1px 0 var(--bg-sidebar)}
/* Le 3/4 de .lib-card-cover, au lieu d'une hauteur fixe : une photo du Sourcing et
   une vue de vendeuse se regardent dans le même format. */
.lib-res-v .ph{display:block;aspect-ratio:3/4;border-radius: var(--r-sm);background-size:cover;
  background-position:center top;background-color:rgba(var(--th-voile),.04)}
.lib-res-v .n{display:block;font-size:var(--t-meta);padding:var(--e-6) var(--e-8);background:var(--surface);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Les voitures en GRILLE, pas en liste pleine largeur : une ligne par compte gaspille
   l'écran, et avec 83 comptes il faudrait dérouler sans fin. Le nombre de colonnes suit
   la largeur disponible — Amadou travaille sur un MacBook ET sur un grand écran. */
.lib-res-liste{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:var(--e-8)}
.lib-res-c{ display:flex;align-items:center;gap:var(--e-12);width:100%;text-align:left;
  color:inherit;font:inherit;cursor:pointer }
.lib-res-c:hover{border-color:rgba(var(--th-accent-rgb),.35);background:var(--bg-hover)}
.lib-res-c .txt{flex:1;min-width:0;display:flex;flex-direction:column}
.lib-res-c .txt b{font-size:var(--t-base);font-weight:var(--fw-moyen)}
.lib-res-c .txt i{font-style:normal;font-size:var(--t-mini);color:var(--text-muted,var(--text-2));
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lib-res-c .etat{flex:0 0 auto;font-size:var(--t-mini);color:var(--text-muted,var(--text-2))}
.lib-res-vide{font-size:var(--t-base);color:var(--text-muted,var(--text-2));padding:var(--e-14) var(--e-2)}
.lib-res-pont{font-size:var(--t-base);padding:var(--e-12) var(--e-14);border-radius: var(--r-md);
  background:rgba(var(--th-accent-rgb),.08);border:1px solid rgba(var(--th-accent-rgb),.22)}

/* ── Sélection dans le stock ─────────────────────────────────────────────────
   Une carte cochée doit se voir d'un coup d'œil : c'est ce qui permet de vérifier
   ce qu'on s'apprête à supprimer. */
.lib-res-v.choisi, .lib-res-c.choisi{border-color:var(--violet,var(--violet));
  box-shadow:0 0 0 1px var(--violet,var(--violet)) inset;background:rgba(var(--th-accent-rgb),.10)}
.lib-res-v{position:relative}
.lib-res-v .coche, .lib-res-c .coche{position:absolute;top:7px;left:7px;width:19px;height:19px;
  border-radius:var(--r-micro);border:1.5px solid rgba(var(--th-voile),.5);background:rgba(var(--th-ombre),.45);
  display:flex;align-items:center;justify-content:center;font-size:var(--t-meta);line-height:var(--lh-un);color: var(--sur-sombre)}
.lib-res-c{position:relative;padding-left:38px}
.lib-res-c .coche{top:50%;transform:translateY(-50%);left:11px}
.lib-res-v.choisi .coche, .lib-res-c.choisi .coche{background:var(--violet,var(--violet));
  border-color:var(--violet,var(--violet))}
#lib-select-bar .hidden{display:none !important}

/* ── Les noms de domaine : une ligne discrète, une petite fenêtre ────────────
   On n'y vient qu'à l'achat d'un domaine : ça ne mérite pas une rubrique à soi. */
.dom-ligne{ display:flex;align-items:center;justify-content:space-between;gap:var(--e-12);
  margin:var(--e-14) 0 0;font-size:var(--t-base) }
.dom-ligne i{font-style:normal;color:var(--text-muted,var(--text-2))}
.dom-ligne .dom-sert{color:var(--cyan,var(--cyan));font-weight:var(--fw-fort)}
.dom-ligne .cok-btn{flex:0 0 auto;--btn-texte: var(--t-meta); --btn-pad-v: var(--e-6); --btn-pad-h: var(--e-12)}

.dom-modale{position:fixed;inset:0;z-index:400;display:flex;align-items:center;justify-content:center;padding:var(--e-20)}
.dom-fond{position:absolute;inset:0;background:rgba(var(--th-panneau-rgb),.6);backdrop-filter:blur(3px)}
.dom-boite{position:relative;width:min(520px,100%);max-height:82vh;overflow:auto;
  background:var(--bg-card-solid,#161A2A);border:1px solid rgba(var(--th-voile),.10);
  border-radius: var(--r-lg);padding:var(--e-18) var(--e-20) var(--e-16)}
.dom-tete{display:flex;justify-content:space-between;align-items:center;margin-bottom:var(--e-14);font-size:var(--t-small)}
.dom-x{background:none;border:none;color:var(--text-muted,var(--text-2));font-size:var(--t-small);cursor:pointer;padding:var(--e-2) var(--e-4)}
.dom-x:hover{color:var(--text,var(--text))}
.dom-liste{display:flex;flex-direction:column;gap:var(--e-8)}
.dom-l{ display:flex;align-items:center;gap:var(--e-12) }
.dom-l.pause{opacity:.55}
.dom-sw{flex:0 0 auto;border:none;border-radius: var(--r-xl);cursor:pointer;font:inherit;font-size:var(--t-mini);
  font-weight:var(--fw-moyen);padding:var(--e-4) var(--e-10);background:rgba(63,209,155,.18);color:var(--green)}
.dom-l.pause .dom-sw{background:rgba(var(--th-voile),.08);color:var(--text-muted,var(--text-2))}
.dom-nom{flex:1;font-size:var(--t-small);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dom-stats{flex:0 0 auto;font-size:var(--t-meta);color:var(--text-muted,var(--text-2))}
.dom-ban{color:var(--cok-red,var(--red));font-weight:var(--fw-moyen)}
.dom-x2{flex:0 0 auto;background:none;border:none;color:var(--text-muted,var(--text-2));
  cursor:pointer;font-size:var(--t-meta);padding:var(--e-2) var(--e-4)}
.dom-x2:hover{color:var(--red)}
.dom-vide{font-size:var(--t-base);color:var(--text-muted,var(--text-2));padding:var(--e-16) var(--e-2);text-align:center}
.dom-ajout{display:flex;gap:var(--e-8);margin-top:var(--e-14)}
.dom-ajout input{flex:1;background:rgba(var(--th-voile),.04);border:1px solid rgba(var(--th-voile),.10);
  border-radius: var(--r-md);color:inherit;font:inherit;font-size:var(--t-base);padding:var(--e-10) var(--e-12)}
.dom-ajout input:focus{outline:none;border-color:var(--violet,var(--violet))}
.dom-ajout .cok-btn{flex:0 0 auto;white-space:nowrap}
.dom-note{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-top:var(--e-12);line-height:var(--lh-normal)}
@media (max-width:560px){
  .dom-ligne{flex-direction:column;align-items:flex-start}
  .dom-ajout{flex-direction:column}
  .dom-ajout .cok-btn{width:100%}
}

/* ── Messages : « à traiter » vit dans la liste des conversations ──────────────
   Amadou (2026-07-29) : deux onglets. Une conversation qui attend n'est pas une
   autre boîte, c'est une conversation urgente — elle remonte et porte son motif. */
.msg-vues{display:flex;gap:var(--e-6);padding:var(--e-10) var(--e-12) 0;flex-wrap:wrap}
.msg-vue{background:none;border:1px solid var(--cok-border,rgba(var(--th-voile),.10));color:var(--text-muted,var(--text-2));
  border-radius: var(--r-pilule);padding:var(--e-4) var(--e-12);font-size:var(--t-meta);cursor:pointer;transition: var(--transi)}
.msg-vue:not(.on):hover{color:var(--text,var(--text));border-color:rgba(var(--th-voile),.22)}
.msg-vue.on{background:rgba(var(--th-second-rgb),.12);border-color:var(--tier-volume-glow);color:var(--cyan,var(--cyan))}
.msg-item--esc{border-left:3px solid var(--amber);border-radius:0}
.msg-item-motif{display:block;font-size:var(--t-mini);margin-top:var(--e-4);color:var(--amber);line-height:var(--lh-serre)}
.msg-item-motif.grave{color:var(--red)}

/* ── Banc d'essai : le contexte réel du test ───────────────────────────────────
   Amadou (2026-07-29) : « ce n'est pas juste un affichage qui n'a pas de fond ».
   L'identité était le trou le plus grave — le banc ne l'envoyait pas au serveur,
   donc il testait l'espace par défaut et jamais les consignes d'Amadou. */
.pg-ident{font-size:var(--t-base);color:var(--cyan,var(--cyan));font-weight:var(--fw-fort);padding:var(--e-2) 0}
.pg-hint{font-size:var(--t-mini);color:var(--text-muted,var(--text-2));margin-top:var(--e-4);line-height:var(--lh-serre)}
.pg-entrepot{display:flex;gap:var(--e-6)}
.pg-ent-btn{flex:1;background:none;border:1px solid var(--cok-border,rgba(var(--th-voile),.10));
  color:var(--text-muted,var(--text-2));border-radius: var(--r-sm);padding:var(--e-6) 0;font-size:var(--t-meta);cursor:pointer;transition: var(--transi)}
.pg-ent-btn:hover{color:var(--text,var(--text))}
.pg-ent-btn.on{background:rgba(var(--th-second-rgb),.12);border-color:var(--tier-volume-glow);color:var(--cyan,var(--cyan))}
.pg-reglages{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));line-height:var(--lh-aere)}
.pg-reglages b{color:var(--text,var(--text));font-weight:var(--fw-fort)}
/* Le verdict : ce qui manquait le plus. On ne juge pas un bot dont on ne voit
   pas le raisonnement — la catégorie passait dans un toast de 3 secondes. */
.pg-verdict{border-left:2px solid var(--rp-blue-mid);border-radius:0;background:var(--surface);
  padding:var(--e-8) var(--e-10);margin:var(--e-2) 0 var(--e-10) 12%;font-size:var(--t-meta);line-height:var(--lh-aere)}
.pg-verdict-tags{display:flex;gap:var(--e-6);flex-wrap:wrap;margin-bottom:var(--e-4)}
.pg-vtag{border-radius: var(--r-sm);padding:var(--e-1) var(--e-8);font-size:var(--t-mini)}
.pg-vtag.envoi{background:rgba(52,211,153,.14);color:var(--green)}
.pg-vtag.esc{background:rgba(230,162,60,.14);color:var(--amber)}
.pg-vtag.silence{background:rgba(var(--th-voile),.07);color:var(--text-muted,var(--text-2))}
.pg-vtag.neutre{background:var(--bg-hover);color:var(--text-muted,var(--text-2));border:1px solid rgba(var(--th-voile),.08)}
.pg-verdict-why{color:var(--text-muted,var(--text-2))}

/* ── Onglet Formation : résumé + grille + trois couleurs ───────────────────────
   Amadou (2026-07-29) : « c'est mal fait », « l'espace n'est pas du tout
   optimisé ». Même correctif que la bibliothèque : une GRILLE auto-fit, jamais
   des lignes pleine largeur — à cinquante comptes une liste verticale fait
   plusieurs écrans pour une information qui se lit d'un coup d'œil.
   Le code couleur est strict : vert = ne fais rien, jaune = Velbo s'en est remis
   seul, rouge = toi seul peux le régler. */
.form-resume{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:var(--e-10);margin:var(--e-12) 0 var(--e-12)}
/* Les tuiles SONT les filtres : cliquer sur un chiffre montre les comptes qu'il
   compte. Avant, un bandeau de chiffres et une barre de boutons disaient la même
   chose l'un sous l'autre (Amadou : « trop d'informations pour rien »). */
.form-tuile{ display:flex;flex-direction:column;gap:var(--e-2);
  cursor:pointer;text-align:left;font:inherit;transition: var(--transi) }
.form-tuile:hover{border-color:rgba(var(--th-voile),.20)}
/* UNE SEULE tuile allumée à la fois (Amadou, 2026-07-29). Au repos elles sont
   ÉTEINTES : fond neutre, texte gris, seul le chiffre reste lisible. La couleur
   n'apparaît que sur la tuile sélectionnée — quatre tuiles colorées en
   permanence, c'était du bruit, et on ne voyait pas laquelle était active. */
.form-tuile.total.on{background:rgba(var(--th-second-rgb),.12);border-color:var(--cyan-glow)}
.form-tuile.total.on .form-tuile-lab,.form-tuile.total.on .form-tuile-n{color:var(--cyan,var(--cyan))}
/* ⚠️ Les tuiles sont des <button> : sans couleur explicite, le chiffre hérite du
   noir par défaut du navigateur et devient INVISIBLE sur fond sombre (mesuré :
   rgb(0,0,0) au repos). Il doit rester lisible éteint — c'est l'information. */
.form-tuile-lab{font-size:var(--t-meta);color:var(--text-muted,var(--text-2))}
.form-tuile-n{font-size:var(--t-lead);font-weight:var(--fw-fort);line-height:var(--lh-titre);color:var(--text,var(--text))}
.form-tuile.vert.on{background:rgba(52,211,153,.12);border-color:rgba(52,211,153,.38)}
.form-tuile.vert.on .form-tuile-lab,.form-tuile.vert.on .form-tuile-n{color:var(--green)}
.form-tuile.jaune.on{background:rgba(230,162,60,.12);border-color:rgba(230,162,60,.38)}
.form-tuile.jaune.on .form-tuile-lab,.form-tuile.jaune.on .form-tuile-n{color:var(--amber)}
.form-tuile.rouge.on{background:rgba(226,75,74,.12);border-color:rgba(226,75,74,.40)}
.form-tuile.rouge.on .form-tuile-lab,.form-tuile.rouge.on .form-tuile-n{color:var(--red)}

.form-grille{display:grid;grid-template-columns:repeat(auto-fit,minmax(212px,1fr));gap:var(--e-10)}
.form-carte{background:rgba(var(--th-voile),.025);border:1px solid var(--cok-border,rgba(var(--th-voile),.07));
  border-left-width:3px;border-radius:0 10px 10px 0;padding:var(--e-10) var(--e-12);min-width:0}
.form-carte.vert {border-left-color:var(--green)}
.form-carte.jaune{border-left-color:var(--amber)}
.form-carte.rouge{border-left-color:var(--red);background:rgba(226,75,74,.05)}
.form-carte.fini {border-left-color:rgba(var(--th-voile),.22)}
.form-carte-tete{display:flex;justify-content:space-between;align-items:baseline;gap:var(--e-8)}
.form-carte-nom{font-size:var(--t-base);font-weight:var(--fw-fort);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.form-carte-reste{font-size:var(--t-mini);color:var(--text-muted,var(--text-2));white-space:nowrap;flex:0 0 auto}
.form-barre{height:4px;background:rgba(var(--th-voile),.07);border-radius:2px;margin:var(--e-8) 0 var(--e-8);overflow:hidden}
.form-barre i{display:block;height:100%;background:var(--green);border-radius:2px}
.form-carte.jaune .form-barre i{background:var(--amber)}
.form-carte.rouge .form-barre i{background:var(--red)}
.form-carte.fini  .form-barre i{background:rgba(var(--th-voile),.28)}
.form-carte-chiffres{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));line-height:var(--lh-normal)}
.form-carte-etat{font-size:var(--t-mini);margin-top:var(--e-4);line-height:var(--lh-normal)}
.form-carte-etat.vert {color:var(--green)}
.form-carte-etat.jaune{color:var(--amber)}
.form-carte-etat.rouge{color:var(--red)}
.form-carte-etat.fini {color:var(--text-muted,var(--text-2))}
@media (max-width:560px){ .form-grille{grid-template-columns:1fr} }

/* ── Banc d'essai : le contexte en UN encart ───────────────────────────────────
   Amadou (2026-07-29) : « le mode playground, tu ne l'as pas codé ». Il avait
   raison sur le fond — j'avais AJOUTÉ trois blocs à une colonne déjà chargée,
   ce qui l'a rendue plus longue qu'avant et a écrasé la conversation. Ici chaque
   réglage tient sur une ligne clé-valeur : six blocs deviennent un encart. */
.pg-ctx{background:var(--surface);border:1px solid var(--cok-border,rgba(var(--th-voile),.07));
  border-radius: var(--r-md);padding:var(--e-4) var(--e-10);margin-bottom:var(--e-8)}
.pg-ctx-l{display:flex;align-items:center;justify-content:space-between;gap:var(--e-8);
  min-height:30px;font-size:var(--t-meta);border-bottom:1px solid var(--bg-hover)}
.pg-ctx-l:last-of-type{border-bottom:none}
.pg-ctx-l>span:first-child{color:var(--text-muted,var(--text-2));flex:0 0 auto}
.pg-ctx-l b{color:var(--cyan,var(--cyan));font-weight:var(--fw-fort);font-size:var(--t-meta);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;min-width:0}
.pg-ctx-btn{background:none;border:1px solid var(--cok-border,rgba(var(--th-voile),.10));
  color:var(--text,var(--text));border-radius: var(--r-sm);padding:var(--e-4) var(--e-10);font-size:var(--t-meta);cursor:pointer}
.pg-ctx-btn:hover{border-color:rgba(var(--th-voile),.22)}
.pg-ctx-prix{display:flex;align-items:center;gap:var(--e-4);color:var(--text-muted,var(--text-2));font-size:var(--t-meta)}
.pg-ctx-prix input{width:52px;background:var(--bg-hover);border:1px solid rgba(var(--th-voile),.08);
  border-radius: var(--r-sm);color:var(--text,var(--text));font-size:var(--t-meta);padding:var(--e-4) var(--e-6);text-align:right}
.pg-ctx-tailles{display:flex;gap:var(--e-4)}
.pg-ctx-tailles .dem-pill{padding:var(--e-2) var(--e-6);font-size:var(--t-micro);min-width:0}
.pg-ctx-note{font-size:var(--t-mini);color:var(--text-muted,var(--text-2));padding:var(--e-6) 0 var(--e-6)}
.pg-ctx .pg-dress-thumb{width:22px;height:22px;border-radius:var(--r-micro);background-size:cover;
  background-position:center;flex:0 0 auto;background-color:var(--bg-elevated)}
.pg-ctx .pg-dress-rm{background:none;border:none;color:var(--text-muted,var(--text-2));
  cursor:pointer;font-size:var(--t-small);padding:0 var(--e-2);line-height:var(--lh-un)}
/* Les scénarios prenaient 9 px de padding et 12 px de police pour huit boutons :
   la colonne défilait alors que tout doit tenir sous les yeux pendant qu'on teste. */
.pg-layout .pg-scn-btn{padding:var(--e-6) var(--e-10);font-size:var(--t-meta);gap:var(--e-6)}
.pg-layout .pg-scn-btn svg{width:12px;height:12px}
.pg-layout .pg-sim-btn{padding:var(--e-6) var(--e-10);font-size:var(--t-meta)}
.pg-layout .pg-sidebar-block{margin-bottom:var(--e-12)}
.pg-layout .pg-sidebar-label{margin-bottom:var(--e-6)}

/* Les deux onglets du VRAI écran Messages (#cockpit-messages). Le banc d'essai
   avait été bâti dans #section-messages, que Velbo n'ouvre jamais depuis la
   barre latérale — d'où « je ne le vois pas » (Amadou, 2026-07-29). */
/* ⚠️ Cette barre était collée au bord gauche (padding 0), alors que la même barre est
   rentrée de 32 px sur tous les autres écrans — l'œil voyait le décalage tout de suite
   (Amadou, 2026-07-30 : « un peu trop sur la partie gauche, donc c'est moche »).
   Ici la toile de l'écran Messages n'a AUCUN padding (c'est une mise en page en trois
   colonnes pleine hauteur) : la barre porte donc sa gouttière elle-même. */
/* ⚠️ Amadou (23/08) : « les boutons Conversations et Tester le bot sont trop centrés,
   mets-les plus vers la gauche, mais ne les colle pas à la bordure ». 32 px les poussaient
   au milieu de nulle part ; 16 px les rapprochent en gardant de l'air. */
.cokmsg-tabs{display:flex;gap:var(--e-8);padding:var(--e-16) var(--e-16) var(--e-12);flex-shrink:0}
.cokmsg-tab{background:none;border:none;border-bottom:2px solid transparent;
  color:var(--text-muted,var(--text-2));font-size:var(--t-base);font-family:inherit;
  padding:var(--e-8) var(--e-12) var(--e-8);cursor:pointer;transition: var(--transi)}
.cokmsg-tab:not(.on):hover{color:var(--text,var(--text))}
.cokmsg-tab.on{color:var(--cyan,var(--cyan));border-bottom-color:var(--cyan,var(--cyan))}
#msg-panel-playground.pg-layout{min-height:520px}
/* `hidden` est un attribut, pas une classe : une règle display explicite l'écrase.
   Sans ça, la ligne « robe » s'affiche vide (« — × ») alors qu'aucune robe n'est
   choisie. */
.pg-ctx-l[hidden]{display:none}

/* ═══════════════════════════════════════════════════════════════════════════
   BANC D'ESSAI — refonte 2026-07-29 (Amadou : « c'est moche, vieillot, l'espace
   n'est pas optimisé »). Carte robe VISUELLE, contrôles modernes, 14 messages
   tout prêts qui remplissent le champ, offre acheteur compacte.
   ═══════════════════════════════════════════════════════════════════════════ */
.pg-sidebar { display: flex; flex-direction: column; gap: var(--e-12); padding: var(--e-14); overflow-y: auto; }

/* ── La robe : une vraie carte avec sa photo ── */
.pg-card { display: flex; gap: var(--e-12); padding: var(--e-10); border-radius: var(--r-lg);
  background: var(--bg-card); border: 1px solid var(--border); position: relative; }
.pg-card-photo { width: 62px; height: 82px; border-radius: var(--r-md); flex-shrink: 0;
  background: var(--bg-hover) center/cover no-repeat; border: 1px solid var(--border); }
.pg-card-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: var(--e-4); padding-top: var(--e-2); }
.pg-card-name { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); line-height: var(--lh-titre);
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.pg-card-meta { font-size: var(--t-meta); color: var(--text-3); }
.pg-card-thumbs { display: flex; gap: var(--e-4); margin-top: var(--e-4); flex-wrap: wrap; }
.pg-card-thumbs:empty { display: none; }
.pg-dress-thumb-mini { width: 22px; height: 22px; border-radius: var(--r-micro); padding: 0; cursor: pointer;
  background: center/cover no-repeat; border: 1.5px solid transparent; opacity: .6; transition: var(--transi-vif); }
.pg-dress-thumb-mini:not(.active):hover { opacity: 1; }
.pg-dress-thumb-mini.active { opacity: 1; border-color: var(--cyan); }
.pg-card-x { position: absolute; top: 7px; right: 7px; width: 22px; height: 22px; padding: 0;
  display: flex; align-items: center; justify-content: center; border-radius: var(--r-sm); cursor: pointer;
  background: var(--bg-hover); border: none; color: var(--text-3); transition: var(--transi-vif); }
.pg-card-x:hover { background: rgba(226,75,74,.16); color: var(--red); }

.pg-pick { display: flex; align-items: center; justify-content: center; gap: var(--e-8); width: 100%;
  padding: var(--e-12); border-radius: var(--r-md); cursor: pointer; font-size: var(--t-base); font-weight: var(--fw-moyen);
  color: var(--cyan-soft); background: var(--cyan-tint);
  border: 1px dashed rgba(var(--th-second-rgb),.4); transition: var(--transi-vif); }
.pg-pick:hover { background: var(--cyan-tint); border-color: var(--cyan); color: var(--cyan); }

/* ── Réglages : lignes clé/valeur, contrôles segmentés modernes ── */
.pg-set { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-4) var(--e-12); }
.pg-set-row { display: flex; align-items: center; justify-content: space-between; gap: var(--e-10);
  min-height: 38px; border-bottom: 1px solid var(--bg-hover); }
.pg-set-row:last-of-type { border-bottom: none; }
.pg-set-k { font-size: var(--t-meta); color: var(--text-3); flex-shrink: 0; }
.pg-set-v { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--cyan); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.pg-price-wrap { display: flex; align-items: center; gap: var(--e-4); }
.pg-price-wrap input { width: 58px; text-align: right; background: var(--bg-hover);
  border: 1px solid var(--border-mid); border-radius: var(--r-sm); color: var(--text); font-size: var(--t-base);
  padding: var(--e-6) var(--e-8); outline: none; -moz-appearance: textfield; }
.pg-price-wrap input::-webkit-outer-spin-button, .pg-price-wrap input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pg-price-wrap input:focus { border-color: var(--cyan); }
.pg-price-wrap i { font-style: normal; font-size: var(--t-meta); color: var(--text-3); }
.pg-seg { display: inline-flex; background: rgba(var(--th-voile),.04); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--e-2); gap: var(--e-1); }
.pg-seg-b { border: none; background: none; color: var(--text-3); font-size: var(--t-meta); font-weight: var(--fw-moyen);
  padding: var(--e-4) var(--e-10); border-radius: var(--r-sm); cursor: pointer; transition: var(--transi-vif); font-family: inherit; }
.pg-seg-b:not(.active):hover { color: var(--text); }
.pg-seg-b.on, .pg-seg-b.active { background: var(--cyan); color: #062b30; }
.pg-set-note { font-size: var(--t-mini); color: var(--text-3); padding: var(--e-8) 0 var(--e-4); }
.pg-set-reglages { font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-aere); border-top: 1px solid var(--bg-elevated);
  padding: var(--e-8) 0 var(--e-6); }
.pg-set-reglages b { color: var(--text-2); font-weight: var(--fw-fort); }

/* ── Les 14 messages tout prêts ── */
.pg-cats-head { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-2); padding: var(--e-2) var(--e-2) 0; }
.pg-cats-head span { font-weight: var(--fw-normal); color: var(--text-3); }
.pg-cats { display: flex; flex-wrap: wrap; gap: var(--e-6); }
.pg-cat { display: inline-flex; align-items: center; gap: var(--e-6); padding: var(--e-6) var(--e-10); border-radius: var(--r-pilule);
  cursor: pointer; font-size: var(--t-meta); font-weight: var(--fw-moyen); font-family: inherit; color: var(--text-2);
  background: var(--bg-card); border: 1px solid var(--border); transition: var(--transi-vif); }
.pg-cat:hover { border-color: var(--border-strong); color: var(--text); transform: translateY(-1px); }
.pg-cat:active { transform: translateY(0); }
.pg-cat .dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.pg-cat .dot.repond { background: var(--green); }
.pg-cat .dot.escalade { background: var(--amber); }
.pg-cat .dot.silence { background: var(--text-3); }

/* ── Alertes, repliées par défaut ── */
.pg-notifs { border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-card); overflow: hidden; }
.pg-notifs summary { font-size: var(--t-meta); color: var(--text-2); padding: var(--e-10) var(--e-12); cursor: pointer; list-style: none; }
.pg-notifs summary::-webkit-details-marker { display: none; }
.pg-notifs summary::before { content: '+'; color: var(--text-3); margin-right: var(--e-8); font-weight: var(--fw-fort); }
.pg-notifs[open] summary::before { content: '–'; }
.pg-notifs-body { padding: 0 var(--e-12) var(--e-12); }
.pg-notifs-hint { font-size: var(--t-mini); color: var(--text-3); margin-bottom: var(--e-8); line-height: var(--lh-normal); }
.pg-sim-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-6); }
.pg-sim-btn { padding: var(--e-8); border-radius: var(--r-sm); font-size: var(--t-meta); font-family: inherit; cursor: pointer;
  color: var(--text-2); background: rgba(var(--th-voile),.04); border: 1px solid var(--border); transition: var(--transi-vif); }
.pg-sim-btn:hover { border-color: var(--border-strong); color: var(--text); }
.pg-sim-btn.pg-sim-fired { border-color: var(--green); background: rgba(47,191,113,.14); color: var(--green); }

/* ── Composeur : message + offre compacte sur une ligne ── */
.pg-composer { border-top: 1px solid var(--border); background: var(--bg-panel); padding: var(--e-12) var(--e-14);
  display: flex; flex-direction: column; gap: var(--e-10); }
.pg-input { width: 100%; resize: none; background: var(--bg-card); border: 1px solid var(--border-mid);
  border-radius: var(--r-md); color: var(--text); font-size: var(--t-base); font-family: inherit; padding: var(--e-10) var(--e-12); outline: none; line-height: var(--lh-normal); }
.pg-input:focus { border-color: var(--cyan); }
.pg-composer-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--e-10); }
.pg-offer-mini { display: inline-flex; align-items: center; gap: var(--e-6); }
.pg-offer-mini i { font-style: normal; font-size: var(--t-meta); color: var(--text-3); }
.pg-offer-mini input { width: 54px; text-align: right; background: var(--bg-card); border: 1px solid var(--border-mid);
  border-radius: var(--r-sm); color: var(--text); font-size: var(--t-base); padding: var(--e-6) var(--e-8); outline: none; -moz-appearance: textfield; }
.pg-offer-mini input::-webkit-outer-spin-button, .pg-offer-mini input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pg-offer-mini input:focus { border-color: var(--cyan); }
.pg-offer-mini b { font-size: var(--t-meta); color: var(--text-3); font-weight: var(--fw-normal); }
.pg-offer-mini button { padding: var(--e-6) var(--e-12); border-radius: var(--r-sm); font-size: var(--t-meta); font-weight: var(--fw-fort); cursor: pointer;
  color: var(--cyan-soft); background: var(--cyan-tint); border: 1px solid var(--tier-volume-glow); transition: var(--transi-vif); font-family: inherit; }
.pg-offer-mini button:hover { background: var(--cok-blue-bg); color: var(--cyan); }
.pg-composer-tools { display: inline-flex; align-items: center; gap: var(--e-8); }
.pg-reset-btn { width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); cursor: pointer; color: var(--text-3); background: rgba(var(--th-voile),.04); border: 1px solid var(--border); transition: var(--transi-vif); }
.pg-reset-btn:hover { color: var(--text); border-color: var(--border-strong); }
.pg-send-btn { display: inline-flex; align-items: center; gap: var(--e-8); padding: 0 var(--e-16); height: 34px; border-radius: var(--r-md);
  cursor: pointer; font-size: var(--t-base); font-weight: var(--fw-fort); color: #062b30; background: var(--cyan); border: none; transition: var(--transi-vif); font-family: inherit; }
.pg-send-btn:hover { background: var(--cyan-soft); }

/* Pastille « en formation » sur les vendeuses du sélecteur (génération).
   Amadou (2026-07-30) : on peut les choisir pour préparer, mais avec un rappel
   visible que la chauffe n'est pas finie. */
.lib-picker-card--formation { position: relative; }
.lib-picker-pastille {
  position: absolute; top: 6px; left: 6px; z-index: 2;
  background: rgba(230,162,60,.92); color: #2a1c05;
  font-size: var(--t-micro); font-weight: var(--fw-fort); padding: var(--e-2) var(--e-8); border-radius: var(--r-pilule);
  pointer-events: none; letter-spacing: .2px;
}
.lib-picker-card--formation { box-shadow: inset 0 0 0 1px rgba(230,162,60,.45); }

/* ══════════════════════════════════════════════════════════════════════════════
   LES BOUTONS DE NAVIGATION — UN SEUL LANGAGE POUR TOUT LE SITE
   ══════════════════════════════════════════════════════════════════════════════
   Amadou, 2026-07-30 : « les boutons dans Messages ne sont pas les mêmes que dans
   Annonces, qui ne sont pas les mêmes que dans Vendeuses. Ça fait vraiment brouillon. »

   Il avait raison, et c'était pire que ça : 26 barres de boutons, avec des rayons de
   bordure de 0, 6, 7, 8, 9, 10, 11, 20, 50 et 999 px, et QUATRE façons différentes de
   montrer l'onglet actif (un soulignement, une teinte, un fond plein, une gouttière).

   Ce bloc est posé À LA FIN du fichier exprès : à spécificité égale, c'est la dernière
   règle qui gagne. On ne touche donc à aucun JavaScript — chaque barre garde son
   attribut data-* et sa classe active (« on » chez les uns, « active » chez les autres).

   TROIS familles, et pas une de plus. Tout rendre identique aurait été aussi mauvais :
   un sous-onglet et un filtre ne font pas le même travail, et l'œil doit le sentir.
     1 · SOUS-ONGLET — passer d'une partie de l'écran à une autre. Le plus visible.
     2 · FILTRE      — restreindre une liste. Discret : il ne doit pas voler la vedette.
     3 · SEGMENT     — un choix exclusif, dans une gouttière (marche/veille, Jour/Mois).
   ────────────────────────────────────────────────────────────────────────────── */

/* ── 1 · SOUS-ONGLET ────────────────────────────────────────────────────────── */
.an-so,
.cokmsg-tab,
.msg-tab,
.ctrl-esc-subtab,
.gen-tab,
.gen-subtab,
.src-stab,
.cok-cmd-stab,
.drafts-tab,
.pa-tab,
.model-tab,
.cok-wtab,
.lib-vend-onglet,
.dress-coloris-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--e-8);
  flex: 0 0 auto;
  height: 34px;
  padding: 0 var(--e-16);
  border: 1px solid var(--border);
  border-bottom: 1px solid var(--border);   /* écrase les anciens soulignements */
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.04);
  color: var(--text-2);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  line-height: var(--lh-un);
  letter-spacing: var(--ls-zero);
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose);
}
.an-so:not(.on):hover,
.cokmsg-tab:not(.on):hover,
.msg-tab:not(.active):hover,
.ctrl-esc-subtab:not(.active):hover,
.gen-tab:not(.active):hover,
.gen-subtab:not(.active):hover,
.src-stab:not(.on):hover,
.cok-cmd-stab:not(.on):hover,
.drafts-tab:not(.active):hover,
.pa-tab:not(.active):hover,
.model-tab:not(.on):hover,
.cok-wtab:not(.on):hover,
.lib-vend-onglet:not(.on):hover,
.dress-coloris-tab:not(.active):hover {
  background: var(--survol-fond);
  border-color: var(--survol-bord);
  color: var(--text);
}
.an-so:focus-visible,
.cokmsg-tab:focus-visible,
.msg-tab:focus-visible,
.ctrl-esc-subtab:focus-visible,
.gen-tab:focus-visible,
.gen-subtab:focus-visible,
.src-stab:focus-visible,
.cok-cmd-stab:focus-visible,
.drafts-tab:focus-visible,
.pa-tab:focus-visible,
.model-tab:focus-visible,
.cok-wtab:focus-visible,
.lib-vend-onglet:focus-visible,
.dress-coloris-tab:focus-visible {
  outline: 2px solid var(--violet-soft);
  outline-offset: 2px;
}
/* Actif : le seul bouton plein de la barre. On le voit du premier coup d'œil. */
.an-so.on,
.an-so.active,
.cokmsg-tab.on,
.cokmsg-tab.active,
.msg-tab.on,
.msg-tab.active,
.ctrl-esc-subtab.on,
.ctrl-esc-subtab.active,
.gen-tab.on,
.gen-tab.active,
.gen-subtab.on,
.gen-subtab.active,
.src-stab.on,
.src-stab.active,
.cok-cmd-stab.on,
.cok-cmd-stab.active,
.drafts-tab.on,
.drafts-tab.active,
.pa-tab.on,
.pa-tab.active,
.model-tab.on,
.model-tab.active,
.cok-wtab.on,
.cok-wtab.active,
.lib-vend-onglet.on,
.lib-vend-onglet.active,
.dress-coloris-tab.on,
.dress-coloris-tab.active {
  background: linear-gradient(135deg, var(--violet-soft), var(--cyan));
  border-color: transparent;
  color: var(--sur-plein);
  font-weight: var(--fw-fort);
  box-shadow: 0 4px 16px rgba(var(--th-accent-rgb),0.28);
}
/* Le petit compteur porté par certains onglets suit son bouton. */
.an-so-n { background: var(--violet-tint); color: var(--violet-light); border-radius: var(--r-pilule);
           min-width: 19px; height: 19px; line-height: 19px; padding: 0 var(--e-6);
           font-size: var(--t-mini); font-weight: var(--fw-fort); text-align: center; font-variant-numeric: tabular-nums; }
.an-so.on .an-so-n { background: rgba(var(--th-ombre),0.20); color: inherit; }

/* La gouttière qui porte une barre de sous-onglets : même respiration partout. */
.an-souso,
.cokmsg-tabs,
.msg-tabs,
.ctrl-esc-subtabs,
.gen-tabs,
.gen-subtabs,
.src-subtabs,
.cok-cmd-subtabs,
.drafts-tabs,
.pa-tabs {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  flex-wrap: wrap;
  border-bottom: 0;
}

/* ── 2 · FILTRE ─────────────────────────────────────────────────────────────── */
/* Il restreint une liste : ronde, plus petite, et JAMAIS pleine — sinon on ne
   distingue plus « je change d'écran » de « je réduis ce que je regarde ». */
.cok-chip,
.lib-tier-tab,
.ctrl-esc-cat-chip,
.lib-fchip,
.ds-pill,
.dem-pill,
.src-gab,
.msg-vue,
.lib-marque-chip,
.prod-view-chip,
.cok-prof-f,
.lib-picker-style-chip,
.atelier-preset-chip,
.mod-motif-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  flex: 0 0 auto;
  height: 30px;
  padding: 0 var(--e-14);
  border: 1px solid var(--border);
  border-radius: var(--r-pilule);
  background: var(--surface);
  color: var(--text-2);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  line-height: var(--lh-un);
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose);
}
.cok-chip:not(.on):hover,
.lib-tier-tab:not(.active):hover,
.ctrl-esc-cat-chip:not(.active):hover,
.lib-fchip:not(.active):hover,
.ds-pill:not(.active):hover,
.dem-pill:not(.active):hover,
.src-gab:not(.on):hover,
.msg-vue:not(.on):hover,
.lib-marque-chip:not(.active):hover,
.prod-view-chip:not(.active):hover,
.cok-prof-f:not(.on):hover,
.lib-picker-style-chip:not(.active):hover,
.atelier-preset-chip:not(.active):hover,
.mod-motif-btn:not(.active):hover {
  background: var(--survol-fond);
  border-color: var(--survol-bord);
  color: var(--text);
}
.cok-chip.on,
.cok-chip.active,
.lib-tier-tab.on,
.lib-tier-tab.active,
.ctrl-esc-cat-chip.on,
.ctrl-esc-cat-chip.active,
.lib-fchip.on,
.lib-fchip.active,
.ds-pill.on,
.ds-pill.active,
.dem-pill.on,
.dem-pill.active,
.src-gab.on,
.src-gab.active,
.msg-vue.on,
.msg-vue.active,
.lib-marque-chip.on,
.lib-marque-chip.active,
.prod-view-chip.on,
.prod-view-chip.active,
.cok-prof-f.on,
.cok-prof-f.active,
.lib-picker-style-chip.on,
.lib-picker-style-chip.active,
.atelier-preset-chip.on,
.atelier-preset-chip.active,
.mod-motif-btn.on,
.mod-motif-btn.active {
  background: var(--violet-tint-strong);
  border-color: var(--violet-soft);
  color: var(--violet-light);
  font-weight: var(--fw-fort);
}

/* ── 3 · SEGMENT ────────────────────────────────────────────────────────────── */
/* Un choix exclusif, posé dans une gouttière : les crans se touchent, et c'est la
   gouttière qui dit « ces options vont ensemble ». */
.cok-master,
.pg-seg,
.cok-cmd-groups,
.lib-filters {
  display: inline-flex;
  align-items: center;
  gap: var(--e-4);
  padding: var(--e-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
}
.cok-master span,
.pg-seg-b,
.cok-cmd-grp,
.lib-filter,
.batch-mode-btn,
.fin-period-btn,
.lib-picker-tier-tab,
.atelier-param-btn,
.cok-vend-onglet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0 var(--e-14);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-2);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  line-height: var(--lh-un);
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.cok-master span:not(.on):hover,
.pg-seg-b:not(.active):hover,
.cok-cmd-grp:hover,
.lib-filter:not(.active):hover,
.batch-mode-btn:not(.active):hover,
.fin-period-btn:not(.active):hover,
.lib-picker-tier-tab:not(.active):hover,
.atelier-param-btn:not(.active):hover,
.cok-vend-onglet:not(.on):hover { background: var(--survol-fond); color: var(--text); }
/* ══ LE BOUTON LITIGES — il s'éteignait quand on le survolait ════════════════
   Amadou (15/08) : « quand je survole litige... il y a vraiment un bug ». Mesuré, le
   bouton étant SÉLECTIONNÉ :
       au repos  → linear-gradient(120deg, rgb(240,120,122), …)   le rouge est là
       survolé   → none                                            il n'y a plus rien
   ⚠️⚠️ CAUSE : `.cok-cmd-grp:hover` (juste en dessous) pose `background: var(--survol-fond)`
   — et `background` est un RACCOURCI, donc il remet `background-image` à `none` et efface
   le dégradé. Cette règle de survol n'a aucune garde `:not()`, elle frappe donc aussi
   l'onglet choisi. Les trois autres filières y échappent par accident : une règle
   POSTÉRIEURE (`.on-vinted, .on-shein, .on-wh`) leur redonne un fond après le survol.
   `.on-lit` n'a jamais été ajouté à cette liste — d'où le seul bouton qui s'éteint.
   ⚠️ Un aplat, pas un dégradé : mesuré, `--red` et `--th-danger` sont EXACTEMENT la même
   couleur (écart 1,00 dans les seize thèmes), et `--amber` aussi (1,01). Aucun second
   rouge n'existe dans la palette — un dégradé aurait été une bande unie déguisée.
   ⚠️ `--sur-plein` par-dessus : 6,17 au pire sur les seize, c'est ce qu'emploient déjà
   les trois autres filières. Le `#2A0F12` d'avant était une valeur brute, et le texte
   calculé sortait quand même en blanc — donc écrit pour rien.
   ⚠️ AUCUNE graisse ici : les quatre boutons sont à --fw-moyen une fois choisis, et en
   forcer une autre décalerait la rangée au clic (le défaut de style.css ~23090). */
.cok-cmd-grp.on-lit,
.cok-cmd-grp.on-lit:hover { background: var(--red); color: var(--sur-plein); }

.cok-master span.on,
.pg-seg-b.on,
.pg-seg-b.active,
.lib-filter.active,
.cok-cmd-grp.on-vinted,
.cok-cmd-grp.on-shein,
.cok-cmd-grp.on-wh,
.batch-mode-btn.on,
.fin-period-btn.active,
.lib-picker-tier-tab.active,
.atelier-param-btn.on,
.cok-vend-onglet.on {
  background: linear-gradient(135deg, var(--violet-soft), var(--cyan));
  color: var(--sur-plein);
  font-weight: var(--fw-fort);
  box-shadow: 0 3px 12px var(--violet-tint-strong);
}
/* Sur la barre du haut, « En marche » doit rester lisible comme un ÉTAT, pas comme
   un onglet : quand le pilote tourne, c'est vert ; en veille, c'est neutre. */
.cok-master span.on { background: linear-gradient(135deg, var(--violet-soft), var(--cyan)); }

@media (prefers-reduced-motion: reduce) {
  .an-so, .cokmsg-tab, .msg-tab, .cok-cmd-stab, .gen-tab, .src-stab,
  .cok-chip, .pg-seg-b, .cok-cmd-grp { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   UNE SEULE CROIX POUR TOUT LE SITE
   ══════════════════════════════════════════════════════════════════════════════
   Amadou, 2026-07-30 : « le modèle de croix, il va devoir être uniformisé dans le site ».
   Il y en avait 22, sous 22 noms de classe différents — et surtout dessinées de deux
   façons : certaines en icône, d'autres avec le CARACTÈRE « ✕ », qui ne rend pas pareil
   d'une police à l'autre (c'est la règle « pas de glyphe dans l'interface »).

   Toutes les croix-caractères sont devenues <i class=velbo-x></i> — un élément sans le
   moindre guillemet, donc insensible au type de chaîne JavaScript qui l'entoure. Le
   dessin, lui, vit ICI, en un seul endroit. Changer la croix du site = changer ce trait.
   ────────────────────────────────────────────────────────────────────────────── */

/* Le trait lui-même. `currentColor` : la croix prend la couleur de son bouton, donc
   elle rougit toute seule quand le bouton passe au rouge. */
.velbo-x {
  display: block;
  width: 14px; height: 14px;
  flex: 0 0 auto;
  background: currentColor;
  -webkit-mask: var(--x-trace) center / 14px 14px no-repeat;
          mask: var(--x-trace) center / 14px 14px no-repeat;
}
:root {
  --x-trace: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E");
}

/* ── Le bouton qui la porte : deux tailles, une seule forme ──────────────────
   PETITE (26 px) — écarter une ligne, vider une recherche, retirer une puce.
   GRANDE (32 px) — fermer une fenêtre. */
.remove-btn, .toast-close, .chip-remove, .velbo-modal-close,
.slot-remove-btn, .dress-import-modal-close,
.cok-x, .lib-search-clear, .lib-rating-clear, .pg-card-x, .mand-regle-x,
.dom-x, .cok-cons-x, .an-sv-x, .an-sp-x, .td-del, .srcg-del,
.msg-conv-del, .ctrl-lesson-del, .msg-delmsg,
.modal-close, .zoom-close, .regen-close, .compare-close-btn,
.batch-picker-close, .avatar-modal-close, .msg-details-close,
.de-color-close, .batch-preview-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 26px; height: 26px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-3);
  font-size: 0;                      /* neutralise un éventuel reste de texte */
  line-height: 0;
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose), transform var(--t-bref) var(--c-pose);
}
.modal-close, .zoom-close, .regen-close, .compare-close-btn,
.batch-picker-close, .avatar-modal-close, .msg-details-close,
.de-color-close, .batch-preview-close {
  width: 32px; height: 32px;
  border-radius: var(--r-md);
}
/* Les boutons qui portaient déjà une vraie icône : on la remet à la bonne taille. */
.cok-x > svg, .lib-search-clear > svg, .pg-card-x > svg, .msg-conv-del > svg,
.modal-close > svg, .zoom-close > svg, .regen-close > svg, .compare-close-btn > svg,
.avatar-modal-close > svg { width: 14px; height: 14px; }
.modal-close > svg, .zoom-close > svg, .regen-close > svg,
.compare-close-btn > svg, .avatar-modal-close > svg { width: 15px; height: 15px; }

/* Fermer, c'est retirer : le survol est rouge partout, sans exception. */
.remove-btn:hover, .toast-close:hover, .chip-remove:hover,
.velbo-modal-close:hover, .slot-remove-btn:hover,
.dress-import-modal-close:hover,
.cok-x:hover, .lib-search-clear:hover, .lib-rating-clear:hover, .pg-card-x:hover,
.mand-regle-x:hover, .dom-x:hover, .cok-cons-x:hover, .an-sv-x:hover, .an-sp-x:hover,
.td-del:hover, .srcg-del:hover, .msg-conv-del:hover, .ctrl-lesson-del:hover,
.msg-delmsg:hover, .modal-close:hover, .zoom-close:hover, .regen-close:hover,
.compare-close-btn:hover, .batch-picker-close:hover, .avatar-modal-close:hover,
.msg-details-close:hover, .de-color-close:hover, .batch-preview-close:hover {
  background: var(--red-bg, var(--cok-red-bg));
  color: var(--red, var(--red));
}
.cok-x:active, .lib-search-clear:active, .pg-card-x:active, .mand-regle-x:active,
.dom-x:active, .cok-cons-x:active, .an-sv-x:active, .an-sp-x:active, .td-del:active,
.srcg-del:active, .msg-conv-del:active, .ctrl-lesson-del:active, .msg-delmsg:active,
.modal-close:active, .zoom-close:active, .regen-close:active, .compare-close-btn:active,
.batch-picker-close:active, .avatar-modal-close:active, .msg-details-close:active,
.de-color-close:active, .batch-preview-close:active { transform: scale(.9); }

.cok-x:focus-visible, .lib-search-clear:focus-visible, .pg-card-x:focus-visible,
.mand-regle-x:focus-visible, .dom-x:focus-visible, .cok-cons-x:focus-visible,
.an-sv-x:focus-visible, .an-sp-x:focus-visible, .td-del:focus-visible,
.srcg-del:focus-visible, .msg-conv-del:focus-visible, .ctrl-lesson-del:focus-visible,
.msg-delmsg:focus-visible, .modal-close:focus-visible, .zoom-close:focus-visible,
.regen-close:focus-visible, .compare-close-btn:focus-visible,
.batch-picker-close:focus-visible, .avatar-modal-close:focus-visible,
.msg-details-close:focus-visible, .de-color-close:focus-visible,
.batch-preview-close:focus-visible { outline: 2px solid var(--violet-soft); outline-offset: 1px; }

/* ══════════════════════════════════════════════════════════════════════════════
   LE MOUVEMENT — juste ce qu'il faut
   ══════════════════════════════════════════════════════════════════════════════
   Amadou, 2026-07-30 : « dès que j'appuie sur un onglet, ça doit faire une petite
   animation… mais quand il y en a trop, c'est même moche. Trouve le juste milieu.
   C'est un site sur lequel on va être souvent, il faut qu'il soit agréable. »

   D'où TROIS mouvements, et pas un de plus :
     · l'écran qui arrive — il monte de 6 px en fondu, 0,22 s ;
     · le bouton qu'on presse — il s'enfonce d'un pixel, 0,1 s ;
     · les lignes d'une liste — elles se posent l'une après l'autre.
   Tout se tait si la machine demande moins d'animations.
   ────────────────────────────────────────────────────────────────────────────── */

/* La courbe qui rend un mouvement DOUX : elle démarre franchement puis se pose
   longuement, au lieu de s'arrêter net. C'est la différence entre « ça apparaît »
   et « ça se pose ». (Amadou : « c'est trop brusque ».) */
:root { --pose: var(--c-pose); }

/* ⚠️⚠️ UNE SEULE CHOSE BOUGE, ET C'ÉTAIT TOUT LE PROBLÈME. Avant : le titre montait de
   3 px sur 110 ms pendant que le contenu montait de 9 sur 340, et qu'un troisième
   glissait de 30 px sur le côté. Trois gestes désaccordés à dix pixels d'écart — l'œil
   ne lit pas ça comme une transition, il le lit comme un raté (Amadou : « il y a un
   petit rollback, c'est malaisant »).
   Le titre se fond désormais sans bouger, le bandeau reste planté, et seul le CONTENU
   se pose — de 4 px, pas 9. Un mouvement discret qui est le seul de l'écran se lit ;
   trois mouvements francs qui se contredisent, non. */
/* ── L'AGRANDISSEMENT ARRIVE, il ne surgit pas ───────────────────────────────
   Amadou (13/08) : « mets-la là pour tous les agrandissements ». Le mouvement
   n'existait que dans la navigation entre deux images ; les onze ouvreurs de la
   visionneuse posaient l'image d'un coup. Une seule porte les sert désormais
   (`_zoomPoser`), donc une seule animation — et elle se règle ICI.
   ⚠️ Pas de `fill-mode` : l'animation garderait sinon la main sur `transform`, qui
   appartient ensuite au glissement horizontal des flèches. */
/* ⚠️⚠️ PREMIÈRE VERSION INVISIBLE, ET AMADOU A CRU QU'ELLE N'ÉTAIT PAS DÉPLOYÉE.
   `scale(.965)` sur 220 ms, c'est 3,5 % d'écart : mathématiquement une animation,
   optiquement rien. Une animation qu'on ne voit pas ne vaut pas mieux que pas
   d'animation — elle coûte le même code et ne rend aucun service.
   Elle a maintenant de l'amplitude (6 %) ET une montée, sur une durée qu'on a le
   temps de lire. Le mouvement dit ce qui se passe : l'image ARRIVE et se pose. */
/* ⚠️⚠️ PLUS DE FONDU DEPUIS ZÉRO, ET C'EST LA CAUSE DU « FLASH » (Amadou, 13/08 :
   « enlève le flash de l'anim slide, il fait mal aux yeux »).
   L'image passait par `opacity: 0` au-dessus de DEUX voiles qui portent un
   `saturate()` — `.modal-overlay` (blur 14 px, saturate 1.25) et `.zoom-backdrop`
   (blur 22 px, saturate 1.1). Pendant que l'image est transparente, il n'y a plus
   rien pour masquer ces voiles : la page du dessous remonte à travers eux,
   sursaturée, puis disparaît quand l'image arrive. Un éclair clair sur un fond
   presque noir — exactement ce qui pique.
   ⭐ Un AGRANDISSEMENT n'a d'ailleurs pas besoin de fondu : il grandit, il
   n'apparaît pas. On garde le mouvement, on retire le trou. */
/* ⚠️⚠️ L'ÉCHELLE, C'ÉTAIT LA CAUSE DU MANQUE DE FLUIDITÉ (Amadou, 13/08 : « un slide
   fluide, c'est tout, mais ça doit être fluide »).
   Animer `scale()` sur une PHOTO PLEIN ÉCRAN oblige le navigateur à ré-échantillonner
   une grande image à chaque trame — c'est le calcul le plus cher qu'on puisse lui
   demander, et ça saccade sur une photo de robe en pleine résolution. Un déplacement,
   lui, ne coûte rien : la carte graphique bouge un calque déjà dessiné.
   ⭐ Et `translate3d` plutôt que `translateX` : les trois axes font passer l'image sur
   sa propre couche GPU. Même mouvement à l'œil, mais composé au lieu d'être redessiné.
   ⚠️ `will-change` est posé PAR LA CLASSE, qui est retirée à la fin : le garder en
   permanence maintiendrait une couche vivante pour rien.
   La direction et la courbe sont celles des flèches — le site n'a qu'une façon de
   faire glisser une image, et l'ouverture ne va pas en inventer une deuxième. */
.zoom-entree {
  animation: velbo-zoom-entree var(--t-long) var(--c-pose);
  will-change: transform;
}
@keyframes velbo-zoom-entree {
  from { transform: translate3d(26px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@media (prefers-reduced-motion: reduce) { .zoom-entree { animation: none; } }

@keyframes velbo-entree {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
/* ⚠️⚠️ LE GLISSEMENT DES ÉCRANS — DEPUIS LE HAUT, et c'est ce qui change tout.
   Amadou veut un glissement à l'ouverture, et il a raison : un fondu seul ne se lit pas
   comme une arrivée. Mais la version d'origine partait de translateY(+9px) — la toile
   commençait PLUS BAS que sa place, un vide de 9 px s'ouvrait sous le bandeau et
   laissait voir le fond de page. C'est la « couture » du 30/07, et c'est elle qui avait
   fait supprimer le mouvement au lieu de le déplacer.
   En partant de translateY(-6px), la toile commence PLUS HAUT : elle passe SOUS le
   bandeau, qui est collant, opaque et au-dessus d'elle. Le mouvement existe, la couture
   devient impossible.
   ⚠️ Et une SEULE surface glisse : la toile. Ses enfants ne s'animent pas — quatre blocs
   qui arrivent séparément, c'était le « pas fluide » —, le bandeau ne bouge pas, le
   titre se fond sans se déplacer. */
@keyframes velbo-pose {
  from { opacity: 0; transform: translateY(-14px); }
  to   { opacity: 1; transform: none; }
}
/* ⚠️ 14 px, pas 6. Par prudence après la couture, j'avais fait un mouvement que
   PERSONNE NE VOIT — Amadou : « je ne vois aucune différence, tu as fait quoi ? ». Un
   geste trop discret n'est pas un geste sobre, c'est un geste raté : il coûte le même
   temps d'affichage et ne dit rien. En dessous de 12 px sur 280 ms, l'œil ne lit pas un
   mouvement, il lit un scintillement. */
/* Le fondu pur reste pour ce qui ne peut vraiment pas bouger. */
/* ⚠️ L'animation porte sur le CONTENU, pas sur l'écran entier.
   Amadou (2026-07-30) : « quand je change de sous-onglet, toute la sous-partie bouge…
   sur les autres c'est juste le haut qui change, et ce n'est pas beau. »
   En animant la section entière, le titre et le bandeau de sous-onglets partaient avec
   le contenu — alors qu'ils ne changent pas. Désormais l'en-tête et le bandeau restent
   plantés, et seul ce qui est réellement remplacé se pose. Même geste partout : d'un
   sous-onglet à l'autre comme d'un écran à l'autre.
   (Le passage de display:none à visible relance l'animation tout seul ; pour un
   changement de sous-onglet, c'est _contenuNeuf() qui la rejoue.) */
/* ⚠️ `:not(.section-offscreen)` : #section-generator n'est JAMAIS masqué — il est
   DÉPLACÉ hors écran pour que la génération continue de tourner. Sans cette exclusion
   il satisfait la règle EN PERMANENCE : son animation se jouait une seule fois, au
   chargement de la page, alors qu'il était hors champ — et plus jamais à l'ouverture.
   Exclu tant qu'il est hors champ, il repart tout seul au RETOUR, et seulement là.
   Bénéfice second : il ne s'anime plus EN MÊME TEMPS que la Vue d'ensemble pendant le
   démarrage — deux écrans entiers animés en parallèle, c'était une part de la saccade. */
/* ⚠️ RÈGLE RETIRÉE : elle déclarait `velbo-entree` sur la toile alors qu'une autre,
   1 500 lignes plus bas, y déclare `velbo-pose`. La dernière gagnait, donc rien ne
   cassait — mais deux animations annoncées pour la même surface, c'est la prochaine
   personne qui corrige la mauvaise. La déclaration vit désormais à un seul endroit. */
/* Rejouée à la main quand le contenu change sans que l'écran change. */
/* ⚠️⚠️ 0,22 s ÉTAIT TROP COURT POUR UN BANDEAU DE CETTE TAILLE. Amadou (23/08) : « son
   animation d'apparition est trop brusque, adoucis-la ».
   La COURBE n'était pas en cause : `--c-pose` est déjà la plus douce du projet, la même
   qui pose les écrans. C'est la durée — `--t-moyen`, faite pour un bouton ou une pastille
   — appliquée à un bloc qui occupe le quart de l'écran. Plus l'objet est grand, plus il
   lui faut de temps pour arriver sans surprendre.
   `--t-long` (0,34 s) et 8 px de course au lieu de 4 : le mouvement devient perceptible
   AU LIEU d'être un clignotement, et c'est ce qui le rend doux. Une course trop courte se
   lit comme un saut, pas comme une arrivée.
   ⚠️ Elle ne sert QU'À CE BANDEAU (un seul appelant dans app.js) : `velbo-entree`, elle,
   anime huit autres choses et n'est pas touchée. */
@keyframes velbo-neuf-doux {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.velbo-neuf { animation: velbo-neuf-doux var(--t-long) var(--pose) both !important; }
/* ⚠️ Et rien ne bouge pour qui a demandé moins de mouvement. Le reste du site respecte
   déjà ce réglage (voir `_contenuNeuf`) ; ce bandeau ne l'écoutait pas. */
@media (prefers-reduced-motion: reduce) {
  .velbo-neuf { animation: none !important; }
}

/* ⚠️ Les écrans qui tiennent EXACTEMENT dans la hauteur (Studio, Messages) sont en
   `overflow: hidden`, et leur contenu touche le bas au pixel près. Un glissement de
   9 px n'a donc nulle part où aller : le bas de la barre de saisie se faisait couper
   pendant le tiers de seconde de l'animation, puis remontait d'un coup. Ces écrans-là
   se posent en fondu seul — le mouvement reste, sans rien rogner. */
@keyframes velbo-entree-fondu {
  from { opacity: 0; }
  to   { opacity: 1; }
}
#section-studio > .section-canvas,
#section-messages > .section-canvas,
#section-cockpit-messages .section-canvas,
#section-studio .studio-section-canvas {
  animation-name: velbo-entree-fondu;
}

/* ⚠️ PAS d'animation ligne par ligne — c'est ce qui faisait « le parc n'apparaît
   nulle part » (Amadou, 2026-07-30). Une liste refaite pendant que sa cascade est
   en attente laisse ses lignes à l'état de DÉPART, c'est-à-dire invisibles, et plus
   rien ne les rallume. Et vingt lignes qui s'animent chacune de leur côté, chacune
   posée sur du verre flouté, c'est exactement ce qui fait saccader.
   L'écran arrive d'un seul tenant : c'est plus doux ET ça ne peut pas se coincer. */
.cok-list > .cok-li.part { animation: velbo-ecarte var(--t-moyen) var(--pose) forwards; }

/* Le bouton qu'on presse s'enfonce — c'est ce qui fait qu'un site « répond ». */
.an-so:active, .cokmsg-tab:active, .msg-tab:active, .ctrl-esc-subtab:active,
.gen-tab:active, .gen-subtab:active, .src-stab:active, .cok-cmd-stab:active,
.drafts-tab:active, .pa-tab:active, .model-tab:active, .cok-wtab:active,
.lib-vend-onglet:active, .dress-coloris-tab:active,
.cok-chip:active, .lib-tier-tab:active, .ctrl-esc-cat-chip:active, .lib-fchip:active,
.ds-pill:active, .dem-pill:active, .src-gab:active, .msg-vue:active,
.lib-marque-chip:active, .cok-prof-f:active, .mod-motif-btn:active,
.cok-master span:active, .pg-seg-b:active, .cok-cmd-grp:active, .lib-filter:active,
.batch-mode-btn:active, .fin-period-btn:active, .lib-picker-tier-tab:active,
.atelier-param-btn:active, .cok-vend-onglet:active,
.cok-btn:active, .nav-item:active { transform: translateY(1px); }
.cok-btn, .nav-item { transition: background var(--d-fast) var(--c-pose),
                        border-color var(--d-fast) var(--c-pose),
                                  color var(--d-fast) var(--c-pose),
                                  transform var(--t-bref) var(--c-pose); }

/* Le liseré de l'onglet actif GLISSE d'une entrée à l'autre au lieu de sauter. */
.nav-item.active::before { transition: background var(--t-moyen) var(--c-pose); }

/* ── Ce qui rend le mouvement FLUIDE, et pas seulement présent ────────────────
   Ce n'était pas qu'une question de durée : chaque carte porte un fond flouté
   (l'effet verre), et un fond flouté doit être recalculé À CHAQUE IMAGE tant que
   quelque chose bouge au-dessus. Vingt cartes qui s'animent = vingt flous
   recalculés soixante fois par seconde : c'est ça qui saccadait.
   On prévient donc le navigateur qu'il n'a qu'UNE surface à faire glisser
   (l'écran entier), et il la prépare une seule fois. */
/* ⚠️ Écrit avec `:not(.pose)` et SANS identifiant : une règle qui contient un id dans
   un `:not()` pèse plus lourd que n'importe quelle règle de classe, et aucune autre
   n'aurait pu la relâcher. Ici la règle cesse simplement de s'appliquer dès que JS
   pose la classe — pas de bras de fer, pas de « !important ». */
/* ⚠️ Même raison : cette préparation graphique cassait le positionnement des menus
   flottants, pour un gain théorique. Retirée. */
/* ⚠️⚠️ PAS de `will-change: transform` ICI. Il crée un bloc conteneur en PERMANENCE
   (l'animation finit, la propriété reste), et cette classe est écrite dans une chaîne
   HTML : elle ne part jamais. Tout `position: fixed` posé dans le contenu animé serait
   décalé — le dépôt s'y est brûlé deux fois. 4 px sur 220 ms n'en ont aucun besoin. */
.velbo-neuf { will-change: opacity, transform; }   /* la course est animée aussi */

/* Les listes qui se rafraîchissent toutes seules (le parc, les discussions, les
   annonces) : leur contenu change sous les yeux, alors il se fond au lieu de sauter. */
.cok-list, .cok-metrics, #vd-root, #cok-cp-content, #cok-rz-content {
  transition: opacity var(--t-moyen) var(--pose);
}

@media (prefers-reduced-motion: reduce) {
  .app-section:not(.hidden), .cok-att.part { animation: none !important; }
  .an-so:active, .cok-chip:active, .cok-btn:active, .nav-item:active { transform: none; }
  .cok-list, .cok-metrics, #vd-root, #cok-cp-content, #cok-rz-content { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   LES BANDEAUX DE SOUS-ONGLETS, PARTOUT PAREILS
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « ce que tu as fait pour Annonces, c'est parfait — fais la
   même chose pour Vendeuses, Résultats, Commandes et Génération. Avec aussi le titre
   qui change au-dessus. »
   Ces quatre barres vivaient AU MILIEU du contenu ; elles prolongent maintenant
   l'en-tête, comme celle d'Annonces. ────────────────────────────────────────── */

/* Une barre reposée en bandeau ne garde aucune de ses anciennes marges. */
.an-souso.cok-cmd-subtabs,
.an-souso.gen-tabs {
  margin: 0 !important;
  border-bottom: 1px solid var(--border);
}
/* La barre des Commandes se cache d'elle-même quand elle n'a qu'un seul onglet :
   son `display:none` posé en JS doit continuer de gagner. */
.an-souso.cok-cmd-subtabs[style*="display: none"] { display: none !important; }

/* Le titre qui change de mot : il se fond au lieu de sauter. */
.topbar-title { transition: opacity var(--t-bref) var(--pose), transform var(--t-bref) var(--pose); }
/* ⚠️ Le titre ne se DÉPLACE plus : il se fond. Son translateY(-3px) partait vers le
   haut pendant que le contenu montait — deux gestes contraires à dix pixels d'écart. */
.topbar-title.mue { opacity: 0; }
/* Le nom de l'écran reste lisible en petit au-dessus : on sait toujours où l'on est. */
.topbar-sur {
  display: block;
  font-size: var(--t-meta);
  font-weight: var(--fw-moyen);
  letter-spacing: var(--ls-leger);
  color: var(--text-3);
  margin-bottom: var(--e-4);
  line-height: var(--lh-un);
}
.topbar-sur[hidden] { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   LES POIGNÉES — choisir soi-même la largeur d'un panneau
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « on pourrait avoir la possibilité manuellement d'étirer la
   barre des messages, pareil pour la partie contexte à droite ».
   Le trait reste invisible au repos : c'est la zone de préhension qui est large
   (6 px), pas le trait. On ne voit apparaître le rail qu'en s'approchant. */
.cok-poignee {
  flex: 0 0 auto;
  width: 6px;
  align-self: stretch;
  cursor: col-resize;
  position: relative;
  background: transparent;
  border: 0;
  padding: 0;
  z-index: 3;
  touch-action: none;
}
.cok-poignee::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 2px;
  margin-left: calc(var(--e-1) * -1);
  border-radius: 2px;
  background: var(--violet-soft);
  opacity: 0;
  transition: opacity var(--t-bref) var(--c-pose);
}
.cok-poignee:hover::before,
.cok-poignee:focus-visible::before,
body.tire-en-cours .cok-poignee::before { opacity: .85; }
.cok-poignee:focus-visible { outline: none; }
/* Pendant qu'on tire : plus de curseur texte parasite, plus de sélection accidentelle. */
body.tire-en-cours { cursor: col-resize; -webkit-user-select: none; user-select: none; }
body.tire-en-cours * { pointer-events: none; }
body.tire-en-cours .cok-poignee { pointer-events: auto; }

/* Les deux panneaux deviennent redimensionnables : largeur imposée, jamais écrasée. */
.cok-msg-list, .cok-msg-ctx { flex: 0 0 auto; }

/* ⚠️ Le panneau de droite (l'annonce) et la liste de gauche ont une largeur FIXE,
   mais rien n'empêchait leur contenu de la forcer : un titre d'annonce un peu long,
   et le panneau s'élargissait en poussant tout le reste — « le chat se dégage un peu
   à droite quand je l'ouvre » (Amadou, 2026-07-30). En flexbox, une largeur ne tient
   que si on autorise l'élément à être plus étroit que son contenu. */
.cok-msg-list, .cok-msg-ctx { min-width: 0; overflow: hidden; }
.cok-msg-cbody, .cok-msg-alog, .cok-msg-convs { min-width: 0; overflow-wrap: anywhere; }

/* ══════════════════════════════════════════════════════════════════════════════
   FLUIDITÉ — que le navigateur travaille moins, sans rien perdre à l'écran
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « ce n'est vraiment pas fluide, j'aimerais du 60 fps minimum,
   voire 120 si possible ». Rien n'est retiré de l'apparence ici : on change seulement
   la FAÇON dont le navigateur dessine. ────────────────────────────────────────── */

/* 1 · LA BIBLIOTHÈQUE — ne pas dessiner ce qui n'est pas à l'écran.
   Avec une centaine de robes, le navigateur calculait et peignait TOUTES les cartes,
   y compris les quatre-vingts qui sont sous le pli. `content-visibility` lui permet
   de sauter celles-là ; `contain-intrinsic-size` lui dit quand même quelle place
   leur réserver, pour que la barre de défilement ne saute pas.
   La hauteur annoncée = vignette 3/4 (≈ 248 px sur 186 de large) + le pied de carte. */
.lib-card, .hist-card, .td-card, .src-card {
  content-visibility: auto;
  contain-intrinsic-size: auto 320px;
}

/* 2 · LES OMBRES AU SURVOL — les faire APPARAÎTRE au lieu de les redessiner.
   Une ombre qu'on anime oblige le navigateur à repeindre la carte et son pourtour à
   chaque image. Ici l'ombre existe déjà, en calque séparé : on ne fait varier que sa
   transparence, ce que la carte graphique sait faire sans rien repeindre. */
.lib-card { isolation: isolate; }
.lib-card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: 0 16px 34px -14px rgba(var(--th-accent-rgb),0.5);
  opacity: 0;
  transition: opacity var(--t-moyen) var(--c-pose);
}
.lib-card:hover::after { opacity: 1; }
.lib-card:hover {
  /* Le soulèvement reste (il est gratuit), l'ombre ne se recalcule plus. */
  box-shadow: 0 5px 18px -12px rgba(var(--th-ombre),0.55), inset 0 1px 0 var(--bg-sidebar);
  transition: border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}

/* 3 · LES GRANDES LISTES — borner ce que le navigateur doit reconsidérer quand une
   ligne change. Sans ça, modifier une ligne le fait recalculer la liste entière. */
.cok-list, .lib-grid, .hist-grid, .cok-msg-convs { contain: layout style; }

/* 4 · LE FOND — il ne bouge jamais, il n'a donc pas à être reconsidéré quand le
   contenu défile au-dessus. */

@media (prefers-reduced-motion: reduce) { .lib-card::after { transition: none; } }

/* ── COMMANDES — la filière et ses onglets, sur une seule ligne ───────────────
   Le chemin se lit de gauche à droite : la filière, une flèche, puis ses onglets.
   On voit toujours d'où l'on vient, et on peut toujours y revenir. */
.cok-cmd-bandeau {
  gap: var(--e-10);
  /* Le chemin ne doit JAMAIS quitter l'écran. Une fois descendu dans la liste des
     ventes, il ne restait que l'en-tête — et plus rien à cliquer pour ressortir de
     SHEIN (Amadou : « après on ne peut plus faire retour en arrière »).
     ⚠️ Aucun nombre en dur : --topbar-h est MESURÉE par _stickyOffsets(). */
  position: sticky;
  top: var(--topbar-h, 76px);
  z-index: 9;                       /* sous l'en-tête (10), au-dessus du contenu */
  background: rgba(var(--th-panneau-rgb),0.82);  /* sinon le tableau se lit au travers */
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  /* ⚠️ DEUX RANGÉES : la filière au-dessus, ses onglets en dessous. Sur une seule
     ligne, six onglets s'intercalaient entre Vinted et SHEIN — changer de filière
     devenait une traversée. Chaque rangée fait une chose. Les onglets défilent à
     l'horizontale s'ils débordent ; la filière, elle, ne bouge jamais. */
  flex-direction: column;
  align-items: stretch;
  gap: var(--e-8);
}
.cok-cmd-bandeau .cok-cmd-groups { flex: 0 0 auto; align-self: flex-start; margin-bottom: 0; }
/* ⚠️⚠️ `width:100%` EST LA SEULE CHOSE QUI TIENT LA BARRE DANS L'ÉCRAN. Ni `min-width:0`,
   ni `align-items:stretch` du bandeau, ni `flex-basis:100%` n'y suffisaient : la barre
   sortait à sa largeur de contenu (1236 px à neuf onglets) et débordait du bandeau. Les
   quatre variantes ont été mesurées dans le navigateur, c'est la seule qui la ramène à
   720 px.
   ⚠️ Et `flex-wrap: wrap` remplace `nowrap` : le défilement latéral marchait, mais avec
   `scrollbar-width:none` il cachait des onglets SANS RIEN MONTRER — à 1024 px, « Au point
   relais » et « Validée » étaient invisibles et rien ne disait qu'ils existaient. Une
   deuxième rangée est moins jolie qu'une seule, et infiniment moins traître. */
.cok-cmd-bandeau .cok-cmd-subtabs { flex-wrap: wrap; width: 100%; overflow-x: auto; min-width: 0;
  row-gap: var(--e-6); margin-bottom: 0; padding-bottom: 0; scrollbar-width: none; }
.cok-cmd-bandeau .cok-cmd-subtabs::-webkit-scrollbar { display: none; }
/* ⚠️ RESSERRÉ POUR LE NEUVIÈME ONGLET, ET SEULEMENT ICI. Neuf étapes ne tenaient plus sur
   une ligne : « Validée » se retrouvait seule sur une deuxième rangée, ce qui est pire que
   deux rangées équilibrées. Le resserrement est limité au bandeau des Commandes — les
   barres de Résultats et de Comptes gardent leur respiration, elles n'ont que trois
   onglets. */
.cok-cmd-bandeau .cok-cmd-stab { flex: 0 0 auto; padding: var(--e-8) var(--e-10); }
.cok-cmd-bandeau .cok-cmd-groups,
.cok-cmd-bandeau .cok-cmd-subtabs {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  margin: 0;
  border: 0;
  padding: 0;
  background: none;
}
/* ⚠️ CET ÉCART DOIT ÊTRE ÉCRIT APRÈS LE BLOC CI-DESSUS, PAS AVANT. Les deux sélecteurs ont
   la même force (deux classes) : c'est le DERNIER qui gagne. Placé plus haut, mon `gap: 5px`
   était repris à 7 px sans rien signaler, et les neuf onglets débordaient de 11 px — juste
   assez pour renvoyer « Validée » seule à la ligne. */
.cok-cmd-bandeau .cok-cmd-subtabs { column-gap: 5px; row-gap: var(--e-6); }

.cok-cmd-fleche { display: flex; align-items: center; color: var(--text-3); flex: 0 0 auto; }

/* ── SANTÉ DE LA MACHINE (Contrôle) — la liste des comptes ne fait plus
   quinze kilomètres de long : cinq lignes, puis elle défile. */
#cok-vds-comptes {
  max-height: 320px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
#cok-vds-comptes::-webkit-scrollbar { width: 6px; }
#cok-vds-comptes::-webkit-scrollbar-thumb { background: rgba(var(--th-voile),.10); border-radius: var(--r-sm); }

/* ── MESSAGES — quand on élargit la colonne de gauche, ses filtres suivent.
   Amadou : « quand on a agrandi la partie de gauche, ça doit aussi allonger les
   boutons, étant donné qu'il y a plus de place. » */
.cok-msg-lhead .cok-chips { display: flex; gap: var(--e-6); width: 100%; }
.cok-msg-lhead .cok-chip { flex: 1 1 0; min-width: 0; justify-content: center; padding: 0 var(--e-8); }

/* ══════════════════════════════════════════════════════════════════════════════
   LE STUDIO — les messages arrivent au lieu d'apparaître
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « dans le Studio il n'y a pas d'animations… ce que tu vois
   à l'intérieur doit avoir une animation. »
   Un message monte et se pose ; celui qu'on écrit vient de la droite, celui de Velbo
   vient de la gauche — chacun de SON côté de la conversation, comme il est aligné.
   Court (0,26 s) : c'est une discussion, pas un spectacle. */
@keyframes velbo-bulle-toi {
  from { opacity: 0; transform: translate3d(14px, 8px, 0) scale(.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes velbo-bulle-lui {
  from { opacity: 0; transform: translate3d(-14px, 8px, 0) scale(.97); }
  to   { opacity: 1; transform: none; }
}
.studio-msg-user  { animation: velbo-bulle-toi var(--t-moyen) var(--pose) both; }
.studio-msg-velbo { animation: velbo-bulle-lui var(--t-moyen) var(--pose) both; }

/* L'historique des discussions, à gauche : il se pose comme le reste du site. */
.studio-history-list > * { animation: velbo-entree var(--t-long) var(--pose) both; }

@media (prefers-reduced-motion: reduce) {
  .studio-msg-user, .studio-msg-velbo, .studio-history-list > * { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   L'ARRIVÉE DU STUDIO
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « un fondu noir à chaque fois que je l'ouvre — la première
   fois plus prononcé, les autres plus léger. Et une animation au niveau des lettres
   du texte. » ────────────────────────────────────────────────────────────────── */

/* Le rideau : il couvre l'écran, puis s'efface. Sa durée est décidée en JS, selon
   qu'on ouvre le Studio pour la première fois de la session ou non. */
.studio-rideau {
  position: absolute;
  inset: 0;
  z-index: 40;
  background: var(--bg);
  pointer-events: none;
}

/* Les lettres, l'une après l'autre. Chacune porte son propre retard, calculé au
   rendu — c'est ce qui fait courir la phrase de gauche à droite. */
.studio-chat-welcome-greeting { display: block; }
/* ⚠️ `inline-block` sur chaque lettre autorise le navigateur à couper la ligne entre
   deux lettres. Le mot, lui, est insécable : c'est lui qui rend les coupures
   normales. Sans cette classe, la phrase d'accueil se brisait n'importe où. */
.studio-mot { white-space: nowrap; }
.studio-lettre {
  display: inline-block;
  white-space: pre;
  animation: velbo-lettre var(--t-long) var(--pose) both;
}
@keyframes velbo-lettre {
  from { opacity: 0; transform: translate3d(0, 8px, 0); filter: blur(4px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* Le sous-titre arrive une fois la phrase écrite. */
.studio-welcome-hint { animation: velbo-entree var(--t-long) var(--pose) both; }

/* Les six cartes se posent l'une après l'autre, à partir de --depart. */
@keyframes velbo-carte {
  from { opacity: 0; transform: translate3d(0, 12px, 0) scale(.985); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .studio-lettre, .studio-welcome-hint { animation: none; }
  .studio-rideau { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   LE CHOIX D'IDENTITÉ — dans la DA du site
   ══════════════════════════════════════════════════════════════════════════════
   C'était un menu déroulant natif de macOS : la seule fenêtre du logiciel qui ne
   ressemblait pas au logiciel (Amadou, 2026-07-30). Le <select> est toujours là,
   caché — il reste la source de vérité ; ce bouton-ci ne fait que le refléter. */
.identite { position: relative; }
.identite-btn {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  width: 100%;
  height: 34px;
  padding: 0 var(--e-10);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile),0.04);
  color: var(--text-2);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.identite-btn:not(.on):hover { background: rgba(var(--th-voile),0.08); border-color: var(--border-mid); color: var(--text); }
.identite-btn.on { border-color: var(--violet-soft); color: var(--text); }
.identite-btn:focus-visible { outline: 2px solid var(--violet-soft); outline-offset: 2px; }
.identite-nom { flex: 1; min-width: 0; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.identite-fleche { flex: 0 0 auto; color: var(--text-3); transition: transform var(--t-moyen) var(--pose); }
.identite-btn.on .identite-fleche { transform: rotate(180deg); }
.sidebar.collapsed .identite-nom, .sidebar.collapsed .identite-fleche { display: none; }

/* Le menu s'ouvre VERS LE HAUT : le bouton est en bas de la barre latérale. */
.identite-menu {
  position: absolute;
  left: 0; right: 0;
  bottom: calc(100% + 6px);
  z-index: 60;
  padding: var(--e-6);
  border: 1px solid var(--border-mid);
  border-radius: var(--r-md);
  background: rgba(var(--th-panneau-rgb),0.92);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 18px 44px rgba(var(--th-ombre),.55);
  animation: velbo-menu var(--t-moyen) var(--pose) both;
}
@keyframes velbo-menu {
  from { opacity: 0; transform: translateY(6px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
.identite-opt {
  display: flex;
  align-items: center;
  gap: var(--e-10);
  width: 100%;
  padding: var(--e-8) var(--e-8);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-2);
  font-family: inherit;
  font-size: var(--t-base);
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.identite-opt:hover { background: rgba(var(--th-voile),0.07); color: var(--text); }
.identite-opt.on { color: var(--violet-light); }
.identite-lbl { flex: 1; min-width: 0; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.identite-coche { flex: 0 0 auto; color: var(--violet-soft); }
.identite-pion {
  flex: 0 0 auto;
  width: 21px; height: 21px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-sm);
  background: linear-gradient(135deg, var(--violet-soft), var(--cyan));
  color: var(--sur-plein);
  font-size: var(--t-micro); font-weight: var(--fw-gras);
}
.identite-pion--tous { background: rgba(var(--th-voile),.10); }
.identite-pion--tous::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--text-3); }

@media (prefers-reduced-motion: reduce) { .identite-menu { animation: none; } }

/* ══════════════════════════════════════════════════════════════════════════════
   LA BIBLIOTHÈQUE — sa rangée de boutons alignée sur celle du Sourcing
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « les sous-onglets doivent être à la même hauteur, il y a une
   étrange différence ». Mesuré : la rangée de la Bibliothèque commençait à 208 px et
   faisait 36 px de haut ; celle du Sourcing à 193 px pour 46 px.
   Les deux barres ont pourtant déjà la même anatomie (un filet dessous, une marge en
   dessous) — tout l'écart venait des 14 px de retrait en haut de la barre collante,
   et de deux pixels de gouttière en trop. */
.lib-sticky-bar {
  padding-top: 0;
  padding-bottom: var(--e-12);   /* comme .src-subtabs */
  margin-bottom: var(--e-18);    /* comme .src-subtabs */
}
/* 2 px de gouttière + 1 px de bordure de chaque côté + 28 px de bouton = 34,
   exactement la hauteur de .src-stab. C'est la bordure que j'avais oubliée. */
.lib-filters { padding: var(--e-2); }
.lib-filters-row { align-items: center; min-height: 34px; }
/* La rangée fait 38 px à cause des commandes de droite (recherche, tri). Le groupe de
   gauche s'accroche donc en HAUT au lieu d'être centré : ses boutons tombent alors
   exactement à la même hauteur que ceux du Sourcing. */
.lib-filters { align-self: flex-start; }

/* ══════════════════════════════════════════════════════════════════════════════
   L'ARRIVÉE D'UN ÉCRAN NE DÉCOLLE PLUS LE CONTENU DE SON BANDEAU
   ══════════════════════════════════════════════════════════════════════════════
   Amadou : « il y a un léger espace entre la partie du haut et la partie du milieu,
   ça fait un vilain effet. »
   Au repos il n'y avait AUCUN espace (mesuré : le bandeau finit à 165, le contenu
   commence à 165). Cet espace n'existait que PENDANT l'animation : la toile entière
   descendait de 9 px avant de se poser, et comme le bandeau a un fond plus sombre et
   un filet sous lui, on voyait une bande de fond de page apparaître puis se refermer.
   C'était donc mon animation qui fabriquait la couture.

   ⚠️⚠️ LA CORRECTION D ALORS A DÉPLACÉ L ANIMATION SUR LES ENFANTS — et c'est ce qui
   rendait le site saccadé. Sur la Bibliothèque il n'y a qu'un bloc sous la toile : une
   seule surface s'anime, c'est doux, et Amadou la cite en exemple. Sur Commandes il y en
   a quatre (compteurs, recherche, panier, liste), sur Vendeuses autant : quatre surfaces
   qui s'animent chacune, ça ne se lit plus comme UNE arrivée.
   ⚠️ Un commentaire du même fichier l'interdisait déjà — « PAS d'animation ligne par
   ligne, c'est ce qui faisait le parc n'apparaît pas d'un coup ». La correction de la
   couture a réintroduit exactement ce qu'une correction antérieure avait banni.

   LA TOILE REPREND SON ANIMATION, EN FONDU SEUL. La couture venait du MOUVEMENT (la
   toile descendait de 9 px et découvrait le fond sous le bandeau), pas de l'animation :
   sans déplacement, rien ne peut se décoller. Une seule surface, aucune couture, et le
   même geste partout — exactement la douceur de la Bibliothèque. */
.app-section:not(.hidden):not(.section-offscreen) > .section-canvas,
.app-section:not(.hidden):not(.section-offscreen) > .cok > .section-canvas {
  /* ⚠️⚠️ `backwards` ET SURTOUT PAS `both`. Avec `both`, le navigateur MAINTIENT la
     propriété animée après la fin : `transform` reste déclaré sur la toile, même à
     `none`, et un `transform` déclaré crée une NOUVELLE RÉFÉRENCE DE POSITIONNEMENT.
     Tout élément en `position: fixed` à l'intérieur — les menus, les popups, le menu des
     coloris — se plaçait alors par rapport à la toile et non à la fenêtre. Mesuré :
     126 px de décalage, en permanence. C'est ce qui cassait le bouton des coloris.
     ⚠️ `both` est conservé, et c'est un choix : il maintient l'état final, donc la toile
     reste visible même si le navigateur gèle l'animation (onglet en arrière-plan). Testé
     avec `none` : l'écran restait à opacité 0 dans un onglet non regardé — un écran vide
     est bien pire qu'un mouvement figé. */
  animation: velbo-pose var(--t-long) var(--c-pose) both;
}
/* ⚠️ Et les enfants ne s'animent PLUS : c'était la source du désaccord. */
.app-section:not(.hidden):not(.section-offscreen) > .section-canvas > *,
.app-section:not(.hidden):not(.section-offscreen) > .cok > .section-canvas > * {
  animation: none;
}
/* Les écrans pleine hauteur gardent leur fondu seul (leur contenu touche le bas
   au pixel près : un glissement s'y ferait rogner). */
/* Ces écrans avaient déjà le fondu seul : ils n'ont plus rien de particulier à dire,
   la règle générale fait la même chose. */
/* ⚠️⚠️ `will-change` ET `backface-visibility` RETIRÉS DE LA TOILE — ils CASSAIENT tous
   les menus flottants du site. Ces deux propriétés créent une nouvelle référence de
   positionnement : un élément en `position: fixed` à l'intérieur se place alors par
   rapport à la TOILE et non à la fenêtre. Le menu des coloris, calculé avec
   `getBoundingClientRect()` puis posé en `top/left`, atterrissait donc à côté — Amadou :
   « quand j'appuie sur un coloris ça ne marche pas ».
   ⚠️ Et le garde-fou prévu ne gardait rien : la classe `.pose` censée relâcher le
   `will-change` est RETIRÉE quelque part dans le code et n'est POSÉE nulle part. La
   préparation graphique restait donc en place à vie, pour une animation de 340 ms.
   Le gain était de toute façon théorique — une opacité et une translation sur une
   surface ne demandent aucune préparation à un navigateur d'aujourd'hui — alors que le
   coût, lui, était tous les menus du site. */
.app-section:not(.hidden):not(.section-offscreen) > .section-canvas,
.app-section:not(.hidden):not(.section-offscreen) > .section-canvas > * {
  will-change: auto;
}

/* ══════════════════════════════════════════════════════════════════════════════
   CE QUI ARRIVE APRÈS COUP — l'attente se voit, mais elle ne dérange pas
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-30) : « je comprends qu'il y ait du chargement, c'est normal. Mais
   comble ça par une animation qui prend plus de temps, qu'il y ait le temps de bien
   charger. Pas abusé non plus, mais pour que ça passe mieux. »

   Un bloc qui attend RESPIRE — un battement très lent, à peine perceptible. C'est ce
   qui fait la différence entre « ça charge » et « c'est cassé ». Puis la donnée se
   pose sur 520 ms au lieu de 340 : assez lent pour qu'on ne voie pas le remplacement,
   assez court pour ne pas se faire attendre. */
/* ⚠️ TROIS RÉGLAGES, ET LE PLUS IMPORTANT EST LE RETARD (Amadou, 2026-07-31 :
   « les parties qui nécessitent un chargement, que ça soit plus délicat et que ça
   passe mieux »).

   1) LE RETARD DE 320 ms. Le battement partait à l'instant même où l'attente
      commençait : une donnée qui arrivait en 150 ms produisait quand même un
      clignotement — on voyait le bloc se ternir pour rien. Avec ce retard, un
      chargement rapide ne bat PAS du tout ; seuls les vrais temps d'attente
      respirent. C'est ça, « ça passe mieux ».
   2) LE CYCLE PART DU HAUT (.9 → .58 → .9) au lieu du bas. Le bloc n'a donc pas de
      marche à descendre au démarrage : il glisse depuis son opacité normale.
   3) 2,6 s AU LIEU DE 1,6. Un battement lent se lit comme une respiration ; un
      battement rapide se lit comme un défaut. */
.velbo-attend { animation: velbo-respire 2.6s ease-in-out var(--t-long) infinite; }
@keyframes velbo-respire {
  0%, 100% { opacity: .9; }
  50%      { opacity: .58; }
}
/* Les valeurs encore inconnues (« — ») s'effacent un peu plus que le reste : l'œil
   comprend tout de suite que le chiffre n'est pas là, plutôt que de lire un tiret.
   Amenées en douceur, elles aussi : sans la transition, un chargement court faisait
   claquer les chiffres du gris au blanc. */
.velbo-attend .cok-bs-v, .velbo-attend .num { opacity: .7; }
.cok-bs-v, .num { transition: opacity var(--t-long) var(--pose); }

@media (prefers-reduced-motion: reduce) { .velbo-attend { animation: none; opacity: .7; } }

/* ══════════════════════════════════════════════════════════════════════════════
   FICHE ROBE — la colonne de droite en sous-onglets
   ══════════════════════════════════════════════════════════════════════════════
   Elle portait quinze blocs à la file, près de 1 700 px, dont 950 pour le seul
   tableau « Infos produit ». Quatre panneaux désormais. La barre reprend la pilule
   maison (.an-so dans .an-souso) : aucun style de pastille n'est réécrit ici, elle
   hérite du gabarit commun à tout le site. */
/* ⚠️ Plus de fond opaque : il dessinait une bande sombre sous les onglets
   (Amadou, 2026-07-31 : « c'est mal incrusté, il y a une partie noire »).
   Du verre, comme toutes les autres barres du site : le contenu passe dessous en se
   floutant, au lieu d'être caché par un aplat noir. */
.dress-rtabs {
  position: sticky;
  top: calc(var(--topbar-h, 76px) + 8px);
  z-index: 4;
  margin: 0 0 var(--e-4);
  padding: var(--e-8) var(--e-10);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  /* ⚠️⚠️ UNE BARRE COLLANTE DOIT ETRE OPAQUE. Amadou (01/09) : « les menus de droite
     empiètent sur leur contenu ». Ils n'empiétaient pas — la barre est `sticky`, donc le
     panneau défile DESSOUS, et son fond était un dégradé quasi transparent : le texte du
     dessous se lisait au travers. Le flou d'arrière-plan ne suffit pas, il adoucit sans
     masquer. On pose la couleur du panneau SOUS le dégradé : le dégradé garde son relief,
     et plus rien ne transparaît. */
  background: linear-gradient(180deg, var(--surface-2), rgba(var(--th-voile),0.025)),
              var(--th-panneau);
  backdrop-filter: blur(16px) saturate(1.25);
  -webkit-backdrop-filter: blur(16px) saturate(1.25);
}
.dress-rpanels { display: block; min-width: 0; }
.dress-rpanel { display: flex; flex-direction: column; gap: var(--e-22); }
/* En tête de panneau, le bloc Annonce n'a plus rien à séparer au-dessus de lui. */
.dress-rpanel > .dress-annonce-section { margin-top: 0; padding-top: 0; border-top: 0; }

/* Le point de rappel : « ça a bougé ici pendant que tu regardais ailleurs ».
   Choisir une taille dans Mesures réécrit la description, qui vit dans Annonce. */
.an-so--point { position: relative; }
.an-so--point::after {
  content: '';
  position: absolute;
  top: 6px; right: 7px;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--violet-soft);
  box-shadow: 0 0 7px var(--violet-glow);
}

/* ══════════════════════════════════════════════════════════════════════════════
   FICHE ROBE — le tiroir des photos générées, et la barre des coloris
   ══════════════════════════════════════════════════════════════════════════════
   Les photos mannequin et produit ne sont pas les photos DE LA ROBE : ce sont des
   rendus. Elles encombraient le flux des photos de référence et rendaient la colonne
   bien plus haute que l'écran — ce qui cassait le calage au défilement. Elles vivent
   maintenant dans un tiroir, ouvert par un bouton posé à côté d'« Utiliser cette robe ». */
/* Dans son onglet, le bloc n'a plus de filet à porter : il EST le contenu. */
.dress-generees { margin-top: 0; padding-top: 0; border-top: 0; }
.lib-detail-actions { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap; }

/* ── LES COLORIS — des bulles, et rien d'autre ────────────────────────────────
   Amadou, trois fois de suite sur ce point. Il avait raison à chaque fois : je n'avais
   fait que rétrécir, puis déplacer, ce qui restait un ruban chargé — un nom, une
   pastille de stock, trois petits points, pour chaque couleur.
   Sa formulation finale : « je veux vraiment que ce soit juste des bulles de couleur,
   et quand on passe dessus on voit les détails avec le nom ».
   Au repos : une bulle. C'est tout. Le nom, l'état du stock et les actions vivent dans
   une carte qui n'apparaît qu'au survol. ⚠️ Rien n'est perdu : le menu portait Renommer,
   Changer la couleur et Supprimer — il est déplacé, pas supprimé. */
.dress-colors-row { display: flex; align-items: center; gap: var(--e-8); margin: 0 0 var(--e-10); flex-wrap: wrap; }
.dress-colors-strip { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap; padding: 0; }

/* ⚠️ La couleur REMPLIT la bulle. Avant, un disque de 14 px flottait dans un cercle
   bordé de 22 : il ne tombait pas au centre et laissait un halo vide tout autour —
   « le cercle est mal fait, ça rentre mal dedans » (Amadou, 2026-07-31).
   La bulle n'a plus de bordure propre : c'est la couleur elle-même, cerclée d'un
   liseré intérieur pour qu'un coloris très sombre se détache quand même du fond. */
.dress-color-chip {
  position: relative;
  width: 22px; height: 22px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  overflow: visible;
  background: transparent;
  cursor: pointer;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--t-bref) var(--pose), box-shadow var(--t-bref) var(--c-pose);
}
.dress-color-chip .dress-color-chip-swatch-wrap { width: 100%; height: 100%; display: block; }
.dress-color-chip .dress-color-chip-swatch {
  width: 100%; height: 100%;
  box-shadow: 0 0 0 1px rgba(var(--th-voile),0.22) inset, 0 0 0 1px rgba(var(--th-ombre),0.35);
}
/* Le grossissement se fait sur la bulle entière, pas sur le disque à l'intérieur —
   sinon le disque débordait de son cercle au survol. */
.dress-color-chip:hover .dress-color-chip-swatch { transform: none; }
.dress-color-chip:hover { transform: scale(1.14); }
/* Le coloris actif porte un anneau : on le reconnaît sans avoir à lire. */
.dress-color-chip.active {
  box-shadow: 0 0 0 2px var(--bg-base), 0 0 0 4px var(--violet-soft);
}
/* Le nom disparaît de la bulle : il vit dans la carte. */
.dress-color-chip .dress-color-chip-name { display: none; }
.dress-color-stock-dot { display: none; }

.dress-color-chip--add {
  width: 22px; height: 22px;
  border-style: dashed;
  color: var(--text-3);
  display: flex; align-items: center; justify-content: center;
}
.dress-color-chip--add:hover { color: var(--violet-light); border-color: var(--violet-soft); }
.dress-color-chip--add svg { width: 11px; height: 11px; }

/* La ligne du nom redevient simple : le nom, puis les actions. */
.lib-detail-title-row { display: flex; align-items: center; gap: var(--e-12); flex-wrap: nowrap; }
.lib-detail-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-detail-actions { flex: 0 0 auto; flex-wrap: nowrap; }
.lib-detail-actions { margin-left: auto; }

/* ══════════════════════════════════════════════════════════════════════════════
   FICHE ROBE — T. Vendeuses et T. Produits, dans la colonne de droite
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️ La pleine largeur est retirée : la mise en page ne bouge plus d'un onglet à
   l'autre (Amadou, 2026-07-31 : « c'est vraiment dans la partie de droite »).
   C'est la galerie qui s'adapte à la colonne, pas la colonne qui s'efface pour elle. */

/* ── T. PRODUITS — le stock de vues supplémentaires ──────────────────────────
   « C'est là où on stocke les vues du produit en plus, au cas où on nous demande.
   La disposition est simple, juste des photos, mais il faut que ce soit beau. » */
.dress-gen-prod .dress-color-views-grid {
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--e-10);
}
.dress-gen-prod .dress-color-view-cell img {
  aspect-ratio: 3 / 4;
  object-fit: cover;
  width: 100%; height: auto;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  transition: border-color var(--t-bref) var(--c-pose), transform var(--t-bref) var(--pose);
}
.dress-gen-prod .dress-color-view-cell:hover img { border-color: var(--violet-soft); transform: translateY(-2px); }
.dress-gen-prod .model-add-tile { aspect-ratio: 3 / 4; height: auto; border-radius: var(--r-md); }

/* ── T. VENDEUSES — les vendeuses d'abord, leurs vues au clic ────────────────
   DEUX TEMPS (Amadou, 12/08) : « elle doit être en 2 étapes, quand j'appuie sur
   une vendeuse un espace doit s'ouvrir ». Le dépliement existait déjà — ce qui
   manquait, c'était la PREMIÈRE étape : une vraie liste.
   ⚠️ Les vendeuses étaient en grille de vignettes de 186 px. Une grille demande de
   BALAYER en deux dimensions ; or ici on cherche une vendeuse par son nom et on
   compare un compteur — deux lectures verticales. D'où des LIGNES pleine largeur :
   le nom a toute la place, et les « 2/3 » s'empilent dans une seule colonne, donc
   se comparent d'un coup d'œil au lieu de sauter d'une case à l'autre. */
.dress-gen-vend .dress-mvbm-cards {
  display: flex;
  flex-direction: column;
  gap: var(--e-6);
}
.dress-gen-vend .dress-mvbm-card {
  padding: var(--e-10) var(--e-12);
  cursor: pointer;
  transition: border-color var(--t-bref) var(--c-pose), background var(--t-bref) var(--c-pose);
}
/* ⚠️ Pas de translateY au survol : sur des lignes collées à 6 px, une ligne qui
   se soulève passe sous sa voisine. Le survol se dit par le filet et le fond. */
.dress-gen-vend .dress-mvbm-card:hover {
  border-color: var(--violet-soft);
  background: var(--surface);
}
/* Au repos : les vues sont rangées, et le retour n'a pas lieu d'être. */
.dress-gen-vend .dress-mvbm-card .dress-mvbm-grid,
.dress-gen-vend .dress-mvbm-retour { display: none; }

/* La ligne : nom élastique à gauche, repères groupés à droite. La taille porte
   déjà `margin-left:auto` — tout ce qui la suit (pastille, chevron) se range donc
   naturellement au bout de la ligne. */
.dress-gen-vend .dress-mvbm-card-head { margin-bottom: 0; }
.dress-gen-vend .dress-mvbm-card-meta { margin-top: var(--e-4); padding-left: 34px; }

/* Le chevron : il n'écoute rien, c'est la ligne entière qui s'ouvre. Il ANNONCE.
   Sans lui, une ligne cliquable ressemble à une ligne morte. */
.dress-mvbm-chev {
  flex-shrink: 0;
  display: inline-flex;
  color: var(--text-3);
  transition: transform var(--t-bref) var(--pose), color var(--t-bref) var(--c-pose);
}
.dress-gen-vend .dress-mvbm-card:hover .dress-mvbm-chev { color: var(--violet-light); }
.dress-gen-vend .dress-mvbm-card.ouverte .dress-mvbm-chev { transform: rotate(180deg); }

/* Espace ouvert : seule la vendeuse choisie reste. */
.dress-gen-vend .dress-mvbm-cards.espace > *:not(.ouverte) { display: none; }
.dress-gen-vend .dress-mvbm-card.ouverte {
  cursor: pointer;
  border-color: var(--violet-soft);
  background: var(--cok-bg-2);
  padding: var(--e-12) var(--e-14) var(--e-14);
}
.dress-gen-vend .dress-mvbm-card.ouverte .dress-mvbm-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--e-10);
  margin-top: var(--e-12);
}
.dress-gen-vend .dress-mvbm-card.ouverte .dress-mvbm-grid img,
.dress-gen-vend .dress-mvbm-card.ouverte .model-add-tile {
  aspect-ratio: 3 / 4;
  object-fit: cover;
  width: 100%; height: auto;
  border-radius: var(--r-md);
}
.dress-gen-vend .dress-mvbm-card.ouverte .dress-color-view-label { font-size: var(--t-meta); }
.dress-gen-vend .dress-mvbm-card.ouverte .dress-mvbm-retour {
  display: inline-flex;
  align-items: center;
  gap: var(--e-6);
  margin-top: var(--e-12);
  padding: 0 var(--e-10);
  height: 28px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: rgba(var(--th-voile),.04);
  color: var(--text-2);
  font-family: inherit; font-size: var(--t-meta);
  cursor: pointer;
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.dress-gen-vend .dress-mvbm-card.ouverte .dress-mvbm-retour:hover { background: rgba(var(--th-voile),.09); color: var(--text); }

/* Le bloc n'a plus de filet ni de marge : il EST le contenu de son onglet. */
.dress-generees { margin: 0; padding: 0; border: 0; }

/* ⚠️ Les six onglets de la fiche tiennent sur UNE ligne, toujours. Ils passaient à deux
   (barre de 93 px de haut) : 565 px de boutons + 35 de gouttières + 20 de retrait, pour
   604 px de colonne. Pilules resserrées, police à 12,5 px, et interdiction de revenir
   à la ligne — un onglet trop long se coupe plutôt que de casser la barre.
   (Amadou, 2026-07-31 : « tous les boutons doivent tenir en une ligne, même si tu dois
   réduire la taille des boutons et la police ».) */
/* Resserré une seconde fois : à 1280 px les six onglets réclamaient 521 px pour
   517 disponibles, et TOUS s'affichaient coupés (« Fic… », « T. Vendeu… »).
   Retrait à 7 px et gouttière à 4 px : 480 px demandés, 37 de marge. */
/* ⚠️⚠️⚠️ ON NE DEVINE PLUS UN SEUIL — ILS ONT TOUS ÉTÉ FAUX À TOUR DE RÔLE. Six onglets
   le 31/07, huit le 11/08, DIX aujourd'hui (Avis SHEIN, Questions reçues). À chaque
   ajout, le seuil de repli devenait trop bas et la barre repassait sur une seule ligne
   coupée. Amadou (27/08), capture à l'appui : « ce n'est pas bon » — dix onglets tous
   tronqués, « Fic… », « Mesu… », « Avis SH… », « Popula… », « Sa… ». On ne lit AUCUN
   intitulé en entier.
   ⭐ Le repli ne se décide pas à un nombre de pixels de fenêtre, il se décide à « est-ce
   que ça rentre ». C'est exactement ce que fait `flex-wrap: wrap` : tant que la place y
   est, tout reste sur une ligne — la règle qu'Amadou avait posée le 31/07 tient donc
   toujours, mais toute seule ; dès qu'elle n'y est plus, la barre prend une seconde
   rangée au lieu de couper les mots. Le onzième onglet n'aura aucun seuil à corriger.
   ⚠️ Et `flex: 0 0 auto` : sans ça les pilules se COMPRESSENT avant de passer à la
   ligne, et on retrouve les mots coupés dans une barre qui n'a pourtant plus besoin de
   les couper. C'est le refus de rétrécir qui déclenche le retour à la ligne. */
/* ⚠️⚠️⚠️ CINQ ONGLETS DE MÊME LARGEUR, SUR UNE SEULE LIGNE (Amadou, 05/09) : « ils
   doivent être centrés au niveau de la bordure, il ne faut pas qu'il y ait un gros
   espace sinon ça va être vilain, et les boutons doivent faire la même taille même s'il
   n'y a pas le même nombre de lettres. »
   La GRILLE fait les deux d'un coup, là où le flex ne pouvait ni l'un ni l'autre :
   `grid-auto-flow: column` met tout sur une ligne, `grid-auto-columns: minmax(0, 1fr)`
   donne à chacun la même part exacte, et la rangée remplit sa bordure — plus de vide à
   droite, plus de pilule plus large parce que son mot est plus long.
   ⚠️ `minmax(0, 1fr)` et pas `1fr` : sans le 0, une colonne refuse de descendre sous la
   largeur de son contenu et « Ce qu'on en dit » repousserait les autres.
   ⚠️ Le repli sur deux lignes disparaît avec le besoin : à dix onglets il fallait bien
   passer à la ligne, à cinq de largeur égale la question ne se pose plus. */
.dress-rtabs { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: var(--e-4); padding: var(--e-8); }
/* ⚠️⚠️ HUIT ONGLETS DEPUIS L'AJOUT DE SANTÉ ET POPULARITÉ (Amadou, 11/08 : « les boutons
   doivent être à côté d'Infos produit »). La règle « tout sur une ligne » qu'il avait
   posée le 31/07 tient tant que la colonne est large — sur son écran elle l'est. Mais
   sous ~1500 px, huit onglets ne rentrent plus et `text-overflow` les couperait TOUS
   (« Fic… », « San… ») : un onglet coupé ne se lit pas, et c'est pire qu'une deuxième
   rangée. On revient donc à la ligne uniquement là où la seule ligne devient illisible. */
/* (Le point de rupture à 1500 px est retiré : le repli est devenu automatique.) */
.dress-rtabs .an-so {
  height: 32px;
  padding: 0 var(--e-8);
  font-size: var(--t-base);
  gap: var(--e-6);
  /* ⚠️ `justify-content: center` : dans une colonne de grille, le contenu se collerait à
     gauche et les cinq intitulés ne s'aligneraient plus entre eux. Et plus de
     `flex: 0 0 auto` — c'est la grille qui donne la largeur, pas le bouton. */
  justify-content: center;
  min-width: 0;
}

/* ══ LES DEUX MODES D'UN ONGLET (05/09) ═════════════════════════════════════
   Trois des cinq onglets montrent deux vues d'une même chose. Le sélecteur reprend le
   dessin des onglets au-dessus, en plus petit : rien de neuf à apprendre. */
.dress-rmodes { display: flex; gap: var(--e-4); margin-bottom: var(--e-12); }
.dress-rmode {
  flex: 1; min-width: 0; height: var(--e-28); padding: 0 var(--e-10);
  font: inherit; font-size: var(--t-meta); cursor: pointer;
  color: var(--text-3); background: transparent;
  border: var(--e-1) solid var(--border); border-radius: var(--r-md);
  transition: var(--transi);
}
.dress-rmode:hover { color: var(--text); border-color: var(--border-strong); }
.dress-rmode.on { color: var(--th-accent-clair); background: var(--cok-accent-bg);
  border-color: var(--cok-accent); }
/* ⚠️ PLUS DE TRONCATURE DU TOUT. Le `text-overflow: ellipsis` était le pansement du
   `nowrap` : il n'a plus lieu d'être, et le garder ferait revenir les mots coupés dès
   qu'un intitulé serait long. Un onglet dit son nom en entier ou il ne sert à rien. */
.dress-rtabs .an-so > span { white-space: nowrap; }

/* ══════════════════════════════════════════════════════════════════════════════
   FICHE ROBE — le panneau de droite est une CARTE, comme à gauche
   ══════════════════════════════════════════════════════════════════════════════
   Amadou (2026-07-31) : « ce n'est pas fermé », « ça dépasse de la card ».
   Exact : la colonne gauche pose ses blocs dans .dress-color-block (fond dégradé +
   filet + rayon 14), tandis que .dress-rpanel n'avait QUE display/flex/gap — son
   contenu flottait donc à même le fond de la page. Les six panneaux sont encadrés,
   pas seulement les deux nouveaux : sinon le cadre apparaîtrait et disparaîtrait
   d'un onglet à l'autre, ce qui est pire que pas de cadre du tout.

   ⚠️ On encadre le PANNEAU, jamais un conteneur qui envelopperait aussi .dress-rtabs :
   la barre d'onglets est collante (position: sticky, plus haut) et un ancêtre en
   overflow:hidden deviendrait son conteneur de défilement — elle repartirait avec la
   page. Elle reste sœur des panneaux, hors de tout cadre.
   ⚠️ Et surtout PAS de `display` ici : .hidden est en !important, mais autant ne pas
   s'approcher du mécanisme qui masque les panneaux inactifs. */
.dress-rpanel {
  background: linear-gradient(158deg, var(--cok-bg) 0%, rgba(var(--th-voile),0.01) 60%);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--e-16);
}

/* ── T. VENDEUSES — la carte au repos tient en une ligne ─────────────────────
   Elle mesurait 150 px de haut pour 28 px de contenu. Ce n'était pas son padding :
   la tuile « Ajouter des modèles » qui la suivait dans la grille portait
   min-height: 120px, et une grille CSS aligne ses cases en `stretch` par défaut —
   la tuile étirait donc toute sa rangée. La tuile est supprimée (elle faisait
   doublon avec le bouton d'en-tête) ; `align-items: start` verrouille le résultat
   pour que plus aucun voisin ne puisse étirer une carte. */
/* ⚠️ `align-items: start` datait de la GRILLE (il empêchait un voisin d'étirer une
   carte). En colonne flex, il ferait l'inverse : chaque ligne rétrécirait à la
   largeur de son propre texte, et la colonne des « 2/3 » deviendrait un escalier. */
.dress-gen-vend .dress-mvbm-cards { align-items: stretch; }

/* La taille de la vendeuse, à côté de son nom — c'est elle qui dit si la robe
   peut lui aller. Volontairement sobre : une pastille, pas un badge de plus. */
.dress-mvbm-taille {
  flex-shrink: 0;
  font-size: var(--t-micro);
  font-weight: var(--fw-gras);
  letter-spacing: var(--ls-leger);
  padding: var(--e-1) var(--e-6);
  border-radius: var(--r-pilule);
  background: var(--violet-tint);
  color: var(--violet-light);
  cursor: help;
}

/* La carte au repos tient sur DEUX lignes : le nom seul en haut (avec la taille
   poussée à droite), le coloris et le compte de vues en dessous. Sur une seule
   ligne, le nom — seul élément élastique — était comprimé à zéro pixel par les
   pastilles, et on ne savait plus de quelle vendeuse il s'agissait. */
.dress-gen-vend .dress-mvbm-cname { flex: 1 1 auto; min-width: 0; }
.dress-gen-vend .dress-mvbm-taille { margin-left: auto; }
/* ⚠️⚠️ LE PIÈGE DE LA JOURNÉE, QUATRIÈME FOIS : à spécificité ÉGALE, c'est la
   DERNIÈRE règle du fichier qui gagne. `margin-bottom: 6px` était écrit ici,
   150 lignes SOUS le nouveau `margin-bottom: 0` — il l'écrasait en silence.
   La règle vit désormais avec le reste de la ligne, plus haut, et une seule fois. */
.dress-mvbm-card-meta { display: flex; align-items: center; gap: var(--e-6); min-width: 0; }
.dress-mvbm-card-meta .dress-mvbm-color { max-width: 100%; }

/* ⭐ Le compteur porte la seule question de l'écran : « à qui manque-t-il des vues ? ».
   Trois états, trois couleurs — zéro (rouge) se distingue de partiel (ambre), sinon
   une vendeuse vide et une vendeuse à 2/3 se ressemblaient. */
.dress-mvbm-pill.vide {
  background: rgba(232,93,93,.16);
  color: var(--red);
}

/* ── L'ÉTAT SOUS UN EN-TÊTE DE CARTE ─────────────────────────────────────────
   Amadou (13/08) : « ça ne respire toujours pas ». `.cok-subt` porte un margin-top
   NÉGATIF (-4 px) et `.cok-launch-head` aucune marge basse : la phrase d'état
   (« Aucune session Brave ouverte sur le VDS… ») remontait dans le bloc titre.
   ⚠️ Deux corrections, pas une : l'écart, ET l'alignement. La phrase repartait du
   bord gauche alors que le titre est décalé de 54 px par l'icône — trois lignes en
   escalier. Elle se range maintenant dans la MÊME colonne que le titre, ce qui la
   rattache visiblement à lui au lieu de flotter sous l'icône.
   (54 px = 42 de l'icône + 12 de gouttière, les deux lus dans `.cok-launch-ic` et
   `.cok-launch-head` — si l'un des deux bouge, celui-ci bouge aussi.) */
.cok-subt.cok-launch-etat {
  margin: var(--e-14) 0 var(--e-16);
  padding-left: 54px;
}
/* Sous 780 px la colonne devient trop étroite pour offrir 54 px : l'alignement
   coûterait plus de lisibilité qu'il n'en rend. */
@media (max-width: 780px) {
  .cok-subt.cok-launch-etat { padding-left: 0; }
}

/* ── T. VENDEUSES — quand la liste est vide, on dit pourquoi ─────────────────
   Même grammaire que `.robe-ps-manque` de la fiche : un filet à gauche, du texte
   éteint. On ne réinvente pas une « carte d'information » pour une phrase. */
.dress-mvbm-vide {
  font-size: var(--t-meta);
  line-height: var(--lh-normal);
  color: var(--text-2);
  border-left: 2px solid rgba(var(--th-voile),0.12);
  padding-left: var(--e-10);
  margin-top: var(--e-2);
}

/* Barre de filtre par taille : le motif de la Bibliothèque, posé dans le panneau. */
.dress-mvbm-filtres { margin: var(--e-10) 0 var(--e-12); }
/* Écartée par le filtre. Classe dédiée plutôt que .hidden : le mécanisme d'espace
   ouvert joue déjà avec display sur ces mêmes cartes, autant ne pas les mélanger. */
.dress-mvbm-card--off { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   BIBLIOTHÈQUE — Robes et Vendeuses partagent la même ossature
   ══════════════════════════════════════════════════════════════════════════════
   Les deux gabarits étaient inversés (voir le commentaire dans index.html). Les
   classes ont été échangées ; il reste à porter les deux détails qui vivaient
   sur l'ancien gabarit des vendeuses. */

/* Une taille à zéro reste lisible mais éteinte — comme avant sur .lib-tier-tab. */
.lib-marque-chip.vide { opacity: .38; }

/* « Filtres » a quitté sa ligne pour rejoindre la barre du haut. Ce qui reste ici
   n'est plus qu'un panneau dépliable : replié, il ne doit RIEN peser — ni filet,
   ni fond, ni hauteur. Sinon on aurait échangé une ligne de bouton contre une
   ligne vide, et la vue Robes décrocherait toujours de la vue Vendeuses. */
#lib-adv-filters { border-top: 0; background: none; }
/* ⚠️⚠️ CETTE COQUILLE NE DOIT JAMAIS ÊTRE UN ITEM DE LA RANGÉE. Elle est vide (son
   seul enfant est le panneau, qui flotte en `absolute`), mais la rangée porte
   `gap: var(--e-8)` : dès qu'elle compte comme item, elle ajoute UN ÉCART de 8 px
   et « Filtres » saute de 8 px vers la gauche à chaque ouverture. Mesuré : 1288 →
   1280, largeur du bouton inchangée. `display: contents` la fait disparaître du
   flux sans toucher à l'ancrage du panneau — il vise `.lib-sticky-bar`, seul
   ancêtre positionné, et cette coquille est `static` de toute façon.
   `.hidden { display: none !important }` continue de la refermer. */
#lib-adv-filters { display: contents; }
/* Repli : si la coquille reste visible, le panneau replié ne pèse rien. */
#lib-adv-filters > .lib-filter-content.hidden { display: none; }

/* Dans la barre du haut, « Filtres » s'aligne sur la flèche et sur Sélectionner. */
/* ⚠️⚠️ DEUX RÈGLES SE DISPUTAIENT CE BOUTON — 32 px ici, 38 px plus bas, la dernière
   écrite gagnait. Elles habillaient l'ancien dessin ; depuis qu'il porte `btn-secondary`
   comme « Sélectionner », elles ne font que l'empêcher de lui ressembler. Retirées toutes
   les deux : un bouton, un dessin. */
.lib-filters-row-right .lib-filter-toggle.hidden { display: none; }

/* « À allier » compte des MARIAGES possibles, pas des fiches en attente : son badge
   passe à l'ambre quand il y a quelque chose à faire. C'était .lib-vend-n.attente. */
.lib-tier-tab-count.attente {
  background: rgba(224,164,59,.18);
  color: var(--amber);
  opacity: 1;
}
.lib-tier-tab.active .lib-tier-tab-count.attente { background: rgba(224,164,59,.22); color: var(--amber); }

/* ══════════════════════════════════════════════════════════════════════════════
   L'ÉCRAN D'ACCUEIL — le rideau d'ouverture
   ══════════════════════════════════════════════════════════════════════════════
   Il couvre le temps que le site charge ses 3 Mo et aille chercher ses données.
   Le parti pris : l'étoile ne se contente pas d'apparaître, elle ARRIVE — elle
   traverse l'écran depuis le bas-gauche et se pose. C'est une étoile filante,
   autant qu'elle file. Le flou de vitesse est le même que celui des transitions
   d'onglets du site : le rideau parle déjà la langue de l'application.

   ⚠️ Le z-index reste SOUS le filet anti-blocage (2147483647, index.html) : si le
   site est mort, son bouton « Recharger » doit pouvoir passer par-dessus. */
.velbo-rideau {
  position: fixed; inset: 0;
  z-index: 2147483000;
  display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(120% 90% at 50% 34%, var(--survol-fond), rgba(var(--th-ombre),0) 58%),
    radial-gradient(90% 70% at 78% 88%, rgba(var(--th-second-rgb),.10), rgba(var(--th-ombre),0) 62%),
    var(--bg);
  /* Dernier étage de sûreté, en CSS PUR : si le JavaScript ne tourne pas du tout,
     le rideau s'efface quand même. Le contrôleur, lui, le retire vers 2,8 s —
     cette animation-ci n'est là que pour le cas où il ne tournerait jamais. */
  animation: velbo-rideau-secours .5s var(--pose, ease) 6s both;
}
@keyframes velbo-rideau-secours { to { opacity: 0; visibility: hidden; } }

/* ⚠️ AU REPOS, LE CONTENU EST INVISIBLE. Sans ça, le navigateur peignait le rideau
   dès qu'il le rencontrait dans le HTML : étoile posée au centre, immobile. Puis le
   contrôleur ajoutait « joue » et l'animation repartait de son premier instant —
   l'étoile disparaissait pour revenir en volant (Amadou : « on voit l'étoile, elle
   disparaît, elle réapparaît, après ça se lance »).
   Rien ne s'affiche donc tant que la décision n'est pas prise. Et si le rideau ne
   doit PAS jouer, on ne voit rien du tout : il est retiré avant la première image. */
.velbo-rideau-corps {
  display: flex; flex-direction: column; align-items: center;
  gap: 0;
  transform: translateY(-8px);
  opacity: 0;
}
.velbo-rideau.joue .velbo-rideau-corps { opacity: 1; }

/* ── L'ASTRE ─────────────────────────────────────────────────────────────────
   Il entre par le bas-gauche, vite, flou de vitesse à fond, et décélère
   longuement jusqu'à sa place. La traînée s'étire pendant le vol puis se détend. */
.velbo-rideau-astre { display: block; width: 108px; height: 108px; }
.velbo-rideau-astre svg { width: 100%; height: 100%; display: block; }
.velbo-rideau.joue .velbo-rideau-astre {
  animation: velbo-astre-arrive 2.05s var(--c-pose) var(--t-long) both;
}
@keyframes velbo-astre-arrive {
  0%   { opacity: 0; transform: translate3d(-190px, 150px, 0) scale(.72) rotate(-8deg); filter: blur(9px); }
  55%  { opacity: 1; filter: blur(2.4px); }
  100% { opacity: 1; transform: none; filter: blur(0); }
}
/* La traînée s'allonge dans le sens du vol, puis reprend sa forme. */
.velbo-rideau.joue .velbo-rideau-trainees {
  transform-origin: 46px 26px;
  animation: velbo-trainee 2.05s var(--c-pose) var(--t-long) both;
}
@keyframes velbo-trainee {
  0%   { transform: scale(1.55, 1.35); opacity: .5; }
  100% { transform: none; opacity: 1; }
}
/* L'étincelle et les poussières n'arrivent qu'une fois l'astre posé : elles se
   déposent derrière lui, comme ce qu'il laisse. */
.velbo-rideau.joue .velbo-rideau-etincelle,
.velbo-rideau.joue .velbo-rideau-poussiere {
  animation: velbo-poussiere .7s var(--pose, ease) 1.65s both;
}
.velbo-rideau.joue .velbo-rideau-poussiere:last-of-type { animation-delay: 1.80s; }
@keyframes velbo-poussiere { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }

/* ── LE NOM, lettre par lettre ───────────────────────────────────────────────
   Même traitement que l'accueil du Studio : le site se cite lui-même plutôt que
   d'inventer un style de plus. */
.velbo-rideau-nom {
  display: flex;
  margin-top: var(--e-14);
  font-size: var(--t-3xl); font-weight: 300;
  letter-spacing: .19em; text-indent: .19em;   /* l'interlettrage recentre le mot */
  color: var(--text);
}
.velbo-rideau-nom span { display: inline-block; opacity: 0; }
.velbo-rideau.joue .velbo-rideau-nom span {
  animation: velbo-lettre .9s var(--c-pose) both;
}
.velbo-rideau.joue .velbo-rideau-nom span:nth-child(1) { animation-delay: 1.30s; }
.velbo-rideau.joue .velbo-rideau-nom span:nth-child(2) { animation-delay: 1.39s; }
.velbo-rideau.joue .velbo-rideau-nom span:nth-child(3) { animation-delay: 1.48s; }
.velbo-rideau.joue .velbo-rideau-nom span:nth-child(4) { animation-delay: 1.57s; }
.velbo-rideau.joue .velbo-rideau-nom span:nth-child(5) { animation-delay: 1.66s; }
@keyframes velbo-lettre {
  from { opacity: 0; transform: translate3d(0, 14px, 0); filter: blur(5px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* ── LA PHRASE ───────────────────────────────────────────────────────────────
   « Ça a tourné sans toi. » — c'est ce que dit ce moment précis : le site va
   chercher ce qui s'est passé pendant l'absence. */
.velbo-rideau-mot {
  margin-top: var(--e-14);
  font-size: var(--t-base); font-weight: var(--fw-normal);
  letter-spacing: var(--ls-ample);
  color: var(--text-2);
  opacity: 0;
}
.velbo-rideau.joue .velbo-rideau-mot {
  animation: velbo-lettre 1.0s var(--c-pose) 1.70s both;
}

/* ── LA JAUGE ────────────────────────────────────────────────────────────────
   Un filet, pas une barre : il informe sans réclamer l'attention. Son remplissage
   est piloté par de VRAIS jalons de chargement (voir le contrôleur, index.html). */
.velbo-rideau-jauge {
  margin-top: 30px;
  width: 168px; height: 2px;
  border-radius: 2px;
  background: rgba(var(--th-voile),.07);
  overflow: hidden;
  opacity: 0;
}
.velbo-rideau.joue .velbo-rideau-jauge {
  animation: velbo-jauge-vient .9s var(--pose, ease) 1.45s both;
}
@keyframes velbo-jauge-vient { from { opacity: 0; width: 40px; } to { opacity: 1; width: 168px; } }
.velbo-rideau-jauge i {
  display: block; width: 100%; height: 100%;
  transform: scaleX(.02); transform-origin: 0 50%;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--violet-soft, var(--violet-soft)), var(--cyan, var(--cyan)));
  box-shadow: 0 0 10px rgba(var(--th-accent-rgb),.55);
  transition: transform var(--t-moyen) linear;
}

/* ⚠️ TOUTE LA SÉQUENCE EST FINIE À 2,70 s, et le plancher du rideau est à 2,95 s
   (index.html). Ces 200 ms d'écart ne sont pas du gâchis : c'est le temps de VOIR
   l'image achevée. Sans eux, la phrase se faisait couper en plein fondu — mesuré :
   elle finissait à 2,87 s pour un rideau qui partait à 2,86.
   Si on rallonge encore une animation, il faut remonter le plancher d'autant. */

/* ── LA SORTIE ───────────────────────────────────────────────────────────────
   Tout monte et se dissout ensemble ; le fond s'efface un peu après, pour que
   l'application se découvre plutôt qu'elle n'apparaisse. */
.velbo-rideau.leve { animation: none; pointer-events: none; }

/* ⚠️⚠️ LA BRUSQUERIE VENAIT D'ICI : UNE COURBE D'ENTRÉE SUR UNE SORTIE.
   Le voile s'effaçait en `--c-pose` — `cubic-bezier(.22, 1, .36, 1)`, la courbe faite
   pour ce qui ARRIVE : elle part à toute vitesse puis traîne. Mesuré sur les 0,72 s :
   0 % à 120 ms, 40 % à 192 ms, **76 % à 300 ms**, et 540 ms de traîne que l'œil ne voit
   plus. Autrement dit, les trois quarts du dévoilement tombaient en un cinquième de
   seconde — mathématiquement, « d'un coup ».
   Et les deux courbes se combattaient : le corps partait en `cubic-bezier(.5,0,.75,0)`,
   qui n'avait fait que **2,2 %** de son chemin (0,7 px sur 30) quand le voile était déjà
   à un quart d'opacité. Le « tout monte et se dissout ensemble » du commentaire n'avait
   donc jamais lieu.
   ⚠️ `--c-sortie` existait depuis le début et le rideau ne l'utilisait nulle part. */
.velbo-rideau.leve .velbo-rideau-corps {
  animation: velbo-rideau-part .78s var(--c-sortie) both;
}
@keyframes velbo-rideau-part {
  to { opacity: 0; transform: translateY(-30px) scale(.985); filter: blur(4px); }
}
/* ── LE VOILE SE DÉCHIRE, IL NE S'EFFACE PAS ──────────────────────────────────
   Amadou (08/08) : « c'est trop simplet ». Un fondu n'est pas un geste : c'est
   l'absence de geste, faite proprement.
   Le rideau s'ouvre donc en un cercle, EXACTEMENT au point où l'étoile du logo se
   tient, et ce cercle emporte le voile jusqu'aux bords. Le bord de l'ouverture porte
   une lueur violette : c'est l'étoile qui perce l'écran, pas un calque qui disparaît.
   ⭐ Tout se passe SUR LE RIDEAU, jamais sur l'application : il est enfant direct de
   <body> et ne contient aucun élément du site. Il peut donc se permettre un masque, un
   flou et un dégradé — trois choses interdites sur un ancêtre de l'app, où elles
   casseraient tout `position: fixed`. C'est ce qui rend le geste possible ici alors
   qu'il ne l'était pas là-bas. */
@property --velbo-iris {
  syntax: '<percentage>';
  initial-value: 0%;
  inherits: true;
}

.velbo-rideau.leve {
  /* ⚠️ Cette animation REMPLACE le `animation: none` qui neutralisait le filet de
     secours à 6 s — une `animation` abrégée écrase toute la déclaration précédente,
     donc le filet reste bien désamorcé. Ne jamais repasser à `animation-name` seul
     ici : le filet reviendrait et claquerait le rideau en plein geste. */
  animation: velbo-iris 1.16s var(--c-sortie) .06s both;

  /* Le trou, au point de l'étoile. Le bord n'est pas net : 22 points de dégradé, sinon
     on voit un cercle découpé aux ciseaux au lieu d'une déchirure. */
  -webkit-mask-image: radial-gradient(circle at 50% 42%,
      rgba(var(--th-ombre),0) var(--velbo-iris),
      rgba(var(--th-ombre),.45) calc(var(--velbo-iris) + 8%),
      #000 calc(var(--velbo-iris) + 22%));
  mask-image: radial-gradient(circle at 50% 42%,
      rgba(var(--th-ombre),0) var(--velbo-iris),
      rgba(var(--th-ombre),.45) calc(var(--velbo-iris) + 8%),
      #000 calc(var(--velbo-iris) + 22%));

  /* La lueur au bord de l'ouverture, qui court devant elle. Elle vit dans le FOND du
     rideau et non dans un pseudo-élément : un enfant serait coupé par le masque au
     moment précis où on veut le voir. */
  /* ⚠️ Les DEUX dégradés d'ambiance du rideau sont repris à l'identique en dessous.
     `background-image` remplace toutes les couches d'images du `background` abrégé :
     sans eux, le fond du rideau changeait d'un coup à l'instant même où la levée
     commence — un saut visuel juste avant le geste qu'on veut rendre doux. */
  background-image:
      radial-gradient(circle at 50% 42%,
        rgba(var(--th-ombre),0) calc(var(--velbo-iris) + 1%),
        rgba(167,139,250,.50) calc(var(--velbo-iris) + 7%),
        rgba(var(--th-accent-rgb),.14) calc(var(--velbo-iris) + 15%),
        rgba(var(--th-ombre),0) calc(var(--velbo-iris) + 26%)),
      radial-gradient(120% 90% at 50% 34%, var(--survol-fond), rgba(var(--th-ombre),0) 58%),
      radial-gradient(90% 70% at 78% 88%, rgba(var(--th-second-rgb),.10), rgba(var(--th-ombre),0) 62%);

  /* ⚠️ Le fondu RESTE, en dessous du masque : c'est le filet. Si `@property` venait à
     manquer, `var(--velbo-iris)` rendrait le masque invalide — sans lui le rideau ne
     partirait jamais. Là, il retombe simplement sur un fondu correct.
     ⚠️ Le délai de `visibility` suit la durée réelle du geste : laissé à 0,86 s, il
     ferait disparaître le rideau d'un coup alors qu'il est encore à moitié opaque —
     ça ne ressemble pas à une erreur de CSS et ça se cherche longtemps. */
  transition: opacity 1.05s var(--c-sortie) .16s,
              filter   1.05s var(--c-sortie) .16s,
              visibility var(--t-bref) linear 1.21s;
  opacity: 0; visibility: hidden;
  filter: blur(9px);
}
/* 132 % et non 100 % : le coin d'un écran large est plus loin du centre que son bord,
   et à 100 % il resterait quatre angles de voile après la fin du geste. */
@keyframes velbo-iris { to { --velbo-iris: 132%; } }

@media (prefers-reduced-motion: reduce) {
  .velbo-rideau.leve { animation: none; -webkit-mask-image: none; mask-image: none; background-image: none; }
}

/* ── L'ARRIVÉE DEPUIS LA CONNEXION : elle n'avait AUCUN geste de sortie ────────
   ⚠️⚠️ `.velbo-rideau.arrive .velbo-rideau-corps { display: none }` — le corps est
   masqué dans ce mode, donc `velbo-rideau-part` ne s'appliquait à RIEN. Il ne restait
   qu'un aplat dont l'opacité s'effondrait. C'est le cas le plus brutal des deux, et
   c'est précisément celui dont parle Amadou : « lorsqu'on se fait aspirer ».
   La lueur retombe donc pour de bon, en s'écartant : elle grandit un peu en se
   dissipant, comme une lumière qu'on traverse. */
.velbo-rideau.arrive.leve::after {
  animation: velbo-lueur-secarte .92s var(--c-sortie) both;
}
@keyframes velbo-lueur-secarte {
  to { opacity: 0; transform: scale(1.18); filter: blur(14px); }
}

@media (prefers-reduced-motion: reduce) {
  .velbo-rideau, .velbo-rideau * { animation: none !important; transition: none !important; }
  .velbo-rideau { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   L'ARRIVÉE — la fin du saut, côté site
   ══════════════════════════════════════════════════════════════════════════════
   La page de connexion se termine sur un éclat de lumière ; le site s'ouvre sur le
   MÊME éclat, et le laisse retomber. Les deux pages partagent donc une image
   identique : c'est dans cette image que tombe le changement de page, et c'est
   pour ça qu'on ne le voit pas.
   Les traits ne partent plus vers l'extérieur — ils décélèrent et se résorbent :
   on sort de la vitesse au lieu d'y entrer. */
.velbo-rideau-saut { position: absolute; inset: 0; overflow: hidden; pointer-events: none; opacity: 0; }
.velbo-rideau-saut i {
  position: absolute; left: 50%; top: 50%;
  width: 1.6px; height: var(--l); border-radius: 2px;
  transform-origin: 50% 0;
  transform: rotate(var(--a)) translateY(125vh) scaleY(1.7);
  background: linear-gradient(180deg, rgba(154,141,255,0), var(--violet-soft, var(--violet-soft)) 30%, var(--cyan, var(--cyan)) 75%, rgba(var(--th-second-rgb),0));
  opacity: 0;
}
.velbo-rideau.arrive .velbo-rideau-saut { opacity: 1; }
.velbo-rideau.arrive .velbo-rideau-saut i {
  animation: velbo-freine 1.3s var(--c-pose) var(--d) both;
}
@keyframes velbo-freine {
  0%   { transform: rotate(var(--a)) translateY(125vh) scaleY(1.7); opacity: .8; }
  70%  { opacity: .35; }
  100% { transform: rotate(var(--a)) translateY(4vh)   scaleY(.04); opacity: 0; }
}
/* La lumière de la page de connexion, qui retombe. C'est elle, l'image commune. */
/* ⚠️ `background-color` et non `background` : l'abrégé écraserait le `background-image`
   de `.leve` — la lueur au bord de la déchirure — puisque cette règle est déclarée plus
   bas à spécificité égale. Le mode aspiration perdrait l'anneau sans qu'on comprenne
   pourquoi, alors que le masque, lui, continuerait de s'ouvrir. */
.velbo-rideau.arrive { background-color: var(--bg); }
.velbo-rideau.arrive::after {
  content: ""; position: absolute; inset: 0;
  /* ⚠️ La MÊME image que la fin du départ, côté connexion : un violet profond avec
     une lueur douce, jamais du blanc. C'est cette image commune qui cache le
     changement de page — et elle n'a pas besoin d'être claire pour ça. */
  background: radial-gradient(70% 55% at 50% 46%, rgba(154,141,255,.30), rgba(var(--th-ombre),0) 70%), #171233;
  animation: velbo-lumiere-retombe 1.05s cubic-bezier(.25, 0, .2, 1) both;
}
@keyframes velbo-lumiere-retombe { from { opacity: 1; } to { opacity: 0; } }
/* En mode arrivée, l'introduction ne se joue pas : elle vient d'avoir lieu ailleurs. */
.velbo-rideau.arrive .velbo-rideau-corps { display: none; }

@media (prefers-reduced-motion: reduce) {
  .velbo-rideau-saut, .velbo-rideau.arrive::after { display: none; }
}

/* ── Paramètres › Sécurité — changer le mot de passe du site ── */
.pa-mdp { display: flex; flex-direction: column; gap: var(--e-8); }
.pa-mdp input {
  width: 100%; height: 38px; padding: 0 var(--e-14);
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-md);
  color: var(--text); font-family: inherit; font-size: var(--t-base); letter-spacing: var(--ls-large);
  outline: none; transition: border-color var(--t-moyen), box-shadow var(--t-moyen);
}
.pa-mdp input::placeholder { color: var(--text-3); letter-spacing: var(--ls-zero); }
.pa-mdp input:focus { border-color: var(--violet-soft); box-shadow: 0 0 0 3px var(--violet-tint); }
.pa-mdp-bas { display: flex; align-items: center; gap: var(--e-8); margin-top: var(--e-2); }
.pa-mdp-etat { flex: 1; min-width: 0; font-size: var(--t-meta); line-height: var(--lh-serre); color: var(--text-3); }
.pa-mdp-etat.ok  { color: var(--green); }
.pa-mdp-etat.non { color: var(--red); }

/* ── LE CIEL DU RIDEAU — la fusée et le satellite ─────────────────────────────
   Ils existent déjà dans l'application (une étoile filante toutes les minutes, une
   fusée ou un satellite toutes les cinq). L'écran d'accueil emprunte les MÊMES
   objets : c'est le même ciel, pas un décor fabriqué pour l'occasion.
   Ils passent DERRIÈRE la scène, très discrètement — ils ne doivent jamais voler
   le regard à l'étoile qui arrive. */
.velbo-rideau-ciel { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.velbo-rideau-fusee, .velbo-rideau-satellite { position: absolute; opacity: 0; }
.velbo-rideau-fusee { width: 26px; height: 26px; left: -60px; top: 66%; }
.velbo-rideau-fusee svg { width: 100%; height: 100%; display: block; }
.velbo-rideau-satellite {
  width: 3px; height: 3px; border-radius: 50%; left: -20px; top: 22%;
  background: var(--violet-light); box-shadow: 0 0 7px 1px rgba(var(--th-voile),.55);
}
/* ⚠️ PAS PENDANT L'ACCUEIL. Amadou (2026-08-01) : « je ne veux pas les voir sur
   l'écran d'affichage — je veux les voir quand se passe l'aspiration, et je veux
   les voir EUX AUSSI se faire aspirer. »
   Ils ne traversent donc plus tranquillement le fond : ils font partie de ce que le
   saut emporte. Ils partent de près du centre et filent vers l'extérieur, étirés et
   flous, dans la même direction que les traits — comme deux objets qu'on double. */
.velbo-rideau.joue .velbo-rideau-ciel { display: none; }

/* Ils se placent au centre : le mouvement d'aspiration est RADIAL, il doit donc
   partir de là où l'on regarde. */
.velbo-rideau-fusee, .velbo-rideau-satellite {
  left: 50%; top: 50%; margin: 0;
}
/* ── LE DÉPART : ils se font aspirer ── */
.velbo-rideau.part .velbo-rideau-fusee {
  animation: velbo-fusee-aspiree 1.35s cubic-bezier(.36, 0, .72, .42) var(--t-bref) both;
}
@keyframes velbo-fusee-aspiree {
  0%   { transform: translate(-58px, -34px) scale(.85) rotate(-10deg); opacity: 0; filter: blur(0); }
  18%  { opacity: .85; }
  100% { transform: translate(-124vh, -72vh) scale(2.3) rotate(-16deg); opacity: 0; filter: blur(7px); }
}
.velbo-rideau.part .velbo-rideau-satellite {
  animation: velbo-satellite-aspire 1.35s cubic-bezier(.36, 0, .72, .42) var(--t-bref) both;
}
@keyframes velbo-satellite-aspire {
  0%   { transform: translate(46px, 30px) scale(1); opacity: 0; }
  20%  { opacity: .9; }
  100% { transform: translate(118vh, 76vh) scale(3.4); opacity: 0; filter: blur(5px); }
}

/* ── L'ARRIVÉE : ils décélèrent avec le reste, et se résorbent ── */
.velbo-rideau.arrive .velbo-rideau-fusee {
  animation: velbo-fusee-freine 1.3s var(--c-pose) var(--t-bref) both;
}
@keyframes velbo-fusee-freine {
  0%   { transform: translate(-124vh, -72vh) scale(2.3) rotate(-16deg); opacity: .7; filter: blur(7px); }
  100% { transform: translate(-44px, -26px) scale(.8) rotate(-8deg); opacity: 0; filter: blur(0); }
}
.velbo-rideau.arrive .velbo-rideau-satellite {
  animation: velbo-satellite-freine 1.3s var(--c-pose) var(--t-bref) both;
}
@keyframes velbo-satellite-freine {
  0%   { transform: translate(118vh, 76vh) scale(3.4); opacity: .75; filter: blur(5px); }
  100% { transform: translate(34px, 22px) scale(1); opacity: 0; filter: blur(0); }
}

@media (prefers-reduced-motion: reduce) { .velbo-rideau-ciel { display: none; } }

/* ── LE DÉPART — la même aspiration, dans l'autre sens ────────────────────────
   La page de connexion la joue avec ses propres règles (elle est autonome, servie
   par le serveur). Ici, c'est la définition partagée : elle sert à l'aperçu en
   boucle, et à tout écran du site qui aurait un jour besoin de « partir ».
   Départ et arrivée finissent/commencent sur LA MÊME image — un violet profond,
   jamais du blanc. C'est ce qui rend la couture invisible sans agresser l'œil. */
.velbo-rideau.part .velbo-rideau-corps {
  animation: velbo-aspire 1.35s cubic-bezier(.42, 0, .7, .35) both;
}
@keyframes velbo-aspire {
  0%   { transform: translateY(-8px) scale(1);   filter: blur(0);    opacity: 1; }
  55%  { opacity: .9; }
  100% { transform: translateY(-8px) scale(2.1); filter: blur(11px); opacity: 0; }
}
/* ⚠️ Le ciel est masqué pendant l'accueil (.joue) — mais le saut se joue AVEC .joue
   encore posé. Il faut donc le rendre explicitement au moment de l'aspiration,
   sinon la fusée et le satellite resteraient invisibles au seul moment où l'on
   veut les voir. */
.velbo-rideau.part .velbo-rideau-ciel { display: block; }
.velbo-rideau.part .velbo-rideau-saut { opacity: 1; }
.velbo-rideau.part .velbo-rideau-saut i {
  animation: velbo-file 1.35s cubic-bezier(.36, 0, .72, .42) var(--d) both;
}
@keyframes velbo-file {
  0%   { transform: rotate(var(--a)) translateY(0)     scaleY(.03); opacity: 0; }
  14%  { opacity: .85; }
  100% { transform: rotate(var(--a)) translateY(125vh) scaleY(1.7); opacity: 0; }
}
.velbo-rideau.part::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(70% 55% at 50% 46%, rgba(154,141,255,.30), rgba(var(--th-ombre),0) 70%), #171233;
  animation: velbo-lueur-monte 1.25s cubic-bezier(.45, 0, .65, .35) var(--t-long) both;
}
@keyframes velbo-lueur-monte { from { opacity: 0; } to { opacity: 1; } }

/* Faire une offre depuis l'en-tête de l'article — compact, il ne doit pas concurrencer
   l'article lui-même. Collé à droite, il se lit sans prendre de place. */
.msg-item-offre{
  margin-left:auto; flex:0 0 auto;
  padding:var(--e-4) var(--e-10); border-radius: var(--r-pilule); cursor:pointer;
  border:1px solid rgba(var(--th-accent-rgb),.42); background:var(--survol-fond);
  color:var(--violet-light); font:500 11px/1.35 inherit; white-space:nowrap;
  transition:background var(--t-moyen) var(--c-pose),color var(--t-moyen) var(--c-pose);
}
.msg-item-offre:hover{ background:var(--violet-tint-strong); color:var(--text); }
.msg-thread-item{ display:flex; align-items:center; gap:var(--e-8); }

/* ── L'OFFRE ────────────────────────────────────────────────────────────────
   Une offre n'est pas une phrase : c'est un CHIFFRE avec un statut. On doit pouvoir
   la lire sans la lire, d'un coup d'œil dans le fil.
   Sa couleur vient de son ÉTAT, et la pastille reprend la forme des badges de la
   liste — l'offre raccroche au reste de l'interface au lieu d'être un objet à part.
   Aucune action : Vinted ne permet pas de supprimer une offre. */
.cok-offre-l{ display:flex; margin-top:var(--e-12); }
.cok-offre-l.me{ justify-content:flex-end; }
.cok-offre-l.them{ justify-content:flex-start; }

.cok-offre{
  --ton:var(--amber);                         /* en attente : ambre, comme les badges */
  min-width:172px; max-width:78%;
  padding:var(--e-10) var(--e-14) var(--e-10); border-radius: var(--r-lg);
  border:1px solid color-mix(in srgb, var(--ton) 34%, transparent);
  background:color-mix(in srgb, var(--ton) 9%, transparent);
}
.cok-offre.ok{ --ton:var(--cok-green,var(--green)); }
.cok-offre.ko{ --ton:var(--cok-red,var(--red)); }

.cok-offre-h{ display:flex; align-items:center; gap:var(--e-6); margin-bottom:var(--e-2);
  font-size:var(--t-micro); letter-spacing:var(--ls-caps); text-transform:uppercase; color:var(--ton); }

/* Prix et état sur UNE ligne : la carte reste basse, elle n'encombre pas le fil. */
.cok-offre-r{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--e-10); }
.cok-offre-p{ display:flex; align-items:baseline; gap:var(--e-8);
  font-size:var(--t-lead); line-height:var(--lh-titre); color:var(--cok-text,var(--text));
  font-variant-numeric:tabular-nums; }
.cok-offre-p s{ font-size:var(--t-meta); color:var(--cok-text-3,var(--text-3)); }

/* Accepter / refuser : sous le prix, discrets, et seulement tant que l'offre attend
   une décision. Un écran qui montre un problème sans permettre de le régler oblige à
   retourner sur Vinted — c'est exactement ce qu'on veut éviter. */
.cok-offre-a{ display:flex; gap:var(--e-6); margin-top:var(--e-10); }
.cok-offre-btn{
  flex:1; padding:var(--e-6) var(--e-10); border-radius: var(--r-sm); cursor:pointer;
  font:500 11px/1.3 inherit; color:var(--cok-text-2,var(--text-2));
  border:1px solid var(--cok-border-2,rgba(var(--th-voile),.15));
  background:rgba(var(--th-voile),.04);
  transition:background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose);
}
.cok-offre-btn:hover{ background:rgba(var(--th-voile),.09); color:var(--cok-text,var(--text)); }
/* LES DEUX BOUTONS SONT ORANGE AU REPOS (Amadou, 2026-08-01). Une offre est une
   décision EN ATTENTE : les deux issues doivent se présenter pareil, sans qu'une
   couleur pousse déjà vers l'une des deux. La couleur qui tranche n'arrive qu'au
   survol — vert pour accepter, rouge pour refuser — au moment où la main est dessus. */
.cok-offre-btn.ok, .cok-offre-btn.ko{ color:var(--cok-warn,var(--amber));
  border-color:color-mix(in srgb, var(--cok-warn,var(--amber)) 40%, transparent);
  background:color-mix(in srgb, var(--cok-warn,var(--amber)) 10%, transparent); }
.cok-offre-btn.ok:hover{ color:var(--text);
  border-color:color-mix(in srgb, var(--cok-green,var(--green)) 55%, transparent);
  background:color-mix(in srgb, var(--cok-green,var(--green)) 26%, transparent); }
.cok-offre-btn.ko:hover{ color:var(--text);
  border-color:color-mix(in srgb, var(--cok-red,var(--red)) 55%, transparent);
  background:color-mix(in srgb, var(--cok-red,var(--red)) 26%, transparent); }

.cok-offre-att{ font-size:var(--t-mini); color:var(--cok-text-3,var(--text-3)); font-style:italic; }

.cok-offre-b{ flex:0 0 auto; font-size:var(--t-micro); padding:var(--e-2) var(--e-8); border-radius: var(--r-pilule);
  white-space:nowrap; color:var(--ton);
  background:color-mix(in srgb, var(--ton) 18%, transparent); }

/* Le message qui annonce un blocage sort du fil : c'est un fait sur le compte,
   pas une conversation. */
.cok-blocage{ display:flex; flex-direction:column; gap:var(--e-4); margin:0 0 var(--e-12);
  padding:var(--e-10) var(--e-14); border-radius: var(--r-md);
  border:1px solid rgba(240,113,90,.42); background:rgba(240,113,90,.11); color:var(--red); }
.cok-blocage span{ font-size:var(--t-mini); line-height:var(--lh-serre); opacity:.85; color:inherit; }

/* La croix pour effacer un message chez Vinted. Elle ne doit pas se voir en
   permanence : une bulle de conversation n'est pas une barre d'outils. Elle
   n'apparaît qu'au survol, et reste accessible au clavier. */
.cok-mb-del{
  flex:0 0 auto;
  opacity:0; pointer-events:none; transition:opacity var(--t-bref) var(--c-pose);
  border:0; background:transparent; cursor:pointer;
  color:var(--cok-text-3,#8b87a8); font-size:var(--t-mini); line-height:var(--lh-un); padding:var(--e-4) var(--e-4);
}
.cok-mb-del:hover{ opacity:1; color:var(--red); }

/* ── LES MESSAGES ───────────────────────────────────────────────────────────
   Un fil de conversation se lit, il ne se parcourt pas. Trois principes :
   · GROUPER — les messages consécutifs d'une même personne forment un bloc.
     Isolés, le fil ressemble à une liste ; groupés, à une conversation.
   · SITUER — l'heure, mais seulement à la fin d'un groupe. La répéter sur chaque
     bulle d'une même salve n'apprend rien et alourdit.
   · RESPIRER — une ligne de texte trop longue se lit mal : on plafonne la largeur. */
.cok-mb-l{ display:flex; align-items:flex-end; gap:var(--e-6); margin-top:var(--e-2); }
.cok-mb-l.me{ justify-content:flex-end; }
.cok-mb-l.them{ justify-content:flex-start; }
.cok-mb-l.them .cok-mb-del{ order:2; }
/* Un nouveau groupe respire ; à l'intérieur, les bulles se serrent. */
.cok-mb-l.debut{ margin-top:var(--e-12); }
.cok-mb-l:first-child{ margin-top:0; }

.cok-mb{ max-width:min(74%, 46ch); }
.cok-mb.note{ max-width:86%; text-align:center; margin:var(--e-10) auto; }

.cok-mb-txt{
  padding:var(--e-10) var(--e-14); font-size:var(--t-base); line-height:var(--lh-normal);
  color:var(--cok-text-1,var(--text));
  /* Coins asymétriques : le coin « d'attache » reste net du côté de l'auteur.
     C'est ce qui donne le sens de lecture sans ajouter d'ornement. */
  border-radius: var(--r-lg);
  word-break:break-word; overflow-wrap:anywhere;
}
.cok-mb-l.them .cok-mb-txt{
  background:var(--surface-2); border:1px solid var(--cok-border,rgba(var(--th-voile),.09));
  border-bottom-left-radius:5px;
}
/* Le liseré d'entrée : sur la PREMIÈRE bulle d'un groupe seulement. Il marque une
   prise de parole — et remplace avantageusement une queue de bulle, qui casse dès
   qu'on groupe. */
.cok-mb-l.them.debut .cok-mb-txt{ border-left:2px solid rgba(var(--th-voile),.22); }
.cok-mb-l.me.debut .cok-mb-txt{ border-right:2px solid var(--cok-accent,var(--violet-soft)); }
.cok-mb-l.me .cok-mb-txt{
  background:linear-gradient(180deg, var(--cok-accent-bg), rgba(var(--th-accent-rgb),.12));
  border:1px solid rgba(var(--th-accent-rgb),.28);
  border-bottom-right-radius:5px;
}
/* Au milieu d'un groupe, le coin d'attache reste petit : les bulles se suivent. */
.cok-mb-l.them:not(.fin) .cok-mb-txt{ border-bottom-left-radius:5px; }
.cok-mb-l.me:not(.fin) .cok-mb-txt{ border-bottom-right-radius:5px; }
.cok-mb-l.them:not(.debut) .cok-mb-txt{ border-top-left-radius:5px; }
.cok-mb-l.me:not(.debut) .cok-mb-txt{ border-top-right-radius:5px; }

.cok-mb.note .cok-mb-txt{
  background:var(--cok-warn-bg,rgba(240,194,90,.10));
  border:1px solid rgba(240,194,90,.25); color:var(--cok-warn,#F0C25A);
  font-size:var(--t-meta); border-radius: var(--r-lg);
}

/* L'heure : présente, jamais insistante. */
.cok-mb-h{ margin-top:var(--e-4); font-size:var(--t-micro); line-height:var(--lh-un);
  color:var(--cok-text-3,#8b87a8); opacity:.55; font-variant-numeric:tabular-nums; }
.cok-mb-l.me .cok-mb-h{ text-align:right; }

.cok-mb-tag{ font-size:var(--t-micro); color:var(--cok-accent,var(--violet)); margin-top:var(--e-4); text-align:right; }

/* La croix « supprimer chez Vinted » : hors de la bulle, révélée au survol de la
   ligne — pas de la bulle, puisqu'elle n'en fait plus partie. */
.cok-mb-del{
  flex:0 0 auto; align-self:center;
  opacity:0; pointer-events:none; transition:opacity var(--t-bref) var(--c-pose);
  border:0; background:transparent; cursor:pointer;
  color:var(--cok-text-3,#8b87a8); font-size:var(--t-mini); line-height:var(--lh-un); padding:var(--e-4) var(--e-4);
}
.cok-mb-l:hover .cok-mb-del,
.cok-mb-del:focus-visible{ opacity:.7; pointer-events:auto; }
.cok-mb-del:hover{ opacity:1; color:var(--red); }

/* ── L'ARRIVÉE D'UN MESSAGE ─────────────────────────────────────────────────
   Inspiration : la notification iPhone. Elle ne surgit pas — elle GLISSE depuis le
   bord, s'installe, et s'arrête net. Ici chacun arrive de SON côté : l'acheteur
   depuis la gauche, nous depuis la droite. Le sens du mouvement dit qui parle avant
   même qu'on ait lu.
   ⚠️ Seuls les messages NEUFS s'animent. Rejouer sur tout le fil à chaque
   rafraîchissement, c'est le clignotement qu'on a passé la nuit à supprimer. */
@keyframes cok-arrive-g{
  from{ opacity:0; transform:translate3d(-26px,0,0) scale(.97); }
  60% { opacity:1; }
  to  { opacity:1; transform:none; }
}
@keyframes cok-arrive-d{
  from{ opacity:0; transform:translate3d(26px,0,0) scale(.97); }
  60% { opacity:1; }
  to  { opacity:1; transform:none; }
}
/* La courbe : elle décélère franchement en fin de course, comme un objet qu'on pose.
   340 ms — assez pour être vue, assez court pour ne jamais gêner la lecture. */
.cok-mb-l.neuf{ animation:cok-arrive-g var(--t-long) var(--c-pose) both; will-change:transform,opacity; }
.cok-mb-l.neuf.me{ animation-name:cok-arrive-d; }
.cok-offre-l.neuf{ animation:cok-arrive-g var(--t-long) var(--c-pose) both; }
.cok-offre-l.neuf.me{ animation-name:cok-arrive-d; }

/* Quelqu'un qui préfère moins de mouvement en a le droit. */
@media (prefers-reduced-motion: reduce){
  .cok-mb-l.neuf, .cok-offre-l.neuf{ animation:none; }
}

/* ── LE MESSAGE EN ATTENTE D'ENVOI ──────────────────────────────────────────
   Il garde son TEXTE : c'est ce qu'Amadou vient d'écrire, le cacher pour annoncer
   qu'on l'écrit serait absurde. On l'estompe, c'est tout. */
.cok-mb-l.attente .cok-mb-txt{ opacity:.55; }
.cok-mb-l.attente .cok-mb-tag{ opacity:.7; }

/* ── LA SUPPRESSION, EN DEUX TEMPS ──────────────────────────────────────────
   1. la bulle RECULE dès le clic : elle a quitté la conversation, mais elle est
      encore là — Vinted n'a pas confirmé.
   2. elle se REPLIE quand la confirmation arrive : hauteur à zéro, les bulles du
      dessous remontent. Pas de disparition sèche, pas de saut. */
.cok-mb-l.part{ opacity:.5; transform:scale(.985); transition:opacity var(--t-moyen) var(--c-pose), transform var(--t-moyen) var(--c-pose); }
.cok-mb-l.part .cok-mb-del{ display:none; }
/* Elle part à l'instant du clic. Si Vinted refuse, la classe est retirée et la bulle
   revient — c'est le seul cas où l'on dit quelque chose. */
/* ⚠️ LE DÉPART DOIT BATTRE L'ARRIVÉE.
   La règle d'arrivée porte trois classes, celle du départ n'en portait que deux :
   l'arrivée gagnait, et un message tout juste reçu ne pouvait pas s'effacer. */

/* LA POUSSIÈRE — la bulle se dissipe, elle ne part pas.
   ⚠️ POURQUOI DES TRANSITIONS ET PAS DES IMAGES-CLÉS.
   La première version animait `max-height` de 200 px vers 0 : sur une bulle haute de
   40 px, les trois quarts du trajet ne montraient RIEN, puis tout tombait d'un coup.
   Ça ne saccadait pas par hasard — la courbe était fausse. On mesure donc la vraie
   hauteur en JS, et on la fait descendre depuis SA valeur.
   Le flou reste léger : c'est l'effet le plus coûteux du lot, et 4 px suffisent. */
.cok-mb-l{ transition:height var(--t-long) var(--c-pose) var(--t-bref),
                      opacity var(--t-moyen) var(--c-pose), filter var(--t-moyen) var(--c-pose),
                      transform var(--t-long) var(--c-pose),
                      margin-top var(--t-long) var(--c-pose); }
.cok-mb-l.partie,
.cok-mb-l.partie.neuf,
.cok-mb-l.partie.neuf.me{
  /* La hauteur est pilotée en JS (le style en ligne bat la classe) — ici on ne
     touche qu'à ce qui n'a pas de valeur mesurée. */
  margin-top:0; opacity:0;
  filter:blur(4px);
  transform:translateY(-8px) scale(.95);
  overflow:hidden; pointer-events:none;
  animation:none;                      /* l'arrivée ne doit rien reprendre */
  will-change:height, opacity, transform, filter;
}}}

/* ── L'OFFRE QUI BASCULE ────────────────────────────────────────────────────
   ⚠️ La couleur d'une offre change par TRANSITION, jamais par remplacement : on doit
   voir l'ambre virer au vert, pas trouver une carte verte à la place de l'ambre.
   L'animation ne se joue qu'au moment du basculement (classe posée par le rendu) —
   sinon elle rejouerait toutes les 12 secondes. */
.cok-offre{ transition:border-color .5s var(--c-pose), background-color .5s var(--c-pose); }
.cok-offre-b, .cok-offre-h{ transition:color .5s var(--c-pose), background-color .5s var(--c-pose); }

/* ACCEPTÉE — un reflet traverse la carte une fois, comme un métal qu'on incline.
   Sobre : la DA du site ne fait pas de confettis. */
.cok-offre.ok.bascule{ position:relative; overflow:hidden; }
.cok-offre.ok.bascule::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(105deg, transparent 30%,
    color-mix(in srgb, var(--ton) 34%, transparent) 50%, transparent 70%);
  transform:translateX(-120%);
  animation:cok-reflet .62s cubic-bezier(.3,0,.2,1) var(--t-bref) 1 forwards;
}
@keyframes cok-reflet{ to{ transform:translateX(120%); } }

/* REFUSÉE — un à-coup bref (le geste du refus), puis la carte se retire : elle reste
   lisible mais n'appelle plus l'action. */
.cok-offre.ko.bascule{ animation:cok-refus var(--t-moyen) ease-in-out 2, cok-retrait .5s ease var(--t-long) forwards; }
@keyframes cok-refus{ 0%,100%{ transform:translateX(0); } 30%{ transform:translateX(-3px); } 70%{ transform:translateX(3px); } }
@keyframes cok-retrait{ to{ opacity:.7; } }

/* Le prix se BARRE : le trait se trace, il n'apparaît pas d'un coup. */
.cok-offre.ko.bascule .cok-offre-p{ position:relative; }
.cok-offre.ko.bascule .cok-offre-p::after{
  content:''; position:absolute; left:0; top:52%; height:1.5px; width:0;
  background:var(--ton); animation:cok-barre var(--t-long) ease var(--t-long) forwards;
}
@keyframes cok-barre{ to{ width:100%; } }

@media (prefers-reduced-motion: reduce){
  .cok-offre.ok.bascule::after, .cok-offre.ko.bascule{ animation:none; }
  .cok-offre.ko.bascule .cok-offre-p::after{ animation:none; width:100%; }
  .cok-mb-l.partie{ transition:none; height:0; opacity:0; }
}

/* Le nom du coloris ACTIF, à la suite du ruban de bulles. Une bulle ne se lit pas :
   deux coloris sombres sont indiscernables sans survoler l'un après l'autre. */
.dress-colors-actif {
  font-size: var(--t-base);
  color: var(--text-2);
  margin-left: var(--e-8);
  align-self: center;
  white-space: nowrap;
}

/* ── L'HORLOGERIE : l'écran de création, d'un seul tenant ─────────────────────
   Amadou (05/08) : « c'est comme une horlogerie — quand on appuie sur le bouton,
   elle se met en marche ». Le mécanisme entier est visible dès l'ouverture, à
   l'arrêt : le compte à gauche, son identité à droite. Rien n'apparaît au clic,
   tout s'allume. Deux colonnes CÔTE À CÔTE — c'est ce qu'il a demandé — et qui
   s'empilent sur écran étroit, comme partout ailleurs dans le site. */
/* ⚠️⚠️ DEUX COLONNES ÉGALES, ET LA MARGE SUR LE CONTENEUR — PAS SUR LES CARTES.
   Les deux cartes portent un `margin-top:26px` en ligne. J'annulais celui de DROITE
   (via #cp-fiche-place) et pas celui de gauche : d'où 26 px de décalage, et un
   alignement qu'aucun réglage de grille ne pouvait rattraper. Amadou l'a vu deux fois.
   On neutralise la marge des deux, on la remet sur le conteneur, et les cartes
   s'étirent à la même hauteur pour occuper l'espace. */
.cok-horlo { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:var(--e-20);
  align-items:stretch; margin-top:26px; }
.cok-horlo > *, .cok-horlo #cp-fiche-place > * { margin-top:0 !important; }
.cok-horlo > *, .cok-horlo #cp-fiche-place { display:flex; flex-direction:column; }
.cok-horlo #cp-fiche-place > * { flex:1; }
@media (max-width: 900px){ .cok-horlo { grid-template-columns:minmax(0,1fr); } }
.cok-horlo > * { min-width:0; }   /* le panneau compte est maintenant une case directe */
/* Le visage doit se JUGER, pas se deviner : 112 px etait une vignette. On lui donne
   la meme presence qu'une carte de la Bibliotheque. */
/* ── LA CARTE « SON IDENTITÉ » ─────────────────────────────────────────────────
   Amadou (06/08) : « c'est moche, l'espace n'est pas bien utilisé. La photo doit être
   en cercle et à droite le nom en plus gros, la ville et le visage pris dans la
   Sourcing. » C'est un en-tête de profil, pas un tableau de champs. */
.cok-horlo-tete { display:flex; align-items:center; gap:var(--e-16); margin-top:var(--e-18); }
/* Le visage descend de 88 à 64 px : il reste le sujet, il cesse d'être un portrait. */
.cok-horlo-ph { width:64px; height:64px; flex:0 0 64px; border-radius:50%;
                border:1px solid var(--border); background:var(--surface);
                background-size:cover; background-position:center top;
                display:flex; align-items:center; justify-content:center; }
.cok-horlo-ph span { font-size:var(--t-meta); color:var(--text-3); }
.cok-horlo-qui { min-width:0; }
.cok-horlo-nom { font-size:var(--t-lead); font-weight:var(--fw-fort); line-height:var(--lh-titre); }
.cok-horlo-nom.vide { color:var(--text-3); font-weight:var(--fw-normal); }
.cok-horlo-sous { font-size:var(--t-base); color:var(--text-2); margin-top:var(--e-4); }

.cok-horlo-k { font-size:var(--t-mini); color:var(--text-3); margin-top:var(--e-12); letter-spacing:.2px; }
.cok-horlo-k:first-child { margin-top:0; }
.cok-horlo-tete + .cok-horlo-k { margin-top:var(--e-20); }
.cok-horlo-vide { font-size:var(--t-meta); color:var(--text-3); opacity:.7; }
/* ⚠️ Même défaut, même correctif : la bio de la carte « Son identité » aplatissait ses
   paragraphes. Le pli à trois lignes ci-dessous continue de fonctionner — il compte des
   LIGNES affichées, et une ligne vide en est une. */
.cok-horlo-bio { margin-top:var(--e-6); border:1px solid var(--border); border-radius: var(--r-sm);
  padding:var(--e-10) var(--e-12); font-size:var(--t-base); line-height:var(--lh-aere); background:var(--cok-bg-2);
  min-height:64px; white-space: pre-wrap; }

/* ══ SA DESCRIPTION SE REPLIE ═════════════════════════════════════════════════
   Amadou (20/08) : « la description doit être dépliable pour gagner de la place ».
   Elle fait souvent 300 à 450 caractères et poussait le reste de la carte hors de
   l'écran. Trois lignes visibles, le reste à un clic. En dessous du seuil, aucun
   bouton n'est écrit : un « voir plus » sur un texte déjà entier est du bruit. */
.cok-horlo-bio.repliable { display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 3; overflow: hidden; }
.cok-horlo-bio.repliable.deplie { display: block; -webkit-line-clamp: none;
  overflow: visible; }
.cok-horlo-plus { display: flex; align-items: center; gap: var(--e-6);
  margin-top: var(--e-6); padding: var(--e-4) 0; border: 0; background: none;
  color: var(--cok-text-3); font: inherit; font-size: var(--t-meta); cursor: pointer;
  transition: color var(--t-bref) var(--c-pose); }
.cok-horlo-plus:hover { color: var(--th-accent-clair); }
.cok-horlo-plus svg { transition: transform var(--t-moyen) var(--c-pose); }
.cok-horlo-plus.ouvert svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .cok-horlo-plus svg { transition: none; } }
.cok-horlo-note { margin-top:var(--e-12); border:1px solid var(--border); border-radius: var(--r-sm);
  padding:var(--e-10) var(--e-12); font-size:var(--t-meta); line-height:var(--lh-normal); color:var(--text-2);
  background:var(--cok-bg-2); }

/* ── LE SUIVI D'UNE CRÉATION : L'ÉCRAN ET LE FIL ───────────────────────────────
   Amadou (06/08) : « dans la partie de gauche, on doit voir un écran, avec ce qui se
   passe en cours, et une partie chat où on voit ce qu'il y a dessus. »
   ⚠️ RIEN D'INVENTÉ ICI. L'écran est `.mdl-ecran` (barre de titre monospace + pastille)
   et le fil est `.cok-feed` — les deux existent déjà sur la fiche vendeuse, où l'écran
   promet depuis des jours « l'image de son écran arrivera ici ». On ne fait que les
   marier dans l'écran Créer. Ces quelques règles ne sont que la couture. */
.cok-crea-zone { display:block; padding:0; background:none; border:0; margin:var(--e-14) 0 0; }
.cok-crea-fil  { margin-top:var(--e-10); }
/* Une ligne pâle = déjà passée, ou pas encore arrivée. La dernière reste en clair :
   c'est celle qu'on lit, et elle doit se distinguer sans qu'on la cherche. */
.cok-crea-fil .row.att { color:var(--cok-text-3); }
.cok-crea-fil .row b   { font-weight:var(--fw-moyen); color:var(--cok-text-2); }
.cok-crea-fil .row.att b { color:var(--cok-text-3); }
.cok-crea-fait { width:100%; justify-content:center; margin-top:var(--e-10); }
/* La sortie de secours. Elle n'apparaît qu'au bout de cinq minutes d'attente, quand
   ni l'extension ni le filet n'ont conclu — donc quelque chose est cassé. Elle se
   présente comme un avertissement, PAS comme l'étape suivante : le geste normal est
   qu'Amadou n'ait rien à faire. */
.cok-crea-secours { margin-top:var(--e-12); padding:var(--e-10) var(--e-12); border-radius:var(--r-md);
  border:1px solid var(--cok-line); background:var(--cok-bg-2); }
.cok-crea-secours-txt { font-size:var(--t-meta); color:var(--cok-text-3); margin-bottom:var(--e-8); }
.cok-crea-secours .cok-crea-fait { margin-top:0; }
/* La pastille de l'écran RESPIRE quand ça tourne : c'est le seul signal qui dit
   « ne fais rien, ça avance » — avant, un bandeau orange figé disait la même chose
   qu'on attende un geste d'Amadou ou pas. */
.mdl-ecran-pt.on { animation:cok-crea-bat 1.6s ease-in-out infinite; }
@keyframes cok-crea-bat { 0%,100%{ opacity:.35; } 50%{ opacity:1; } }
@media (prefers-reduced-motion: reduce){ .mdl-ecran-pt.on{ animation:none; } }
@media (max-width: 640px){
  .cok-crea-fil .row { align-items:flex-start; }
}
/* Les trois vues de la modèle, sous sa photo de profil. Amadou : « pour vraiment se
   situer ». Format des annonces (3/4), en ligne, elles se partagent la largeur. */
/* ⚠️⚠️ LES TROIS VUES SONT UN REPÈRE, PAS UNE GALERIE. Amadou (20/08) : « les vues de
   la modèle beaucoup plus petites. En fait, tout doit être aligné. Il faut que ça prenne
   moins de place. » En pleine largeur elles faisaient ~240 px de haut chacune et
   poussaient la description hors de l'écran : trois grandes photos pour dire une chose
   qu'une vignette dit aussi bien — de quoi elle a l'air en pied.
   Elles se calent maintenant sur la largeur de la pastille du visage, à gauche : le
   visage, le nom et les vues partagent le même bord. */
/* À DROITE DU NOM, séparées par un trait. Le trait n'est pas décoratif : il dit que ce
   sont deux informations de nature différente — qui elle est, et de quoi elle a l'air. */
.cok-horlo-vues { display:flex; gap:var(--e-6); margin-top:0;
  margin-left:auto; padding-left:var(--e-16);
  border-left:1px solid var(--border); flex:0 0 auto; }
.cok-horlo-vues span { flex:0 0 var(--e-40); width:var(--e-40); }
/* L'en-tête devient la ligne complète : visage · nom/ville · | · les trois vues. */
.cok-horlo-tete { flex-wrap:wrap; }

/* ══ SA FICHE SE PEINT ═══════════════════════════════════════════════════════
   Amadou (20/08) : « la partie de droite doit apparaître comme de la peinture ».
   Le contenu se dévoile de GAUCHE À DROITE, bloc après bloc, au lieu de surgir
   entier à la milliseconde où la vendeuse est choisie.
   ⚠️ C'est une SCÈNE, pas une transition d'interface : elle a donc sa propre durée,
   comme la pastille qui respire et le reflet (voir CLAUDE.md). Elle emprunte en
   revanche la courbe d'ENTRÉE du site — `--c-pose` — parce que c'est bien une
   entrée. (Le rideau d'ouverture avait tourné sur la mauvaise courbe et dévoilait
   76 % de l'écran en 180 ms : une entrée sur une courbe de sortie se lit comme un
   sursaut, pas comme une apparition.)
   ⚠️ Le balayage se fait au `clip-path`, sans aucune couleur : un masque coloré
   aurait posé un noir en dur dans la feuille, et il aurait fallu l'écrire seize fois. */
@keyframes cok-peinture {
  0%   { clip-path: inset(0 100% 0 0); opacity: 0; }
  55%  { opacity: 1; }
  100% { clip-path: inset(0 0 0 0);    opacity: 1; }
}
.cok-horlo-peint .cok-horlo-tete,
.cok-horlo-peint .cok-horlo-vues,
.cok-horlo-peint .cok-horlo-k,
.cok-horlo-peint .cok-horlo-bio {
  animation: cok-peinture var(--peint-duree) var(--c-pose) both;
}
/* Le pinceau descend : chaque bloc part un peu après le précédent. Les retards sont
   des fractions de la durée, pas des nombres posés à la main. */
.cok-horlo-peint .cok-horlo-tete { animation-delay: 0s; }
.cok-horlo-peint .cok-horlo-vues { animation-delay: var(--peint-pas); }
.cok-horlo-peint .cok-horlo-k    { animation-delay: calc(var(--peint-pas) * 2); }
.cok-horlo-peint .cok-horlo-bio  { animation-delay: calc(var(--peint-pas) * 3); }
/* Le visage arrive avec sa propre pose : il est le sujet, il ne balaie pas. */
.cok-horlo-peint .cok-horlo-ph { animation: cok-peinture-visage var(--peint-duree) var(--c-pose) both; }
@keyframes cok-peinture-visage {
  0%   { opacity: 0; transform: scale(.88); }
  100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cok-horlo-peint .cok-horlo-tete, .cok-horlo-peint .cok-horlo-vues,
  .cok-horlo-peint .cok-horlo-k, .cok-horlo-peint .cok-horlo-bio,
  .cok-horlo-peint .cok-horlo-ph { animation: none; }
}
.cok-horlo-vues span { display:block; aspect-ratio:3/4; border-radius: var(--r-sm);
                       border:1px solid var(--border); background:var(--surface);
                       background-size:cover; background-position:center top; }

/* L'image du VDS, en direct. Le corps de l'écran perd son centrage et sa hauteur
   minimale : l'image commande, et elle garde ses proportions. */
.mdl-ecran-corps.direct { min-height:0; padding:0; display:block; }
.mdl-ecran-corps.direct img { display:block; width:100%; height:auto; }

/* Le bouton ne colle plus au fil : il termine la colonne, il ne la continue pas. */
#cp-compte-etat + .cok-launch-btn { margin-top:var(--e-16); }

/* ── LA COLONNE DE DROITE REMPLIT SA HAUTEUR ───────────────────────────────────
   Amadou (06/08) : « la partie droite doit être mieux utilisée au niveau de l'espace ».
   Les deux cartes font la même hauteur (la grille les étire), mais celle de droite
   s'arrêtait à mi-chemin et laissait un grand vide sous la description.
   On l'étire donc pour de vrai : le visage prend plus de place, et la description
   occupe tout ce qui reste jusqu'en bas. */
#cp-horlo-id { display:flex; flex-direction:column; }
.cok-horlo-k  { margin-top:var(--e-14); }
/* `flex:1` sur la description : c'est elle qui absorbe le vide, pas une marge. */
.cok-horlo-bio { flex:1; min-height:86px; display:flex; align-items:flex-start; }
/* Sous 900 px les colonnes s'empilent : plus de hauteur à égaliser, on relâche. */
@media (max-width: 900px){
  #cp-horlo-id { display:block; }
  .cok-horlo-bio { min-height:64px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   LE SURVOL — quatre familles, quatre gestes, et pas un de plus.
   ⚠️ Un site répond de la même façon partout, mais pas avec le même geste selon
   ce qu'on touche : une LIGNE dans une liste n'est pas une CARTE, et une carte
   n'est pas un BOUTON. Le geste doit dire ce que l'objet est.
   ⚠️ Tout passe par la même durée et la même courbe que le reste du socle :
   c'est ce qui fait qu'on ne remarque pas les transitions individuellement, mais
   qu'on trouve le tout « fluide ».
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Les LIGNES : elles s'éclairent et se signalent à gauche. Pas de mouvement —
   dans une liste de cinquante lignes, un déplacement au survol fait vibrer tout
   l'écran dès qu'on traverse la page avec la souris. */
/* ⚠️ `.lib-list-row` n'existe nulle part dans le site : la règle visait une classe
   fantôme, donc un tiers de ce sélecteur ne servait à rien. Retirée plutôt que
   corrigée — la Bibliothèque n'a pas de vue en liste. */
.cmd-ord, .wh-row, .cok-list > * {
  transition: background-color var(--t-bref) var(--c-pose),
              box-shadow       var(--t-bref) var(--c-pose);
}
.cmd-ord:hover, .wh-row:hover {
  background: var(--bg-sidebar);
  box-shadow: inset 3px 0 0 -1px var(--violet-soft, #8B78FF);
}

/* ── Les CARTES : elles se soulèvent. Une carte est un objet posé ; qu'elle
   décolle légèrement dit qu'on peut la prendre. 2 px suffisent — au-delà, la
   grille entière semble bouger. */
.cmd-counter, .cok-card, .mod-carte, .cmd-cart-row {
  transition: transform  var(--t-bref) var(--c-pose),
              box-shadow var(--t-bref) var(--c-pose),
              border-color var(--t-bref) var(--c-pose),
              background-color var(--t-bref) var(--c-pose);
}
/* ⚠️⚠️ CETTE RÈGLE NE VISE QUE LES CARTES QUI N'AVAIENT RIEN. En y mettant `.lib-card`
   et `.cok-metric`, j'ai ÉCRASÉ des survols déjà travaillés : la carte de la
   Bibliothèque se soulevait de 3 px avec une ombre violette large — l'écran qu'Amadou
   cite en exemple — et je l'ai remplacée par 2 px et une ombre noire quelconque. Les
   métriques du Cockpit avaient une bordure bleutée, à laquelle j'ai ajouté une ombre que
   personne n'avait demandée.
   Uniformiser, ce n'est pas passer le même rouleau partout : c'est donner un geste à ce
   qui n'en avait pas, et respecter ce qui en avait déjà un. */
.cmd-counter:hover, .cok-card:hover, .cmd-cart-row:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 18px rgba(var(--th-ombre),0.28);
}
/* ⚠️ Une carte déjà choisie ne se soulève pas : elle est posée, c'est son état.
   La soulever au survol ferait douter de ce qui est sélectionné. */
.cmd-counter.active:hover { transform: none; }

/* ── Les IMAGES : elles s'approchent. Le cadre garde sa forme, l'image grandit
   dedans — c'est le geste qui donne envie de regarder une photo de plus près. */
.cmd-th, .lib-card-cover, .mod-vign, .wh-row .cmd-th { overflow: hidden; }
.cmd-th img, .lib-card-cover img, .mod-vign img {
  transition: transform var(--t-long) var(--c-pose);
}
.cmd-ord:hover .cmd-th img, .lib-card:hover .lib-card-cover img,
.wh-row:hover .cmd-th img, .mod-carte:hover .mod-vign img {
  transform: scale(1.06);
}

/* ── Les ONGLETS et la NAVIGATION : le fond se pose derrière le mot. Aucun
   déplacement : une barre d'onglets qui bouge au survol donne le sentiment que
   la page n'est pas stable. */
/* ⚠️⚠️ EXCLURE L'ONGLET ACTIF, SINON LE SURVOL L'EFFACE. Cette règle est écrite APRÈS
   celle de l'état actif et pèse le même poids : au survol, `background` — le RACCOURCI —
   remet `background-image` à `none` et emporte le dégradé violet→bleu de l'onglet
   sélectionné. Il ne restait qu'un aplat translucide, qui sur ce fond se lit GRIS.
   Amadou (09/08) : « les boutons buguent et deviennent gris ».
   ⚠️ Vérifié : c'est le SEUL cas réel du fichier. Les trois autres candidats trouvés par
   la recherche sont des règles DESCENDANTES (`.x:hover .y`), qui n'entrent pas en conflit,
   et le survol des étoiles de notation, où l'aperçu au survol est voulu. */
.nav-item:hover:not(.on):not(.active),
.an-so:not(.on):not(.active):hover,
.cok-cmd-stab:not(.on):not(.active):hover,
.cok-chip:not(.on):not(.active):hover {
  background: var(--survol-fond);
}

/* ══════════════════════════════════════════════════════════════════════════
   LA PLACE EST RÉSERVÉE AVANT QUE LE CONTENU ARRIVE
   ⚠️⚠️ CE N'ÉTAIT PAS UNE ANIMATION. Amadou : « la vigie, ce qui est en dessous
   se relève puis ça baisse » — sur Contrôle, Vue d'ensemble, Vendeuses et
   Génération. Ces conteneurs sont VIDES dans le HTML et se remplissent par le
   code une fois l'écran affiché : ils passent donc de zéro à leur vraie hauteur
   sous les yeux, et poussent tout ce qui les suit. Aucune animation en cause —
   c'est la page qui se réorganise.
   On leur réserve une hauteur TANT QU'ILS SONT VIDES. Dès qu'ils se remplissent,
   `:empty` cesse de s'appliquer et la hauteur redevient naturelle : rien ne
   saute, et aucun vide ne subsiste ensuite.
   ⚠️ Des valeurs MODESTES, volontairement : mieux vaut un petit reste de
   mouvement qu'un grand vide permanent quand la liste est courte.
   ══════════════════════════════════════════════════════════════════════════ */
.cok-list:empty,
#cok-cp-content:empty,
#cok-rz-content:empty,
#cok-cmd-content:empty,
#cok-vigie:empty,
#commandes-list:empty,
.cok-metrics:empty { min-height: 120px; }

/* Les grilles de cartes réservent davantage : elles portent toujours plusieurs
   lignes, et c'est là que le décalage se voit le plus. */
#cok-ov-grid:empty, .cok-cards:empty, .lib-grid:empty { min-height: 220px; }

/* ⚠️ Et pendant qu'ils sont vides, ils ne montrent RIEN — ni bordure ni fond.
   Une boîte vide dessinée serait pire que le décalage : on croirait à un bloc
   qui n'a pas chargé. */
.cok-list:empty, .cok-metrics:empty, #cok-ov-grid:empty,
.cok-cards:empty, .lib-grid:empty { border: 0; background: none; }

/* ══════════════════════════════════════════════════════════════════════════
   L'ÉDITEUR DE COULEUR — un seul écran, toutes les couleurs
   Amadou (07/08) : « la sélection est trop pauvre, je dois avoir toutes les couleurs
   possibles, il y avait un curseur ».
   ⚠️ Il tient dans 216 px de large : c'est un réglage, pas une fenêtre. Posé au-dessus
   de la bulle, il ne doit jamais couvrir la rangée de coloris qu'on est en train de
   regarder — d'où la largeur contrainte autant que la hauteur.
   ══════════════════════════════════════════════════════════════════════════ */
.velbo-palette {
  position: fixed;
  z-index: 10000;
  width: 216px;
  padding: var(--e-12);
  border-radius: var(--r-lg);
  border: 1px solid var(--border-mid);
  background: rgba(var(--th-panneau-rgb),0.97);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 18px 44px rgba(var(--th-ombre),.55);
  animation: velbo-menu var(--t-moyen) var(--c-pose) both;
}
.velbo-pal-tete {
  font-size: var(--t-meta); font-weight: var(--fw-fort);
  color: var(--text-2);
  letter-spacing: var(--ls-leger);
  margin-bottom: var(--e-10);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Les teintes de CE coloris ───────────────────────────────────────────────
   En haut, avant le réglage : on voit d'abord ce qu'on modifie, on règle ensuite. */
.velbo-pal-teintes { display: flex; align-items: center; gap: var(--e-6); margin-bottom: var(--e-10); }
.velbo-pal-teinte {
  width: 24px; height: 24px; flex: 0 0 auto;
  padding: 0; border-radius: 50%;
  border: 1px solid rgba(var(--th-voile),0.18);
  cursor: pointer;
}
/* Celle qu'on règle porte l'anneau violet — sans lui, régler la seconde teinte d'une
   robe bicolore se fait à l'aveugle. */
.velbo-pal-teinte.on {
  box-shadow: 0 0 0 2px rgba(var(--th-panneau-rgb),0.97), 0 0 0 4px var(--violet, var(--violet-soft));
}
.velbo-pal-plus {
  width: 24px; height: 24px; flex: 0 0 auto;
  padding: 0; border-radius: 50%;
  border: 1px dashed rgba(var(--th-voile),0.28);
  background: transparent;
  color: var(--text-3);
  font-size: var(--t-small); line-height: var(--lh-un);
  cursor: pointer;
}
.velbo-pal-plus:hover { color: var(--violet-light); border-color: var(--violet-soft); }

/* ── Le carré : saturation en X, luminosité en Y ─────────────────────────────
   Le fond est posé en JS (il dépend de la teinte courante). */
.velbo-pal-carre {
  position: relative;
  height: 132px;
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-voile),0.12);
  cursor: crosshair;
  touch-action: none;          /* sans ça, glisser sur mobile fait défiler la page */
}
.velbo-pal-carre:focus-visible { outline: 2px solid var(--violet, var(--violet-soft)); outline-offset: 2px; }
.velbo-pal-viseur {
  position: absolute;
  width: 14px; height: 14px;
  margin: calc(var(--e-8) * -1) 0 0 calc(var(--e-8) * -1);       /* le viseur est CENTRÉ sur le point visé, pas à côté */
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px rgba(var(--th-ombre),.45), 0 1px 4px rgba(var(--th-ombre),.5);
  pointer-events: none;        /* il ne doit jamais intercepter le glissement */
}

/* ── Le curseur de teinte : tout le spectre ──────────────────────────────────
   ⚠️ Pas un `<input type="range">` : son curseur se style par des pseudo-éléments
   propres à chaque navigateur, et il aurait fallu redessiner le même objet trois fois
   pour qu'il ressemble au carré juste au-dessus. Le rail est donc le même objet que le
   carré — même bordure, même viseur, même geste. */
.velbo-pal-rail {
  position: relative;
  height: 12px;
  margin-top: var(--e-10);
  border-radius: var(--r-pilule);
  border: 1px solid rgba(var(--th-voile),0.12);
  cursor: ew-resize;
  touch-action: none;
  background: linear-gradient(to right,
    #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%);
}
.velbo-pal-rail:focus-visible { outline: 2px solid var(--violet, var(--violet-soft)); outline-offset: 2px; }
.velbo-pal-poucet {
  position: absolute;
  top: 50%;
  width: 14px; height: 14px;
  /* ⚠️ Pas de marge négative ici, contrairement au viseur du carré : le rail fait 12 px
     de haut pour un curseur de 14, donc un curseur centré sur sa valeur déborderait de
     moitié au rouge de gauche comme au rouge de droite — les deux extrémités du spectre,
     celles qu'on vise le plus. Le JS le pose dans `calc(ratio * (100% - 14px))`, ce qui
     le garde entier dans le rail. */
  margin: calc(var(--e-8) * -1) 0 0 0;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px rgba(var(--th-ombre),.45), 0 1px 4px rgba(var(--th-ombre),.5);
  pointer-events: none;
}

/* ── Le code exact, et le retrait d'une teinte ───────────────────────────────── */
.velbo-palette-libre { display: flex; gap: var(--e-6); margin-top: var(--e-12); }
.velbo-palette-champ {
  flex: 1; min-width: 0;
  padding: var(--e-6) var(--e-10);
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-voile),0.14);
  background: var(--bg-hover);
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-base);
}
.velbo-palette-champ:focus { outline: none; border-color: var(--accent); }
/* Une teinte invalide se signale sans bloquer : le champ rougit une seconde. */
.velbo-palette-champ.faux { border-color: var(--red); background: rgba(var(--th-danger-rgb),0.10); }
.velbo-pal-retirer {
  flex: 0 0 auto;
  padding: var(--e-6) var(--e-10);
  border-radius: var(--r-sm);
  border: 1px solid rgba(var(--th-voile),0.14);
  background: var(--bg-hover);
  color: var(--text-2);
  font-family: inherit; font-size: var(--t-meta); font-weight: var(--fw-fort);
  cursor: pointer;
}
.velbo-pal-retirer:hover:not(:disabled) {
  border-color: rgba(var(--th-danger-rgb),0.5); background: var(--danger-fond); color: var(--ose-text);
}
/* ⚠️ Grisé, pas caché : un bouton qui disparaît fait douter de l'avoir rêvé. Il redevient
   actif dès qu'il y a une seconde teinte à retirer. */
.velbo-pal-retirer:disabled { opacity: .35; cursor: default; }

/* ── Les vingt-quatre raccourcis ─────────────────────────────────────────────
   Plus petits que les teintes du coloris : ce sont des propositions, pas l'objet réglé. */
.velbo-palette-grille {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--e-6);
  margin-top: var(--e-12);
  padding-top: var(--e-12);
  border-top: 1px solid rgba(var(--th-voile),0.08);
}
.velbo-teinte {
  width: 100%; aspect-ratio: 1;
  border-radius: 50%;
  border: 1px solid rgba(var(--th-voile),0.16);
  cursor: pointer;
  padding: 0;
}
.velbo-teinte:hover { transform: scale(1.14); border-color: rgba(var(--th-voile),0.5); }
.velbo-teinte.on { box-shadow: 0 0 0 2px rgba(var(--th-panneau-rgb),0.97), 0 0 0 4px var(--violet, var(--violet-soft)); }

/* ── LES SPÉCIALES : multicolore, argenté, doré ─────────────────────────────
   Ce ne sont pas des teintes : on ne les règle pas au curseur, et un clic pose
   le NOM du coloris. Elles ne peuvent donc pas se mélanger aux 24 aplats sans
   mentir sur ce qu'elles font — d'où leur rangée à part, sous son propre titre.
   ⚠️ Le titre n'est pas décoratif : le multicolore EXISTAIT déjà et ne se
   trouvait pas, parce qu'il fallait taper le mot dans le nom du coloris.
   Même grille à 6 colonnes que les aplats : les pastilles gardent exactement la
   même taille et le même alignement, seule leur ligne change. */
.velbo-palette-speciales {
  margin-top: var(--e-12);
  padding-top: var(--e-12);
  border-top: 1px solid rgba(var(--th-voile),0.08);
}
.velbo-palette-speciales-titre {
  display: block;
  font-size: var(--t-micro);
  font-weight: var(--fw-fort);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: var(--e-8);
}
.velbo-palette-speciales-rangee {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--e-6);
}
/* Anneau un peu plus marqué : un métal clair posé sur un panneau clair perdrait
   son contour sans lui. */
.velbo-teinte--speciale { border-color: rgba(var(--th-voile),0.3); }

/* ══════════════════════════════════════════════════════════════════════════
   L'APPLICATION ARRIVE — elle ne se contentait pas d'être découverte
   Amadou (08/08) : « le site doit apparaître d'une manière douce, là c'est trop
   brusque, ça casse cet effet ».
   ⚠️ Rien n'accueillait l'application derrière le rideau. Sa seule animation
   d'entrée (`velbo-pose`) s'était jouée DERRIÈRE le rideau, environ deux secondes
   plus tôt : au moment où le noir s'en va, l'interface est figée depuis longtemps.
   Le rideau se levait donc sur une image immobile.

   ⚠️⚠️ OPACITÉ SEULE, JAMAIS DE `transform` / `scale` / `filter` ICI. Le dépôt s'est
   brûlé DEUX FOIS là-dessus : ces propriétés créent une nouvelle référence de
   positionnement, et tout `position: fixed` à l'intérieur se recale dessus — 126 px
   de décalage mesurés, sur `.dress-color-menu`, `.lib-picker`, `.velbo-palette`…
   L'opacité, elle, ne crée aucune référence : elle est sûre sur un ancêtre de l'app.

   ⚠️ Le fond monte plus LENTEMENT que l'interface : c'est ce décalage qui donne la
   profondeur, sans qu'aucun élément ne bouge d'un pixel.
   ⚠️ `both` obligatoire — dans un onglet en arrière-plan les animations gèlent, et
   avec `none` l'écran resterait à opacité 0 (le cas est déjà documenté plus haut).
   ══════════════════════════════════════════════════════════════════════════ */
@keyframes velbo-site-arrive { from { opacity: 0; } to { opacity: 1; } }

/* ⚠️⚠️ ON N'ANIME PAS `.app-shell` ET SES ENFANTS : deux fondus imbriqués multiplient
   leurs opacités (0,5 × 0,5 = 0,25) et l'écran reste sombre bien plus longtemps que
   prévu. Le squelette ne bouge donc pas ; ce sont ses trois zones qui montent, chacune
   un peu après l'autre. C'est ce décalage qui fait la profondeur — sans qu'un seul
   élément ne se déplace d'un pixel.
   ⚠️ Plus vite que le voile ne part : si une zone montait moins vite que le rideau ne
   s'ouvre, on verrait du noir par la déchirure. */
/* ⚠️ La courbe d'arrivée propre au « fond espace » a été retirée avec lui (14/08) :
   plus aucun porteur. Les trois autres zones vivent à 1 au repos, leur animation est
   juste telle quelle. */
  to   { opacity: var(--space-bg-opacite); }
}
body.velbo-site-arrive .sidebar,
body.velbo-site-arrive .mobile-hamburger {
  animation: velbo-site-arrive .5s var(--c-pose) .12s both;
}
body.velbo-site-arrive .app-content {
  animation: velbo-site-arrive .5s var(--c-pose) .24s both;
}
@media (prefers-reduced-motion: reduce) {
  body.velbo-site-arrive .sidebar,
  body.velbo-site-arrive .mobile-hamburger,
  body.velbo-site-arrive .app-content { animation: none; }
}

/* ⚠️ `.cok-rz-vieux` retirée avec les deux bandeaux orange qu'elle habillait (09/08) :
   plus aucun porteur dans app.js ni index.html. */

/* La carte de formation qu'on peut ouvrir pour voir son écran (Amadou, 08/08 : « dans
   l'onglet formation, quand j'appuie sur un compte, je dois pouvoir voir son écran »).
   Rien de neuf dessiné : juste le curseur et un survol qui dit qu'elle répond, comme
   les autres surfaces cliquables du site. */
.form-carte.cliquable { cursor: pointer; }
.form-carte.cliquable:hover { border-color: var(--violet); }

/* La vignette produit peut être une vraie image (historique des ventes) ou un carré
   vide (vente sans photo). Les deux doivent occuper exactement la même place, sinon
   les lignes du tableau ne s'alignent plus entre elles. */
img.cok-cmd-thumb { object-fit: cover; display: inline-block; }

/* ── L'ATTENTE ANIMÉE, POUR TOUS LES ÉCRANS ──────────────────────────────────
   Amadou, 08/08 : « lorsque ça se connecte, ça fasse une animation, parce que là ça
   met juste un texte. Et c'est comme ça pour tous les écrans. »
   Il y avait bien `velbo-attend`, mais il ne fait respirer que l'OPACITÉ du bloc — et
   ce bloc ne contenait qu'un mot. Un texte qui s'éclaircit puis s'assombrit ne dit pas
   « je travaille », il dit « je clignote ». Trois points qui se lèvent l'un après
   l'autre, si : l'œil lit un mouvement qui avance, pas une pulsation.
   Rien d'inventé : le violet de la DA, la même taille de texte que les sous-titres. */
.velbo-charge {
  display: flex; align-items: center; gap: var(--e-10);
  padding: var(--e-16) 0;
  color: var(--cok-text-3);
  font-size: var(--t-meta);
}
.velbo-charge-pts { display: inline-flex; gap: var(--e-4); align-items: center; }
.velbo-charge-pts i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--violet);
  opacity: .28;
  animation: velbo-point 1.15s ease-in-out infinite;
}
.velbo-charge-pts i:nth-child(2) { animation-delay: .14s; }
.velbo-charge-pts i:nth-child(3) { animation-delay: .28s; }
@keyframes velbo-point {
  0%, 100% { opacity: .28; transform: translateY(0); }
  50%      { opacity: 1;   transform: translateY(-3px); }
}
/* ⚠️ Un bloc en attente porte DÉJÀ `velbo-attend` (respiration d'opacité) : sans ça,
   les points battraient sous un parent qui bat aussi, et les deux se contrarient. */
.velbo-attend .velbo-charge-pts i { animation-duration: 1.4s; }
@media (prefers-reduced-motion: reduce) {
  .velbo-charge-pts i { animation: none; opacity: .6; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PRODUCTION — la chaîne, pas le formulaire
   Amadou (08/08) : l'écran « devrait être la Génération mais en automatique »,
   et il est « vraiment mal fait ». Le défaut de fond n'était pas l'habillage :
   l'écran montrait COMBIEN d'annonces étaient faites, jamais OÙ elles en étaient,
   et un lot terminé n'avait aucune porte de sortie.
   ══════════════════════════════════════════════════════════════════════════ */
.an-bandeau {
  background: var(--cok-card); border: 1px solid var(--cok-border);
  border-radius: var(--r-carte); padding: var(--e-16) var(--e-18); margin-bottom: var(--e-12);
}
.an-bandeau-h { display: flex; align-items: center; gap: var(--e-12); margin-bottom: var(--e-14); }
.an-etat { font-size: var(--t-small); color: var(--cok-text-2); display: inline-flex; align-items: center; gap: var(--e-10); }
/* La pastille ne bat QUE pendant la fabrication : un point qui clignote en
   permanence cesse d'être un signal. */
.an-etat.on::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--cok-green); animation: an-bat 1.6s ease-in-out infinite;
}
.an-etat.on { color: var(--cok-text); }
@keyframes an-bat { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .an-etat.on::before { animation: none; } }

.an-chiffres { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--e-10); }
.an-chi { background: var(--cok-accent-bg); border-radius: var(--r-md); padding: var(--e-10) var(--e-14); }
.an-chi .l { font-size: var(--t-meta); color: var(--cok-text-2); margin-bottom: var(--e-4); }
.an-chi .v { font-size: var(--t-title); font-weight: var(--fw-fort); line-height: var(--lh-titre); }

/* ── La chaîne ──────────────────────────────────────────────────────────────
   ⚠️ Elle défile horizontalement au lieu de se comprimer : sept postes écrasés
   dans 700 px deviennent sept nombres illisibles, et c'est justement l'écran
   qu'on regarde en diagonale pendant que ça tourne. */
.an-chaine {
  background: var(--cok-card); border: 1px solid var(--cok-border);
  border-radius: var(--r-carte); padding: var(--e-14) var(--e-18); margin-bottom: var(--e-12);
}
.an-chaine-t { font-size: var(--t-base); color: var(--cok-text-2); margin-bottom: var(--e-12); }
.an-chaine-r { display: flex; gap: var(--e-6); overflow-x: auto; padding-bottom: var(--e-2); }
.an-cha {
  flex: 1 0 78px; background: var(--cok-accent-bg);
  border-radius: var(--r-md); padding: var(--e-10) var(--e-12); min-width: 0;
}
.an-cha b { display: block; font-size: var(--t-lead); font-weight: var(--fw-fort); line-height: var(--lh-titre); color: var(--cok-text-3); }
.an-cha i {
  display: block; font-style: normal; font-size: var(--t-meta); color: var(--cok-text-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Un poste vide reste gris : seuls ceux qui portent quelque chose s'allument. */
.an-cha.on b { color: var(--cok-accent); }
.an-cha.on i { color: var(--cok-text-2); }

/* ── La sortie ──────────────────────────────────────────────────────────────
   Le seul vrai ajout de mécanique de cet écran. Elle porte un liseré vert :
   c'est l'endroit où le travail sort, il doit se trouver sans être cherché. */
.an-sortie-b {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-16);
  flex-wrap: wrap;
  background: var(--cok-card); border: 1px solid var(--cok-green);
  border-radius: var(--r-carte); padding: var(--e-16) var(--e-18); margin-bottom: var(--e-12);
}
.an-sortie-t { font-size: var(--t-small); color: var(--cok-text); }
.an-sortie-s { font-size: var(--t-base); color: var(--cok-text-2); margin-top: var(--e-4); max-width: 62ch; }

@media (max-width: 760px) {
  .an-chiffres { grid-template-columns: repeat(2, 1fr); }
  .an-sortie-b { flex-direction: column; align-items: stretch; }
}

/* Le compte porté par la carte, en vue « Toutes » (Amadou, 08/08 : c'est là qu'il
   planifie les publications de toute la flotte). Discret : c'est un repère, pas le
   titre — l'annonce reste ce qu'on lit en premier. */
.dcard-qui {
  font-size: var(--t-micro); letter-spacing: var(--ls-leger);
  color: var(--violet-soft);
  margin-bottom: var(--e-4);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* La ligne « Toutes » se détache du reste du rail : c'est une vue, pas un compte. */
/* ⚠️ Même piège que `.dcard-vinted` : hors de `.cok`, donc `--cok-line` ne se résout
   pas et le trait devient `currentColor` — blanc. C'est le liseré sous « Toutes ». */
.drafts-rail-toutes { border-bottom: 1px solid var(--border); margin-bottom: var(--e-4); padding-bottom: var(--e-8); }
.drafts-rail-toutes .dpack-av { background: var(--violet); color: var(--sur-accent); }

/* ── PRODUCTION AU REPOS ─────────────────────────────────────────────────────
   ⚠️ C'est l'écran qu'on voit 99 % du temps : sans production en cours, il n'y
   avait qu'un formulaire seul sur une page, qui ne disait rien de la boutique.
   Ce bandeau répond aux deux questions qu'on se pose en arrivant : qu'est-ce qui
   attend d'être publié, et qu'est-ce que j'ai fait la dernière fois. */
.an-repos {
  background: var(--cok-card); border: 1px solid var(--cok-border);
  border-radius: var(--r-carte); padding: var(--e-16) var(--e-18); margin-bottom: var(--e-12);
}
/* ⚠️⚠️ LA PLACE EST RÉSERVÉE TANT QU'ON N'A PAS LU. Amadou (24/08) : « il met du temps à
   apparaître parce que le site cherche des informations, sauf qu'il apparaît brusquement ».
   Le cadre seul ne suffisait pas : il faisait 75 px en lecture et 163 px une fois rempli,
   donc il poussait encore tout l'écran de 88 px — mesuré à 1512 px de large.
   160 px, c'est la hauteur MESURÉE du cas courant (titre + « N annonces attendent » +
   « Dernière production »), pas un chiffre choisi au jugé.
   ⚠️ La réserve tombe dès que c'est lu : la garder ferait un bloc à moitié vide le jour
   où il n'y a qu'une ligne à dire.
   C'est la façon de faire du site — `#ov-attend` réserve 268 px, les listes du cockpit 120. */
/* ⚠️⚠️ LA RÉSERVE EST SUR LE CADRE, PAS SUR LA ZONE. Amadou (24/08) : « je veux qu'au
   chargement la bulle fasse la taille qu'elle aura une fois remplie ».
   Elle était posée sur `.an-repos-zone` — un conteneur INVISIBLE. La place était bien
   gardée dans la page, mais le cadre qu'on VOIT, lui, gardait sa petite taille au milieu
   du vide, puis grandissait d'un coup. On réservait donc l'espace sans rien y montrer :
   le saut restait, exactement là où l'œil regarde.
   ⚠️ Et la hauteur n'est plus un chiffre choisi : `--an-repos-h` porte celle que le bloc
   a VRAIMENT eue la dernière fois (voir `_anReposPeindre`). Une valeur en dur redevient
   fausse dès qu'une ligne s'ajoute ; celle-ci suit. Le repli ne sert qu'au tout premier
   chargement, avant qu'on ait pu mesurer quoi que ce soit. */
.an-repos-zone:not(.lu) .an-repos { min-height: var(--an-repos-h, 148px); }
.an-repos-t { font-size: var(--t-base); color: var(--cok-text-2); margin-bottom: var(--e-10); }
.an-repos-l {
  display: flex; align-items: center; gap: var(--e-10);
  font-size: var(--t-small); color: var(--cok-text);
  padding: var(--e-8) 0; border-top: 1px solid var(--cok-border);
}
.an-repos-l:first-of-type { border-top: 0; padding-top: 0; }
.an-repos-l b { font-size: var(--t-lead); font-weight: var(--fw-fort); color: var(--cok-accent); }
.an-repos-l .cok-btn { margin-left: auto; }
.an-repos-ko b { color: var(--cok-red); }
/* La dernière production est un repère, pas une alerte : elle reste en retrait. */
.an-repos-d { font-size: var(--t-base); color: var(--cok-text-2); }

/* La place des trois chiffres, tant qu'il n'y a rien à compter. */
.an-les-vide {
  font-size: var(--t-base); color: var(--cok-text-2);
  background: var(--cok-accent-bg); border-radius: var(--r-md);
  padding: var(--e-12) var(--e-14); margin: var(--e-12) 0;
}

/* ── LES PAQUETS DU JOUR, DANS LES BROUILLONS ────────────────────────────────
   Amadou, 08/08 : « c'est ici qu'on va venir planifier les publications. »
   Une grille a plat repond a « qu'est-ce que j'ai ? » ; planifier demande « qu'est-ce
   qui part quand, et qu'est-ce qui n'a pas encore de date ? ». Le titre separe les
   paquets sans rien ajouter au dessin des cartes. */
.drafts-jour {
  display: flex; align-items: baseline; gap: var(--e-10);
  margin: var(--e-18) 0 var(--e-8); padding-bottom: var(--e-6);
  border-bottom: 1px solid var(--border)  /* hors .cok : voir .dcard-vinted */;
}
.drafts-jour:first-child { margin-top: var(--e-2); }
.drafts-jour-nom {
  font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--cok-text-2);
  text-transform: capitalize;
}
.drafts-jour-n { font-size: var(--t-mini); color: var(--cok-text-3); }

/* Un brouillon qui vit deja chez Vinted : on le distingue sans le deguiser. Il se
   consulte, il ne s edite pas d ici -- ses gestes rapides sont retires plutot que
   grises, parce qu un bouton gris invite quand meme a essayer. */
/* ⚠️⚠️ `var(--border)`, PAS `var(--cok-line)`. Les variables `--cok-*` sont définies
   dans `.cok` — et une carte de brouillon n'est PAS dans `.cok` (son ascendance est
   dcard-grid › drafts-detail › drafts-split › section-canvas). La variable ne se
   résolvait donc jamais ici : `color-mix` devenait invalide, et `border-color`
   retombait sur sa valeur initiale, `currentColor` — la couleur du TEXTE, quasi
   blanche. C'était le contour blanc, et il n'apparaissait QUE sur les cartes déjà
   déposées sur Vinted, d'où trois corrections à côté de la plaque.
   ⚠️ Vérifier qu'une variable existe ne suffit pas : il faut vérifier qu'elle existe
   LÀ OÙ ON S'EN SERT. */
.dcard-vinted { border-color: color-mix(in srgb, var(--violet) 34%, var(--border)); }
.dcard-status.vinted { color: var(--violet-soft); }
.dcard-status.vinted .dcard-dot { background: var(--violet); }

/* ⚠️ Le motif du blocage n'est pas une note discrète : c'est la seule chose à lire
   quand le bouton ne part pas. Sans elle, un bouton grisé se cherche longtemps. */
.an-launch2-note.an-note-ko { color: var(--amber); }

/* ── L ESPACE D UN BROUILLON QUI VIT SUR VINTED ──────────────────────────────
   Amadou, 08/08 : « c est hyper mal fait, c est decoupe, utilise bien l espace. »
   J avais mis une bordure entre chaque bloc -- en-tete, photos, champs, description,
   note, actions : six separations pour un seul panneau. Ca hache au lieu d organiser.
   Ici c est l ESPACE qui separe : plus une seule ligne horizontale.
   Et une hierarchie -- la vendeuse en petit, le titre en grand, LE PRIX en tres grand :
   c est le chiffre qui compte au moment de decider si on publie. */
/* ⚠️⚠️ IL DOIT GRANDIR AVEC L ECRAN. Amadou, 08/08 : « utilise la place que tu as.
   La tu as scrolle pour lire la description alors qu on pourrait gratter de la largeur
   et de la hauteur. Plus j agrandis mon ecran, plus le panel doit s elargir. »
   La boite de base est figee a min(880px, 95vw) : sur un grand ecran elle laissait donc
   des centaines de pixels vides de chaque cote pendant qu on lisait la description dans
   une lucarne de 190 px. On monte le plafond a 1500 px et on garde les 94vw : le
   panneau occupe l ecran quand il y en a, et se replie quand il n y en a plus. */
.dv-modal { width: min(1800px, 94vw); max-width: none; position: relative; padding: 30px 34px; }
.dv-fermer { position: absolute; top: 14px; right: 14px; }

/* La photo suit la largeur au lieu d etre figee a 260 px : sur un grand ecran elle
   gagne, sans jamais ecraser le texte ni descendre sous une taille lisible. */
/* ⚠️ RECTANGLE, PAS CARRÉ. Amadou (09/08) : « il n'est pas assez long en largeur ».
   La colonne de gauche était proportionnelle (26 %) : sur grand écran elle grandissait
   avec le panneau, qui restait donc carré. Elle est désormais FIXE — la droite prend
   tout le gain de largeur, et le panneau s'étale au lieu de s'allonger. */
.dv-corps { display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: 34px; }
.dv-gauche { position: sticky; top: 0; align-self: start; }
.dv-grande { width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  border-radius: var(--r-lg); display: block; background: var(--cok-bg-2); }
.dv-vign { display: flex; gap: var(--e-6); margin-top: var(--e-8); flex-wrap: wrap; }
.dv-vign img { width: 48px; height: 64px; object-fit: cover; border-radius: var(--r-sm);
  cursor: pointer; opacity: .55; border: 1.5px solid transparent; transition: opacity .15s; }
.dv-vign img:hover { opacity: .85; }
.dv-vign img.on { opacity: 1; border-color: var(--violet); }
.dv-sansphoto { aspect-ratio: 3 / 4; display: flex; align-items: center; justify-content: center;
  font-size: var(--t-meta); color: var(--cok-text-3); border-radius: var(--r-lg); background: var(--cok-bg-2); }

/* ⚠️ min-width: 0 -- sans lui, une colonne de grille prend la largeur de son contenu
   le plus long, et la troncature des textes (categorie, couleur) ne joue jamais. */
.dv-droite { min-width: 0; }
.dv-qui { margin: 0 0 var(--e-2); font-size: var(--t-meta); color: var(--cok-text-3); }
.dv-titre { margin: 0; font-size: var(--t-lead); font-weight: var(--fw-moyen); line-height: var(--lh-serre); color: var(--cok-text); }
.dv-prix { margin: var(--e-10) 0 0; font-size: var(--t-xl); font-weight: var(--fw-moyen); color: var(--cok-text); }

/* Deux colonnes fixes : les libelles alignes a gauche se lisent d une traite, la ou
   des colonnes automatiques donnaient des largeurs inegales selon le texte. */
/* ⚠️⚠️ UNE LIGNE PAR CHAMP, PLUS DE GRILLE. En 92px/1fr/92px/1fr, les paires
   libellé-valeur se décalaient d'une case dès qu'un élément manquait : « M » se
   retrouvait à côté d'« État ». Amadou (09/08) : « tout est mélangé ». Une ligne par
   champ ne peut pas se désaligner. */
.dv-champs { display: flex; flex-direction: column; gap: var(--e-10); margin-top: var(--e-20); }
.dv-ch { display: flex; align-items: center; gap: var(--e-14); }
.dv-l { color: var(--cok-text-3); font-size: var(--t-base); flex: 0 0 92px; }
.dv-v { color: var(--cok-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dv-v.muet { color: var(--cok-text-3); }

/* Les champs se modifient SUR PLACE : le brouillon est un état de travail, pas une
   fiche à consulter. Ils ne portent donc pas de cadre au repos — c'est au survol et
   au focus qu'ils se révèlent. */
.dv-edit { font: inherit; color: var(--cok-text); background: transparent;
  border: 1px solid transparent; border-radius: var(--r-sm); padding: var(--e-6) var(--e-10);
  transition: background var(--t-bref), border-color var(--t-bref); }
.dv-edit:hover { background: var(--cok-bg-2); border-color: var(--cok-border); }
.dv-edit:focus { outline: none; background: var(--cok-bg-2);
  border-color: var(--cok-accent); }
/* Les menus sont ceux du site (_deDropdown) : ils apportent leur propre habillage,
   on ne leur en met pas un second par-dessus. */
.dv-ddm { flex: 1; min-width: 0; }
input.dv-titre { width: 100%; margin: var(--e-2) 0 0 calc(var(--e-10) * -1); }
/* ⚠️ PAS DE « € » EN GROS À CÔTÉ DU PRIX. Amadou (09/08) : « le logo prix, tu
   m'enlèves, ce n'est pas fou. » Le signe vit dans le texte indicatif du champ. */
.dv-prixl { margin-left: calc(var(--e-10) * -1); }
.dv-prixl input { width: 7ch; }
textarea.dv-desc { width: 100%; margin-left: calc(var(--e-10) * -1); resize: vertical; line-height: var(--lh-normal); }

.dv-desc-l { display: block; margin: var(--e-20) 0 var(--e-4); }
/* ⚠️ PLUS DE LUCARNE. La description tenait dans 190 px avec sa propre barre de
   defilement -- on lisait une annonce par la fente. Elle coule desormais ; c est la
   boite entiere qui defile si vraiment il le faut, et avec la largeur gagnee ca
   n arrive quasiment plus. */
.dv-desc { margin: 0; font-size: var(--t-small); line-height: var(--lh-aere); color: var(--cok-text-2);
  white-space: pre-wrap; }

/* ⚠️⚠️ AU-DELA D UNE CERTAINE LARGEUR, LA DESCRIPTION SE MET EN DEUX COLONNES.
   Amadou veut que le panneau grandisse avec l ecran -- mais une ligne de texte de
   1 200 px ne se lit pas : l oeil perd le debut de la ligne suivante. Les deux colonnes
   utilisent VRAIMENT la largeur gagnee tout en gardant des lignes lisibles, au lieu de
   laisser du vide a droite ou d etirer le texte au-dela du confortable. */
@media (min-width: 1500px) {
  .dv-desc { column-count: 2; column-gap: var(--e-40); }
  .dv-champs { grid-template-columns: 92px minmax(0, 1fr) 92px minmax(0, 1fr); }
}

.dv-actions { display: flex; align-items: center; gap: var(--e-10); margin-top: var(--e-22); }
/* Le numéro d'annonce est une référence, pas une action : il se range à l'opposé des
   boutons plutôt que de leur coller au bout. En dessous de 520 px les deux boutons
   passent l'un sous l'autre — sinon « Publier maintenant » se fait écraser. */
.dv-num { font-size: var(--t-meta); color: var(--cok-text-3); margin-left: auto; }
.dv-actions { flex-wrap: wrap; }
.dv-actions .dv-publier { flex: 0 0 auto; }
@media (max-width: 520px) {
  .dv-actions .btn-primary, .dv-actions .cok-btn { flex: 1 1 100%; }
  .dv-num { margin-left: 0; }
}
.dv-mot { font-size: var(--t-meta); color: var(--cok-text-3); margin-top: var(--e-8); min-height: 16px; }

/* ⚠️ Sous 780 px, deux colonnes de 260 px ne tiennent plus : on empile, la photo garde
   sa taille. Regle d Amadou -- toute interface doit s adapter a l ecran. */
@media (max-width: 780px) {
  .dv-corps { grid-template-columns: 1fr; }
  .dv-gauche { max-width: 300px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PRODUCTION — l'écran AVANT le lancement
   Amadou (09/08). Le formulaire demandait deux choses et n'en montrait aucune :
   deux blocs empilés, hauts et vides, puis trois chiffres. On ne savait pas ce
   qu'on allait obtenir avant de payer.
   ══════════════════════════════════════════════════════════════════════════ */
.an-deux { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-12); }
.an-deux > .an-sec { margin: 0; }
@media (max-width: 900px) { .an-deux { grid-template-columns: 1fr; } }

/* ── Les modèles : un visage, pas une pastille ───────────────────────────────
   « On doit voir leur image de face en plus grand » — on reconnaît une vendeuse
   à sa tête, pas à son pseudo. 62 px : assez pour identifier un visage, assez
   petit pour en aligner cinq sans faire défiler. */
.an-sm { width: 62px; flex: 0 0 auto; text-align: left; background: none; border: 0; padding: 0; cursor: pointer; }
.an-sm-i {
  position: relative; width: 62px; height: 76px;
  border-radius: 9px;
  /* ⚠️ PAS DE BORDURE SUR UNE PHOTO. `--cok-border` vaut rgba(var(--th-voile),.09) : sur
     une vignette qui porte une image, ce liseré blanc cerne le visage et se voit —
     Amadou (09/08) : « il y a un contour blanc autour des cartes, ce n'est pas beau ».
     Le fond suffit à poser la carte quand il n'y a pas d'image ; les cases vides, elles,
     gardent leur trait pointillé pour rester lisibles. */
  border: 0;
  background: var(--cok-accent-bg) center top / cover no-repeat;
  display: flex; align-items: center; justify-content: center;
}
/* ── LES MODÈLES PORTENT LA VIGNETTE DES ROBES ──────────────────────────────
   Deux blocs côte à côte qui font le même geste dessinaient deux objets différents.
   `.an-sv--m` n'ajoute que ce qui est propre au modèle : l'initiale quand il n'y a
   pas de visage, et l'alerte de compte. Tout le reste — taille, 3/4, nom, rayon —
   vient de `.an-sv`, donc les deux ne peuvent plus diverger. */
.an-sv--m .an-sv-i { display: flex; align-items: center; justify-content: center; }
.an-sv--m.ko .an-sv-i { outline: 1px solid rgba(var(--th-danger-rgb),.45); outline-offset: -1px; }
.an-sm-ini { font-size: var(--t-lead); font-weight: var(--fw-fort); color: var(--cok-text-3); }
.an-sm-n {
  font-size: var(--t-meta); color: var(--cok-text-2); margin-top: var(--e-6);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Un compte qui ne peut plus publier : signalé, jamais interdit. Il peut se
   reconnecter d'ici la publication, et refuser un choix sur une donnée de dix-huit
   jours serait pénible. */
.an-sm.ko .an-sm-i { opacity: .5; border: 1px solid var(--cok-red); }
.an-sm.ko .an-sm-n { color: var(--cok-red); }
.an-sm-ko { font-size: var(--t-micro); color: var(--cok-red); line-height: var(--lh-serre); }
.an-sm-plus .an-sm-i { border: 1px dashed var(--cok-border-2); background: transparent; }
.an-sm-more { font-size: var(--t-title); color: var(--cok-text-3); }
.an-sm-plus:hover .an-sm-i { border-color: var(--violet-soft); }
.an-sm-plus:hover .an-sm-more { color: var(--violet-light); }
/* ⚠️⚠️ LA CROIX SE RETROUVAIT AU MILIEU DE LA PHOTO, et Amadou l'a vu (13/08 : « quand
   je sélectionne une modèle c'est pas bien mis, c'est pas centré »). Cette règle visait
   `.an-sm` — l'ancienne vignette de modèle. Depuis que le modèle emprunte `.an-sv`, elle
   ne s'appliquait plus, et la croix tombait dans le centrage flex posé pour l'initiale.
   Une règle de position qui cesse de matcher ne disparaît pas : elle laisse l'élément à
   la merci de son conteneur. */
.an-sm .an-sp-x,
.an-sv--m .an-sp-x { position: absolute; top: 4px; right: 4px; }

/* ── Les raccourcis de sélection ─────────────────────────────────────────────
   Choisir des robes voulait dire ouvrir un sélecteur et cocher une par une. */
.an-racc { display: flex; gap: var(--e-6); flex-wrap: wrap; margin-top: var(--e-12); 
  /* ⚠️⚠️ ILS DEVENAIENT DES OVALES GÉANTS, ET AMADOU L'A VU (13/08 : « les sortes de
     bulles là c'est moche »). `.an-sec-b` est un flex avec `align-items: stretch` par
     défaut : quand il restait de la place sur la rangée, cette barre y montait comme
     un article de plus et s'ÉTIRAIT à la hauteur d'une vignette (~110 px) — un
     `border-radius: 999px` sur une boîte de 110 px de haut, ça fait une ellipse.
     Elle prend donc toute la largeur : elle passe à la ligne, et retrouve sa hauteur. */
  flex: 0 0 100%;
  align-self: flex-start;
}
.an-racc-b {
  font-size: var(--t-meta); color: var(--violet-light);
  background: var(--cok-accent-bg); border: 1px solid transparent;
  border-radius: var(--r-pilule); padding: var(--e-4) var(--e-12); cursor: pointer;
}
.an-racc-b:hover { border-color: var(--violet-soft); }
.an-racc-x { color: var(--cok-text-2); }
.an-racc-x:hover { border-color: rgba(var(--th-danger-rgb),.5); color: var(--ose-text); }

/* ⚠️ LE MÊME BOUTON, DANS L'EN-TÊTE DES DEUX ZONES DE PHOTOS. Il emprunte `.an-racc-b`
   et `.an-racc-x` aux Annonces — même forme, même rouge au survol — et n'ajoute que sa
   place : collé au compteur, à droite du titre. Un deuxième dessin pour le même geste,
   c'était deux apparences à tenir. */
.preview-vider {
  margin-left: auto;
  margin-right: var(--e-8);
  font-size: var(--t-micro);
  padding: var(--e-2) var(--e-8);
  line-height: var(--lh-un);
  /* ⚠️ Vérifié en étroit (860 px) : sans ça il se coupe en deux lignes et déforme
     l'en-tête. Deux largeurs, toujours — c'est la règle de ce projet. */
  white-space: nowrap;
}

/* ── Ce que ça va produire ───────────────────────────────────────────────────
   Le cœur de l'écran : la liste RÉELLE des annonces, avant de lancer. */
.an-prod {
  border: 1px solid var(--violet-soft); border-radius: var(--r-carte);
  padding: var(--e-14) var(--e-16); margin: var(--e-12) 0;
}
.an-prod-t { font-size: var(--t-base); color: var(--cok-text-2); margin-bottom: var(--e-10); }
.an-prod-c { display: flex; gap: var(--e-18); flex-wrap: wrap; font-size: var(--t-base); color: var(--cok-text-2); margin-bottom: var(--e-12); }
.an-prod-c b { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--cok-text); margin-right: var(--e-4); }
.an-prod-g { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--e-6); }
.an-prod-g span {
  font-size: var(--t-meta); color: var(--cok-text-2);
  background: var(--cok-accent-bg); border-radius: 7px; padding: var(--e-6) var(--e-10);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.an-prod-p { color: var(--cok-text-3) !important; }

/* ══════════════════════════════════════════════════════════════════════════
   LES CASES À COCHER
   ⚠️⚠️ Amadou (09/08), sur les Brouillons : « il y a un contour blanc, ce n'est
   pas beau ». Ce n'était pas le contour des cartes — c'étaient les cases à
   cocher, laissées en rendu NATIF. Le navigateur dessine alors un carré blanc
   avec son propre liseré, quelle que soit la couleur du site : sur le fond
   sombre, quatre carrés blancs éclatants, un par carte.
   ⚠️ `accent-color` ne suffit pas : il ne colore QUE l'état coché. Une case
   décochée reste blanche — c'est-à-dire l'état dans lequel on la voit le plus.
   Il faut `appearance: none` et la dessiner soi-même.
   ══════════════════════════════════════════════════════════════════════════ */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 15px; height: 15px; flex: 0 0 auto;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-micro);
  background: var(--bg-hover);
  cursor: pointer;
  display: inline-grid; place-content: center;
  transition: background var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose);
}
/* La coche est dessinée en CSS pur : pas d'image à charger, et elle suit la
   couleur du texte donc elle reste lisible si le violet change un jour. */
input[type="checkbox"]::before {
  content: ""; width: 9px; height: 9px;
  transform: scale(0);
  transition: transform var(--t-bref) var(--c-pose);
  background: #fff;
  clip-path: polygon(14% 44%, 0 65%, 39% 100%, 100% 16%, 84% 0, 39% 68%);
}
input[type="checkbox"]:checked {
  background: var(--violet, var(--violet));
  border-color: var(--violet, var(--violet));
}
input[type="checkbox"]:checked::before { transform: scale(1); }
input[type="checkbox"]:hover:not(:disabled) { border-color: var(--violet-soft, var(--violet-soft)); }
input[type="checkbox"]:focus-visible { outline: 2px solid var(--violet, var(--violet)); outline-offset: 2px; }
input[type="checkbox"]:disabled { opacity: .4; cursor: default; }
/* ⚠️ Sur une carte, la case est posée sur une photo : elle garde son pastillage
   sombre derrière, sinon elle disparaît sur une robe claire. */
.dcard-cb input { width: 15px; height: 15px; }

/* ══════════════════════════════════════════════════════════════════════════
   LES CARTES DE BROUILLON PRENNENT LE TRAITEMENT DE LA BIBLIOTHÈQUE
   Amadou (09/08) : « c'est comme pour les cartes dans la bibliothèque ».
   ⚠️⚠️ Les deux cartes portaient DÉJÀ la même bordure (`var(--border)`) — ce n'est
   donc pas la couleur du trait qui les séparait, et c'est pour ça que je tournais
   en rond en baissant l'opacité. La différence est ailleurs :
     • en Bibliothèque la photo est EN RETRAIT de 6 px dans la carte, donc le trait
       ne touche jamais l'image ; en Brouillons elle colle au bord, et le liseré
       cerne directement une photo claire — c'est ça qui le fait ressortir ;
     • la carte de Bibliothèque a une OMBRE PORTÉE et un liseré intérieur, qui la
       posent par le relief plutôt que par le trait.
   On reprend donc les valeurs de `.lib-card` à l'identique — emprunter, pas
   réinventer une troisième façon de dessiner une carte.
   ══════════════════════════════════════════════════════════════════════════ */
.dcard {
  padding: var(--e-6);
  background: linear-gradient(158deg, rgba(var(--th-voile),0.042) 0%, rgba(var(--th-voile),0.012) 55%);
  /* ⚠️ `overflow: hidden` devient `visible` comme en Bibliothèque : c'est le bloc
     photo qui découpe l'image, plus la carte. Sans ça, le retrait ne se verrait pas. */
  overflow: visible;
  box-shadow: 0 5px 18px -12px rgba(var(--th-ombre),0.55), inset 0 1px 0 var(--bg-sidebar);
  transition: background var(--d-fast) var(--c-pose), border-color var(--d-fast) var(--c-pose),
              transform var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
.dcard:hover {
  border-color: var(--violet-mid);
  transform: translateY(-3px);
  box-shadow: 0 16px 34px -14px rgba(var(--th-accent-rgb),0.5), inset 0 1px 0 var(--bg-elevated);
}
/* La photo se découpe elle-même, en retrait du bord de la carte. */
.dcard-ph {
  border-radius: var(--r-sm);
  overflow: hidden;
  background: linear-gradient(135deg, var(--bg-hover) 0%, rgba(var(--th-voile),0.015) 100%);
}
/* Le corps suit le retrait : sans ça le texte serait plus à gauche que la photo. */
.dcard-body { padding: var(--e-10) var(--e-6) var(--e-4); }

/* ══════════════════════════════════════════════════════════════════════════
   BARRE DE SÉLECTION DES BROUILLONS — alignée sur celle de la Bibliothèque
   Amadou (09/08) : « dans la bibliothèque c'est bien fait, là c'est mal fait —
   inspire-toi de la partie bibliothèque pour la barre ».
   On reprend la structure de `.hist-select-bar` : ce qu'on sélectionne à gauche,
   ce qu'on en fait à droite, boutons de même gabarit, séparateur entre les
   familles d'actions. Avant : six éléments à la suite qui débordaient sur deux
   rangs, sans hiérarchie.
   ══════════════════════════════════════════════════════════════════════════ */
.drafts-bulkbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-12); flex-wrap: wrap;
  margin-bottom: var(--e-12); padding: var(--e-10) var(--e-14);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color var(--t-moyen) var(--c-pose);
}
/* ⚠️ La bordure violette n'apparaît QU'AVEC une sélection, comme en Bibliothèque :
   c'est le seul signal qui dit « tu es en train de choisir ». Allumée en permanence,
   elle ne voudrait plus rien dire. */
.drafts-bulkbar.on { border-color: var(--violet); }
.drafts-bulk-count { font-size: var(--t-base); color: var(--text-3); }
.drafts-bulk-count.on { color: var(--violet-light); }

/* La seule action qui publie vraiment sur Vinted : la seule en plein. Les deux
   autres se défont — un brouillon se supprime, une date se change. */
.lib-bulk-pri:not(:disabled) {
  background: var(--violet-tint);
  border-color: var(--violet);
  color: var(--violet-light);
}
.lib-bulk-pri:not(:disabled):hover { background: var(--violet-tint-strong); color: var(--text); }

/* Le menu du bouton de sélection : chaque choix porte le nombre qu'il prendrait. */
.drafts-sel-menu { min-width: 210px; }
.drafts-sel-menu .dress-color-menu-item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-14);
}
.drafts-sel-menu .dress-color-menu-item b {
  font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--text-3);
}
.drafts-sel-menu .dress-color-menu-item:hover b { color: var(--violet-light); }

@media (max-width: 700px) {
  .drafts-bulkbar { flex-direction: column; align-items: stretch; }
  .hist-select-right { flex-wrap: wrap; }
}

/* ── Annonces en ligne ───────────────────────────────────────────────────────
   Jetons du cockpit uniquement (--cok-*), rien de nouveau côté couleurs.
   Amadou a choisi la version sobre : « l'écran doit montrer des robes, pas des
   compteurs ». Le filtre à gauche, les chiffres à droite, aucun bloc. */
.el-barre { display:flex; align-items:center; justify-content:space-between;
            gap:var(--e-20); flex-wrap:wrap; }
.el-seg { display:inline-flex; gap:var(--e-4); padding:var(--e-4); border-radius: var(--r-pilule);
          background:var(--cok-bg-2); border:1px solid var(--cok-border); }
/* ⚠️ `font:inherit` posait la graisse à 400 alors que tous les autres onglets sont à 500 :
   c'était la seule famille à changer de graisse au clic APRÈS la correction générale, et
   elle changeait dans l'autre sens (400 → 500). Une graisse écrite explicitement la remet
   au niveau des autres et la fige. */
.el-segb { font:inherit; font-size:var(--t-base); font-weight:var(--fw-moyen); color:var(--cok-text-2); background:none;
           border:0; cursor:pointer; padding:var(--e-8) var(--e-16); border-radius: var(--r-pilule);
           white-space:nowrap; transition:background var(--t-bref), color var(--t-bref); }
.el-segb b { font-weight:var(--fw-fort); color:var(--cok-text-3); margin-left:var(--e-4); }
.el-segb:hover { color:var(--cok-text); }
.el-segb.on { background:var(--cok-accent-bg); color:var(--violet-light); font-weight:var(--fw-fort); }
.el-segb.on b { color:var(--cok-accent); }

.el-chiffres { display:flex; align-items:center; gap:var(--e-14); flex-wrap:wrap;
               font-size:var(--t-base); color:var(--cok-text-3); }
.el-chiffres b { font-size:var(--t-small); font-weight:var(--fw-fort); color:var(--cok-text); margin-right:var(--e-4); }
.el-chiffres em { font-style:normal; font-size:var(--t-mini); font-weight:var(--fw-fort);
                  color:var(--cok-accent); margin-left:var(--e-6); }
.el-chiffres i { display:inline-block; width:1px; height:14px; background:var(--cok-border); }
.el-chiffres > span:last-child + i, .el-chiffres i:last-child { display:none; }
.el-sur { font-size:var(--t-meta); font-weight:var(--fw-normal); color:var(--cok-text-3); }

.el-alerte { display:flex; align-items:flex-start; gap:var(--e-10); margin-top:var(--e-14);
             padding:var(--e-12) var(--e-16); border-radius: var(--r-md); font-size:var(--t-base);
             line-height:var(--lh-normal); color:var(--text);
             background:var(--cok-warn-bg); border:1px solid rgba(230,162,60,.25); }
.el-alerte b { color:var(--cok-warn); font-weight:var(--fw-fort); }
.el-alerte-i { width:6px; height:6px; border-radius:50%; margin-top:var(--e-6); flex:0 0 auto;
               background:var(--cok-warn); }

.el-grille { display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr));
             gap:var(--e-14); margin-top:var(--e-18); }
.el-c { background:var(--cok-card); border:1px solid var(--cok-border);
        border-radius: var(--r-md); overflow:hidden; cursor:pointer;
        transition:border-color var(--t-moyen), transform var(--t-moyen); }
.el-c:hover { border-color:var(--cok-border-2); transform:translateY(-2px); }
/* La photo occupe toute la largeur, sans marge : c'est le produit qu'on vient voir. */
.el-ph { aspect-ratio:4/5; position:relative; background-size:cover; background-position:center;
         background-color:rgba(var(--th-voile),.04); }
/* ⚠️⚠️ PAS DE `backdrop-filter` ICI. La première version en mettait sur les pastilles :
   au survol, la carte se soulève (transform), ce qui crée un contexte de composition —
   et le flou virait au NOIR sur toute la vignette. Amadou : « quand je survole, il bug,
   on est déjà en tout noir. » Un dégradé fait le même travail de lisibilité, sans
   contexte de composition. */
.el-scrim { position:absolute; inset:auto 0 0 0; height:64px; pointer-events:none;
            background:linear-gradient(to top, rgba(var(--th-ombre),.78), transparent); }
.el-prix { position:absolute; left:11px; bottom:10px; font-size:var(--t-small); font-weight:var(--fw-fort); color: var(--text); }
.el-corps { padding:var(--e-12) var(--e-14) var(--e-10); }
.el-titre { font-size:var(--t-base); font-weight:var(--fw-moyen); line-height:var(--lh-serre); min-height:34px;
            overflow:hidden; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; }
.el-qui { display:flex; justify-content:space-between; gap:var(--e-8); margin-top:var(--e-6);
          font-size:var(--t-mini); color:var(--cok-text-3); }
.el-qui span:first-child { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Les trois compteurs partagent la largeur, séparés par un filet — pas d'espacement
   arbitraire à régler à l'œil. */
.el-stats { display:flex; border-top:1px solid var(--cok-border); }
.el-stats span { flex:1; display:inline-flex; align-items:center; justify-content:center;
                 gap:var(--e-6); padding:var(--e-10) 0; font-size:var(--t-meta); color:var(--cok-text-2);
                 border-left:1px solid var(--cok-border); }
.el-stats span:first-child { border-left:0; }
.el-stats svg { width:13px; height:13px; opacity:.6; flex:0 0 auto; }
.el-stats .chaud { color:var(--cok-accent); }
.el-stats .chaud svg { opacity:1; }

.el-vide { background:var(--cok-card); border:1px solid var(--cok-border);
           border-radius: var(--r-lg); padding:26px; margin-top:var(--e-14); text-align:center; }
.el-vide-t { font-size:var(--t-small); font-weight:var(--fw-fort); }
.el-vide-s { font-size:var(--t-base); color:var(--cok-text-2); margin-top:var(--e-6); }

@media (max-width:640px) {
  .el-barre { gap:var(--e-12); }
  .el-chiffres { gap:var(--e-10); font-size:var(--t-meta); }
  .el-chiffres b { font-size:var(--t-small); }
  .el-grille { grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:var(--e-10); }
}

/* ══════════════════════════════════════════════════════════════════════════
   LE BOUTON D'ACTION PRINCIPAL — une seule recette
   ⚠️⚠️ Il y en avait CINQ : le dégradé officiel `var(--aurora)`, un dégradé refait
   à la main pour le lancement de batch, un autre pour un bouton mort, l'aplat
   `var(--violet)`, et `var(--cok-accent-solid)` côté cockpit. Plus QUATRE hauteurs
   pour le même geste : 32, 38, 40 et 48 px.
   C'est pourtant le bouton qu'on regarde en premier sur chaque écran.
   ⚠️ POSÉ EN FIN DE FICHIER, comme le bloc d'harmonisation juste au-dessus : à
   spécificité égale c'est la dernière règle qui gagne. Le mettre « près des classes
   concernées » le rendrait inopérant — le piège est documenté dans ce fichier.
   ⚠️ On ne touche NI la taille du texte NI le padding : chaque bouton garde sa
   place dans son écran. On unifie ce qui se voit de loin — la matière et la hauteur.
   ══════════════════════════════════════════════════════════════════════════ */
.btn-primary,
.btn-generate,
.atelier-gen-btn,
.mod-go-btn,
.batch-btn-launch,
.pg-send-btn,
.studio-send-btn,
.studio-new-chat-btn,
.cok-msg-sbtn,
.velbo-dd-addbtn {
  background: var(--aurora);
  border: 0;
  color: var(--sur-accent);
}
/* 40 px partout : 32 faisait bouton d'appoint, 48 faisait bandeau. Les boutons qui
   vivent dans une barre de saisie gardent leur hauteur — elle est calée sur le champ. */
.btn-primary,
.mod-go-btn,
.batch-btn-launch,
.atelier-gen-btn { min-height: 40px; }

/* Le bouton violet DOUX (teinté) : il existait en 11 recettes, dont 9 opacités
   tapées à la main entre .07 et .18. Une seule désormais. */
.atelier-regen-btn,
.cok-msg-asbtn {
  background: var(--violet-tint, rgba(var(--th-accent-rgb),.14));
}

/* Le temps d'aller lire la fiche complète dans son navigateur, la carte le montre —
   sans quoi le clic paraît sans effet pendant une à deux secondes. */
.el-c-charge { opacity: .55; pointer-events: none; }

/* ── LA BANDE D'UNE COMMANDE, ÉPURÉE ────────────────────────────────────────
   Amadou (09/08) : « il y a trop de choses pour rien, c'est mal fait, c'est moche ».
   Elle portait 13 éléments sur une seule ligne, tous au même niveau : deux prix
   identiques, une étiquette SHEIN coupée en plein milieu, et cinq boutons.
   ⚠️ Rien n'est perdu — le panneau de détail existe désormais, la bande n'a plus à
   tout porter. */
.cmd-ord-acts { gap: var(--e-8); }
/* Le bouton « ⋯ » : présent mais en retrait. Il ne doit pas concurrencer l'action
   d'étape juste à sa gauche, qui est celle de tous les jours. */
.cmd-plus { font-size: var(--t-small); line-height: var(--lh-un); letter-spacing: 1px; }
.cmd-plus:hover { color: var(--cok-text); }
.cmd-ligne-menu { min-width: 208px; }

/* ── PHOTO EN GRAND À GAUCHE, UN SEUL BLOC À DROITE ──────────────────────────
   Amadou (09/08) : « la robe à commander qui est affichée, ça soit plus gros », et
   avant ça « c'est trop étiré, tu peux augmenter la hauteur ». Les deux se règlent
   ensemble : la bande gagne en hauteur ce qu'elle rend en largeur.
   ⚠️ Le titre, le prix, le délai et les boutons étaient QUATRE colonnes posées sur la
   ligne, écartées par tout l'espace disponible — d'où le vide au milieu. */

/* Le titre a droit à DEUX lignes : les titres Vinted font 60 à 90 caractères et la
   coupe à une ligne les tronquait juste avant le détail qui distingue deux robes. */
.cmd-ord-main > .cmd-t {
  white-space: normal; line-height: var(--lh-serre);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* La colonne de droite : le prix en haut, les actions en bas, calée sur la hauteur de
   la photo. C'est ce qui fait tenir la bande en TROIS zones au lieu de six éléments
   éparpillés sur toute la largeur. */
.cmd-ord-cote {
  flex: 0 0 auto; align-self: stretch; min-height: var(--cmd-ph-h);
  display: flex; flex-direction: column; align-items: flex-end;
  justify-content: space-between; gap: var(--e-12);
}
/* ⚠️ `.cmd-prix` n'avait AUCUNE règle : la colonne posée le 09/08 sortait en texte nu,
   police et taille par défaut. */
.cmd-prix { flex: 0 0 auto; text-align: right; line-height: var(--lh-titre); }
.cmd-prix-v { font-size: var(--t-small); font-weight: var(--fw-gras); color: var(--cok-text);
  font-variant-numeric: tabular-nums; }
.cmd-prix-d { font-size: var(--t-mini); color: var(--cok-text-3); font-variant-numeric: tabular-nums;
  margin-top: var(--e-1); }

/* Statut et délai, à la suite des étiquettes : de l'information, pas des commandes. */
.cmd-ord-pied { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap; margin-top: var(--e-1); }

/* Sur les étapes passives il n'y a ni étiquettes ni bouton d'étape : le « ⋯ » restait
   donc seul tout en bas d'une colonne vide, à cent pixels du prix. Les deux se rangent
   sur une ligne, et la bande retrouve une hauteur de liste. */
.cmd-ord:not(.cmd-ord--gros) { padding-top: var(--e-10); padding-bottom: var(--e-10); }
.cmd-ord:not(.cmd-ord--gros) .cmd-ord-cote {
  flex-direction: row; align-items: center; justify-content: flex-end;
  min-height: 0; align-self: flex-start; gap: var(--e-14);
}

@media (max-width: 900px) {
  /* La photo garde sa raison d'être ; c'est le bloc de droite qui se resserre. */
  .cmd-ord--gros { --cmd-ph-l: 84px; --cmd-ph-h: 105px; }
  .cmd-ord .cmd-b { min-width: 0; }
}

/* Le panneau s'ouvre AVANT d'avoir tout son contenu : un liseré discret dit que la
   description et les menus sont encore en route, sans figer l'écran. */
.dv-attend .dv-desc { opacity: .5; }
.dv-attend .dv-ddm { opacity: .5; pointer-events: none; }

/* ── Analyse d'une annonce, sous sa photo ────────────────────────────────────
   Elle occupe la place laissée libre à côté de la description : elle ne coûte
   donc rien en hauteur, ce qui était le reproche fait à la première version. */
.dv-an { margin-top: var(--e-14); background: var(--cok-card); border: 1px solid var(--cok-border);
  border-radius: var(--r-md); padding: var(--e-14) var(--e-14); }
.dv-an-t { font-size: var(--t-micro); letter-spacing: .5px; text-transform: uppercase;
  color: var(--cok-text-3); margin-bottom: var(--e-12); }
.dv-an-g { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e-2); }
.dv-an-c { display: flex; flex-direction: column; gap: var(--e-2); padding-left: var(--e-12);
  border-left: 1px solid var(--cok-border); }
.dv-an-c:first-child { padding-left: 0; border-left: 0; }
.dv-an-c .n { font-size: var(--t-lead); font-weight: var(--fw-fort); line-height: var(--lh-titre); }
.dv-an-c .l { font-size: var(--t-micro); color: var(--cok-text-3); }
.dv-an-c .m { font-size: var(--t-micro); font-weight: var(--fw-fort); color: var(--cok-accent); }
.dv-an-ratio { margin-top: var(--e-14); padding-top: var(--e-12); border-top: 1px solid var(--cok-border); }
.dv-an-rn { display: flex; align-items: baseline; gap: var(--e-8); font-size: var(--t-lead);
  font-weight: var(--fw-fort); color: var(--cok-accent); }
.dv-an-rn span { font-size: var(--t-micro); font-weight: var(--fw-normal); color: var(--cok-text-3); }
.dv-an-jauge { height: 4px; border-radius: var(--r-pilule); margin-top: var(--e-8); overflow: hidden;
  background: var(--bg-elevated); }
.dv-an-jauge i { display: block; height: 100%; border-radius: var(--r-pilule); background: var(--cok-accent); }
.dv-an-v { font-size: var(--t-meta); line-height: var(--lh-normal); color: var(--cok-text-2); margin: var(--e-12) 0 0; }

/* Les champs prennent la largeur gagnée : quatre sur une ligne quand la place le
   permet, au lieu d'une colonne qui allongeait le panneau. */
.dv-champs { flex-direction: row; flex-wrap: wrap; gap: var(--e-12) var(--e-14); }
.dv-ch { flex: 1 1 165px; flex-direction: column; align-items: stretch; gap: var(--e-6); }
.dv-ch .dv-l { flex: 0 0 auto; }
.dv-quitter { margin-left: auto; }

/* ══════════════════════════════════════════════════════════════════════════════
   LA VISIONNEUSE D'IMAGES — REFONTE (09/08)
   Amadou : « à chaque fois que j'ouvre une image, je trouve que l'interface est
   vraiment moche, on va améliorer tout ça pour TOUT le site ».
   Il y a UNE seule visionneuse pour treize points d'entrée : la corriger ici les
   corrige tous. Ce bloc est en FIN de fichier parce que `.zoom-*` est décrite plus
   haut à plusieurs endroits — la dernière recette est celle qui commande.
   ════════════════════════════════════════════════════════════════════════════ */

/* ⚠️⚠️ LA VISIONNEUSE PASSAIT DERRIÈRE LES PANNEAUX. `.modal-overlay` est en
   `z-index: 200` alors que le panneau d'annonce est à 9000, l'aperçu de lot à 9200 et
   les fenêtres Velbo à 9600 : ouvrir une image depuis l'un d'eux l'affichait DESSOUS,
   donc invisible — et le clic suivant tombait sur le panneau. */
#modal-zoom, #modal-compare, #modal-avatar { z-index: 9800; }

/* Le fond descend plus bas et floute plus : une visionneuse doit faire reculer
   l'application, pas cohabiter avec elle. */
#modal-zoom { padding: 0; }
#modal-zoom .zoom-backdrop {
  background: rgba(var(--th-panneau-rgb),0.90);
  backdrop-filter: blur(22px) saturate(1.1);
  -webkit-backdrop-filter: blur(22px) saturate(1.1);
}

/* ── LA CROIX, DANS LE COIN DE L'ÉCRAN ──────────────────────────────────────
   Elle était `position: absolute` sur le wrapper, à `-10px` de son coin : sur une photo
   plus étroite que la fenêtre, elle atterrissait au milieu du vide. Sa FORME reste celle
   de toutes les croix du site (bloc d'harmonisation) — seule sa place change. */
#modal-zoom > .zoom-close {
  position: absolute;
  top: 18px; right: 22px;
  z-index: 3;
  width: 38px; height: 38px;
  background: rgba(var(--th-voile),0.07);
  border-color: rgba(var(--th-voile),0.12);
  color: var(--text-2);
}
#modal-zoom > .zoom-close > svg { width: 17px; height: 17px; }

/* ── LE CADRE ───────────────────────────────────────────────────────────────
   La colonne de référence de droite gardait 220 px + 16 px de gouttière MÊME VIDE : dans
   tous les cas simples — c'est-à-dire presque partout — l'image était décentrée de 236 px
   avec un trou noir à côté. C'était ça, « c'est moche ». */
.zoom-wrapper { max-height: 94vh; max-width: 96vw; gap: var(--e-18); }
.zoom-right { display: none; }
.zoom-wrapper.with-ref .zoom-right,
.zoom-wrapper.product-mode .zoom-right { display: flex; }

.zoom-left { gap: var(--e-14); min-width: 0; }

/* La scène : l'image et ses deux flèches, rien d'autre. Les flèches se posent SUR ses
   bords — hors de l'image elles obligeaient l'œil à quitter la photo pour naviguer. */
.zoom-scene { position: relative; display: flex; align-items: center; justify-content: center; min-width: 0; }

.zoom-track {
  border-radius: var(--r-lg, 16px);
  box-shadow: 0 30px 90px -20px rgba(var(--th-ombre),0.9), 0 0 0 1px var(--bg-elevated);
  /* ⚠️ `cursor: grab` promettait un glissement à la souris qui n'existe pas : il n'y a
     que des gestionnaires TACTILES. Le curseur ne doit rien promettre de faux. */
  cursor: default;
  background: var(--cok-bg-2);
}
@media (hover: none) and (pointer: coarse) { .zoom-track { cursor: grab; } }

/* L'image prend la place disponible. 62vw × 76vh laissait un quart d'écran inutilisé. */
#zoom-img, .zoom-sortante {
  max-width: min(92vw, 1500px);
  max-height: 86vh;
  border-radius: var(--r-lg, 16px);
}
#zoom-img {
  transition: opacity var(--t-moyen) var(--c-pose), transform var(--t-moyen) var(--c-pose);
}

/* ── LE GLISSEMENT ENTRE DEUX PHOTOS ─────────────────────────────────────────
   ⚠️⚠️ L'ANCIEN GLISSEMENT NE GLISSAIT PAS. Il poussait l'image de 18 px, la faisait
   tomber à 45 % d'opacité, ATTENDAIT 160 ms dans un `setTimeout`, changeait la source,
   puis revenait. Trois défauts dans un seul geste : 18 px ne se lisent pas comme un
   mouvement, l'attente coupe le geste en deux moitiés qui ne s'enchaînent pas, et une
   seule balise <img> ne peut pas faire SORTIR une photo pendant qu'une autre ENTRE.
   Désormais : deux couches, deux animations SIMULTANÉES, et un flou qui suit la vitesse.

   ⚠️ Le flou de mouvement n'est pas un `blur()` rond : un objet lancé s'étire dans SON
   axe. C'est le couple `blur()` + `scaleX()` qui donne la traînée — le flou seul donne
   une image sale, l'étirement seul donne un caoutchouc. Les deux culminent au départ et
   se résorbent ensemble.

   ⚠️ `--zoom-sens` est posé par le JS (+1 vers la suivante, -1 vers la précédente) :
   sans lui les deux photos partiraient du même côté. */
/* ⚠️ Le cadre change de format d'une photo à l'autre : il l'ACCOMPAGNE au lieu de sauter.
   Même durée que le glissement — deux mouvements simultanés de durées différentes se
   voient immédiatement. */
.zoom-track {
  transition: width var(--t-long) var(--c-pose), height var(--t-long) var(--c-pose);
}
.zoom-sortante {
  position: absolute;
  inset: 0;
  margin: auto;
  display: block;
  object-fit: contain;
  opacity: 0;                 /* invisible au repos : elle ne sert qu'au temps du geste */
  pointer-events: none;
}
/* ⚠️⚠️ LA MÊME COURBE POUR LES DEUX COUCHES, SINON CE N'EST PAS UN GLISSEMENT.
   Première version : entrée en `--c-pose`, sortie en `--c-sortie`. Mesuré à 25 % du
   geste, la photo qui arrive était DÉJÀ presque en place (-59 px sur 351) pendant que
   celle qui part n'avait bougé que de 48 px. Les deux se recouvraient au lieu de
   défiler — un fondu déguisé, pas un slide. Deux couches qui glissent ensemble doivent
   partager leur courbe ET leur durée, comme une seule bande qui défile.
   ⚠️ Et la course fait 100 %, pas 42 % : en dessous, la photo sortante est encore à
   l'écran quand la nouvelle est posée. C'est `overflow: hidden` du cadre qui la coupe. */
.zoom-glisse-sortie {
  animation: velbo-zoom-sortie var(--t-long) var(--c-pose) forwards;
  will-change: transform, filter;
}
.zoom-glisse-entree {
  animation: velbo-zoom-entrant var(--t-long) var(--c-pose);
  will-change: transform, filter;
}
/* Le flou culmine TÔT et pas au milieu : avec cette courbe la vitesse est maximale au
   départ, et un flou de mouvement suit la vitesse — sinon il flotte sans raison. */
@keyframes velbo-zoom-sortie {
  from { transform: translate3d(0, 0, 0) scaleX(1); filter: blur(0px); opacity: 1; }
  16%  { filter: blur(11px); }
  to   { transform: translate3d(calc(var(--zoom-sens, 1) * -100%), 0, 0) scaleX(1.03);
         filter: blur(5px); opacity: 1; }
}
@keyframes velbo-zoom-entrant {
  from { transform: translate3d(calc(var(--zoom-sens, 1) * 100%), 0, 0) scaleX(1.03);
         filter: blur(11px); }
  16%  { filter: blur(9px); }
  to   { transform: translate3d(0, 0, 0) scaleX(1); filter: blur(0px); }
}
/* ⚠️ Mouvement réduit : on ne joue RIEN, et la couche sortante disparaît — animée à zéro
   elle resterait posée sur la photo courante. */
@media (prefers-reduced-motion: reduce) {
  .zoom-glisse-sortie, .zoom-glisse-entree { animation: none; }
  .zoom-sortante { display: none; }
}

/* ── LES FLÈCHES ────────────────────────────────────────────────────────────
   ⚠️ Elles étaient HAUT/BAS, alors que le clavier accepte aussi ← → et que tout le monde
   attend gauche/droite d'une galerie de photos. Un seul langage de direction désormais,
   côté CSS comme côté glissement. */
.zoom-nav-arrow {
  position: absolute;
  /* ⚠️⚠️ PAS DE `transform: translateY(-50%)` POUR CENTRER. Une règle globale de ce
     fichier fait `button:disabled { transform: none !important }` (ligne ~218) : sur la
     flèche éteinte au bout de la liste, le centrage sautait et le bouton se retrouvait
     23 px plus bas que son jumeau. Mesuré : prev à 444, next à 421.
     `top/bottom: 0` + marges automatiques centrent sans toucher à `transform`. */
  top: 0; bottom: 0;
  margin-top: auto; margin-bottom: auto;
  /* ⚠️⚠️ SANS CE `z-index`, LA FLÈCHE GAUCHE EST INVISIBLE — et seulement elle. `.zoom-track`
     est en `position: relative` et vient APRÈS `#zoom-prev` dans le balisage : à `z-index`
     égal, l'ordre du document tranche, donc le rail se peint par-dessus. `#zoom-next`, lui,
     vient après le rail et se voyait très bien. Les mesures disaient « flèche bien
     placée » : seule la capture d'écran l'a montré. */
  z-index: 2;
  width: 46px; height: 46px;
  background: rgba(var(--th-panneau-rgb),0.62);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(var(--th-voile),0.14);
  color: var(--text-2);
  /* ⚠️⚠️ TRANSITION RÉPARÉE. `transition: background-color, border-color, color,
     box-shadow, transform, opacity var(--t-moyen)` : en CSS chaque valeur séparée par une
     virgule est une transition COMPLÈTE, donc seule `opacity` avait une durée — les cinq
     autres claquaient à 0 s. Le défaut vivait sur quatre sélecteurs de la visionneuse. */
  transition: background-color var(--t-moyen) var(--c-pose),
              border-color     var(--t-moyen) var(--c-pose),
              color            var(--t-moyen) var(--c-pose),
              opacity          var(--t-moyen) var(--c-pose);
}
#zoom-prev { left: 14px; }
#zoom-next { right: 14px; }
.zoom-nav-arrow:hover:not(:disabled) {
  background: var(--violet, var(--violet));
  border-color: var(--violet, var(--violet));
  color: var(--sur-accent);
}
/* Une flèche au bout de la liste ne disparaît pas — elle s'éteint. Disparaître ferait
   sauter l'autre de place, et on ne saurait plus s'il reste des photos. */
.zoom-nav-arrow:disabled { opacity: 0.16; pointer-events: none; }
/* Une seule photo : aucune flèche, aucune pastille. Rien ne doit suggérer une suite. */
.zoom-wrapper:has(.zoom-dots:empty) .zoom-nav-arrow { display: none; }

/* ── LA LÉGENDE : CE QU'ON REGARDE, ET OÙ ON EN EST ─────────────────────────
   Le libellé de chaque vue (« Face — Camila · Bordeaux ») était CALCULÉ par la galerie et
   affiché NULLE PART : on naviguait à l'aveugle entre onze images qui se ressemblent. */
.zoom-legende {
  display: flex; align-items: center; justify-content: center; gap: var(--e-10);
  max-width: min(92vw, 1500px);
}
.zoom-legende[hidden] { display: none; }
.zoom-legende-vue {
  font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.zoom-legende-cpt {
  flex: 0 0 auto;
  font-size: var(--t-mini); font-weight: var(--fw-gras); letter-spacing: var(--ls-leger);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule, 999px);
  background: rgba(var(--th-voile),0.07);
}

/* ── LES PASTILLES ──────────────────────────────────────────────────────────
   6 px sur un fond noir : on ne voyait ni combien il y en avait, ni laquelle était
   active, et elles étaient trop petites pour être visées. */
.zoom-dots { gap: var(--e-8); flex-wrap: wrap; justify-content: center; max-width: min(92vw, 1500px); }
.zoom-dot {
  width: 8px; height: 8px;
  background: rgba(var(--th-voile),0.28);
  transition: background-color var(--t-moyen) var(--c-pose),
              width            var(--t-moyen) var(--c-pose);
}
.zoom-dot:not(.active):hover { background: rgba(var(--th-voile),0.55); }
.zoom-dot.active { background: var(--violet-light, var(--violet-light)); width: 22px; border-radius: var(--r-micro); }

/* Les deux autres transitions cassées du même bloc. */
.zoom-action-btn {
  transition: background-color var(--t-moyen) var(--c-pose),
              border-color     var(--t-moyen) var(--c-pose),
              color            var(--t-moyen) var(--c-pose);
}

/* ── MODE PRODUIT ───────────────────────────────────────────────────────────
   Il faisait tourner les chevrons de 90° pour les rendre horizontaux : ils le sont
   maintenant partout, la rotation les remettrait à l'envers. */
.zoom-wrapper.product-mode .zoom-left { flex-direction: column; }
.zoom-wrapper.product-mode #zoom-prev svg,
.zoom-wrapper.product-mode #zoom-next svg { transform: none; }
.zoom-wrapper.product-mode .zoom-nav-arrow { width: 46px; height: 46px; }
.zoom-wrapper.product-mode #zoom-img { max-width: min(56vw, 1000px); max-height: 84vh; }

/* ── ÉTROIT ─────────────────────────────────────────────────────────────────
   Sur un écran étroit, la colonne de référence passe DESSOUS au lieu de comprimer
   l'image à rien. */
@media (max-width: 900px) {
  .zoom-wrapper, .zoom-wrapper.with-ref, .zoom-wrapper.product-mode { flex-direction: column; }
  .zoom-wrapper.with-ref .zoom-right, .zoom-wrapper.product-mode .zoom-right {
    width: 100%; max-height: 26vh;
  }
  #zoom-img { max-height: 68vh; }
  .zoom-nav-arrow { width: 40px; height: 40px; }
  #zoom-prev { left: 8px; } #zoom-next { right: 8px; }
}

/* Le mouvement de l'image suit maintenant la direction des flèches : horizontal. */
@media (prefers-reduced-motion: reduce) {
  #zoom-img, .zoom-dot, .zoom-nav-arrow { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════
   LE PANNEAU DE DÉTAIL D'UNE COMMANDE
   Amadou (09/08) : « le descriptif est vraiment moche, il est vilain. On ne voit
   même pas les photos de la robe, on ne voit rien du tout. »
   ⚠️⚠️ IL N'AVAIT AUCUN STYLE : 16 de ses 17 classes n'avaient pas UNE SEULE règle
   dans ce fichier. Tout sortait en texte brut empilé, libellés et valeurs collés
   (« TailleL », « Entrepôtpas encore déclarée »). Même cause que `.cmd-prix` la
   veille : une classe neuve qu'on croit stylée parce qu'on l'a nommée.
   ════════════════════════════════════════════════════════════════════════════ */

.cmd-detail {
  position: relative;
  width: min(920px, 94vw);
  max-height: 92vh;
  overflow-y: auto;
  padding: 26px var(--e-28) var(--e-24);
}

/* ── LE PARCOURS ────────────────────────────────────────────────────────────
   Six étapes empilées en gras, sans repère : on ne voyait pas où en était la
   commande. Un rail horizontal, une pastille par étape, la courante en violet. */
.cmd-parc {
  display: flex;
  margin: var(--e-4) 34px var(--e-22) 0;      /* la marge de droite laisse la croix tranquille */
  padding: 0;
}
.cmd-parc-e {
  flex: 1; min-width: 0;
  position: relative;
  padding-top: var(--e-24);
  text-align: center;
}
/* Le rail : un segment par étape, coupé aux deux bouts pour ne pas dépasser. */
.cmd-parc-e::before {
  content: ''; position: absolute; top: 7px; left: 0; right: 0; height: 2px;
  background: rgba(var(--th-voile),0.10);
}
.cmd-parc-e:first-child::before { left: 50%; }
.cmd-parc-e:last-child::before  { right: 50%; }
.cmd-parc-e.faite::before, .cmd-parc-e.ici::before { background: var(--violet-glow); }
/* La pastille. */
.cmd-parc-e::after {
  content: ''; position: absolute; top: 2px; left: 50%; margin-left: calc(var(--e-6) * -1);
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--bg-panel-solid); border: 2px solid rgba(var(--th-voile),0.16);
}
.cmd-parc-e.faite::after { background: var(--violet-soft, var(--violet-soft)); border-color: var(--violet-soft, var(--violet-soft)); }
.cmd-parc-e.ici::after {
  background: var(--violet, var(--violet)); border-color: var(--violet, var(--violet));
  box-shadow: 0 0 0 4px var(--cok-accent-bg);
}
.cmd-parc-e > b {
  display: block;
  font-size: var(--t-mini); font-weight: var(--fw-fort); line-height: var(--lh-serre);
  color: var(--cok-text-3, rgba(var(--th-voile),0.42));
}
.cmd-parc-e.faite > b { color: var(--cok-text-2, rgba(var(--th-voile),0.66)); font-weight: var(--fw-moyen); }
.cmd-parc-e.ici > b   { color: var(--text); font-weight: var(--fw-gras); }
/* Le délai de l'étape courante — en clair, plus collé au libellé. */
.cmd-parc-e > i {
  display: block; margin-top: var(--e-4);
  font-size: var(--t-micro); font-style: normal; font-weight: var(--fw-fort);
  color: var(--amber, var(--amber));
}

/* ── LE CORPS : PHOTOS À GAUCHE, FAITS À DROITE ────────────────────────────── */
.cmd-detail-corps { display: flex; gap: var(--e-24); align-items: flex-start; }
.cmd-detail-g { flex: 0 0 300px; min-width: 0; display: flex; flex-direction: column; gap: var(--e-12); }
.cmd-detail-d { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--e-4); }
/* ⚠️⚠️ LA MISE EN PAGE DU LITIGE SE RÈGLE ICI, ET PAS PLUS HAUT DANS LE FICHIER.
   Premier essai écrit vers la ligne 3020 en `grid-template-columns` : DEUX fautes d'un
   coup — ce corps est un `flex`, qui ignore cette propriété, et la règle générale de
   cette ligne-ci passe APRÈS, donc elle l'aurait écrasée de toute façon. On répartit
   donc en `flex`, et on élargit le panneau puisqu'il porte une colonne de plus. */
/* ⚠️ C'est `width` qui borne ce panneau, pas `max-width` : un `max-width: 1180px` posé
   ici ne l'élargissait PAS d'un pixel, il restait à ses 920 px. Et sans plancher sur la
   colonne du milieu, les faits de la commande étaient écrasés à 102 px — mesuré. */
@media (max-width: 1080px) {
  /* Sous cette largeur, trois colonnes écrasent le fil : il passe dessous, pleine largeur. */
  .cmd-detail--litige .cmd-detail-corps { flex-wrap: wrap; }
  .cmd-detail--litige .lit-chat { flex: 1 1 100%; border-left: 0; padding-left: 0;
    border-top: 1px solid rgba(var(--th-voile),0.07); padding-top: var(--e-14); }
}

.cmd-detail-photo {
  width: 100%; aspect-ratio: 3 / 4;
  border-radius: var(--r-lg, 12px);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--cok-border, rgba(var(--th-trait),0.125));
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-meta); color: var(--cok-text-3, rgba(var(--th-voile),0.42)); text-align: center;
}
.cmd-detail-photo img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.cmd-detail-photo.cliquable { cursor: zoom-in; transition: box-shadow var(--t-moyen) var(--c-pose); }
.cmd-detail-photo.cliquable:hover { box-shadow: 0 0 0 2px rgba(var(--th-accent-rgb),0.55); }
.cmd-detail-sansphoto { padding: 0 var(--e-20); line-height: var(--lh-normal); }

/* La bande des vues de la robe reliée : le repère qui manquait le plus. */
.cmd-detail-bande-t {
  font-size: var(--t-micro); letter-spacing: .5px; text-transform: uppercase;
  color: var(--cok-text-3, rgba(var(--th-voile),0.42));
  margin-bottom: var(--e-8);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* ⚠️ Elle DÉFILE au lieu de passer à la ligne : une robe peut avoir onze vues, et une
   grille les ferait pousser le panneau bien au-delà de l'écran. */
.cmd-detail-bande-r {
  display: flex; gap: var(--e-8); overflow-x: auto; padding-bottom: var(--e-4);
  /* ⚠️ Sans ce dégradé, la dernière vignette est coupée NET au bord de la colonne : ça se
     lit comme un défaut d'affichage, pas comme « ça continue ». Le fondu dit qu'il faut
     faire défiler. */
  mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
}
.cmd-detail-vig {
  flex: 0 0 auto; width: 48px; height: 62px;
  border-radius: var(--r-sm, 8px); overflow: hidden; cursor: zoom-in;
  border: 1px solid var(--cok-border, rgba(var(--th-trait),0.125));
  background: var(--surface);
  transition: border-color var(--t-bref) var(--c-pose), transform var(--t-bref) var(--c-pose);
}
.cmd-detail-vig img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.cmd-detail-vig:hover { border-color: var(--violet, var(--violet)); transform: translateY(-2px); }

/* ── LES FAITS ──────────────────────────────────────────────────────────────── */
.cmd-detail-qui {
  font-size: var(--t-mini); font-weight: var(--fw-fort); letter-spacing: .3px;
  color: var(--violet-soft, var(--violet-soft));
}
/* ⚠️⚠️ `--sur-accent` VEUT DIRE « ce qui s'écrit SUR L'ACCENT PLEIN », pas « du blanc ».
   Ces deux textes sont posés sur un PANNEAU. Le jeton vaut #FFFFFF sur Dune et Nimbe
   (du blanc sur une carte blanche) et #03090C sur Abysse (du noir sur un panneau noir) :
   invisible des DEUX côtés, pour deux raisons opposées. Amadou l'a vu sur Nimbe :
   « entre camilakwlska et Taille on ne voit pas ce qui est affiché ».
   C'est la couleur de TEXTE du thème qu'il faut ici, tout simplement. */
.cmd-detail-titre {
  font-size: var(--t-body); font-weight: var(--fw-gras); line-height: var(--lh-serre); color: var(--text);
  margin-top: var(--e-4);
}
.cmd-detail-prix {
  font-size: var(--t-title); font-weight: 800; color: var(--text);
  font-variant-numeric: tabular-nums;
  margin-top: var(--e-8);
}

/* Le tableau. ⚠️⚠️ C'EST LUI QUI DONNAIT « TailleL » ET « Entrepôtpas encore déclarée » :
   deux `<span>` côte à côte sans une seule règle, donc sans le moindre espace entre le
   libellé et sa valeur. Une grille à deux colonnes, et les valeurs s'alignent. */
.cmd-detail-tbl {
  margin-top: var(--e-16);
  border-top: 1px solid var(--cok-border, rgba(var(--th-trait),0.125));
}
.cmd-detail-l {
  display: grid; grid-template-columns: 132px 1fr; gap: var(--e-14);
  align-items: baseline;
  padding: var(--e-10) 0;
  border-bottom: 1px solid rgba(var(--th-trait),0.085);
  font-size: var(--t-base);
}
/* ⚠️ La DERNIÈRE ligne garde son filet, et la barre d'actions en pose un autre juste
   dessous : deux traits à quatre pixels d'écart, qu'on lit comme une erreur. */
.cmd-detail-l:last-child { border-bottom: 0; }
.cmd-detail-l .l { color: var(--cok-text-3, rgba(var(--th-voile),0.42)); }
.cmd-detail-l .v { color: var(--cok-text, rgba(var(--th-voile),0.86)); font-weight: var(--fw-moyen); min-width: 0; word-break: break-word; }
.cmd-detail-l .v.manque { color: var(--amber, var(--amber)); font-weight: var(--fw-fort); }
.cmd-detail-l .v.ok     { color: var(--green, var(--green)); font-weight: var(--fw-fort); }
.cmd-detail-l .v.mono   { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t-meta); letter-spacing: -.2px; }
.cmd-detail-col { display: inline-flex; align-items: center; gap: var(--e-8); }
.cmd-detail-col .coloris-dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 auto; box-shadow: inset 0 0 0 1px rgba(var(--th-ombre),0.35); }

/* ── LES ACTIONS ────────────────────────────────────────────────────────────
   Deux rangées de boutons de tailles inégales. Elles se rangent, et la principale
   passe devant. */
.cmd-detail-acts {
  display: flex; flex-wrap: wrap; gap: var(--e-8);
  margin-top: var(--e-20); padding-top: var(--e-18);
  border-top: 1px solid var(--cok-border, rgba(var(--th-trait),0.125));
}
.cmd-detail-acts .cok-btn { min-height: 34px; }
.cmd-detail-acts .cok-btn.pri { order: -1; font-weight: var(--fw-fort); }

/* ── ÉTROIT ────────────────────────────────────────────────────────────────── */
@media (max-width: 820px) {
  .cmd-detail { padding: var(--e-22) var(--e-18) var(--e-20); }
  .cmd-detail-corps { flex-direction: column; }
  .cmd-detail-g { flex: 1 1 auto; width: 100%; }
  .cmd-detail-photo { aspect-ratio: 4 / 3; }
  /* Six étapes sur 300 px sont illisibles : on ne garde que celle où on en est. */
  .cmd-parc-e:not(.ici) > b { font-size: 0; }
  .cmd-parc-e:not(.ici) > b::after { content: ''; }
  .cmd-detail-l { grid-template-columns: 104px 1fr; gap: var(--e-10); }
}

/* La note du pied pendant que le relevé se fait. ⚠️ Elle ne doit PAS être ambre comme
   « il manque… » : on ne sait pas encore s'il manque quelque chose. Un ton neutre qui
   respire, le temps que la lecture d'IndexedDB et l'aller-retour au VPS reviennent. */
.an-launch2-note.an-note-attend { color: var(--cok-text-3); }
.an-launch2-note.an-note-attend::after {
  content: '';
  display: inline-block; vertical-align: middle;
  width: 5px; height: 5px; margin-left: var(--e-8); border-radius: 50%;
  background: currentColor;
  animation: an-attend-pouls 1.15s ease-in-out infinite;
}
@keyframes an-attend-pouls { 0%, 100% { opacity: .25; } 50% { opacity: .9; } }
@media (prefers-reduced-motion: reduce) {
  .an-launch2-note.an-note-attend::after { animation: none; opacity: .6; }
}

/* ── Le parcours de création, à l'HORIZONTALE ────────────────────────────────
   Disposition validée par Amadou (09/08) : la frise en haut sur toute la largeur,
   sa fiche à gauche, l'écran à droite. En vertical, la frise mangeait une colonne
   entière en hauteur et écrasait les deux autres zones — chacune a maintenant la
   forme qui lui convient : la frise est linéaire, la fiche verticale, l'écran paysage. */
.cpf-zone { margin-top: var(--e-4); }
.cpf-tete { display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-18); flex-wrap: wrap; padding-bottom: var(--e-16); margin-bottom: var(--e-18);
  border-bottom: 1px solid var(--cok-border); }
.cpf-qui { font-size: var(--t-title); font-weight: var(--fw-fort); letter-spacing: -.3px; }
.cpf-sous { font-size: var(--t-base); color: var(--cok-text-3); margin-top: var(--e-4); }
/* ⚠️ PAR QUELLE SORTIE LE COMPTE NAÎT. C'est la décision la plus lourde du parcours —
   elle fixe l'IP pour toute la vie du compte — et elle n'était affichée nulle part.
   Elle prend les jetons de `.cpf-sous`, sa voisine de l'entête : même famille, rien de
   nouveau. L'adresse ressort en clair, le reste reste en retrait. */
.cpf-sortie { display: flex; align-items: baseline; gap: var(--e-8); flex-wrap: wrap;
  font-size: var(--t-base); color: var(--cok-text-3); margin-top: var(--e-6); }
.cpf-sortie b { color: var(--cok-text-2); font-weight: var(--fw-fort);
  font-variant-numeric: tabular-nums; }
.cpf-sortie i { font-style: normal; }
.cpf-pouls { display: inline-flex; align-items: center; gap: var(--e-8); font-size: var(--t-base);
  color: var(--cok-accent); background: var(--cok-accent-bg);
  padding: var(--e-8) var(--e-16); border-radius: var(--r-pilule); }
.cpf-pouls span { width: 7px; height: 7px; border-radius: 50%; background: currentColor;
  animation: cpfPuls 1.2s ease-in-out infinite; }
@keyframes cpfPuls { 0%,100% { opacity: 1 } 50% { opacity: .35 } }

.cpf-frise { background: var(--cok-card); border: 1px solid var(--cok-border);
  border-radius: var(--r-lg); padding: var(--e-20) var(--e-22) var(--e-16); margin-bottom: var(--e-18); }
.cpf { list-style: none; display: flex; margin: 0; padding: 0; }
.cpf-e { flex: 1; position: relative; display: flex; flex-direction: column;
  align-items: center; text-align: center; padding: 0 var(--e-6); cursor: default; }
/* Le trait de liaison passe DERRIÈRE les pastilles, d'un centre à l'autre. */
.cpf-e::before { content: ''; position: absolute; top: 11px; left: -50%; width: 100%;
  height: 1.5px; background: var(--cok-border); }
.cpf-e:first-child::before { display: none; }
.cpf-e.fait::before, .cpf-e.encours::before { background: rgba(99,214,176,.45); }
.cpf-p { position: relative; z-index: 1; width: 23px; height: 23px; border-radius: 50%;
  background: var(--bg-panel-solid); border: 1.5px solid var(--cok-border-2);
  display: flex; align-items: center; justify-content: center; margin-bottom: var(--e-10); }
.cpf-p svg { width: 11px; height: 11px; fill: none; stroke: currentColor; stroke-width: 2.6; }
.cpf-e.fait .cpf-p { border-color: var(--cok-green); color: var(--cok-green); }
.cpf-e.encours .cpf-p { border-color: var(--cok-accent); color: var(--cok-accent);
  box-shadow: 0 0 0 5px rgba(var(--th-accent-rgb),.14); }
.cpf-e.bloque .cpf-p { border-color: var(--cok-red); color: var(--cok-red); }
.cpf-e.avenir .cpf-p { opacity: .45; }
.cpf-n { font-size: var(--t-base); font-weight: var(--fw-moyen); line-height: var(--lh-serre); }
.cpf-e.avenir .cpf-n { color: var(--cok-text-3); font-weight: var(--fw-normal); }
.cpf-e.encours .cpf-n { color: var(--cok-accent); }
.cpf-e.bloque .cpf-n { color: var(--cok-red); }
.cpf-h { font-style: normal; font-size: var(--t-meta); color: var(--cok-text-3); margin-top: var(--e-4); }
.cpf-dit { font-size: var(--t-base); line-height: var(--lh-normal); color: var(--cok-text-2);
  margin: var(--e-18) 0 0; padding-top: var(--e-16); border-top: 1px solid var(--cok-border); }
.cpf-dit b { color: var(--cok-text); font-weight: var(--fw-fort); }
.cpf-dit.rate, .cpf-dit.rate b { color: var(--cok-red); }

/* ⚠️ L'ÉCRAN PREND LES DEUX TIERS : c'est lui qu'on regarde en attendant, et il est
   paysage. Sa fiche tient dans le tiers restant — elle dit QUI, pas OÙ. */
/* ⚠️⚠️ SA FICHE NE CHANGE JAMAIS DE CÔTÉ. Elle est à droite au repos ; je la faisais
   passer à gauche pendant la création, et elle se téléportait d'un bord à l'autre au
   moment de la bascule — Amadou (09/08) : « ça fait un bug ». Une carte qui saute d'un
   côté à l'autre, aucune animation ne la rendra fluide : il faut qu'elle ne bouge pas.
   L'écran prend donc la gauche, sur les deux tiers, et elle garde sa colonne. */
.cpf-grid { display: grid; grid-template-columns: minmax(0,1.9fr) minmax(0,1fr);
  gap: var(--e-18); align-items: start; }
.cpf-fiche > * { margin-top: 0 !important; }
.cpf-ecran > * { margin: 0 !important; width: 100% !important; max-width: none !important; }
/* ⚠️ L'ÉCRAN S'ALIGNE SUR LA HAUTEUR DE SA FICHE. Amadou (09/08). Il s'étirait à sa
   guise et dépassait la colonne d'à côté : deux blocs voisins de hauteurs différentes,
   c'est ce qui donnait l'impression que tout se marchait dessus. L'image se contient à
   l'intérieur au lieu de pousser la carte. */
.cpf-grid { align-items: stretch; }
.cpf-ecran { display: flex; flex-direction: column; max-height: 460px; overflow: hidden; }
.cpf-ecran > * { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.cpf-ecran img { width: 100% !important; height: 100% !important; object-fit: contain;
  display: block; border-radius: var(--r-md); }
/* Sa fiche reste un repère, pas une lecture : photos plafonnées, texte resserré. */
.cpf-fiche .cok-horlo-vues > * { aspect-ratio: 3/4; height: auto; max-height: 150px;
  object-fit: cover; border-radius: var(--r-sm); }
.cpf-fiche .cok-horlo-bio { max-height: 104px; overflow: auto; }

@media (max-width: 900px) {
  .cpf-grid { grid-template-columns: 1fr; }
  .cpf { overflow-x: auto; padding-bottom: var(--e-6); }
  .cpf-e { min-width: 110px; }
}

/* « Actualiser » sous la frise : discret, mais toujours atteignable. */
/* ⚠️ LES DEUX BOUTONS ONT LA MÊME FACTURE. Ils avaient chacun leurs propres règles :
   marges, fonds et bordures différents, donc deux tailles pour deux gestes de même
   rang. Une seule règle les gouverne maintenant ; seule la COULEUR au survol les
   distingue — « Abandonner » vire au rouge, parce qu'il est sans retour. */
/* ⚠️ « Créer un autre compte » REJOINT LA FAMILLE, il ne se redessine pas. Posé nu,
   il sortait en gris de navigateur avec du texte noir sur un fond sombre — la faute
   qu'on refait chaque fois qu'on ajoute un bouton sans regarder ses voisins. */
.cpf-relire, .cpf-abandon, .cpf-fermer { font: inherit; font-size: var(--t-base); line-height: var(--lh-un);
  cursor: pointer; padding: var(--e-10) var(--e-18); border-radius: var(--r-pilule);
  background: var(--cok-bg-2); border: 1px solid var(--cok-border);
  color: var(--cok-text-2);
  transition: border-color var(--t-bref), color var(--t-bref); }
.cpf-relire:hover, .cpf-fermer:hover { border-color: var(--cok-border-2); color: var(--cok-text); }
.cpf-relire:disabled, .cpf-abandon:disabled { opacity: .55; cursor: default; }

.cpf-actions { display: flex; gap: var(--e-10); margin-top: var(--e-14); flex-wrap: wrap; }
/* ⚠️ « Abandonner » est en retrait, pas en rouge vif : il ne doit pas attirer le clic.
   Sa couleur de danger n'apparaît qu'au survol, quand l'intention est déjà là. */
.cpf-abandon:hover { color: var(--cok-red); border-color: rgba(var(--th-danger-rgb),.45); }

/* ── L'ÉTAPE QU'ON OUVRE, ET LE BOUTON QUI LA REJOUE ──────────────────────────
   Amadou (15/08) : « si j'appuie sur transfert d'identité, par exemple, que ça
   déclenche — c'est un peu une mesure de sécurité. »
   ⚠️ DEUX CLICS, PAS UN. Le premier ouvre l'étape et dit ce qu'elle va faire, le
   second lance. Un clic unique, sur une frise qu'on parcourt du regard, ce serait
   déclencher une écriture sur Vinted en visant mal — l'inverse d'une sécurité.
   ⚠️ Le bouton EMPRUNTE `.v-btn--pri`, il ne se réinvente pas une apparence : c'est
   la règle de la bibliothèque, et c'est ce qui fait qu'il suit les onze thèmes. */
.cpf-e { cursor: pointer; }
/* ⚠️⚠️ `:not(.bloque)` N'EST PAS UN DÉTAIL. Mesuré dans le navigateur : sur l'étape
   ouverte ET bloquée, le nom ressortait en rgb(238,240,247) — le gris clair normal —
   au lieu du rouge. `.cpf-e.bloque .cpf-n` est écrite PLUS HAUT, à force égale (0,2,0) :
   la dernière écrite gagne, et c'était la mienne. Exactement le défaut que cette
   feuille a déjà payé plusieurs fois. Ouvrir une étape ne doit rien dire sur son état. */
.cpf-e.ouverte:not(.bloque) .cpf-n { color: var(--cok-text); }
.cpf-e.ouverte .cpf-p { box-shadow: 0 0 0 3px rgba(var(--th-accent-rgb),.18); }
.cpf-detail { display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-16); flex-wrap: wrap; margin-top: var(--e-14);
  padding: var(--e-12) var(--e-14); border-radius: var(--r-md);
  border: 1px solid var(--cok-line); background: var(--cok-bg-2); }
.cpf-detail-txt { display: flex; flex-direction: column; gap: var(--e-4);
  min-width: 0; flex: 1 1 240px; }
.cpf-detail-txt b { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--cok-text); }
.cpf-detail-txt span { font-size: var(--t-meta); line-height: var(--lh-normal); color: var(--cok-text-3); }
.cpf-detail-txt i { font-style: normal; font-size: var(--t-meta); line-height: var(--lh-normal);
  color: var(--cok-text-2); }
.cpf-nonlancable { font-size: var(--t-meta); line-height: var(--lh-normal);
  color: var(--cok-text-3); max-width: 30ch; }

/* « Relancer » sur la ligne d'une vendeuse en formation. Discret : le geste normal est
   que la formation tourne seule. Il n'apparaît en clair qu'au survol de sa ligne. */
.form-ligne-relance { font: inherit; font-size: var(--t-meta); line-height: var(--lh-un);
  cursor: pointer; padding: var(--e-6) var(--e-12); border-radius: var(--r-pilule);
  background: transparent; border: 1px solid var(--cok-border); color: var(--cok-text-3);
  white-space: nowrap; opacity: .55; transition: opacity var(--t-bref), color var(--t-bref); }
.form-ligne:hover .form-ligne-relance { opacity: 1; }
.form-ligne-relance:hover { color: var(--cok-text); border-color: var(--cok-border-2); }
.form-ligne-relance:disabled { opacity: .4; cursor: default; }
.form-ligne-relance-vide { display: inline-block; }

/* La taille que la flotte réclame : un repère sur le bouton, pas une sélection.
   Le choix reste celui du gabarit lu sur sa photo — voir le commentaire dans app.js. */
.src-gab.manque { border-color: var(--cok-accent); color: var(--cok-accent); }
.src-gab.manque.on { border-color: var(--cok-accent); }
.mdl-quota { margin-top: var(--e-8); }

/* ── LA COMPOSITION DE LA FLOTTE ──────────────────────────────────────────────
   Une ligne par taille : sa part atteinte en barre, un trait vertical à l'objectif.
   ⚠️ La couleur ne porte pas seule le sens — le compte et l'objectif sont écrits à
   côté. Une barre qui dépasse son trait se voit sans qu'on lise la teinte. */
.cok-tailles { margin-top: var(--e-20); }

/* ⚠️ Défaut préexistant, même cause : 2,96 sur Médina. */
.tai-l.vise 

/* ⚠️ RETIRÉ : la ligne visée peignait AUSSI sa barre en accent. Depuis le simulateur,
   l'accent désigne le segment « à créer » — deux sens pour une couleur, et on ne lit
   plus rien. La ligne visée reste marquée par sa lettre. */
/* ⚠️ LE TRAIT D'OBJECTIF NE PEUT PAS PORTER LE MÊME JETON QUE LE REMPLISSAGE. Il se
   pose PAR-DESSUS la barre : partout où l'objectif tombe dans la partie déjà remplie,
   deux `--cok-text-3` l'un sur l'autre font un écart de 1,00 — le trait n'existe plus,
   et c'est justement là qu'il compte (la taille est en excédent). Il prend donc le
   texte le plus fort, qui se détache et de la piste et du remplissage. */

.tai-suite { margin-top: var(--e-14); }

/* ══ LA COMPOSITION DE LA FLOTTE — version SOBRE ══════════════════════════════
   Amadou (15/08) : « visuellement c'est vraiment moche, il faut penser à comment on
   pourrait présenter d'une meilleure façon ». Il a choisi la sobre : une lettre, une
   barre, un chiffre. Sont SUPPRIMÉS — la bascule Comptes/%, l'en-tête de colonnes, la
   quatrième colonne et la sous-carte du simulateur. Le pourcentage, lui, est
   désormais TOUJOURS écrit : un bouton pour révéler un nombre de quatre caractères
   coûtait plus cher que le nombre lui-même.

   ⚠️⚠️ LA GOUTTIÈRE ÉTAIT INVISIBLE, ET C'ÉTAIT ÇA, LE « MOCHE ».
   `.tai-b` était peinte avec `--cok-bg-2`, qui vaut `--surface-2` dans la portée du
   cockpit — c'est-à-dire EXACTEMENT `--cok-card`, la couleur de la carte qui la porte.
   Mesuré le 15/08 : contraste piste / carte = 1,00 dans les seize thèmes. La partie
   vide de chaque barre n'existait donc pas à l'œil : XS, qui occupe 8 % de sa piste,
   ne ressemblait pas à une jauge presque vide mais à un trait posé dans le vide.
   `--surface-3` (le barreau juste en dessous dans l'échelle des surfaces, et qui suit
   le même multiplicateur `--th-surface-force`) donne 1,26 à 1,58 selon le thème, tout
   en restant à 3,51 du remplissage. Mesuré meilleur que `--border` (1,06),
   `--bg-elevated` (1,13) et `--bg-hover` (1,11). */
/* ⚠️⚠️ UNE SEULE GRILLE POUR LES CINQ LIGNES, et pas cinq grilles d'une ligne. Des
   colonnes de grille ne s'alignent QU'À L'INTÉRIEUR d'une même grille : tant que chaque
   ligne était sa propre grille, une colonne `auto` se dimensionnait sur SON contenu et
   les cinq barres s'arrêtaient à cinq abscisses différentes. Il fallait donc figer les
   largeurs — ce qui débordait dès que les nombres grandissaient (à 2000 comptes
   simulés, M en porte 707).
   Avec `display: contents` sur les lignes, les vingt-cinq cellules vivent dans la MÊME
   grille : les colonnes se dimensionnent sur la plus large de toutes, et l'alignement
   tient à n'importe quelle échelle. */
.tai-liste { display: grid;
  grid-template-columns: var(--e-28) minmax(0,1fr) minmax(var(--e-24),auto)
                         minmax(var(--e-40),auto) minmax(var(--e-24),auto);
  row-gap: var(--e-10); column-gap: var(--e-12); align-items: center;
  margin-top: var(--e-16); }
.tai-l { display: contents; }
.tai-n { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--cok-text-2);
  font-variant-numeric: tabular-nums; }
.tai-l.vise .tai-n { color: var(--th-accent-clair); }

.tai-b { position: relative; height: var(--e-10); border-radius: var(--r-pilule);
  background: var(--surface-3); }
/* ⚠️ LES TROIS COUCHES SE DISTINGUENT PAR LA FORME, PAS PAR LA TEINTE — deux couleurs
   ne survivent pas à seize palettes (mesuré : 1,03 d'écart sur Nimbe et Lanternes).
   La flotte est un aplat, « à créer » est une TEXTURE, l'objectif est un TRAIT. */
.tai-b i, .tai-b b { position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  border-radius: var(--r-pilule);
  transition: width var(--t-moyen) var(--c-pose), left var(--t-moyen) var(--c-pose),
              opacity var(--t-bref) var(--c-pose); }
.tai-b i { background: var(--cok-text-3); }
.tai-b b { background: repeating-linear-gradient(115deg,
    var(--cok-accent) 0 var(--e-6), var(--surface-3) var(--e-6) var(--e-8)); }
.tai-b b.vide { opacity: 0; }
/* Le trait déborde en haut et en bas : c'est ce qui le sauve là où il tombe DANS la
   partie pleine — sur le seul fond de la barre, il ne ferait que 1,58 sur Médina. */
.tai-b u { position: absolute; top: calc(var(--e-4) * -1); bottom: calc(var(--e-4) * -1);
  width: var(--e-2); background: var(--cok-text); border-radius: var(--e-1);
  text-decoration: none; transition: left var(--t-moyen) var(--c-pose); }

.tai-ct, .tai-pc, .tai-d { text-align: right; white-space: nowrap;
  font-size: var(--t-base); font-variant-numeric: tabular-nums; }
.tai-ct { font-weight: var(--fw-fort); color: var(--cok-text); }
.tai-pc { color: var(--cok-text-3); }
/* ⚠️ PAS DE VERT QUAND C'EST BON. L'équilibre est l'état NORMAL : le peindre en vert
   mettrait quatre lignes sur cinq en couleur et on ne verrait plus celle qui cloche. */
.tai-pc.trop { color: var(--cok-amber); }
.tai-pc.peu  { color: var(--th-accent-clair); }
/* ⚠️ PAS de `:empty { display: none }` — la colonne doit GARDER sa place quand il n'y
   a rien à créer, sinon les quatre autres se décalent dès qu'une ligne se remplit. */
.tai-d { font-style: normal; font-weight: var(--fw-fort); color: var(--th-accent-clair); }

/* ══ LE CURSEUR — enfin dessiné ═══════════════════════════════════════════════
   ⚠️⚠️ C'ÉTAIT LE SEUL OBJET DE L'ÉCRAN QUE PERSONNE N'AVAIT DESSINÉ. Il n'existait
   AUCUN `::-webkit-slider-thumb` dans les 23 000 lignes de cette feuille : la poignée
   et la piste étaient celles de Chrome, teintées au seul `accent-color`. Sur Nimbe ça
   donnait un pouce brun sur une piste système grise, au milieu d'un écran fait main.
   ⚠️ Il reste un VRAI <input type="range">. Le refaire en <div>, comme l'écran
   Modèles, coûterait le clavier, les lecteurs d'écran et la capture du pointeur —
   trois choses qu'un input natif donne gratuitement et qu'on rate en les réécrivant. */
.tai-cur { margin-top: var(--e-16); }
.tai-cur input[type="range"] { -webkit-appearance: none; appearance: none;
  width: 100%; background: transparent; cursor: pointer; margin: 0; display: block; }
.tai-cur input[type="range"]::-webkit-slider-runnable-track {
  height: var(--e-6); border-radius: var(--r-pilule); background: var(--surface-3); }
.tai-cur input[type="range"]::-moz-range-track {
  height: var(--e-6); border-radius: var(--r-pilule); background: var(--surface-3); }
.tai-cur input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none;
  width: var(--e-16); height: var(--e-16); border-radius: 50%;
  background: var(--cok-accent); border: var(--e-2) solid var(--cok-card);
  margin-top: calc((var(--e-16) - var(--e-6)) / -2);
  transition: transform var(--t-bref) var(--c-pose); }
.tai-cur input[type="range"]::-moz-range-thumb {
  width: var(--e-16); height: var(--e-16); border-radius: 50%; box-sizing: border-box;
  background: var(--cok-accent); border: var(--e-2) solid var(--cok-card);
  transition: transform var(--t-bref) var(--c-pose); }
.tai-cur input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.14); }
.tai-cur input[type="range"]:hover::-moz-range-thumb { transform: scale(1.14); }
.tai-cur input[type="range"]:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 var(--e-4) var(--cok-accent-bg); }
.tai-cur input[type="range"]:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 var(--e-4) var(--cok-accent-bg); }
.tai-cur input[type="range"]:focus { outline: none; }
.tai-cur-l { display: flex; align-items: baseline; gap: var(--e-8);
  margin-top: var(--e-8); font-size: var(--t-meta); color: var(--cok-text-3); }
.tai-cur-f { margin-left: auto; }
/* ⚠️ LE NOMBRE SE TAPE, et c'est ça la réponse à « je dois pouvoir monter à l'infini » :
   un curseur a forcément une fin, un champ non. Il ne s'ajoute à rien — il REMPLACE le
   nombre qui était déjà écrit là, donc l'écran ne gagne aucun objet. */
.tai-cur-q { display: inline-flex; align-items: baseline; gap: var(--e-6); cursor: text; }
/* ⚠️ Largeur unique, calée sur le pire cas : six chiffres en tabulaire à --t-base
   tiennent tout juste dans --e-48. Pas de `field-sizing`, que Chrome connaît seul. */
.tai-cur-n { width: var(--e-48); padding: var(--e-2) var(--e-6); text-align: right;
  font-family: inherit; font-size: var(--t-base); font-weight: var(--fw-fort);
  font-variant-numeric: tabular-nums; color: var(--cok-text);
  background: var(--surface-3); border: var(--e-1) solid transparent;
  border-radius: var(--r-xs); transition: var(--transi); }
.tai-cur-n:hover { border-color: var(--cok-border-2); }
.tai-cur-n:focus { outline: none; border-color: var(--cok-accent);
  background: var(--cok-accent-bg); }

/* ⚠️ Le mouvement réduit coupe TOUT : c'est un réglage système, pas une préférence
   qu'on négocie. Les valeurs se posent d'un coup, elles ne disparaissent pas. */
@media (prefers-reduced-motion: reduce) {
  .tai-b i, .tai-b b, .tai-b u,
  .tai-cur input[type="range"]::-webkit-slider-thumb { transition: none; }
}

/* Sous le bouton de création : pas de carte dans la carte — un simple bloc séparé
   d'un filet, avec la conclusion en tête et le détail dessous. */
/* ══ LA RÉPARTITION EN FRISE ══════════════════════════════════════════════════
   Amadou (20/08) : « je veux qu'elle soit indiquée sous forme de frise pareil ».
   Cinq colonnes côte à côte au lieu de cinq lignes empilées : la répartition se lit
   d'un coup d'œil, à la même place et à la même largeur que le chemin des étapes
   juste dessous. On ne change QUE la mise en page — les mêmes cellules, les mêmes
   barres, les mêmes chiffres. */
.tai-bande { margin-bottom: var(--e-16); }

/* Le formulaire de branchement d'une sortie : deux champs côte à côte, qui s'empilent
   quand la carte se resserre. On emprunte les encadrés de l'écran Créer — même dessin,
   rien de neuf à apprendre. */
/* Le bouton d'ajout, en tête du parc — un geste rare mérite un bouton, pas un
   formulaire posé en permanence. */
.mac-ajout { display: flex; justify-content: flex-end; margin-bottom: var(--e-12); }

/* ══ LES SORTIES SONT DES CARTES ══════════════════════════════════════════════
   Amadou (20/08) : « au niveau de ses sorties, ça doit être sous forme de card, et
   quand j'appuie dessus ça ouvre l'espace du proxy ». Une sortie est un objet qu'on
   ouvre — comme une machine. Deux choses de même nature se lisent et se manipulent
   pareil, sinon on hésite à chaque fois. */
.mac-sectete { display: flex; align-items: baseline; gap: var(--e-12);
  margin-bottom: var(--e-12); }
.mac-sectete .cok-launch-title { flex: 0 0 auto; }
.mac-seccpt { flex: 1 1 auto; font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-sgrille { display: grid; gap: var(--e-12);
  grid-template-columns: repeat(auto-fit, minmax(calc(var(--e-48) * 4), 1fr)); }
.mac-scarte { display: flex; flex-direction: column; gap: var(--e-6);
  padding: var(--e-14); border: 1px solid var(--border); border-radius: var(--r-carte);
  background: var(--cok-bg); text-align: left; color: inherit; font: inherit;
  cursor: pointer; transition: border-color var(--t-bref) var(--c-pose); }
.mac-scarte:hover { border-color: var(--violet-mid); }
.mac-scarte .sn { font-size: var(--t-mini); color: var(--cok-text-3);
  letter-spacing: var(--ls-large); text-transform: uppercase; }
.mac-scarte .sadr { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-meta); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⚠️ ON ÉTEND LE SÉLECTEUR, ON NE RECOPIE PAS LA RÈGLE. La rangée « valeur · libellé ·
   pourcentage » existait déjà, mais scopée à la carte du niveau 2 ; l'écran d'une sortie
   en a besoin du même. Recopier aurait donné deux rangées qui divergent au premier
   ajustement — c'est la faute la plus répétée du projet. Même geste que `.danger`, dont
   les quatre noms ont été réunis en une règle. */
.mac-scarte .srow, .mac-tu .srow { display: flex; align-items: baseline; gap: var(--e-8); }
.mac-scarte .srow b, .mac-tu .srow b { font-size: var(--t-lead); font-weight: var(--fw-moyen); }
.mac-scarte .srow .u, .mac-tu .srow .u { flex: 1 1 auto; font-size: var(--t-mini); color: var(--cok-text-3); }
.mac-scarte .srow .pc, .mac-tu .srow .pc { font-size: var(--t-mini); color: var(--cok-text-2); }
.mac-scarte .srow .pc.am, .mac-tu .srow .pc.am { color: var(--cok-amber); }
.mac-scarte .jauge { height: var(--e-6); border-radius: var(--r-pilule);
  background: var(--bg-elevated); overflow: hidden; }
.mac-scarte .jauge i { display: block; height: 100%; background: var(--cok-green);
  transition: width var(--t-long) var(--c-pose); }
.mac-scarte .jauge i.am { background: var(--cok-amber); }
/* ⭐⭐ L'ÉTAT D'UNE SORTIE. Il se lit à la FORME autant qu'à la teinte : la pastille
   `.mac-pt` porte déjà les trois tons du site, on l'emprunte au lieu d'en refaire une.
   ⚠️ L'âge du verdict est en retrait — il ne doit pas concurrencer l'état lui-même,
   mais il doit être là : « elle répond » sans depuis-quand, c'est ce qui a laissé une
   sortie morte passer pour saine pendant six jours. */
.mac-scarte .setat { display: flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-mini); color: var(--cok-text-2); }
.mac-scarte .setat b { font-weight: var(--fw-moyen); }
.mac-scarte .setat u { text-decoration: none; color: var(--cok-text-3);
  margin-left: auto; white-space: nowrap; }
.mac-scarte .setat.no b { color: var(--cok-red, var(--red)); }
.mac-scarte .setat.am b { color: var(--cok-amber); }

/* La place libre : un pointillé, parce que ce n'est pas encore une sortie. */
.mac-scarte.neuve { border-style: dashed; align-items: center; justify-content: center;
  color: var(--cok-text-3); font-size: var(--t-meta); }
.mac-scarte.neuve:hover { color: var(--th-accent-clair); }

/* ══ UNE CAPACITÉ SE RÈGLE SUR PLACE ══════════════════════════════════════════
   Amadou (20/08) : « je dois pouvoir en temps réel changer le nombre de comptes par
   proxy — la même chose pour le VDS ». Rouvrir un panneau pour changer un nombre qu'on
   a sous les yeux, c'est trois gestes pour un chiffre. Le champ vit là où le chiffre
   se lit ; il s'enregistre quand la main s'arrête. */
/* ⚠️⚠️ UN NOMBRE DE DEUX CHIFFRES SE LIT DANS LA PHRASE. Amadou (20/08) : « ces boutons
   pour sélectionner le nombre de comptes, c'est trop grand pour rien et ce n'est pas
   esthétique » — puis « tu peux le caler au-dessus, franchement c'est tout petit ».
   Le champ vit maintenant DANS la ligne de titre (« peut tenir [12] comptes ») : il ne
   prend que sa largeur, il n'a plus de flèches (voir `data-sans-pas` côté script), et il
   se lit comme le reste de la phrase. */
.mac-cap { display: inline-flex; align-items: baseline; gap: var(--e-4); }
.mac-cap .lb { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-cap input { width: calc(var(--e-20) * 2); text-align: center;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--r-xs); padding: var(--e-1) var(--e-4);
  color: var(--cok-text); font: inherit; font-size: var(--t-meta);
  font-variant-numeric: tabular-nums;
  transition: border-color var(--t-bref) var(--c-pose); }
.mac-cap input:hover { border-color: var(--border-strong); }
.mac-cap input:focus { outline: none; border-color: var(--violet-mid); }
.mac-cap-dit { font-size: var(--t-mini); color: var(--cok-text-3); }

/* Poser une sortie : le geste et sa consequence, cote a cote. */
/* La barre d'actions d'une sortie : une ligne, des libellés courts, et un seul mot
   d'explication dessous. Avant : quatre paragraphes éparpillés entre les boutons. */
.mac-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-8);
               margin-top: var(--e-20); padding-top: var(--e-16);
               border-top: 1px solid var(--border); }
/* ⚠️ « Poussé à droite » devient « étiré » sur un écran large : mesuré, 363 px de vide
   entre le dernier bouton et « Retirer ». C'est le reproche déjà fait sur la bande
   d'une commande. Un écart FRANC vaut mieux qu'un rejet au bord. */
.mac-actions .danger { margin-left: var(--e-24); }
.mac-actions-mot { display: flex; flex-wrap: wrap; gap: var(--e-4) var(--e-12);
                   margin-top: var(--e-10); }
/* Les retours de bouton ne gardent pas de place tant qu'ils n'ont rien à dire. */
.mac-actions-mot .mac-k:empty { display: none; }
/* ⚠️⚠️ PAS DE QUATRIÈME NOM POUR « BOUTON ROUGE ». J'avais écrit `.dang` — le site
   en connaissait déjà trois (`.danger`, `.src-px-danger`, `.v-btn--danger`), et la
   règle de survol (ligne 1855) ne protège que les deux premiers. Mon bouton perdait
   donc son rouge AU MOMENT PRÉCIS où on met la souris dessus, mesuré : texte blanc,
   liseré violet — l'apparence d'un bouton ordinaire. Le rouge est un SENS, pas une
   décoration. On emprunte `.danger`, qui existe et qui est déjà protégé. */

/* ══ CINQUANTE COMPTES SANS DÉFILER ═══════════════════════════════════════════
   Amadou (20/08) : « on part du principe qu'il y en a vingt-cinq, cinquante — je vais
   devoir scroller pendant dix mille minutes ». Une ligne fait trente pixels : cinquante
   comptes, c'est un écran et demi pour trouver celui qui cloche. Une case en fait
   vingt-six — cinquante tiennent en trois rangées. La couleur porte l'information, le
   survol donne le pseudo, et seule la liste des comptes À TRAITER reste écrite. */
.mac-puces { display: flex; flex-wrap: wrap; gap: var(--e-4); margin: var(--e-6) 0 var(--e-10); }
/* ⚠️ MÊME FAMILLE QUE LA PASTILLE : mêmes couples fond-doux / texte-vif, même arrondi
   de pilule. Une case est une pastille carrée — pas un objet d'une autre planète. */
.mac-puce { width: var(--e-28); height: var(--e-28); border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-micro); font-weight: var(--fw-moyen);
  line-height: var(--lh-un);
  background: var(--bg-elevated); color: var(--cok-text-3); }
/* ⚠️⚠️ FOND DOUX, TEXTE VIF — PAS L'INVERSE. J'avais posé la couleur pleine avec
   `--th-sur-accent` par-dessus : le vérificateur a signalé les trois cases sur-le-champ.
   `--sur-accent` veut dire « ce qui s'écrit sur L'ACCENT », pas « du blanc » — sur un
   fond vert ou ambre il ne garantit rien, et il change de sens d'un thème à l'autre.
   Le couple fond-doux / texte-vif est celui que le site utilise déjà partout (les
   pastilles d'état) : il est mesuré sur les seize thèmes. On l'emprunte. */
/* Un contour, pas un fond plein : la case se lit d'un coup d'œil sans hurler. */
.mac-puce { border: 1px solid var(--border); background: var(--cok-bg); }
.mac-puce.ok { border-color: var(--cok-green); color: var(--cok-green); background: var(--cok-green-bg); }
.mac-puce.am { border-color: var(--cok-amber); color: var(--cok-amber); background: var(--cok-warn-bg); }
.mac-puce.rd { border-color: var(--cok-red);   color: var(--cok-red);   background: var(--cok-red-bg); }
/* ⚠️ LA MARGE HAUTE EST À ELLE, PAS À SON VOISIN. Elle n'était espacée que par le
   `margin-bottom` de `.mac-puces` : le jour où la grille ne s'affiche pas (une sortie
   sans compte), la légende venait se coller à la barre du dessus. Un espacement qui
   dépend de la présence d'un autre bloc casse dès que ce bloc disparaît. */
.mac-legende { display: flex; flex-wrap: wrap; gap: var(--e-14);
  font-size: var(--t-mini); color: var(--cok-text-3);
  margin-top: var(--e-12); margin-bottom: var(--e-16); }
.mac-legende i { display: inline-block; width: var(--e-8); height: var(--e-8);
  border-radius: var(--r-micro); margin-right: var(--e-4);
  background: var(--bg-elevated); vertical-align: -1px; }
/* La légende, elle, n'a pas de texte dessus : la couleur pleine y est juste. */
.mac-legende i.ok { background: var(--cok-green); }
.mac-legende i.am { background: var(--cok-amber); }
.mac-legende i.rd { background: var(--cok-red); }

/* Le panneau : ses champs, son message, ses deux boutons. */
/* Panneau Machines : assez large pour qu'une ligne de proxy tienne d'un seul tenant.
   On reprend la largeur de la fenêtre Paramètres — deux panneaux de même nature se
   lisent pareil — sans sa hauteur fixe : ce panneau n'a que deux champs. */
.modal-card--mac { width: 680px; max-width: 94vw; }
/* ⚠️ LE VIDE VENAIT D'ICI. `.pa-body` impose 540 px de haut — c'est juste pour la
   fenêtre Paramètres, dont les volets sont longs. Ce panneau-ci fait trois quarts de
   ça : le reste était du vide sous les boutons. Il prend la hauteur de son contenu. */
#modal-mac .pa-body { display: flex; flex-direction: column; gap: var(--e-20);
                      height: auto; max-height: 82vh; padding: var(--e-8) var(--e-22) var(--e-20); }
/* Un sous-titre absent ne doit pas garder sa place : sinon il pousse tout d'un cran. */
#modal-mac #mac-pan-sous:empty, #modal-mac #mac-pan-dit:empty { display: none; }
/* ⚠️ L'ÉCART DU PANNEAU NE SÉPARAIT RIEN. Le compte, l'avertissement et les choix
   vivent dans UN seul bloc (`#mac-pan-champs`, écrit d'un coup en innerHTML) : le
   `gap` du corps ne joue qu'ENTRE les blocs, jamais à l'intérieur. Les trois idées se
   touchaient donc, quel que soit l'air donné au-dessus. */
#modal-mac #mac-pan-champs { display: flex; flex-direction: column; gap: var(--e-16); }
#modal-mac #mac-pan-champs > p { margin: 0; }
#modal-mac .cok-raf-champ { flex: 1 1 auto; }
.mac-pan-dit { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-pan-pied { display: flex; justify-content: flex-end; gap: var(--e-8);
               margin-top: var(--e-4); padding-top: var(--e-16);
               border-top: 1px solid var(--border); }

/* ══ LA RÉPARTITION SE REPLIE ═════════════════════════════════════════════════
   Amadou (20/08) : « elle prend trop de place. Le mieux serait de la condenser,
   d'avoir la possibilité de la dérouler. » Repliée, elle tient sur UNE ligne : une
   barre où les cinq tailles se partagent la largeur au prorata, et la phrase qui dit
   ce que cette création va faire. Le détail est à un clic, et le pli se souvient. */
.tai-pli { display: flex; align-items: center; gap: var(--e-12); width: 100%;
  padding: var(--e-8) var(--e-10); border: 1px solid var(--border);
  border-radius: var(--r-lg); background: var(--cok-bg); cursor: pointer;
  text-align: left; color: inherit; font: inherit;
  transition: border-color var(--t-bref) var(--c-pose),
              background var(--t-bref) var(--c-pose); }
.tai-pli:hover { border-color: var(--violet-mid); }
.tai-pli .tai-suite { flex: 1 1 auto; min-width: 0; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* La barre condensée : cinq parts d'un même trait. On la distingue du détail par sa
   finesse — c'est un résumé, pas une mesure qu'on lit au chiffre près. */
.tai-mini { flex: 0 0 34%; display: flex; height: var(--e-8);
  border-radius: var(--r-pilule); overflow: hidden; background: var(--bg-elevated); }
.tai-mini i { display: block; height: 100%; background: var(--cok-text-3);
  border-right: var(--e-1) solid var(--cok-bg);
  transition: width var(--t-long) var(--c-pose); }
.tai-mini i:last-child { border-right: 0; }
/* La taille que CETTE création va prendre : la seule qui porte l'accent. */
.tai-mini i.vise { background: var(--th-accent-clair); }
.tai-chev { flex: 0 0 auto; color: var(--cok-text-3);
  transition: transform var(--t-moyen) var(--c-pose); }
.tai-pli.ouvert .tai-chev { transform: rotate(180deg); }
.tai-detail[hidden] { display: none; }
.tai-crea .tai-detail { margin-top: var(--e-12); }
@media (prefers-reduced-motion: reduce) {
  .tai-mini i, .tai-chev { transition: none; }
}
.tai-crea { margin-top: 0; padding-top: 0; border-top: 0; }
.tai-crea .tai-suite { margin-top: var(--e-10); }
.tai-crea .tai-liste { display: flex; gap: var(--e-10); margin-top: 0; align-items: stretch; }
/* ⚠️ `display: contents` sert à faire vivre les 25 cellules dans UNE grille commune,
   pour que les cinq barres s'arrêtent à la même abscisse. En frise, chaque taille est
   au contraire une colonne à elle : on redonne donc une boîte à la ligne. */
.tai-crea .tai-l { display: flex; flex-direction: column; align-items: center;
  gap: var(--e-4); flex: 1 1 0; min-width: 0; }
.tai-crea .tai-b { width: 100%; }
.tai-crea .tai-ct, .tai-crea .tai-pc, .tai-crea .tai-d { text-align: center; }
.tai-crea .tai-n { font-size: var(--t-mini); letter-spacing: var(--ls-large); }
.tai-crea .tai-ct { font-size: var(--t-small); }
/* La taille visée par CETTE création se distingue par un trait sous sa colonne — la
   couleur seule ne suffit pas : sur seize thèmes, deux accents voisins se confondent. */
.tai-crea .tai-l.vise { border-bottom: var(--e-2) solid var(--th-accent-clair);
  padding-bottom: var(--e-6); }
.tai-crea 

/* ══════════════════════════════════════════════════════════════════════════════
   MACHINES — la machine d'abord, ses comptes au clic.
   ⚠️ Aucune couleur ne porte seule un sens : « annoncé, muet » est écrit en toutes
   lettres à côté du chiffre. Un écran de diagnostic qu'il faut décoder n'en est pas un.
   ══════════════════════════════════════════════════════════════════════════════ */
.mac-liste { display: flex; flex-direction: column; gap: var(--e-12); }
/* ── UNE CARTE PAR MACHINE, ET AUCUN RANG ─────────────────────────────────────
   Amadou (15/08) : « oubliez l'histoire de parc principal ou de second parc, ils sont
   tous égaux » et « plus tard j'en aurai vraiment beaucoup ».
   Les cartes sont donc IDENTIQUES — rien dans le dessin ne dit que l'une compte plus
   qu'une autre — et la grille se remplit toute seule. ⚠️ Les comptes ne s'ouvrent PAS
   dans la carte : ils s'affichent sous la grille. Vingt cartes qui se déplient font
   vingt écrans, et on ne retrouve plus celle qu'on regardait. */
/* ── LA BARRE DES SOUS-ONGLETS ────────────────────────────────────────────────
   Amadou (15/08) : « l'overlay doit être arrondie… je sais que pour le thème volcanique
   ce n'est pas arrondi, sauf que là ça doit être arrondi. »
   ⚠️ C'est pour ça qu'elle prend `--r-pilule` et PAS `--r-lg`. Les onze thèmes
   redéfinissent le rayon — l'un d'eux descend à 4 px — et cette barre-là doit rester
   ronde partout. Un jeton de rayon aurait suivi le thème et l'aurait carrée. */
/* ⚠️⚠️⚠️ CETTE BARRE AVAIT SA PROPRE FORME, ET C'ÉTAIT LA FAUTE (27/08/2026).
   Amadou : « ils sont arrondis alors que normalement — regarde les Commandes, les
   Comptes, la Bibliothèque — c'est des boutons comme ça ». Il a raison : l'écran des
   Machines était le SEUL à porter une pilule, dans un site où tous les onglets sont
   des rectangles à `--r-md`. Un écran qui invente sa propre forme se remarque, et pas
   pour la bonne raison.
   ⚠️ « Emprunter, jamais inventer » est déjà une règle de ce projet, reprise quatre
   fois. La barre reprend donc exactement celle des Commandes : `.cok-cmd-stab` telle
   qu'elle est définie pour tout le monde, sans un seul réglage à elle. */

/* ══ LE RAIL DU PARCOURS ═════════════════════════════════════════════════════
   Amadou : « le parcours de suivi n'est pas agréable à utiliser, il y a trop de boutons,
   tout en évitant de déborder ».
   ⚠️⚠️ LES NEUF ÉTAPES ÉTAIENT NEUF PASTILLES CÔTE À CÔTE. À 1280 px elles s'enroulaient
   sur DEUX rangées — et l'ordre, qui est toute l'information d'un parcours, disparaissait
   au moment du retour à la ligne. Treize boutons s'affichaient avant la première commande.
   ⭐ Un rail répond aux trois demandes d'un coup : l'ordre se lit, il tient sur UNE ligne
   à toute largeur (les étapes se partagent l'espace, elles ne le réclament pas), et il n'y
   a plus de boutons — il y a un chemin. */
/* ⚠️ LE PAS EST PASSÉ DE 140 À 184 px. Amadou : « pour l'Entrepôt, augmente l'espace
   entre les étapes ». Ses libellés sont longs — « Expéditions entrantes »,
   « Expéditions sortantes » — et à 140 px ils remplissaient leur place jusqu'au bord :
   deux libellés voisins se touchaient, sans être coupés pour autant (la mesure disait
   « 0 coupé », et elle avait raison — ce n'était pas une troncature, c'était une
   collision).
   ⚠️ Suivi ne bouge pas : ses neuf étapes dépassent déjà la barre, le plafond à 100 %
   les ramène. Élargir le pas ne joue donc que sur les rails COURTS, ceux qui avaient
   de la place à revendre. */
.cok-cmd-subtabs.cok-cmd-rail { --cmd-pas: 184px;   /* la largeur d'une étape */
  display: flex; align-items: stretch;
  gap: 0; flex-wrap: nowrap; padding: var(--e-10) 0 var(--e-4);
  margin-bottom: var(--e-8); }
/* ⚠️ La barre N'EST PLUS un conteneur de requête : plus rien ne l'interroge depuis que
   le seuil est passé sur l'étape. Un conteneur déclaré que personne ne lit ne coûte rien
   à l'écran, mais il ment au prochain qui lira — il laisse croire que la barre décide
   quelque chose, alors que la décision a changé d'échelle. */

/* ⚠️⚠️ LE CHEMIN ET SES ANNEXES SONT DEUX BLOCS, PAS UNE SEULE RANGÉE. L'Entrepôt est un
   parcours à quatre étapes (bon → entrante → stock → sortante) PLUS deux branches
   (Retours, Factures). Collées au bout du rail, elles se liraient comme une cinquième et
   une sixième étape — le rail leur inventerait une progression qui n'existe pas. */
/* ⚠️⚠️ LE CHEMIN NE S ÉTIRE PLUS POUR REMPLIR. Amadou : « mets la frise à gauche, là
   c'est trop centré ». Chaque étape prenait une part ÉGALE de toute la largeur : à neuf
   c'est juste, à quatre ça les écarte de 280 px et le chemin se lit comme une guirlande
   tendue d'un bord à l'autre. `flex: 0 1 auto` : le rail fait la largeur de ce qu'il
   porte, et se cale à gauche. Les annexes le suivent au lieu d'être renvoyées au loin —
   c'est ce grand vide au milieu qui donnait l'impression de centrage. */
.cmd-rail-fil { position: relative; flex: 0 1 auto; min-width: 0;
  display: flex; align-items: flex-start;
  /* ⚠️⚠️ LA LARGEUR EST CALCULÉE, PAS DEVINÉE. Laissée à `auto`, le parent se dimensionne
     sur le contenu AVANT que les bases des étapes s'appliquent : mesuré, 94 px par étape
     au lieu de 140, et les libellés se coupaient. On connaît déjà le nombre d'étapes
     (`--cmd-n`, posé par app.js) — la largeur du chemin en découle, et le plafond à 100 %
     le laisse se serrer quand la place manque. */
  width: calc(var(--cmd-n, 9) * var(--cmd-pas)); max-width: 100%; }
/* Le trait qui relie les étapes. Il s'arrête au centre des deux extrêmes : un rail qui
   dépasse de la première et de la dernière donnerait un chemin qui vient d'ailleurs et
   continue nulle part.
   ⚠️ La marge dépend du NOMBRE d'étapes : elle vaut une demi-place. `100%/18` valait pour
   neuf étapes ; à deux, elle laissait le trait sortir loin devant. On la calcule donc sur
   la largeur d'une étape, que le navigateur connaît déjà. */
.cmd-rail-fil::before { content: ''; position: absolute; top: 4px; height: 1px;
  left: 0; right: 0; background: var(--cok-border-2);
  transform: scaleX(calc(1 - 1 / var(--cmd-n, 9))); }

/* Les annexes, après un filet : elles appartiennent à la filière, pas au chemin. */
.cmd-rail-a { flex: 0 0 auto; display: flex; align-items: center; gap: var(--e-4);
  margin-left: var(--e-16); padding-left: var(--e-16);
  border-left: 1px solid var(--cok-border); }
.cmd-annexe { align-self: center; }

/* ⚠️⚠️ UNE LARGEUR DE BASE, PAS UN PLAFOND SUR UNE BASE NULLE. Premier essai :
   `flex: 1 1 0` + `max-width`. Mais dans un parent qui s'ajuste à son contenu, une base
   nulle fait s'EFFONDRER les enfants sur leur plus petite largeur — mesuré : 62 px par
   étape au lieu de 140, et les libellés n'avaient plus la place d'exister.
   `flex: 0 1 140px` donne à chaque étape sa largeur, et l'autorise à se serrer quand la
   place manque : à neuf elles remplissent presque tout, à deux le chemin reste court. */
.cmd-e { position: relative; flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: var(--e-6);
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--cok-text-3); transition: color var(--t-bref); }
/* ⚠️ La pastille porte le FOND de l'écran, pas `transparent` : c'est elle qui doit
   masquer le trait derrière elle, sinon la ligne traverse le point. */
.cmd-e-pt { width: 9px; height: 9px; border-radius: 50%; box-sizing: border-box;
  background: var(--cok-card); border: 1.5px solid var(--cok-border-2);
  transition: background var(--t-bref), border-color var(--t-bref), box-shadow var(--t-bref); }
/* ⚠️ Une étape VIDE reste visible, elle ne disparaît pas : c'est ce qui permet de lire le
   parcours en entier et de savoir que rien n'attend là. Elle est juste plus sourde. */
.cmd-e-pt.plein { background: var(--cok-text-3); border-color: var(--cok-text-3); }
.cmd-e-pt.urgent { background: var(--cok-red); border-color: var(--cok-red); }
/* ⚠️⚠️ LA FRISE SAUTAIT, ET LA CAUSE EST QU'ELLE NAÎT VIDE. `.cmd-e-n` est écrit sans
   contenu (`<span class="cmd-e-n">`), les chiffres n'arrivent qu'une requête plus tard.
   Or un élément VIDE n'a pas de ligne, donc pas de hauteur : la frise se dessinait
   tassée, puis les chiffres la faisaient GRANDIR d'un coup et poussaient les neuf
   libellés vers le bas. Amadou, 23/08 : « les chiffres mettent du temps à s'afficher,
   ce qui fait que ça fait moche ».
   La place d'une ligne est donc tenue dès le premier dessin, chiffre ou pas — et le
   chiffre se pose en fondu au lieu d'apparaître d'un coup. */
.cmd-e-n { font-size: var(--t-meta); font-variant-numeric: tabular-nums;
  color: var(--cok-text-2); line-height: var(--lh-un);
  min-height: 1em;              /* une ligne, toujours : `1em` = sa propre taille */
  transition: opacity var(--t-moyen) var(--c-pose),
              transform var(--t-moyen) var(--c-pose); }
/* Tant qu'il n'a pas son chiffre, il tient la place sans rien montrer. Le chiffre monte
   de deux pixels en se révélant : il se POSE, il ne clignote pas. */
.cmd-e-n:empty { opacity: 0; transform: translateY(var(--e-2)); }
/* ⚠️ Une étape à zéro reste visible, mais plus sourde : c'est ce qui permet de lire le
   parcours en entier et de savoir que rien n'attend là. */
.cmd-e-n.vide { color: var(--cok-text-3); opacity: .5; }
/* Même chose pour les pastilles des annexes, qui se remplissent au même moment. */
.cok-cmd-stab-n { transition: opacity var(--t-moyen) var(--c-pose); }
.cok-cmd-stab-n:empty { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .cmd-e-n, .cok-cmd-stab-n { transition: none; }
  .cmd-e-n:empty { transform: none; }
}
[data-anim="off"] .cmd-e-n, [data-anim="off"] .cok-cmd-stab-n { transition: none; }
[data-anim="off"] .cmd-e-n:empty { transform: none; }
/* ⚠️ Le libellé garde SA marge, quelle que soit la largeur de l'étape : c'est elle qui
   garantit que deux voisins ne se touchent jamais, même le jour où le pas rétrécit. */
/* ⚠️ ET QUAND ÇA DÉPASSE D'UN CHEVEU, ON ÉLIDE — on ne coupe pas au milieu d'une lettre.
   Mesuré sur l'Entrepôt à 129 px par étape : « Expéditions entrantes » déborde de 2 px.
   Deux pixels ne justifient pas de faire disparaître le nom, mais un mot tranché net se
   lit comme un défaut. Trois points le disent proprement, et aucun seuil n'a à connaître
   la longueur des libellés. */
.cmd-e-l { font-size: var(--t-meta); line-height: var(--lh-serre); text-align: center;
  max-width: 100%; padding: 0 var(--e-8);
  overflow: hidden; text-overflow: ellipsis; }

.cmd-e:hover { color: var(--cok-text-2); }
.cmd-e:hover .cmd-e-pt { border-color: var(--cok-border); }
/* L'étape ouverte : son point s'allume et rayonne. Le libellé passe en clair — c'est le
   seul de la ligne, donc il se trouve sans le chercher. */
.cmd-e.on { color: var(--cok-text); }
.cmd-e.on .cmd-e-pt { background: var(--cok-accent); border-color: var(--cok-accent);
  box-shadow: 0 0 10px rgba(var(--th-accent-rgb), .55); }
.cmd-e.on .cmd-e-n { color: var(--cok-text); font-weight: var(--fw-fort); }
.cmd-e.on .cmd-e-l { font-weight: var(--fw-fort); }

/* ⚠️⚠️ LA MESURE PORTE SUR LE RAIL, PAS SUR LA FENÊTRE. Première écriture : une media
   query à 620 px de FENÊTRE. Mesuré à 820 px — le canevas ne fait que 516 px de large,
   soit 57 px par étape, et CINQ libellés sur neuf étaient coupés alors que la règle ne
   s'était pas déclenchée. Ce qui manque de place, c'est le rail ; c'est donc lui qu'il
   faut interroger. Neuf libellés demandent environ 72 px chacun.
   ⭐ En dessous, on garde le point et le chiffre — ils suffisent à naviguer — et le nom
   de l'étape ouverte reste, puisque c'est le seul qu'on cherche. */
/* ⚠️⚠️⚠️ ET LE SEUIL PORTE SUR L'ÉTAPE, PAS SUR LE RAIL. Deuxième correction, même
   défaut d'un cran plus haut : 660 px était le seuil JUSTE pour NEUF étapes (660/9 ≈ 73 px
   par libellé) et FAUX pour toutes les autres. Mesuré sur les trois étapes de Litiges :
   à 596 px de barre, chaque étape faisait encore 184 px — largement de quoi écrire
   « Retour demandé » — et les libellés disparaissaient quand même. Un seuil réglé sur un
   seul cas se trompe sur tous les autres : SHEIN (2), Litiges (3) et l'Entrepôt (4)
   perdaient leurs noms plus de cent pixels trop tôt.
   L'étape devient donc son propre conteneur : la question posée est « ai-je la place
   d'écrire MON nom ? », qui ne dépend plus du nombre d'étapes. 108 px = le plus long
   libellé du site (« Bon à déposer ») plus sa marge.
   ⚠️ Le conteneur se pose sur `.cmd-e` et la règle vise `.cmd-e-l` : un élément ne peut
   PAS interroger sa propre largeur — c'est le piège déjà payé sur `.rp-corps`.
   ⭐ En dessous, on garde le point et le chiffre — ils suffisent à naviguer — et le nom
   de l'étape ouverte reste, puisque c'est le seul qu'on cherche. */
.cmd-e { container-type: inline-size; container-name: etape; }
@container etape (max-width: 108px) {
  .cmd-e-l { display: none; }
  .cmd-e.on .cmd-e-l { display: block; }
}

.mac-grille { margin-top: var(--e-20); display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
  gap: var(--e-14); }
/* ── LA CARTE : UN CARRÉ, TROIS CHOSES ───────────────────────────────────────
   Elle sert à REPÉRER parmi vingt, pas à lire. Son numéro, ce qu'elle est, et son
   signe vital en grand : combien de ses comptes parlent. Tout le reste est derrière
   le clic. ⚠️ Le même dessin sert aux machines ET aux sorties : deux cartes pour la
   même idée finiraient par diverger. */
/* ⚠️⚠️ `aspect-ratio: 1 / .82` CREUSAIT 117 px DE VIDE. Mesuré le 18/08 : la carte
   faisait 259 px de haut pour quatre lignes courtes, et `margin-top: auto` poussait le
   chiffre tout en bas — 45 % de la carte ne portait rien. Le carré se défendait par
   « repérer parmi vingt » ; il y en a DEUX, et elles tiennent le même ordinateur. Une
   carte doit faire la hauteur de ce qu'elle a à dire. */
.mac-c { display: flex; flex-direction: column; gap: var(--e-10); text-align: left;
  font: inherit; cursor: pointer; padding: var(--e-16);
  border: 1px solid var(--cok-border); border-radius: var(--r-lg);
  background: var(--cok-card); transition: border-color var(--t-bref); }
.mac-c:hover { border-color: var(--cok-border-2); }
.mac-c-num { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-c-hd { display: flex; align-items: center; gap: var(--e-8); min-width: 0; }
.mac-pt { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
  background: var(--cok-green); }
.mac-pt.wa { background: var(--cok-amber); }
.mac-pt.no { background: var(--cok-red); }
/* Vide : ni bien ni mal, personne n'habite là. Le vert est une récompense. */
.mac-pt.vi { background: var(--cok-text-3); }
.mac-c-ad { font-size: var(--t-base); color: var(--cok-text-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mac-c-big { margin-top: auto; display: flex; align-items: baseline; gap: var(--e-6); }
.mac-c-big b { font-size: var(--t-display); font-weight: var(--fw-moyen);
  color: var(--cok-text); line-height: var(--lh-un); }
.mac-c-big i { font-style: normal; font-size: var(--t-lead); color: var(--cok-text-3); }
.mac-c-lg { font-size: var(--t-base); color: var(--cok-text-3); }
.mac-c-lg.wa { color: var(--cok-amber); }
.mac-c-lg.no { color: var(--cok-red); }
.mac-c-lg.vi { color: var(--cok-text-3); }
.mac-c-big.vi b { color: var(--cok-text-3); }
/* La note explique un chiffre que le calcul ne peut pas expliquer : « remise le 15/08
   à la demande de Kristo » dit pourquoi c'est zéro, mieux que n'importe quel verdict. */
.mac-c-note { font-size: var(--t-meta); color: var(--cok-text-3); line-height: var(--lh-serre);
  border-top: 1px solid var(--cok-border); padding-top: var(--e-10); }

/* L'EN-TÊTE QUAND TOUT TIENT SUR UN SEUL ORDINATEUR. Il dit l'hôte et l'adresse UNE
   fois, pour que les cartes en dessous n'aient plus à les répéter. */
.mac-uneseule { margin-top: var(--e-20); padding-bottom: var(--e-14);
  border-bottom: 1px solid var(--cok-border); }
.mac-uneseule-t { font-size: var(--t-lead); color: var(--cok-text); }
.mac-uneseule-s { margin-top: var(--e-6); display: flex; flex-wrap: wrap;
  align-items: center; gap: var(--e-6) var(--e-14);
  font-size: var(--t-base); color: var(--cok-text-3); }
.mac-uneseule + .mac-grille { margin-top: var(--e-14); }
.mac-ko { color: var(--cok-red); }
/* ⚠️⚠️ LE FIL D'ARIANE A ETE RETIRE (27/08/2026). Il inventait « Les machines › la
   machine › sortie 1 », avec des chevrons qu'on ne trouve nulle part ailleurs sur le
   site. Le retour se fait maintenant par `.cok-back` — la flèche du site, déjà stylée,
   déjà comprise. Amadou : « inspire-toi de ce qu'il y a sur le site, ça fait un décalage
   avec la DA ». Un écran qui invente son propre geste de retour oblige à l'apprendre.
   ⚠️ Ses règles partent avec lui : une classe CSS que plus personne n'écrit est un
   piège pour le prochain qui la lira en croyant qu'elle sert. */

/* Les deux vues d'une machine. ⚠️ MÊME FORME QUE LES ONGLETS DU SITE, plus une pilule à
   moi : c'était la même faute que la barre du haut, au même écran, deux fois. */
.mac-vues { display: inline-flex; width: fit-content; gap: var(--e-4);
  margin-bottom: var(--e-14); }
.mac-vues button { font: inherit; font-size: var(--t-base); line-height: var(--lh-un);
  height: 34px; padding: 0 var(--e-16); border-radius: var(--r-md);
  border: 1px solid var(--border); background: rgba(var(--th-voile),0.04);
  color: var(--text-2); cursor: pointer; }
.mac-vues button.on { background: var(--cok-accent-bg); color: var(--cok-accent);
  border-color: transparent; }
.mac-sec { font-size: var(--t-meta); color: var(--cok-text-3); margin: var(--e-24) 0 var(--e-10); }
/* ── L'ESPACE D'UNE MACHINE ───────────────────────────────────────────────────
   ⚠️⚠️ CE BLOC AVAIT DISPARU. En réécrivant les cartes j'ai supprimé `.mac-fiche` et
   `.mac-f-l` sans les remettre : l'écran affichait « hôteVMI3454088 », étiquette collée
   à sa valeur, sur dix-huit lignes. Amadou : « visuellement c'est moche et ce n'est pas
   parlant ». Une règle supprimée ne lève aucune erreur — elle laisse juste du HTML nu.
   ⚠️ Et le fond du problème n'était pas que l'espacement : DIX pastilles « à brancher »
   identiques criaient plus fort que les vraies mesures. Ce qui se mesure passe en
   TUILES, ce qui manque tient en UNE phrase, en bas, discrète. */
.mac-tete { display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--e-16); flex-wrap: wrap; }
.mac-h1 { font-size: var(--t-lead); font-weight: var(--fw-fort); letter-spacing: -.2px; }
.mac-h2 { font-size: var(--t-base); color: var(--cok-text-3); margin-top: var(--e-4); }
/* Le verdict : la première chose à lire — cette machine a-t-elle un problème ? */
/* ══ UN ÉTAT SE DIT PAR UN POINT ET DU TEXTE ══════════════════════════════════
   Amadou (20/08) : « en aucun cas il y a des bulles rondes comme ça — regarde comment
   le site est fait ». Il a raison, et je m'étais trompé de composant : `.v-pastille`
   sert aux étiquettes de CONTENU (un coloris, une taille, un code robe). Un ÉTAT, sur
   cet écran comme sur Santé, se dit par `.cok-bs-dot` — un point de 9 px avec son halo —
   suivi du texte dans la même couleur. Deux composants, deux usages ; j'avais pris le
   mauvais, et ça se voyait à l'œil avant de se voir dans le code. */
.mac-verdict { display: inline-flex; align-items: center; gap: var(--e-8);
  font-size: var(--t-base); font-weight: var(--fw-moyen); white-space: nowrap;
  background: none; padding: 0; border-radius: 0; color: var(--cok-text-3); }
.mac-verdict::before { content: ''; flex: none;
  width: var(--e-8); height: var(--e-8); border-radius: 50%;
  background: currentColor; box-shadow: 0 0 0 var(--e-2) transparent; }
.mac-verdict.v-pastille--ok      { color: var(--cok-green); }
.mac-verdict.v-pastille--ok::before      { box-shadow: 0 0 0 var(--e-2) var(--cok-green-bg); }
.mac-verdict.v-pastille--attente { color: var(--cok-amber); }
.mac-verdict.v-pastille--attente::before { box-shadow: 0 0 0 var(--e-2) var(--cok-warn-bg); }
.mac-verdict.v-pastille--alerte  { color: var(--cok-red); }
.mac-verdict.v-pastille--alerte::before  { box-shadow: 0 0 0 var(--e-2) var(--cok-red-bg); }
/* ⚠️ ELLE N'AVAIT DE MARGE QU'EN HAUT : ce qui la suivait venait s'y coller. Un bloc
   qui ne réserve d'air que d'un côté oblige chacun de ses voisins à s'en occuper. */
.mac-tuiles2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(164px, 1fr));
  gap: var(--e-12); margin-top: var(--e-20); margin-bottom: var(--e-20); }
.mac-tu { padding: var(--e-14) var(--e-16); border-radius: var(--r-md);
  background: var(--cok-bg-2); border: 1px solid var(--cok-line); }
.mac-tu .lb { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-tu .vl { font-size: var(--t-title); font-weight: var(--fw-moyen);
  line-height: var(--lh-titre); margin-top: var(--e-4); color: var(--cok-text); }
.mac-tu .vl.ok { color: var(--cok-green); }
.mac-tu .vl.rd { color: var(--cok-red); }
.mac-tu .vl.am { color: var(--cok-amber); }
.mac-tu .nt { font-size: var(--t-meta); color: var(--cok-text-3); margin-top: var(--e-2); }
/* ⚠️ `.mac-fiche` / `.mac-f-l` RETIRÉES (15/08). Les grilles étiquette-valeur ne
   servaient qu'à répéter le sous-titre — l'hôte, l'adresse, l'espace y étaient déjà.
   Amadou : « le système d'intitulé avec à droite le nom, ça fait trop brouillon ».
   Le défaut n'était pas leur dessin : c'est qu'elles disaient une deuxième fois ce
   qu'on venait de lire. Du CSS qui met en forme une redondance reste une redondance. */
/* Ce qui n'est pas mesuré se dit UNE fois, en creux — jamais en dix pastilles. */
.mac-attente { margin-top: var(--e-22); padding: var(--e-14) var(--e-16);
  border-radius: var(--r-md); border: 1px dashed var(--cok-border-2);
  color: var(--cok-text-3); font-size: var(--t-base); line-height: var(--lh-normal); }
.mac-attente b { color: var(--cok-text-2); font-weight: var(--fw-moyen); }
.mac-detail { margin-top: var(--e-18); }
.mac-k { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-faux { color: var(--cok-red); }
/* Le corps ne se dessine que si la machine est ouverte : un bloc masqué qu'on garde
   dans la page, c'est du contenu qui s'imprime et se lit à l'aveugle. */
.mac-corps { display: none; padding: 0 var(--e-16) var(--e-14);
  border-top: 1px solid var(--cok-line); }
.mac-vds.ouverte .mac-corps { display: block; }
.mac-ln { display: grid; grid-template-columns: 56px minmax(0,1.6fr) auto;
  gap: var(--e-14); align-items: center; padding: var(--e-14) 0;
  border-bottom: 1px solid var(--cok-line); }
.mac-ln:last-child { border-bottom: none; }
/* ── LE SOUS-PARC : une sortie mobile, et les comptes qui la partagent ────────
   Amadou (15/08) : « un parc de VDS avec des sous-parcs — dans un VDS, un sous-parc
   avec une IP mobile contenant vingt-cinq comptes ». C'est la maille qui compte : si
   cette sortie grille, tous ces comptes grillent ensemble. */
.mac-sp { margin-top: var(--e-14); }
.mac-sp:first-child { margin-top: var(--e-4); }
.mac-sp-tete { display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-8) 0 var(--e-6); color: var(--cok-text-3); }
.mac-sp-nom { font-size: var(--t-base); color: var(--cok-text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mac-entete, .mac-entete span { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-pro { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--cok-text-2); }
.mac-cpt { font-size: var(--t-base); color: var(--cok-text-2); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; }
.mac-cpt i { display: block; font-style: normal; margin-top: var(--e-2); }
.mac-et { display: flex; gap: var(--e-6); flex-wrap: wrap; }
.mac-flux { margin-top: var(--e-18); }
.mac-fl-tete { display: flex; gap: var(--e-10); margin-top: var(--e-12); }
.mac-fl-liste { margin-top: var(--e-12); display: flex; flex-direction: column; }
.mac-fl { display: grid; grid-template-columns: minmax(0,1fr) auto auto; gap: var(--e-12);
  align-items: center; padding: var(--e-8) 0; border-bottom: 1px solid var(--cok-line);
  font-size: var(--t-base); color: var(--cok-text-2); }
.mac-fl:last-child { border-bottom: none; }
/* ── LE FLUX ──────────────────────────────────────────────────────────────────
   ⚠️ Le débit d'abord, et en gros : c'est la seule chose qui explique pourquoi une
   création traîne. Le détail (qui consomme, qui est lent) vient après. */
.mac-tuiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: var(--e-10); margin-top: var(--e-14); }
.mac-t { padding: var(--e-12) var(--e-14); border-radius: var(--r-md);
  background: var(--cok-bg-2); border: 1px solid var(--cok-line); }
.mac-t b { display: block; font-size: var(--t-title); font-weight: var(--fw-moyen);
  color: var(--cok-text); line-height: var(--lh-titre); }
.mac-t span { font-size: var(--t-meta); color: var(--cok-text-3); }
.mac-fams { margin-top: var(--e-14); }
.mac-fam { display: grid; grid-template-columns: 120px minmax(0,1fr) 44px; gap: var(--e-10);
  align-items: center; padding: var(--e-6) 0; font-size: var(--t-base);
  color: var(--cok-text-2); }
/* ⚠️⚠️⚠️ SANS `display`, ELLE N'EXISTAIT PAS (27/08/2026). `.mac-bar` est posée sur un
   `<span>` : inline par défaut, donc `height` est IGNORÉ et la barre ne se voit pas.
   Elle s'affichait quand même à un endroit — par accident, parce que son parent était
   flex et la « blockifiait ». Ailleurs, rien. Une règle qui dépend du parent pour
   exister n'est pas une règle, c'est une coïncidence. */
.mac-bar { display: block; height: 8px; border-radius: var(--r-pilule);
  background: var(--cok-bg-2); }
.mac-bar i { display: block; height: 100%; border-radius: var(--r-pilule);
  background: var(--cok-accent); }
.mac-fam .mac-k { text-align: right; }
.mac-nat { display: flex; gap: var(--e-6); flex-wrap: wrap; margin-top: var(--e-12);
  padding-top: var(--e-12); border-top: 1px solid var(--cok-line); }
@media (max-width: 620px) { .mac-fam { grid-template-columns: 88px minmax(0,1fr) 38px; } }
@media (max-width: 760px) {
  .mac-ln { grid-template-columns: 44px minmax(0,1fr); }
  .mac-et { grid-column: 1 / -1; }
  .mac-hote { width: 100%; }
}
@media (max-width: 700px) {
  
  
}

/* L'étiquette qui porte ce que SHEIN nous dit du colis : l'arrivée estimée et le
   transporteur. ⚠️ Un ton à part, ni violet (le logiciel) ni ambre (l'alerte) : c'est une
   information venue de l'extérieur, et la confondre avec un état de Velbo ferait croire
   qu'on la maîtrise. Quand l'arrivée est proche, l'étiquette passe en ambre — elle devient
   alors une échéance, pas un renseignement. */
.cmd-tag--shein {
  color: var(--green);
  background: rgba(127,212,193,0.10);
  border-color: rgba(127,212,193,0.32);
}
/* « En attente de l'expédition » : une étape sans geste doit le DIRE, sinon on cherche le
   bouton qui manque. */
.cmd-attend {
  font-size: var(--t-meta); color: var(--cok-text-3, rgba(var(--th-voile),0.42));
  white-space: nowrap; padding: 0 var(--e-4);
}

/* ── L'écran de lancement d'une création ─────────────────────────────────────
   Validé par Amadou (09/08) : elle à gauche — son visage, sa ville, ses photos,
   sa description — et le lancement à droite. On met une personne au monde, pas
   un enregistrement : c'est elle qui prend la place, pas le formulaire. */
/* Sa fiche vit dans un logement nommé pour être prêtée au parcours pendant une
   création, puis rendue. Elle garde sa colonne de droite au repos. */
/* ⚠️⚠️ L'ESPACE SE POSE SUR LE PARENT, PAS SUR LES ENFANTS.
   Mesuré dans le navigateur le 20/08 : entre le bas des réglages et le haut du bouton
   « Créer le compte », il y avait **0 pixel**, à 1440 comme à 1100 de large. Le bouton,
   écrit après, peignait son fond plein par-dessus le trait des encadrés : « ça mord
   dedans ».
   Les 16 px qui séparaient les deux appartenaient à l'ANCIEN bouton « Lancer la rafale »
   (`.cok-raf-go`, plus aucun utilisateur depuis le 18/08). Le HTML a déménagé, la feuille
   de style n'a pas suivi — la marge est restée écrite sur une règle morte, si bien qu'en
   relisant le CSS on croyait l'espace géré.
   Un `gap` sur le parent ne peut pas déménager avec un bloc. C'est déjà le motif de la
   maison : `.cok-horlo-g` juste au-dessus fait exactement ça. */
.cpl-lancer { display: flex; flex-direction: column; gap: var(--e-20);
  margin-top: var(--e-18); }
/* ⚠️ UN ENFANT VIDE PREND QUAND MÊME SON `gap`. `#cp-rafale-corps` et `#cp-tailles-crea`
   sont vides au repos (mesuré : deux div à hauteur 0) : sans ça, ils ajoutaient 40 px de
   blanc sous le bouton pour ne rien dire. */
.cpl-lancer > :empty { display: none; }
/* la marge basse est passée au `gap` du parent (voir .cpl-lancer) */
.cpl-pret { display: flex; flex-direction: column; gap: var(--e-10); margin: 0; }
.cpl-p { display: flex; align-items: center; gap: var(--e-10); font-size: var(--t-base);
  color: var(--cok-text-2); }
.cpl-p i { width: 17px; height: 17px; border-radius: 50%; flex: 0 0 auto;
  font-style: normal; font-size: var(--t-micro); display: flex; align-items: center;
  justify-content: center; }
.cpl-p i.ok { background: var(--cok-green-bg); color: var(--cok-green); }
/* ⚠️ Ce qui reste à SA charge se distingue de ce qui est déjà prêt : sans cette
   différence, la liste laisserait croire que tout est automatique. */
.cpl-p i.toi { background: var(--cok-accent-bg); color: var(--cok-accent); font-weight: var(--fw-gras); }
@media (max-width: 760px) { .cpl-grid { grid-template-columns: 1fr; gap: var(--e-22); } }

/* ── Pendant une création : équilibrer les deux colonnes ─────────────────────
   ⚠️ Amadou (09/08) : « c'est hyper mal agencé ». Sa carte fait trois grandes
   photos plus une description entière — elle écrasait une frise de sept lignes,
   et repoussait l'écran en direct tout en bas de la page. On la compacte : ce
   n'est pas une fiche à lire ici, c'est un repère pour savoir QUI se crée. */
#cpf-fiche .cok-horlo-vues { grid-template-columns: repeat(3, 1fr); gap: var(--e-6); }
#cpf-fiche .cok-horlo-vues img,
#cpf-fiche .cok-horlo-vues > * { aspect-ratio: 3/4; height: auto; max-height: 190px;
  object-fit: cover; border-radius: var(--r-sm); }
/* La description se lit en entier dans sa fiche vendeuse, pas ici : quelques
   lignes suffisent à reconnaître le ton, le reste défile. */
#cpf-fiche .cok-horlo-bio { max-height: 108px; overflow: auto; }
#cpf-fiche .cok-launch { margin-top: 0 !important; }

/* La colonne de droite ne doit pas s'étirer plus haut que son contenu utile :
   l'écran vient juste sous la fiche, pas après un mur de texte. */
.cpf-cote { position: sticky; top: 12px; align-self: start; }

/* La frise et l'écran forment une seule colonne : l'un dit où on en est, l'autre le
   montre. Les séparer obligeait à regarder à deux endroits. */
.cpf-suite { display: flex; flex-direction: column; gap: var(--e-20); min-width: 0; }
.cpf-suite .cpf-ecran { margin-top: 0; }

/* ══════════════════════════════════════════════════════════════════════════════
   UN ONGLET NE CHANGE PAS DE TAILLE QUAND ON LE CHOISIT
   Amadou (09/08) : « les boutons quand on appuie dessus s'allongent, c'est gênant ».
   ⚠️⚠️ CAUSE : l'état actif passe la graisse de 500 à 600. Avec Inter chargée, le texte
   gras est plus large — donc le bouton s'élargit, et tous ses voisins de droite se
   décalent. Sur une barre de huit onglets, chaque clic fait bouger la barre entière.
   ⚠️ Invisible en essai : le navigateur d'épreuve n'a pas Inter, il dessine 500 et 600 à
   l'identique. Padding et bordure, eux, sont mesurés IDENTIQUES dans les deux états — la
   graisse est donc la seule différence capable de changer la largeur.
   ⭐ On garde la graisse normale : le fond en dégradé et le texte foncé disent déjà, sans
   la moindre ambiguïté, quel onglet est choisi. On ne perd aucun repère, on gagne une
   barre qui ne bouge plus.
   ⚠️ Ne concerne QUE les onglets. Une puce d'état ou un compteur peuvent grossir sans
   gêner : ils ne sont pas dans une rangée dont l'alignement compte.
   ════════════════════════════════════════════════════════════════════════════ */
.an-so.on, .an-so.active,
.cokmsg-tab.on, .cokmsg-tab.active,
.msg-tab.on, .msg-tab.active,
.ctrl-esc-subtab.on, .ctrl-esc-subtab.active,
.gen-tab.on, .gen-tab.active,
.gen-subtab.on, .gen-subtab.active,
.src-stab.on, .src-stab.active,
.cok-cmd-stab.on, .cok-cmd-stab.active,
.drafts-tab.on, .drafts-tab.active,
.pa-tab.on, .pa-tab.active,
.model-tab.on, .model-tab.active,
.cok-wtab.on, .cok-wtab.active,
.lib-vend-onglet.on, .lib-vend-onglet.active,
.lib-tier-tab.on, .lib-tier-tab.active,
.dress-coloris-tab.on, .dress-coloris-tab.active,
/* ⚠️⚠️ VINGT FAMILLES MANQUAIENT, ET AMADOU L'A REDIT LE 11/08 : « c'est le CLIC qui crée
   le décalage ». La première liste ne couvrait que les barres d'onglets ; or le même
   défaut vit dans les rangées de PUCES et de SEGMENTS, et surtout dans `.cok-cmd-grp` —
   les boutons Suivi / SHEIN / Entrepôt, c'est-à-dire la rangée qu'on clique le plus.
   ⚠️ Recensé en listant TOUTES les règles `.on`/`.active` qui touchent une propriété
   capable de changer une largeur (graisse, chasse, marge intérieure, corps, bordure) sur
   un sélecteur de bouton — pas en cherchant à l'œil. C'est le comptage qui a trouvé les
   vingt, la lecture n'en avait vu qu'une.
   ⚠️⚠️ ET ÇA NE SE VOIT PAS À L'ESSAI : le navigateur d'épreuve n'a pas Inter, il dessine
   500 et 600 à l'identique. Toute vérification ici doit lire la GRAISSE CALCULÉE, jamais
   comparer deux largeurs à l'écran — c'est ce qui m'avait fait conclure « corrigé » à
   tort. */
.cok-cmd-grp.on, .cok-cmd-grp.active,
.cok-cmd-grp.on-vinted, .cok-cmd-grp.on-shein, .cok-cmd-grp.on-wh,
.cok-chip.on, .cok-chip.active,
.ctrl-esc-cat-chip.on, .ctrl-esc-cat-chip.active,
.lib-fchip.on, .lib-fchip.active,
.ds-pill.on, .ds-pill.active,
.dem-pill.on, .dem-pill.active,
.src-gab.on, .src-gab.active,
.msg-vue.on, .msg-vue.active,
.lib-marque-chip.on, .lib-marque-chip.active,
.prod-view-chip.on, .prod-view-chip.active,
.cok-prof-f.on, .cok-prof-f.active,
.pg-seg-b.on, .pg-seg-b.active,
.lib-filter.on, .lib-filter.active,
.batch-mode-btn.on, .batch-mode-btn.active,
.fin-period-btn.on, .fin-period-btn.active,
.lib-picker-tier-tab.on, .lib-picker-tier-tab.active,
.atelier-param-btn.on, .atelier-param-btn.active,
.cok-vend-onglet.on, .cok-vend-onglet.active,
.el-segb.on, .el-segb.active,
.cok-master span.on {
  font-weight: var(--fw-moyen);
}

/* ⚠️⚠️ ET DEUX ENFONCEMENTS QUI SE CONTREDISAIENT. `scale(.975)` était écrit ligne ~240,
   `translateY(1px)` ligne ~17993 : à poids égal, le second gagnait, mais les deux
   prétendaient décrire « l'appui » et personne ne pouvait le deviner en lisant l'un des
   deux. Un seul geste, énoncé une fois — et c'est l'enfoncement, pas le rétrécissement :
   un bouton qui rapetisse sous le doigt donne l'impression de reculer. */
.an-so:active, .cokmsg-tab:active, .msg-tab:active, .ctrl-esc-subtab:active,
.gen-tab:active, .gen-subtab:active, .src-stab:active, .cok-cmd-stab:active,
.drafts-tab:active, .pa-tab:active, .model-tab:active, .cok-wtab:active,
.lib-vend-onglet:active, .dress-coloris-tab:active, .lib-tier-tab:active,
.cok-chip:active, .cok-cmd-grp:active, .nav-item:active {
  transform: translateY(1px);
}

/* ══════════════════════════════════════════════════════════════════════════════
   TOUS LES COMPTEURS D'ONGLET RÉSERVENT LEUR PLACE
   Amadou (09/08) : « ce n'est pas que pour le bouton "En retard", c'est pour tous les
   autres aussi ». Il a raison : j'avais protégé UNE famille sur sept.
   ⚠️⚠️ Le défaut est le même partout : un compteur qui passe de 9 à 10, ou qui arrive
   après le premier rendu, s'élargit — et pousse tous ses voisins de droite. Sur une
   rangée d'onglets, toute la barre se décale sous le doigt.
   ⚠️ `font-variant-numeric: tabular-nums` était déjà posé sur plusieurs d'entre eux et ne
   suffit pas : il égalise les chiffres ENTRE EUX, pas le NOMBRE de chiffres.
   ⚠️ `box-sizing: content-box` est indispensable : ces compteurs sont des pastilles avec
   du rembourrage, et en `border-box` (le réglage global du site) la largeur minimale
   engloberait le rembourrage — il resterait treize pixels pour écrire « 148 ».
   ⚠️⚠️ LA RÉSERVE ÉTAIT EN `ch`, ET C'ÉTAIT LA FAUTE (corrigé le 11/08, Amadou : « le même
   bug qu'au niveau des sous-boutons »). `ch` vaut la largeur du zéro DANS LA POLICE
   COURANTE — donc elle change deux fois toute seule :
     · quand Inter finit de charger, `2.4ch` ne mesure plus la même chose qu'au premier
       rendu en police de repli. La réserve elle-même se met à bouger.
     · et quand la graisse change (voir `.vide` plus bas), `ch` change AVEC elle.
   Autrement dit, une réserve censée figer la largeur variait pour deux raisons. En
   pixels, elle ne bouge plus jamais, quelle que soit la police.
   ⭐ Et le compte est plafonné à « 99+ » côté JS : au-delà, aucune réserve ne tiendrait.
   ════════════════════════════════════════════════════════════════════════════ */
.cok-cmd-stab-n,
.an-so-n,
.lib-tier-tab-count,
.lib-marque-chip-count,
.src-stab .n,
.src-gab .n,
.src-usage-b .n,
.cok-cmd-grp .n,
.drafts-tab-n,
.cok-wtab-n {
  display: inline-block;
  box-sizing: content-box;
  font-variant-numeric: tabular-nums;
  /* ⚠️ DEUX CHIFFRES, pas trois. Réserver trois donnait des pastilles de 37 px pour
     afficher « 7 » : on remplaçait un décalage par un vide. Au-delà de 99, le JS écrit
     « 99+ », qui tient dans la même place. */
  min-width: 17px;
  text-align: center;
  /* ⚠️⚠️ ET LA GRAISSE NE CHANGE PLUS. `.vide` la passait de 700 à 500 : un compteur qui
     recevait son premier chiffre devenait plus GRAS, donc plus large, et poussait ses
     voisins — le décalage exact qu'Amadou décrit. Un zéro se distingue très bien par sa
     seule transparence. */
  font-weight: var(--fw-gras);
}

/* ── La bascule lancement → parcours ─────────────────────────────────────────
   Amadou (09/08) : « c'est brusque ». L'ancien écran s'efface en fondu pendant que
   le nouveau monte. 150 ms : assez pour que l'œil suive, trop court pour attendre.
   ⚠️ Ces classes sont posées UNE FOIS, au moment du clic, et retirées juste après.
   Les laisser ferait rejouer l'entrée à chaque rafraîchissement de la frise — soit
   un clignotement toutes les dix secondes, le défaut qu'on a déjà payé avec
   `velbo-entree`. */
.cp-sort { animation: cpSort .15s ease forwards; }
@keyframes cpSort { to { opacity: 0; transform: translateY(-6px); } }
.cp-entre { animation: cpEntre .34s cubic-bezier(.22,.61,.36,1) both; }
@keyframes cpEntre { from { opacity: 0; transform: translateY(10px); } }
/* Les étapes se posent l'une après l'autre — un décalage court, jamais rejoué. */
.cp-entre .cpf-e { animation: cpPas .3s ease both; }
.cp-entre .cpf-e:nth-child(2) { animation-delay: .04s; }
.cp-entre .cpf-e:nth-child(3) { animation-delay: .08s; }
.cp-entre .cpf-e:nth-child(4) { animation-delay: .12s; }
.cp-entre .cpf-e:nth-child(5) { animation-delay: .16s; }
.cp-entre .cpf-e:nth-child(6) { animation-delay: .2s; }
.cp-entre .cpf-e:nth-child(7) { animation-delay: .24s; }
@keyframes cpPas { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) {
  .cp-sort, .cp-entre, .cp-entre .cpf-e { animation: none; }
}

/* La fiche et l'écran arrivent en douceur avec le parcours, sans se déplacer. */
.cp-entre .cpf-fiche, .cp-entre .cpf-ecran { animation: cpPas .32s ease both; }
.cp-entre .cpf-ecran { animation-delay: .1s; }
.cp-entre .cpf-fiche { animation-delay: .14s; }

/* ── Le parcours vit AU-DESSUS des deux colonnes ─────────────────────────────
   ⚠️ Sa fiche ne change plus jamais de place ni d'état : seule la colonne de
   gauche échange son contenu (la carte de lancement, puis l'écran en direct).
   C'est ce qui règle les disparitions décalées — un seul élément bouge. */
.cok-horlo-g { min-width: 0; display: flex; flex-direction: column; gap: var(--e-18); }
.cok-horlo-g > * { margin-top: 0 !important; }
.cpf-droite { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap; }
/* Les boutons rejoignent la pastille : les gestes du parcours au même endroit
   que son état, au lieu d'être relégués tout en bas de la page. */
.cpf-droite .cpf-actions { display: flex; gap: var(--e-10); margin: 0; }

/* ── Les deux colonnes se calent sur la plus courte ──────────────────────────
   Choix d'Amadou (09/08) : c'est l'ÉCRAN qui décide de la hauteur — c'est lui
   qu'on regarde — et sa carte s'y adapte. Sa description défile à l'intérieur
   plutôt que d'allonger la colonne. Sans ça, les deux pavés finissaient à des
   hauteurs différentes et le bloc paraissait bancal. */
.cok-horlo { align-items: stretch; }
.cok-horlo > * { min-height: 0; }
#cp-fiche-place { display: flex; min-height: 0; }
#cp-fiche-place > * { flex: 1; display: flex; flex-direction: column; min-height: 0; }
/* La description prend ce qui reste, et défile si sa carte est plus haute que l'écran. */
#cp-fiche-place .cok-horlo-bio { flex: 1; min-height: 0; overflow: auto; }

/* ── L'écran d'attente a la taille de l'écran final ──────────────────────────
   Amadou (09/08). Le bloc « Son navigateur travaille » faisait 235 px de haut,
   l'image reçue en fait le double : la colonne changeait donc de hauteur au
   moment où la première photo arrivait, et sa fiche sautait avec elle. Les deux
   états partagent maintenant le même format — celui d'une fenêtre Brave. */
#cp-compte-etat .mdl-ecran-corps { aspect-ratio: 16 / 10; min-height: 0; }
#cp-compte-etat .mdl-ecran-corps.direct { display: flex; align-items: center;
  justify-content: center; overflow: hidden; }
#cp-compte-etat .mdl-ecran-corps.direct img { width: 100%; height: 100%;
  object-fit: contain; }
/* ⚠️⚠️ LE CADRE PREND LA FORME DE L'IMAGE, IL NE LA LUI IMPOSE PAS. Amadou (15/08) :
   « l'affichage de l'écran ne rentre pas entièrement dans l'écran, c'est moche. »
   Le 16/10 était une réservation de place — il évite que la colonne saute quand la
   première photo arrive (Amadou, 09/08) — mais une fenêtre Brave n'est PAS en 16/10 :
   la sienne est presque carrée. Résultat, deux bandes vides sur les côtés et une
   image rétrécie au milieu.
   Dès que l'image est là, le JS écrit sa vraie proportion dans `--ecran-forme` (voir
   `_cpEcranSuivre`) et le cadre s'y ajuste : plus de bandes, et toujours rien de
   coupé. Le plafond garde la colonne raisonnable — au-delà, `contain` reprend la
   main et l'image se contente d'être plus petite, jamais rognée.
   ⚠️ La proportion par défaut reste le 16/10 : `var()` sur une variable absente ne
   lève AUCUNE erreur dans ce projet, elle rend la déclaration muette. Le repli est
   donc écrit ici, dans le var() lui-même. */
#cp-compte-etat .mdl-ecran-corps.direct { aspect-ratio: var(--ecran-forme, 16 / 10);
  max-height: 58vh; }

/* ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ CE BLOC EST EN FIN DE FICHIER, ET CE N'EST PAS UN HASARD.
   Écrit d'abord au milieu, il était ÉCRASÉ par une règle de survol plus ancienne,
   de MÊME FORCE, située plus bas : `.cok-cmd-stab:not(.on):not(.active):hover`
   posait à nouveau le fond pâle. À force égale, c'est le dernier qui gagne — c'est
   la troisième fois aujourd'hui que ce détail change tout (l'écart des onglets, la
   graisse, et maintenant le survol).
   ⚠️ Mesuré dans le CSSOM, pas à l'œil : `getComputedStyle` ne recalcule pas sur un
   élément déjà en place, il m'aurait répondu que tout allait bien.
   ════════════════════════════════════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════════════════════════════
   LE SURVOL D'UN ONGLET TIRE VERS LE VIOLET, PAS VERS LE BLANC
   ══════════════════════════════════════════════════════════════════════════════
   Amadou, pour la troisième fois : « lorsque je survole les boutons, ça se met en
   gris ». Le fond de survol EST violet (`--survol-fond`), et pourtant il a raison.
   ⚠️⚠️ MESURÉ, PAS SUPPOSÉ. Fond de page rgb(16,19,31) ; onglet au repos
   rgb(26,28,40) ; au survol rgb(41,41,68). L'écart est de quinze points sur trois
   canaux : trop faible et trop sombre pour se lire comme une couleur. ET SURTOUT le
   survol force `color: var(--sur-accent)` — du blanc sur du presque-noir écrase la teinte, c'est
   le défaut déjà corrigé sur 115 règles le 10/08. Le texte blanchit, le fond bouge à
   peine : l'œil ne voit qu'un gris.
   ⭐ On inverse : au survol, le TEXTE prend le violet clair — la même teinte que
   l'onglet actif, en plus léger. Un onglet survolé annonce ainsi ce qu'il deviendra
   au clic, au lieu de se décolorer. C'est le changement le plus lisible et c'est le
   moins coûteux : la couleur du texte se voit toujours, un fond à 13 % non.
   ⚠️ `:not(.on):not(.active)` — un onglet DÉJÀ choisi ne doit pas bouger au survol. */
.cok-cmd-stab:not(.on):not(.active):hover,
.cok-cmd-grp:hover:not(.on):not([class*="on-"]),
.an-so:not(.on):not(.active):hover,
.cok-chip:not(.on):not(.active):hover,
.lib-filter:not(.active):not(.on):hover,
.src-stab:not(.on):not(.active):hover,
.drafts-tab:not(.active):not(.on):hover,
.cok-wtab:not(.on):not(.active):hover,
.lib-tier-tab:not(.active):not(.on):hover {
  /* ⚠️⚠️ CE SURVOL POSAIT LA COULEUR DE L'ÉTAT CHOISI (`--cok-accent-bg`, exactement ce
     qu'écrit `.on`). Sur huit familles d'onglets et de pastilles, frôler celui qu'on n'a
     PAS choisi le faisait passer pour choisi. Amadou (02/09), à l'étape Source : « lorsque
     je sélectionne une option et que je survole l'autre, ce n'est pas intuitif ».
     Le doigt reste neutre — `--survol-fond` — et l'accent appartient à ce qui est retenu.
     C'est déjà la règle des deux autres survols groupés de cette feuille. */
  background: var(--survol-fond);
  color: var(--text);
}

/* ── L'ESPACE PERSONNEL D'UNE VENDEUSE EN FORMATION ─────────────────────────
   Il répond à deux questions : qui est-elle, et est-ce qu'elle chauffe vraiment ?
   Les classes prolongent `form-*` de la liste — on n'invente pas un second dialecte. */
.form-carte-ecourt{font-size:var(--t-mini);color:var(--amber);margin-top:var(--e-4);line-height:var(--lh-normal)}
/* ⚠️ Le retour appartient à la FICHE, pas à l'en-tête de l'onglet. Il s'encastrait
   sous le sous-titre « Un compte migré chauffe… » et empiétait dessus. Il respire. */
.form-retour{margin:var(--e-2) 0 var(--e-18);font-size:var(--t-meta)}
.form-fiche-tete{display:flex;align-items:center;gap:var(--e-12);margin-bottom:var(--e-12)}
.form-fiche-qui{min-width:0}
.form-fiche-nom{font-size:var(--t-lead);font-weight:var(--fw-fort);letter-spacing:-.2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.form-fiche-sous{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-top:var(--e-2)}
.form-fiche-lien{margin-left:auto;flex:0 0 auto;font-size:var(--t-meta);text-decoration:none}

/* ⚠️ L'ESSENTIEL EN UNE PHRASE, avant tout bloc. La fiche ouvrait sur quatre tuiles de
   chiffres qui répétaient ce que la frise montre déjà — « 1/5 séances » et « prochaine
   dans 1 min » se lisent sur la frise, à leur vraie place dans la journée. */
.form-verdict{font-size:var(--t-body);font-weight:var(--fw-fort);color:var(--cok-text)}
.form-verdict-s{font-size:var(--t-meta);color:var(--cok-text-3);margin-top:var(--e-2);
  margin-bottom:var(--e-14)}
.form-jour-note{margin-top:var(--e-8);margin-bottom:0}
.form-bloc{background:rgba(var(--th-voile),.025);border:1px solid var(--cok-border,rgba(var(--th-voile),.07));
  border-radius:var(--r-lg);padding:var(--e-14) var(--e-16);margin-bottom:var(--e-10)}
.form-bloc-tete{display:flex;justify-content:space-between;align-items:baseline;gap:var(--e-10);
  font-size:var(--t-base);color:var(--text-muted,var(--text-2));margin-bottom:var(--e-8)}
.form-bloc-t{font-size:var(--t-base);font-weight:var(--fw-fort);margin-bottom:var(--e-4)}
.form-bloc-s{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));line-height:var(--lh-normal);margin-bottom:var(--e-12)}
.form-chiffres{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:var(--e-10);margin-top:var(--e-12)}
.form-chiffres b{display:block;font-size:var(--t-body);font-weight:var(--fw-fort);line-height:var(--lh-titre)}
.form-chiffres span{display:block;font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-top:var(--e-2)}
/* La journée de 24 h : son sommeil en creux, ses séances en points. */
.form-jour{position:relative;height:28px;background:var(--bg-hover);border-radius:var(--r-xs);overflow:hidden}
.form-nuit{position:absolute;top:0;height:100%;background:var(--cyan-tint);display:block}
.form-pt{position:absolute;top:10px;width:8px;height:8px;border-radius:50%;
  background:var(--green);margin-left:calc(var(--e-4) * -1);display:block}
.form-pt.rate{background:var(--red)}
.form-jour-h{display:flex;justify-content:space-between;font-size:var(--t-micro);
  color:var(--text-muted,var(--text-2));margin-top:var(--e-6)}
.form-seance{display:flex;gap:var(--e-12);padding:var(--e-10) 0;border-top:1px solid var(--cok-border,rgba(var(--th-voile),.07))}
.form-seance:first-of-type{border-top:0;padding-top:var(--e-2)}
.form-seance-h{flex:0 0 42px;font-size:var(--t-meta);color:var(--text-muted,var(--text-2));
  font-variant-numeric:tabular-nums;padding-top:var(--e-1)}
.form-seance-t{font-size:var(--t-base)}
.form-seance-d{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-top:var(--e-2)}
.form-seance-n{font-size:var(--t-mini);color:var(--amber);margin-top:var(--e-4);line-height:var(--lh-normal)}
.form-ecran-place{margin-bottom:var(--e-10)}
.form-actions{display:flex;gap:var(--e-8);flex-wrap:wrap}

/* ── L'ENTRÉE : un bandeau discret, puis une ligne par vendeuse ─────────────
   Cinq cartes de 210 px écrasaient tout — noms tronqués, chiffres sur trois lignes.
   En ligne, chaque information a sa colonne et se compare d'un coup d'œil. */
/* ⚠️ TROIS NIVEAUX, TROIS RESPIRATIONS. Amadou (13/08) : « c'est trop serré, je vois
   trois couches, espace un minimum ». L'en-tête, le bandeau et la liste se touchaient :
   l'œil ne savait pas où commençait quoi. Chaque niveau a maintenant sa marge. */
.form-bandeau{display:flex;align-items:center;gap:26px;flex-wrap:wrap;
  padding:0 var(--e-2) var(--e-18);border-bottom:1px solid var(--cok-border,rgba(var(--th-voile),.07));
  margin:var(--e-20) 0 var(--e-6)}
.form-chip{background:none;border:0;padding:0;cursor:pointer;display:flex;align-items:baseline;
  gap:var(--e-6);color:var(--text-muted,var(--text-2));font:inherit;transition:color .16s ease}
.form-chip b{font-size:var(--t-lead);font-weight:var(--fw-fort);line-height:var(--lh-titre);color:var(--text,var(--text))}
.form-chip span{font-size:var(--t-base)}
.form-chip:hover{color:var(--text,var(--text))}
.form-chip.on b,.form-chip.on span{color:var(--cyan,var(--cyan))}
.form-chip.vert.on b,.form-chip.vert.on span{color:var(--green)}
.form-chip.jaune.on b,.form-chip.jaune.on span{color:var(--amber)}
.form-chip.rouge.on b,.form-chip.rouge.on span{color:var(--red)}
.form-bandeau-alerte{margin-left:auto;font-size:var(--t-meta);color:var(--amber)}
.form-liste{display:flex;flex-direction:column}
.form-ligne{display:flex;align-items:center;gap:var(--e-20);padding:var(--e-20) var(--e-4);
  border-bottom:1px solid var(--cok-border,rgba(var(--th-voile),.07));transition:background .16s ease}
.form-ligne:last-child{border-bottom:0}
.form-ligne.cliquable{cursor:pointer}
.form-ligne.cliquable:hover{background:var(--surface)}
.form-pastille{width:6px;height:6px;border-radius:50%;flex:0 0 auto;background:var(--green)}
.form-ligne.jaune .form-pastille{background:var(--amber)}
.form-ligne.rouge .form-pastille{background:var(--red)}
.form-ligne.fini  .form-pastille{background:rgba(var(--th-voile),.30)}
/* ⚠️⚠️ UNE SEULE LIGNE POUR LE NOM ET SON PROFIL. Mesuré le 15/08 : le nom empilé
   au-dessus de son sous-titre fixait CHAQUE rangée à 82 px de haut — sept comptes
   remplissaient l'écran. Le profil (« C2 ») fait deux caractères ; il n'a jamais eu
   besoin d'une ligne à lui. Amadou : « c'est brouillon, les informations sont
   entassées ». */
.form-ligne-qui{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;gap:var(--e-8)}
.form-ligne-profil{flex:0 0 auto;font-size:var(--t-meta);color:var(--cok-text-3)}
.form-ligne-nom{font-size:var(--t-small);font-weight:var(--fw-fort);line-height:var(--lh-serre);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.form-ligne-sous{font-size:var(--t-meta);color:var(--text-muted,var(--text-2));margin-top:var(--e-4);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.form-ligne-barre{flex:0 0 180px;min-width:0}
.form-ligne-barre .form-barre{margin:0}
.form-ligne-reste{font-size:var(--t-meta);color:var(--cok-text-3);margin-top:var(--e-6)}
/* ⚠️⚠️ 172 px POUR UN TEXTE QUI EN DEMANDE 173. Mesuré le 15/08 sur la vraie donnée :
   « 1 séance · 13 pages · 11 favoris » réclame 173 px et la colonne en offrait 172.
   UN pixel — et « favoris » passait à la ligne, ce qui faisait monter CHAQUE rangée de
   la liste à 82 px de haut. C'est ça qu'Amadou voyait : « c'est brouillon, les
   informations sont entassées ». Pas un défaut de conception, une largeur figée à un
   cheveu près.
   ⚠️ D'où `nowrap` EN PLUS de la largeur : sans lui, le jour où un compte atteint
   100 séances le même défaut revient en silence. Une largeur fixe sans interdiction de
   coupure est une bombe à retardement. */
.form-ligne-faits{flex:0 0 calc(var(--e-48) * 4);white-space:nowrap;font-size:var(--t-meta);color:var(--text-muted,var(--text-2));line-height:var(--lh-normal)}
.form-ligne-ennui{flex:0 0 120px;font-size:var(--t-meta);color:var(--amber);line-height:var(--lh-normal)}
/* ⚠️ UNE BARRE TOUJOURS PLEINE N'EST PAS UNE INFORMATION. Mesuré : six lignes sur sept
   affichaient une barre à 100 % — une formation finie EST à 100 %, par définition. Elle
   occupait la colonne la plus large de la rangée pour ne rien apprendre, pendant que le
   texte utile (« elle peut vendre », « profil disparu ») se serrait ailleurs.
   Sur une formation finie, la barre disparaît et son texte prend la place. */
.form-ligne.fini .form-barre,
.form-ligne.finie .form-barre{display:none}
.form-ligne.fini .form-ligne-reste,
.form-ligne.finie .form-ligne-reste{margin-top:0}
.form-ligne-fleche{flex:0 0 auto;color:var(--text-muted,var(--text-2));opacity:.55}
.form-ligne.cliquable:hover .form-ligne-fleche{opacity:1}
/* ⚠️ AUX DEUX LARGEURS. En dessous de 1100 px les colonnes se marchent dessus :
   le rendement et l'ennui passent sous le nom plutôt que d'être rognés. */
@media (max-width:1100px){
  .form-ligne{flex-wrap:wrap;gap:var(--e-10) var(--e-18);padding:var(--e-18) var(--e-4)}
  .form-ligne-qui{flex:1 1 100%}
  .form-ligne-barre{flex:1 1 140px}
  .form-ligne-faits,.form-ligne-ennui{flex:0 0 auto}
  .form-ligne-fleche{margin-left:auto}
}

/* ⚠️ LA PASTILLE SEULE NE DIT RIEN. Un point vert à côté d'un nom ne s'interprète pas :
   on écrit le mot à côté. Il vit dans l'en-tête de l'écran, discret, entre le nom et
   la pastille — même bloc partout (Bibliothèque, Formation, création). */
.mdl-ecran-etat{margin-left:auto;font-size:var(--t-micro);letter-spacing:var(--ls-leger);
  color:var(--text-muted,var(--text-2));font-family:var(--font-sans,inherit)}
/* La pastille portait `margin-left:auto` : avec le mot devant elle, les deux marges
   se disputaient l'espace libre et la pastille partait se coller au bord. */
.mdl-ecran-tete .mdl-ecran-etat + .mdl-ecran-pt{margin-left:0}

/* ══════════════════════════════════════════════════════════════════════════════
   T. PRODUITS — QUATRE EMPLACEMENTS, ET CE QUI MANQUE SE VOIT
   ══════════════════════════════════════════════════════════════════════════════
   ⚠️⚠️ ÉCRIT EN MÊME TEMPS QUE LE JS, ET C'EST LE POINT. Trois fois aujourd'hui une
   classe a été nommée dans app.js sans jamais être stylée ici : le prix d'une
   commande, le panneau de détail, les tuiles du Sourcing. Rien ne prévient — le
   rendu ne plante pas, il s'affiche nu. On écrit donc les deux d'un seul geste.
   ⚠️ Bloc en fin de fichier : à force égale, c'est le dernier qui gagne. */
.dress-prod-tete { display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-12); flex-wrap: wrap; margin-bottom: var(--e-12); }
.dress-prod-qui { display: flex; align-items: center; gap: var(--e-8); min-width: 0; }
.dress-prod-nom { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.dress-prod-sub { font-size: var(--t-mini); color: var(--text-3); }
/* ⚠️ La phrase dit une CONSÉQUENCE, pas un compte — elle mérite donc d'être lue :
   teinte pleine, jamais grise. */
.dress-prod-etat { font-size: var(--t-meta); padding: var(--e-4) var(--e-10); border-radius: var(--r-md);
  background: var(--bg-hover); color: var(--text-2); }
.dress-prod-etat.ok    { background: rgba(74,222,128,0.13); color: var(--green); }
.dress-prod-etat.moyen { background: rgba(240,176,85,0.14); color: var(--amber); }
.dress-prod-etat.vide  { background: rgba(var(--th-danger-rgb),0.13); color: var(--red); }

.dress-prod-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--e-10); }
.dress-prod-case { min-width: 0; }
.dress-prod-case > .model-view-cell, .dress-prod-case > .dress-prod-vide {
  width: 100%; aspect-ratio: 3 / 4; border-radius: var(--r-md); overflow: hidden; }
/* L'emplacement VIDE reste dessiné : c'est tout l'objet de la refonte. Une grille qui
   n'affiche que l'existant ne dit jamais ce qui manque. */
.dress-prod-vide { display: flex; align-items: center; justify-content: center; cursor: pointer;
  border: 1px dashed rgba(var(--th-voile),0.16); color: var(--text-3);
  background: var(--cok-bg-2);
  transition: border-color var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose); }
.dress-prod-vide:hover { border-color: var(--violet-glow); color: var(--violet-light, #B9AEFF); }
.dress-prod-lbl { font-size: var(--t-meta); color: var(--text-2); margin-top: var(--e-6);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dress-prod-st { font-size: var(--t-micro); color: var(--amber); margin-top: var(--e-1); }
.dress-prod-st.ok { color: var(--green); }

.dress-prod-autres { display: flex; align-items: center; flex-wrap: wrap; gap: var(--e-6); margin-top: var(--e-16); }
.dress-prod-autres-l { font-size: var(--t-mini); font-weight: var(--fw-fort); letter-spacing: var(--ls-large);
  text-transform: uppercase; color: var(--text-3); margin-right: var(--e-4); }
.dress-prod-chip { display: inline-flex; align-items: center; gap: var(--e-8); font: inherit;
  font-size: var(--t-meta); cursor: pointer; color: var(--text-2);
  background: rgba(var(--th-voile),0.04); border: 1px solid transparent;
  border-radius: var(--r-md); padding: var(--e-6) var(--e-10); }
.dress-prod-chip:hover { background: var(--violet-tint); color: var(--violet-light, #B9AEFF);
  border-color: var(--tier-premium-glow); }
.dress-prod-chip b { font-weight: var(--fw-fort); color: var(--green); }
.dress-prod-chip b.zero { color: var(--text-3); }

/* Sous 1100 px la colonne de droite se resserre : deux emplacements par rangée
   plutôt que quatre écrasés. */
@media (max-width: 1100px) {
  .dress-prod-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ── QUI CONDUIT QUOI ────────────────────────────────────────────────────────
   Même dialecte que la liste de Formation : une ligne par vendeuse, chaque
   information dans sa colonne, et les doutes en haut. */

/* ══ LIENS — LE VERDICT D'ABORD ══════════════════════════════════════════════
   Amadou (15/08) : « la partie lien, c'est vraiment mal fait, l'interface n'est pas
   pertinente ». Mesuré sur le serveur : 21 liens, 21 sûrs, ZÉRO à relire. L'écran dont
   le métier est de faire relire les liens devinés n'avait rien à faire relire — et
   déroulait quand même 21 rangées. Un écran de sécurité rassure en une phrase ; il ne
   fait pas lire une liste. */
/* ⚠️ CE VERDICT N'APPARTIENT PLUS AUX LIENS. La Vigie s'en sert aussi : deux écrans
   qui répondent à la même sorte de question — « est-ce que ça tient ? » — doivent se
   lire pareil. Un deuxième dessin pour la même idée finirait par diverger, comme
   `.mac-c` a failli le faire. */
.v-verdict { font-size: var(--t-body); font-weight: var(--fw-fort); color: var(--cok-text);
  margin-top: var(--e-4); }
.v-verdict-s { font-size: var(--t-meta); color: var(--cok-text-3); margin-top: var(--e-2); }

/* ⚠️ CETTE ALERTE EXISTAIT DÉJÀ DANS LA DONNÉE, noyée en petit gris dans un sous-titre :
   `etat: "inconnu du serveur"`. C'est pourtant la seule chose actionnable de l'écran —
   un lien qui tient sur un compte que la machine ne voit plus. */
.v-alerte { margin-top: var(--e-14); padding: var(--e-10) var(--e-12);
  border-radius: var(--r-md); background: var(--moy-bg); color: var(--cok-amber);
  font-size: var(--t-base); line-height: var(--lh-normal); }
.v-alerte b { font-weight: var(--fw-fort); }

/* ⚠️⚠️ « UNE CLASSE NOMMÉE N'EST PAS UNE CLASSE STYLÉE » — repris deux fois déjà. La
   liste de la vigie vient après un verdict : sans cette règle, elle se collerait
   dessus et le verdict se lirait comme la première ligne de la liste. */
.vig-liste { margin-top: var(--e-16); }
/* ══ LE CENTRE DE CONTRÔLE DU DÉMASQUAGE ═════════════════════════════════════
   Remplace un écran qui portait un scan manuel, un choix de motif, un dépôt de photos et
   un bouton « Démasquer l'annonce ».
   ⚠️⚠️ LE CHIFFRE DE TÊTE EST LE TRAVAIL, PAS LE STOCK. Amadou : « les annonces masquées
   sont censées être démasquées dans les minutes qui suivent, donc pourquoi mettre le
   nombre de masquées ? ». Un stock ne raconte rien quand la machine tourne — il reste à
   zéro. On met donc en tête ce que ça COÛTE : les favoris qui dorment.
   ⚠️ Et UN SEUL grand chiffre : trois nombres nus alignés ne se hiérarchisent pas,
   l'œil ne sait pas lequel lire. Le reste passe dans la phrase. */
/* ⚠️ LE CONTENEUR EST LA BOÎTE, PAS LA GRILLE. Première écriture : `container-type` posé
   sur `.rp-corps`, et la requête `@container` visait `.rp-corps` — un élément ne peut PAS
   répondre à sa propre largeur, sinon la mesure changerait ce qu'elle mesure. Résultat :
   une seule colonne à 1600 px, sans erreur ni avertissement. Le conteneur se met sur le
   PARENT de ce qu'on veut styler. */
.rp-box { border: 1px solid var(--cok-border); border-radius: var(--r-xl);
  background: var(--cok-card); overflow: hidden;
  container-type: inline-size; container-name: dmq; }

.rp-tete { padding: var(--e-20) var(--e-24) var(--e-18);
  border-bottom: 1px solid var(--cok-border); }
/* L'état tient dans une pastille. Il tenait dans un pavé orange qui écrasait l'écran :
   un état se signale, il ne se crie pas. */
.rp-pil { display: inline-flex; align-items: center; gap: var(--e-6);
  font-size: var(--t-mini); letter-spacing: .06em; text-transform: uppercase;
  color: var(--cok-amber); background: var(--moy-bg);
  border: 1px solid var(--cok-border-2); padding: var(--e-4) var(--e-12);
  border-radius: var(--r-pilule); }
.rp-pt { width: 5px; height: 5px; border-radius: 50%; background: var(--cok-amber); }
.rp-pil.ok { color: var(--cok-green); background: var(--cok-green-bg); }
.rp-pil.ok .rp-pt { background: var(--cok-green); }

.rp-hero { display: flex; align-items: baseline; gap: var(--e-10); margin-top: var(--e-12); }
.rp-hn { font-size: var(--t-display); font-weight: var(--fw-moyen); color: var(--cok-text);
  line-height: var(--lh-un); font-variant-numeric: tabular-nums; }
.rp-hl { font-size: var(--t-lead); color: var(--cok-text-2); }
.rp-sub { font-size: var(--t-base); color: var(--cok-text-3); margin-top: var(--e-6);
  line-height: var(--lh-normal); max-width: 62ch; }

/* ⚠️⚠️ LA JAUGE DIT CE QU'AUCUN CHIFFRE NE DISAIT : la concentration. Trois annonces
   pèsent 180 des 312 favoris — savoir qu'il y en a dix-neuf n'aide pas, savoir que trois
   valent plus que les seize autres réunies, si. */
.rp-jauge { display: flex; gap: var(--e-2); margin-top: var(--e-14); height: 6px;
  border-radius: var(--r-sm); overflow: hidden; }
.rp-jauge i { display: block; height: 100%; }
.rp-ja { background: var(--cok-amber); }
.rp-jb { background: var(--cok-accent); }
.rp-jc { background: var(--cok-border-2); }
.rp-leg { display: flex; gap: var(--e-16); margin-top: var(--e-8); flex-wrap: wrap;
  font-size: var(--t-mini); color: var(--cok-text-3); }
.rp-leg span { display: inline-flex; align-items: center; gap: var(--e-6); }
.rp-leg b { width: 7px; height: 7px; border-radius: 2px; }

/* ⚠️ DEUX COLONNES, PARCE QU'IL Y A DEUX HISTOIRES : ce qui attend, ce qui a été fait.
   Élargir une liste unique n'aurait fait que rallonger ses lignes.
   ⚠️ La mesure porte sur la BOÎTE, pas sur la fenêtre : le canevas fait 1322 px pour une
   fenêtre de 1600, et c'est la boîte qui manque de place, pas l'écran. */
.rp-corps { display: grid; grid-template-columns: 1fr; }
.rp-col { padding: var(--e-16) var(--e-24) var(--e-20); min-width: 0; }
.rp-col + .rp-col { border-top: 1px solid var(--cok-border); }
@container dmq (min-width: 860px) {
  .rp-corps { grid-template-columns: 1fr 1fr; }
  .rp-col + .rp-col { border-top: 0; border-left: 1px solid var(--cok-border); }
}
.rp-ct { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--e-10); margin-bottom: var(--e-6); }
.rp-cl { font-size: var(--t-mini); letter-spacing: .07em; text-transform: uppercase;
  color: var(--cok-text-3); }
.rp-cn { font-size: var(--t-base); color: var(--cok-text-2);
  font-variant-numeric: tabular-nums; }

/* Les filtres vivent SOUS le titre de la colonne qu'ils filtrent — flottants au-dessus,
   on ne savait pas ce qu'ils commandaient. */
.rp-f { display: flex; gap: var(--e-4); margin: var(--e-2) 0 var(--e-8); flex-wrap: wrap; }
.rp-f button { font: inherit; font-size: var(--t-mini); padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule); border: 1px solid var(--cok-border);
  background: none; color: var(--cok-text-3); cursor: pointer;
  transition: border-color var(--t-bref), color var(--t-bref), background var(--t-bref); }
.rp-f button:hover { border-color: var(--cok-border-2); color: var(--cok-text-2); }
.rp-f button.on { background: var(--cok-accent-bg); border-color: var(--cok-accent);
  color: var(--cok-accent); }

.rp-l { display: flex; align-items: center; gap: var(--e-12); padding: var(--e-8) 0;
  border-top: 1px solid var(--cok-border); }
.rp-l:first-of-type { border-top: 0; }
.rp-v { width: 28px; height: 36px; border-radius: var(--r-sm);
  background: var(--surface-3); flex: 0 0 auto; }
.rp-t { flex: 1 1 auto; min-width: 0; }
.rp-ti { font-size: var(--t-base); color: var(--cok-text-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rp-cp { font-size: var(--t-mini); color: var(--cok-text-3); margin-top: var(--e-2); }
.rp-q { flex: 0 0 auto; text-align: right; font-variant-numeric: tabular-nums; }
.rp-qn { font-size: var(--t-base); color: var(--cok-text-2); line-height: var(--lh-serre); }
.rp-qn.ok { color: var(--cok-green); }
.rp-ql { font-size: var(--t-mini); color: var(--cok-text-3); letter-spacing: .03em; }
/* Au-delà de 30 favoris, l'annonce coûte assez cher pour se voir sans être cherchée. */
.rp-l.top .rp-qn { color: var(--cok-amber); font-weight: var(--fw-fort); }
.rp-l.top .rp-ti { color: var(--cok-text); }

/* ⚠️ LE VIDE SE DESSINE. Une phrase grise abandonnée dans un coin donne un écran qui a
   l'air cassé ; un bloc centré donne un écran qui attend. */
.rp-vide { padding: var(--e-24) 0 var(--e-8); text-align: center; }
.rp-vi { width: 34px; height: 34px; margin: 0 auto var(--e-10); border-radius: 50%;
  border: 1px dashed var(--cok-border-2); display: flex; align-items: center;
  justify-content: center; }
.rp-vi::after { content: ''; width: 11px; height: 11px; border-radius: 50%;
  background: var(--cok-border-2); }
.rp-vt { font-size: var(--t-base); color: var(--cok-text-3); line-height: var(--lh-normal);
  max-width: 34ch; margin: 0 auto; }

/* ══ LA SALLE DES OUVRIERS ═══════════════════════════════════════════════════
   Amadou : « c'est l'endroit où on gère nos salariés, il faut quelque chose de
   spécial — une table de réunion avec à chaque chaise un bouton ».
   ⚠️⚠️ TROIS FORMES ONT ÉTÉ JETÉES AVANT CELLE-CI : une liste de cinq lignes, une
   grille de cartes, un tableau d'interrupteurs. Trois fois « c'est moche », et trois
   fois il avait raison. Le défaut n'était pas le dessin : on affichait un RÉGLAGE là
   où il fallait montrer une ÉQUIPE. Une chaise vide dit « personne ne fait ce
   travail » mieux qu'un interrupteur sur « arrêt » — on voit le manque au lieu de
   lire un état. */
.sal { padding: var(--e-8) 0 var(--e-16); }
/* ⚠️ LA PIÈCE PREND LA LARGEUR QU'ON LUI DONNE. Amadou : « l'écran au final sera plus
   large que ça ». À 680 px tout se marche dessus ; à 1100 chaque place respire. Le
   plafond est là pour que la salle ne devienne pas une banderole sur un écran 4K. */
/* ⚠️⚠️ LA PIÈCE SUIT L'ÉCRAN, MAIS RESTE UNE PIÈCE. Amadou : « l'onglet doit être
   responsive en largeur selon la taille de l'écran ». Une largeur figée laissait un
   grand écran à moitié vide ; une hauteur figée transformait un grand écran en
   BANDEROLE. La hauteur suit donc la largeur — bornée aux deux bouts, pour qu'on ne
   descende jamais sous une salle lisible ni ne monte jusqu'à une salle de cinéma. */
.sal-piece { position: relative; width: 100%; height: clamp(320px, 30vw, 520px);
  margin: 0 auto; border-radius: var(--r-xl); overflow: hidden;
  container-type: inline-size; container-name: salle; }

/* ── LE DÉCOR ─────────────────────────────────────────────────────────────────
   Ce qui peut s'étirer est en CSS ; ce qui doit garder ses proportions (fenêtres,
   suspension, plante) est un SVG à taille fixe, posé par-dessus. Un décor entier en
   `preserveAspectRatio="none"` s'aplatit dès qu'on élargit la pièce. */
.sal-mur, .sal-lampe { pointer-events: none; }
/* ⚠️ LES RÈGLES DES FENÊTRES PARTENT AVEC ELLES. Une classe qui ne s'applique plus à
   rien n'est pas neutre : c'est la prochaine personne qui la croit vivante et cherche
   pourquoi elle ne fait rien. */
.sal-mur { position: absolute; inset: 0;
  background: linear-gradient(180deg, var(--surface-3), var(--surface-2)); }

.sal-lampe { position: absolute; left: 50%; top: 0; width: 104px; height: 54px;
  transform: translateX(-50%); }
.sal-fil { fill: var(--cok-border-2); }
.sal-abat { fill: var(--surface-3); stroke: var(--cok-accent); stroke-opacity: .45; }
.sal-ampoule { fill: var(--cok-accent); opacity: .32; }

/* LA TABLE, vue de dessus. Ses proportions sont celles que le calcul des places
   utilise (`_SAL_RX/_SAL_RY/_SAL_CX/_SAL_CY` dans app.js) : les changer ici sans les
   changer là-bas décrocherait les chaises du plateau. */
/* LA TABLE, éclairée par la suspension : le plateau est plus clair au point que le
   cône touche, et non uniformément — c'est ce qui la fait exister dans la pièce. */
.sal-table { position: absolute; left: 8%; top: 50%; width: 84%; height: 30%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 34%, rgba(var(--th-accent-rgb), .26),
              rgba(var(--th-accent-rgb), .09) 55%, var(--surface-2));
  border: 1px solid var(--cok-border-2);
  box-shadow: inset 0 1px 0 rgba(var(--th-voile), .16); }

.sal-centre { position: absolute; left: 50%; top: 66%; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: var(--e-2);
  text-align: center; pointer-events: none; }
.sal-compte { font-size: var(--t-display); font-weight: var(--fw-moyen); color: var(--cok-text);
  line-height: var(--lh-un); }
.sal-compte i { font-style: normal; font-size: var(--t-lead); color: var(--cok-text-3);
  margin-left: var(--e-4); }
.sal-l { font-size: var(--t-base); color: var(--cok-text-3); }
.sal-s { font-size: var(--t-meta); color: var(--cok-text-3); margin-top: var(--e-4); }

/* UNE PLACE. Elle est ancrée sur le bord de l'ellipse : la chaise est DERRIÈRE ce
   point, la plaque de nom devant — donc posée sur le plateau. */
/* ⚠️ LA PLAQUE DOIT TOMBER SUR LE PLATEAU, pas flotter au-dessus. On pousse donc la
   station sous son point d'ancrage : le point est le bord de l'ellipse, la chaise reste
   derrière, la plaque passe devant — donc sur la table. */
/* ⚠️⚠️ UNE LARGEUR EN DUR NE PEUT PAS MARCHER. Mesuré à 820 px de fenêtre : la salle
   tombe à 516 px, l'écart entre deux places passe à 104 px, et des stations de 128 px se
   chevauchaient de 33. L'écart vaut toujours `2·ÉTAL·RX/(n−1)` de la largeur, soit 20 % ;
   une place doit donc se mesurer en POURCENTAGE de la pièce, jamais en pixels. */
.sal-p { position: absolute;   /* la transform est calculée par station, dans app.js */
  /* 20 % est l'écart exact entre deux places ; la rentrée vers le centre en mange
     encore ~9 px. 17,5 % laisse le jeu qu'il faut à toutes les largeurs. */
  /* ⚠️ Le plafond doit suivre la pièce : à 1100 px, 17,5 % font 192 — un plafond à
     140 laissait 84 px de trou entre les places du milieu et 3 px entre celles du
     bord. Un maximum trop bas ne serre pas, il DÉSÉQUILIBRE. */
  width: 17.5%; max-width: 200px; display: flex; flex-direction: column; align-items: center;
  gap: var(--e-2); background: none; border: 0; padding: 0;
  font: inherit; cursor: pointer; text-align: center; }

/* ⚠️⚠️ LA CHAISE EXISTE VRAIMENT MAINTENANT. Elle n'était qu'un trait de 13 px sous les
   pieds : à l'écran on ne voyait personne assis, on voyait une silhouette qui flotte.
   Dossier arrondi derrière les épaules, assise en travers — et le buste par-dessus, pour
   qu'on lise « quelqu'un est assis là » et non « une forme et un meuble ». */
/* ⚠️ UNE SILHOUETTE QUI PREND TOUTE LA PLACE N'EST PLUS UNE PERSONNE, C'EST UNE AFFICHE.
   `width: 100%` d'une station de 17,5 % donnait 171 px de large à 976 px de pièce : les
   cinq écrasaient la table et le compte central. Une personne assise se mesure en
   dizaines de pixels, pas en fraction de l'écran. */
.sal-fig { display: block; width: 100%; max-width: 92px; height: auto; margin: 0 auto;
  transition: filter var(--t-moyen), transform var(--t-bref); }
.sal-dos, .sal-assise { fill: none; stroke: var(--cok-border-2); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round;
  transition: stroke var(--t-bref); }
.sal-corps { fill: var(--cok-inactif); transition: fill var(--t-moyen); }
/* ⚠️⚠️ L'EMBLÈME EST RETIRÉ DE LA MATIÈRE PAR UN MASQUE SVG, il n'est pas peint
   par-dessus. Peint, il fallait lui choisir une couleur qui tienne sur seize thèmes ET
   sur un corps qui change de teinte (éteint, allumé, survolé) — impossible. Retiré, ce
   qu'on voit à travers est la pièce : le contraste est celui de la silhouette elle-même,
   donc il ne peut pas se tromper. */

/* ⚠️ LE SURVOL NE PEUT PAS ÊTRE POSÉ SUR `.sal-p` : sa `transform` porte la POSITION de
   la place, calculée station par station dans app.js — la remplacer déplacerait la
   chaise à travers la pièce. Et un simple éclaircissement ne se voyait pas : ce qui se
   lit, c'est le MOUVEMENT — l'ouvrier se redresse, comme quelqu'un à qui on s'adresse. */
.sal-p:hover:not([disabled]) .sal-fig { transform: translateY(-4px);
  filter: drop-shadow(0 0 8px rgba(var(--th-accent-rgb), .26)); }
.sal-p:hover:not([disabled]) .sal-corps { fill: var(--cok-text-2); }
.sal-p:hover:not([disabled]) .sal-dos,
.sal-p:hover:not([disabled]) .sal-assise { stroke: var(--cok-border); }

/* Au travail : le corps s'allume et rayonne, et sa chaise avec lui. */
.sal-p.on .sal-corps { fill: var(--cok-accent); }
.sal-p.on .sal-dos, .sal-p.on .sal-assise { stroke: var(--cok-accent); stroke-opacity: .6; }
.sal-p.on .sal-fig { filter: drop-shadow(0 0 9px rgba(var(--th-accent-rgb), .55)); }
.sal-p.on:hover:not([disabled]) .sal-fig {
  filter: drop-shadow(0 0 14px rgba(var(--th-accent-rgb), .75)); }

/* LA PLAQUE, posée sur le plateau devant sa chaise. */
.sal-nom { font-size: var(--t-base); color: var(--cok-text-3); white-space: nowrap;
  transition: color var(--t-bref); }
.sal-p.on .sal-nom { color: var(--cok-text); font-weight: var(--fw-fort); }
/* ⚠️ HAUTEUR FIXE. Sans elle, une plaque d'une ligne et une plaque de deux ne
   s'alignent pas, et les cinq chaises se retrouvent à cinq hauteurs — l'arc de la table
   disparaît. C'est le même défaut que les plaques en dents de scie de la version bande. */
.sal-q { font-size: var(--t-meta); color: var(--cok-text-3); line-height: var(--lh-serre);
  min-height: calc(var(--t-meta) * var(--lh-serre) * 2); }
.sal-p.on .sal-q { color: var(--cok-accent); }

/* La place choisie : son corps s'éclaircit et sa chaise se marque, sans prendre la
   couleur du travail — « je te regarde » n'est pas « tu bosses ». */
.sal-p.choisi .sal-corps { fill: var(--cok-text-2); }
.sal-p.choisi .sal-dos, .sal-p.choisi .sal-assise { stroke: var(--cok-border); }
.sal-p.choisi.on .sal-corps { fill: var(--cok-accent); }

/* ══ L'ESPACE D'UN OUVRIER ═══════════════════════════════════════════════════
   Amadou : « quand on appuie sur les ouvriers, on doit avoir un espace à eux qui
   s'ouvre », et « en bas, vu qu'il y a de l'espace ».
   ⚠️ Il se pose SOUS la salle, dans la place qui était vide : l'écran ne s'allonge pas
   d'un panneau, il remplit ce qu'il laissait perdre. */
.sal-esp { max-width: 560px; margin: var(--e-16) auto 0;
  border: 1px solid var(--cok-border); border-radius: var(--r-lg);
  background: var(--cok-card); padding: var(--e-16) var(--e-18) var(--e-18); }
.sal-esp-tete { display: flex; align-items: flex-start; gap: var(--e-12); }
.sal-esp-nom { font-size: var(--t-lead); color: var(--cok-text); }
.sal-esp-quoi { font-size: var(--t-base); color: var(--cok-text-3); margin-top: var(--e-2);
  line-height: var(--lh-serre); }
.sal-esp-x { margin-left: auto; flex: 0 0 auto; background: none; border: 0;
  font: inherit; font-size: var(--t-lead); line-height: var(--lh-un);
  color: var(--cok-text-3); cursor: pointer; padding: 0 var(--e-2); }
.sal-esp-x:hover { color: var(--cok-text); }

.sal-esp-faits { display: flex; gap: var(--e-32); margin: var(--e-16) 0; }
.sal-esp-f { display: flex; flex-direction: column; gap: var(--e-2); }
.sal-esp-f .l { font-size: var(--t-meta); color: var(--cok-text-3); }
.sal-esp-f .v { font-size: var(--t-base); color: var(--cok-text-2); }
.sal-esp-f .v.on { color: var(--cok-accent); }
.sal-esp-btn { width: 100%; }
.sal-esp-note { font-size: var(--t-meta); color: var(--cok-text-3); line-height: var(--lh-normal); }

/* ⚠️ Un ouvrier forcé depuis le serveur ne se commande PAS d'ici : sa chaise doit se
   voir inerte, sinon c'est un bouton mort — le défaut que ce projet traque. */
.sal-p.fige { cursor: not-allowed; }
.sal-p.fige .sal-dos, .sal-p.fige .sal-assise { stroke-dasharray: 3 3; }

/* ⚠️ SOUS 640 px, LA PLAQUE PERD SA LIGNE DE TÂCHE. En dessous, une place fait moins de
   120 px : la tâche y tombe sur trois lignes, la plaque grandit, et les cinq chaises ne
   sont plus sur le même arc — le cercle disparaît. Le nom suffit à ce format ; ce que
   fait l'ouvrier se lit dès qu'on élargit. Mieux vaut en montrer moins que casser la
   seule chose que cet écran raconte. */
@container salle (max-width: 640px) {
  .sal-q { display: none; }
}

/* Le profil devant le compte : c'est par LUI qu'on va le chercher sur le VDS, et c'est
   lui que nomme l'alerte (« C3, C10 : rien ne renouvelle ces sessions »). En retrait,
   parce qu'il situe — il ne remplace pas le nom du compte.
   ⚠️ « Une classe nommée n'est pas une classe stylée » : sans cette règle, `ses-profil`
   n'aurait RIEN fait et le profil se serait collé au pseudo, sans erreur nulle part. */
.ses-profil { display: inline-block; min-width: var(--e-32); margin-right: var(--e-8);
  color: var(--cok-text-3); font-variant-numeric: tabular-nums; }

/* ── LA FICHE D'UN LIEN — ce qui SOUTIENT le lien, point par point ── */
/* ⚠️ Une réserve n'est pas une faute : elle se dit en gris, pas en rouge. Peindre en
   rouge « son nom porte le compte » ferait croire à une anomalie alors que c'est le cas
   le plus courant du parc. */

/* ══ LES COMPTES D'UN LIEN ═══════════════════════════════════════════════════
   Amadou (15/08) : « le compte ou les comptes concernés, même avant validation ».
   ⚠️ Mesuré : 25 fiches sur 58 portent d'anciens comptes, et plusieurs n'ont QUE ça.
   Le serveur les sautait (`if not uid: continue`) : leur compte a vécu, et personne
   ne pouvait plus le retrouver ici. On n'attend pas qu'un lien soit confirmé pour
   dire de quels comptes il parle. */

/* Une vendeuse libre n'est pas en faute : elle est disponible. Gris, jamais rouge. */
@media (max-width:1000px){
}

/* ── TON ESPACE : une ligne d'état, plus un menu ──────────────────────────────
   ⚠️ Elle prend la place du sélecteur retiré le 13/08 et calque `.api-status`, sa
   voisine immédiate : même retrait, même gap, même discrétion. Elle ne se clique pas —
   c'est voulu. Un espace privé qu'on change en frôlant le bas de la barre n'est pas un
   espace privé ; le choix est dans Paramètres › Sécurité.
   ⚠️ On NE touche PAS à `.identite-btn` / `.identite-menu` / `.identite-opt` : le
   sélecteur de compte de l'écran Commandes les réutilise, et les retirer le casserait. */
.identite-ligne {
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-6) var(--e-10);
  color: var(--text-3); font-size: var(--t-mini);
  overflow: hidden; min-width: 0;
}
.identite-ligne svg { flex: 0 0 auto; }
.identite-ligne span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.identite-ligne b { color: var(--text-2); font-weight: var(--fw-fort); }
.sidebar.collapsed .identite-ligne span { display: none; }

/* ══ LE JOURNAL ══════════════════════════════════════════════════════════════
   ⚠️⚠️ RIEN N'EST INVENTÉ ICI, ET LA PREMIÈRE VERSION L'AVAIT OUBLIÉ. La cloche est un
   `nav-item` avec `.nav-ic` + `.nav-badge` — les classes que Vendeuses utilise déjà. La
   modale est `modal-card--settings`, la carte des Paramètres, telle quelle : Amadou
   (13/08) « le journal doit prendre la même place que la partie paramètres ». Ma
   première carte, à 470 px, « ressemblait » aux Paramètres ; elle faisait la moitié.
   Ne restent ici que les trois choses qui n'existaient nulle part : la bande de filtres,
   la carte d'un fait, et la ligne d'un fait mineur. */

/* Le corps calque `.pa-body` — même hauteur, même respiration, même défilement. */
.jr-corps { padding: var(--e-20) var(--e-22); overflow-y: auto; height: 540px; max-height: 66vh; }
/* La bande de filtres calque `.pa-tabs` : elle tient la place des onglets Paramètres. */
.jr-filtres {
  display: flex; gap: var(--e-6); flex-wrap: wrap;
  padding: 0 var(--e-22) var(--e-14); flex-shrink: 0;
  border-bottom: 1px solid var(--border);
}
.jr-f {
  font-size: var(--t-meta); padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule);
  border: 1px solid var(--border-mid); background: transparent;
  color: var(--text-2); cursor: pointer; font-family: inherit;
  transition: color var(--t-moyen), border-color var(--t-moyen);
}
.jr-f:hover { color: var(--text); border-color: var(--border-strong); }
.jr-f.on { background: var(--violet-tint-strong); border-color: transparent; color: var(--violet-light); }

.jr-groupe {
  font-size: var(--t-micro); letter-spacing: var(--ls-ample); color: var(--text-3);
  padding: var(--e-14) var(--e-2) var(--e-8); text-transform: uppercase; font-weight: var(--fw-gras);
}
.jr-groupe:first-child { padding-top: 0; }

.jr-main {
  margin-bottom: var(--e-10); padding: var(--e-12) var(--e-14); border-radius: var(--r-lg);
  background: var(--bg-card-solid); border: 1px solid var(--border-mid);
  display: flex; gap: var(--e-12); align-items: flex-start;
}
.jr-main.g-ban    { border-color: rgba(236,160,160,0.35); }
.jr-main.g-flotte { border-color: rgba(229,194,138,0.30); }
.jr-main .jr-ic { flex-shrink: 0; margin-top: var(--e-1); color: var(--text-2); }
.jr-main.g-ban    .jr-ic { color: var(--red); }
.jr-main.g-flotte .jr-ic { color: var(--amber); }
.jr-t { font-size: var(--t-base); color: var(--text); margin-bottom: var(--e-6); }
.jr-d { font-size: var(--t-small); color: var(--text-2); line-height: var(--lh-normal); white-space: pre-line; }
.jr-quand { font-size: var(--t-meta); color: var(--text-3); white-space: nowrap; flex-shrink: 0; }
.jr-actions { display: flex; gap: var(--e-8); margin-top: var(--e-12); flex-wrap: wrap; }
.jr-a {
  font-size: var(--t-small); padding: var(--e-6) var(--e-12); border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid var(--border-mid); background: transparent; color: var(--text-2);
  font-family: inherit; transition: color var(--t-moyen), border-color var(--t-moyen);
}
.jr-a:hover { color: var(--text); border-color: var(--border-strong); }
.jr-a.fort { background: var(--violet-tint-strong); border-color: transparent; color: var(--violet-light); }

/* Un fait d'information : UNE ligne. Il ne mérite pas une carte. */
.jr-info { display: flex; gap: var(--e-12); align-items: center; padding: var(--e-8) var(--e-2); position: relative; }
.jr-info .jr-ic { color: var(--text-3); flex-shrink: 0; }
.jr-info.ok .jr-ic { color: var(--green); }
.jr-info .jr-t { font-size: var(--t-small); color: var(--text-2); margin: 0; flex: 1; min-width: 0; }

/* Une alerte LEVÉE : ce qui l'a fait taire en titre, ce qui avait crié en dessous.
   Le détail passe d'un cran en dessous du titre, sinon les deux se valent et on ne
   sait plus lequel est la nouvelle. */
.jr-leve { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--e-2); }
.jr-leve .jr-d { font-size: var(--t-meta); color: var(--text-3); }

/* Non lu : un point, pas un fond coloré — il signale, il ne hurle pas. */
.jr-neuf { position: relative; }
.jr-neuf::before {
  content: ''; position: absolute; left: -10px; top: 18px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--violet);
}
.jr-info.jr-neuf::before { top: 50%; transform: translateY(-50%); }
.jr-vide { font-size: var(--t-small); color: var(--text-3); padding: var(--e-40) var(--e-2); text-align: center; }

/* ══ LES PARCS ════════════════════════════════════════════════════════════════
   Amadou (14/08) : « il est vraiment très moche […] prends en compte qu'il y aura
   plusieurs parcs, plus je scale plus j'aurai de VDS ».
   D'où la forme : UN PARC = UNE CARTE. Avec un seul VDS c'est une carte, avec cinq
   c'est cinq cartes dans la même grille — la mise en page ne change pas, seul leur
   nombre change. L'ancienne liste plate mélangeait tout : à deux machines, on
   n'aurait plus su à qui appartenait quelle ligne.
   ⚠️ Formes EMPRUNTÉES, pas inventées : la jauge et sa légende viennent de l'écran
   Annonces (.an-jauge / .an-leg), la double densité — une carte quand il faut agir,
   une ligne quand on informe — vient du Journal. */
/* Amadou (14/08) : « espace plus entre la partie Les parcs et les cartes d'en dessous ».
   L'espacement vit ICI et nulle part ailleurs : le bandeau d'alerte portait une marge en
   dur, si bien que l'écart changeait selon qu'il y avait une alerte ou non. */
.pc-grille { display: grid; gap: var(--e-14); margin-top: var(--e-32);
             grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); }

.pc-carte { background: var(--surface-2); border: var(--e-1) solid var(--border);
            border-radius: var(--r-carte); padding: var(--e-14) var(--e-16) var(--e-12);
            display: flex; flex-direction: column; gap: var(--e-12); }
.pc-carte.muet { border-color: color-mix(in srgb, var(--red) 45%, var(--border)); }

.pc-tete { display: flex; align-items: flex-start; gap: var(--e-10); }
.pc-ic   { color: var(--text-3); flex-shrink: 0; margin-top: var(--e-2); }
.pc-nom  { font-size: var(--t-small); color: var(--text); font-weight: var(--fw-fort);
           line-height: var(--lh-serre); }
/* Deux parcs peuvent partager une machine (deux sessions Windows sur un serveur) :
   le nom de session les départage, en retrait — il précise, il ne titre pas. */
.pc-sess { font-size: var(--t-mini); font-weight: var(--fw-normal); color: var(--text-3);
           margin-left: var(--e-6); }
.pc-adr  { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-2);
           font-variant-numeric: tabular-nums; }

/* Le verdict : un chiffre et un mot, jamais une phrase. Il se lit à un mètre. */
.pc-verdict { margin-left: auto; flex-shrink: 0; display: flex; flex-direction: column;
              align-items: flex-end; gap: var(--e-4); }
.pc-chiffre { font-size: var(--t-lead); font-weight: var(--fw-fort); color: var(--text);
              line-height: var(--lh-un); font-variant-numeric: tabular-nums; }
.pc-chiffre.ok    { color: var(--green); }
.pc-chiffre.tiede { color: var(--amber); }
.pc-chiffre.mort  { color: var(--red); }
.pc-mot { font-size: var(--t-micro); color: var(--text-3); letter-spacing: var(--ls-caps);
          text-transform: uppercase; }

/* La jauge porte les TROIS COUCHES que le projet nomme déjà : le profil existe, sa
   fenêtre est ouverte, son compte parle. Une barre, trois segments, et la légende
   chiffre chacun — un chiffre sans sa couleur ne se relie à rien. */
.pc-jauge { display: flex; height: var(--e-6); border-radius: var(--r-pilule);
            overflow: hidden; background: var(--surface); }
.pc-jauge i { display: block; }
.pc-leg { display: flex; flex-wrap: wrap; gap: var(--e-4) var(--e-12);
          font-size: var(--t-mini); color: var(--text-3); }
.pc-leg span { display: inline-flex; align-items: center; gap: var(--e-6); }
.pc-leg i { width: var(--e-6); height: var(--e-6); border-radius: 50%; flex-shrink: 0; }
.pc-leg b { color: var(--text-2); font-weight: var(--fw-moyen); font-variant-numeric: tabular-nums; }

.pc-filet { height: var(--e-1); background: var(--border); }
/* Le pied se colle en bas : sans ça, deux cartes côte à côte n'alignent pas leurs
   pieds dès qu'elles n'ont pas le même nombre de comptes. */
.pc-filet.bas { margin-top: auto; }

.pc-comptes { display: flex; flex-direction: column; gap: var(--e-2); }
.pc-l { display: flex; align-items: center; gap: var(--e-8); padding: var(--e-6) var(--e-8);
        border-radius: var(--r-sm); cursor: pointer; }
.pc-l:hover { background: var(--surface); }
.pc-pion { width: var(--e-8); height: var(--e-8); border-radius: 50%; flex-shrink: 0;
           background: var(--text-3); }
.pc-pion.ok    { background: var(--green); }
.pc-pion.tiede { background: var(--amber); }
.pc-cn { font-size: var(--t-base); color: var(--text); flex: 1; min-width: 0;
         white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* ⚠️ On teinte le CHIFFRE, pas la ligne. Une ligne colorée au milieu de dix attire
   l'œil plus fort que l'alerte elle-même — et c'est l'alerte qu'on veut lire. */
.pc-cq { font-size: var(--t-mini); color: var(--text-3); flex-shrink: 0; white-space: nowrap;
         font-variant-numeric: tabular-nums; }
.pc-cq.tiede { color: var(--amber); }
/* Un parc à trente comptes ne doit pas faire une carte à rallonge : on montre les
   premiers — muets en tête — et on dit combien restent. */
.pc-plus { font-size: var(--t-mini); color: var(--text-3); padding: var(--e-6) var(--e-8);
           border-radius: var(--r-sm); cursor: pointer; }
.pc-plus:hover { background: var(--surface); color: var(--text-2); }
.pc-vide { font-size: var(--t-mini); color: var(--text-3); padding: var(--e-8); }

.pc-pied { margin-top: auto; display: flex; align-items: center; gap: var(--e-8);
           font-size: var(--t-mini); color: var(--text-3); }
.pc-pied b { color: var(--text-2); font-weight: var(--fw-moyen); font-variant-numeric: tabular-nums; }
.pc-pied .sep { margin-left: auto; }

.pc-alerte { display: flex; gap: var(--e-8); align-items: flex-start;
             background: color-mix(in srgb, var(--red) 10%, transparent);
             border: var(--e-1) solid color-mix(in srgb, var(--red) 35%, transparent);
             border-radius: var(--r-sm); padding: var(--e-8) var(--e-10);
             font-size: var(--t-mini); color: var(--text-2); line-height: var(--lh-serre); }
.pc-alerte svg { color: var(--red); flex-shrink: 0; margin-top: var(--e-1); }

/* Une carte qui s'ouvre doit AVOIR L'AIR de s'ouvrir. Le filet se réveille au survol —
   pas de déplacement : à quatorze pixels d'écart, deux cartes qui bougent se touchent. */
.pc-carte[data-parc] { cursor: pointer; transition: border-color var(--t-moyen) var(--c-pose); }
.pc-carte[data-parc]:hover { border-color: var(--violet-soft); }

/* ── L'ESPACE D'UN PARC (la modale) ─────────────────────────────────────────
   La carte montre, le panneau explique : ici vivent les détails qui n'ont pas leur
   place dans six lignes — port de pilotage, sous-profil, par quel signal le compte a
   parlé. Formes reprises du Journal, dont ce panneau partage la carte. */
.pcd-bloc { display: flex; flex-direction: column; gap: var(--e-2); }
.pcd-l { display: flex; align-items: baseline; gap: var(--e-12); padding: var(--e-4) 0; }
.pcd-e { font-size: var(--t-mini); color: var(--text-3); flex: 0 0 42%; }
.pcd-v { font-size: var(--t-base); color: var(--text-2); flex: 1; min-width: 0;
         word-break: break-word; }

.pcd-c { border-top: var(--e-1) solid var(--border); padding-top: var(--e-14);
         margin-top: var(--e-14); display: flex; flex-direction: column; gap: var(--e-8); }
.pcd-t { display: flex; align-items: center; gap: var(--e-8); }
.pcd-n { font-size: var(--t-small); color: var(--text); font-weight: var(--fw-fort);
         flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pcd-etat { font-size: var(--t-micro); letter-spacing: var(--ls-caps); text-transform: uppercase;
            color: var(--text-3); flex-shrink: 0; }
.pcd-etat.parle { color: var(--green); }
.pcd-etat.muet  { color: var(--amber); }
.pcd-actions { display: flex; flex-wrap: wrap; gap: var(--e-8); }

/* ══ LES THÈMES ═══════════════════════════════════════════════════════════════
   ⚠️⚠️ UN THÈME N'ÉCRIT QUE DES VARIABLES DU SOCLE. Jamais un sélecteur, jamais une
   règle de mise en page. Si un thème a besoin de déplacer quelque chose pour être
   joli, c'est le SOCLE qui est incomplet — on répare le socle, pas le thème. C'est
   ce qui permet d'en tenir onze sans que le site devienne ingérable, et c'est vérifié
   automatiquement par outils/verifier-themes.py.
   Nuit violette n'a pas de bloc : c'est le socle lui-même, la référence. */

[data-theme="abysse"] { --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2312586A%22%2F%3E%3Cstop%20offset%3D%22.38%22%20stop-color%3D%22%230A3542%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2303161E%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22r%22%20cx%3D%22.5%22%20cy%3D%220%22%20r%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23A8ECF4%22%20stop-opacity%3D%22.22%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23A8ECF4%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.12%22%3E%3Cg%20fill%3D%22url%28%23r%29%22%3E%3Cpath%20d%3D%22M784-40q-56%20240-176%20368t-208%20248l160%2032q104-160%20200-312t104-336z%22%2F%3E%3Cpath%20d%3D%22M848-40q40%20224%20152%20352t184%20232l-144%2032q-96-152-184-296t-88-320z%22%2F%3E%3Cpath%20d%3D%22M600-40q-88%20208-224%20328t-232%20216l120%2040q128-144%20240-280t176-304z%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20690q208-64%20416-16t416%200%20384-40%20384%2032v234H0z%22%20fill%3D%22%230C3B47%22%20opacity%3D%22.85%22%2F%3E%3Cpath%20d%3D%22M0%20770q256-48%20504-8t496-16%20600%2024v130H0z%22%20fill%3D%22%23155866%22%20opacity%3D%22.7%22%2F%3E%3Cg%20stroke%3D%22%239FEAF2%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20opacity%3D%22.26%22%3E%3Cpath%20d%3D%22M72%20812q88-48%20176-8t184-16%20160%2032%20176-24%20184%2024%20160-32%20176%2024%20184-16%22%2F%3E%3Cpath%20d%3D%22M32%20866q104-40%20200%200t176-24%20168%2032%20184-24%20176%2024%20168-32%20176%2024%22%2F%3E%3Cpath%20d%3D%22M176%20796v88M448%20780v104M728%20804v88M1008%20792v104M1280%20812v88%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%232A7C86%22%20opacity%3D%22.45%22%3E%3Cpath%20d%3D%22M248%20800c-16-64%2016-104%208-144%2028%2032%2040%2080%2040%20120%2020-40%2048-60%2072-88-8%2052-28%2092-52%20120z%22%2F%3E%3Cpath%20d%3D%22M1312%20824c-20-72%2012-108%204-148%2032%2032%2044%2084%2044%20124%2024-44%2052-64%2076-96-8%2056-32%20100-60%20128z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(162,198,205,.42), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(207,234,238,.38), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(162,198,205,.34), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(207,234,238,.36), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(162,198,205,.30), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(143,211,220,.32), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(162,198,205,.28), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(207,234,238,.26), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(162,198,205,.30), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(99,183,195,.15) 0%, rgba(3,9,12,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(120,220,230,.16), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(99,183,195,.12), transparent 70%),repeating-linear-gradient(96deg, rgba(160,225,235,.05) 0 3px, transparent 3px 26px);
  --th-fond-rgb: 3,9,12; --th-panneau-rgb: 14,38,48;
  --th-sur-plein: #111111;
  --th-ambiance: 0.55;          /* Abysse */
  --th-voile: 255,255,255; --th-ombre: 0,0,0;
  --th-fond: #03090C; --th-panneau: #0E2630; --th-carte: #1A3C46;
  --th-texte: #E4F1F2; --th-texte-2: #A8C4CA; --th-texte-3: #9BB2B8;
  --th-trait: 103,141,153;
  --th-accent: #63B7C3; --th-accent-clair: #BFE4E9; --th-accent-doux: #A2C6CD; --th-accent-fort: #7FCAD5;
  --th-accent-rgb: 99,183,195; --th-sur-accent: #03090C;
  --th-second: #67C188; --th-second-clair: #A8DEBC; --th-second-rgb: 103,193,136;
  --th-succes: #67C188; --th-alerte: #E3BD63; --th-danger: #F18F96; --th-danger-rgb: 240,138,145;
  --th-rayon-micro: 4px; --th-rayon-xs: 6px; --th-rayon-sm: 8px; --th-rayon-md: 8px;
  --th-rayon-lg: 10px; --th-rayon-carte: 10px; --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
}

[data-theme="basalte"] { --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2314100D%22%2F%3E%3Cstop%20offset%3D%22.58%22%20stop-color%3D%22%2320160F%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2333200F%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22h%22%20cx%3D%22.5%22%20cy%3D%221%22%20r%3D%22.7%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FFA23C%22%20stop-opacity%3D%22.24%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23FFA23C%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.13%22%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23h%29%22%2F%3E%3Cpath%20d%3D%22M0%20704l232-280%2088%2096%2064-64%20184%20248z%22%20fill%3D%22%230B0906%22%20opacity%3D%22.9%22%2F%3E%3Cpath%20d%3D%22M472%20728l344-416%20120%20136%2080-80%20240%20360z%22%20fill%3D%22%23100C08%22%20opacity%3D%22.92%22%2F%3E%3Cpath%20d%3D%22M1200%20736l208-248%20192%20248z%22%20fill%3D%22%230B0906%22%20opacity%3D%22.85%22%2F%3E%3Cpath%20d%3D%22M784%20320l64-8%2032%2048-56%2016z%22%20fill%3D%22%23FF8A3C%22%20opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M816%20368q24%2072-8%20136t8%20160%22%20stroke%3D%22%23FF7A2E%22%20stroke-width%3D%229%22%20fill%3D%22none%22%20opacity%3D%22.32%22%2F%3E%3Cpath%20d%3D%22M224%20432l48-8%2024%2036-40%2012z%22%20fill%3D%22%23FF8A3C%22%20opacity%3D%22.36%22%2F%3E%3Cpath%20d%3D%22M0%20744q240-32%20472%200t560-16%20568%2024v148H0z%22%20fill%3D%22%233A2412%22%20opacity%3D%22.5%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 30% 74%, rgba(255,201,138,.34), transparent 60%),radial-gradient(2px 2px at 58% 60%, rgba(255,176,92,.30), transparent 60%),radial-gradient(1.5px 1.5px at 76% 78%, rgba(255,201,138,.28), transparent 60%),radial-gradient(2px 2px at 16% 58%, rgba(255,158,74,.26), transparent 60%),radial-gradient(1.5px 1.5px at 45% 40%, rgba(255,201,138,.22), transparent 60%),radial-gradient(2px 2px at 88% 46%, rgba(255,176,92,.20), transparent 60%);
  --th-decor-pres: radial-gradient(120% 44% at 50% 108%, rgba(238,155,63,.20), transparent 62%),radial-gradient(50% 22% at 18% 104%, rgba(242,88,60,.15), transparent 66%),linear-gradient(72deg, transparent 26%, rgba(238,155,63,.07) 27%, transparent 28%),linear-gradient(-64deg, transparent 54%, rgba(242,120,60,.06) 55%, transparent 56%),linear-gradient(84deg, transparent 72%, rgba(238,155,63,.05) 73%, transparent 74%);
  --th-fond-rgb: 20,16,13; --th-panneau-rgb: 32,25,20;
  --th-sur-plein: #111111;
  --th-ambiance: 0.38;          /* Basalte */
  --th-voile: 255,255,255; --th-ombre: 0,0,0;
  --th-fond: #14100D; --th-panneau: #201914; --th-carte: #2A211B;
  --th-texte: #EDE4DB; --th-texte-2: #D3C3B5; --th-texte-3: #B0A093;
  --th-trait: 87,70,54;
  --th-accent: #EE9B3F; --th-accent-clair: #F8D3A8; --th-accent-doux: #F5C68C; --th-accent-fort: #F2AC5C;
  --th-accent-rgb: 238,155,63; --th-sur-accent: #14100D;
  --th-second: #8FD07E; --th-second-clair: #C2E7B8; --th-second-rgb: 143,208,126;
  --th-succes: #8FD07E; --th-alerte: #E4D45F; --th-danger: #F36376; --th-danger-rgb: 242,88,108;
  --th-rayon-pilule: 4px;
  --th-rayon-micro: 2px; --th-rayon-xs: 3px; --th-rayon-sm: 3px; --th-rayon-md: 3px;
  --th-rayon-lg: 4px; --th-rayon-carte: 4px; --th-rayon-panneau: 6px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
}

[data-theme="sylve"] { --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%231D4029%22%2F%3E%3Cstop%20offset%3D%22.46%22%20stop-color%3D%22%230F2417%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23050D08%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22r%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23E4F5C0%22%20stop-opacity%3D%22.20%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%23E4F5C0%22%20stop-opacity%3D%22.06%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23E4F5C0%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.17%22%3E%3Cg%20fill%3D%22url%28%23r%29%22%3E%3Cpath%20d%3D%22M280%200h36l-96%20600h-36z%22%2F%3E%3Cpath%20d%3D%22M368%200h20l-88%20488h-20z%22%2F%3E%3Cpath%20d%3D%22M672%200h44l-112%20648h-44z%22%2F%3E%3Cpath%20d%3D%22M776%200h16l-96%20472h-16z%22%2F%3E%3Cpath%20d%3D%22M1128%200h32l-104%20584h-32z%22%2F%3E%3Cpath%20d%3D%22M1208%200h20l-88%20432h-20z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%230A1A0F%22%20opacity%3D%22.85%22%3E%3Cpath%20d%3D%22M208%20144h1200v28H208z%22%20transform%3D%22rotate%28-4%20800%20158%29%22%2F%3E%3Cpath%20d%3D%22M160%20368h1320v20H160z%22%20transform%3D%22rotate%283%20800%20378%29%22%2F%3E%3Cpath%20d%3D%22M256%20560h1200v16H256z%22%20transform%3D%22rotate%28-2%20800%20568%29%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%2309170D%22%20opacity%3D%22.75%22%3E%3Cpath%20d%3D%22M88%20900V408l-40-44%2040%2012v-44l44%2052-28-80%2044%2072V320l40%2088%2028-60v80l40-44-36%2072%2044-20-48%2052v412z%22%2F%3E%3Cpath%20d%3D%22M512%20900V464l-36-40%2036%2012v-36l40%2048-24-72%2040%2064V384l36%2080%2024-56v72l36-40-32%2064%2040-16-44%2048v304z%22%2F%3E%3Cpath%20d%3D%22M976%20900V432l-40-44%2040%2012v-44l44%2052-28-80%2044%2072V336l40%2088%2028-60v80l40-44-36%2072%2044-20-48%2052v384z%22%2F%3E%3Cpath%20d%3D%22M1416%20900V496l-32-36%2032%208v-32l36%2044-20-64%2036%2056v-64l32%2072%2024-48v64l32-36-28%2056%2036-16-40%2044v352z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23EAF7CE%22%20opacity%3D%22.5%22%3E%3Ccircle%20cx%3D%22304%22%20cy%3D%22264%22%20r%3D%224%22%2F%3E%3Ccircle%20cx%3D%22328%22%20cy%3D%22392%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%22696%22%20cy%3D%22216%22%20r%3D%224.5%22%2F%3E%3Ccircle%20cx%3D%22720%22%20cy%3D%22416%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%221152%22%20cy%3D%22288%22%20r%3D%224%22%2F%3E%3Ccircle%20cx%3D%221176%22%20cy%3D%22472%22%20r%3D%223.5%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20672q280-32%20528%2016t536-8%20536%2024v196H0z%22%20fill%3D%22%23071108%22%20opacity%3D%22.55%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(2px 2px at 22% 48%, rgba(216,233,188,.34), transparent 60%),radial-gradient(1.5px 1.5px at 66% 36%, rgba(198,222,164,.30), transparent 60%),radial-gradient(2px 2px at 44% 70%, rgba(216,233,188,.28), transparent 60%),radial-gradient(1.5px 1.5px at 84% 62%, rgba(198,222,164,.26), transparent 60%),radial-gradient(2px 2px at 14% 24%, rgba(216,233,188,.24), transparent 60%),radial-gradient(1.5px 1.5px at 55% 88%, rgba(198,222,164,.22), transparent 60%);
  --th-decor-pres: linear-gradient(104deg, transparent 12%, rgba(190,225,145,.09) 15%, transparent 19%),linear-gradient(101deg, transparent 34%, rgba(190,225,145,.07) 36%, transparent 41%),linear-gradient(106deg, transparent 58%, rgba(190,225,145,.08) 61%, transparent 65%),linear-gradient(168deg, rgba(180,215,140,.13) 0%, rgba(10,20,14,0) 46%),linear-gradient(0deg, rgba(10,20,14,.55) 0%, transparent 26%);
  --th-fond-rgb: 10,20,14; --th-panneau-rgb: 21,33,24;
  --th-sur-plein: #111111;
  --th-ambiance: 0.42;          /* Sylve */
  --th-voile: 255,255,255; --th-ombre: 0,0,0;
  --th-fond: #0A140E; --th-panneau: #152118; --th-carte: #213024;
  --th-texte: #DDE8E0; --th-texte-2: #AFC2B3; --th-texte-3: #93A796;
  --th-trait: 55,76,62;
  --th-accent: #9CBE6C; --th-accent-clair: #CFE2B4; --th-accent-doux: #B4CE8E; --th-accent-fort: #AECB80;
  --th-accent-rgb: 156,190,108; --th-sur-accent: #0A140E;
  --th-second: #5AC9BC; --th-second-clair: #A6E2DA; --th-second-rgb: 90,201,188;
  --th-succes: #5AC9BC; --th-alerte: #E2913A; --th-danger: #EE7B84; --th-danger-rgb: 238,123,132;
  --th-rayon-micro: 4px; --th-rayon-xs: 6px; --th-rayon-sm: 8px; --th-rayon-md: 10px;
  --th-rayon-lg: 12px; --th-rayon-carte: 12px; --th-rayon-panneau: 18px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
}

/* ══ LES TROIS CRANS ═══════════════════════════════════════════════════════════
   ⚠️ Trois crans, pas un curseur : un curseur continu casse toujours une mise en
   page quelque part, et on ne peut pas tester l'infini. Ces trois-là se vérifient.
   Seules les NEUF tailles de texte changent — 1 636 usages passent déjà par elles,
   donc tout le site suit sans qu'une règle ne bouge. */
[data-densite="compact"] {
  --t-display: 25px; --t-title: 20px; --t-lead: 17px; --t-body: 14px; --t-small: 13px;
  --t-base: 12px; --t-meta: 11px; --t-mini: 10px; --t-micro: 9px;
}
[data-densite="confortable"] {
  --t-display: 31px; --t-title: 25px; --t-lead: 21px; --t-body: 18px; --t-small: 16px;
  --t-base: 15px; --t-meta: 14px; --t-mini: 13px; --t-micro: 12px;
}

/* ⚠️⚠️ LA BARRE DE GAUCHE NE SUIT PAS LE CRAN CONFORTABLE — 15/08. Amadou : « diminue
   uniquement pour la partie confortable, et uniquement dans la barre d'onglets à
   gauche, parce que là il y a un ascenseur qui me dérange ».
   MESURÉ, hauteur du contenu de la barre : 630 px en normal, 648 px en confortable.
   Ces 18 px sont exactement ce qui fait apparaître l'ascenseur à ce cran-là et pas
   aux autres. En rendant à la barre ses tailles normales, elle retombe à 630 : le
   confortable ne lui coûte plus rien.
   ⚠️ Ce n'est PAS un contournement du cran, c'est une exception assumée : la barre est
   une LISTE FIXE de onze entrées, sa hauteur est bornée par le nombre d'onglets, pas
   par le confort de lecture. Tout le reste du site suit le cran, comme prévu.
   ⚠️ Et la police seule ne suffirait pas si les onglets n'avaient pas déjà une hauteur
   fixe (36 px) : c'est parce qu'elle est fixe que seuls les intitulés de groupe et les
   interlignes grandissent — donc que 18 px se récupèrent en touchant au seul texte. */
[data-densite="confortable"] .sidebar {
  --t-small: 14px; --t-base: 13px; --t-meta: 12px; --t-mini: 11px; --t-micro: 10px;
}

/* La police du thème s'applique à la racine ; tout en hérite. */
body { font-family: var(--th-police); }
h1, h2, h3, .cok-launch-title { font-family: var(--th-police-titre); }
.nav-item > span:not(.nav-ic) { text-transform: var(--th-casse-nav); }

/* ══ LES COMMANDES SHEIN : la fiche et son détail ════════════════════════════
   Amadou (15/08) : « l'interface c'est vraiment moche, il n'y a pas l'image du
   produit. Quand j'appuie dessus, il doit y avoir un écran qui s'affiche en plus
   grand avec les détails ».
   ⚠️ L'image ne vient PAS de SHEIN — les mails stockés n'en contiennent aucune.
   Elle est retrouvée dans la Bibliothèque par le SKU du coloris, qui est le même
   des deux côtés. Voir `_sheinSkuIndex` dans app.js.
   Rien d'inventé ici : la fiche reprend la forme des cartes du site, la fenêtre
   emprunte celle du parc. */
.shc-liste { display: flex; flex-direction: column; gap: var(--e-8); }
.shc-fiche {
  display: grid; grid-template-columns: 62px 1fr; gap: var(--e-12);
  padding: var(--e-10); width: 100%; text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); cursor: pointer; font-family: inherit;
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
.shc-fiche:hover { border-color: var(--border-strong); background: var(--surface-2); }
.shc-vue {
  width: 62px; aspect-ratio: 3/4; border-radius: var(--r-sm); overflow: hidden;
  background: var(--bg-elevated); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.shc-vue img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shc-vue svg { width: 22px; height: 22px; }
.shc-corps { min-width: 0; display: flex; flex-direction: column; gap: var(--e-2); }
/* Deux lignes maximum : un titre SHEIN fait couramment cent caractères, et une
   fiche qui grandit avec son titre casse le rythme de la liste. */
.shc-nom {
  font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text);
  line-height: var(--lh-serre);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.shc-meta { font-size: var(--t-mini); color: var(--text-3); }
.shc-bas { display: flex; align-items: center; gap: var(--e-6); margin-top: var(--e-6); flex-wrap: wrap; }
.shc-prix { margin-left: auto; font-size: var(--t-mini); color: var(--text-2); }
.shc-pil {
  font-size: var(--t-micro); font-weight: var(--fw-fort); line-height: var(--lh-un);
  padding: var(--e-4) var(--e-8); border-radius: var(--r-pilule);
}
/* Les trois états prennent les jetons d'état du thème — donc ils suivent les seize. */
.shc-pil--confirmee { background: var(--moy-bg);  color: var(--moy-text); }
.shc-pil--expediee  { background: var(--cyan-tint); color: var(--cyan); }
.shc-pil--livree    { background: var(--safe-bg); color: var(--safe-text); }

/* ── Le détail ────────────────────────────────────────────────────────────────
   ⚠️⚠️ REPRIS le 15/08 — Amadou : « visuellement ce n'est pas beau, c'est trop
   brouillon ». La cause était une seule ligne : les faits étaient posés dans une
   grille `repeat(auto-fit, minmax(120px,1fr))`. Une grille auto-fit REPLACE ses
   cellules selon la largeur disponible — donc rien n'est jamais en face de rien,
   le numéro de suivi (18 caractères) se coupait en deux et l'adresse sur quatre
   lignes poussait tout le reste.
   ⭐ Une liste libellé / valeur à DEUX colonnes fixes s'aligne toujours, quelle que
   soit la largeur. C'est moins malin et c'est bien mieux. */
/* ⚠️⚠️ LES DEUX BLOCS PARTAGENT LA LARGEUR — 15/08. Empilés, l'article et la
   livraison faisaient à eux deux ~640 px de haut : la frise passait sous la ligne de
   flottaison, et il fallait défiler pour voir OÙ EN EST la commande, c'est-à-dire la
   seule chose qu'on vient chercher en l'ouvrant. Amadou : « côte à côte, que ça
   m'évite de scroller ». Mesuré après : ~430 px, tout tient. */
/* ⚠️ `stretch` et pas `start` : sans ça, chaque colonne s'arrête à SON contenu, et le
   filet entre les deux ne descendrait que jusqu'au bas de la plus courte — un trait qui
   s'interrompt en l'air. Étirées, les deux font la hauteur de la plus haute et le filet
   va d'un bord à l'autre. */
.shc-d-duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--e-20); align-items: stretch; }
/* Le filet de séparation. Il n'est pas décoratif : deux blocs côte à côte sans rien
   entre eux se lisent comme un seul tableau à quatre colonnes, et l'œil cherche des
   correspondances de ligne à ligne qui n'existent pas. */
.shc-d-duo > .shc-d-bloc { border-left: 1px solid var(--border); padding-left: var(--e-20); }
/* ⚠️ En dessous de 620 px, deux colonnes ne libèrent plus rien — elles serrent. On
   les remet l'une sous l'autre : c'est la largeur qui décide, pas l'appareil.
   Et le filet passe alors de la GAUCHE au DESSUS : il sépare toujours les deux blocs,
   mais dans l'autre sens. Oublier ce basculement laisserait un trait vertical orphelin
   au-dessus d'une liste. */
@media (max-width: 620px) {
  .shc-d-duo { grid-template-columns: 1fr; gap: var(--e-16); }
  .shc-d-duo > .shc-d-bloc {
    border-left: none; padding-left: 0;
    border-top: 1px solid var(--border); padding-top: var(--e-14);
  }
}
.shc-d-art { display: grid; grid-template-columns: 60px 1fr; gap: var(--e-12);
             align-items: start; }
.shc-d-vue {
  width: 60px; aspect-ratio: 3/4; border-radius: var(--r-sm); overflow: hidden;
  background: var(--bg-elevated); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; color: var(--text-3);
}
.shc-d-vue img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shc-d-vue svg { width: 22px; height: 22px; }
.shc-d-info { min-width: 0; }
.shc-d-nom { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text);
             line-height: var(--lh-serre); }
.shc-d-sous { font-size: var(--t-base); color: var(--text-2); margin-top: var(--e-4); }
/* ⚠️ Le message sort du cadre photo pour venir SOUS LE NOM : tassé dans 68 px de
   large, il ne se lisait pas — et c'est la seule chose qui explique l'image absente. */
.shc-d-sansphoto { font-size: var(--t-mini); color: var(--text-2); margin-top: var(--e-6);
                   line-height: var(--lh-serre); }
/* Le prix avait sa case dans la grille des faits, au même poids qu'un SKU. C'est le
   seul chiffre de cet écran qui coûte de l'argent : il mérite d'être vu. */
.shc-d-prix { font-size: var(--t-lead); font-weight: var(--fw-fort); color: var(--text);
              white-space: nowrap; margin-top: var(--e-10); }

/* ⚠️ « l'étiquette statut en haut est trop collée au num » — et c'est un vrai défaut
   de lecture : sans écart, « Livrée GSO1RT01200MML1 » se parcourt comme un seul bloc.
   L'écart les sépare en DEUX informations, qui n'ont ni le même rôle ni le même poids. */
.shc-d-tete { display: flex; align-items: center; }
.shc-d-tete .shc-pil { margin-right: var(--e-14); }
.shc-d-num { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
             font-size: var(--t-base); font-weight: var(--fw-normal); color: var(--text-2); }

/* Plus de marge haute : le bloc n'est plus SOUS l'article, il est À CÔTÉ. */
.shc-d-ligne { display: grid; grid-template-columns: 96px 1fr; gap: var(--e-10);
               align-items: baseline; padding: var(--e-8) 0;
               border-top: 1px solid var(--border); }
.shc-d-ligne:first-child { border-top: none; }
.shc-d-k { font-size: var(--t-mini); color: var(--text-3); }
.shc-d-v { font-size: var(--t-base); color: var(--text); min-width: 0; overflow-wrap: anywhere; }
/* ⚠️ `flex-wrap` : dans une colonne moitié moins large, le bouton « Copier » n'a plus
   toujours la place à côté du code. Sans lui il déborderait au lieu de passer dessous. */
.shc-d-v.mono { display: flex; align-items: center; gap: var(--e-8); flex-wrap: wrap; }
.shc-d-v.mono .shc-d-val { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
                           font-size: var(--t-mini); }
.shc-d-adr { line-height: var(--lh-normal); }
/* Un code de vingt caractères n'est pas fait pour être lu, mais RECOPIÉ. */
.shc-d-copie {
  flex: none; font-size: var(--t-micro); font-family: inherit; color: var(--text-3);
  background: transparent; border: 1px solid var(--border); border-radius: var(--r-micro);
  padding: var(--e-1) var(--e-6); cursor: pointer; transition: var(--transi);
}
.shc-d-copie:hover { color: var(--text); border-color: var(--border-strong); }

/* ── La frise. Chaque étape porte le SUJET du mail dont elle vient : sans source,
      une frise ne se vérifie pas — et c'est précisément une frise sans source qui
      a laissé une commande livrée s'afficher « confirmée » pendant trois jours. */
.shc-d-frise { margin-top: var(--e-20); padding-top: var(--e-16); border-top: 1px solid var(--border); }
.shc-d-lab {
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: var(--ls-caps);
  color: var(--text-3); margin-bottom: var(--e-12);
}
.shc-d-et { display: grid; grid-template-columns: 13px 1fr; gap: var(--e-12); }
.shc-d-pt { display: flex; flex-direction: column; align-items: center; }
.shc-d-rond { width: 9px; height: 9px; border-radius: 50%; margin-top: var(--e-4);
              flex: none; background: var(--safe-text); }
.shc-d-trait { width: var(--e-1); flex: 1; min-height: var(--e-14); background: var(--border-strong); }
.shc-d-trait.fin { display: none; }
.shc-d-txt { padding-bottom: var(--e-14); }
/* ⚠️ La DERNIÈRE étape n'a rien en dessous d'elle : sa marge basse ne sépare de rien
   et coûtait les 5 px qui obligeaient encore à défiler. Mesuré : contenu à 502 px pour
   497 px disponibles — il ne manquait que ça. */
.shc-d-et:last-child .shc-d-txt { padding-bottom: 0; }
.shc-d-t1 { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); }
.shc-d-t2 { font-size: var(--t-mini); color: var(--text-2); margin-top: var(--e-2); }
.shc-d-src { font-size: var(--t-micro); color: var(--text-3); margin-top: var(--e-2); }
.shc-d-vide { font-size: var(--t-base); color: var(--text-3); }

/* ══ L'ONGLET APPARENCE ══════════════════════════════════════════════════════
   Rien d'inventé : la grille reprend `.pa-conn-grid`, les crans reprennent la
   forme d'un groupe de boutons segmentés, l'aperçu est une carte comme les autres. */
/* ⚠️⚠️ SEIZE THÈMES NE SE LISENT PAS COMME HUIT — 15/08. En passant de 8 à 16,
   une liste de NOMS devient un mur : « Abysse », « Basalte », « Sylve »… on clique
   au hasard. Amadou : « grille de vignettes, mais diminue la taille des cards pour
   que toutes les vignettes rentrent ».
   Donc : le décor remplace les trois bandes de couleur (on voit ce qu'on choisit
   AVANT de cliquer), la carte rétrécit de 126 à 94 px, et la seconde ligne de texte
   part dans l'infobulle. Seize tiennent alors en quatre rangées dans la fenêtre. */
.ap-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(94px, 1fr)); gap: var(--e-6); }
.ap-vignette {
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: var(--e-4); background: transparent; cursor: pointer;
  text-align: center; font-family: inherit; transition: border-color var(--t-moyen);
}
.ap-vignette:hover { border-color: var(--border-strong); }
.ap-vignette.on { border-color: var(--violet); background: var(--violet-tint); }
/* Le décor lui-même, au format de l'écran. `--th-fond-scene` se résout ici parce
   que le bouton porte `data-theme` (voir `_apRendre` dans app.js) : aucune image
   n'est dupliquée, chaque vignette va chercher la sienne dans la feuille. */
.ap-vue {
  display: block; aspect-ratio: 16/10;
  border-radius: var(--r-micro); overflow: hidden;
  margin-bottom: var(--e-4);
  background: var(--th-fond) var(--th-fond-scene);
  box-shadow: 0 0 0 1px rgba(var(--th-voile),0.12) inset;
}
/* La vignette du socle : elle n'a pas de `data-theme` à porter, donc elle lit
   les deux valeurs qu'aucun thème ne réécrit. Sans ça, elle affiche le décor du
   thème actif — voir la note dans `:root`. */
.ap-vignette[data-th=""] .ap-vue { background: var(--socle-fond) var(--socle-scene); }

/* ── VOIR UN THÈME EN GRAND ─────────────────────────────────────────────────
   Une vignette de 90 px dit la couleur d'un thème, pas son dessin — et ces décors sont
   des paysages. Il s'ouvre au CLIC DROIT, comme tous les menus du site.
   ⚠️ REFAIT le 24/08 : « lorsque j'agrandis c'est vraiment moche ». La première version
   posait un bandeau pleine largeur sous l'image — il coupait le décor en deux et alignait
   cinq boutons sans hiérarchie. Ici le décor prend TOUT, et ce qui le commande flotte
   par-dessus : les flèches sur les côtés, une seule carte en bas, la fermeture en haut. */
.ap-grand {
  position: fixed; inset: 0; z-index: 300;
  background: var(--th-fond);
  animation: apGrandVient var(--t-moyen) var(--c-pose);
}
@keyframes apGrandVient { from { opacity: 0; } to { opacity: 1; } }
.ap-grand.hidden { display: none; }

/* ⚠️ `cover`, PAS `contain`. `contain` laissait deux bandes vides au-dessus et en dessous
   — c'est ce qui faisait « vide » à l'agrandissement. Ces décors sont dessinés en 16/9
   pour être des FONDS : les voir remplir l'écran, c'est justement les voir tels qu'ils
   seront. */
.ap-grand-scene {
  position: absolute; inset: 0;
  background: var(--th-fond) var(--th-fond-scene);
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
/* ⚠️⚠️ LE SOCLE N'A PAS DE `data-theme` À PORTER — il EST l'absence de thème. Posé sur la
   fenêtre, `.socle` remet donc les valeurs d'origine à la place de celles du thème actif :
   tout ce qui est dedans (décor, carte, bouton, flèches) les hérite d'un coup.
   On ne redéclare que ce que l'aperçu emploie ; les autres jetons n'y servent à rien. */
.ap-grand.socle {
  --th-fond: var(--socle-fond);
  --th-fond-scene: var(--socle-scene);
  --th-texte: var(--socle-texte);
  --th-accent: var(--socle-accent);
  --th-sur-accent: var(--socle-sur-accent);
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-panneau-rgb: 20,18,31;
  --th-texte-2: #B3B8C9;
  --th-texte-3: #888CA1;
  --th-trait: 148,150,172;
}

/* La carte du bas : posée SUR le décor, détachée du bord, en verre dépoli.
   ⚠️⚠️ LARGEUR FIXE. Amadou (24/08) : « je veux que ce soit la même taille partout ».
   Elle se dimensionnait sur son contenu : « un champ au crépuscule » la rendait plus large
   que « un champ à midi », donc elle changeait de taille à chaque thème — un sautillement
   à chaque flèche, sur l'élément qu'on regarde.
   ⚠️ Centrée par `margin: auto` et non par `transform`, pour la même raison que les
   flèches : rien qui puisse être écrasé par un état de bouton. */
.ap-grand-carte {
  position: absolute; left: 0; right: 0; bottom: var(--e-32);
  margin: 0 auto; width: 320px; max-width: calc(100vw - var(--e-32) * 2);
  display: flex; flex-direction: column; align-items: stretch; gap: var(--e-4);
  padding: var(--e-18) var(--e-20);
  text-align: center;
  border-radius: var(--r-carte);
  /* ⚠️⚠️⚠️ LA SURFACE DU THÈME, PAS UN NOIR FIXE. Amadou (24/08) : « certains blocs sont
     dans l'obscurité, on voit mal — et ça ne doit pas se reproduire pour les prochains
     thèmes ». J'avais écrit `rgba(--th-ombre, .72)` : un noir semi-transparent QUOI QU'IL
     ARRIVE. Sur les six thèmes clairs (Colza, Dune, Cyclades, Hanami, Nimbe, Médina) le
     texte, lui, suit le thème et devient SOMBRE — texte sombre sur fond sombre.
     `--th-panneau-rgb` est la surface du thème : claire sur un thème clair, sombre sur un
     thème sombre. Un thème créé demain sera juste sans qu'on y touche, parce que la règle
     ne décide plus de la couleur — elle la demande au thème. */
  background: rgba(var(--th-panneau-rgb), .86);
  border: 1px solid rgba(var(--th-trait), .22);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 var(--e-16) var(--e-40) rgba(var(--th-ombre), .28);
}
/* Le rang d'abord : il dit OÙ l'on est avant de dire ce qu'on regarde. */
.ap-grand-rang {
  font-size: var(--t-micro); color: var(--th-texte-3);
  font-variant-numeric: tabular-nums; margin-bottom: var(--e-2);
}
.ap-grand-titres { min-width: 0; }
/* ⚠️ Le nom peut être long (« Nuit violette ») : il tient sur une ligne et se coupe
   proprement plutôt que de faire grandir une carte dont toute la valeur est d'être fixe. */
.ap-grand-nom {
  font-size: var(--t-titre); font-weight: var(--fw-fort); color: var(--th-texte);
  line-height: var(--lh-serre);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ap-grand-pol { font-size: var(--t-meta); color: var(--th-texte-2); }

.ap-grand-poser {
  margin-top: var(--e-12);
  font: inherit; font-size: var(--t-meta); font-weight: var(--fw-moyen);
  background: var(--th-accent); color: var(--sur-accent);
  border: 0; border-radius: var(--r-pilule); padding: var(--e-10) var(--e-16); cursor: pointer;
  white-space: nowrap;
}
/* ⚠️ « Déjà choisi » ne doit pas paraître cliquable : sinon on appuie, rien ne se passe,
   et on croit le bouton cassé. */
.ap-grand-poser:disabled {
  background: rgba(var(--th-voile), .1); color: rgba(var(--th-voile), .45); cursor: default;
}

/* Les flèches vivent sur les CÔTÉS, là où va la main — pas alignées dans une barre avec
   tout le reste. Elles s'effacent tant qu'on ne les approche pas.
   ⚠️⚠️⚠️ ELLES NE SE CENTRENT PLUS AVEC `transform`. Amadou (24/08) : « quand j'appuie
   dessus le bouton va vers le bas, et celui de droite, une chance sur deux, ça quitte ».
   UN SEUL DÉFAUT expliquait les deux : le site applique `transform: scale(…)` à tout
   bouton pressé. Ce transform REMPLACE le `translateY(-50%)` qui centrait la flèche —
   elle plongeait donc d'une demi-hauteur au moment du clic. Et comme elle se dérobait
   sous le curseur, le relâchement tombait à côté : le clic était attribué au fond, qui
   ferme. « Une chance sur deux » selon qu'on avait bougé ou non.
   `top/bottom: 0` + `margin: auto 0` centre sans transform : rien à écraser. */
.ap-grand-cote {
  position: absolute; top: 0; bottom: 0; margin: auto 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: var(--r-pilule);
  /* Même raison que la carte : la surface vient du THÈME. Un rond noir sur un décor de
     plein midi, c'est une tache ; un rond blanc sur une nuit, c'est un phare. */
  background: rgba(var(--th-panneau-rgb), .78); border: 1px solid rgba(var(--th-trait), .2);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  color: var(--th-texte); cursor: pointer; opacity: .35;
  transition: opacity var(--t-moyen) var(--c-pose), background var(--t-bref) var(--c-pose);
}
.ap-grand:hover .ap-grand-cote { opacity: .8; }
.ap-grand-cote:hover { opacity: 1; background: rgba(var(--th-panneau-rgb), .95); }
.ap-grand-cote.gauche { left: var(--e-24); }
.ap-grand-cote.droite { right: var(--e-24); }

.ap-grand-x {
  position: absolute; top: var(--e-20); right: var(--e-24);
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: var(--r-pilule);
  background: rgba(var(--th-panneau-rgb), .78); border: 1px solid rgba(var(--th-trait), .2);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  color: var(--th-texte); cursor: pointer; opacity: .55;
  transition: opacity var(--t-bref) var(--c-pose);
}
.ap-grand-x:hover { opacity: 1; }

@media (max-width: 700px) {
  .ap-grand-carte { bottom: var(--e-20); }
  .ap-grand-cote { width: 38px; height: 38px; }
}
.ap-nom { font-size: var(--t-micro); color: var(--text); display: block;
          white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.ap-crans { display: inline-flex; border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.ap-cran {
  border: 0; background: transparent; color: var(--text-2); font-family: inherit;
  font-size: var(--t-meta); padding: var(--e-6) var(--e-16); cursor: pointer;
  border-right: 1px solid var(--border); transition: color var(--t-moyen);
}
.ap-cran:last-child { border-right: 0; }
.ap-cran:hover { color: var(--text); }
.ap-cran.on { background: var(--violet-tint-strong); color: var(--violet-light); }
.ap-apercu {
  margin-top: var(--e-10); background: var(--bg-card-solid);
  border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--e-10) var(--e-12);
}
.ap-apercu-t { font-size: var(--t-base); color: var(--text); margin-bottom: var(--e-2); }
.ap-apercu-d { font-size: var(--t-small); color: var(--text-2); line-height: var(--lh-normal); }

[data-theme="aurore"] { --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230C1626%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23070D18%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2303060C%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.20%22%3E%3Cpath%20d%3D%22M-80%20136q320-104%20640%2016t1040-32v184q-360%2088-760-8T-80%20312z%22%20fill%3D%22%235AE0B4%22%20opacity%3D%22.08%22%2F%3E%3Cpath%20d%3D%22M-80%20208q400-80%20720%2032t960-24v136q-400%2072-800-16T-80%20360z%22%20fill%3D%22%238FA2FF%22%20opacity%3D%22.055%22%2F%3E%3Cg%20stroke%3D%22%23BFD8E6%22%20stroke-width%3D%221.8%22%20opacity%3D%22.17%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M208%20512l120-88%20136%2056%20104-120%20128%2040%22%2F%3E%3Cpath%20d%3D%22M928%20384l112%2088%20144-40%20120%2080%22%2F%3E%3Cpath%20d%3D%22M384%20672l152-56%20120%2080%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23E8F1F5%22%20opacity%3D%22.55%22%3E%3Ccircle%20cx%3D%22208%22%20cy%3D%22512%22%20r%3D%225.2%22%2F%3E%3Ccircle%20cx%3D%22328%22%20cy%3D%22424%22%20r%3D%224%22%2F%3E%3Ccircle%20cx%3D%22464%22%20cy%3D%22480%22%20r%3D%224.4%22%2F%3E%3Ccircle%20cx%3D%22568%22%20cy%3D%22360%22%20r%3D%224.4%22%2F%3E%3Ccircle%20cx%3D%22696%22%20cy%3D%22400%22%20r%3D%223.6%22%2F%3E%3Ccircle%20cx%3D%22928%22%20cy%3D%22384%22%20r%3D%224.8%22%2F%3E%3Ccircle%20cx%3D%221040%22%20cy%3D%22472%22%20r%3D%224%22%2F%3E%3Ccircle%20cx%3D%221184%22%20cy%3D%22432%22%20r%3D%225.6%22%2F%3E%3Ccircle%20cx%3D%221304%22%20cy%3D%22512%22%20r%3D%224%22%2F%3E%3Ccircle%20cx%3D%22384%22%20cy%3D%22672%22%20r%3D%224.4%22%2F%3E%3Ccircle%20cx%3D%22536%22%20cy%3D%22616%22%20r%3D%225.2%22%2F%3E%3Ccircle%20cx%3D%22656%22%20cy%3D%22696%22%20r%3D%223.6%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23A9BECB%22%20opacity%3D%22.34%22%3E%3Ccircle%20cx%3D%22120%22%20cy%3D%22280%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%22784%22%20cy%3D%22208%22%20r%3D%223.5%22%2F%3E%3Ccircle%20cx%3D%221408%22%20cy%3D%22256%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%221152%22%20cy%3D%22704%22%20r%3D%222.8%22%2F%3E%3Ccircle%20cx%3D%22264%22%20cy%3D%22768%22%20r%3D%223%22%2F%3E%3Ccircle%20cx%3D%221512%22%20cy%3D%22600%22%20r%3D%222.8%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;          /* Aurore */
  --th-ambiance: 0.55;
  --th-voile: 255,255,255; --th-ombre: 0,0,0;
  --th-fond: #070C14; --th-panneau: #0D1420; --th-carte: #121B29;
  --th-fond-rgb: 7,12,20; --th-panneau-rgb: 13,20,32;
  --th-texte: #E8F1F5; --th-texte-2: #A9BECB; --th-texte-3: #7E93A2;
  --th-trait: 92,114,134;
  --th-accent: #5AE0B4; --th-accent-clair: #C8F7E4; --th-accent-doux: #6FE6C0; --th-accent-fort: #7DEDC8;
  --th-accent-rgb: 90,224,180;
  --th-sur-accent: #070C14; --th-sur-plein: #111111;
  --th-second: #8FA2FF; --th-second-clair: #C3CEFF; --th-second-rgb: 143,162,255;
  --th-succes: #9BE77E; --th-alerte: #F2B85C; --th-danger: #FF8E90; --th-danger-rgb: 255,142,144;
  --th-rayon-micro: 4px; --th-rayon-xs: 6px; --th-rayon-sm: 8px; --th-rayon-md: 10px;
  --th-rayon-lg: 12px; --th-rayon-carte: 12px; --th-rayon-panneau: 16px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-decor-loin: radial-gradient(2.4px 2.4px at 6% 12%, rgba(232,241,245,0.20), transparent 62%), radial-gradient(2.2px 2.2px at 23% 5%, rgba(232,241,245,0.18), transparent 64%), radial-gradient(2.6px 2.6px at 41% 19%, rgba(232,241,245,0.19), transparent 62%), radial-gradient(2.2px 2.2px at 68% 9%, rgba(232,241,245,0.17), transparent 64%), radial-gradient(2.4px 2.4px at 87% 23%, rgba(232,241,245,0.20), transparent 62%), radial-gradient(2.2px 2.2px at 13% 31%, rgba(232,241,245,0.16), transparent 64%), radial-gradient(2.5px 2.5px at 55% 33%, rgba(232,241,245,0.18), transparent 62%), radial-gradient(2.2px 2.2px at 79% 54%, rgba(232,241,245,0.15), transparent 64%), radial-gradient(1.8px 1.8px at 30% 8%, rgba(90,224,180,0.13), transparent 66%), radial-gradient(1.8px 1.8px at 77% 20%, rgba(143,162,255,0.12), transparent 66%), radial-gradient(1.8px 1.8px at 3% 44%, rgba(232,241,245,0.19), transparent 66%), radial-gradient(1.6px 1.6px at 17% 17%, rgba(232,241,245,0.17), transparent 68%), radial-gradient(2px 2px at 31% 27%, rgba(232,241,245,0.20), transparent 66%), radial-gradient(1.8px 1.8px at 47% 7%, rgba(232,241,245,0.18), transparent 66%), radial-gradient(1.6px 1.6px at 61% 21%, rgba(232,241,245,0.16), transparent 68%), radial-gradient(2px 2px at 74% 36%, rgba(232,241,245,0.20), transparent 66%), radial-gradient(1.8px 1.8px at 91% 8%, rgba(232,241,245,0.18), transparent 66%), radial-gradient(1.6px 1.6px at 96% 41%, rgba(232,241,245,0.15), transparent 68%), radial-gradient(1.8px 1.8px at 36% 48%, rgba(232,241,245,0.17), transparent 66%), radial-gradient(1.6px 1.6px at 8% 62%, rgba(232,241,245,0.14), transparent 68%), radial-gradient(1.8px 1.8px at 27% 57%, rgba(232,241,245,0.15), transparent 66%), radial-gradient(1.6px 1.6px at 64% 44%, rgba(232,241,245,0.14), transparent 68%), radial-gradient(1.2px 1.2px at 11% 24%, rgba(169,190,203,0.16), transparent 70%), radial-gradient(1px 1px at 21% 39%, rgba(169,190,203,0.14), transparent 72%), radial-gradient(1.3px 1.3px at 34% 11%, rgba(169,190,203,0.17), transparent 70%), radial-gradient(1px 1px at 44% 30%, rgba(169,190,203,0.13), transparent 72%), radial-gradient(1.2px 1.2px at 52% 15%, rgba(169,190,203,0.15), transparent 70%), radial-gradient(1px 1px at 58% 45%, rgba(169,190,203,0.12), transparent 72%), radial-gradient(1.3px 1.3px at 66% 29%, rgba(169,190,203,0.14), transparent 70%), radial-gradient(1px 1px at 71% 14%, rgba(169,190,203,0.13), transparent 72%), radial-gradient(1.2px 1.2px at 83% 33%, rgba(169,190,203,0.16), transparent 70%), radial-gradient(1px 1px at 89% 47%, rgba(169,190,203,0.11), transparent 72%), radial-gradient(1.3px 1.3px at 94% 26%, rgba(169,190,203,0.14), transparent 70%), radial-gradient(1px 1px at 15% 51%, rgba(169,190,203,0.11), transparent 72%), radial-gradient(1.2px 1.2px at 39% 63%, rgba(126,147,162,0.13), transparent 72%), radial-gradient(1px 1px at 49% 71%, rgba(126,147,162,0.10), transparent 74%), radial-gradient(1.2px 1.2px at 63% 66%, rgba(126,147,162,0.12), transparent 72%), radial-gradient(1px 1px at 76% 76%, rgba(126,147,162,0.09), transparent 74%), radial-gradient(1.3px 1.3px at 85% 68%, rgba(126,147,162,0.12), transparent 72%), radial-gradient(1px 1px at 92% 84%, rgba(126,147,162,0.07), transparent 74%), radial-gradient(1.2px 1.2px at 5% 79%, rgba(126,147,162,0.11), transparent 72%), radial-gradient(1px 1px at 29% 88%, rgba(126,147,162,0.08), transparent 74%), radial-gradient(1.1px 1.1px at 43% 82%, rgba(126,147,162,0.09), transparent 74%), radial-gradient(1px 1px at 57% 93%, rgba(126,147,162,0.06), transparent 74%), radial-gradient(1.2px 1.2px at 69% 89%, rgba(126,147,162,0.08), transparent 72%), radial-gradient(1px 1px at 19% 72%, rgba(126,147,162,0.10), transparent 74%), radial-gradient(1px 1px at 81% 96%, rgba(126,147,162,0.06), transparent 74%);
  --th-decor-pres: radial-gradient(2.5% 15% at 21% 10%, rgba(90,224,180,0.060), transparent 72%), radial-gradient(2% 12% at 27% 8%, rgba(96,217,190,0.050), transparent 74%), radial-gradient(3% 17% at 34% 12%, rgba(103,209,199,0.055), transparent 70%), radial-gradient(2% 13% at 41% 7%, rgba(110,201,208,0.045), transparent 74%), radial-gradient(2.5% 16% at 49% 11%, rgba(117,193,218,0.050), transparent 72%), radial-gradient(2% 12% at 56% 9%, rgba(123,186,227,0.045), transparent 74%), radial-gradient(3% 15% at 63% 13%, rgba(130,178,236,0.050), transparent 70%), radial-gradient(2% 11% at 70% 8%, rgba(136,170,246,0.045), transparent 74%), radial-gradient(2.5% 14% at 77% 12%, rgba(143,162,255,0.045), transparent 72%), linear-gradient(174deg, transparent 2%, rgba(90,224,180,0.060) 7%, rgba(103,209,199,0.050) 11%, transparent 18%), linear-gradient(177deg, transparent 5%, rgba(117,193,218,0.050) 12%, transparent 21%), linear-gradient(185deg, transparent 1%, rgba(143,162,255,0.045) 9%, transparent 19%), linear-gradient(171deg, transparent 8%, rgba(96,217,190,0.035) 14%, transparent 23%), linear-gradient(188deg, transparent 10%, rgba(130,178,236,0.030) 16%, transparent 24%), radial-gradient(62% 30% at 22% 2%, rgba(90,224,180,0.090), transparent 66%), radial-gradient(54% 26% at 47% -1%, rgba(117,193,218,0.075), transparent 68%), radial-gradient(58% 28% at 75% 1%, rgba(143,162,255,0.080), transparent 66%), radial-gradient(90% 20% at 55% 9%, rgba(110,201,208,0.040), transparent 74%), radial-gradient(130% 52% at 50% -14%, rgba(103,209,199,0.045), transparent 72%);
}

[data-theme="dune"] {
  --th-logo-coeur: #C98A34; --th-logo-halo: var(--th-accent); --th-surface-force: 2.4;
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FAF2E4%22%2F%3E%3Cstop%20offset%3D%22.44%22%20stop-color%3D%22%23F4E8D2%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23EADCC0%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.30%22%3E%3Ccircle%20cx%3D%22344%22%20cy%3D%22264%22%20r%3D%2284%22%20fill%3D%22%23FFE9B8%22%20opacity%3D%22.7%22%2F%3E%3Cpath%20d%3D%22M0%20512q256-120%20512-32t552-24%20536%2080v364H0z%22%20fill%3D%22%23EFDDBC%22%2F%3E%3Cpath%20d%3D%22M0%20600q288-104%20560-16t520-40%20520%2088v268H0z%22%20fill%3D%22%23E4CFA6%22%2F%3E%3Cpath%20d%3D%22M0%20696q320-88%20608%200t480-56%20512%2072v188H0z%22%20fill%3D%22%23D6BC8C%22%2F%3E%3Cpath%20d%3D%22M0%20784q360-56%20672%208t592-32%20336%2032v108H0z%22%20fill%3D%22%23C7A874%22%2F%3E%3Cg%20stroke%3D%22%23FFF6E2%22%20stroke-width%3D%224%22%20fill%3D%22none%22%20opacity%3D%22.45%22%3E%3Cpath%20d%3D%22M32%20528q248-112%20496-24%22%2F%3E%3Cpath%20d%3D%22M592%20608q240-88%20472-16%22%2F%3E%3Cpath%20d%3D%22M88%20712q304-80%20576%208%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;          /* Dune */
  --th-ambiance: 0.45;
  --th-voile: 0,0,0; --th-ombre: 0,0,0;
  --th-fond: #F3E7D6; --th-panneau: #FBF4EA; --th-carte: #FFFAF2;
  --th-fond-rgb: 243,231,214; --th-panneau-rgb: 251,244,234;
  --th-texte: #2A1C12; --th-texte-2: #5C3E26; --th-texte-3: #5C3D26;
  --th-trait: 166,140,111;
  --th-accent: #8E2C0E; --th-accent-clair: #6B1F08; --th-accent-doux: #7A4A0B; --th-accent-fort: #7A2409;
  --th-accent-rgb: 142,44,14;
  --th-sur-accent: #FFFFFF; --th-sur-plein: #FFFFFF;
  --th-second: #6B3D63; --th-second-clair: #4C2A47; --th-second-rgb: 107,61,99;
  --th-succes: #2A6234; --th-alerte: #6F4800; --th-danger: #96241C; --th-danger-rgb: 150,36,28;
  --th-rayon-micro: 4px; --th-rayon-xs: 8px; --th-rayon-sm: 10px; --th-rayon-md: 12px;
  --th-rayon-lg: 14px; --th-rayon-carte: 16px; --th-rayon-panneau: 22px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-decor-loin: radial-gradient(2px 2px at 8% 14%, rgba(255,252,243,0.92), rgba(255,252,243,0) 62%), radial-gradient(1.5px 1.5px at 21% 31%, rgba(255,249,236,0.78), rgba(255,249,236,0) 62%), radial-gradient(2.5px 2.5px at 34% 9%, rgba(255,252,243,0.85), rgba(255,252,243,0) 62%), radial-gradient(1.5px 1.5px at 46% 27%, rgba(255,250,238,0.70), rgba(255,250,238,0) 62%), radial-gradient(2px 2px at 57% 15%, rgba(255,252,243,0.88), rgba(255,252,243,0) 62%), radial-gradient(1.5px 1.5px at 68% 36%, rgba(255,249,236,0.72), rgba(255,249,236,0) 62%), radial-gradient(2.5px 2.5px at 79% 11%, rgba(255,252,243,0.85), rgba(255,252,243,0) 62%), radial-gradient(2px 2px at 91% 29%, rgba(255,250,238,0.80), rgba(255,250,238,0) 62%), radial-gradient(1.5px 1.5px at 14% 48%, rgba(255,252,243,0.74), rgba(255,252,243,0) 62%), radial-gradient(2px 2px at 29% 57%, rgba(255,249,236,0.82), rgba(255,249,236,0) 62%), radial-gradient(2.5px 2.5px at 41% 44%, rgba(255,252,243,0.80), rgba(255,252,243,0) 62%), radial-gradient(1.5px 1.5px at 63% 52%, rgba(255,250,238,0.70), rgba(255,250,238,0) 62%), radial-gradient(2px 2px at 74% 61%, rgba(255,252,243,0.84), rgba(255,252,243,0) 62%), radial-gradient(1.5px 1.5px at 86% 47%, rgba(255,249,236,0.72), rgba(255,249,236,0) 62%), radial-gradient(2px 2px at 5% 68%, rgba(255,252,243,0.78), rgba(255,252,243,0) 62%), radial-gradient(2.5px 2.5px at 95% 66%, rgba(255,250,238,0.76), rgba(255,250,238,0) 62%), radial-gradient(2px 2px at 18% 22%, rgba(190,150,102,0.070), rgba(190,150,102,0) 60%), radial-gradient(2px 2px at 52% 38%, rgba(190,150,102,0.060), rgba(190,150,102,0) 60%), radial-gradient(2.5px 2.5px at 83% 24%, rgba(190,150,102,0.065), rgba(190,150,102,0) 60%), repeating-linear-gradient(180deg, rgba(255,253,247,0.42) 0 1px, rgba(255,253,247,0) 1px 8px), repeating-linear-gradient(179.6deg, rgba(255,247,232,0.34) 0 1px, rgba(255,247,232,0) 1px 13px), repeating-linear-gradient(180.4deg, rgba(255,250,238,0.26) 0 1px, rgba(255,250,238,0) 1px 21px), repeating-linear-gradient(180deg, rgba(184,143,96,0.030) 0 1px, rgba(184,143,96,0) 1px 34px);
  --th-decor-pres: radial-gradient(152% 46% at 38% 139%, rgba(168,126,80,0.070) 0 98.5%, rgba(168,126,80,0) 100%), radial-gradient(134% 44% at 73% 132%, rgba(186,146,99,0.055) 0 98.6%, rgba(186,146,99,0) 100%), radial-gradient(120% 45% at 24% 127%, rgba(203,167,121,0.040) 0 98.7%, rgba(203,167,121,0) 100%), radial-gradient(circle 72px at 22% 78%, rgba(255,243,211,0.80) 0 58%, rgba(255,231,178,0.38) 80%, rgba(255,228,175,0) 100%), radial-gradient(760px 520px at 21% 79%, rgba(255,214,146,0.24) 0%, rgba(255,206,142,0.12) 42%, rgba(255,202,140,0) 72%), linear-gradient(101deg, rgba(255,243,216,0) 18%, rgba(255,243,216,0.15) 21%, rgba(255,243,216,0) 26%), linear-gradient(95deg, rgba(255,239,208,0) 33%, rgba(255,239,208,0.12) 36%, rgba(255,239,208,0) 41%), linear-gradient(110deg, rgba(255,246,224,0) 46%, rgba(255,246,224,0.10) 49%, rgba(255,246,224,0) 54%), linear-gradient(180deg, rgba(232,178,120,0) 58%, rgba(232,178,120,0.050) 74%, rgba(232,178,120,0.030) 84%, rgba(232,178,120,0) 92%), linear-gradient(180deg, rgba(255,252,245,0.55) 0%, rgba(255,246,231,0.22) 34%, rgba(255,244,226,0) 62%);
}

[data-theme="orage"] { --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230D121A%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%23121924%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%231B2430%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.18%22%3E%3Cellipse%20cx%3D%22480%22%20cy%3D%2272%22%20rx%3D%22600%22%20ry%3D%22208%22%20fill%3D%22%2305080D%22%20opacity%3D%22.5%22%2F%3E%3Cellipse%20cx%3D%221240%22%20cy%3D%2240%22%20rx%3D%22520%22%20ry%3D%22176%22%20fill%3D%22%23070B12%22%20opacity%3D%22.45%22%2F%3E%3Cellipse%20cx%3D%22848%22%20cy%3D%22184%22%20rx%3D%22480%22%20ry%3D%22104%22%20fill%3D%22%23A3BED6%22%20opacity%3D%22.04%22%2F%3E%3Cg%20stroke%3D%22%23BED0E2%22%20stroke-width%3D%222%22%20opacity%3D%22.11%22%3E%3Cpath%20d%3D%22M160%20240l-64%20360%22%2F%3E%3Cpath%20d%3D%22M384%20176l-64%20424%22%2F%3E%3Cpath%20d%3D%22M608%20264l-64%20360%22%2F%3E%3Cpath%20d%3D%22M832%20160l-64%20464%22%2F%3E%3Cpath%20d%3D%22M1056%20248l-64%20368%22%2F%3E%3Cpath%20d%3D%22M1280%20184l-64%20432%22%2F%3E%3Cpath%20d%3D%22M1488%20280l-64%20344%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M824%20136l-40%20120h48l-40%20136%22%20stroke%3D%22%23E7F0FF%22%20stroke-width%3D%226%22%20fill%3D%22none%22%20opacity%3D%22.22%22%2F%3E%3Cpath%20d%3D%22M0%20760q400-40%20800%208t800-24v156H0z%22%20fill%3D%22%23212B38%22%20opacity%3D%22.45%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;          /* Orage */
  --th-ambiance: 0.55;
  --th-voile: 255,255,255; --th-ombre: 0,0,0;
  --th-fond: #0F141A; --th-panneau: #151B23; --th-carte: #1B222B;
  --th-fond-rgb: 15,20,26; --th-panneau-rgb: 21,27,35;
  --th-texte: #E9EEF3; --th-texte-2: #B2BDC9; --th-texte-3: #8A98A6;
  --th-trait: 101,113,128;
  --th-accent: #8FB3D4; --th-accent-clair: #CFE0EF; --th-accent-doux: #9DBEDB; --th-accent-fort: #A8C6E0;
  --th-accent-rgb: 143,179,212;
  --th-sur-accent: #0F141A; --th-sur-plein: #111111;
  --th-second: #93A7C4; --th-second-clair: #C3D0E2; --th-second-rgb: 147,167,196;
  --th-succes: #7FC2A6; --th-alerte: #DCB271; --th-danger: #E38B8B; --th-danger-rgb: 227,139,139;
  --th-rayon-micro: 2px; --th-rayon-xs: 4px; --th-rayon-sm: 6px; --th-rayon-md: 8px;
  --th-rayon-lg: 10px; --th-rayon-carte: 10px; --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-decor-loin: repeating-linear-gradient(74deg, rgba(190,208,226,0.030) 0 1px, transparent 1px 11px), repeating-linear-gradient(78deg, rgba(168,188,210,0.022) 0 1px, transparent 1px 17px), repeating-linear-gradient(71deg, rgba(206,222,238,0.017) 0 1px, transparent 1px 29px), repeating-linear-gradient(82deg, rgba(150,172,194,0.013) 0 2px, transparent 2px 43px), repeating-linear-gradient(76deg, rgba(198,216,234,0.010) 0 1px, transparent 1px 67px), radial-gradient(1.5px 1.5px at 17% 24%, rgba(214,230,244,0.18), transparent 70%), radial-gradient(2px 2px at 57% 12%, rgba(214,230,244,0.16), transparent 70%), radial-gradient(1.5px 1.5px at 68% 46%, rgba(214,230,244,0.14), transparent 70%), radial-gradient(1.5px 1.5px at 31% 79%, rgba(214,230,244,0.12), transparent 70%);
  --th-decor-pres: radial-gradient(1240px 640px at 24% -16%, rgba(3,5,9,0.22), transparent 68%), radial-gradient(1120px 580px at 79% -12%, rgba(4,7,11,0.20), transparent 66%), radial-gradient(880px 420px at 52% 4%, rgba(163,190,214,0.026), transparent 72%), radial-gradient(420px 230px at 55% 0%, rgba(198,220,238,0.018), transparent 74%), linear-gradient(101deg, transparent 33%, rgba(170,195,218,0.014) 41%, transparent 48%), radial-gradient(1500px 520px at 50% 116%, rgba(2,4,7,0.18), transparent 70%);
}

[data-theme="nimbe"] {
  --th-logo-coeur: #C99B3F; --th-logo-halo: var(--th-accent);          /* Nimbe */
  --th-ambiance: 0.30;
  --th-surface-force: 2.0;
  --th-voile: 0,0,0; --th-ombre: 0,0,0;
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%201000%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22b%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FDFDFC%22%2F%3E%3Cstop%20offset%3D%22.45%22%20stop-color%3D%22%23FAFAF8%22%2F%3E%3Cstop%20offset%3D%22.78%22%20stop-color%3D%22%23F4F3EF%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23EEEDE7%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22s%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FFF6DF%22%20stop-opacity%3D%22.9%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23F2D9A2%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23E8C87F%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3ClinearGradient%20id%3D%22r%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23F0DCAE%22%20stop-opacity%3D%22.4%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23F0DCAE%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%221000%22%20fill%3D%22url%28%23b%29%22%2F%3E%3Cg%20opacity%3D%220.34%22%3E%3Ccircle%20cx%3D%221200%22%20cy%3D%22240%22%20r%3D%22232%22%20fill%3D%22url%28%23s%29%22%2F%3E%3Ccircle%20cx%3D%221200%22%20cy%3D%22240%22%20r%3D%2248%22%20fill%3D%22%23FFFAEC%22%2F%3E%3Cg%20fill%3D%22url%28%23r%29%22%3E%3Cpath%20d%3D%22M1176%20280L808%201000h128l272-704z%22%2F%3E%3Cpath%20d%3D%22M1232%20284l232%20716h-104l-176-696z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23FFFFFF%22%3E%3Cpath%20d%3D%22M-40%20584q120-96%20248-40%2048-112%20184-88%2080-104%20216-40%2096-72%20184%2016%20112-88%20224%208%20104-56%20184%2032%2096-24%20176%2056v480H-40z%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M-40%20640q120-80%20248-32%2048-96%20184-72l-8%2040q-120-24-168%2064-120-48-256%2024z%22%20fill%3D%22%23E4E3DE%22%2F%3E%3Cpath%20d%3D%22M592%20592q96-72%20184%2016%20112-88%20224%208l-16%2040q-96-80-200%200-80-80-184-16z%22%20fill%3D%22%23E4E3DE%22%2F%3E%3Cg%20fill%3D%22%23FFFFFF%22%20opacity%3D%22.97%22%3E%3Cpath%20d%3D%22M-40%20736q136-80%20272-24%2064-88%20208-48%2088-72%20216%208%20104-56%20208%2032%20112-48%20208%2040%2080-16%20144%2040v216H-40z%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M-40%20784q136-72%20272-16%2064-80%20208-40l-8%2036q-128-32-184%2048-128-48-288%2020z%22%20fill%3D%22%23EBEAE4%22%2F%3E%3Cg%20fill%3D%22%23EFEBE0%22%3E%3Cpath%20d%3D%22M-40%20880q168-56%20328-8%2080-56%20232-16%20104-40%20224%2024%20120-32%20224%2032%2080-8%20152%2032v56H-40z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23E2C384%22%20stroke-width%3D%226%22%20fill%3D%22none%22%20opacity%3D%22.8%22%3E%3Cpath%20d%3D%22M-24%20608q128-88%20264-40%2048-104%20192-80%22%2F%3E%3Cpath%20d%3D%22M600%20600q96-64%20184%2016%20112-80%20224%208%22%2F%3E%3Cpath%20d%3D%22M-24%20760q136-64%20272-12%2064-72%20208-36%22%2F%3E%3Cpath%20d%3D%22M1080%20744q112-40%20208%2040%2080-16%20144%2040%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-fond: #FAFAF8; --th-panneau: #FDFDFC; --th-carte: #FFFFFF;
  --th-fond-rgb: 250,250,248; --th-panneau-rgb: 253,253,252;
  --th-texte: #26231C; --th-texte-2: #5A564A; --th-texte-3: #5A574D;
  --th-trait: 152,147,133;
  --th-accent: #6C5317; --th-accent-clair: #4A3708; --th-accent-doux: #6F5518; --th-accent-fort: #6D5417;
  --th-accent-rgb: 108,83,23;
  --th-sur-accent: #FFFFFF; --th-sur-plein: #FFFFFF;
  --th-second: #4F5862; --th-second-clair: #464E58; --th-second-rgb: 79,88,98;
  --th-succes: #386230; --th-alerte: #794F0B; --th-danger: #9E3428; --th-danger-rgb: 158,52,40;
  --th-rayon-micro: 5px; --th-rayon-xs: 8px; --th-rayon-sm: 10px; --th-rayon-md: 12px;
  --th-rayon-lg: 16px; --th-rayon-carte: 18px; --th-rayon-panneau: 24px;
  --th-police: system-ui, -apple-system, sans-serif; --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-decor-loin: none;
  --th-decor-pres: none;
}

/* ▼▼ DÉCORS GÉNÉRÉS — ne pas éditer à la main ▼▼ */

/* ══════════════════════════════════════════════════════════════════════════
   HUIT DÉCORS DE PLUS — 15/08/2026
   Amadou : « on a plutôt fait des paysages, mais j'aimerais aussi des décors ».
   La différence : un paysage, c'est « une forêt » ; un décor, c'est un LIEU
   qu'on nomme. Les sept premiers sont des milieux, ces huit-là sont des
   endroits — et Velours n'est même pas un extérieur, c'est un salon.
   Dubaï est dessiné d'après une photo qu'il a fournie : on garde l'heure bleue,
   la flèche seule au centre, l'or aux fenêtres et l'eau devant. ⚠️ Pas la photo
   elle-même — elle appartient à quelqu'un, et deux méga-octets dans la feuille
   ralentiraient CHAQUE chargement de page. Le dessin fait deux kilo-octets.
   ⚠️⚠️ CES BLOCS SONT GÉNÉRÉS. Ne pas les modifier à la main : la source est
   outils/decors.py + outils/gen_themes.py, et le générateur REFUSE d'écrire s'il
   manque un seul des 38 jetons obligatoires. Un thème incomplet retombe en
   silence sur les valeurs de Nuit violette — un seul mauvais gris au milieu d'un
   thème clair, on ne le voit qu'en le cherchant.
   ══════════════════════════════════════════════════════════════════════════ */

[data-theme="dubai"] {   /* Dubaï */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2305081A%22%2F%3E%3Cstop%20offset%3D%22.3%22%20stop-color%3D%22%230A1230%22%2F%3E%3Cstop%20offset%3D%22.56%22%20stop-color%3D%22%23121F44%22%2F%3E%3Cstop%20offset%3D%22.76%22%20stop-color%3D%22%23252C4E%22%2F%3E%3Cstop%20offset%3D%22.9%22%20stop-color%3D%22%234A3A46%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%236B4436%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22h%22%20cx%3D%22.34%22%20cy%3D%221.04%22%20r%3D%22.8%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23C2825A%22%20stop-opacity%3D%22.3%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%239A6448%22%20stop-opacity%3D%22.1%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%239A6448%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3ClinearGradient%20id%3D%22tw%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%237E96CE%22%2F%3E%3Cstop%20offset%3D%22.22%22%20stop-color%3D%22%234A5F98%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%231E2A56%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23070C22%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22w%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23182548%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23070B1C%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23h%29%22%2F%3E%3Cg%20opacity%3D%220.42%22%3E%3Cg%20fill%3D%22%23CBD8F2%22%3E%3Ccircle%20cx%3D%22180%22%20cy%3D%2270%22%20r%3D%222%22%20opacity%3D%22.45%22%2F%3E%3Ccircle%20cx%3D%22430%22%20cy%3D%2242%22%20r%3D%221.6%22%20opacity%3D%22.35%22%2F%3E%3Ccircle%20cx%3D%22700%22%20cy%3D%2296%22%20r%3D%221.8%22%20opacity%3D%22.4%22%2F%3E%3Ccircle%20cx%3D%221050%22%20cy%3D%2254%22%20r%3D%221.6%22%20opacity%3D%22.32%22%2F%3E%3Ccircle%20cx%3D%221320%22%20cy%3D%2288%22%20r%3D%222%22%20opacity%3D%22.4%22%2F%3E%3Ccircle%20cx%3D%221500%22%20cy%3D%2240%22%20r%3D%221.5%22%20opacity%3D%22.3%22%2F%3E%3Ccircle%20cx%3D%22290%22%20cy%3D%22140%22%20r%3D%221.5%22%20opacity%3D%22.26%22%2F%3E%3Ccircle%20cx%3D%22900%22%20cy%3D%22150%22%20r%3D%221.5%22%20opacity%3D%22.24%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3Cg%20opacity%3D%220.1%22%3E%3Cg%20fill%3D%22%23C08A64%22%3E%3Cpath%20d%3D%22M120%20612q180-24%20360%206t300-9%20420%2013%20380-8v17q-190%2015-380%204t-420-13-300%209-360-6z%22%2F%3E%3Cpath%20d%3D%22M40%20662q140-17%20280%204t240-8%20320%2010%20300-6v13q-150%2012-300%204t-320-10-240%208-280-4z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3Cg%20opacity%3D%220.11%22%3E%3Cg%20fill%3D%22%2393A9D6%22%3E%3Cpath%20d%3D%22M0%20704h58l6-80h30l6%2080h72l8-116h26l8%20116h96l6-66h24l6%2066h1254v36H0z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3Cg%20opacity%3D%220.15%22%3E%3Cg%20fill%3D%22%230C1430%22%3E%3Cpath%20d%3D%22M22%20660h70l4-40h14l4%2040h64v240H22zM196%20636h52l6-46h12l6%2046h56v264H196zM342%20674h84v226h-84zM452%20618h44l5-52h12l5%2052h50v282H452zM1082%20646h60l5-44h12l5%2044h56v254h-138zM1256%20610h74l6-56h14l6%2056h64v290h-164zM1444%20664h56l5-38h12l5%2038h56v236h-134z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23070C24%22%3E%3Cpath%20d%3D%22M0%20720h120v180H0zM150%20700h96v200h-96zM276%20742h84v158h-84zM392%20690h70v210h-70zM1130%20706h78v194h-78zM1240%20736h96v164h-96zM1366%20688h74v212h-74zM1470%20730h130v170h-130z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3Cg%20opacity%3D%220.3%22%3E%3Cpath%20d%3D%22M800%2026l4%2038%208%206%204%2074%2022%2014%206%2092%2026%2016%208%20110%2030%2020%2010%20148%2034%2022%2012%20296H636l12-296%2034-22%2010-148%2030-20%208-110%2026-16%206-92%2022-14%204-74%208-6z%22%20fill%3D%22url%28%23tw%29%22%2F%3E%3Cpath%20d%3D%22M800%200l5%2030-5%208-5-8z%22%20fill%3D%22%23DCE7FF%22%20opacity%3D%22.8%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%2216%22%20r%3D%229%22%20fill%3D%22%23FFF3D0%22%20opacity%3D%22.35%22%2F%3E%3C%2Fg%3E%3Cg%20opacity%3D%220.2%22%3E%3Cg%20fill%3D%22%23F7CE84%22%3E%3Cpath%20d%3D%22M772%20300h7v10h-7zM812%20344h7v10h-7zM784%20402h7v10h-7zM820%20452h7v10h-7zM766%20496h7v10h-7zM806%20560h7v10h-7zM776%20620h7v10h-7zM830%20654h7v10h-7zM758%20700h7v10h-7zM812%20748h7v10h-7zM782%20800h7v10h-7z%22%2F%3E%3Cpath%20d%3D%22M40%20700h7v10h-7zM86%20676h7v10h-7zM214%20726h7v10h-7zM300%20766h7v10h-7zM410%20716h7v10h-7zM466%20660h7v10h-7zM1148%20730h7v10h-7zM1272%20764h7v10h-7zM1388%20712h7v10h-7zM1290%20646h7v10h-7zM1496%20754h7v10h-7zM1548%20780h7v10h-7zM60%20780h7v10h-7zM330%20820h7v10h-7zM1180%20812h7v10h-7zM1420%20800h7v10h-7z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3Cg%20opacity%3D%220.16%22%3E%3Cpath%20d%3D%22M0%20838h1600v62H0z%22%20fill%3D%22url%28%23w%29%22%2F%3E%3Cpath%20d%3D%22M540%20836q130-30%20260-30t260%2030v10H540z%22%20fill%3D%22%230E1938%22%20opacity%3D%22.6%22%2F%3E%3Cg%20fill%3D%22%23F3B457%22%20opacity%3D%22.3%22%3E%3Cpath%20d%3D%22M796%20840h7v54h-7zM596%20846h5v38h-5zM986%20846h5v38h-5zM296%20852h4v32h-4zM1276%20852h4v32h-4zM176%20856h4v26h-4zM1436%20856h4v26h-4zM416%20850h4v36h-4zM1146%20850h4v36h-4z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23F7D9A8%22%20stroke-width%3D%223%22%20opacity%3D%22.18%22%3E%3Cpath%20d%3D%22M120%20862h1360M60%20884h1480%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(243,215,154,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(166,193,230,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(243,215,154,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(166,193,230,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(243,215,154,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(166,193,230,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(243,215,154,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(166,193,230,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(243,215,154,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(224,178,92,.13) 0%, rgba(5,11,36,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(94,134,196,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(224,178,92,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(224,178,92,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.5;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #050B24;
  --th-panneau: #0E1C3E;
  --th-carte: #17294F;
  --th-fond-rgb: 5,11,36;
  --th-panneau-rgb: 14,28,62;
  --th-texte: #EDE4D2;
  --th-texte-2: #C3B79C;
  --th-texte-3: #A99C82;
  --th-trait: 150,136,110;
  --th-accent: #E0B25C;
  --th-accent-clair: #F3D79A;
  --th-accent-doux: #C9A468;
  --th-accent-fort: #EFC97C;
  --th-accent-rgb: 224,178,92;
  --th-sur-accent: #050B24;
  --th-sur-plein: #111111;
  --th-second: #5E86C4;
  --th-second-clair: #A6C1E6;
  --th-second-rgb: 94,134,196;
  --th-succes: #5FC79A;
  --th-alerte: #E8BC63;
  --th-danger: #EF8A82;
  --th-danger-rgb: 239,138,130;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #E0B25C;
  --th-logo-halo: var(--th-accent);
}

[data-theme="hanami"] {   /* Hanami */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FDF6F8%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%23F7E2E9%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23EFCFD9%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.5%22%3E%3Ccircle%20cx%3D%221240%22%20cy%3D%22200%22%20r%3D%2296%22%20fill%3D%22%23FFF7F8%22%20opacity%3D%22.7%22%2F%3E%3Cpath%20d%3D%22M430%20760l370-380%20370%20380z%22%20fill%3D%22%23C6AFC2%22%20opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M690%20490l110-116%20110%20116-74-30-36%2040-38-26z%22%20fill%3D%22%23FFFDFE%22%2F%3E%3Cpath%20d%3D%22M0%20748q300-48%20600%2012t1000-32v172H0z%22%20fill%3D%22%23BCA5B9%22%20opacity%3D%22.38%22%2F%3E%3Cpath%20d%3D%22M0%20812q400-40%20800%2016t800-26v98H0z%22%20fill%3D%22%238E7288%22%20opacity%3D%22.32%22%2F%3E%3Cg%20stroke%3D%22%236B4152%22%20stroke-width%3D%2215%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%20opacity%3D%22.85%22%3E%3Cpath%20d%3D%22M-30%2070q200%2050%20310%20160t230%20130%22%2F%3E%3Cpath%20d%3D%22M150%20116q30%20100%2010%20170%22%2F%3E%3Cpath%20d%3D%22M380%20220q70%2060%2070%20150%22%2F%3E%3Cpath%20d%3D%22M520%20310q90%2010%20150-40%22%2F%3E%3Cpath%20d%3D%22M60%2040q40%2070%2030%20130%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23F0A9C0%22%3E%3Ccircle%20cx%3D%2286%22%20cy%3D%2296%22%20r%3D%2230%22%2F%3E%3Ccircle%20cx%3D%22196%22%20cy%3D%22150%22%20r%3D%2235%22%2F%3E%3Ccircle%20cx%3D%22146%22%20cy%3D%22256%22%20r%3D%2230%22%2F%3E%3Ccircle%20cx%3D%22286%22%20cy%3D%22188%22%20r%3D%2230%22%2F%3E%3Ccircle%20cx%3D%22376%22%20cy%3D%22240%22%20r%3D%2235%22%2F%3E%3Ccircle%20cx%3D%22456%22%20cy%3D%22308%22%20r%3D%2230%22%2F%3E%3Ccircle%20cx%3D%22346%22%20cy%3D%22348%22%20r%3D%2225%22%2F%3E%3Ccircle%20cx%3D%22536%22%20cy%3D%22278%22%20r%3D%2230%22%2F%3E%3Ccircle%20cx%3D%22626%22%20cy%3D%22258%22%20r%3D%2235%22%2F%3E%3Ccircle%20cx%3D%22246%22%20cy%3D%2266%22%20r%3D%2225%22%2F%3E%3Ccircle%20cx%3D%22556%22%20cy%3D%22378%22%20r%3D%2225%22%2F%3E%3Ccircle%20cx%3D%22676%22%20cy%3D%22330%22%20r%3D%2228%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23FBD3DF%22%3E%3Ccircle%20cx%3D%22118%22%20cy%3D%22168%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22238%22%20cy%3D%22228%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22416%22%20cy%3D%22168%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22496%22%20cy%3D%22220%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22586%22%20cy%3D%22330%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22306%22%20cy%3D%22288%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22646%22%20cy%3D%22196%22%20r%3D%2218%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23F3B8CB%22%20opacity%3D%22.75%22%3E%3Ccircle%20cx%3D%22740%22%20cy%3D%22480%22%20r%3D%2214%22%2F%3E%3Ccircle%20cx%3D%22920%22%20cy%3D%22614%22%20r%3D%2212%22%2F%3E%3Ccircle%20cx%3D%221050%22%20cy%3D%22420%22%20r%3D%2214%22%2F%3E%3Ccircle%20cx%3D%221250%22%20cy%3D%22590%22%20r%3D%2212%22%2F%3E%3Ccircle%20cx%3D%221420%22%20cy%3D%22490%22%20r%3D%2214%22%2F%3E%3Ccircle%20cx%3D%22830%22%20cy%3D%22716%22%20r%3D%2211%22%2F%3E%3Ccircle%20cx%3D%221150%22%20cy%3D%22700%22%20r%3D%2212%22%2F%3E%3Ccircle%20cx%3D%221360%22%20cy%3D%22300%22%20r%3D%2211%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%238C3550%22%20stroke-width%3D%2219%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M1270%20780V638M1460%20780V638M1240%20632h250M1258%20588h214%22%2F%3E%3Cpath%20d%3D%22M1232%20588q126-24%20256%200%22%20stroke-width%3D%2214%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(106,32,57,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(58,70,103,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(106,32,57,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(58,70,103,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(106,32,57,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(58,70,103,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(106,32,57,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(58,70,103,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(106,32,57,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(140,53,80,.13) 0%, rgba(251,241,244,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(78,94,134,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(140,53,80,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(140,53,80,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.42;
  --th-surface-force: 2.2;
  --th-voile: 0,0,0;
  --th-ombre: 0,0,0;
  --th-fond: #FBF1F4;
  --th-panneau: #FEF8FA;
  --th-carte: #FFFCFD;
  --th-fond-rgb: 251,241,244;
  --th-panneau-rgb: 254,248,250;
  --th-texte: #3A1B29;
  --th-texte-2: #633446;
  --th-texte-3: #6A3B4C;
  --th-trait: 168,132,148;
  --th-accent: #8C3550;
  --th-accent-clair: #6A2039;
  --th-accent-doux: #A35168;
  --th-accent-fort: #77293F;
  --th-accent-rgb: 140,53,80;
  --th-sur-accent: #FFFFFF;
  --th-sur-plein: #FFFFFF;
  --th-second: #4E5E86;
  --th-second-clair: #3A4667;
  --th-second-rgb: 78,94,134;
  --th-succes: #2E6140;
  --th-alerte: #7A4A08;
  --th-danger: #9B2530;
  --th-danger-rgb: 155,37,48;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 8px;
  --th-rayon-sm: 10px;
  --th-rayon-md: 12px;
  --th-rayon-lg: 14px;
  --th-rayon-carte: 16px;
  --th-rayon-panneau: 22px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #8C3550;
  --th-logo-halo: var(--th-accent);
}

[data-theme="miroir"] {   /* Miroir */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230C1826%22%2F%3E%3Cstop%20offset%3D%22.58%22%20stop-color%3D%22%2322405A%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%237E9BA8%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22e%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%236A879A%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2312202F%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.19%22%3E%3Ccircle%20cx%3D%221190%22%20cy%3D%22180%22%20r%3D%2262%22%20fill%3D%22%23E9F2F0%22%20opacity%3D%22.7%22%2F%3E%3Cpath%20d%3D%22M0%20470l260-224%20200%20166%20170-118%20230%20196%20280-244%20460%20302v70H0z%22%20fill%3D%22%2312202F%22%2F%3E%3Cpath%20d%3D%22M630%20294l230%20196-230-40z%22%20fill%3D%22%2331536B%22%20opacity%3D%22.6%22%2F%3E%3Cpath%20d%3D%22M1090%20250l120%2078-230%2030z%22%20fill%3D%22%2331536B%22%20opacity%3D%22.6%22%2F%3E%3Cpath%20d%3D%22M0%20470h1600v430H0z%22%20fill%3D%22url%28%23e%29%22%2F%3E%3Cpath%20d%3D%22M0%20470l260%20224%20200-166%20170%20118%20230-196%20280%20244%20460-302v-52H0z%22%20fill%3D%22%230E1B27%22%20opacity%3D%22.72%22%2F%3E%3Cg%20stroke%3D%22%23BBD3DC%22%20stroke-width%3D%225%22%20opacity%3D%22.22%22%3E%3Cpath%20d%3D%22M70%20570h360M630%20610h480M160%20690h290M910%20720h520M350%20790h600M1130%20830h360%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23D8E6EA%22%20stroke-width%3D%224%22%20opacity%3D%22.16%22%3E%3Cpath%20d%3D%22M0%20500h1600M0%20528h1600%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M660%20730h150l-20%2034h-110z%22%20fill%3D%22%23080F16%22%2F%3E%3Cpath%20d%3D%22M735%20730v-56%22%20stroke%3D%22%23080F16%22%20stroke-width%3D%228%22%2F%3E%3Cg%20fill%3D%22%23CFE2E6%22%20opacity%3D%22.5%22%3E%3Ccircle%20cx%3D%22220%22%20cy%3D%22110%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22480%22%20cy%3D%2270%22%20r%3D%225%22%2F%3E%3Ccircle%20cx%3D%22760%22%20cy%3D%22132%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%221430%22%20cy%3D%2296%22%20r%3D%225%22%2F%3E%3Ccircle%20cx%3D%22980%22%20cy%3D%2256%22%20r%3D%224%22%2F%3E%3Ccircle%20cx%3D%221310%22%20cy%3D%22200%22%20r%3D%224%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(196,224,232,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(190,207,226,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(196,224,232,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(190,207,226,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(196,224,232,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(190,207,226,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(196,224,232,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(190,207,226,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(196,224,232,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(127,176,190,.13) 0%, rgba(11,22,34,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(143,169,198,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(127,176,190,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(127,176,190,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.5;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #0B1622;
  --th-panneau: #152A3A;
  --th-carte: #1F3C50;
  --th-fond-rgb: 11,22,34;
  --th-panneau-rgb: 21,42,58;
  --th-texte: #E3EFF2;
  --th-texte-2: #A9C2CC;
  --th-texte-3: #93AAB6;
  --th-trait: 108,142,158;
  --th-accent: #7FB0BE;
  --th-accent-clair: #C4E0E8;
  --th-accent-doux: #A6C8D2;
  --th-accent-fort: #94C4D2;
  --th-accent-rgb: 127,176,190;
  --th-sur-accent: #0B1622;
  --th-sur-plein: #111111;
  --th-second: #8FA9C6;
  --th-second-clair: #BECFE2;
  --th-second-rgb: 143,169,198;
  --th-succes: #6BC49C;
  --th-alerte: #DEBB6E;
  --th-danger: #EE9098;
  --th-danger-rgb: 238,144,152;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #7FB0BE;
  --th-logo-halo: var(--th-accent);
}

[data-theme="lanternes"] {   /* Lanternes */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230A0810%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%231E1420%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232C1C26%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22l%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FFBE7E%22%20stop-opacity%3D%22.6%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23FFBE7E%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.16%22%3E%3Cpath%20d%3D%22M0%200h430l180%20560v340H0z%22%20fill%3D%22%231A1119%22%2F%3E%3Cpath%20d%3D%22M1600%200h-430l-180%20560v340h610z%22%20fill%3D%22%231A1119%22%2F%3E%3Cpath%20d%3D%22M0%2090q150-70%20320-34l150%2032-10%2058-160-34q-170-34-300%2042z%22%20fill%3D%22%2331202A%22%2F%3E%3Cpath%20d%3D%22M1600%2090q-150-70-320-34l-150%2032%2010%2058%20160-34q170-34%20300%2042z%22%20fill%3D%22%2331202A%22%2F%3E%3Cpath%20d%3D%22M60%20300q120-50%20250-26l130%2026-8%2048-140-26q-134-24-232%2034z%22%20fill%3D%22%2331202A%22%2F%3E%3Cpath%20d%3D%22M1540%20300q-120-50-250-26l-130%2026%208%2048%20140-26q134-24%20232%2034z%22%20fill%3D%22%2331202A%22%2F%3E%3Cpath%20d%3D%22M180%20520q90-38%20190-18l100%2020-6%2038-108-20q-102-18-176%2026z%22%20fill%3D%22%2331202A%22%2F%3E%3Cpath%20d%3D%22M1420%20520q-90-38-190-18l-100%2020%206%2038%20108-20q102-18%20176%2026z%22%20fill%3D%22%2331202A%22%2F%3E%3Cg%20fill%3D%22%233E2A34%22%3E%3Cpath%20d%3D%22M40%20160h140v190H40zM220%20190h100v160H220zM1280%20190h100v160h-100zM1420%20160h140v190h-140zM120%20400h120v170H120zM1360%20400h120v170h-120zM60%20620h150v200H60zM1390%20620h150v200h-150zM250%20600h110v180H250zM1240%20600h110v180h-110z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23E8B95E%22%20opacity%3D%22.42%22%3E%3Cpath%20d%3D%22M50%20170h120v170H50zM230%20200h80v140h-80zM1290%20200h80v140h-80zM1430%20170h120v170h-120zM130%20410h100v150H130zM1370%20410h100v150h-100zM70%20630h130v180H70zM1400%20630h130v180h-130zM260%20610h90v160h-90zM1250%20610h90v160h-90z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23241820%22%20stroke-width%3D%226%22%20opacity%3D%22.85%22%3E%3Cpath%20d%3D%22M90%20170v170M130%20170v170M50%20240h120M50%20290h120M262%20200v140M1332%20200v140M1470%20170v170M1510%20170v170M170%20410v150M1418%20410v150M110%20630v180M155%20630v180M70%20720h130M1445%20630v180M1490%20630v180M1400%20720h130M300%20610v160M1290%20610v160%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23B8323C%22%20opacity%3D%22.85%22%3E%3Cpath%20d%3D%22M50%20372h120q10%200%208%2012l-14%2054q-2%2010-14%2010H70q-12%200-14-10l-14-54q-2-12%208-12z%22%2F%3E%3Cpath%20d%3D%22M1430%20372h120q10%200%208%2012l-14%2054q-2%2010-14%2010h-92q-12%200-14-10l-14-54q-2-12%208-12z%22%2F%3E%3Cpath%20d%3D%22M130%20590h100q9%200%207%2011l-12%2044q-2%209-12%209h-66q-10%200-12-9l-12-44q-2-11%207-11z%22%2F%3E%3Cpath%20d%3D%22M1370%20590h100q9%200%207%2011l-12%2044q-2%209-12%209h-66q-10%200-12-9l-12-44q-2-11%207-11z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%233A2830%22%20stroke-width%3D%224%22%20opacity%3D%22.8%22%3E%3Cpath%20d%3D%22M180%20120q620-40%201240%200M300%20330q500-30%201000%200M420%20520q380-24%20760%200%22%2F%3E%3C%2Fg%3E%3Cg%3E%3Cellipse%20cx%3D%22200%22%20cy%3D%22200%22%20rx%3D%2266%22%20ry%3D%2284%22%20fill%3D%22url%28%23l%29%22%2F%3E%3Cellipse%20cx%3D%22200%22%20cy%3D%22200%22%20rx%3D%2240%22%20ry%3D%2254%22%20fill%3D%22%23D2453C%22%2F%3E%3Cellipse%20cx%3D%22200%22%20cy%3D%22200%22%20rx%3D%2226%22%20ry%3D%2240%22%20fill%3D%22%23F58C5A%22%2F%3E%3Cpath%20d%3D%22M178%20146h44v12h-44zM178%20242h44v12h-44z%22%20fill%3D%22%233A1418%22%2F%3E%3Cpath%20d%3D%22M200%20130v16M200%20254v30%22%20stroke%3D%22%233A1418%22%20stroke-width%3D%226%22%2F%3E%3Cpath%20d%3D%22M191%20284h18l-9%2028z%22%20fill%3D%22%23C9A24A%22%2F%3E%3Cellipse%20cx%3D%221400%22%20cy%3D%22200%22%20rx%3D%2266%22%20ry%3D%2284%22%20fill%3D%22url%28%23l%29%22%2F%3E%3Cellipse%20cx%3D%221400%22%20cy%3D%22200%22%20rx%3D%2240%22%20ry%3D%2254%22%20fill%3D%22%23D2453C%22%2F%3E%3Cellipse%20cx%3D%221400%22%20cy%3D%22200%22%20rx%3D%2226%22%20ry%3D%2240%22%20fill%3D%22%23F58C5A%22%2F%3E%3Cpath%20d%3D%22M1378%20146h44v12h-44zM1378%20242h44v12h-44z%22%20fill%3D%22%233A1418%22%2F%3E%3Cpath%20d%3D%22M1400%20130v16M1400%20254v30%22%20stroke%3D%22%233A1418%22%20stroke-width%3D%226%22%2F%3E%3Cpath%20d%3D%22M1391%20284h18l-9%2028z%22%20fill%3D%22%23C9A24A%22%2F%3E%3Cellipse%20cx%3D%22520%22%20cy%3D%22400%22%20rx%3D%2250%22%20ry%3D%2264%22%20fill%3D%22url%28%23l%29%22%2F%3E%3Cellipse%20cx%3D%22520%22%20cy%3D%22400%22%20rx%3D%2230%22%20ry%3D%2241%22%20fill%3D%22%23D2453C%22%2F%3E%3Cellipse%20cx%3D%22520%22%20cy%3D%22400%22%20rx%3D%2219%22%20ry%3D%2230%22%20fill%3D%22%23F58C5A%22%2F%3E%3Cpath%20d%3D%22M504%20359h32v9h-32zM504%20432h32v9h-32z%22%20fill%3D%22%233A1418%22%2F%3E%3Cpath%20d%3D%22M520%20345v14M520%20441v22%22%20stroke%3D%22%233A1418%22%20stroke-width%3D%225%22%2F%3E%3Cellipse%20cx%3D%221080%22%20cy%3D%22400%22%20rx%3D%2250%22%20ry%3D%2264%22%20fill%3D%22url%28%23l%29%22%2F%3E%3Cellipse%20cx%3D%221080%22%20cy%3D%22400%22%20rx%3D%2230%22%20ry%3D%2241%22%20fill%3D%22%23D2453C%22%2F%3E%3Cellipse%20cx%3D%221080%22%20cy%3D%22400%22%20rx%3D%2219%22%20ry%3D%2230%22%20fill%3D%22%23F58C5A%22%2F%3E%3Cpath%20d%3D%22M1064%20359h32v9h-32zM1064%20432h32v9h-32z%22%20fill%3D%22%233A1418%22%2F%3E%3Cpath%20d%3D%22M1080%20345v14M1080%20441v22%22%20stroke%3D%22%233A1418%22%20stroke-width%3D%225%22%2F%3E%3Cellipse%20cx%3D%22700%22%20cy%3D%22560%22%20rx%3D%2236%22%20ry%3D%2246%22%20fill%3D%22url%28%23l%29%22%2F%3E%3Cellipse%20cx%3D%22700%22%20cy%3D%22560%22%20rx%3D%2221%22%20ry%3D%2229%22%20fill%3D%22%23D2453C%22%2F%3E%3Cellipse%20cx%3D%22700%22%20cy%3D%22560%22%20rx%3D%2213%22%20ry%3D%2221%22%20fill%3D%22%23F58C5A%22%2F%3E%3Cpath%20d%3D%22M689%20531h22v7h-22zM689%20582h22v7h-22z%22%20fill%3D%22%233A1418%22%2F%3E%3Cpath%20d%3D%22M700%20522v9%22%20stroke%3D%22%233A1418%22%20stroke-width%3D%224%22%2F%3E%3Cellipse%20cx%3D%22900%22%20cy%3D%22560%22%20rx%3D%2236%22%20ry%3D%2246%22%20fill%3D%22url%28%23l%29%22%2F%3E%3Cellipse%20cx%3D%22900%22%20cy%3D%22560%22%20rx%3D%2221%22%20ry%3D%2229%22%20fill%3D%22%23D2453C%22%2F%3E%3Cellipse%20cx%3D%22900%22%20cy%3D%22560%22%20rx%3D%2213%22%20ry%3D%2221%22%20fill%3D%22%23F58C5A%22%2F%3E%3Cpath%20d%3D%22M889%20531h22v7h-22zM889%20582h22v7h-22z%22%20fill%3D%22%233A1418%22%2F%3E%3Cpath%20d%3D%22M900%20522v9%22%20stroke%3D%22%233A1418%22%20stroke-width%3D%224%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M610%20560h380l290%20340H320z%22%20fill%3D%22%23241A28%22%2F%3E%3Cpath%20d%3D%22M0%20620h1600v280H0z%22%20fill%3D%22%23150E18%22%2F%3E%3Cpath%20d%3D%22M610%20560h380l290%20340H320z%22%20fill%3D%22%232A1E2E%22%2F%3E%3Cg%20fill%3D%22%23F2764F%22%20opacity%3D%22.26%22%3E%3Cellipse%20cx%3D%22200%22%20cy%3D%22700%22%20rx%3D%22120%22%20ry%3D%2242%22%2F%3E%3Cellipse%20cx%3D%221400%22%20cy%3D%22700%22%20rx%3D%22120%22%20ry%3D%2242%22%2F%3E%3Cellipse%20cx%3D%22520%22%20cy%3D%22660%22%20rx%3D%2286%22%20ry%3D%2230%22%2F%3E%3Cellipse%20cx%3D%221080%22%20cy%3D%22660%22%20rx%3D%2286%22%20ry%3D%2230%22%2F%3E%3Cellipse%20cx%3D%22700%22%20cy%3D%22628%22%20rx%3D%2258%22%20ry%3D%2220%22%2F%3E%3Cellipse%20cx%3D%22900%22%20cy%3D%22628%22%20rx%3D%2258%22%20ry%3D%2220%22%2F%3E%3Cellipse%20cx%3D%22800%22%20cy%3D%22830%22%20rx%3D%22200%22%20ry%3D%2248%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23F2764F%22%20opacity%3D%22.18%22%3E%3Cpath%20d%3D%22M172%20700q28-110%2056%200-28%20190-56%200z%22%2F%3E%3Cpath%20d%3D%22M1372%20700q28-110%2056%200-28%20190-56%200z%22%2F%3E%3Cpath%20d%3D%22M498%20660q22-80%2044%200-22%20140-44%200z%22%2F%3E%3Cpath%20d%3D%22M1058%20660q22-80%2044%200-22%20140-44%200z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%233B2A32%22%20stroke-width%3D%225%22%20opacity%3D%22.5%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M0%20660q800-26%201600%200M0%20730q800-26%201600%200M0%20806q800-26%201600%200M0%20878q800-26%201600%200%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%230E0A10%22%3E%3Cpath%20d%3D%22M776%20500q24-32%2048%200l12%2074h-72z%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22486%22%20r%3D%2218%22%2F%3E%3Cpath%20d%3D%22M742%20500q58-46%20116%200z%22%20opacity%3D%22.85%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(245,168,148,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(240,204,148,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(245,168,148,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(240,204,148,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(245,168,148,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(240,204,148,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(245,168,148,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(240,204,148,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(245,168,148,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(228,103,90,.13) 0%, rgba(12,10,18,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(224,168,90,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(228,103,90,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(228,103,90,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.55;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #0C0A12;
  --th-panneau: #1F1620;
  --th-carte: #2E2130;
  --th-fond-rgb: 12,10,18;
  --th-panneau-rgb: 31,22,32;
  --th-texte: #F3E3DA;
  --th-texte-2: #C7ABA4;
  --th-texte-3: #AE948E;
  --th-trait: 140,112,110;
  --th-accent: #E4675A;
  --th-accent-clair: #F5A894;
  --th-accent-doux: #CE8478;
  --th-accent-fort: #F08172;
  --th-accent-rgb: 228,103,90;
  --th-sur-accent: #0C0A12;
  --th-sur-plein: #111111;
  --th-second: #E0A85A;
  --th-second-clair: #F0CC94;
  --th-second-rgb: 224,168,90;
  --th-succes: #6FC28E;
  --th-alerte: #E8B95E;
  --th-danger: #F0838C;
  --th-danger-rgb: 240,131,140;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #E4675A;
  --th-logo-halo: var(--th-accent);
}

[data-theme="shinjuku"] {   /* Shinjuku */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3CradialGradient%20id%3D%22n1%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FF5FA8%22%20stop-opacity%3D%22.9%22%2F%3E%3Cstop%20offset%3D%22.42%22%20stop-color%3D%22%23E43D8C%22%20stop-opacity%3D%22.34%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23E43D8C%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3CradialGradient%20id%3D%22n2%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%237BF0F8%22%20stop-opacity%3D%22.85%22%2F%3E%3Cstop%20offset%3D%22.42%22%20stop-color%3D%22%232FD6E0%22%20stop-opacity%3D%22.3%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%232FD6E0%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3CradialGradient%20id%3D%22n3%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23B49BFF%22%20stop-opacity%3D%22.8%22%2F%3E%3Cstop%20offset%3D%22.42%22%20stop-color%3D%22%237B5CF0%22%20stop-opacity%3D%22.28%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%237B5CF0%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3CradialGradient%20id%3D%22n4%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FFE07A%22%20stop-opacity%3D%22.8%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23F2C94C%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3ClinearGradient%20id%3D%22sk%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230A0718%22%2F%3E%3Cstop%20offset%3D%22.62%22%20stop-color%3D%22%23150B24%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%230C0716%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23sk%29%22%2F%3E%3Cg%20opacity%3D%220.17%22%3E%3Cellipse%20cx%3D%22170%22%20cy%3D%22190%22%20rx%3D%22190%22%20ry%3D%22210%22%20fill%3D%22url%28%23n1%29%22%2F%3E%3Cellipse%20cx%3D%22120%22%20cy%3D%22470%22%20rx%3D%22160%22%20ry%3D%22180%22%20fill%3D%22url%28%23n2%29%22%2F%3E%3Cellipse%20cx%3D%22230%22%20cy%3D%22700%22%20rx%3D%22150%22%20ry%3D%22150%22%20fill%3D%22url%28%23n3%29%22%2F%3E%3Cellipse%20cx%3D%221440%22%20cy%3D%22200%22%20rx%3D%22180%22%20ry%3D%22200%22%20fill%3D%22url%28%23n2%29%22%2F%3E%3Cellipse%20cx%3D%221500%22%20cy%3D%22490%22%20rx%3D%22160%22%20ry%3D%22180%22%20fill%3D%22url%28%23n1%29%22%2F%3E%3Cellipse%20cx%3D%221380%22%20cy%3D%22720%22%20rx%3D%22150%22%20ry%3D%22150%22%20fill%3D%22url%28%23n4%29%22%2F%3E%3Cellipse%20cx%3D%22620%22%20cy%3D%22230%22%20rx%3D%22150%22%20ry%3D%22160%22%20fill%3D%22url%28%23n3%29%22%2F%3E%3Cellipse%20cx%3D%22990%22%20cy%3D%22250%22%20rx%3D%22150%22%20ry%3D%22160%22%20fill%3D%22url%28%23n1%29%22%2F%3E%3Cellipse%20cx%3D%22800%22%20cy%3D%22430%22%20rx%3D%22180%22%20ry%3D%22140%22%20fill%3D%22url%28%23n4%29%22%2F%3E%3Cg%20fill%3D%22%2309061A%22%20opacity%3D%22.6%22%3E%3Cpath%20d%3D%22M0%200h260v640H0zM300%2040h180v600H300zM1120%2040h180v600h-180zM1340%200h260v640h-260z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%230C0820%22%20opacity%3D%22.45%22%3E%3Cpath%20d%3D%22M520%20120h240v520H520zM840%20120h240v520H840z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23FF7DBB%22%20stroke-width%3D%2210%22%20fill%3D%22none%22%20opacity%3D%22.55%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M60%20130q50-46%20100%200t100%200%22%2F%3E%3Cpath%20d%3D%22M50%20210h210M90%20270h140%22%2F%3E%3Cpath%20d%3D%22M60%20400q40%2050%200%20100M140%20400q60%2040%200%20100M220%20400q30%2060%200%20100%22%2F%3E%3Cpath%20d%3D%22M70%20620q60-40%20120%200t100-10%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%237BF0F8%22%20stroke-width%3D%229%22%20fill%3D%22none%22%20opacity%3D%22.5%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M1360%20140q46%2054%200%20108t0%2096%22%2F%3E%3Cpath%20d%3D%22M1470%20150q-40%2066%200%20130%22%2F%3E%3Cpath%20d%3D%22M1350%20420h200M1380%20480h150M1400%20540h110%22%2F%3E%3Cpath%20d%3D%22M1330%20660q70-44%20140%200%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23C3AEFF%22%20stroke-width%3D%229%22%20fill%3D%22none%22%20opacity%3D%22.45%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M560%20180q70-34%20140%200M580%20250q60%2034%20120%200M600%20320h100M920%20180q70-34%20140%200M940%20250q60%2034%20120%200M960%20320h100%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23FFE9A0%22%20stroke-width%3D%227%22%20fill%3D%22none%22%20opacity%3D%22.4%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M700%20430q100-36%20200%200M730%20490h140%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23FFE9A0%22%20opacity%3D%22.45%22%3E%3Ccircle%20cx%3D%22380%22%20cy%3D%22120%22%20r%3D%229%22%2F%3E%3Ccircle%20cx%3D%22430%22%20cy%3D%22180%22%20r%3D%227%22%2F%3E%3Ccircle%20cx%3D%22360%22%20cy%3D%22250%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22450%22%20cy%3D%22330%22%20r%3D%228%22%2F%3E%3Ccircle%20cx%3D%22390%22%20cy%3D%22430%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22440%22%20cy%3D%22520%22%20r%3D%227%22%2F%3E%3Ccircle%20cx%3D%221150%22%20cy%3D%22130%22%20r%3D%228%22%2F%3E%3Ccircle%20cx%3D%221210%22%20cy%3D%22200%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%221140%22%20cy%3D%22290%22%20r%3D%227%22%2F%3E%3Ccircle%20cx%3D%221220%22%20cy%3D%22380%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%221160%22%20cy%3D%22480%22%20r%3D%228%22%2F%3E%3Ccircle%20cx%3D%221210%22%20cy%3D%22560%22%20r%3D%226%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20640h1600v260H0z%22%20fill%3D%22%23090614%22%2F%3E%3Cg%20fill%3D%22%23E43D8C%22%20opacity%3D%22.2%22%3E%3Cellipse%20cx%3D%22170%22%20cy%3D%22700%22%20rx%3D%22200%22%20ry%3D%2246%22%2F%3E%3Cellipse%20cx%3D%221500%22%20cy%3D%22720%22%20rx%3D%22180%22%20ry%3D%2242%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%232FD6E0%22%20opacity%3D%22.18%22%3E%3Cellipse%20cx%3D%22120%22%20cy%3D%22800%22%20rx%3D%22180%22%20ry%3D%2242%22%2F%3E%3Cellipse%20cx%3D%221440%22%20cy%3D%22690%22%20rx%3D%22190%22%20ry%3D%2244%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%237B5CF0%22%20opacity%3D%22.18%22%3E%3Cellipse%20cx%3D%22620%22%20cy%3D%22710%22%20rx%3D%22180%22%20ry%3D%2242%22%2F%3E%3Cellipse%20cx%3D%22230%22%20cy%3D%22870%22%20rx%3D%22160%22%20ry%3D%2236%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23F2C94C%22%20opacity%3D%22.15%22%3E%3Cellipse%20cx%3D%22900%22%20cy%3D%22770%22%20rx%3D%22220%22%20ry%3D%2248%22%2F%3E%3Cellipse%20cx%3D%221300%22%20cy%3D%22860%22%20rx%3D%22180%22%20ry%3D%2238%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%230F0C1E%22%20opacity%3D%22.9%22%3E%3Cpath%20d%3D%22M300%20690q-84-100%200-114t84%20114z%22%2F%3E%3Cpath%20d%3D%22M342%20694v104%22%20stroke%3D%22%230F0C1E%22%20stroke-width%3D%228%22%2F%3E%3Cpath%20d%3D%22M328%20798q16%2040%200%2070h30q-16-30%200-70z%22%2F%3E%3Cpath%20d%3D%22M560%20720q-70-84%200-96t70%2096z%22%2F%3E%3Cpath%20d%3D%22M595%20724v92%22%20stroke%3D%22%230F0C1E%22%20stroke-width%3D%227%22%2F%3E%3Cpath%20d%3D%22M583%20816q14%2034%200%2060h26q-14-26%200-60z%22%2F%3E%3Cpath%20d%3D%22M1020%20700q-76-92%200-104t76%20104z%22%2F%3E%3Cpath%20d%3D%22M1058%20704v100%22%20stroke%3D%22%230F0C1E%22%20stroke-width%3D%228%22%2F%3E%3Cpath%20d%3D%22M1045%20804q15%2036%200%2066h28q-15-28%200-66z%22%2F%3E%3Cpath%20d%3D%22M1260%20730q-62-74%200-86t62%2086z%22%2F%3E%3Cpath%20d%3D%22M1291%20734v84%22%20stroke%3D%22%230F0C1E%22%20stroke-width%3D%226%22%2F%3E%3Cpath%20d%3D%22M1280%20818q12%2030%200%2054h24q-12-24%200-54z%22%2F%3E%3Cpath%20d%3D%22M810%20748q-56-68%200-78t56%2078z%22%2F%3E%3Cpath%20d%3D%22M838%20752v76%22%20stroke%3D%22%230F0C1E%22%20stroke-width%3D%226%22%2F%3E%3Cpath%20d%3D%22M828%20828q11%2028%200%2048h22q-11-20%200-48z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23CFE3F2%22%20stroke-width%3D%222.5%22%20opacity%3D%22.17%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M60%200l-56%20900M180%200l-56%20900M300%200l-56%20900M420%200l-56%20900M540%200l-56%20900M660%200l-56%20900M780%200l-56%20900M900%200l-56%20900M1020%200l-56%20900M1140%200l-56%20900M1260%200l-56%20900M1380%200l-56%20900M1500%200l-56%20900M1620%200l-56%20900%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23CFE3F2%22%20stroke-width%3D%222%22%20opacity%3D%22.1%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M120%200l-40%20900M360%200l-40%20900M600%200l-40%20900M840%200l-40%20900M1080%200l-40%20900M1320%200l-40%20900M1560%200l-40%20900%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(251,168,206,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(162,236,242,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(251,168,206,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(162,236,242,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(251,168,206,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(162,236,242,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(251,168,206,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(162,236,242,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(251,168,206,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(240,98,166,.13) 0%, rgba(8,6,20,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(79,216,226,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(240,98,166,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(240,98,166,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.6;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #080614;
  --th-panneau: #150F28;
  --th-carte: #211838;
  --th-fond-rgb: 8,6,20;
  --th-panneau-rgb: 21,15,40;
  --th-texte: #EFE6F8;
  --th-texte-2: #B9A8CE;
  --th-texte-3: #9E8CB6;
  --th-trait: 128,110,158;
  --th-accent: #F062A6;
  --th-accent-clair: #FBA8CE;
  --th-accent-doux: #D287B0;
  --th-accent-fort: #FA80BA;
  --th-accent-rgb: 240,98,166;
  --th-sur-accent: #080614;
  --th-sur-plein: #111111;
  --th-second: #4FD8E2;
  --th-second-clair: #A2ECF2;
  --th-second-rgb: 79,216,226;
  --th-succes: #5ED8B0;
  --th-alerte: #F2C94C;
  --th-danger: #FF7C8E;
  --th-danger-rgb: 255,124,142;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #F062A6;
  --th-logo-halo: var(--th-accent);
}

[data-theme="cyclades"] {   /* Cyclades */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23BEDBEF%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23EEF6FA%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.24%22%3E%3Ccircle%20cx%3D%221350%22%20cy%3D%22160%22%20r%3D%2274%22%20fill%3D%22%23FBEFC9%22%2F%3E%3Cpath%20d%3D%22M0%20580h1600v320H0z%22%20fill%3D%22%232E7FB2%22%2F%3E%3Cpath%20d%3D%22M0%20580h1600v110H0z%22%20fill%3D%22%233F98C7%22%2F%3E%3Cg%20stroke%3D%22%23EAF4FA%22%20stroke-width%3D%225%22%20opacity%3D%22.45%22%3E%3Cpath%20d%3D%22M100%20640h200M480%20700h270M940%20660h240M1270%20760h250M300%20810h360M760%20850h420%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23FCFCFA%22%3E%3Cpath%20d%3D%22M60%20380h210v200H60zM290%20320h170v260H290zM480%20410h150v170H480zM660%20350h200v230H660zM890%20430h140v150H890zM1060%20360h190v220h-190zM1280%20440h170v140h-170z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23E2E7E2%22%3E%3Cpath%20d%3D%22M60%20380h210v18H60zM290%20320h170v18H290zM660%20350h200v18H660zM1060%20360h190v18h-190z%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M290%20320a85%2062%200%2001170%200z%22%20fill%3D%22%231E6FA8%22%2F%3E%3Cpath%20d%3D%22M660%20350a100%2072%200%2001200%200z%22%20fill%3D%22%231E6FA8%22%2F%3E%3Cpath%20d%3D%22M1060%20360a95%2068%200%2001190%200z%22%20fill%3D%22%232A83BE%22%2F%3E%3Cg%20fill%3D%22%231E6FA8%22%3E%3Cpath%20d%3D%22M120%20460h36v52h-36zM200%20460h36v52h-36zM530%20470h36v52h-36zM930%20490h34v50h-34zM1330%20490h34v50h-34zM1390%20490h34v50h-34zM720%20470h36v52h-36zM800%20470h36v52h-36z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23C4CFC7%22%20stroke-width%3D%227%22%3E%3Cpath%20d%3D%22M480%20410v-90M556%20320h-152M518%20320v50%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23D8A0B4%22%20opacity%3D%22.8%22%3E%3Ccircle%20cx%3D%22352%22%20cy%3D%22530%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%22392%22%20cy%3D%22552%22%20r%3D%2217%22%2F%3E%3Ccircle%20cx%3D%22322%22%20cy%3D%22558%22%20r%3D%2215%22%2F%3E%3Ccircle%20cx%3D%221198%22%20cy%3D%22520%22%20r%3D%2220%22%2F%3E%3Ccircle%20cx%3D%221236%22%20cy%3D%22546%22%20r%3D%2216%22%2F%3E%3Ccircle%20cx%3D%221166%22%20cy%3D%22552%22%20r%3D%2214%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23FCFCFA%22%20opacity%3D%22.9%22%3E%3Cpath%20d%3D%22M0%20560h1600v22H0z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(11,68,104,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(122,52,80,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(11,68,104,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(122,52,80,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(11,68,104,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(122,52,80,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(11,68,104,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(122,52,80,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(11,68,104,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(18,96,143,.13) 0%, rgba(238,245,250,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(158,74,102,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(18,96,143,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(18,96,143,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.4;
  --th-surface-force: 2.0;
  --th-voile: 0,0,0;
  --th-ombre: 0,0,0;
  --th-fond: #EEF5FA;
  --th-panneau: #FAFCFE;
  --th-carte: #FFFFFF;
  --th-fond-rgb: 238,245,250;
  --th-panneau-rgb: 250,252,254;
  --th-texte: #12303F;
  --th-texte-2: #33505F;
  --th-texte-3: #405A6A;
  --th-trait: 120,148,166;
  --th-accent: #12608F;
  --th-accent-clair: #0B4468;
  --th-accent-doux: #3A7CA5;
  --th-accent-fort: #0E5480;
  --th-accent-rgb: 18,96,143;
  --th-sur-accent: #FFFFFF;
  --th-sur-plein: #FFFFFF;
  --th-second: #9E4A66;
  --th-second-clair: #7A3450;
  --th-second-rgb: 158,74,102;
  --th-succes: #1F6448;
  --th-alerte: #7A5008;
  --th-danger: #9C2C34;
  --th-danger-rgb: 156,44,52;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 8px;
  --th-rayon-sm: 10px;
  --th-rayon-md: 12px;
  --th-rayon-lg: 14px;
  --th-rayon-carte: 16px;
  --th-rayon-panneau: 22px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #12608F;
  --th-logo-halo: var(--th-accent);
}

[data-theme="medina"] {   /* Médina */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23E7B679%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23F7E0BD%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.21%22%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22300%22%20r%3D%22130%22%20fill%3D%22%23F9DCA6%22%20opacity%3D%22.8%22%2F%3E%3Cg%20fill%3D%22%23B65A34%22%3E%3Cpath%20d%3D%22M60%20900V560a110%20110%200%2001220%200v340zM440%20900V520a120%20120%200%2001240%200v380zM880%20900V520a120%20120%200%2001240%200v380zM1300%20900V560a110%20110%200%2001220%200v340z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%237C3A22%22%3E%3Cpath%20d%3D%22M100%20900V620a70%2070%200%2001140%200v280zM480%20900V590a80%2080%200%2001160%200v310zM920%20900V590a80%2080%200%2001160%200v310zM1340%20900V620a70%2070%200%2001140%200v280z%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20748h1600v40H0z%22%20fill%3D%22%238E4526%22%2F%3E%3Cg%20fill%3D%22%23E0A94E%22%3E%3Cpath%20d%3D%22M20%20768l30-30%2030%2030-30%2030zM140%20768l30-30%2030%2030-30%2030zM260%20768l30-30%2030%2030-30%2030zM380%20768l30-30%2030%2030-30%2030zM500%20768l30-30%2030%2030-30%2030zM620%20768l30-30%2030%2030-30%2030zM740%20768l30-30%2030%2030-30%2030zM860%20768l30-30%2030%2030-30%2030zM980%20768l30-30%2030%2030-30%2030zM1100%20768l30-30%2030%2030-30%2030zM1220%20768l30-30%2030%2030-30%2030zM1340%20768l30-30%2030%2030-30%2030zM1460%20768l30-30%2030%2030-30%2030zM1580%20768l30-30%2030%2030-30%2030z%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20788h1600v112H0z%22%20fill%3D%22%23A8552F%22%2F%3E%3Cg%20stroke%3D%22%233E5B34%22%20stroke-width%3D%2216%22%20fill%3D%22none%22%20stroke-linecap%3D%22round%22%3E%3Cpath%20d%3D%22M340%20900V620M1240%20900V660%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%233E5B34%22%3E%3Cpath%20d%3D%22M340%20620q-110-40-130-120%2090%2010%20130%2080zM340%20620q110-40%20130-120-90%2010-130%2080zM340%20640q-100%2010-150-40%2080-30%20150%2010zM340%20640q100%2010%20150-40-80-30-150%2010zM1240%20660q-90-30-110-100%2076%2010%20110%2066zM1240%20660q90-30%20110-100-76%2010-110%2066zM1240%20678q-80%2010-120-30%2066-24%20120%208zM1240%20678q80%2010%20120-30-66-24-120%208z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%237C3A22%22%20opacity%3D%22.5%22%3E%3Ccircle%20cx%3D%22170%22%20cy%3D%22700%22%20r%3D%2216%22%2F%3E%3Ccircle%20cx%3D%22560%22%20cy%3D%22680%22%20r%3D%2218%22%2F%3E%3Ccircle%20cx%3D%221000%22%20cy%3D%22680%22%20r%3D%2218%22%2F%3E%3Ccircle%20cx%3D%221410%22%20cy%3D%22700%22%20r%3D%2216%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(94,38,16,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(58,76,40,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(94,38,16,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(58,76,40,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(94,38,16,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(58,76,40,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(94,38,16,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(58,76,40,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(94,38,16,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(166,75,36,.13) 0%, rgba(246,222,186,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(78,100,56,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(166,75,36,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(166,75,36,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.46;
  --th-surface-force: 2.3;
  --th-voile: 0,0,0;
  --th-ombre: 0,0,0;
  --th-fond: #F6DEBA;
  --th-panneau: #FCEFD8;
  --th-carte: #FFF8EA;
  --th-fond-rgb: 246,222,186;
  --th-panneau-rgb: 252,239,216;
  --th-texte: #3A1E10;
  --th-texte-2: #603520;
  --th-texte-3: #66391F;
  --th-trait: 170,134,98;
  --th-accent: #A64B24;
  --th-accent-clair: #5E2610;
  --th-accent-doux: #A85830;
  --th-accent-fort: #8E3C1A;
  --th-accent-rgb: 166,75,36;
  --th-sur-accent: #FFFFFF;
  --th-sur-plein: #FFFFFF;
  --th-second: #4E6438;
  --th-second-clair: #3A4C28;
  --th-second-rgb: 78,100,56;
  --th-succes: #3A6030;
  --th-alerte: #7A5006;
  --th-danger: #98281E;
  --th-danger-rgb: 152,40,30;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 8px;
  --th-rayon-sm: 10px;
  --th-rayon-md: 12px;
  --th-rayon-lg: 14px;
  --th-rayon-carte: 16px;
  --th-rayon-panneau: 22px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #A64B24;
  --th-logo-halo: var(--th-accent);
}

[data-theme="velours"] {   /* Velours */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22%2313251E%22%2F%3E%3Cg%20opacity%3D%220.20%22%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22%230D1A15%22%20opacity%3D%22.35%22%2F%3E%3Cg%20stroke%3D%22%231D362B%22%20stroke-width%3D%226%22%20opacity%3D%22.8%22%3E%3Cpath%20d%3D%22M200%200v900M400%200v900M600%200v900M1000%200v900M1200%200v900M1400%200v900%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M680%20840V350a120%20120%200%2001240%200v490z%22%20fill%3D%22%230A1626%22%2F%3E%3Cg%20fill%3D%22%23F0E0B0%22%20opacity%3D%22.75%22%3E%3Ccircle%20cx%3D%22750%22%20cy%3D%22300%22%20r%3D%227%22%2F%3E%3Ccircle%20cx%3D%22850%22%20cy%3D%22260%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22390%22%20r%3D%227%22%2F%3E%3Ccircle%20cx%3D%22730%22%20cy%3D%22480%22%20r%3D%225%22%2F%3E%3Ccircle%20cx%3D%22870%22%20cy%3D%22440%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22780%22%20cy%3D%22560%22%20r%3D%226%22%2F%3E%3Ccircle%20cx%3D%22840%22%20cy%3D%22640%22%20r%3D%225%22%2F%3E%3Ccircle%20cx%3D%22710%22%20cy%3D%22620%22%20r%3D%224%22%2F%3E%3C%2Fg%3E%3Ccircle%20cx%3D%22862%22%20cy%3D%22330%22%20r%3D%2234%22%20fill%3D%22%23F3E6BC%22%20opacity%3D%22.62%22%2F%3E%3Cg%20stroke%3D%22%23B8913F%22%20stroke-width%3D%2213%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M680%20840V350a120%20120%200%2001240%200v490%22%2F%3E%3Cpath%20d%3D%22M800%20230v610M680%20540h240%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M480%20900V280q0-50%2050-50h30v670z%22%20fill%3D%22%233E2038%22%2F%3E%3Cpath%20d%3D%22M1120%20900V280q0-50-50-50h-30v670z%22%20fill%3D%22%233E2038%22%2F%3E%3Cpath%20d%3D%22M480%20900V280q0-50%2050-50h30v670z%22%20fill%3D%22%2354294A%22%20opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M1120%20900V280q0-50-50-50h-30v670z%22%20fill%3D%22%2354294A%22%20opacity%3D%22.5%22%2F%3E%3Cg%20stroke%3D%22%232C1728%22%20stroke-width%3D%225%22%20opacity%3D%22.65%22%3E%3Cpath%20d%3D%22M510%20230v670M534%20236v664M1090%20230v670M1066%20236v664%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20840h1600v60H0z%22%20fill%3D%22%23091310%22%2F%3E%3Cg%20stroke%3D%22%23B8913F%22%20stroke-width%3D%228%22%20fill%3D%22none%22%20opacity%3D%22.5%22%3E%3Cpath%20d%3D%22M110%20660h220M110%20660v-40M330%20660v-40M220%20660V550%22%2F%3E%3Ccircle%20cx%3D%22220%22%20cy%3D%22524%22%20r%3D%2226%22%2F%3E%3Cpath%20d%3D%22M1270%20660h220M1270%20660v-40M1490%20660v-40M1380%20660V550%22%2F%3E%3Ccircle%20cx%3D%221380%22%20cy%3D%22524%22%20r%3D%2226%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23F3E6BC%22%20opacity%3D%22.18%22%3E%3Ccircle%20cx%3D%22220%22%20cy%3D%22524%22%20r%3D%2270%22%2F%3E%3Ccircle%20cx%3D%221380%22%20cy%3D%22524%22%20r%3D%2270%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(232,206,146,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(199,154,190,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(232,206,146,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(199,154,190,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(232,206,146,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(199,154,190,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(232,206,146,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(199,154,190,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(232,206,146,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(201,161,85,.13) 0%, rgba(16,31,26,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(160,110,150,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(201,161,85,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(201,161,85,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.5;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #101F1A;
  --th-panneau: #1A3029;
  --th-carte: #244036;
  --th-fond-rgb: 16,31,26;
  --th-panneau-rgb: 26,48,41;
  --th-texte: #EDE6D2;
  --th-texte-2: #BDB49B;
  --th-texte-3: #A49B84;
  --th-trait: 140,138,112;
  --th-accent: #C9A155;
  --th-accent-clair: #E8CE92;
  --th-accent-doux: #B08F52;
  --th-accent-fort: #DCB86E;
  --th-accent-rgb: 201,161,85;
  --th-sur-accent: #101F1A;
  --th-sur-plein: #111111;
  --th-second: #A06E96;
  --th-second-clair: #C79ABE;
  --th-second-rgb: 160,110,150;
  --th-succes: #6FC095;
  --th-alerte: #DDB868;
  --th-danger: #E88C8C;
  --th-danger-rgb: 232,140,140;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #C9A155;
  --th-logo-halo: var(--th-accent);
}

[data-theme="marbre"] {   /* Marbre */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2304050A%22%2F%3E%3Cstop%20offset%3D%22.46%22%20stop-color%3D%22%230B0D13%22%2F%3E%3Cstop%20offset%3D%22.78%22%20stop-color%3D%22%2314171E%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%231E222A%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22c%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%221%22%20y2%3D%220%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%2323262D%22%2F%3E%3Cstop%20offset%3D%22.38%22%20stop-color%3D%22%237A818D%22%2F%3E%3Cstop%20offset%3D%22.64%22%20stop-color%3D%22%234E545E%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%231E2128%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22s%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23161A21%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23070910%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22m%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23F5E3B4%22%20stop-opacity%3D%22.8%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23D9B063%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.2%22%3E%3Cellipse%20cx%3D%22800%22%20cy%3D%22150%22%20rx%3D%22300%22%20ry%3D%22240%22%20fill%3D%22url%28%23m%29%22%20opacity%3D%22.5%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22146%22%20r%3D%2246%22%20fill%3D%22%23F2DDA8%22%20opacity%3D%22.7%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22146%22%20r%3D%22104%22%20fill%3D%22%23F2DDA8%22%20opacity%3D%22.08%22%2F%3E%3Cg%20fill%3D%22%23C6CBD3%22%3E%3Ccircle%20cx%3D%22250%22%20cy%3D%22118%22%20r%3D%223%22%20opacity%3D%22.4%22%2F%3E%3Ccircle%20cx%3D%22520%22%20cy%3D%2280%22%20r%3D%222.4%22%20opacity%3D%22.3%22%2F%3E%3Ccircle%20cx%3D%221118%22%20cy%3D%22108%22%20r%3D%222.8%22%20opacity%3D%22.38%22%2F%3E%3Ccircle%20cx%3D%221372%22%20cy%3D%2270%22%20r%3D%222.4%22%20opacity%3D%22.3%22%2F%3E%3Ccircle%20cx%3D%22980%22%20cy%3D%22178%22%20r%3D%222%22%20opacity%3D%22.26%22%2F%3E%3Ccircle%20cx%3D%22380%22%20cy%3D%22222%22%20r%3D%222%22%20opacity%3D%22.24%22%2F%3E%3Ccircle%20cx%3D%22660%22%20cy%3D%22150%22%20r%3D%221.8%22%20opacity%3D%22.22%22%2F%3E%3Ccircle%20cx%3D%221240%22%20cy%3D%22240%22%20r%3D%221.8%22%20opacity%3D%22.22%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20620h1600v280H0z%22%20fill%3D%22url%28%23s%29%22%2F%3E%3Cpath%20d%3D%22M800%20620L1600%20764v136H800z%22%20fill%3D%22%2312151C%22%20opacity%3D%22.55%22%2F%3E%3Cpath%20d%3D%22M800%20620L0%20764v136h800z%22%20fill%3D%22%230F1218%22%20opacity%3D%22.55%22%2F%3E%3Cg%20stroke%3D%22%23C6CBD3%22%20stroke-width%3D%222%22%20fill%3D%22none%22%20opacity%3D%22.07%22%3E%3Cpath%20d%3D%22M800%20620L96%20900M800%20620L392%20900M800%20620L1208%20900M800%20620L1504%20900%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23C6CBD3%22%20stroke-width%3D%222%22%20fill%3D%22none%22%20opacity%3D%22.12%22%3E%3Cpath%20d%3D%22M0%20686h1600M0%20754h1600M0%20838h1600%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M764%20620h72l46%20280h-164z%22%20fill%3D%22%23F2DDA8%22%20opacity%3D%22.1%22%2F%3E%3Cpath%20d%3D%22M0%20614h1600v10H0z%22%20fill%3D%22%23C6CBD3%22%20opacity%3D%22.1%22%2F%3E%3Cg%3E%3Crect%20x%3D%2246%22%20y%3D%22146%22%20width%3D%22120%22%20height%3D%22474%22%20fill%3D%22url%28%23c%29%22%2F%3E%3Crect%20x%3D%22232%22%20y%3D%22184%22%20width%3D%2298%22%20height%3D%22436%22%20fill%3D%22url%28%23c%29%22%20opacity%3D%22.88%22%2F%3E%3Crect%20x%3D%221270%22%20y%3D%22184%22%20width%3D%2298%22%20height%3D%22436%22%20fill%3D%22url%28%23c%29%22%20opacity%3D%22.88%22%2F%3E%3Crect%20x%3D%221434%22%20y%3D%22146%22%20width%3D%22120%22%20height%3D%22474%22%20fill%3D%22url%28%23c%29%22%2F%3E%3Cg%20fill%3D%22%23868D98%22%20opacity%3D%22.5%22%3E%3Crect%20x%3D%2230%22%20y%3D%22114%22%20width%3D%22152%22%20height%3D%2234%22%2F%3E%3Crect%20x%3D%22218%22%20y%3D%22156%22%20width%3D%22126%22%20height%3D%2230%22%2F%3E%3Crect%20x%3D%221256%22%20y%3D%22156%22%20width%3D%22126%22%20height%3D%2230%22%2F%3E%3Crect%20x%3D%221418%22%20y%3D%22114%22%20width%3D%22152%22%20height%3D%2234%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%235A606A%22%20opacity%3D%22.46%22%3E%3Crect%20x%3D%2230%22%20y%3D%22602%22%20width%3D%22152%22%20height%3D%2226%22%2F%3E%3Crect%20x%3D%22218%22%20y%3D%22600%22%20width%3D%22126%22%20height%3D%2222%22%2F%3E%3Crect%20x%3D%221256%22%20y%3D%22600%22%20width%3D%22126%22%20height%3D%2222%22%2F%3E%3Crect%20x%3D%221418%22%20y%3D%22602%22%20width%3D%22152%22%20height%3D%2226%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23EAEDF1%22%20stroke-width%3D%222.5%22%20fill%3D%22none%22%20opacity%3D%22.18%22%3E%3Cpath%20d%3D%22M84%20156q24%2092-4%20182t16%20200%22%2F%3E%3Cpath%20d%3D%22M132%20168q-18%20122%208%20222t-8%20198%22%2F%3E%3Cpath%20d%3D%22M266%20194q20%20100-6%20190t12%20190%22%2F%3E%3Cpath%20d%3D%22M310%20202q-12%20108%206%20198t-10%20186%22%2F%3E%3Cpath%20d%3D%22M1300%20194q-16%20110%206%20200t-8%20180%22%2F%3E%3Cpath%20d%3D%22M1344%20204q14%2096-8%20188t10%20192%22%2F%3E%3Cpath%20d%3D%22M1470%20156q22%2096-6%20186t14%20194%22%2F%3E%3Cpath%20d%3D%22M1518%20170q-16%20116%206%20214t-4%20194%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23C6CBD3%22%20stroke-width%3D%221.6%22%20fill%3D%22none%22%20opacity%3D%22.1%22%3E%3Cpath%20d%3D%22M108%20150v470M290%20188v432M1322%20188v432M1496%20150v470%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%236E7480%22%20stroke-width%3D%229%22%20fill%3D%22none%22%20opacity%3D%22.3%22%3E%3Cpath%20d%3D%22M106%20150q112-92%20224%200%22%2F%3E%3Cpath%20d%3D%22M1322%20150q112-92%20224%200%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%2092h1600v26H0z%22%20fill%3D%22%23D9B063%22%20opacity%3D%22.26%22%2F%3E%3Cpath%20d%3D%22M0%20126h1600v5H0z%22%20fill%3D%22%23F2DDA8%22%20opacity%3D%22.2%22%2F%3E%3Cg%20fill%3D%22%23D9B063%22%20opacity%3D%22.22%22%3E%3Cpath%20d%3D%22M106%2054l26%2038H80zM1494%2054l26%2038h-52zM800%2038l32%2054h-64z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23D9B063%22%20stroke-width%3D%223%22%20fill%3D%22none%22%20opacity%3D%22.16%22%3E%3Cpath%20d%3D%22M300%2078h1000M360%2062h880%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(242,221,168,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(199,205,214,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(242,221,168,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(199,205,214,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(242,221,168,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(199,205,214,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(242,221,168,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(199,205,214,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(242,221,168,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(217,176,99,.13) 0%, rgba(7,8,10,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(154,161,172,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(217,176,99,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(217,176,99,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.5;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #07080A;
  --th-panneau: #101318;
  --th-carte: #171B21;
  --th-fond-rgb: 7,8,10;
  --th-panneau-rgb: 16,19,24;
  --th-texte: #ECEAE5;
  --th-texte-2: #B9BEC7;
  --th-texte-3: #9AA1AC;
  --th-trait: 150,156,166;
  --th-accent: #D9B063;
  --th-accent-clair: #F2DDA8;
  --th-accent-doux: #B8934F;
  --th-accent-fort: #E8C87E;
  --th-accent-rgb: 217,176,99;
  --th-sur-accent: #07080A;
  --th-sur-plein: #111111;
  --th-second: #9AA1AC;
  --th-second-clair: #C7CDD6;
  --th-second-rgb: 154,161,172;
  --th-succes: #6BC49B;
  --th-alerte: #E0BE74;
  --th-danger: #E88F8A;
  --th-danger-rgb: 232,143,138;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #D9B063;
  --th-logo-halo: var(--th-accent);
}

[data-theme="brume"] {   /* Brume */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23070809%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23111316%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2322262B%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22e%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%231B1F24%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%230A0C0E%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.22%22%3E%3Cpath%20d%3D%22M0%20900V520h1600v380z%22%20fill%3D%22url%28%23e%29%22%2F%3E%3Cpath%20d%3D%22M0%20508h1600v14H0z%22%20fill%3D%22%237E858F%22%20opacity%3D%22.5%22%2F%3E%3Cg%20fill%3D%22%235B626B%22%20opacity%3D%22.55%22%3E%3Crect%20x%3D%22352%22%20y%3D%22150%22%20width%3D%2234%22%20height%3D%22360%22%2F%3E%3Crect%20x%3D%22416%22%20y%3D%22150%22%20width%3D%2234%22%20height%3D%22360%22%2F%3E%3Crect%20x%3D%221150%22%20y%3D%22150%22%20width%3D%2234%22%20height%3D%22360%22%2F%3E%3Crect%20x%3D%221214%22%20y%3D%22150%22%20width%3D%2234%22%20height%3D%22360%22%2F%3E%3Crect%20x%3D%22340%22%20y%3D%22236%22%20width%3D%22122%22%20height%3D%2216%22%2F%3E%3Crect%20x%3D%221138%22%20y%3D%22236%22%20width%3D%22122%22%20height%3D%2216%22%2F%3E%3Crect%20x%3D%22340%22%20y%3D%22150%22%20width%3D%22122%22%20height%3D%2218%22%2F%3E%3Crect%20x%3D%221138%22%20y%3D%22150%22%20width%3D%22122%22%20height%3D%2218%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%238A9199%22%20stroke-width%3D%225%22%20fill%3D%22none%22%20opacity%3D%22.42%22%3E%3Cpath%20d%3D%22M0%20300q200%2060%20402%20-132M402%20168q396%20300%20794%200M1196%20168q200%20192%20404%20132%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%238A9199%22%20stroke-width%3D%222%22%20opacity%3D%22.22%22%3E%3Cpath%20d%3D%22M120%20340v168M240%20372v136M540%20300v208M700%20400v108M900%20400v108M1060%20300v208M1360%20372v136M1480%20340v168%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23C6CBD3%22%3E%3Crect%20y%3D%22430%22%20width%3D%221600%22%20height%3D%2290%22%20opacity%3D%22.07%22%2F%3E%3Crect%20y%3D%22330%22%20width%3D%221600%22%20height%3D%2260%22%20opacity%3D%22.05%22%2F%3E%3Crect%20y%3D%22560%22%20width%3D%221600%22%20height%3D%22120%22%20opacity%3D%22.06%22%2F%3E%3Crect%20y%3D%22700%22%20width%3D%221600%22%20height%3D%22160%22%20opacity%3D%22.05%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23E4E7EB%22%20opacity%3D%22.05%22%3E%3Cellipse%20cx%3D%22300%22%20cy%3D%22470%22%20rx%3D%22420%22%20ry%3D%2270%22%2F%3E%3Cellipse%20cx%3D%221250%22%20cy%3D%22500%22%20rx%3D%22460%22%20ry%3D%2280%22%2F%3E%3Cellipse%20cx%3D%22800%22%20cy%3D%22620%22%20rx%3D%22560%22%20ry%3D%2290%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%23C6CBD3%22%20stroke-width%3D%222%22%20opacity%3D%22.1%22%3E%3Cpath%20d%3D%22M0%20640h1600M0%20720h1600M0%20812h1600%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(228,231,235,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(170,177,186,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(228,231,235,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(170,177,186,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(228,231,235,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(170,177,186,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(228,231,235,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(170,177,186,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(228,231,235,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(194,199,206,.13) 0%, rgba(11,12,14,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(126,133,143,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(194,199,206,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(194,199,206,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.45;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #0B0C0E;
  --th-panneau: #14161A;
  --th-carte: #1B1E23;
  --th-fond-rgb: 11,12,14;
  --th-panneau-rgb: 20,22,26;
  --th-texte: #E9EBEE;
  --th-texte-2: #B5BAC1;
  --th-texte-3: #969CA5;
  --th-trait: 150,156,166;
  --th-accent: #C2C7CE;
  --th-accent-clair: #E4E7EB;
  --th-accent-doux: #989EA7;
  --th-accent-fort: #D6DAE0;
  --th-accent-rgb: 194,199,206;
  --th-sur-accent: #0B0C0E;
  --th-sur-plein: #111111;
  --th-second: #7E858F;
  --th-second-clair: #AAB1BA;
  --th-second-rgb: 126,133,143;
  --th-succes: #7FC0A0;
  --th-alerte: #D8C07E;
  --th-danger: #DE9490;
  --th-danger-rgb: 222,148,144;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #C2C7CE;
  --th-logo-halo: var(--th-accent);
}

[data-theme="lavande"] {   /* Lavande */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%230B0716%22%2F%3E%3Cstop%20offset%3D%22.38%22%20stop-color%3D%22%231A0E2E%22%2F%3E%3Cstop%20offset%3D%22.62%22%20stop-color%3D%22%232E1A46%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%233C2450%22%2F%3E%3C%2FlinearGradient%3E%3CradialGradient%20id%3D%22s%22%20cx%3D%22.5%22%20cy%3D%22.5%22%20r%3D%22.5%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23F3C9A8%22%20stop-opacity%3D%22.7%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23A472F0%22%20stop-opacity%3D%220%22%2F%3E%3C%2FradialGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.26%22%3E%3Cellipse%20cx%3D%22800%22%20cy%3D%22470%22%20rx%3D%22420%22%20ry%3D%22200%22%20fill%3D%22url%28%23s%29%22%20opacity%3D%22.5%22%2F%3E%3Ccircle%20cx%3D%22800%22%20cy%3D%22474%22%20r%3D%2240%22%20fill%3D%22%23F6D8B4%22%20opacity%3D%22.55%22%2F%3E%3Cg%20fill%3D%22%23D9C7F2%22%3E%3Ccircle%20cx%3D%22220%22%20cy%3D%22110%22%20r%3D%222.6%22%20opacity%3D%22.4%22%2F%3E%3Ccircle%20cx%3D%22560%22%20cy%3D%2270%22%20r%3D%222%22%20opacity%3D%22.3%22%2F%3E%3Ccircle%20cx%3D%221080%22%20cy%3D%22120%22%20r%3D%222.4%22%20opacity%3D%22.35%22%2F%3E%3Ccircle%20cx%3D%221400%22%20cy%3D%2280%22%20r%3D%222%22%20opacity%3D%22.3%22%2F%3E%3Ccircle%20cx%3D%22900%22%20cy%3D%22180%22%20r%3D%221.8%22%20opacity%3D%22.25%22%2F%3E%3Ccircle%20cx%3D%22380%22%20cy%3D%22200%22%20r%3D%221.8%22%20opacity%3D%22.25%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20500h1600v400H0z%22%20fill%3D%22%23241338%22%20opacity%3D%22.8%22%2F%3E%3Cg%20fill%3D%22%237B4FC4%22%3E%3Cpath%20d%3D%22M0%20520q400-26%20800%200t800-16v34q-400%2022-800-2t-800%2018z%22%20opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M0%20578q400-30%20800%200t800-18v44q-400%2026-800-2t-800%2020z%22%20opacity%3D%22.55%22%2F%3E%3Cpath%20d%3D%22M0%20650q400-34%20800%200t800-20v54q-400%2030-800-2t-800%2022z%22%20opacity%3D%22.6%22%2F%3E%3Cpath%20d%3D%22M0%20736q400-38%20800%200t800-22v64q-400%2034-800-2t-800%2024z%22%20opacity%3D%22.65%22%2F%3E%3Cpath%20d%3D%22M0%20838q400-42%20800%200t800-24v86H0z%22%20opacity%3D%22.7%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23C9A8FA%22%20opacity%3D%22.32%22%3E%3Cpath%20d%3D%22M0%20512q400-26%20800%200t800-16v8q-400%2020-800-2t-800%2016z%22%2F%3E%3Cpath%20d%3D%22M0%20570q400-30%20800%200t800-18v9q-400%2022-800-2t-800%2018z%22%2F%3E%3Cpath%20d%3D%22M0%20642q400-34%20800%200t800-20v10q-400%2026-800-2t-800%2020z%22%2F%3E%3Cpath%20d%3D%22M0%20728q400-38%20800%200t800-22v11q-400%2030-800-2t-800%2022z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%232A4038%22%20opacity%3D%22.7%22%3E%3Cpath%20d%3D%22M92%20500q-30-150%2026-250%2056%20100%2026%20250z%22%2F%3E%3Cpath%20d%3D%22M1490%20500q-26-134%2022-222%2048%2088%2022%20222z%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%238FB39B%22%20stroke-width%3D%224%22%20opacity%3D%22.3%22%3E%3Cpath%20d%3D%22M118%20502V330M1512%20502V352%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(201,168,250,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(182,208,190,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(201,168,250,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(182,208,190,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(201,168,250,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(182,208,190,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(201,168,250,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(182,208,190,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(201,168,250,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(164,114,240,.13) 0%, rgba(16,10,26,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(143,179,155,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(164,114,240,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(164,114,240,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.5;
  --th-voile: 255,255,255;
  --th-ombre: 0,0,0;
  --th-fond: #100A1A;
  --th-panneau: #1C1230;
  --th-carte: #261A3E;
  --th-fond-rgb: 16,10,26;
  --th-panneau-rgb: 28,18,48;
  --th-texte: #EDE7F5;
  --th-texte-2: #C0B3D4;
  --th-texte-3: #A497BC;
  --th-trait: 150,132,180;
  --th-accent: #A472F0;
  --th-accent-clair: #C9A8FA;
  --th-accent-doux: #9264D7;
  --th-accent-fort: #B78BF5;
  --th-accent-rgb: 164,114,240;
  --th-sur-accent: #100A1A;
  --th-sur-plein: #111111;
  --th-second: #8FB39B;
  --th-second-clair: #B6D0BE;
  --th-second-rgb: 143,179,155;
  --th-succes: #6FC095;
  --th-alerte: #DDB868;
  --th-danger: #E88C8C;
  --th-danger-rgb: 232,140,140;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 6px;
  --th-rayon-sm: 8px;
  --th-rayon-md: 8px;
  --th-rayon-lg: 10px;
  --th-rayon-carte: 10px;
  --th-rayon-panneau: 14px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #A472F0;
  --th-logo-halo: var(--th-accent);
}

[data-theme="colza"] {   /* Colza */
  --th-fond-scene: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20900%22%20preserveAspectRatio%3D%22xMidYMid%20slice%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22g%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23DCEAF6%22%2F%3E%3Cstop%20offset%3D%22.52%22%20stop-color%3D%22%23F2F6F4%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23FBF6DE%22%2F%3E%3C%2FlinearGradient%3E%3ClinearGradient%20id%3D%22c%22%20x1%3D%220%22%20y1%3D%220%22%20x2%3D%220%22%20y2%3D%221%22%3E%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23E8DC7A%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23C9A417%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%221600%22%20height%3D%22900%22%20fill%3D%22url%28%23g%29%22%2F%3E%3Cg%20opacity%3D%220.34%22%3E%3Ccircle%20cx%3D%221290%22%20cy%3D%22150%22%20r%3D%2266%22%20fill%3D%22%23FBF3C0%22%20opacity%3D%22.8%22%2F%3E%3Cg%20fill%3D%22%23FFFFFF%22%20opacity%3D%22.7%22%3E%3Cellipse%20cx%3D%22300%22%20cy%3D%22170%22%20rx%3D%22150%22%20ry%3D%2242%22%2F%3E%3Cellipse%20cx%3D%22420%22%20cy%3D%22150%22%20rx%3D%22110%22%20ry%3D%2234%22%2F%3E%3Cellipse%20cx%3D%22980%22%20cy%3D%22130%22%20rx%3D%22130%22%20ry%3D%2236%22%2F%3E%3C%2Fg%3E%3Cpath%20d%3D%22M0%20452h1600v448H0z%22%20fill%3D%22url%28%23c%29%22%20opacity%3D%22.75%22%2F%3E%3Cpath%20d%3D%22M0%20440q200-16%20400%200t400%204%20400-12%20400%206v20H0z%22%20fill%3D%22%23B9C48A%22%20opacity%3D%22.6%22%2F%3E%3Cg%20fill%3D%22%23C9A417%22%20opacity%3D%22.35%22%3E%3Cpath%20d%3D%22M0%20500q400-20%20800%204t800-12v26q-400%2020-800-4t-800%2014z%22%2F%3E%3Cpath%20d%3D%22M0%20592q400-24%20800%206t800-14v32q-400%2024-800-6t-800%2016z%22%2F%3E%3Cpath%20d%3D%22M0%20706q400-28%20800%208t800-16v40q-400%2028-800-8t-800%2018z%22%2F%3E%3Cpath%20d%3D%22M0%20838q400-32%20800%2010t800-18v70H0z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%23F0E48C%22%20opacity%3D%22.5%22%3E%3Cpath%20d%3D%22M0%20486q400-20%20800%204t800-12v10q-400%2018-800-4t-800%2012z%22%2F%3E%3Cpath%20d%3D%22M0%20578q400-24%20800%206t800-14v11q-400%2022-800-6t-800%2014z%22%2F%3E%3Cpath%20d%3D%22M0%20692q400-28%20800%208t800-16v12q-400%2026-800-8t-800%2016z%22%2F%3E%3C%2Fg%3E%3Cg%20fill%3D%22%235E7A4E%22%20opacity%3D%22.55%22%3E%3Cellipse%20cx%3D%22120%22%20cy%3D%22410%22%20rx%3D%2270%22%20ry%3D%2246%22%2F%3E%3Cellipse%20cx%3D%22230%22%20cy%3D%22424%22%20rx%3D%2252%22%20ry%3D%2232%22%2F%3E%3Cellipse%20cx%3D%221430%22%20cy%3D%22404%22%20rx%3D%2280%22%20ry%3D%2250%22%2F%3E%3Cellipse%20cx%3D%221320%22%20cy%3D%22424%22%20rx%3D%2254%22%20ry%3D%2232%22%2F%3E%3Cellipse%20cx%3D%221520%22%20cy%3D%22428%22%20rx%3D%2246%22%20ry%3D%2228%22%2F%3E%3C%2Fg%3E%3Cg%20stroke%3D%22%234A6140%22%20stroke-width%3D%227%22%20opacity%3D%22.5%22%3E%3Cpath%20d%3D%22M120%20452v-30M1430%20452v-34%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E") center / cover no-repeat;
  --th-decor-loin: radial-gradient(1.5px 1.5px at 18% 34%, rgba(94,86,0,0.4), transparent 60%),radial-gradient(2px 2px at 61% 22%, rgba(46,81,62,0.36), transparent 60%),radial-gradient(1.5px 1.5px at 38% 66%, rgba(94,86,0,0.32), transparent 60%),radial-gradient(2px 2px at 82% 54%, rgba(46,81,62,0.34), transparent 60%),radial-gradient(1.5px 1.5px at 12% 80%, rgba(94,86,0,0.28), transparent 60%),radial-gradient(2.5px 2.5px at 70% 84%, rgba(46,81,62,0.3), transparent 60%),radial-gradient(1.5px 1.5px at 47% 12%, rgba(94,86,0,0.26), transparent 60%),radial-gradient(2px 2px at 28% 52%, rgba(46,81,62,0.24), transparent 60%),radial-gradient(1.5px 1.5px at 90% 30%, rgba(94,86,0,0.28), transparent 60%);
  --th-decor-pres: linear-gradient(178deg, rgba(124,114,0,.13) 0%, rgba(250,247,232,0) 44%),radial-gradient(60% 30% at 24% -6%, rgba(63,107,84,.14), transparent 70%),radial-gradient(40% 24% at 72% -4%, rgba(124,114,0,.10), transparent 70%),repeating-linear-gradient(96deg, rgba(124,114,0,.04) 0 3px, transparent 3px 26px);
  --th-ambiance: 0.4;
  --th-surface-force: 2.1;
  --th-voile: 0,0,0;
  --th-ombre: 0,0,0;
  --th-fond: #FAF7E8;
  --th-panneau: #FEFDF6;
  --th-carte: #FFFFFC;
  --th-fond-rgb: 250,247,232;
  --th-panneau-rgb: 254,253,246;
  --th-texte: #241F08;
  --th-texte-2: #4A4114;
  --th-texte-3: #5A5020;
  --th-trait: 150,142,100;
  --th-accent: #7C7200;
  --th-accent-clair: #5E5600;
  --th-accent-doux: #82781A;
  --th-accent-fort: #6B6300;
  --th-accent-rgb: 124,114,0;
  --th-sur-accent: #FFFFFF;
  --th-sur-plein: #FFFFFF;
  --th-second: #3F6B54;
  --th-second-clair: #2E513E;
  --th-second-rgb: 63,107,84;
  --th-succes: #2F6B45;
  --th-alerte: #8A5A08;
  --th-danger: #A32620;
  --th-danger-rgb: 163,38,32;
  --th-rayon-micro: 4px;
  --th-rayon-xs: 8px;
  --th-rayon-sm: 10px;
  --th-rayon-md: 12px;
  --th-rayon-lg: 14px;
  --th-rayon-carte: 16px;
  --th-rayon-panneau: 22px;
  --th-police: system-ui, -apple-system, sans-serif;
  --th-police-titre: system-ui, -apple-system, sans-serif;
  --th-logo-coeur: #7C7200;
  --th-logo-halo: var(--th-accent);
}
/* ▲▲ FIN DES DÉCORS GÉNÉRÉS ▲▲ */

/* Réglages et serveur (Paramètres) : la pile de groupes. Une seule règle neuve pour
   ces deux volets — la respiration des volets Paramètres, réutilisée telle quelle. */
.rg-pile { display: flex; flex-direction: column; gap: var(--e-16); }

/* Panneau Machines : la commande d'installation d'un VDS, prête à copier. */
.mac-cmd { display: flex; flex-direction: column; gap: var(--e-8); }

/* Retirer un VDS : le geste vit au pied du détail, séparé du reste par un filet. */
.mac-retrait { display: flex; flex-direction: column; gap: var(--e-8); align-items: flex-start;
               margin-top: var(--e-20); padding-top: var(--e-16); border-top: 1px solid var(--border); }
/* L'avertissement change le SENS des trois choix : il se lit avant eux, pas après. */
/* L'avertissement ne se met plus en boîte : une boîte pleine à côté de trois cartes
   encadrées, ça fait quatre blocs qui se disputent le regard. Un filet et du texte. */
.mac-avert { border-left: 2px solid var(--amber); padding: var(--e-2) 0 var(--e-2) var(--e-14);
             font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-normal); }
.mac-choix { display: flex; flex-direction: column; gap: var(--e-8); }
.mac-choix { gap: var(--e-6); }
.mac-ch { display: flex; gap: var(--e-12); align-items: baseline; cursor: pointer;
          border: 1px solid transparent; border-radius: var(--r-sm);
          padding: var(--e-12) var(--e-14); transition: var(--transi); }
.mac-ch:hover { background: var(--bg-hover); }
.mac-ch.on { border-color: var(--accent); background: rgba(var(--th-accent-rgb), .05); }
.mac-ch .ct { display: block; font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text); }
.mac-ch .cs { display: block; font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-normal); margin-top: var(--e-4); }
/* ⚠️ LES DESTINATIONS ÉTAIENT ENTASSÉES : nom, machine, charge et verdict sur une seule
   ligne, en quatre morceaux qui se disputaient la largeur. Deux lignes suffisent — le
   nom et son verdict en haut, ce qui la décrit en dessous, en gris. */
.mac-accs { display: flex; flex-direction: column; gap: var(--e-8); }
.mac-acc { display: grid; grid-template-columns: 1fr auto; gap: var(--e-4) var(--e-16);
           align-items: baseline; text-align: left; cursor: pointer; background: transparent;
           border: 1px solid var(--border); border-radius: var(--r-sm);
           padding: var(--e-14) var(--e-16); font-family: inherit; transition: var(--transi); }
.mac-acc:hover:not(:disabled) { border-color: var(--border-strong); background: var(--bg-hover); }
.mac-acc.on { border-color: var(--accent); background: rgba(var(--th-accent-rgb), .05); }
.mac-acc.no, .mac-acc:disabled { opacity: .45; cursor: not-allowed; }
.mac-acc .an { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--text);
               font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.mac-acc .av { font-size: var(--t-meta); color: var(--text-3); text-align: right;
               white-space: nowrap; }
.mac-acc .av.ok { color: var(--green); }
.mac-acc .ac { grid-column: 1 / -1; font-size: var(--t-meta); color: var(--text-3); }
/* Le compteur du haut : une ligne, et le bouton de remise à zéro dans son fil. */
.mac-mig-cpt { display: flex; align-items: center; gap: var(--e-12); margin: 0;
               font-size: var(--t-small); color: var(--text-2); }
.mac-pre { margin: 0; padding: var(--e-12) var(--e-14); background: var(--bg-hover);
           border: 1px solid var(--border); border-radius: var(--radius-xs);
           font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t-meta);
           color: var(--text); line-height: var(--lh-normal); white-space: pre-wrap;
           word-break: break-all; overflow-x: auto; }

/* ═══ LE RANG « LES VENDEUSES » — une LANGUETTE par compte ═══════════════════
   Amadou (22/08) : « on ne va pas prendre un compte par ligne, on peut en entasser ;
   il faut que ça soit responsive, j'ai un grand écran et aussi un écran de PC portable ».
   ⚠️ MÊME MÉCANISME QUE LA BIBLIOTHÈQUE — `auto-fill` + `minmax`. Aucun palier à écrire,
   aucune largeur d'écran à deviner : la grille compte elle-même combien de languettes
   tiennent. Mesuré sur sa mise en page (barre latérale 232 px + 2 × 32 px de marge) :
   3 par ligne sur un portable 1280, 6 sur un 1920, 9 sur un 2560.
   ⚠️ La largeur vient de `--cp-lg-w`, posée par le JS depuis `_CP_LANGUETTE`. Elle n'est
   PAS écrite ici : deux nombres pour une même mesure finissent toujours par diverger.
   ⚠️ Aucune valeur brute : tout vient de la bibliothèque de jetons (--e-*, --r-*, --t-*). */
.cok-cp-filter.on { border-color: var(--violet-mid); background: var(--violet-tint); color: var(--text-1); }
.cp-vend-zone { display: block; }

/* Le bandeau : cinq chiffres, et c'est aussi le filtre. ⚠️ Un résumé en haut et des
   filtres ailleurs finiraient par se contredire — la barre d'avant annonçait « Toutes
   10 » au-dessus de « 0 + 5 + 0 ». Un seul objet, une seule vérité. */
.cp-vie-bandeau { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--e-40), 1fr));
  gap: var(--e-1); background: var(--border); border: var(--e-1) solid var(--border);
  border-radius: var(--r-sm); overflow: hidden; margin-bottom: var(--e-16); }
.cp-vie-tuile { display: block; text-align: left; background: var(--surface);
  border: 0; border-top: var(--e-2) solid transparent; border-radius: 0;
  padding: var(--e-12) var(--e-14); font: inherit; color: var(--text);
  cursor: pointer; transition: var(--transi); }
.cp-vie-tuile:hover { background: var(--surface-2); }
.cp-vie-tuile.on { background: var(--surface-2); border-top-color: var(--cok-accent); }
.cp-vie-tuile .n { display: block; font-size: var(--t-title); font-weight: var(--fw-fort);
  line-height: var(--lh-titre); font-variant-numeric: tabular-nums; }
.cp-vie-tuile .l { display: block; font-size: var(--t-meta); color: var(--text-2);
  margin-top: var(--e-2); }
/* ⚠️ La couleur du chiffre PORTE le sens, elle n'est pas décorative : ce qui attend est
   ambre, ce qui est sorti est rouge, ce qui travaille est vert. */
.cp-vie-tuile.ton-bloques .n { color: var(--amber); }
.cp-vie-tuile.ton-sortis .n { color: var(--red); }
.cp-vie-tuile.ton-travail .n { color: var(--green); }

.cp-vie-pied { display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-16); flex-wrap: wrap; padding: var(--e-14) var(--e-16) var(--e-8);
  font-size: var(--t-meta); color: var(--text-3); }

/* ══ LE PARTAGE LOCAL / VDS ══════════════════════════════════════════════════
   Empruntée telle quelle : la pilule de la bibliothèque (.v-btn--pilule). Rien de neuf
   à dessiner, donc rien de neuf à maintenir.
   ⚠️⚠️⚠️ LA SÉLECTION DOIT BATTRE LE SURVOL, ET ELLE NE LE FAIT PAS TOUTE SEULE.
   `.v-btn:hover:not(:disabled)` pèse TROIS classes ; `.cp-poste-f.on` n'en pèse que
   deux. Sans le `:hover` écrit ici, passer la souris sur le bouton choisi lui rendrait
   le fond du survol — la sélection s'éteindrait sous le doigt. C'est déjà arrivé sur
   cet écran (31 règles à reprendre), et c'est exactement le même piège. */
/* ⚠️ LE PANNEAU N'A PLUS DE COQUILLE (Amadou, 07/09 : « les boutons local et VDS ne
   doivent pas être dans la bulle »). Une bulle dans une bulle : les boutons vivaient
   dans le panneau qu'ils commandent, ce qui se lit « ceci appartient au VDS » alors
   qu'ils servent à en CHANGER. Ils sont remontés dans la barre ; le panneau ne porte
   plus que les cartes, et n'a donc plus besoin de se dessiner un cadre. */
.cp-poste-w { margin: 0; }

/* Les deux hôtes de la barre du haut. */
.cp-barre-basc { display: flex; align-items: center; }
.cp-barre-famz { display: flex; align-items: center; }
/* Le bouton des familles se colle aux métriques : c'est un réglage de LECTURE, pas un
   élément du contenu — il appartient à la même rangée que les chiffres. */
.cp-barre-famz .cp-fam-zone { padding: 0; }
.cp-poste-i { display: grid; place-items: center; flex: 0 0 auto; opacity: .75; }
.cp-poste-i svg { display: block; }

/* ══ CHOISIR UNE FAMILLE ═════════════════════════════════════════════════════
   Le bouton est EMPRUNTÉ au « Trier » des Messages (`.cok-msg-search, .cok-msg-filtre`,
   plus haut dans ce fichier) : même taille, même fond, même liseré, icône à 60 %.
   Amadou (07/09) : « ça doit être juste un bouton avec le logo, là il est gros pour
   rien ». Au repos il n'a QUE son icône — « toutes les familles » est l'état par
   défaut, son libellé n'apprenait rien. */
.cp-fam-zone { position: relative; padding: 0 var(--e-12) var(--e-12); }
.cp-fam-b { font: inherit; font-size: var(--t-meta); color: var(--cok-text);
  background: var(--surface-2); border: 1px solid var(--cok-border);
  border-radius: var(--r-sm); padding: var(--e-6) var(--e-10);
  display: inline-flex; align-items: center; gap: var(--e-6);
  cursor: pointer; white-space: nowrap; max-width: 100%;
  transition: border-color var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose); }
.cp-fam-b:hover { border-color: var(--border-strong); }
.cp-fam-b:focus-visible { outline: none; border-color: var(--violet); }
.cp-fam-b svg { flex: 0 0 auto; opacity: .6; }
/* ⚠️⚠️ L'ÉTAT ACTIF EST UN LISERÉ, PAS UN APLAT. À cette taille un aplat violet
   redevient le gros bouton qu'on vient d'enlever — et l'aplat est déjà le langage des
   ONGLETS, un cran au-dessus. Un état se distingue par la FORME, pas par la teinte. */
.cp-fam-b.actif { border-color: var(--violet); color: var(--violet-light); }
.cp-fam-b.actif svg { opacity: 1; }
/* Icône seule : le bouton se resserre, il ne prend que sa place. */
.cp-fam-b.nu { padding: var(--e-6) var(--e-8); gap: 0; }
.cp-fam-b-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cp-fam-b-n { font-variant-numeric: tabular-nums; color: var(--text-3); flex: 0 0 auto; }
.cp-fam-b.actif .cp-fam-b-n { color: var(--violet-light); }

.cp-fam-pop { position: absolute; z-index: 40; top: calc(100% - var(--e-8)); left: var(--e-12);
  width: min(22rem, calc(100% - var(--e-24)));
  background: var(--cok-card); border: 1px solid var(--border-strong);
  border-radius: var(--r-lg); box-shadow: 0 18px 44px rgba(var(--th-ombre), .55);
  overflow: hidden; }
.cp-fam-pop[hidden] { display: none; }
.cp-fam-rech { display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-10) var(--e-12); border-bottom: 1px solid var(--cok-border); }
.cp-fam-rech svg { color: var(--text-3); flex: 0 0 auto; }
.cp-fam-rech input { flex: 1; min-width: 0; background: transparent; border: 0; outline: none;
  color: var(--cok-text); font: inherit; font-size: var(--t-base); }
.cp-fam-rech input::placeholder { color: var(--text-3); }
.cp-fam-liste { max-height: 17rem; overflow-y: auto; padding: var(--e-6); }
.cp-fam-sec { font-size: var(--t-micro); letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-3); padding: var(--e-8) var(--e-8) var(--e-4); }
.cp-fam-sec[hidden] { display: none; }
.cp-fam-l { display: flex; align-items: center; gap: var(--e-10); width: 100%;
  font: inherit; text-align: left; cursor: pointer;
  padding: var(--e-6) var(--e-8); border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--text-2);
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose); }
.cp-fam-l[hidden] { display: none; }
.cp-fam-l:hover { background: var(--bg-elevated); color: var(--cok-text); }
.cp-fam-l:focus-visible { outline: 2px solid var(--cok-accent); outline-offset: -2px; }
.cp-fam-l-i { display: grid; place-items: center; flex: 0 0 16px; width: 16px; height: 16px; opacity: .7; }
.cp-fam-l-i svg { width: 16px; height: 16px; }
.cp-fam-l-t { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--t-base); }
.cp-fam-l-n { font-variant-numeric: tabular-nums; font-size: var(--t-meta); color: var(--text-3);
  min-width: 1.2rem; text-align: right; }
/* ⚠️ La sélection doit BATTRE le survol : `.cp-fam-l:hover` pèse deux classes, on écrit
   donc les deux, sinon la ligne choisie s'éteint sous le doigt. */
.cp-fam-l.on, .cp-fam-l.on:hover { background: var(--cok-accent-bg); color: var(--violet-light);
  font-weight: var(--fw-fort); }
.cp-fam-l.on .cp-fam-l-i { opacity: 1; }
.cp-fam-l.on .cp-fam-l-n { color: var(--violet-light); }
/* Une famille vide reste ATTEIGNABLE : atténuée, jamais désactivée — on y range des
   comptes justement parce qu'elle est vide. */
.cp-fam-l.zero { opacity: .45; }
.cp-fam-l.zero:hover { opacity: .8; }
.cp-fam-rien { padding: var(--e-16) var(--e-10); color: var(--text-3);
  font-size: var(--t-base); text-align: center; }
.cp-fam-rien[hidden] { display: none; }
/* ══ LE CHOIX DE LA MACHINE, EN GRADUATION ═══════════════════════════════════
   Amadou (07/09) : « les boutons local et VDS, fais mieux que ça, c'est vraiment moche…
   au pire tu mets les boutons en graduation comme il y a dans commande ».
   On emprunte donc `.cok-cmd-groups` / `.cok-cmd-grp` tels quels : un CADRE qui contient
   ses segments. Deux pilules côte à côte ne disaient pas qu'elles s'excluent ; le cadre
   le dit, et c'est déjà le langage du site pour « choisis-en un ».
   Ne restent ici que les écarts propres à cet emplacement. */
.cp-poste-grad { margin-bottom: 0; flex: 0 0 auto; }
.cp-poste-g { flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--e-8);
  padding: var(--e-6) var(--e-12); font-size: var(--t-meta); }
/* ⚠️⚠️⚠️ L'ÉTAT CHOISI DOIT BATTRE LE SURVOL, ET ON NE COMPTE PAS SUR L'ORDRE.
   `.cok-cmd-grp:hover` (ligne ~22116) n'a AUCUNE garde `:not()` et pose un `background`
   — un raccourci, donc il efface aussi l'image de fond. C'est exactement ce qui éteignait
   le bouton « Litiges » au survol en août. Une règle postérieure suffirait aujourd'hui,
   mais elle casserait au prochain déplacement de bloc : on écrit donc le `:hover`, qui
   pèse une classe de plus et gagne où qu'il soit. */
.cp-poste-g.on,
.cp-poste-g.on:hover { background: var(--cok-accent-bg); color: var(--cok-accent); }
.cp-poste-g.on .cp-poste-i { opacity: 1; }
.cp-poste-g.on .cp-poste-n,
.cp-poste-g.on:hover .cp-poste-n { color: var(--cok-accent); }
/* Un lieu vide reste ATTEIGNABLE : atténué, jamais désactivé — c'est en y entrant qu'on
   lit pourquoi il est vide. */
.cp-poste-g.vide { opacity: .55; }
.cp-poste-g.vide.on { opacity: 1; }
/* Le compte, collé au nom : c'est lui qu'on lit en premier. */
.cp-poste-n { font-variant-numeric: tabular-nums; font-weight: var(--fw-gras);
  font-size: var(--t-mini); color: var(--text-3); }
/* ⚠️ Un espace VIDE reste cliquable : c'est en y entrant qu'on lit pourquoi il l'est.
   On l'atténue, on ne le désactive pas — un bouton mort ne s'explique jamais. */

/* ⚠️ LE VIDE SE DIT LÀ OÙ LE CONTENU AURAIT COMMENCÉ. Il était posé loin sous la barre,
   avec le retrait d'un gros bloc de texte : on lisait un paragraphe flottant au milieu
   de rien. Une ligne, à la place de la première carte. */
.cp-poste-vide { padding: var(--e-14) var(--e-16) var(--e-20);
  font-size: var(--t-small); color: var(--text-2); }

/* La période, discrète, collée aux chiffres du pouls. */
.cp-pouls-per { font-size: var(--t-meta); color: var(--text-3); }

.cp-vie-legende { display: flex; flex-wrap: wrap; gap: var(--e-20);
  padding: var(--e-4) var(--e-16) var(--e-16); font-size: var(--t-meta); color: var(--text-2); }
.cp-vie-lg { display: inline-flex; align-items: center; gap: var(--e-6); }
.cp-vie-lg .pt { width: var(--e-8); height: var(--e-8); border-radius: var(--r-micro);
  display: inline-block; }
.cp-vie-lg.ok .pt { background: var(--green); }
.cp-vie-lg.tiede .pt { background: var(--amber); }
.cp-vie-lg.ko .pt { background: var(--red); }

/* Où le compte va naître. ⚠️ Une ligne, pas une carte : c'est un fait qu'on lit en
   passant avant de cliquer, pas un panneau qu'on consulte. */
.cpl-ou { font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-serre);
  padding: var(--e-10) var(--e-14); margin-bottom: var(--e-12);
  background: var(--surface-2); border: var(--e-1) solid var(--border);
  border-radius: var(--r-sm); }
.cpl-ou b { color: var(--text); font-weight: var(--fw-fort); }
.cpl-ou .s { color: var(--text-3); }
/* ⚠️ Le refus se voit AVANT le clic : c'est tout l'intérêt de cette ligne. */
.cpl-ou .ko { color: var(--amber); }

/* ══ LA VIE D'UN COMPTE — UNE LIGNE, DEUX RÉPONSES ═══════════════════════════
   Amadou (28/08) : « l'onglet Comptes, c'est l'aboutissement du travail. »
   Une ligne dit OÙ IL EN EST et CE QU'IL ATTEND. Le reste vit dans sa fiche.
   ⚠️ Zéro valeur brute : tout vient des jetons. La règle du 13/08 tient. */
.cp-vie-liste { display: flex; flex-direction: column; }

/* ══ SES PACKS — UNE SECTION, DES PASTILLES (04/09) ═══════════════════════════
   Amadou : « le bloc Ses packs est trop collé à la partie du haut et elle est trop
   brouillon ».
   ⚠️ LE COLLAGE : l'ancienne barre était une CARTE posée juste sous l'avatar, sans
   marge haute. Une carte dans une colonne qui n'en contient aucune autre se lit comme
   un corps étranger. C'est maintenant une SECTION, comme « Ses vues » juste en dessous :
   un filet, de l'air, un titre à gauche, le compte et l'action à droite.
   ⚠️⚠️ LE BROUILLON : les flèches sont parties. Sur un seul pack — le cas des cinq
   comptes tenus — elles étaient DEUX BOUTONS MORTS, et le « 1 / 1 » qu'elles servaient
   à parcourir ne disait rien. Des pastilles sur une ligne donnent la même compacité et
   vont droit au but. La rangée défile SUR LE CÔTÉ : la colonne ne descend jamais, ce
   qui était toute la raison des flèches.
   ⚠️ Aucune valeur brute : tout en jetons. */
/* ══ LE PACK ET SES VUES : UN SEUL CADRE (04/09) ═════════════════════════════
   Amadou : « on dirait 2 blocs alors qu'ils sont liés ». Ils l'étaient au sens propre —
   le tiroir vivait DANS le bloc de l'avatar, dont le `border-bottom` passait juste au
   dessus des trois vues. L'œil voyait donc : [avatar + tiroir] | filet | [vues].
   Le pack choisi et les vues qu'il porte sont maintenant dans le MÊME cadre : la tête
   dit lequel, le corps montre le sien. Changer de pack change ce qu'il y a dedans, et
   ça se voit sans qu'on l'explique.
   ⚠️⚠️ SURTOUT PAS D'`overflow: hidden` SUR CE CADRE. La liste du tiroir se pose en
   ABSOLU et déborde largement de la tête : un cadre qui coupe l'aurait rendue
   invisible — un menu déroulant qui ne se déroule pas, sans erreur, sans rien dire.
   Les coins du haut sont donc arrondis SUR LE BOUTON, pas par un recadrage du parent. */
.pk-bloc.a-pack { border: var(--e-1) solid var(--border); border-radius: var(--r-md);
  background: var(--bg-panel); }
/* ⚠️ La tête du cadre est maintenant la LISTE elle-même : plus de bouton en haut, donc
   plus de filet sous lui ni de coins arrondis à lui donner. Le cadre respire à la place. */
.pk-bloc.a-pack .pk-liste { padding: var(--e-10); }
.pk-bloc.a-pack .model-slots { padding: var(--e-12); }
/* Le titre vit AU-DESSUS du cadre, comme « Son avatar Vinted » au-dessus du sien : les
   deux sections de la colonne se présentent de la même façon. */
#model-pack-tete:empty { display: none; }
.pk-sec-tete { display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--e-8); margin-bottom: var(--e-10); }
.pk-sec-t { font-size: var(--t-base); font-weight: var(--fw-fort); color: var(--text); }
.pk-sec-d { display: flex; align-items: baseline; gap: var(--e-8); flex: 0 0 auto; }
.pk-sec-n { font-size: var(--t-meta); color: var(--text-3); }

/* ══ SES PACKS — UNE LIGNE PAR PACK (04/09, piste choisie sur maquette) ══════
   Le tiroir est retiré : sur ses comptes il n'y a qu'UN pack, et un menu déroulant qui
   ne mène qu'à lui-même n'est pas un choix. Les lignes montrent tous les packs à la fois,
   leurs trois vues en miniature suffisent à les reconnaître, et la colonne reste courte
   même à dix packs.
   ⚠️ Les règles du tiroir partent AVEC lui — `.pk-tir-*`, `.pk-tiroir`. Une classe que
   plus personne ne pose est du poids mort, et pire, une fausse piste : on la lit dans la
   feuille et on croit que l'écran déplie encore. */
.pk-liste { display: flex; flex-direction: column; gap: var(--e-6); }
.pk-l { display: flex; align-items: center; gap: var(--e-10);
  padding: var(--e-8); border-radius: var(--r-md);
  border: var(--e-1) solid var(--border); background: var(--surface);
  transition: var(--transi); }
.pk-l:hover { border-color: var(--border-strong); }
/* ⚠️ Le pack OUVERT se marque par son FOND, pas par un cadre doré : sur ce thème l'accent
   et l'ambre sont deux dorés, et un cadre s'y lit « il manque quelque chose ». */
.pk-l.on { background: var(--cok-accent-bg); border-color: var(--cok-accent); }
.pk-l-vues { display: flex; gap: var(--e-2); flex: 0 0 auto; }
/* ⚠️ `--e-40`, pas `--e-44` : ce dernier n'existe pas dans l'échelle, et `var()` sur un
   jeton absent ne crie pas — il vide la propriété. La miniature aurait eu 0 de haut. */
.pk-l-v { display: block; width: var(--e-32); height: var(--e-40);
  padding: 0; border: 0; border-radius: var(--r-xs); overflow: hidden;
  background: var(--bg-hover); cursor: zoom-in; }
.pk-l-v img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pk-l-v--vide { border: var(--e-1) dashed var(--border-strong); background: transparent;
  cursor: default; }
/* ⚠️ LE NOM PREND TOUTE LA PLACE QUI RESTE. Le compteur « 3 vues sur 3 » a été retiré
   (Amadou : « ça sert à rien ») — et ses règles partent avec lui, sinon c'est une classe
   qu'on relit en croyant qu'elle sert encore. Le signal « pack incomplet » vit maintenant
   dans la FORME : un emplacement en pointillés dans la bande de miniatures. */
.pk-l-n { flex: 1; min-width: 0;
  font-size: var(--t-base); font-weight: var(--fw-moyen); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ⚠️ CELUI-CI RESTE VISIBLE : ouvrir le pack est l'action PRINCIPALE de la languette,
   pas une action de bord. Ce qui se cache au survol, c'est ce qui défait — pas ce qu'on
   vient faire. */
.pk-l-ouv { display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: var(--e-20); height: var(--e-20); padding: 0; cursor: pointer;
  background: transparent; color: var(--text-3); border: 0; border-radius: var(--r-xs);
  transition: var(--transi); }
.pk-l-ouv svg { width: var(--e-14); height: var(--e-14); }
.pk-l-ouv:hover { color: var(--th-accent-clair); background: var(--cok-accent-bg); }

/* ⚠️ Détacher se révèle au survol : une action qui défait ne s'offre pas. Elle reste
   atteignable au clavier, sinon ce serait la cacher pour de bon. */
.pk-l-det { display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: var(--e-20); height: var(--e-20); padding: 0; cursor: pointer;
  background: transparent; color: var(--text-3); border: 0; border-radius: var(--r-xs);
  opacity: 0; transition: var(--transi); }
.pk-l-det svg { width: var(--e-12); height: var(--e-12); }
.pk-l:hover .pk-l-det, .pk-l-det:focus-visible { opacity: 1; }
.pk-l-det:hover { color: var(--red); background: var(--cok-red-bg); }
.pk-liste .pk-add { width: 100%; text-align: center;
  padding: var(--e-8); border-radius: var(--r-md);
  border: var(--e-1) dashed var(--border-strong); }

/* ⚠️ « + Ajouter » N'EST PLUS UNE BOÎTE EN POINTILLÉS. Dans une barre bourrée, le
   pointillé disait « ceci est un ajout » ; dans un en-tête de section, à côté du
   compte, la place suffit à le dire. Un mot en accent, et rien de plus. */
.pk-add { flex: 0 0 auto; font: inherit; font-size: var(--t-meta); cursor: pointer;
  padding: 0; background: transparent; border: 0;
  color: var(--th-accent-clair); transition: var(--transi); }
.pk-add:hover:not(:disabled) { text-decoration: underline; }
.pk-add:disabled { color: var(--text-3); cursor: default; text-decoration: none; }
/* ══ LE PANNEAU D'AJOUT — IL COUVRE LA COLONNE (03/09) ════════════════════════
   Amadou : « ça va ouvrir un panel sur la gauche, qui fait la taille de la partie Son
   avatar Vinted, et où je dois pouvoir scroller. Parce que là, c'est illisible. »
   ⚠️ L'ANCIEN ÉTAIT `position:absolute` SANS ANCRAGE : il retombait à sa position
   statique, donc PAR-DESSUS l'avatar, et ses pastilles se chevauchaient. Celui-ci se cale
   sur la colonne entière et défile à l'intérieur — il ne peut plus rien recouvrir
   d'autre, et l'écran ne s'allonge pas quand une famille a beaucoup de niches. */
.pk-hote { position: relative; }
/* ⚠️⚠️⚠️ UN PANNEAU QUI SE POSE SUR QUELQUE CHOSE DOIT ÊTRE OPAQUE. Amadou : « trop
   transparent, beaucoup trop même ». Il avait raison, et c'est mesuré : `--surface` vaut
   `rgba(255,255,255,0.03)` — trois pour cent de blanc sur le fond de page. Parfait pour
   une carte POSÉE DANS le flux, désastreux pour un panneau qui en recouvre un autre : on
   lisait l'avatar et « Son espace modèle » au travers.
   `--bg-panel-solid` est le jeton du projet pour ça — celui des fenêtres modales. */
/* ⚠️ ÉCLAIRCI D'UN CRAN, SANS PERDRE L'OPACITÉ. Amadou : « c'est un peu trop foncé,
   mais légèrement ». Le voile de blanc est posé EN PREMIÈRE COUCHE au-dessus du fond
   solide : deux fonds empilés restent opaques, alors qu'un `rgba` seul redeviendrait
   translucide — c'est exactement le défaut qu'on vient de réparer. */
.pk-panneau { position: absolute; inset: 0; z-index: 30; display: flex;
  flex-direction: column; overflow: hidden;
  background: linear-gradient(rgba(255,255,255,.045), rgba(255,255,255,.045)),
              var(--bg-panel-solid);
  border: var(--e-1) solid var(--border-strong);
  border-radius: var(--r-carte); }
.pk-pan-tete { display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-8); padding: var(--e-12) var(--e-12) var(--e-4); flex: 0 0 auto; }
.pk-pan-t { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text); }
.pk-pan-x { display: flex; align-items: center; justify-content: center;
  width: var(--e-24); height: var(--e-24); padding: 0; cursor: pointer;
  background: transparent; color: var(--text-3); border: 0; transition: var(--transi); }
.pk-pan-x svg { width: var(--e-14); height: var(--e-14); }
.pk-pan-x:hover { color: var(--text); }
.pk-pan-s { font-size: var(--t-meta); color: var(--text-3);
  padding: 0 var(--e-12) var(--e-8); flex: 0 0 auto; }
/* Des CARTES, pas des lignes — et ce sont celles de la Bibliothèque (`lib-niche`).
   Deux par rangée dans cette colonne ; elles défilent, le panneau ne grandit pas. */
.pk-pan-l { flex: 1; min-height: 0; overflow-y: auto;
  /* ⚠️⚠️ DEUX PAR RANGÉE, IMPOSÉES. Amadou : « il faudrait mes deux par ligne, parce
     que là on voit juste rien ». `auto-fill` avec un minimum de 10 rem tombait à UNE
     colonne : sa colonne fait ~360 px, et deux pistes de 160 px plus la gouttière et les
     marges n'y tenaient qu'au pixel près. Un calcul qui bascule sur un arrondi n'est pas
     une mise en page — on demande donc deux pistes, et `minmax(0,1fr)` les laisse se
     serrer sans jamais déborder. */
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--e-10); align-content: start;
  padding: var(--e-12); border-top: var(--e-1) solid var(--border); }
/* ⚠️⚠️ UNE HAUTEUR FIXE, PAS UN RATIO. Mesuré au banc : avec `aspect-ratio: 4/5` les
   cartes se dessinaient en 178 px de haut pendant que la grille ne réservait que 135 px
   à ses rangées — elles se CHEVAUCHAIENT de 43 px. Une grille dimensionne ses rangées
   sur le contenu, et un ratio n'est pas du contenu. On donne donc une hauteur définie :
   la rangée la connaît, plus de recouvrement. */
.pk-pan-l .lib-niche { aspect-ratio: auto; height: 9.5rem; }

/* ══ LE MUR DES FAMILLES DANS LE PANNEAU (04/09) ══════════════════════════════
   Amadou : « remets les familles de niches » — et, le 01/09 déjà, « ça doit être un panel
   comme la Bibliothèque ». On y pose donc `.lib-fam-carte`, la carte que la Bibliothèque
   et l'Atelier partagent, rétrécie comme l'Atelier la rétrécit déjà (`#atelier-step-1`).
   ⚠️⚠️ `aspect-ratio` EST RETIRÉ, ET CE N'EST PAS COSMÉTIQUE. `.lib-fam-carte` porte
   `4 / 5` ; une grille dimensionne ses rangées sur le CONTENU, pas sur un ratio — c'est
   ce qui a fait chevaucher les cartes de 43 px le 03/09, au même endroit. Hauteur définie. */
.pk-pan-l--fam .lib-fam-carte { aspect-ratio: auto; height: 8.5rem;
  padding: var(--e-10); border-radius: var(--r-md); }
.pk-pan-l--fam .lib-fam-carte-logo { width: var(--e-32); height: var(--e-32);
  margin-bottom: var(--e-8); border-radius: var(--r-sm); }
.pk-pan-l--fam .lib-fam-carte-nom { font-size: var(--t-mini); line-height: var(--lh-serre); }
.pk-pan-l--fam .lib-fam-carte-n   { font-size: var(--t-micro); }

/* ⚠️ DEUX LIGNES PLUTÔT QU'UNE COUPURE. À 160 px de large, « Vestes pour femmes » ne
   tient pas sur une ligne : la couper au milieu d'un mot, c'est rendre la carte illisible
   pour gagner huit pixels. On lui en donne deux, et on ne coupe qu'au-delà. */
.pk-pan-l .lib-niche-nom { white-space: normal; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  line-height: var(--lh-serre); }
/* Le fil du second étage : « ‹ Vêtements · Robes ». Il remplace la phrase du pied —
   ⚠️ Amadou : « épure au niveau de son contenu ». Une phrase qui explique une règle
   coûte quatre lignes ; un fil qui dit où on est en coûte une, et il sert à revenir. */
.pk-pan-retour { font: inherit; font-size: var(--t-meta); color: var(--th-accent-clair);
  background: transparent; border: 0; padding: 0 var(--e-6) 0 0; cursor: pointer; }
.pk-pan-retour:hover { text-decoration: underline; }
.pk-pan-s { display: flex; align-items: baseline; gap: var(--e-4); }
.pk-pan-sep { color: var(--text-3); }
/* ⚠️ « JE NE SAIS PAS » N'EST PAS « IL N'Y A RIEN ». Sans pack libre, on dit quoi faire :
   un panneau vide sans phrase se lit comme une panne. */
.pk-pan-rien { grid-column: 1 / -1; font-size: var(--t-meta); color: var(--text-3);
  line-height: var(--lh-normal); padding: var(--e-8) var(--e-4); }
/* Les packs sont plus hauts que les niches : on y lit un visage, pas une couverture. */
.pk-pan-l--packs .lib-niche { height: 11.5rem; }

/* ══ LES COMPTES : UN MUR DE FAMILLES, PUIS UNE GRILLE DE CARTES (03/09) ══════
   Amadou : « ça prend toute la longueur du site pour au final peu de choses ». Une bande
   pleine largeur par compte étalait trois informations sur 1 400 px. Les cartes se
   répartissent maintenant sur la largeur — deux, trois ou quatre par ligne selon l'écran.
   ⚠️ Aucune valeur brute : tout en jetons, comme le reste du fichier. */
.cp-mur { display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: var(--e-8); margin-bottom: var(--e-20); }

.cp-vie-grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--e-10); }
.cp-carte { display: block; width: 100%; text-align: left; font: inherit; color: var(--text);
  padding: var(--e-12) var(--e-14); background: var(--surface);
  border: var(--e-1) solid var(--border); border-radius: var(--r-carte);
  cursor: pointer; transition: var(--transi); }
.cp-carte:hover { border-color: var(--cok-border-2); background: var(--surface-2); }
.cp-carte:hover .cp-carte-chev { color: var(--th-accent-clair); }
.cp-carte:focus-visible { outline: var(--e-2) solid var(--cok-accent); outline-offset: var(--e-2); }
/* ⚠️⚠️⚠️ LE CADRE AMBRE EST RETIRÉ (Amadou, 04/09 : « le compte leanguyen est
   constamment sélectionné »). Ce n'était NI une sélection NI un focus — mesuré dans le
   navigateur : `focus: false`, `outline: none`. C'était `.sansfam`, qui peignait la
   bordure en rgb(224,190,116).
   Le défaut est que cette interface se sert du DORÉ pour dire « ceci est choisi » :
   l'onglet actif, la pastille de l'espace, le pack sélectionné dans le tiroir. L'ambre
   du « il manque quelque chose » est la même teinte. Deux sens pour une couleur, et
   c'est le sens le plus fréquent qui gagne dans l'œil.
   ⚠️ LE SIGNAL N'EST PAS PERDU, IL CHANGE DE PLACE : « Sans famille » devient une vraie
   pastille ambre sur la ligne du bas (voir `.cp-carte-fam.manque`). Il se voit autant,
   sans mentir sur l'état de la carte. Et à quarante comptes dont la plupart sans
   famille, quarante cadres ambre ne rangeaient plus rien de toute façon. */
.cp-carte.sorti { opacity: .55; }

.cp-carte-haut { display: flex; align-items: center; gap: var(--e-10); }
.cp-carte-txt { flex: 1; min-width: 0; }
.cp-carte-p { font-size: var(--t-base); font-weight: var(--fw-gras); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cp-carte-m { font-size: var(--t-meta); color: var(--text-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cp-carte-chev { flex: 0 0 auto; width: var(--e-16); height: var(--e-16);
  color: var(--text-3); transition: var(--transi); }
.cp-carte-chev svg { width: 100%; height: 100%; display: block; }

.cp-carte-bas { display: flex; align-items: center; gap: var(--e-8);
  margin-top: var(--e-10); font-size: var(--t-meta); flex-wrap: wrap; }
.cp-carte-etat { color: var(--green); }
.cp-carte-etat.attend { color: var(--amber); }
.cp-carte-etat.sorti { color: var(--red); }
.cp-carte-pk { color: var(--text-3); }

.cp-carte-fam { display: inline-flex; align-items: center; flex: 0 0 auto;
  margin-left: auto; font-size: var(--t-micro); padding: var(--e-2) var(--e-8);
  border-radius: var(--r-pilule);
  background: var(--cok-accent-bg); color: var(--th-accent-clair); }
/* ⚠️⚠️⚠️ ET SURTOUT PAS UNE PASTILLE PLEINE DE PLUS. Première tentative, mesurée dans
   le navigateur : « Vêtements » rgba(217,176,99,.16) sur rgb(242,221,168), « Sans
   famille » rgba(213,156,82,.13) sur rgb(224,190,116). Deux dorés à s'y méprendre — on
   ne distinguait plus « il a une famille » de « il lui en manque une ». Sur ce thème
   l'accent EST doré, et l'ambre aussi : distinguer par la TEINTE ne marche pas.
   On distingue donc par la FORME, qui tient sur les vingt thèmes : une famille est une
   pastille pleine (une catégorie), un manque est du texte nu suivi du point ambre —
   `.champ-manque`, le marqueur « case à renseigner » que la fiche pose déjà derrière
   IBAN et TÉLÉPHONE. Emprunté, pas inventé : aucune règle nouvelle. */
.cp-carte-fam.manque { background: transparent; color: var(--amber); padding: 0; }

/* ⚠️ LA PHOTO A BESOIN DE PLACE (Amadou, 04/09 : « on doit voir la pfp des comptes »).
   À 28 px un visage n'est plus un visage, c'est une tache — et deux comptes se
   ressemblent. Le rond passe à 40 px SUR LA CARTE SEULEMENT : `.cp-lg-av` sert aussi
   aux languettes de 240 px, où 40 px mangerait la ligne. */
.cp-carte-haut .cp-lg-av { width: var(--e-40); height: var(--e-40);
  font-size: var(--t-meta); }

/* ══ LA BARRE UNIQUE DE « LES COMPTES » (04/09) ══════════════════════════════
   Amadou : « la partie au-dessus des cards des comptes est vraiment brouillon ». Quatre
   étages empilés — tuiles, phrase, recherche, pastille — remplacés par une ligne.
   ⚠️ `flex-wrap` N'EST PAS UN LUXE : en colonne étroite la ligne se replie au lieu de
   pousser le pouls hors de l'écran. Les deux largeurs sont vérifiées. */
.cp-barre { display: flex; align-items: center; gap: var(--e-10); flex-wrap: wrap;
  margin-bottom: var(--e-10); }
.cp-barre .cp-vend-rech { margin-bottom: 0; flex: 1 1 calc(var(--e-20) * 9);
  min-width: calc(var(--e-20) * 7); max-width: calc(var(--e-20) * 16); }
.cp-barre-fam { display: flex; flex: 0 0 auto; }
.cp-barre-fam .cp-fam-bascule { margin-bottom: 0; }
/* ⚠️ LE ZÉRO NE CRIE PAS. Une tuile de 152 px donnait le même poids à « 0 cœur » qu'à
   « 40 vivantes » ; ici un chiffre à zéro reste gris et le reste passe en clair. */
.cp-pouls { display: flex; align-items: center; gap: var(--e-14); flex: 0 0 auto;
  margin-left: auto; padding: var(--e-8) var(--e-12); border-radius: var(--r-md);
  background: var(--bg-panel); font-size: var(--t-meta); color: var(--text-2);
  white-space: nowrap; }
.cp-pouls-m b { font-weight: var(--fw-fort); color: var(--text); }
.cp-pouls-m.zero, .cp-pouls-m.zero b { color: var(--text-3);
  font-weight: var(--fw-moyen); }
/* ⚠️ L'AIR ENTRE LE HAUT ET LES CARTES (Amadou, 04/09 : « espace un peu plus »). La
   barre et sa phrase forment UN groupe — 10 px entre elles — et c'est le groupe entier
   qui s'écarte des cartes. Poser la marge sur la phrase seule laisserait les cartes
   collées au jour où elle ne s'affiche pas. */
.cp-barre-sous { margin: 0; }
#cp-vend-corps { margin-top: var(--e-24); }

.cp-vie-qui { display: flex; align-items: center; gap: var(--e-10); min-width: 0; }
.cp-vie-txt { min-width: 0; }
.cp-vie-p { font-weight: var(--fw-fort); font-size: var(--t-small);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-vie-m { font-size: var(--t-meta); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.cp-vie-mil { min-width: 0; }
/* Les cinq temps : né · installé · vérifié · chauffé · au travail. */
.cp-vie-frise { display: flex; align-items: center; gap: var(--e-4); }
.cp-vie-cran { height: var(--e-4); flex: 1; border-radius: var(--r-micro); background: var(--border); }
.cp-vie-cran.fait { background: var(--green); }
.cp-vie-cran.ici { background: var(--amber); }
.cp-vie-mot { font-size: var(--t-meta); color: var(--text-2); margin-top: var(--e-6);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cp-vie-mot.attend { color: var(--amber); }
.cp-vie-mot.sorti { color: var(--red); }

.cp-vie-ou { font-size: var(--t-mini); color: var(--text-2); line-height: var(--lh-serre);
  font-variant-numeric: tabular-nums; }
.cp-vie-ou .s { color: var(--text-3); }

.cp-vie-signal { text-align: right; font-size: var(--t-meta);
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.cp-vie-signal .pt { display: inline-block; width: var(--e-6); height: var(--e-6);
  border-radius: 50%; margin-right: var(--e-6); }
.cp-vie-signal.ok { color: var(--green); }
.cp-vie-signal.ok .pt { background: var(--green); }
.cp-vie-signal.tiede { color: var(--amber); }
.cp-vie-signal.tiede .pt { background: var(--amber); }
.cp-vie-signal.ko { color: var(--text-3); }
.cp-vie-signal.ko .pt { background: var(--red); }

/* ⚠️ À l'étroit, la ligne s'empile au lieu de se serrer. Quatre colonnes sur un
   écran de portable donnent quatre colonnes illisibles — vérifié aux deux largeurs. */
@media (max-width: 60rem) {
  .cp-vie { grid-template-columns: 1fr; gap: var(--e-8); }
  .cp-vie-signal { text-align: left; }
}

.cp-lg-grille {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--cp-lg-w, 240px), 1fr));
  gap: var(--e-10);
}
.cp-lg {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--e-8);
  min-width: 0;
  padding: var(--e-10);
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  /* ⚠️ UN FOND PLEIN, PAS UN VOILE. Amadou (22/08) : « les cards des comptes doivent être
     moins transparentes ». Le dégradé de voile montait à 0,042 d'opacité — sur les fonds
     très sombres, la languette se confondait avec la page. `--bg-card-solid` est le fond
     de carte du thème, opaque : la languette devient un objet posé, pas une zone teintée.
     Le voile reste PAR-DESSUS, très léger, pour garder le grain des cartes du site. */
  background: linear-gradient(158deg, rgba(var(--th-voile),0.05) 0%, rgba(var(--th-voile),0.015) 55%),
              var(--bg-card-solid);
  box-shadow: 0 var(--e-4) var(--e-18) calc(var(--e-12) * -1) rgba(var(--th-ombre),0.55),
              inset 0 1px 0 var(--bg-sidebar);
  /* ⚠️ On énumère les PROPRIÉTÉS, pas des durées virgulées : chaque valeur virgulée d'un
     `transition` est une transition complète (leçon des « 82 virgules »). */
  transition: border-color var(--d-fast) var(--c-pose), background var(--d-fast) var(--c-pose),
              transform var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
/* ⚠️ LE SURVOL EST CELUI DE LA BIBLIOTHÈQUE, AU PIXEL PRÈS. Amadou : « quand on les
   survole il doit y avoir une animation comme dans la bibliothèque ». J'avais retiré le
   soulèvement en croyant calmer l'écran — mais un geste appris à un endroit doit se
   comporter pareil partout : trois pixels de montée, la même ombre projetée, le même
   liseré violet. On copie `.lib-card:hover`, on n'en invente pas une variante.
   ⚠️ `z-index` sur la languette survolée : sans lui, la bulle du point passerait SOUS la
   languette voisine, qui est elle aussi positionnée. */
.cp-lg:hover {
  border-color: var(--violet-mid);
  transform: translateY(-3px);
  /* 34 px de flou, comme `.lib-card:hover` — composé depuis l'échelle, jamais écrit brut. */
  box-shadow: 0 var(--e-16) calc(var(--e-16) * 2 + var(--e-2)) calc(var(--e-14) * -1) rgba(var(--th-accent-rgb),0.5),
              inset 0 1px 0 var(--bg-elevated);
  z-index: 3;
}

.cp-lg-haut { display: flex; align-items: center; gap: var(--e-8); min-width: 0; }
.cp-lg-av {
  width: var(--e-28); height: var(--e-28); flex: 0 0 auto;
  border-radius: var(--r-pilule); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--violet-tint); color: var(--text-2);
  font-size: var(--t-mini); font-weight: var(--fw-moyen);
}
.cp-lg-av img { width: 100%; height: 100%; object-fit: cover; }
.cp-lg-txt { min-width: 0; }
/* Le pseudo Vinted d'abord, et en grand : c'est le nom de l'objet regardé. */
.cp-lg-p { font-size: var(--t-meta); color: var(--text-1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* La modèle en dessous, en petit : elle n'est que l'habit que ce compte porte. */
.cp-lg-m { font-size: var(--t-mini); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.cp-lg-bas { display: flex; align-items: center; gap: var(--e-4); min-width: 0; }
/* ⚠️ LA LIGNE DU BAS EST MUETTE DE COULEUR. Amadou : « il y a trop de couleurs ».
   Le profil n'a plus de cadre : sur 240 px, un chip encadré se disputait l'œil avec le
   point d'état. La seule couleur de la languette, c'est le point. */
.cp-lg-c { font-size: var(--t-mini); color: var(--text-3); flex: 0 0 auto; }

/* ═══ LE POINT SUR LA BORDURE ════════════════════════════════════════════════
   Amadou : « juste un point sur la bordure à droite du compte pour remplacer les
   écriteaux muettes, endormies. Et quand je survole le point, ça met en plus grand
   muette. »
   ⚠️⚠️ LE MOT NE S'ÉCRIT JAMAIS SUR LA COULEUR. La bulle qui s'ouvre est NEUTRE et le
   point coloré reste à côté : les huit teintes d'état sont illisibles sur les cinq
   thèmes clairs (mesuré : 1,95 à 3,49 pour un seuil de 4,5). Poser le libellé dessus
   aurait ramené ce défaut ici.
   ⚠️⚠️⚠️ ET LE FOND DE LA BULLE EST OPAQUE (`--bg-card-solid`), PAS UN VOILE.
   `--bg-elevated` est un rgba à 0,06 : la bulle aurait laissé voir la languette d'à
   côté par transparence. C'est la leçon « les fonds mentent selon la clarté » — un voile
   n'est pas un fond, il ne fait que teinter ce qu'il y a dessous. */
/* ⚠️ EN HAUT À DROITE, SURÉLEVÉE — EXACTEMENT COMME CELLE DE LA BIBLIOTHÈQUE.
   Amadou (22/08) : « elle doit se surélever comme dans la bibliothèque ».
   J'avais fabriqué autre chose : un petit jeton à fond opaque, débordant des deux bords.
   Ça se détachait, mais ce n'était pas le même objet — et deux pastilles différentes pour
   la même idée, c'est deux choses à apprendre au lieu d'une.
   Le relief de la Bibliothèque, c'est un ANNEAU sombre autour du disque, plus une ombre
   portée : le point a l'air posé PAR-DESSUS. On le reprend tel quel, et du coup la
   pastille rentre DANS le coin (comme là-bas, à 6 px des bords) au lieu de déborder —
   c'est ce débordement qui m'interdisait l'anneau, puisque sa moitié extérieure aurait
   fait une tache sur le fond de la page.
   ⚠️ L'anneau de la Bibliothèque est écrit en dur (`rgba(6,8,12,0.45)`). Ici il passe par
   `--th-ombre` : même rendu sur les thèmes sombres, et il s'éclaircit sur les cinq thèmes
   clairs au lieu d'y poser une bague noire. */
.cp-lg-pt {
  position: absolute; top: var(--e-6); right: var(--e-6);
  display: flex; align-items: center; justify-content: flex-end;
  border-radius: var(--r-pilule);
  transition: background var(--d-fast) var(--c-pose), box-shadow var(--d-fast) var(--c-pose);
}
.cp-lg-pt-d {
  width: var(--e-10); height: var(--e-10); border-radius: var(--r-pilule); flex: 0 0 auto;
  box-shadow: 0 0 0 var(--e-2) rgba(var(--th-ombre),0.45),
              0 var(--e-1) var(--e-4) rgba(var(--th-ombre),0.35);
}
.cp-lg-pt-l {
  max-width: 0; padding: 0; opacity: 0;
  overflow: hidden; white-space: nowrap;
  font-size: var(--t-mini); color: var(--text-1);
  transition: max-width var(--d-fast) var(--c-pose), opacity var(--d-fast) var(--c-pose),
              padding var(--d-fast) var(--c-pose);
}
/* Au survol, le mot sort dans une bulle NEUTRE posée à gauche du point. Le point garde
   son anneau : c'est lui qu'on suit des yeux, il ne doit pas changer d'aspect. */
.cp-lg-pt:hover {
  background: var(--bg-card-solid);
  box-shadow: 0 var(--e-4) var(--e-12) calc(var(--e-4) * -1) rgba(var(--th-ombre),0.75);
  z-index: 6;
}
.cp-lg-pt:hover .cp-lg-pt-l {
  max-width: calc(var(--e-20) * 6); opacity: 1;
  padding: 0 var(--e-6) 0 var(--e-8);
}

.cp-lg-corps { display: block; }
/* ⚠️ Le champ est celui de la Bibliothèque, repris tel quel : même dessin, même geste. */
.cp-vend-rech { margin-bottom: var(--e-12); max-width: calc(var(--e-20) * 18); }
/* Le dernier signe de vie, aligné à droite et en chiffres de même chasse : c'est la
   colonne qu'on lit en diagonale pour repérer une session en train de mourir. */
.cp-lg-t { font-size: var(--t-mini); color: var(--text-3); margin-left: auto; flex: 0 0 auto; font-variant-numeric: tabular-nums; }

.cp-lg-bande {
  display: flex; align-items: baseline; gap: var(--e-8);
  padding: var(--e-14) var(--e-2) var(--e-8);
  border-top: 1px solid var(--border);
}
.cp-lg-bande.premiere { border-top: none; padding-top: var(--e-4); }
.cp-lg-bande-nom { font-size: var(--t-base); color: var(--text-1); }
.cp-lg-bande-n { font-size: var(--t-mini); color: var(--text-3); }
.cp-lg-pied { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-14); }

/* ⚠️ LE VISAGE D'UNE PANNE DE LECTURE. Amadou (22/08) : « dans la bibliothèque j'appuie
   sur vendeuse, rien ne s'affiche et rien ne semble se charger ». Une grille vide est le
   pire des messages : elle dit « il n'y en a pas » alors que le vrai sens est « je n'ai
   pas pu demander ». Ce bloc dit la panne, la nomme, et offre de recommencer. */
.lib-panne {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: center; gap: var(--e-10);
  padding: var(--e-32) var(--e-20);
  text-align: center;
}
.lib-panne-t { font-size: var(--t-body); color: var(--text-1); }
.lib-panne-d { font-size: var(--t-base); color: var(--text-2); max-width: 46ch; line-height: var(--lh-normal); }

/* ═══ LA RANGÉE ROBES / VENDEUSES : UNE SEULE HAUTEUR ════════════════════════
   Amadou (22/08) : « la barre contenant Robes et Vendeuses ainsi que les boutons à
   droite doit faire la même taille, et les boutons sont trop collés au-dessus ».
   ⚠️ MESURÉ, TROIS HAUTEURS DIFFÉRENTES DANS LA MÊME RANGÉE :
     · le groupe Robes/Vendeuses ~40 px (4 px de cadre + 6+6 de bouton + le texte)
     · « Sélectionner »            38 px
     · le rangement et le chevron  34 et 32 px
   Aucune n'était fausse toute seule ; c'est leur voisinage qui l'était.
   ⚠️ 38 px N'EST PAS UN CHIFFRE CHOISI ICI : c'est la hauteur de commande déjà employée
   par le champ de recherche juste au-dessus, par les boutons de l'Atelier et par la
   bascule de la fiche robe. On s'aligne sur l'existant au lieu d'inventer un quatrième
   étalon — et « Sélectionner » n'a même pas besoin d'être touché, il l'avait déjà. */
.lib-filters { padding: var(--e-4); align-items: center; }
.lib-filters .lib-filter { height: 30px; padding: 0 var(--e-12); }
.lib-filters .lib-filter-add-btn { height: 30px; }
/* (la seconde des deux règles retirées le 25/08 — voir plus haut) */
.lib-filters-row-right .lib-filters-collapse { width: 38px; height: 38px; }
.lib-filters-row-right .identite-btn { height: 38px; }

/* ⚠️ ET DE L'AIR AU-DESSUS. La rangée démarrait à 14 px du bord haut de sa barre — assez
   pour que les boutons semblent posés contre le titre. On passe à 22 px : le même écart
   que celui qui sépare déjà la barre du contenu en dessous, donc la rangée respire de
   la même façon des deux côtés au lieu d'être poussée vers le haut. */
.lib-sticky-bar { padding-top: var(--e-22); }

/* ═══ L'ÉTIQUETTE « INCOMPLET » : PLUS PETITE, ET ELLE MÈNE QUELQUE PART ═════
   Amadou (22/08) : « les robes incomplètes doivent avoir une étiquette plus petite et
   discrète, et quand on appuie dessus on doit voir une bulle de couleur dans la partie
   où il manque des infos ».
   ⚠️ ELLE ÉTAIT UN BLOC PLEIN D'ORANGE OPAQUE (0,88) posé sur la photo, en gras, avec un
   chiffre. Sur une grille de vingt-neuf robes dont la moitié est incomplète, ça faisait
   une rangée de pastilles criardes. Elle devient un simple rond : le triangle seul, sans
   chiffre — le compte exact se lit dans la fiche, où il est ACTIONNABLE.
   ⚠️ Et elle reprend `pointer-events` : c'est un bouton maintenant, plus une décoration. */
/* ⚠️ ELLES VIVENT DANS `.lib-card-coin`, la colonne des cartes de vendeuses — donc en
   flux, l'une SOUS l'autre. Elles se posaient toutes les deux dans le même coin en
   absolu (7 px et 8 px), et celle du dessus masquait l'autre : une robe à la fois
   incomplète et épuisée ne montrait jamais qu'elle était épuisée. */
.lib-card-coin .lib-card-incomplete-badge,
.lib-card-coin .lib-card-stock-badge { position: static; top: auto; left: auto; }

/* ⚠️ 14 px, et c'est le TROISIÈME essai. 18 px puis « toujours trop gros » : sur une
   vignette de 186 px de large, une pastille de 18 px pèse un dixième de la largeur de la
   photo. À 14 px elle se voit sans se regarder — et le glyphe descend à 8 px, mesuré
   dans le HTML puisqu'un `<svg width=…>` ignore la feuille de style. */
.lib-card-incomplete-badge {
  width: var(--e-14); height: var(--e-14);
  padding: 0;
  gap: 0;
  justify-content: center;
  font-size: 0;                 /* le chiffre disparaît, l'icône reste */
  background: rgba(234, 88, 12, 0.55);
  border-color: transparent;
  pointer-events: auto;
  cursor: pointer;
  transition: background var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.lib-card-incomplete-badge:hover { background: rgba(234, 88, 12, 0.95); transform: scale(1.15); }

/* La pastille de stock suit la même échelle : deux tailles différentes dans une même
   colonne se liraient comme deux importances différentes, ce qui est faux. */
.lib-card-coin .lib-card-stock-badge {
  width: var(--e-14); height: var(--e-14);
  font-size: var(--t-micro);
}

/* La bulle posée sur la case vide, et la pastille sur l'onglet qui la contient.
   ⚠️ Le champ n'est pas repeint en orange : on l'ENTOURE. Colorer le fond d'un champ de
   saisie rendrait son texte illisible sur une partie des seize thèmes — la leçon du
   badge « ≈ 1 image », qui vient d'être payée. */
.robe-manque {
  position: relative;
  border-radius: var(--r-md);
  box-shadow: 0 0 0 2px rgba(234, 88, 12, 0.75);
}
.robe-manque::after {
  content: '';
  position: absolute; top: calc(var(--e-6) * -1); right: calc(var(--e-6) * -1);
  width: var(--e-10); height: var(--e-10);
  border-radius: var(--r-pilule);
  background: rgb(234, 88, 12);
  box-shadow: 0 0 0 var(--e-2) rgba(var(--th-ombre),0.45);
}
.robe-onglet-manque {
  display: inline-block; margin-left: var(--e-6);
  width: var(--e-6); height: var(--e-6);
  border-radius: var(--r-pilule);
  background: rgb(234, 88, 12);
}

/* ⚠️⚠️ LE RANGEMENT DES VENDEUSES RENDAIT LA BARRE PLUS HAUTE DE DIX PIXELS.
   Amadou (22/08) : « la barre latérale ne fait pas la même taille dans la partie robes
   et modèles ». Mesuré : `#lib-vend-etats` est un `.lib-tier-bar` — un cadre avec 1 px
   de bordure et 4 px de marge intérieure — qui ENTOURE un bouton déjà haut de 38 px.
   Total : 48 px, contre 38 pour « Filtres » et « Sélectionner ». La rangée Vendeuses
   était donc plus haute que la rangée Robes, et tout l'écran descendait de dix pixels au
   changement de rayon.
   Ce cadre a un sens là où `.lib-tier-bar` sert vraiment de barre d'onglets (les gammes
   des robes) ; ici il n'entoure qu'un seul bouton, qui porte déjà sa propre bordure.
   Deux cadres imbriqués pour un contrôle : on retire l'extérieur. */
.lib-filters-row-right .lib-tier-bar {
  background: none;
  border: none;
  padding: 0;
  align-self: center;
}

/* ⚠️ LE CURSEUR DIT QUE LA BULLE SE SAISIT. Amadou (22/08) : « je dois pouvoir, en
   restant appuyé sur un coloris, le changer de place ». Le geste existait, mais la bulle
   affichait `cursor: pointer` — la main qui clique, pas celle qui attrape. Rien n'invitait
   à rester appuyé : il fallait le deviner.
   ⚠️ `:active` est posé sur la bulle ENTIÈRE, pas seulement pendant le glissement HTML5 :
   la main se referme dès qu'on presse, avant même que le navigateur décide qu'il s'agit
   d'un glisser. C'est ce délai-là qui fait croire que rien ne se passe. */
.dress-color-chip { cursor: grab; }
.dress-color-chip:active { cursor: grabbing; }
/* Pendant l'échange, la bulle visée grandit d'un cheveu : elle ne dit plus « insère ici »
   mais « c'est avec celle-ci que tu permutes ». */
.dress-color-chip.drag-over { transform: scale(1.06); }

/* ── ATELIER SUR ÉCRAN BAS : on reprend la hauteur là où elle est perdue ────────
   Mesuré à 1280×720 : l'étape ne commençait qu'à 446 px du haut, dont 143 px de simples
   MARGES entre la frise, les boutons de mode et la première étape. Le contenu utile
   n'avait plus que 274 px. Le seuil est à 1000 px : un portable courant (1440×900) est
   concerné, un vrai grand écran non — il a la place de respirer.
   ⚠️ `max-height` et pas `max-width` : c'est une contrainte de HAUTEUR. Sur un portable
   1440×810 le problème existe, sur un 1280×1600 non — la largeur n'y est pour rien.
   ⚠️⚠️ CE BLOC EST EN FIN DE FEUILLE, ET CE N'EST PAS UN DÉTAIL. Placé plus haut, il
   perdait contre `.atelier-mode-switch { margin: 0 0 var(--e-18) }` déclaré après lui :
   même spécificité, c'est le DERNIER écrit qui gagne. Mesuré — la marge restait à 18 px
   alors que la règle demandait 10. */
@media (max-height: 1000px) {
  #topbar-atelier { padding-top: var(--e-10); padding-bottom: var(--e-10); }
  #topbar-atelier .topbar-subtitle { display: none; }   /* « Crée un modèle en 7 étapes » : lu une fois
                                                            à la découverte, il coûte une ligne à chaque visite */
  .atelier-progress { padding: var(--e-10) var(--e-8); }
  .atelier-mode-switch { margin: 0 0 var(--e-10); }
  .atelier-mode-btn { padding: var(--e-8) var(--e-12); }
  .atelier-steps { gap: var(--e-10); margin-top: var(--e-10); }
  .atelier-hint { padding: var(--e-8) var(--e-10); line-height: var(--lh-serre); }
}

/* ═══ PREMIER ÉTAGE DE LA BIBLIOTHÈQUE : LES NICHES ══════════════════════════
   Cet étage ne fait qu'une chose — choisir ce qu'on vend. Ses cartes sont donc plus
   grandes et plus rares que celles d'un catalogue : on en voit quatre, pas trente.
   ⚠️ LA CARTE EST UNE IMAGE, PAS UNE FICHE. Amadou (23/08) : « le fait qu'il y ait un
   paragraphe, un espace, ce n'est vraiment pas beau ». Le nom et les comptes vivaient
   SOUS la photo, sur deux lignes séparées par une marge — trois blocs empilés pour dire
   une chose. Ils sont maintenant POSÉS sur le voile du bas de la photo : un seul objet,
   et la carte se lit d'un coup. */
/* ⚠️ `#lib-niches` N'EST PLUS LA GRILLE, C'EST LE CONTENEUR. Depuis le rangement par
   famille il porte une barre, des titres de rayon et PLUSIEURS grilles ; le laisser en
   `display:grid` aurait aligné les titres comme des cartes. */
.lib-niches { display: block; margin-top: var(--e-4); }
.lib-niches-grille {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
  gap: var(--e-16);
  margin-bottom: var(--e-32);
}

/* ══ LES CARTES DE FAMILLES ════════════════════════════════════════════════════
   Amadou (01/09) : « on va plutôt passer sur l'idée de faire des cartes où on va mettre
   des logos, stylisé comme pour les niches ».
   ⚠️ MÊME FORMAT QUE LA CARTE DE NICHE — 4/5, même grille, même animation d'entrée. Une
   famille n'a pas de photo de produit : son LOGO est son image, et c'est tout le dessin. */
.lib-fam-carte {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--e-16);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-card-solid);
  font-family: inherit;
  cursor: pointer;
  box-shadow: 0 var(--e-4) var(--e-18) calc(var(--e-12) * -1) rgba(var(--th-ombre),0.55);
  transition: border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose),
              box-shadow var(--d-fast) var(--c-pose);
  animation: velbo-entree var(--t-long) var(--pose) backwards;
  animation-delay: calc(var(--rang, 0) * 55ms);
}
@media (prefers-reduced-motion: reduce) { .lib-fam-carte { animation: none; } }
.lib-fam-carte::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 80% at 50% 12%,
              rgba(var(--th-accent-rgb), .09), transparent 62%);
}
.lib-fam-carte:hover { border-color: var(--violet-mid); transform: translateY(calc(var(--e-2) * -1)); }

/* L'emplacement du logo : grand, au centre, et VIDE tant qu'Amadou n'a pas posé le sien.
   ⚠️ Rien n'est dessiné à sa place — une icône par défaut serait à refaire. */
.lib-fam-carte-logo {
  position: relative;
  width: var(--e-48);
  height: var(--e-48);
  margin-bottom: var(--e-16);
  border-radius: var(--r-carte);
  border: 1.5px dashed var(--border-strong);
  background: rgba(var(--th-voile), .03);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-3);
  font-size: var(--t-lead);
  font-weight: var(--fw-normal);
  line-height: var(--lh-un);
}
/* ⚠️ LE CARRÉ CESSE D'ÊTRE EN POINTILLÉS DÈS QU'IL PORTE UN DESSIN : les pointillés
   disaient « il manque quelque chose ici », et ce n'est plus vrai. */
.lib-fam-carte-logo:has(svg) { border-style: solid; border-color: var(--border); }
.lib-fam-carte-logo svg {
  width: 60%;
  height: 60%;
  color: var(--violet-soft);
}
.lib-fam-carte--vide .lib-fam-carte-logo svg { color: var(--text-3); }
.lib-fam-carte-logo img { width: 100%; height: 100%; object-fit: contain; border-radius: inherit; }
.lib-fam-carte-nom {
  position: relative;
  font-size: var(--t-body);
  font-weight: var(--fw-fort);
  line-height: var(--lh-titre);
  color: var(--text);
}
.lib-fam-carte-n {
  position: relative;
  margin-top: var(--e-6);
  font-size: var(--t-meta);
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
/* ⚠️ UNE FAMILLE SANS NICHE RESTE AFFICHÉE, EN RETRAIT. La cacher ferait un mur plus
   propre, mais Amadou ne saurait plus où il n'a pas encore posé de niche. */
.lib-fam-carte--vide {
  background: transparent;
  border-style: dashed;
  box-shadow: none;
}
.lib-fam-carte--vide .lib-fam-carte-nom { color: var(--text-2); font-weight: var(--fw-moyen); }
.lib-fam-carte--vide .lib-fam-carte-n { color: var(--text-3); }
/* « À ranger » n'est PAS une famille : c'est un rappel, et il ne ressemble pas aux autres. */
.lib-fam-carte--ranger { border-color: var(--violet-mid); background: var(--surface-2); }
.lib-fam-carte--ranger .lib-fam-carte-logo {
  border-style: solid;
  border-color: var(--violet-mid);
  color: var(--violet-soft);
  font-size: var(--t-title);
  font-weight: var(--fw-gras);
}
.lib-fam-carte--ranger .lib-fam-carte-n { color: var(--violet-soft); }

/* Le fil du deuxième étage. */
.lib-fam-fil {
  display: flex;
  align-items: center;
  gap: var(--e-8);
  margin: 0 0 var(--e-16);
  font-size: var(--t-base);
  color: var(--text-3);
}
.lib-fam-retour {
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  color: var(--text-2);
  cursor: pointer;
  transition: var(--transi);
}
.lib-fam-retour:hover { color: var(--violet-soft); }
.lib-fam-sep { color: var(--text-3); }
.lib-fam-fil b { color: var(--text); font-weight: var(--fw-fort); }
.lib-fam-vide {
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
  padding: var(--e-20);
  margin-bottom: var(--e-16);
  color: var(--text-3);
  font-size: var(--t-base);
  text-align: center;
}

/* La carte « + Nouvelle niche », en dernière case du deuxième étage. */
/* ⚠️ `.lib-niche` EST EN `display:block` AVEC UN CONTENU POSÉ EN BAS — c'est ce qui fait
   qu'une carte de niche montre son titre sur la photo. La carte « Nouvelle niche » n'a pas
   de photo : sans forcer le centrage, le « + » et le mot restaient collés en haut à gauche.
   Amadou (01/09) : « le texte ainsi que le plus ne sont pas centrés ». */
/* ⚠️⚠️⚠️ ELLE DEMANDAIT DÉJÀ LA TRANSPARENCE, ET NE L'OBTENAIT PAS. `background:
   transparent` et `box-shadow: none` étaient écrits ici depuis toujours — mais la règle
   `.lib-niche` est écrite PLUS BAS dans la feuille, à spécificité égale (une classe
   contre une classe), et repose donc `background: var(--bg-card-solid)` et son ombre
   par-dessus. La carte d'ajout portait ainsi le plein habillage d'une vraie niche.
   Amadou (02/09) : « je veux qu'elle soit plus transparente ».
   ⚠️ On ne DÉPLACE pas la règle, on la rend plus PRÉCISE — deux classes contre une, ce
   qui la met hors d'atteinte de l'ordre d'écriture. Déplacer aurait marché aujourd'hui
   et cassé au premier bloc ajouté en dessous.
   ⚠️ Un voile très léger plutôt que rien du tout : à zéro, le pointillé flotte sur le
   décor du thème et la case cesse de se lire comme une carte qu'on peut viser. */
.lib-niche.lib-niche--neuve {
  border-style: dashed;
  border-color: var(--border-strong);
  background: rgba(var(--th-voile), .022);
  box-shadow: none;
  display: flex !important;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--e-16);
  color: var(--text-3);
  font-family: inherit;
  font-size: var(--t-base);
}
.lib-niche.lib-niche--neuve > span {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-6);
}
/* ⚠️ LE DESSIN, PAS UN GLYPHE. C'était un `+` écrit en toutes lettres ; le projet n'écrit
   aucun caractère de ce genre dans l'interface. Un seul dessinateur (`_carteNouvelleNiche`)
   sert la Bibliothèque ET l'Atelier — ils divergeaient, et ça se voyait. */
.lib-niche.lib-niche--neuve svg {
  width: var(--e-24); height: var(--e-24);
  color: var(--violet-soft);
}
.lib-niche.lib-niche--neuve em { font-style: normal; }
.lib-niche {
  position: relative;
  display: block;
  padding: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  text-align: left; font-family: inherit; cursor: pointer;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-card-solid);
  box-shadow: 0 var(--e-4) var(--e-18) calc(var(--e-12) * -1) rgba(var(--th-ombre),0.55);
  transition: border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose),
              box-shadow var(--d-fast) var(--c-pose);
}
/* ⚠️⚠️ `backwards`, JAMAIS `both`. `.lib-niche` porte déjà un `transform` au survol :
   avec `both`, l'animation GARDE son état final (`transform: none`) après la fin et le
   survol ne peut plus soulever la carte. `backwards` ne tient que l'état de DÉPART,
   pendant le délai — l'arrivée est décalée, et le survol reste vivant.
   ⚠️ Le décalage vient de `--rang`, posé par app.js sur chaque carte. Sans lui toutes
   les cartes arriveraient ensemble, ce qui se lit comme un affichage brusque — c'est
   exactement ce qu'Amadou a signalé le 23/08 : « il n'y a pas d'animation, c'est
   brusque ». Même pas de 55 ms que les autres listes du site. */
.lib-niche {
  animation: velbo-entree var(--t-long) var(--pose) backwards;
  animation-delay: calc(var(--rang, 0) * 55ms);
}
@media (prefers-reduced-motion: reduce) { .lib-niche { animation: none; } }

/* ⚠️ LE MENU OUVERT COMPTE COMME UN SURVOL — même règle, pas une copie. Le survol
   s'arrête dès qu'on entre dans le menu : la carte s'éteignait au moment précis où l'on
   choisissait ce qu'on allait lui faire. Écrire un second bloc identique serait la
   garantie qu'un jour les deux ne se ressembleront plus. */
.lib-niche:not(.lib-niche--on):not(.selected):hover, .lib-niche.velbo-menu-cible {
  border-color: var(--border-mid);
  transform: translateY(-3px);
  box-shadow: 0 var(--e-16) calc(var(--e-16) * 2 + var(--e-2)) calc(var(--e-14) * -1) rgba(var(--th-accent-rgb),0.5);
}
.lib-niche-img { position: absolute; inset: 0; }
.lib-niche-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Niche encore vide : le dessin au trait reprend sa place, centré.
   ⚠️ Il porte `currentColor` — un trait figé en violet serait illisible sur les cinq
   thèmes clairs (leçon du badge « ≈ 1 image »). */
.lib-niche-img.vide {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--bg-hover) 0%, rgba(var(--th-voile),0.015) 100%);
  color: var(--text-3);
}
.lib-niche:not(.lib-niche--on):not(.selected):hover .lib-niche-img.vide,
.lib-niche.velbo-menu-cible .lib-niche-img.vide { color: var(--violet-mid); }

/* ⚠️⚠️ LE VOILE EST OPAQUE EN BAS, ET C'EST OBLIGATOIRE. Le texte est posé sur une PHOTO
   qu'on ne choisit pas : elle peut être blanche, dorée, claire. Sans un fond franc
   dessous, le nom disparaîtrait sur une robe jaune et resterait lisible sur une noire —
   le pire des défauts, celui qui ne se voit qu'une fois sur deux.
   ⚠️ `--sur-sombre` est LE jeton du texte sur un voile noir (mesuré 6,92 au pire des
   seize thèmes). Ni `--text-1`, qui suit le thème et devient noir sur les thèmes clairs,
   ni un `#fff` en dur, qui ne dirait pas pourquoi. */
.lib-niche-bas {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--e-24) var(--e-14) var(--e-12);
  background: linear-gradient(to top, rgba(var(--th-ombre),0.86) 30%, rgba(var(--th-ombre),0) 100%);
  color: var(--sur-sombre);
}
.lib-niche-nom { font-size: var(--t-body); font-weight: var(--fw-moyen); line-height: var(--lh-un); }
.lib-niche-n   { font-size: var(--t-mini); opacity: .82; margin-top: var(--e-4); }

/* La carte d'ajout : même gabarit, en pointillés — elle est de la même famille. */
.lib-niche--plus {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--e-8);
  border-style: dashed; border-color: var(--border-strong);
  background: none; box-shadow: none;
  color: var(--text-3); font-size: var(--t-base);
}
.lib-niche--plus:hover { border-color: var(--violet-mid); color: var(--text-1); transform: none; box-shadow: none; }

/* ═══ LA LIGNE DU FIL, ENTRE LES DEUX BARRES ═════════════════════════════════
   Amadou (23/08) : « mets le bouton retour entre le bouton Bibliothèque et Ses
   produits ». Deux places essayées avant : dans la rangée des onglets, où il les décalait
   de sa largeur ; puis dans le fil d'Ariane du haut, trop loin de ce qu'on quitte.
   ⚠️ Elle est DISCRÈTE : c'est un chemin, pas une commande. Si elle pesait autant que les
   onglets, on aurait trois barres de boutons empilées sur le même écran. */
.lib-fil {
  display: flex; align-items: center; gap: var(--e-8);
  padding: 0;
  font-size: var(--t-meta); color: var(--text-3);
}
/* ⚠️ Le fil POUSSE, les deux boutons tiennent le bord. Il avait sa propre ligne, et son
   `padding-bottom` la creusait encore : une ligne pleine pour trois mots, et les produits
   d'autant plus bas. Sur la même rangée, il prend la place qui reste. */
.lib-filters-row .lib-fil { flex: 1; min-width: 0; }
.lib-fil-back {
  display: inline-flex; align-items: center; gap: var(--e-4);
  background: none; border: none; padding: 0;
  font-family: inherit; font-size: var(--t-meta); color: var(--text-2);
  cursor: pointer;
  transition: color var(--d-fast) var(--c-pose);
}
.lib-fil-back:hover { color: var(--text-1); }
.lib-fil-sep { color: var(--text-3); }
.lib-fil-ici { color: var(--text-1); }

/* ═══ CHOISIR L'IMAGE D'UNE NICHE ════════════════════════════════════════════ */
.niche-img-card { max-width: 560px; width: 92vw; }
.niche-img-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: var(--e-8);
  max-height: 46vh; overflow-y: auto;
  padding: var(--e-4) 0;
}
.niche-img-choix {
  padding: 0; border: 2px solid transparent; border-radius: var(--r-sm);
  overflow: hidden; cursor: pointer; background: none; aspect-ratio: 3 / 4;
  transition: border-color var(--d-fast) var(--c-pose), transform var(--d-fast) var(--c-pose);
}
.niche-img-choix img { width: 100%; height: 100%; object-fit: cover; display: block; }
.niche-img-choix:hover { border-color: var(--violet-mid); transform: scale(1.04); }
/* ⚠️ Celle qui est POSÉE se distingue par un cadre plein, pas par une opacité : baisser
   l'opacité d'une vignette la rend simplement moins nette, pas « choisie ». */
.niche-img-choix.on { border-color: var(--violet); }
/* ⚠️ L'INTERTITRE TRAVERSE LA GRILLE. Sans `grid-column: 1 / -1`, il occuperait une seule
   case de 76 px et se lirait comme une vignette de texte coincée entre deux photos. */
.niche-img-separe {
  grid-column: 1 / -1;
  padding: var(--e-10) 0 var(--e-2);
  border-top: 1px solid var(--border);
  margin-top: var(--e-4);
}
.niche-img-grille > .niche-img-separe:first-child { border-top: 0; margin-top: 0; padding-top: 0; }

/* ═══ CATÉGORIE ET COLORIS NE SE LAISSENT PLUS ÉCRASER ═══════════════════════
   Amadou (23/08) : « dans la partie robe, la partie catégorie et coloris, c'est coupé ».
   ⚠️ LA CAUSE N'EST PAS UNE LARGEUR TROP PETITE, C'EST UNE PERMISSION DE RÉTRÉCIR.
   `.dress-prix-ligne .dress-field:has(> select) { min-width: 0 }` autorise un champ à
   descendre SOUS la taille de son contenu ; le groupe de droite porte `flex: 0 1 auto`,
   donc il rétrécit AVANT de passer à la ligne. Résultat : les libellés se coupent au
   lieu de descendre d'une ligne — et les catégories Vinted sont longues, jusqu'à
   « ↳ Occasions · Robes de bal de fin d'année ».
   ⚠️ On garde `min-width: 0` pour tout le reste — il est là pour empêcher un `select`
   trop large de faire déborder la ligne entière, et c'est toujours vrai. On pose
   seulement un PLANCHER sur le groupe Vinted : sous cette largeur, il descend.
   La ligne a déjà `flex-wrap: wrap` : elle savait passer à la ligne, on ne lui en avait
   jamais laissé l'occasion. */
.dress-prix-groupe--fin { min-width: 272px; }
.dress-prix-groupe--fin .dress-field:has(> select) { min-width: 152px; }
/* ⚠️ 88 px ne suffisaient pas pour « Multicolore » ni « Bleu marine » — les deux coloris
   les plus courants d'Amadou. Le cadre garde sa hauteur de 38 px : c'est la largeur du
   texte qui manquait, pas la place. */
.dress-coloris { min-width: 236px; }
.dress-field .dress-coloris select { max-width: 104px; }

/* ═══ CATÉGORIE ET COLORIS : LE DÉROULANT MAISON, ET DES CHAMPS BORNÉS ═══════
   Amadou (23/08) : « la catégorie est beaucoup trop longue pour ce que c'est » et
   « quand je sélectionne, ça doit être dans la DA du site — là c'est une sélection
   type mac ».
   ⚠️ LE CHAMP N'A PLUS À ÊTRE AUSSI LARGE QUE SON PLUS LONG LIBELLÉ. C'était la raison
   d'être de sa largeur : « ↳ Occasions · Robes de bal de fin d'année » devait tenir dans
   le `<select>` fermé. Avec le déroulant maison, le libellé long vit dans la LISTE, qui
   s'ouvre par-dessus la page — le champ fermé peut donc être court et couper proprement
   (`text-overflow: ellipsis`, déjà porté par `.de-dd-val`). */
.dress-champ-court { flex: 0 1 auto; min-width: 176px; max-width: 232px; }

/* ⚠️ LE PANNEAU DU DÉROULANT SORT DE SON CADRE. Il est `position: absolute` dans un
   `.dress-coloris` haut de 38 px : sans cette ligne, la liste serait rognée par le cadre
   qui l'héberge — le défaut exact qu'Amadou signale sur la catégorie. */
.dress-coloris { overflow: visible; }
.dress-coloris .de-dd { flex: 1 1 0; min-width: 0; }
/* Dans le cadre partagé, le déclencheur perd son propre cadre : c'est l'encadré qui le
   porte pour les deux. Deux bordures imbriquées pour un contrôle, c'est ce qu'on retire
   partout depuis ce matin. */
.dress-coloris .de-dd-trigger {
  border: none; background: none; padding: 0 var(--e-2) 0 0;
  height: 100%; font-size: var(--t-meta);
}
/* La liste, elle, reprend une largeur lisible — les noms de couleurs sont courts mais le
   cadre partagé est étroit. */
.dress-coloris .de-dd-panel { min-width: 180px; right: auto; }

/* ⚠️⚠️ L'ALIGNEMENT PERDU : LA RÈGLE VISAIT UNE CIBLE QUI N'EXISTE PLUS.
   Amadou (23/08) : « la partie catégorie n'est pas alignée ». La cause est mon propre
   remplacement : `.dress-prix-ligne select { height: 38px }` imposait la hauteur — et je
   viens de retirer les `<select>`. Le déroulant maison prenait donc sa hauteur naturelle,
   quelques pixels de moins, et comme la rangée s'aligne par le BAS, son étiquette
   remontait d'autant.
   La hauteur suit maintenant le contrôle, pas la balise. C'est la même famille que le
   compteur et la grille : une règle qui décrit un moyen plutôt qu'une intention finit par
   ne plus rien décrire du tout. */
.dress-prix-ligne .de-dd-trigger { height: 38px; box-sizing: border-box; }

/* ⚠️ LE PANNEAU QUI S'OUVRE VERS LE HAUT. Amadou : « le panel doit s'ouvrir vers le
   haut ». Le JS décide du côté en mesurant la place restante — cette classe ne fait que
   poser le résultat. Forcer le haut en CSS aurait déplacé le problème sur les champs du
   haut de page. */
/* ⚠️⚠️ DEUX CLASSES, PAS UNE — ET C'EST TOUT LE SUJET.
   `.de-dd-panel--droite` seul pèse UNE classe. `.dress-coloris .de-dd-panel { right: auto }`
   en pèse DEUX : elle gagnait donc, quel que soit l'ordre dans le fichier, et le panneau
   continuait de déborder alors que le JS posait bien la classe.
   Amadou : « ba non, toujours pas, regarde, ça dépasse sur la droite encore ». Le
   correctif était juste ; il n'arrivait jamais jusqu'à l'écran.
   ⚠️ EN CSS, C'EST LA SPÉCIFICITÉ QUI TRANCHE, PAS LA POSITION DANS LE FICHIER. Écrit
   `.de-dd-panel.de-dd-panel--droite`, le modificateur pèse deux classes lui aussi — et
   comme il est écrit plus bas, il gagne l'égalité. C'est la troisième fois que ce piège
   se présente dans ce projet ; c'est la première fois qu'il coûte deux allers-retours. */
.de-dd-panel.de-dd-panel--haut { top: auto; bottom: calc(100% + 6px); }

/* ⚠️ LE PANNEAU S'ACCROCHE PAR LA DROITE quand il ne tient pas à gauche. Posé par le JS,
   qui mesure la place réelle — voir `_deDropdown`. Forcer ce côté en CSS casserait tous
   les déroulants qui, eux, ont la place. */
.de-dd-panel.de-dd-panel--droite { left: auto; right: 0; }

/* ⚠️ LE CADRE DU BANDEAU DE PRODUCTION, POSÉ HORS DE LA ZONE REDESSINÉE.
   Il n'a pas d'apparence propre : c'est `.an-repos`, à l'intérieur, qui la porte. Cette
   zone n'existe que pour donner au bandeau un nœud qui SURVIT aux redessins de l'écran —
   un cadre qui ne bouge jamais ne peut pas clignoter. */
.an-repos-zone { display: block; }
.an-repos-zone.hidden { display: none; }

/* ══════════════════════════════════════════════════════════════════════════════
   LES BOUTONS D'ACTION — TROIS NIVEAUX, ET PAS UN DE PLUS
   ══════════════════════════════════════════════════════════════════════════════
   Amadou, 2026-08-23 : « dans la bibliothèque de variables il y a beaucoup trop de
   boutons. Il faut des boutons pour les boutons principaux, les sous-boutons, les
   sous-sous-boutons, mais il ne faut pas chaque fois changer. »

   Le 30/07, la même plainte avait été réglée POUR LES ONGLETS (trois familles :
   sous-onglet, filtre, segment). Les boutons d'ACTION, eux, n'avaient jamais été
   repris. Mesuré le 23/08 en fabriquant chaque classe dans la page et en relevant ses
   propriétés CALCULÉES — pour le même travail, « le bouton principal de l'écran » :

     .btn-primary       40 px   rayon 8    texte 14   graisse 500
     .v-btn--pri        34 px   rayon 10   texte 13   graisse 500
     .batch-btn-launch  45 px   rayon 12   texte 14   graisse 700
     .atelier-gen-btn   40 px   rayon 10   texte 14   graisse 500
     .btn-generate      46 px   rayon 10   texte 16   graisse 500
     .mod-go-btn        48 px   rayon 12   texte 14   graisse 500
     .btn-save-views    43 px   rayon 10   texte 14   graisse 600

   Sept hauteurs, trois rayons, trois tailles de texte, quatre graisses.

   DEUX AXES, qu'il ne faut pas confondre :
     · LE NIVEAU dit l'IMPORTANCE — c'est la couleur qui le porte.
         1 · PRINCIPAL   l'action de l'écran. Une seule par zone. Teintée d'accent.
         2 · SOUS-BOUTON les autres actions. Neutre, bordé.
         3 · DISCRET     ce qui ne doit pas attirer l'œil. Nu, sans bordure.
     · LA TAILLE dit la DENSITÉ — `--lg` pour un héros, rien pour la norme, `--sm`
       pour une barre serrée. Un bouton discret peut être grand ; un principal, petit.

   ⚠️ ON N'INVENTE AUCUNE APPARENCE. Les trois niveaux reprennent EXACTEMENT ce que
   `.v-btn`, `.v-btn--pri` et `.v-btn--fantome` faisaient déjà : la bibliothèque
   existait, presque personne ne s'en servait. Le but est que tout le monde s'y range,
   pas que le site change de tête.

   ⚠️ CE BLOC EST À LA FIN DU FICHIER, EXPRÈS. À spécificité égale, c'est la dernière
   règle qui gagne : aucune ancienne règle n'a besoin d'être retirée, et aucun rendu
   JavaScript n'a à changer de classe. Même méthode que le bloc des onglets.

   ⚠️ LES BOUTONS-ICÔNE NE PRENNENT QUE LA COULEUR, jamais la géométrie : leur carré
   est leur raison d'être. Les forcer à `padding: 0 14px` les étirerait en rectangles.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── La géométrie commune : la même pour les trois niveaux ─────────────────── */
.btn-primary, .batch-btn-launch, .atelier-gen-btn, .btn-generate, .mod-go-btn,
.btn-save-views, .cok-launch-btn, .btn-secondary, .btn-action, .lib-bulk-btn,
.compte-w-btn, .identite-btn, .cok-msg-cbtn, .btn-ghost,
.btn-ghost--sm, .btn-danger-sm, .lib-io-btn, .lib-menu-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-6);
  /* ⚠️ `height: auto` D'ABORD. Six familles portaient une HAUTEUR FIXE (`.mod-go-btn`
     48 px, `.btn-generate` 46, `.batch-btn-launch` 45…) : un `min-height` ne peut pas
     rétrécir une hauteur fixe, il ne peut que l'agrandir. Sans cette ligne, la moitié
     des boutons gardaient leur taille d'avant et le rangement n'en était pas un. */
  height: auto;
  min-height: 34px;
  padding: var(--e-8) var(--e-14);
  border-radius: var(--r-md);
  font-family: inherit;
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
  line-height: var(--lh-un);
  letter-spacing: var(--ls-zero);
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-bref), color var(--t-bref), border-color var(--t-bref), transform var(--t-bref) var(--c-rebond);
}

/* La taille — l'autre axe. `--lg` garde leur présence aux boutons de lancement,
   sans leur rendre le droit d'avoir chacun la sienne. */
.batch-btn-launch, .btn-generate, .mod-go-btn, .atelier-gen-btn {
  min-height: 40px;
  padding: var(--e-10) var(--e-20);
  font-size: var(--t-small);
}
.btn-ghost--sm, .btn-action, .lib-bulk-btn, .btn-danger-sm, .lib-io-btn {
  min-height: 28px;
  padding: var(--e-4) var(--e-10);
  font-size: var(--t-meta);
}

/* ── 1 · PRINCIPAL — l'action de l'écran. Teintée d'accent. ────────────────── */
.btn-primary, .cok-btn.pri, .v-btn--pri, .batch-btn-launch, .atelier-gen-btn,
.btn-generate, .mod-go-btn, .btn-save-views, .cok-launch-btn.pri {
  background: var(--cok-accent-bg, rgba(var(--th-accent-rgb), .2));
  color: var(--violet-light);
  border: 1px solid rgba(var(--th-accent-rgb), .35);
}
.btn-primary:hover, .cok-btn.pri:hover, .v-btn--pri:hover, .batch-btn-launch:hover,
.atelier-gen-btn:hover, .btn-generate:hover, .mod-go-btn:hover,
.btn-save-views:hover, .cok-launch-btn.pri:hover {
  background: rgba(var(--th-accent-rgb), .3);
  border-color: rgba(var(--th-accent-rgb), .5);
}

/* ── 2 · SOUS-BOUTON — les autres actions. Neutre, bordé. ──────────────────── */
.btn-secondary, .btn-action, .lib-bulk-btn, .compte-w-btn, .identite-btn,
.btn-key-act, .cok-msg-cbtn, .cok-launch-btn, .lib-io-btn, .lib-menu-item {
  background: rgba(var(--th-voile), .03);
  color: var(--text);
  border: 1px solid var(--border);
}
.btn-secondary:hover, .btn-action:hover, .lib-bulk-btn:hover, .compte-w-btn:hover,
.identite-btn:not(.on):hover, .btn-key-act:hover, .cok-msg-cbtn:hover,
.cok-launch-btn:hover, .lib-io-btn:hover, .lib-menu-item:hover {
  background: rgba(var(--th-voile), .07);
  border-color: var(--border-mid);
}

/* ── 3 · DISCRET — ce qui ne doit pas attirer l'œil. Nu, sans bordure. ─────── */
.btn-ghost, .btn-ghost--sm, .btn-icon, .link-btn, .remove-btn, .compare-close-btn {
  background: transparent;
  color: var(--text-2);
  border: 1px solid transparent;
}
/* ⚠️⚠️⚠️ `.remove-btn` ET `.compare-close-btn` NE SONT PLUS DANS CETTE LISTE.
   Elles y étaient, et elles ANNULAIENT en silence la règle « Fermer, c'est retirer : le
   survol est rouge partout, SANS EXCEPTION » écrite 7 700 lignes plus haut : même force
   (une classe + une pseudo-classe), donc la dernière écrite gagne.
   Mesuré le 01/09 : sur les 29 boutons que la règle rouge vise, 27 le gardaient et
   DEUX seulement le perdaient — ces deux-là. Amadou : « quand je survole le bouton pour
   mettre la croix, il devient transparent, ce n'est pas agréable à utiliser » — c'était
   le voile blanc à 6 % qui remplaçait le rouge.
   ⚠️ On les RETIRE de la famille discrète plutôt que de reposer le rouge après : deux
   règles qui se contredisent, même dans le bon ordre, se recontrediront au prochain
   déplacement de bloc. Une seule dit la couleur du survol d'une croix. */
.btn-ghost:hover, .btn-ghost--sm:hover, .btn-icon:hover, .link-btn:hover {
  background: rgba(var(--th-voile), .06);
  color: var(--text);
}

/* ── LE TON « DANGER » n'est PAS un quatrième niveau : c'est une couleur posée
   sur n'importe lequel des trois. Un bouton rouge reste principal ou discret.
   ⚠️ Quatre noms disaient déjà la même chose (`.danger`, `.btn-danger-sm`,
   `.src-px-danger`, `.v-btn--danger`) — ils sont réunis ici, une fois. */
.danger, .btn-danger-sm, .src-px-danger, .v-btn--danger, .cok-btn.danger {
  background: var(--danger-fond);
  color: var(--red);
  border: 1px solid var(--danger-bord);
}
.danger:hover, .btn-danger-sm:hover, .src-px-danger:hover, .v-btn--danger:hover,
.cok-btn.danger:hover {
  background: rgba(var(--th-danger-rgb), .2);
  border-color: var(--red);
}

/* ── LES BOUTONS-ICÔNE : la couleur du niveau 3, mais leur carré intact. ───── */
.btn-icon, .remove-btn, .compare-close-btn, .btn-key-act {
  padding: 0;
  min-width: 32px;
  min-height: 32px;
  border-radius: var(--r-sm);
}

/* ⚠️⚠️ ET UNE ICÔNE NE SE LAISSE PLUS JAMAIS ÉCRASER. Mesuré le 23/08 : `.btn-key-act`
   est une icône seule dans un bouton de 34 px. En le rangeant avec les boutons à texte
   il a hérité de `padding: 8px 14px` — 28 px de marge pour un SVG de 14 px, que le flex
   a comprimé à QUATRE pixels de large. À l'écran : deux boutons vides à côté des clés.
   La règle qui suit ferme le piège pour toutes les familles d'un coup, y compris celles
   qui sont mixtes (`.btn-primary` et `.btn-action` ont chacune un emploi sans texte) :
   un flex a le droit de rétrécir ses enfants, une icône n'est pas négociable. */
.btn-primary > svg, .batch-btn-launch > svg, .atelier-gen-btn > svg, .btn-generate > svg,
.mod-go-btn > svg, .btn-save-views > svg, .cok-launch-btn > svg, .btn-secondary > svg,
.btn-action > svg, .lib-bulk-btn > svg, .compte-w-btn > svg, .identite-btn > svg,
.btn-key-act > svg, .cok-msg-cbtn > svg, .btn-ghost > svg, .btn-ghost--sm > svg,
.btn-danger-sm > svg, .lib-io-btn > svg, .lib-menu-item > svg,
.btn-icon > svg, .remove-btn > svg, .compare-close-btn > svg,
.upload-pick > svg {
  flex: 0 0 auto;
}

/* ⚠️ `.link-btn` est un LIEN déguisé en bouton : ni fond, ni cadre, ni hauteur —
   sinon il se met à ressembler à un bouton discret et on ne sait plus lequel des
   deux emmène ailleurs. */
.link-btn {
  padding: 0;
  min-height: 0;
  border: 0;
  color: var(--violet-light);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.link-btn:hover { background: transparent; color: var(--violet); }

/* ── ET LE SEGMENT ORPHELIN DE « EN LIGNE » ────────────────────────────────────
   Amadou, 23/08 : « les boutons En ligne / Vendus / Masqués doivent être comme ceux
   dans la partie Brouillons ». `.el-segb` n'était rattachée à AUCUNE des trois
   familles d'onglets du 30/07 : elle avait gardé sa pilule à elle, dans sa gouttière
   à elle. `.drafts-tab` est un SOUS-ONGLET — `.el-segb` en devient un aussi.
   ⚠️ La gouttière `.el-seg` disparaît avec : un sous-onglet ne vit pas dans une
   boîte, sinon on a deux cadres l'un dans l'autre. */
.el-seg {
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  gap: var(--e-4);
}
.el-segb {
  height: 34px;
  padding: 0 var(--e-16);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile), .04);
  font-size: var(--t-base);
  font-weight: var(--fw-moyen);
}
.el-segb b {
  font-size: var(--t-micro);
  font-weight: var(--fw-moyen);
  background: rgba(var(--th-voile), .08);
  border-radius: var(--r-pilule);
  padding: var(--e-1) var(--e-8);
  margin-left: var(--e-6);
}
.el-segb.on {
  background: var(--cok-accent-bg, rgba(var(--th-accent-rgb), .2));
  color: var(--violet-light);
  border-color: rgba(var(--th-accent-rgb), .35);
}
.el-segb.on b { background: rgba(var(--th-accent-rgb), .2); color: var(--violet-light); }

/* ══════════════════════════════════════════════════════════════════════════════
   PARAMÈTRES : LA BARRE D'ONGLETS RESPIRE, ET LE CORPS DIT QU'IL CONTINUE
   ══════════════════════════════════════════════════════════════════════════════
   Amadou, 2026-08-23 : « les boutons pour sélectionner les types de paramètres sont
   trop collés » et « il faut qu'il y ait un effet de flou ».

   Deux choses, et elles vont ensemble : la barre passe à huit onglets et se plie sur
   deux rangées ; à `gap: 8px` les deux rangées se touchaient presque et l'œil ne
   voyait plus une barre mais un bloc. Et le corps se coupait NET sous la barre et
   au-dessus du pied — un texte tranché à mi-hauteur se lit comme une page cassée, pas
   comme une page qui continue.
   ══════════════════════════════════════════════════════════════════════════════ */
.pa-tabs {
  column-gap: var(--e-10);
  row-gap: var(--e-10);
  padding-bottom: var(--e-12);
}

/* ⚠️ LE FONDU EST UN MASQUE, PAS UN VOILE POSÉ PAR-DESSUS. Un dégradé en `::after`
   aurait fallu peindre la couleur du fond — donc la redevenir fausse dans quinze des
   dix-sept thèmes. `mask-image` efface, il ne peint pas : il marche sur n'importe quel
   fond sans le connaître. */
.pa-body {
  --pa-fondu: 26px;
  transition: mask-image var(--t-bref);
}
/* ⚠️ ET IL N'APPARAÎT QUE S'IL Y A VRAIMENT QUELQUE CHOSE À VOIR. Un fondu permanent
   en haut effacerait le premier titre alors qu'on est déjà tout en haut : le lecteur
   croirait à un défaut d'affichage. Les deux classes sont posées par le JS, au
   défilement — voir `_paFondu()`. */
.pa-body.fondu-haut:not(.fondu-bas) {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--pa-fondu));
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--pa-fondu));
}
.pa-body.fondu-bas:not(.fondu-haut) {
  -webkit-mask-image: linear-gradient(to top, transparent 0, #000 var(--pa-fondu));
  mask-image: linear-gradient(to top, transparent 0, #000 var(--pa-fondu));
}
.pa-body.fondu-haut.fondu-bas {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--pa-fondu),
                              #000 calc(100% - var(--pa-fondu)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--pa-fondu),
                              #000 calc(100% - var(--pa-fondu)), transparent 100%);
}
@media (prefers-reduced-motion: reduce) { .pa-body { transition: none; } }

/* ── LE FAIT PORTÉ PAR CHAQUE CARTE DE CONNEXION ───────────────────────────────
   Amadou voulait « des petites informations quand j'appuie sur la carte ». Elles ne
   se cachent pas derrière un clic : un fait qu'il faut aller chercher n'est pas lu.
   Il tient sur deux lignes au plus, en dessous de la description, au-dessus du lien.
   ⚠️ `min-height` réserve sa ligne dès le premier dessin : sans elle, les six cartes
   sautaient à l'arrivée des données — la leçon de la frise des Commandes, le 23/08. */
/* ⚠️⚠️ ET LA RÉSERVE DE PLACE A ÉTÉ RETIRÉE, APRÈS DEUX ESSAIS RATÉS. J'ai d'abord
   réservé UNE ligne (la carte sautait quand même : la plupart des faits en prennent
   deux), puis DEUX — et Amadou l'a vu tout de suite : « il y a un espace en dessous de
   30320 MARGUERITTES (FRANCE), c'est perturbant ». Réserver deux lignes à tout le monde,
   c'est creuser un TROU PERMANENT dans les cartes dont le fait tient sur une ligne
   (« Aucune clé posée. », « 1 sortie branchée · 30 places »).
   Le saut à l'arrivée des données se règle autrement, et mieux : le lien « Ouvrir » est
   POUSSÉ AU BAS de la carte. Les six boutons s'alignent alors sur une même ligne, et le
   blanc au-dessus se lit comme de l'alignement — ce qu'il est — au lieu d'un trou. La
   grille égalise déjà la hauteur des cartes d'une même rangée. */
.pa-conn-card { display: flex; flex-direction: column; }
.pa-conn-open { margin-top: auto; align-self: flex-start; }
.pa-conn-fait {
  margin: calc(var(--e-8) * -1) 0 var(--e-10);
  font-size: var(--t-mini);
  line-height: var(--lh-serre);
  color: var(--text-3);
  overflow-wrap: anywhere;
  transition: opacity var(--t-moyen) var(--c-pose);
}
.pa-conn-fait:empty { opacity: 0; }

/* ══ L ONGLET AVIS : UN ESPACE TEXTE, UN ESPACE PHOTO ════════════════════════
   Deux blocs distincts, pas un empilement — Amadou (25/08) : « il n y a pas d espace
   photo et d espace texte a proprement parler ». Voir `_avisSheinPanneau`. */
.shein-avis {
  display: flex;
  flex-direction: column;
  gap: var(--e-12);
  width: 100%;
}
.shein-avis-tete {
  display: flex;
  align-items: baseline;
  gap: var(--e-8);
  flex-wrap: wrap;
  padding-bottom: var(--e-12);
  border-bottom: 1px solid var(--border);
}
.shein-avis-chiffre {
  font-size: var(--t-2xl);
  font-weight: 700;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.shein-avis-etoiles { color: var(--amber); letter-spacing: 1px; }
.shein-avis-src { font-size: var(--t-meta); color: var(--text-3); }
/* La regle metier, dite et pas appliquee de force : « sous 3 etoiles, on ne source pas ». */
.shein-avis-alerte {
  font-size: var(--t-meta);
  color: var(--red);
  font-weight: 600;
}
/* Un bloc = un cadre. C est ce qui separe le texte de la photo a l oeil nu. */
/* ⚠️ LE RESUME SE LIT, LES GROUPES SE SURVOLENT — ils ne se touchent pas.
   Amadou (25/08) : « l espace entre ce qu elles disent et les compartiments, c est trop
   colle, ce n est pas assez aere ». Un texte qu on lit a besoin de respirer AVANT le
   tableau qui le resume, sinon les deux se lisent comme un seul pave. */
.shein-bloc {
  display: flex;
  flex-direction: column;
  gap: var(--e-16);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-carte);
  padding: var(--e-16) var(--e-20) var(--e-20);
}
.shein-bloc-h { display: flex; justify-content: space-between; align-items: baseline; gap: var(--e-8); }
.shein-bloc-tt { font-size: var(--t-meta); color: var(--text-3); }
.shein-bloc-aide { font-size: var(--t-meta); color: var(--text-3); }
.shein-bloc-st {
  font-size: var(--t-meta);
  color: var(--text-3);
  padding-top: var(--e-8);
  border-top: 1px solid var(--border);
}
/* Le resume se LIT — il a droit a une ligne plus aeree que le reste du panneau. */
.shein-resume {
  font-size: var(--t-body);
  color: var(--text-1);
  line-height: 1.65;
  /* Il porte le bloc : il prend l air au-dessus comme en dessous. */
  margin: var(--e-4) 0 var(--e-8);
}
.shein-groupes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--e-10);
}
/* ⚠️ AUCUNE BANDE SUR LE COTE. Amadou (25/08) : « les petites bandes de couleur, je
   trouve que ce n est pas beau ». Un lisere de deux pixels n existe nulle part ailleurs
   dans Velbo, et il coupait le coin arrondi de la carte. Ce qu on lit en premier, c est
   COMBIEN : le chiffre passe donc en grand, le nom dessous. */
.shein-groupe {
  display: flex;
  flex-direction: column;
  gap: 0;
  border-radius: var(--r-sm);
  padding: var(--e-12) var(--e-14);
  background: var(--surface-3);
}
.shein-groupe-n {
  font-size: var(--t-xl);
  font-weight: 600;
  color: var(--text-1);
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
/* ⚠️ LES RESERVES NE SE FONDENT PAS DANS LA MOYENNE : c est le groupe qui decide d un
   achat. La couleur tient desormais dans le NOMBRE, elle ne cerne plus la carte. */
.shein-groupe-n--reserve { color: var(--red); }
.shein-groupe-h { font-size: var(--t-meta); color: var(--text-1); padding-top: var(--e-4); }
.shein-groupe-m { font-size: var(--t-meta); color: var(--text-3); padding-top: var(--e-2); }
.shein-propre { display: flex; flex-direction: column; gap: var(--e-2); }
.shein-propre-t { font-size: var(--t-meta); color: var(--text-1); line-height: 1.45; }
.shein-propre-q { font-size: var(--t-meta); color: var(--text-3); }
/* ⚠️ LES PHOTOS D ACHETEUSES SE COMPARENT, DONC ELLES SE RANGENT EN GRILLE. Elles se
   cliquent pour rejoindre les photos de reference du coloris. */
.shein-avis-grille {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: var(--e-6);
}
.shein-avis-grille img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: opacity var(--t-bref);
}
.shein-avis-grille img:hover { opacity: .8; }
/* ⚠️ LE VIDE EST LE CAS LE PLUS FREQUENT — les clientes n envoient des photos que sur une
   ou deux couleurs. Il merite donc d etre SOIGNE, pas bacle : un bloc qui disparait
   laisse croire qu on n a pas cherche. Deux lignes centrees, calees sur la hauteur d une
   rangee de vignettes pour que le panneau ne saute pas quand on change de coloris. */
.shein-avis-vide {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--e-4);
  min-height: 78px;
  border: 1px dashed var(--border);
  border-radius: var(--r-sm);
  text-align: center;
  padding: var(--e-12);
}
.shein-avis-vide-t { font-size: var(--t-meta); color: var(--text-2); }
.shein-avis-vide-s { font-size: var(--t-meta); color: var(--text-3); }

/* ══ STUDIO — LA RÉPONSE MISE EN FORME ═══════════════════════════════════════
   ⚠️⚠️ AVANT, LE TEXTE ÉTAIT POSÉ BRUT (`createTextNode` + `<br>`) : les
   astérisques du gras, les tirets des listes et les clôtures de blocs de code
   s'affichaient tels quels. Ça se voyait au premier coup d'œil à côté de
   ChatGPT — et ça poussait à demander des réponses plates, donc pauvres.
   ⚠️ TOUT PASSE PAR LES JETONS `--th-*` : ces règles doivent tenir sur les vingt
   thèmes, clairs compris. Un `#fff` ou un `rgba(0,0,0,.4)` écrit ici serait
   illisible sur la moitié d'entre eux. */

.studio-msg-text.md { line-height: var(--lh-aere); }
.studio-msg-text.md > *:first-child { margin-top: 0; }
.studio-msg-text.md > *:last-child  { margin-bottom: 0; }
.studio-msg-text.md p { margin: 0 0 var(--e-12); }

.studio-msg-text.md .md-h {
  margin: var(--e-20) 0 var(--e-8);
  font-weight: var(--fw-moyen);
  line-height: var(--lh-titre);
  color: var(--th-texte);
}
.studio-msg-text.md h2.md-h { font-size: var(--t-lead); }
.studio-msg-text.md h3.md-h { font-size: var(--t-base); }
.studio-msg-text.md h4.md-h,
.studio-msg-text.md h5.md-h { font-size: var(--t-small); color: var(--th-texte-2); }

.studio-msg-text.md ul,
.studio-msg-text.md ol { margin: 0 0 var(--e-12); padding-left: var(--e-20); }
.studio-msg-text.md li { margin: var(--e-4) 0; }
.studio-msg-text.md li::marker { color: var(--th-texte-3); }

.studio-msg-text.md strong { font-weight: var(--fw-moyen); color: var(--th-texte); }
.studio-msg-text.md em     { font-style: italic; }
.studio-msg-text.md del    { opacity: .6; }
.studio-msg-text.md a      { color: var(--th-accent-clair); text-decoration: underline;
                             text-underline-offset: var(--e-2); }
.studio-msg-text.md a:hover { color: var(--th-accent); }

.studio-msg-text.md code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-meta);
  background: rgba(var(--th-voile), .08);
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  padding: var(--e-1) var(--e-6);
}

/* Un bloc de code garde SA barre de défilement — sans ça une longue ligne
   élargit la bulle, qui élargit la colonne, qui pousse la page entière. */
.md-code {
  margin: 0 0 var(--e-12);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  background: rgba(var(--th-voile), .05);
}
.md-code-tete {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-6) var(--e-10);
  font-size: var(--t-micro);
  color: var(--th-texte-3);
  border-bottom: 1px solid var(--border);
}
/* ⚠️⚠️ IL ÉTAIT VISIBLE EN PERMANENCE, AVEC SON MOT. Amadou (26/08) : « le bouton
   copier, il n'est pas beau, il faut qu'il soit beaucoup plus discret ». Un libellé
   posé en haut de chaque bloc de code pèse autant que la première ligne du code.
   Il ne se montre qu'au survol du bloc — et reste visible au doigt, où le survol
   n'existe pas. */
.md-code-copier {
  background: none; border: 0; cursor: pointer;
  color: var(--th-texte-3); font-size: var(--t-nano);
  padding: var(--e-2) var(--e-6); border-radius: var(--r-xs);
  opacity: 0;
  transition: opacity var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.md-code:hover .md-code-copier,
.md-code-copier:focus-visible { opacity: 1; }
.md-code-copier:hover { color: var(--th-texte-2); }
@media (hover: none) { .md-code-copier { opacity: 1; } }
.md-code pre { margin: 0; padding: var(--e-10) var(--e-12); overflow-x: auto; }
.md-code pre code { background: none; border: 0; padding: 0; font-size: var(--t-meta); }

.md-table-boite { overflow-x: auto; margin: 0 0 var(--e-12); }
/* ⚠️ `width: 100%` SEUL fait rétrécir les colonnes au lieu de faire défiler : en
   largeur étroite, « Taille » se coupait en « Taill / e ». Le plancher force le
   tableau à garder ses colonnes et à défiler dans sa boîte — qui est déjà en
   `overflow-x: auto` juste au-dessus. */
.md-table-boite table { border-collapse: collapse; width: 100%; min-width: 26rem;
                        font-size: var(--t-small); }
.md-table-boite th, .md-table-boite td {
  border: 1px solid var(--border); padding: var(--e-6) var(--e-10); text-align: left;
}
.md-table-boite th { background: rgba(var(--th-voile), .06); font-weight: var(--fw-moyen); }

/* ⚠️ Bord d'un seul côté : donc PAS de rayon (règle du socle — un coin arrondi
   sur un filet unique laisse un angle vide qui se voit). */
.md-cite {
  margin: 0 0 var(--e-12); padding: var(--e-6) var(--e-14);
  border-left: 2px solid var(--th-accent-doux);
  border-radius: 0;
  color: var(--th-texte-2);
}
.md-hr { border: 0; border-top: 1px solid var(--border); margin: var(--e-18) 0; }

/* ── Ce qu'il est en train de faire ─────────────────────────────────────────
   Une ligne par outil. Elle apparaît AVANT le texte : sans elle, chercher dans
   les données ressemble à un blanc de plusieurs secondes. */
.studio-outils {
  display: flex; flex-direction: column; gap: var(--e-4);
  margin-bottom: var(--e-10);
}
.studio-outil {
  display: flex; align-items: center; gap: var(--e-8);
  font-size: var(--t-meta); color: var(--th-texte-3);
}
.studio-outil-pt {
  width: var(--e-6); height: var(--e-6); border-radius: 50%;
  background: var(--th-accent);
  animation: studioOutilBat 1.1s var(--c-pose) infinite;
  flex: 0 0 auto;
}
.studio-outil.fini .studio-outil-pt { background: var(--th-succes); animation: none; }
.studio-outil-det { color: var(--th-texte-3); opacity: .75; }
@keyframes studioOutilBat { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .studio-outil-pt { animation: none; } }

/* Son raisonnement : replié par défaut. Il est là pour qui veut vérifier, pas
   pour occuper l'écran. */
.studio-pense { margin-bottom: var(--e-10); }
.studio-pense > summary {
  cursor: pointer; font-size: var(--t-meta); color: var(--th-texte-3);
  list-style: none; user-select: none;
}
.studio-pense > summary::-webkit-details-marker { display: none; }
.studio-pense > summary::before { content: '▸ '; }
.studio-pense[open] > summary::before { content: '▾ '; }
.studio-pense > summary:hover { color: var(--th-texte-2); }
.studio-pense-corps {
  margin-top: var(--e-6); padding-left: var(--e-10);
  border-left: 1px solid var(--border); border-radius: 0;
  font-size: var(--t-meta); color: var(--th-texte-3);
  white-space: pre-wrap; line-height: var(--lh-normal);
  max-height: var(--e-48); overflow-y: auto;
}
.studio-pense[open] .studio-pense-corps { max-height: none; }

/* ══ STUDIO — LA RÉPONSE PREND SA PLACE ══════════════════════════════════════
   ⚠️⚠️ MESURÉ : une réponse structurée s'affichait dans **249 px** alors que son
   emplacement en faisait 620. La bulle se calait sur son contenu, et un tableau
   en `width: 100%` dans un parent qui se cale sur son contenu tourne en rond —
   le tableau prend la largeur du texte, qui prend la largeur du tableau. Sur une
   réponse riche, ça donne une colonne de journal.
   ⭐ Une RÉPONSE n'est pas une bulle de conversation, c'est un document : elle
   occupe la largeur du fil, comme chez ChatGPT et Claude. Les messages d'Amadou,
   eux, restent des bulles à droite — c'est le contraste entre les deux qui fait
   lire « lui / moi » sans avoir besoin d'y penser. */
.studio-msg-velbo { max-width: 100%; width: 100%; }
.studio-msg-velbo .studio-msg-bubble-text {
  max-width: none;
  width: 100%;
  background: transparent;
  border: 0;
  padding-left: 0;
  padding-right: 0;
}
/* La borne de lecture est posée sur le FIL, pas sur la bulle : ainsi les messages
   d'Amadou et les réponses partagent le même axe, sans décalage. */
.studio-chat-messages { --studio-lecture: 74ch; }
.studio-msg-velbo .studio-msg-text.md { max-width: var(--studio-lecture); }
.studio-msg-velbo .studio-msg-bubble-text > .studio-msg-actions { padding-left: 0; }

/* ══ STUDIO — LA DISPOSITION, FUSION CLAUDE + CHATGPT ════════════════════════
   Amadou (26/08) : « inspire-toi de l'interface de Claude et de ChatGPT, pour moi
   ce sont les meilleures, fusionne-les ».
   De CLAUDE : l'accueil. La salutation et la saisie AU CENTRE de l'écran tant que
   rien n'est écrit — c'est ce qui donne envie de commencer, au lieu de fixer un
   grand vide avec une barre collée en bas.
   De CHATGPT : la conversation. Dès le premier message la saisie descend, le fil
   prend toute la place ; plus la recherche en haut de l'historique.
   ⚠️ UN SEUL DRAPEAU commande les deux états (`.vide`, posé par `_studioVide`).
   Deux réglages séparés finiraient par se contredire — barre en bas sur un écran
   d'accueil, ou l'inverse. */
/* ⚠️⚠️ LA SAISIE EST REDESCENDUE EN BAS (Amadou, 26/08 : « du coup la barre des
   messages doit être en bas »). Elle avait été remontée au centre le matin même,
   à l'imitation de Claude — mais Claude peut le faire parce que son accueil ne
   porte rien d'autre. Ici, les cartes retirées, une barre au milieu d'un écran
   vide flotte sans rien pour l'ancrer. La salutation garde le centre de la zone
   au-dessus ; la barre reste là où on la cherche. */
.studio-chat.vide .studio-chat-welcome {
  justify-content: center;
  padding-top: var(--e-32);
  padding-bottom: var(--e-32);
}

/* ── La rangée de commandes, sous le texte ─────────────────────────────────── */
.studio-input-ops {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e-8); margin-top: var(--e-6);
}
.studio-ops-gauche { display: flex; align-items: center; gap: var(--e-8); min-width: 0; }
/* Micro + envoi : les deux façons de faire PARTIR un message, donc côte à côte. */
.studio-ops-droite { display: flex; align-items: center; gap: var(--e-6); flex: 0 0 auto; }

/* ── Auto / Répondre / Image ───────────────────────────────────────────────── */
.studio-mode {
  display: flex; gap: var(--e-2);
  background: rgba(var(--th-voile), .05);
  border-radius: var(--r-md);
  padding: var(--e-2);
}
.studio-mode-b {
  background: none; border: 0; cursor: pointer;
  font-size: var(--t-micro); font-family: inherit;
  color: var(--th-texte-3);
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-xs);
  white-space: nowrap;
}
.studio-mode-b:hover { color: var(--th-texte-2); }
.studio-mode-b.active {
  background: rgba(var(--th-accent-rgb), .16);
  color: var(--th-accent-clair);
}

/* Le bouton joindre reprend la taille des commandes de la rangée : à 38 px il
   dominait un segment de 26 px et déséquilibrait toute la ligne. */
.studio-input-ops .studio-attach-btn { width: 28px; height: 28px; border-radius: var(--r-sm); }
.studio-input-ops .studio-attach-btn:hover { color: var(--th-texte); background: rgba(var(--th-voile), .08); }
.studio-input-ops .studio-send-btn { width: 30px; height: 30px; border-radius: var(--r-md); }

/* ── Chercher dans ses conversations ───────────────────────────────────────── */
.studio-rech {
  display: flex; align-items: center; gap: var(--e-6);
  margin-top: var(--e-8);
  padding: var(--e-6) var(--e-8);
  border-radius: var(--r-md);
  background: rgba(var(--th-voile), .05);
  color: var(--th-texte-3);
}
.studio-rech:focus-within { background: rgba(var(--th-voile), .09); }
.studio-rech svg { flex: 0 0 auto; }
.studio-rech input {
  flex: 1; min-width: 0;
  background: none; border: 0; outline: none;
  color: var(--th-texte); font-family: inherit; font-size: var(--t-meta);
}
.studio-rech input::placeholder { color: var(--th-texte-3); }
/* La croix native de `type="search"` est dessinée par le navigateur, en gris fixe :
   invisible sur les thèmes sombres, disgracieuse sur les clairs. */
.studio-rech input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ── Le modèle en cours, dans la barre du haut ─────────────────────────────── */
.studio-modele {
  font-size: var(--t-meta);
  color: var(--th-texte-3);
  padding: var(--e-4) var(--e-10);
  border-radius: var(--r-pilule);
  border: 1px solid var(--border);
  white-space: nowrap;
}

/* ⚠️ LE CENTRAGE NE VAUT QU'À L'ACCUEIL. `.studio-chat-welcome` est en
   `text-align: left` parce qu'il servait aussi de bandeau au-dessus d'une grille
   de cartes ; centrer la règle de base décalerait ces cas-là. Le centre est donc
   posé sous `.vide`, avec le reste de la disposition d'accueil. */
.studio-chat.vide .studio-chat-welcome { text-align: center; }
.studio-chat.vide .studio-welcome-inner { align-items: center; }
/* ⚠️ DEUX ENFANTS SEULEMENT, sinon le `gap` s'insère ENTRE CHAQUE MOT. La phrase
   est découpée en blocs-mots (pour que la ligne ne se coupe pas au milieu d'un
   mot) : sans l'enveloppe `.studio-welcome-phrase`, chacun de ces blocs devient un
   item flex et reçoit 12 px d'écart en plus de son espace — « On  génère,  on
   écrit » s'étalait avec des trous. */
.studio-chat.vide .studio-chat-welcome-greeting {
  display: flex; align-items: center; justify-content: center;
  gap: var(--e-12); flex-wrap: wrap;
}
.studio-welcome-phrase { display: inline; }
.studio-welcome-marque { display: inline-flex; flex: 0 0 auto; }
.studio-chat.vide .studio-welcome-hint { text-align: center; }

/* ══ STUDIO — L'ACCUEIL QUAND LA PLACE MANQUE ════════════════════════════════
   ⚠️⚠️ `justify-content: center` DÉBORDE PAR LE HAUT. Mesuré en largeur tablette :
   la salutation et le logo passaient hors de l'écran, inatteignables même en
   défilant — un contenu centré plus haut que son conteneur dépasse des DEUX côtés,
   et le haut n'est pas rattrapable. `safe center` centre tant que ça tient et
   revient au début dès que ça ne tient plus ; c'est exactement le cas d'usage. */
/* ⚠️ `safe center` réglait le débordement d'un accueil CENTRÉ (salutation + barre +
   six cartes, plus hauts que l'écran). La barre est redescendue et les cartes sont
   parties : il n'y a plus de pile à centrer, donc plus rien à protéger ici. */

/* ⚠️ Le segment Auto/Répondre/Image RECOUVRAIT le bouton d'envoi en étroit : ses
   libellés sont en `nowrap`, donc il refusait de rétrécir et poussait la rangée
   au-delà de la barre. Il se resserre au lieu de pousser. */
@container studiochat (max-width: 480px) {
  .studio-mode-b { padding: var(--e-4) var(--e-6); font-size: var(--t-nano); }
  .studio-input-ops { gap: var(--e-4); }
  .studio-ops-gauche { gap: var(--e-4); }
}
/* Plus étroit encore : les cartes tiennent sur deux colonnes serrées plutôt que
   de s'empiler sur six rangs — six cartes en colonne font un accueil de deux
   écrans de haut, où la barre de saisie n'est plus visible avec la salutation. */

/* ══ STUDIO — LES ACTIONS, LA VOIX, LES MENTIONS ═════════════════════════════
   ⚠️⚠️ L'ANCIEN BOUTON PORTAIT SON MOT (« Copier »), dans une pilule bordée,
   visible en permanence. Amadou (26/08) : « le bouton copier n'est pas beau, il
   doit être plus discret ». Un libellé sous chaque réponse pèse autant que la
   réponse ; ce sont des icônes, et elles n'apparaissent qu'au survol du message —
   comme chez ChatGPT et Claude, où seule la barre du message visé se montre. */
.studio-msg-actions {
  display: flex; gap: var(--e-2); margin-top: var(--e-6);
  opacity: 0;
  transition: opacity var(--t-bref) var(--c-pose);
}
.studio-msg:hover .studio-msg-actions,
.studio-msg-actions:focus-within { opacity: 1; }
/* ⚠️ Le survol n'existe pas au doigt : sur un écran tactile les actions doivent
   rester visibles, sinon elles sont inatteignables. */
@media (hover: none) { .studio-msg-actions { opacity: 1; } }

.studio-msg-actions--user { justify-content: flex-end; }

/* ⚠️ Plus petites et plus effacées : elles accompagnent la réponse, elles ne la
   commentent pas. Le fond au survol est retiré — sur une rangée de quatre icônes,
   quatre pastilles qui s'allument font une barre d'outils, pas une aide discrète. */
.studio-act {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border-radius: var(--r-sm);
  border: 0; background: none;
  color: var(--th-texte-3);
  opacity: .7;
  cursor: pointer; padding: 0;
  transition: opacity var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.studio-act:hover { color: var(--th-texte-2); opacity: 1; }
.studio-act.parle { color: var(--th-accent-clair); background: rgba(var(--th-accent-rgb), .14); }

/* ── Le micro ──────────────────────────────────────────────────────────────── */
.studio-mic-btn {
  flex-shrink: 0;
  width: 30px; height: 30px;
  border-radius: var(--r-md);
  border: 0; background: none;
  color: var(--th-texte-3);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; padding: 0;
}
.studio-mic-btn:hover { color: var(--th-texte); background: rgba(var(--th-voile), .08); }
/* ⚠️⚠️ DEUX ÉTATS, PAS UN — et c'est tout le problème qu'Amadou décrit : « des fois
   ça m'arrivait de cliquer plein de fois parce que je pensais qu'il n'était pas
   enclenché ». Entre le clic et le vrai départ de l'écoute, le navigateur demande
   l'autorisation du micro et ouvre le flux : ça prend un temps VISIBLE, pendant
   lequel l'ancien bouton ne changeait pas d'aspect. On cliquait donc à nouveau — et
   le deuxième clic ARRÊTAIT ce qui venait de démarrer.
   « attente » se pose dès le clic (avant même d'appeler le moteur) ; « ecoute »
   quand le moteur confirme. Il se passe toujours quelque chose sous le doigt. */
.studio-mic-btn.attente {
  color: var(--th-accent-clair);
  background: rgba(var(--th-accent-rgb), .16);
}
/* ⚠️ LA COULEUR DU SITE, PAS DU ROUGE. J'avais pris `--th-danger` par réflexe
   « enregistrement ». Amadou : « mets-le dans la couleur de la DA du site en
   fonction du thème ». Le rouge dit « attention/erreur » dans tout le reste de
   l'interface — l'employer ici brouille les deux sens, et il ne suit aucun thème.
   ⚠️ Le fond est PLEIN pendant l'écoute : un simple halo se confond avec un survol.
   L'état actif doit se distinguer du survol, sinon on ne sait pas s'il est armé. */
.studio-mic-btn.ecoute {
  color: var(--sur-accent);
  background: var(--th-accent);
  animation: studioMicRespire 1.7s var(--c-pose) infinite;
}
.studio-mic-btn.ecoute:hover { background: var(--th-accent-fort); }
@keyframes studioMicRespire {
  0%, 100% { box-shadow: 0 0 0 0 rgba(var(--th-accent-rgb), .40); }
  50%      { box-shadow: 0 0 0 var(--e-6) rgba(var(--th-accent-rgb), 0); }
}
@media (prefers-reduced-motion: reduce) { .studio-mic-btn.ecoute { animation: none; } }

/* ⚠️ LE CHAMP MARQUE QU'IL TRAVAILLE, SANS SE BLOQUER. Pendant la reprise de
   formulation, Amadou doit pouvoir continuer à écrire ou envoyer tout de suite
   s'il ne veut pas attendre — un champ verrouillé pendant un aller-retour réseau
   vaut moins qu'un texte non repris. Un liseré qui respire suffit à le dire. */
.studio-chat-inputbar.repare { border-color: rgba(var(--th-accent-rgb), .4); }
.studio-chat-inputbar.repare .studio-prompt-input { opacity: .72; }
/* ⚠️⚠️ LE BOUTON NE BOUGE PAS, IL S'ALLUME. Amadou (26/08) : « il ne doit pas…
   il doit juste être coloré, et les étoiles doivent briller ». Le halo qui
   respirait faisait grossir et rétrécir le bouton lui-même : sur un carré de 30 px
   posé à côté du bouton d'envoi, ce battement attire l'œil hors du texte qu'on est
   en train de relire — et c'est précisément le texte qu'il faut regarder pendant
   la reprise. Le bouton prend donc la couleur pleine et n'en bouge plus ; ce qui
   vit, ce sont les étoiles.
   ⚠️ Les trois scintillent EN DÉCALÉ. Ensemble, elles ne feraient qu'un
   clignotement du bouton entier — exactement ce qu'on vient de retirer. Décalées,
   l'œil lit trois étoiles qui brillent chacune leur tour. */
.studio-mic-btn.travaille {
  color: var(--sur-accent);
  background: var(--th-accent);
  animation: none;
}
.studio-mic-btn.travaille:hover { background: var(--th-accent-fort); }
.studio-mic-btn.travaille svg path { animation: studioEtoileBrille 1.35s ease-in-out infinite; }
.studio-mic-btn.travaille svg path:nth-child(2) { animation-delay: .28s; }
.studio-mic-btn.travaille svg path:nth-child(3) { animation-delay: .62s; }
@keyframes studioEtoileBrille {
  0%, 100% { opacity: .45; }
  45%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .studio-mic-btn.travaille svg path { animation: none; opacity: 1; }
}

/* ══ STUDIO — LE FLUX QUI FAIT LE TOUR ═══════════════════════════════════════
   Amadou (26/08) : « le contour doit s'illuminer, mais comme si c'était du flux,
   un liquide qui fait le tout et après qu'il se rejoignait ».
   ⚠️⚠️ LE POINT DE DÉPART EST LE MILIEU DU BORD SUPÉRIEUR. Amadou (26/08, après
   deux essais) : « en haut, sur la ligne d'en haut au milieu, l'eau part, et au
   final ça remplit le rectangle arrondi ». J'avais d'abord lu « ça doit partir
   vers le haut » comme « ça monte », d'où une origine en bas — l'inverse. C'est le
   `from` du dégradé qui décide : 0deg place l'origine en haut, les deux fronts
   descendent chacun d'un côté et se rejoignent au milieu du bord inférieur.
   Une seule passe : ce n'est pas une attente qui tourne en boucle, c'est un accusé
   de réception.
   ⚠️ `@property` est indispensable : une variable CSS ordinaire ne s'anime PAS
   (le navigateur ne sait pas l'interpoler, elle saute d'une valeur à l'autre).
   Déclarée avec son type `<angle>`, elle devient animable. Deux autres animations
   du site s'appuient déjà dessus.
   ⚠️ L'anneau est un `conic-gradient` MASQUÉ, pas une bordure : une bordure ne
   peut pas être peinte en dégradé le long de son périmètre. Le masque garde le
   liseré et évide l'intérieur — d'où les deux couches et `mask-composite`.
   ⚠️ Là où `@property` manque (Firefox), l'arc reste à 0° : rien ne s'affiche, et
   la bordure violette du focus tient toute seule. Pas de dégradation visible. */
@property --studio-arc {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
/* ⚠️ TROIS RYTHMES QUI NE RETOMBENT JAMAIS ENSEMBLE. Une seule oscillation à
   cadence constante se lit comme un balancement mécanique : l'œil suit le
   va-et-vient. Trois ondes dont aucune n'est multiple des autres (0,78 s / 1,27 s /
   0,61 s) ne coïncident qu'au bout de plusieurs minutes — c'est cette
   non-coïncidence qui donne l'agitation.
   ⚠️ UN ESSAI ÉCARTÉ, ET LA RAISON. J'avais tenté des VAGUES : un motif de crêtes
   (`repeating-conic-gradient`) défilant le long du contour, doublé d'une seconde
   houle en sens inverse. Techniquement plus proche de l'image d'une eau agitée,
   mais Amadou (26/08), après l'avoir vu : « on va rester sur le glissement ». Sur
   un liseré d'un pixel et demi, des crêtes deviennent un clignotement — le relief
   qu'on croit dessiner n'a pas la place d'exister.
   Au repos les trois valent leur neutre : l'eau est étale et rien ne tourne. */
@property --studio-clapot {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
/* L'angle de la seconde houle. */
@property --studio-remous {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
/* La chaleur : ce qui pulse, ce n'est pas la position mais la LUMIÈRE. Sans elle,
   l'eau bouge mais reste froide — et le mouvement seul se lit comme une hésitation
   plutôt que comme une activité. */
@property --studio-chaleur {
  syntax: '<number>';
  inherits: false;
  initial-value: 1;
}

.studio-chat-inputbar { position: relative; }
.studio-chat-inputbar::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  /* L'épaisseur du liseré : la même que la bordure qu'il double. */
  padding: var(--e-1);
  /* ⚠️⚠️ LA TÊTE DU FRONT DOIT ÊTRE LA PARTIE LA PLUS VIVE. Première écriture :
     le clair était au DÉPART et la tête à 15 % d'opacité — on voyait donc une
     zone qui s'allume près de l'origine, pas un front qui avance. Amadou (26/08) :
     « tout se remplit en même temps, or ça doit vraiment faire le contour ».
     Ici : traîne posée derrière, tête vive, et surtout COUPURE NETTE à l'angle
     atteint. C'est ce bord franc qui fait lire « ça avance » plutôt que « ça
     s'allume ». */
  background: conic-gradient(from calc(0deg + var(--studio-clapot) + var(--studio-remous)),
      rgba(var(--th-accent-rgb), .42) 0deg,
      rgba(var(--th-accent-rgb), .62) calc(var(--studio-arc) - 26deg),
      var(--th-accent-clair) var(--studio-arc),
      transparent var(--studio-arc),
      transparent calc(360deg - var(--studio-arc)),
      var(--th-accent-clair) calc(360deg - var(--studio-arc)),
      rgba(var(--th-accent-rgb), .62) calc(360deg - var(--studio-arc) + 26deg),
      rgba(var(--th-accent-rgb), .42) 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  opacity: 0;
  pointer-events: none;
  filter: brightness(var(--studio-chaleur));
  transition: opacity var(--t-moyen) var(--c-sortie);
}
/* ⚠️⚠️ LA COURBE ÉTAIT LA VRAIE CAUSE DU « C'EST INSTANTANÉ ». `--c-pose` freine
   très tôt : mesuré, l'arc atteignait 173° sur 180 à la MOITIÉ du temps — 96 % du
   tour parcouru en 50 % de la durée. Quelle que soit la durée choisie, on ne
   voyait donc que la fin, immobile. Une eau qui coule garde une vitesse à peu près
   constante : la courbe ci-dessous démarre progressivement, tient son rythme, et ne
   se pose qu'à l'arrivée.
   Six courbes comparées sur la même durée, en relevant l'angle atteint à mi-temps
   (le régulier serait 90° sur 180) :
     --c-pose (l'ancienne) .... 173°  ← 96 %, d'où « c'est instantané »
     .32,.06,.42,1 ............ 123°
     .35,.25,.5,1 ............. 122°
     .5,.2,.5,.9 ..............  97°
     .45,.15,.55,.9 ...........  93°  ← retenue
   ⚠️ La DURÉE ne pouvait pas régler ce défaut : avec une courbe qui brûle le trajet,
   rallonger l'animation ne fait qu'allonger la partie où plus rien ne bouge. */
.studio-chat-inputbar:focus-within::before {
  opacity: 1;
  animation: studioFlux var(--studio-coule) cubic-bezier(.45, .15, .55, .9) forwards;
  transition: none;
}
/* ⚠️⚠️ UNE FOIS COULÉ, ÇA RESTE COULÉ. Amadou (26/08) : « une fois que l'animation
   est terminée… ça refait l'animation où ça part des deux côtés et ça coule. Il
   faut que le contour reste ».
   Le défaut : pendant la reprise du prompt, `.repare` REMPLACE l'animation par le
   frémissement. En la retirant, la règle du focus reprend la main — et une
   animation qu'on réattribue REDÉMARRE. Le contour se revidait donc pour se
   remplir à nouveau, alors qu'il n'avait aucune raison de bouger.
   `.a-coule` est posée par le JS à la fin du premier écoulement : elle fige l'arc à
   180° sans animation. Elle est retirée à la sortie du champ, pour que le geste
   rejoue à la prochaine venue. */
.studio-chat-inputbar.a-coule:focus-within::before {
  opacity: 1;
  animation: none;
  --studio-arc: 180deg;
}
/* ⚠️⚠️ UN CHAMP QUI PORTE DU TEXTE GARDE SON CONTOUR. Amadou (26/08) : « à partir du
   moment où il y a quelque chose dans l'espace, le contour doit rester allumé ».
   Le focus disait « tu écris ici en ce moment » ; ce qu'il faut dire est autre chose :
   « il y a quelque chose ici qui n'est pas parti ». Un message à moitié écrit qu'on
   quitte des yeux ne doit pas s'éteindre comme un champ vide — sinon rien ne
   distingue les deux à un coup d'œil.
   ⚠️ Et l'écoulement ne rejoue PAS au retour : on remplit une rigole vide, pas une
   rigole déjà pleine. D'où l'arc figé plutôt qu'une animation relancée. */
.studio-chat-inputbar.rempli::before {
  opacity: 1;
  animation: none;
  --studio-arc: 180deg;
}
/* Le frémissement reste prioritaire : il est déclaré après, et sa règle porte la
   classe `.repare` en plus. */
@keyframes studioFlux {
  from { --studio-arc: 0deg; }
  to   { --studio-arc: 180deg; }
}
/* ⚠️⚠️ L'EAU S'AGITE PENDANT LA REPRISE. Amadou : « quand j'appuie sur les étoiles,
   le cours d'eau doit s'agiter un peu ». Le bassin est déjà plein (l'arc est à
   180°) : ce qui bouge, c'est l'ORIGINE du dégradé, qui va et vient de quelques
   degrés — la lumière clapote le long du contour sans que le niveau change.
   ⚠️ `.repare` seul, PAS `:focus-within .repare` : cliquer l'étoile donne le focus
   AU BOUTON, pas au champ. Conditionner le clapot au focus le rendrait invisible
   précisément quand il doit se voir. */
.studio-chat-inputbar.repare::before {
  opacity: 1;
  --studio-arc: 180deg;
  animation: studioClapot  .78s ease-in-out infinite,
             studioRemous 1.27s ease-in-out infinite,
             studioChaleur .61s ease-in-out infinite;
  transition: none;
}
@keyframes studioClapot {
  0%   { --studio-clapot: -8deg; }
  50%  { --studio-clapot:  8deg; }
  100% { --studio-clapot: -8deg; }
}
@keyframes studioRemous {
  0%   { --studio-remous:  4deg; }
  50%  { --studio-remous: -4deg; }
  100% { --studio-remous:  4deg; }
}
@keyframes studioChaleur {
  0%   { --studio-chaleur: .9; }
  50%  { --studio-chaleur: 1.22; }
  100% { --studio-chaleur: .9; }
}

@media (prefers-reduced-motion: reduce) {
  .studio-chat-inputbar:focus-within::before { animation: none; --studio-arc: 180deg; }
  .studio-chat-inputbar.repare::before { animation: none; }
}

/* ⚠️ LE TEXTE REPRIS DOIT SE VOIR CHANGER. Amadou : « quand j'appuie pour
   améliorer le prompt, le texte doit avoir une petite animation ». Sans elle, le
   champ se réécrit en silence : on ne sait pas si quelque chose s'est passé, et on
   reclique — le même défaut que le micro, une heure plus tôt.
   Le texte se recompose (flou qui se dissipe) plutôt que de clignoter : on doit
   POUVOIR LE LIRE pendant qu'il arrive, puisque c'est justement ce qu'on va
   vérifier. */
.studio-prompt-input.repris { animation: studioTexteRepris .52s var(--c-pose); }
@keyframes studioTexteRepris {
  from { opacity: .3; filter: blur(3px); transform: translateY(3px); }
  to   { opacity: 1;  filter: blur(0);   transform: none; }
}
@media (prefers-reduced-motion: reduce) { .studio-prompt-input.repris { animation: none; } }

/* ⚠️ UNE IMAGE DANS UNE RÉPONSE EST UNE ILLUSTRATION, PAS UNE PIÈCE JOINTE. Amadou
   (26/08) : « il faut qu'il m'envoie des images pour que ce soit bien illustré ».
   Elle se pose donc dans le fil, bornée à la largeur de lecture, avec le même
   arrondi que les autres blocs — et jamais plus haute qu'un tiers d'écran, sinon
   une seule photo chasse le texte qu'elle illustre.
   ⚠️ Une image distante peut ne jamais arriver (lien mort, hébergeur qui refuse) :
   le filet et le fond restent visibles, donc le trou se lit comme un trou plutôt
   que comme une erreur d'affichage. */
.studio-msg-text.md .md-img {
  display: block;
  max-width: 100%;
  max-height: 34vh;
  width: auto;
  margin: var(--e-10) 0;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: rgba(var(--th-voile), .04);
  object-fit: contain;
}
/* ⚠️ Une image qui n'a pas chargé ne doit pas laisser un rectangle vide : sans
   dimension propre, elle retombe à zéro et disparaît de la mise en page — le texte
   se referme dessus au lieu de contourner un trou. */
.studio-msg-text.md .md-img:not([src]) { display: none; }
/* Plusieurs images qui se suivent forment une planche, pas une colonne. */
.studio-msg-text.md p:has(> .md-img + .md-img) {
  display: flex; flex-wrap: wrap; gap: var(--e-8);
}
.studio-msg-text.md p:has(> .md-img + .md-img) .md-img {
  flex: 1 1 var(--e-48); max-height: 24vh; margin: 0;
}

/* ⚠️⚠️ L'ASCENSEUR DE LA CONVERSATION, MÊME DÉFAUT QUE CELUI DU CHAMP. Amadou
   (26/08) : « c'est exactement la même chose que je t'avais dit la dernière fois,
   mais pour la barre dans le chat : c'est vraiment trop imposant, ce n'est pas dans
   la DA du site, et c'est moche ». Le réglage global fait 8 px avec un pouce en
   `--bg-hover` — sur un fil de conversation qui occupe tout l'écran, ce trait clair
   longe la réponse sur toute sa hauteur et attire l'œil autant que le texte.
   Ici il s'efface : fin, en voile du thème, et il ne se révèle qu'au survol du fil.
   ⚠️ `scrollbar-color` (Firefox) ET `::-webkit-scrollbar` (Chrome/Brave) — les deux
   moteurs ne lisent pas le même, et n'en poser qu'un laisse l'autre au trait clair
   du système. */
.studio-chat-messages {
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--th-voile), .06) transparent;
}
/* ⚠️⚠️ DEUXIÈME BAISSE — la première ne suffisait pas. Amadou (26/08) : « la barre
   est toujours trop lumineuse ». Elle était à 9 % au repos et montait à 11 % au
   survol du FIL. Mon erreur : raisonner en pourcentage. Sur un thème sombre, un
   voile BLANC à 9 % sur du presque-noir donne déjà un trait franc — ce qui compte
   n'est pas l'opacité mais l'ÉCART avec le fond, et il est maximal ici.
   Elle descend à 5 %, et surtout le survol du fil ne la révèle PLUS : seul le survol
   du pouce la marque, au moment où on va l'attraper. Le reste du temps, elle se
   devine. */
.studio-chat-messages::-webkit-scrollbar-thumb {
  background: rgba(var(--th-voile), .05);
  border-radius: var(--r-pilule);
  transition: background var(--t-moyen) var(--c-pose);
}
.studio-chat-messages::-webkit-scrollbar-thumb:hover { background: rgba(var(--th-voile), .13); }

/* ── Revenir en bas ──────────────────────────────────────────────────────────
   ⚠️⚠️ ELLE EST ACCROCHÉE À LA BARRE DE SAISIE, pas au fil. Amadou (27/08) : « le
   bouton pour descendre empiète sur la barre, et il change de position, droite,
   gauche ». Les deux défauts venaient du même endroit :
   • `bottom: 104px` était une distance FIXE depuis le bas du fil, alors que la
     barre grandit avec le texte (97 → 223 px mesurés), avec une photo jointe et
     avec l'étiquette « Modifier ». Passé un certain point, la barre montait sous
     la flèche et elles se recouvraient.
   • `left: 50%` se calculait sur toute la zone de chat, pas sur la barre — donc
     elle glissait de côté dès que la colonne des conversations se repliait.
   Posée dans la barre (qui est déjà `position: relative`), elle la suit en hauteur
   ET en largeur sans qu'aucun chiffre n'ait à être tenu à jour. */
/* ⚠️⚠️⚠️ ET SURTOUT : PLUS DE `translateX(-50%)` POUR CENTRER. C'était ÇA, le
   « il change de position, droite, gauche ». L'animation d'entrée `velbo-entree`
   anime `transform` (`translateY(4px)` → `none`) : tant qu'elle joue, elle REMPLACE
   le transform de la règle, donc le décalage de centrage disparaît et la flèche
   apparaît 16 px trop à droite avant de sauter à sa place. Mesuré en direct : centre
   999 px pendant l'animation, 983 px après — et l'animation rejoue à CHAQUE fois que
   la flèche revient, puisqu'on la sort de `display: none`.
   Le centrage passe donc par `left: 0; right: 0; margin-inline: auto`, qui ne touche
   pas au transform : les deux ne se marchent plus dessus. */
.studio-descendre {
  position: absolute;
  left: 0; right: 0;
  margin-inline: auto;
  top: calc(-1 * (var(--e-32) + var(--e-10)));
  width: var(--e-32); height: var(--e-32);
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-pilule);
  border: 1px solid var(--border-strong);
  background: var(--th-panneau);
  color: var(--th-texte-2);
  cursor: pointer; padding: 0;
  box-shadow: 0 var(--e-4) var(--e-14) rgba(var(--th-ombre), .3);
  z-index: 4;
  /* ⚠️⚠️ UNE TRANSITION, PAS UNE ANIMATION D'ENTRÉE. Amadou (27/08) : « elle doit
     disparaître avec un fondu, là c'est trop brusque ». Une `animation` ne joue qu'à
     l'apparition : le départ restait sec. Une transition, elle, marche dans les DEUX
     sens avec une seule écriture — et c'est le sens du départ qui manquait. */
  opacity: 1;
  transform: none;
  transition: opacity var(--t-long) var(--c-pose),
              transform var(--t-long) var(--c-pose),
              color var(--t-bref), border-color var(--t-bref);
}
.studio-descendre:hover { color: var(--th-texte); border-color: rgba(var(--th-accent-rgb), .45); }

/* ⚠️ ELLE RESTE DANS LE RENDU. `display: none` la ferait disparaître d'un coup —
   c'était le défaut. On la rend transparente, on la décale de quatre pixels vers le
   bas (elle s'en va par où elle est venue), et on coupe les clics.
   ⚠️ `visibility` est RETARDÉE de la durée du fondu : sans ce délai elle basculerait
   à la première image et emporterait le fondu avec elle. Et sans `visibility` du
   tout, un bouton transparent resterait attrapable au clavier. */
.studio-descendre.dehors {
  opacity: 0;
  transform: translateY(var(--e-4));
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--t-long) var(--c-sortie),
              transform var(--t-long) var(--c-sortie),
              visibility 0s linear var(--t-long);
}
@media (prefers-reduced-motion: reduce) {
  .studio-descendre, .studio-descendre.dehors { transition: none; }
}

/* ══ STUDIO — LE BLOC D'ACTIVITÉ, PLIÉ UNE FOIS LE TRAVAIL FINI ══════════════
   ⚠️ Déplié en permanence, il empile quatre ou cinq lignes au-dessus de CHAQUE
   réponse : utiles pendant que ça travaille, inutiles après, et un fil de dix
   échanges devient une suite de journaux techniques entrecoupés de texte.
   Replié, il ne laisse qu'une ligne, qu'on rouvre d'un clic. */
.studio-outil { font-size: var(--t-nano); }
.studio-outils.replie .studio-outil { display: none; }
.studio-outils.replie.ouvert .studio-outil { display: flex; }
.studio-outils-resume {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: inherit; font-size: var(--t-nano);
  color: var(--th-texte-3);
  text-align: left;
  opacity: .75;
  transition: opacity var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.studio-outils-resume::before { content: '▸ '; }
.studio-outils.ouvert .studio-outils-resume::before { content: '▾ '; }
.studio-outils-resume:hover { color: var(--th-texte-2); opacity: 1; }
/* Une seule ligne finie : la pastille verte n'a plus rien à signaler, elle
   n'est qu'un point de couleur de plus sur un fil qu'on veut calme. */
.studio-outils.replie:not(.ouvert) .studio-outil-pt { display: none; }

/* ══ RAYON VINTED D'UNE NICHE ════════════════════════════════════════════════
   Amadou (26/08) : « il faut que ça soit un véritable paramètre qui s'ouvre comme la
   partie journal ou paramètre. »
   ⚠️ ON EMPRUNTE : la carte est `modal-card--settings`, le champ de recherche est
   `.de-dd-q` (celui du déroulant maison), les pilules du fil reprennent `.jr-f`. Rien
   d'inventé, et AUCUNE valeur brute — tout passe par les jetons.
   ⚠️ `flex: 1 1 0` ET `min-height: 0` sur le corps : sans ça le pied est POUSSÉ DEHORS
   sur une fenêtre basse, exactement comme le bouton « Enregistrer » des Paramètres. */
.modal-card--rayon .ry-haut {
  padding: 0 var(--e-22) var(--e-14);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.ry-fil {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--e-4); margin-bottom: var(--e-10); min-height: var(--e-24);
}
/* Un cran du fil d'Ariane. Reprend la pilule de filtre du Journal (`.jr-f`). */
.ry-cran {
  font-size: var(--t-meta); padding: var(--e-4) var(--e-12); border-radius: var(--r-pilule);
  border: 1px solid var(--border-mid); background: transparent; color: var(--text-2);
  font-family: inherit; cursor: pointer;
  transition: color var(--t-moyen), border-color var(--t-moyen);
}
.ry-cran:hover { color: var(--text); border-color: var(--border-strong); }
.ry-cran.ici { background: var(--violet-tint-strong); border-color: transparent; color: var(--violet-light); cursor: default; }
.ry-sep { color: var(--text-3); font-size: var(--t-meta); }
.ry-q { margin-bottom: 0; }

/* ⚠️⚠️ PAS DE `flex: 1 1 0` ICI — MESURÉ : la liste s'écrasait à 24 px de haut alors
   qu'elle contenait ses 13 lignes. Avec une base flex à 0, le corps ne compte pour RIEN
   dans la hauteur intrinsèque de la carte : la carte ne grandit donc jamais, et il ne
   reste aucune place à distribuer. C'est le contraire du défaut des Paramètres (là, le
   corps refusait de rétrécir et poussait le pied dehors) — même famille, sens inverse.
   On copie le Journal (`.jr-corps`), qui n'a AUCUNE propriété flex : une hauteur, un
   plafond en vh, et le débordement qui défile. Il marche depuis des semaines. */
.ry-corps {
  overflow-y: auto;
  padding: var(--e-12) var(--e-16); height: 460px; max-height: 56vh;
}
/* Une ligne du catalogue. Reprend l'option du déroulant maison (`.de-dd-opt`), en
   deux colonnes : le nom, puis ce qu'il y a dessous. */
.ry-ligne {
  display: flex; align-items: center; gap: var(--e-12);
  padding: var(--e-10) var(--e-12); border-radius: var(--r-sm);
  cursor: pointer; font-size: var(--t-base); color: var(--text);
}
.ry-ligne:hover { background: var(--bg-hover); }
.ry-ligne.sel { background: var(--violet-tint); color: var(--violet-light); }
.ry-nom { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Le chemin complet, montré seulement dans les résultats de recherche : sans lui, deux
   « Robes » — celle des femmes et celle des enfants — sont indiscernables. */
.ry-voie { display: block; font-size: var(--t-micro); color: var(--text-3); margin-top: var(--e-2); }

/* ══ RÉGLAGES D'UN PACK — ce qu'il photographie ═════════════════════════════
   ⚠️⚠️ TOUT EST EMPRUNTÉ AU PANNEAU « RAYON VINTED » juste au-dessus : même corps qui
   défile, même ligne, même état choisi (`.ry-ligne.sel`). Inventer une deuxième façon de
   présenter une liste de choix, c'est la faire diverger au premier changement — le projet
   a payé six fois « emprunter, jamais inventer ».
   ⚠️ L'ÉTAT CHOISI SE VOIT AUSSI À LA GRAISSE, pas seulement à la teinte : un état qui ne
   tient qu'à une couleur disparaît pour qui la distingue mal, et l'ambre du site est déjà
   le doré de l'accent. */
.pkreg-corps {
  overflow-y: auto;
  padding: var(--e-12) var(--e-16); max-height: 56vh;
}
.pkreg-quoi, .pkreg-vide {
  font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-normal);
  margin: 0 0 var(--e-12); padding: 0 var(--e-12);
}
.pkreg-ligne {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--e-2);
  width: 100%; text-align: left;
  padding: var(--e-10) var(--e-12); border-radius: var(--r-sm);
  border: 1px solid transparent; background: transparent;
  font-family: inherit; font-size: var(--t-base); color: var(--text); cursor: pointer;
  transition: background var(--t-moyen), color var(--t-moyen);
}
.pkreg-ligne:hover { background: var(--bg-hover); }
.pkreg-ligne.est-choisi {
  background: var(--violet-tint); color: var(--violet-light);
  font-weight: var(--fw-moyen);
}
.pkreg-noms { line-height: var(--lh-serre); }
.pkreg-rayon { font-size: var(--t-micro); color: var(--text-3); }
.pkreg-ligne.est-choisi .pkreg-rayon { color: var(--violet-light); }
.pkreg-etat { flex: 1 1 auto; font-size: var(--t-meta); color: var(--text-3); }

/* ══ CHOISIR UN PACK POUR LA GÉNÉRATION ════════════════════════════════════
   ⚠️⚠️ RIEN N'EST DESSINÉ ICI : les cartes sont celles de l'écran Packs (`.pk-portes`,
   `.pk-porte`, `.lib-niches-grille`, `.lib-niche`) et le fil celui de la Bibliothèque
   (`.lib-fam-fil`). Cette feuille ne pose que le CADRE — la fenêtre et le corps qui
   défile. Redessiner une carte ici, ce serait deux apparences à tenir pour la même
   chose, et elles divergeraient au premier changement. */
.modal-card--pkchoix { width: min(980px, 92vw); }
.pkx-haut {
  padding: 0 var(--e-22) var(--e-12);
  flex-shrink: 0;
}
/* ⚠️ IL DIT CE QUI REMONTE, ET QUE RIEN N'EST CACHÉ. Amadou : « il remonte, sans
   cacher » — un ordre qu'on ne nomme pas ressemble à un filtre qui a mangé le reste. */
.pkx-dit {
  font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-normal);
  margin-top: var(--e-8);
}
/* ⚠️⚠️⚠️ LE SCROLLER N'EST PAS LA GRILLE, et c'est la correction d'un défaut mesuré à
   375 px. Quand `.pkx-corps` portait LUI-MÊME `.lib-niches-grille`, ses rangées tombaient
   à 2 px : une carte `.lib-niche` n'a que du contenu ABSOLU et tire sa hauteur d'un
   `aspect-ratio: 4/5`, ce qui ne se résout pas dans un conteneur à `max-height` +
   `overflow`. Les cinquante cartes se chevauchaient. Relevé côte à côte : 408 px de
   rangée sur l'écran Packs, 2 px ici. On reprend son imbrication — le scroller dehors,
   la grille dedans. */
.pkx-corps {
  overflow-y: auto;
  padding: var(--e-12) var(--e-22) var(--e-22);
  max-height: 62vh;
}
/* ⚠️ LA MARGE BASSE DE `.lib-niches-grille` (32 px) doublerait le pas du scroller : elle
   est déjà donnée par le `padding` du corps. */
#pkx-grille { margin-bottom: 0; }
/* Un pack sans une seule photo ne peut rien donner au générateur : il se voit, il ne se
   choisit pas. ⚠️ ON L'ÉTEINT SANS LE CACHER — le faire disparaître laisserait croire
   qu'il n'existe pas, alors qu'il attend ses photos. */
.lib-niche--vide { opacity: .45; cursor: default; }

/* ══ L'HISTORIQUE DES IMPORTS ══════════════════════════════════════════════
   ⚠️ LA LIGNE EST CELLE DU JOURNAL, pas une nouvelle : vignette, corps, heure à droite.
   Deux listes qui se ressemblent sans être pareilles, c'est l'écart qu'on ne voit qu'en
   plaçant les deux écrans côte à côte. */
.imp-jour {
  display: flex; align-items: baseline; gap: var(--e-10);
  font-size: var(--t-micro); letter-spacing: var(--ls-caps); text-transform: uppercase;
  color: var(--text-3); padding: var(--e-20) var(--e-4) var(--e-8);
}
.imp-jour-note { text-transform: none; letter-spacing: var(--ls-zero); color: var(--text-3); }
.imp-ligne {
  display: flex; align-items: flex-start; gap: var(--e-12); width: 100%;
  text-align: left; font-family: inherit; cursor: pointer;
  padding: var(--e-10) var(--e-12); border-radius: var(--r-sm);
  border: 1px solid transparent; background: transparent; color: var(--text);
  border-top: 1px solid var(--border);
  transition: background var(--t-moyen);
}
.imp-ligne:hover { background: var(--bg-hover); }
.imp-vign {
  flex: none; width: var(--e-40); aspect-ratio: 4 / 5; overflow: hidden;
  border-radius: var(--r-xs); border: 1px solid var(--border); background: var(--surface-2);
}
.imp-vign img { width: 100%; height: 100%; object-fit: cover; display: block; }
.imp-corps { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--e-4); }
.imp-nom {
  font-size: var(--t-base); line-height: var(--lh-serre);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.imp-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--e-6); }
.imp-puce {
  font-size: var(--t-micro); padding: var(--e-2) var(--e-8); border-radius: var(--r-pilule);
  border: 1px solid var(--border-mid); color: var(--text-2);
}
.imp-puce--ok { border-color: var(--violet-mid); color: var(--violet-light); }
/* ⚠️ L'ABSENCE DE NICHE SE VOIT — c'est le fait qu'Amadou cherche : « je ne sais même pas
   où elle a été classée ». Et elle se distingue par sa FORME (un fond plein), pas
   seulement par sa teinte. */
/* ⚠️⚠️⚠️ `--red-tint` N'EXISTE PAS, ET JE L'AVAIS ÉCRIT. Un `var()` sur une variable non
   déclarée rend la déclaration invalide EN SILENCE — la pastille aurait été transparente,
   sans une erreur nulle part. Mesuré : déclaré 0 fois, utilisé 1 fois — par moi.
   ⚠️ ON EMPRUNTE LA PASTILLE ROUGE DU SITE (`.cok-badge.r`), qui existe et qui est tenue
   par les dix-sept thèmes. */
.imp-puce--sans { border-color: var(--cok-red); background: var(--cok-red-bg); color: var(--cok-red); }
.imp-chiffres { font-size: var(--t-micro); color: var(--text-3); }
.imp-heure {
  flex: none; font-size: var(--t-meta); color: var(--text-3);
  font-variant-numeric: tabular-nums; padding-top: var(--e-2);
}
.imp-manque {
  font-size: var(--t-meta); color: var(--text-2);
  border-left: var(--e-1) solid var(--border-mid); padding-left: var(--e-12);
  margin-bottom: var(--e-8);
}
.imp-vide { font-size: var(--t-meta); color: var(--text-3); padding: var(--e-20) var(--e-4); }
.ry-sous { flex: 0 0 auto; font-size: var(--t-micro); color: var(--text-3); }
.ry-chev { flex: 0 0 auto; color: var(--text-3); display: flex; }
.ry-vide { padding: var(--e-24) var(--e-12); text-align: center; color: var(--text-3); font-size: var(--t-base); }

/* Le pied : le choix courant à gauche, les boutons à droite. */
.ry-pied { padding: var(--e-14) var(--e-22); border-top: 1px solid var(--border); flex-shrink: 0; align-items: center; }
.ry-choix { margin-right: auto; font-size: var(--t-meta); color: var(--text-2); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ry-choix b { color: var(--text); font-weight: var(--fw-fort); }

/* ⚠️ AU FORMAT ÉTROIT, LE CHOIX DISPARAISSAIT. Mesuré à 390 px : « Rayon choisi :
   Maison › Outils et bricolage › Outils à main » était tronqué jusqu'à ne plus rien
   afficher, écrasé par les deux boutons. On perdait la seule chose qui dit ce qu'on
   s'apprête à valider. Il passe donc sur sa propre ligne, au-dessus des boutons.
   760 px : le point de rupture déjà employé neuf fois dans cette feuille. */
@media (max-width: 760px) {
  .ry-pied { flex-wrap: wrap; }
  .ry-choix {
    flex: 1 0 100%; margin-right: 0; margin-bottom: var(--e-10);
    white-space: normal; overflow: visible; line-height: 1.4;
  }
  /* ⚠️ LES DEUX BOUTONS NE TIENNENT PAS SUR UNE LIGNE, MESURÉ : 128 + 122 + 10 = 260 px
     pour 247 disponibles à 390 px de large — et c'est déjà avec le libellé raccourci en
     « Tout le catalogue » (qui reprend au passage le premier cran du fil d'Ariane).
     Les comprimer faisait déborder le texte de sa boîte ; les laisser s'empiler alignés
     à droite donnait un pied en escalier. On les passe donc PLEINE LARGEUR, comme le
     projet le fait déjà pour `.hist-panel-actions .btn-ghost`. */
  .ry-pied .btn-ghost, .ry-pied .btn-primary { width: 100%; justify-content: center; }
}

/* ══ AMÉLIORER UNE VUE ════════════════════════════════════════════════════════
   Amadou (02/09) : un bouton à côté d'« Importer », et un panneau de degrés. Le champ
   d'instructions de « Régénérer » ne s'ouvre qu'à la demande — il occupait la place sous
   chaque vue en permanence. */
/* ⚠️ LA ZONE VIDE EST LE BOUTON. Amadou (02/09) : « supprime le bouton importer, il ne
   sert à rien, j'ai juste à appuyer sur la partie du dessus ». Mesuré avant de le retirer :
   la zone n'était PAS cliquable et son curseur ne disait rien — le supprimer sans ça aurait
   ôté le seul chemin pour déposer une photo. */
.atelier-img-zone--cliquable { cursor: pointer; }
.atelier-img-zone--cliquable:hover { border-color: var(--violet); background: var(--bg-hover); }
.atelier-img-zone--cliquable:hover .atelier-img-placeholder { color: var(--text-2); }
.atelier-img-zone--cliquable:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; }
/* ⚠️ L'ÉTIQUETTE DU DEGRÉ (« décor rangé ») A ÉTÉ RETIRÉE LE 05/09. Amadou : « je ne vois
   pas l'utilité ». Elle nommait un travail DEMANDÉ, pas un résultat constaté — sur une
   photo dont la pièce n'avait pas bougé, elle décrivait une chose qui n'a pas eu lieu.
   Le pan est parti en entier : le dessinateur, cette règle et son garde-fou. */

.atelier-regen-box { display: flex; flex-direction: column; gap: var(--e-6); margin-top: var(--e-6); }
.atelier-regen-go { width: 100%; }
/* ⚠️ `.atelier-zone-travaille` A ÉTÉ RETIRÉE : c'était un simple estompage, alors que le
   site avait déjà un voile de travail — le balayage de la vérification. Amadou (02/09) :
   « il doit y avoir une animation comme la vérif de la conformité ». Un seul voile
   (`_atelierVoileTravail`) sert désormais l'amélioration ET le recadrage IA. */

/* ══ RÉGLAGES D'ATELIER D'UNE NICHE ═══════════════════════════════════════════
   Amadou (02/09) : « clic droit sur niche […] un espace où je vais pouvoir configurer
   pour l'Atelier ». Trois réglages, une fenêtre, aucun style neuf : les cartes de choix
   reprennent celles de l'Atelier (`.atelier-choix`), la fenêtre reprend `--settings`. */
/* ⚠️⚠️ 560 px, C'ÉTAIT DEUX FOIS TROP PETIT — et c'est la MÊME leçon que le Journal,
   écrite en toutes lettres dans index.html : « ma carte à 470 px ressemblait ». Amadou
   (03/09) : « ça prend la taille du journal, qui a vraiment de la place ». On ne surcharge
   donc plus la largeur : `modal-card--settings` donne 760 px et 86vh, comme Paramètres,
   comme le Journal, comme le Rayon. `--nial` ne garde que ce qui lui est propre. */
.nial-onglets { padding-top: var(--e-2); }
/* ⚠️⚠️ UNE HAUTEUR FIXE, PAS UN PLAFOND. Amadou (03/09) : « le panneau doit faire la
   même taille pour la partie génération et atelier ». Avec `max-height` seul, la carte
   se dimensionne sur son contenu : l'Atelier a trois sections et ses vues, la Génération
   deux — la fenêtre changeait donc de taille en cliquant un onglet, et le pied remontait
   sous la souris. C'est exactement ce que fait le Journal (`.jr-corps`), pour la même
   raison : on lui emprunte sa recette, `height` + `max-height`. */
.nial-corps {
  overflow-y: auto; padding: var(--e-12) var(--e-22) var(--e-20);
  height: 540px; max-height: 62vh;
}
.nial-chapeau { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-serre); }
.nial-titre {
  font-size: var(--t-mini); letter-spacing: var(--ls-caps); text-transform: uppercase;
  color: var(--text-3); margin: var(--e-20) 0 var(--e-8);
}
/* ⚠️ TROIS CHOIX DEPUIS LE 02/09 (« porté et objet »). `auto-fit` plutôt que trois colonnes
   en dur : à l'étroit, les cartes passent à la ligne au lieu d'être écrasées. */
.nial-duo { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: var(--e-8); }
.nial-carte {
  display: block; text-align: left; font-family: inherit; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12); color: var(--text); transition: var(--transi);
}
.nial-carte:not(.nial-carte--on):hover { border-color: var(--border-mid); background: var(--bg-hover); }
.nial-carte--on { border-color: var(--violet); background: var(--violet-tint); }
.nial-carte b { display: block; font-size: var(--t-base); font-weight: var(--fw-moyen); }
.nial-carte span { display: block; font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-2); }
.nial-note { font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-8); line-height: var(--lh-serre); }

/* Une vue : son rang, son nom, et de quoi la déplacer ou la retirer. */
.nial-vues { display: flex; flex-direction: column; gap: var(--e-6); }
/* La consigne d'une vue, dans sa fenêtre. ⚠️ Amadou (02/09) : « quand j'appuie sur le
   prompt, ça doit ouvrir un mini panneau ». Dépliée sous la carte, elle se lisait dans une
   colonne de 190 px — six mots par ligne pour deux mille caractères. */
.atl-consigne-modal {
  position: fixed; inset: 0; z-index: 120;
  background: rgba(var(--th-ombre), 0.62);
  display: flex; align-items: center; justify-content: center; padding: var(--e-20);
}
.atl-consigne-carte {
  width: min(560px, 94vw); max-height: 76vh; display: flex; flex-direction: column;
  background: var(--th-panneau); border: 1px solid var(--border);
  border-radius: var(--r-panneau); overflow: hidden;
}
.atl-consigne-tete {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-16) var(--e-20); border-bottom: 1px solid var(--border);
}
.atl-consigne-tete h3 { margin: 0; font-size: var(--t-body); font-weight: var(--fw-moyen); }
.atl-consigne-corps {
  overflow-y: auto; padding: var(--e-16) var(--e-20) var(--e-20);
  font-size: var(--t-meta); line-height: var(--lh-aere); color: var(--text-2);
  white-space: pre-wrap;
}

/* ⚠️ LA CONSIGNE DE PRISE DE VUE (02/09) : écrite une fois dans la niche, elle voyage
   jusqu'au générateur. Même dessin que les autres champs du site. */
.nial-consigne {
  width: 100%; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm); color: var(--text); font-family: inherit;
  font-size: var(--t-meta); padding: var(--e-8); resize: vertical;
  line-height: var(--lh-normal);
}
.nial-consigne:focus { outline: none; border-color: var(--violet); }
.nial-consigne:disabled { opacity: 0.5; cursor: default; }
.nial-consigne--vue { margin-top: var(--e-6); font-size: var(--t-mini); }

/* La photo de départ d'une vue : une vignette qui EST le bouton.
   ⚠️ Un carré vide qui ne dit pas qu'il se clique ne se clique pas — d'où la bordure
   pointillée et l'icône quand rien n'est posé. */
.nial-tpl {
  width: 34px; height: 42px; flex: none; padding: 0; cursor: pointer;
  border: 1px dashed var(--border-strong); border-radius: var(--photo-rayon);
  background: transparent center/cover no-repeat;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3); transition: border-color var(--t-moyen);
}
.nial-tpl:hover { border-color: var(--violet-light); color: var(--text-2); }
.nial-tpl--pleine { border-style: solid; border-color: var(--border-mid); }

/* ⚠️ LES STYLES DU DIAGNOSTIC DES NICHES ONT ÉTÉ RETIRÉS AVEC LUI (04/09). Amadou :
   « tu pourras aussi supprimer le bouton diagnostic » — la gestion passe par la
   BIBLIOTHÈQUE DE PACKS, un sous-onglet à part entière. Du CSS qui ne style plus rien se
   fait recopier par le suivant qui cherche un motif, et surtout il garde des noms qui se
   remettent à gagner tout seuls le jour où quelqu'un les réutilise. */

/* ══ LA BIBLIOTHÈQUE DE PACKS ════════════════════════════════════════════════
   Amadou (04/09) : « l'écran des réglages, ce sera la nouvelle bibliothèque de packs.
   C'est ici qu'on va gérer les packs. »
   Un pack se lit d'un coup d'œil : ses prises de vue en vignettes, son type, et les
   niches qu'il sert. ⚠️ AUCUNE VALEUR BRUTE — tout passe par les jetons. */

/* ⚠️ IL DIT CE QUI MANQUE, PAS CE QUI VA : 7 niches sur 9 n'ont aucun pack, et la
   Génération leur sert les vues d'origine sans qu'un seul écran le dise. */
.pk-manque {
  display: flex; align-items: flex-start; gap: var(--e-10);
  padding: var(--e-12) var(--e-14); margin-bottom: var(--e-16);
  border-radius: var(--r-lg); border: 1px solid var(--amber);
  background: var(--surface-2);
  font-size: var(--t-base); color: var(--text-2); line-height: var(--lh-normal);
}
.pk-manque svg { flex: none; color: var(--amber); margin-top: var(--e-2); }
.pk-manque b { color: var(--text); font-weight: var(--fw-moyen); }

/* ⚠️⚠️⚠️ DE LA PLACE POUR LE SURVOL, DANS L'ATELIER SEULEMENT. Amadou (05/09) : « quand
   je survole une des recettes, le haut se coupe ». La porte se lève de 2 px au survol, et
   `.atelier-step-body` est en `overflow: hidden` — il le doit, c'est lui qui anime le
   dépliage de l'étape. On ne peut pas lui rendre son débordement sans casser l'animation :
   on donne la place À L'INTÉRIEUR, exactement comme le 02/09 pour les cartes de niches.
   ⚠️ SCOPÉ À L'ATELIER : dans l'onglet Packs le canevas déborde librement, et y ajouter du
   creux décalerait les trois portes sans raison. */
#atelier-step-1 .pk-portes { padding-top: var(--e-6); }

/* ══ LES TROIS PORTES — TRAITEMENT TYPOGRAPHIQUE ═══════════════════════════════
   Amadou (05/09) a choisi cette mise en page après en avoir vu trois : le nom en grand
   calé EN BAS À GAUCHE, un numéro d'ordre au-dessus, un filet, le compte — et la
   silhouette de la recette en filigrane derrière.
   ⚠️⚠️ ELLE N'EMPRUNTE PLUS `.lib-fam-carte`, et c'est assumé : cette carte-là centre
   tout. Lui imposer ce plan demanderait de redire la moitié de ses propriétés, et le jour
   où la carte des Familles bouge, celle des recettes bougerait avec elle sans raison.
   ⚠️ TROIS PORTES, ÇA SE DIT `repeat(3, …)` — pas un `auto-fill` fait pour dix-sept
   familles, qui remplirait trois colonnes sur huit.
   ⚠️ `minmax(0, 1fr)` ET PAS `1fr` : le défaut d'une colonne de grille est
   `min-width: auto`, donc un nom long la pousse au-delà du conteneur. */
.pk-portes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--e-16);
}

/* ⚠️⚠️⚠️ UNE HAUTEUR FIXE, ET C'EST LA TROISIÈME FOIS QU'ON LA RÈGLE. Étape 1 : trois
   cartes de 214 px perdues dans un canevas de 1098 — « il doit prendre toute la place ».
   Étape 2 : elles ont pris TOUTE la place, soit 550 × 850 px avec une icône de 96 px au
   milieu — « l'interface ne me plaît pas ». Trois portes larges, hauteur humaine. */
.pk-porte {
  position: relative;
  height: calc(var(--e-48) * 7);
  overflow: hidden;
  display: block;
  text-align: left;
  padding: var(--e-20);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  background: var(--bg-card-solid);
  font-family: inherit;
  cursor: pointer;
  transition: border-color var(--t-moyen), transform var(--t-moyen);
  animation: velbo-entree var(--t-long) var(--pose) backwards;
  animation-delay: calc(var(--rang, 0) * 55ms);
}
@media (prefers-reduced-motion: reduce) { .pk-porte { animation: none; } }
.pk-porte:hover { border-color: var(--violet-mid); transform: translateY(calc(var(--e-2) * -1)); }
/* ⚠️⚠️ UNE RECETTE SANS PACK RESTE AFFICHÉE — c'est justement là qu'il faut aller. Mais
   elle doit se VOIR : mesuré à 900 px, ses deux portes étaient peintes, à la bonne place,
   opacité 1 — et invisibles à l'œil, leur filet à 0,114 d'alpha se noyant sur ce fond.
   Une carte qu'on ne voit pas est une carte qu'on ne clique pas. Le projet avait déjà
   tranché la même question pour la carte « Nouvelle niche » : le filet MOYEN est le
   minimum ici. La différence se dit alors par le filigrane et le numéro, qui prennent
   l'accent. */
.pk-porte--vide { border-color: var(--border-mid); }

/* La silhouette : GRANDE, à droite, et très pâle. Elle teinte la carte, elle ne se lit
   pas. ⚠️ `pointer-events: none` : sinon elle intercepte le clic destiné à la porte. */
.pk-porte-sil {
  position: absolute;
  right: calc(var(--e-12) * -1);
  top: var(--e-16);
  bottom: var(--e-48);
  display: block;
  pointer-events: none;
  color: var(--text-3);
  opacity: 0.14;
}
.pk-porte--vide .pk-porte-sil { opacity: 0.1; }
.pk-porte-sil svg { height: 100%; width: auto; }
.pk-porte:not(.pk-porte--vide) .pk-porte-sil { color: var(--violet-soft); opacity: 0.16; }

/* Le bloc de texte, calé en bas à gauche. */
.pk-porte-bas {
  position: absolute;
  left: var(--e-20); right: var(--e-20); bottom: var(--e-18);
  display: block;
}
.pk-porte-num {
  display: block; margin-bottom: var(--e-6);
  font-size: var(--t-mini); letter-spacing: var(--ls-caps); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.pk-porte:not(.pk-porte--vide) .pk-porte-num { color: var(--violet-light); }
.pk-porte-nom {
  display: block;
  font-size: var(--t-title); font-weight: var(--fw-fort);
  line-height: var(--lh-titre); color: var(--text);
}
/* Le filet vit sur le compte : une ligne de moins dans le DOM, et il ne peut pas se
   retrouver seul si le compte disparaît. */
.pk-porte-n {
  display: block; margin-top: var(--e-10); padding-top: var(--e-10);
  border-top: 1px solid var(--border);
  font-size: var(--t-meta); color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.pk-porte--vide .pk-porte-n { color: var(--text-3); }

/* ⚠️ EN DESSOUS DE 980 px, TROIS COLONNES DEVIENNENT TROIS COULOIRS : à 900 px de fenêtre
   et barre latérale dépliée, il reste 596 px pour trois portes, soit 188 de large. On
   raccourcit plutôt que d'empiler — trois cartes qui se voient d'un coup, c'est tout
   l'intérêt de n'en avoir que trois. */
@media (max-width: 980px) {
  .pk-porte { height: calc(var(--e-48) * 5); padding: var(--e-14); }
  .pk-porte-bas { left: var(--e-14); right: var(--e-14); bottom: var(--e-12); }
  .pk-porte-nom { font-size: var(--t-body); }
  .pk-porte-sil { bottom: var(--e-40); right: calc(var(--e-8) * -1); }
}

/* ⚠️⚠️ LA BARRE DE SOUS-ONGLETS, DÉNUDÉE. `an-souso` est une BANDE : dégradé, bordure
   basse, 32 px de marge — taillée pour vivre pleine largeur sous le bandeau. Au milieu
   d'une page elle dessine un rectangle qui n'a rien à faire là. On garde les pastilles,
   on retire la bande, et on les centre. */
.an-souso--nu {
  justify-content: center;
  padding: 0;
  background: none;
  border-bottom: 0;
}

/* ══ LA PAGE D'UN PACK — TROISIÈME ÉTAGE ═══════════════════════════════════════
   Amadou (04/09) : « ça doit ouvrir une page entière maintenant, ça va fortement
   ressembler à un pack comme ça niveau interface ». Le modèle est la fiche d'une
   mannequin : un grand titre, un intitulé en petites capitales souligné, puis les photos
   en ligne avec leur nom dessous.
   ⚠️ TOUTES LES CLASSES SONT EN `pkp-` : une autre session travaille dans cette feuille au
   même moment, sur des `pk-l-*`. Un préfixe à part, c'est zéro croisement possible. */
.pkp { display: flex; flex-direction: column; gap: var(--e-18); }
.pkp-tete h2 {
  margin: 0; font-size: var(--t-title); font-weight: var(--fw-fort);
  line-height: var(--lh-titre); color: var(--text);
}
.pkp-sous { margin-top: var(--e-4); font-size: var(--t-base); color: var(--text-2); }

.pkp-vues {
  /* ⚠️⚠️ UNE RANGÉE CENTRÉE, PLUS UNE GRILLE ÉTALÉE. Amadou (04/09) : « diminue l'espace
     entre les vues et elles doivent être centrées ». Une grille de colonnes égales étale
     les vignettes sur toute la largeur quoi qu'on fasse — c'est son métier. Un `flex`
     centré les groupe, et l'écart devient vraiment l'écart entre deux photos.
     ⚠️ `flex-wrap` : une recette de six vues ne doit pas déborder de l'écran. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--e-10);
}
.pkp-v { display: flex; flex-direction: column; gap: var(--e-10); }

/* ⚠️ LA PHOTO EST UN BOUTON PLEIN CADRE : c'est le geste principal de cette page. */
.pkp-ph {
  position: relative;
  /* ⚠️⚠️⚠️ 3:4, ET LA HAUTEUR COMMANDE. Amadou (04/09) : « les photos doivent être en
     format 3:4, pas carré ». Trois réglages ont précédé : le ratio seul faisait 735 px de
     haut pour 551 de large (trop haut), la hauteur seule faisait un cadre paysage qui
     rognait la photo (carré à l'œil). Ici la hauteur est fixe ET le ratio tenu : la
     LARGEUR s'en déduit, 288 px, et la vignette se centre dans sa colonne.
     ⚠️ La colonne, elle, reste à `1fr` — la RANGÉE tient toujours toute la largeur, ce
     sont les photos qui ne s'étirent plus. */
  aspect-ratio: 3 / 4;
  height: calc(var(--e-48) * 8);
  width: auto; max-width: 100%; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-6); padding: 0; cursor: pointer; font-family: inherit;
  font-size: var(--t-meta); color: var(--text-3);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-lg); transition: var(--transi);
}
.pkp-ph:hover { border-color: var(--violet-soft); color: var(--text-2); }
.pkp-ph svg { width: var(--e-24); height: var(--e-24); }
/* ⚠️⚠️ `object-position: center top` — ET C'EST LE DÉTAIL QUI COMPTE. Les photos de départ
   sont des selfies en pied dans un miroir : un cadre plus large que haut les recoupe, et
   un recadrage centré coupe la tête. On garde le haut. */
.pkp-ph img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
}
/* ⚠️ « Remplacer » NE S'AFFICHE QU'AU SURVOL D'UNE VIGNETTE PLEINE : posé en permanence,
   il masque le coin de la photo qu'on vient justement regarder. */
.pkp-remp {
  position: absolute; right: var(--e-8); bottom: var(--e-8); z-index: 1;
  padding: var(--e-4) var(--e-10); border-radius: var(--r-pilule);
  background: rgba(var(--th-ombre), 0.72); color: var(--sur-sombre);
  font-size: var(--t-mini); opacity: 0; transition: var(--transi);
}
.pkp-ph--pleine:hover .pkp-remp { opacity: 1; }

/* La légende — celle de la fiche d'une mannequin : centrée, petites capitales grises.
   ⚠️ Le mode se lit ICI, en clair, sans pastille : une pastille violette à côté d'un
   libellé n'existe nulle part ailleurs sur le site. */
.pkp-lg {
  text-align: center;
  font-size: var(--t-mini); letter-spacing: var(--ls-caps);
  color: var(--text-3); line-height: var(--lh-serre);
}

/* ⚠️ L'ENTÊTE D'UNE VUE, SA PASTILLE DE MODE ET SA CONSIGNE ONT ÉTÉ RETIRÉES (04/09).
   Amadou : « enlève le texte en dessous là, qui ne sert à rien — ce que cette vue doit
   montrer, on s'en fiche ». Une vue, c'est une photo et sa légende. La donnée `consigne`,
   elle, reste écrite : le champ a disparu, pas ce qui était déjà saisi. */

/* ══ LES COMPTES D'UN PACK — DEUX RANGÉES ══════════════════════════════════════
   Amadou (05/09) : ceux en service en grand, ceux qu'on peut ajouter en petit dessous, et
   la recherche SOUS les bulles. Avant : deux listes empilées dont un mur de quatorze
   pastilles grises toutes pareilles — on ne voyait ni qui servait, ni ce qui manquait.
   ⚠️ CENTRÉ, comme la rangée des vues : les deux onglets d'une même page ne peuvent pas
   avoir deux alignements. */
.pkp-mur {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--e-22);
}
/* ⚠️⚠️ DE L'AIR AU-DESSUS. Amadou : « les icônes sont trop collées ». Les ronds venaient
   à 12 px sous les pastilles d'onglet : la barre et la première rangée se lisaient comme
   un seul bloc. */
.pkp-mur--grand { margin-top: var(--e-24); }
.pkp-mur--petit { gap: var(--e-14); }

.pkp-cpt {
  display: flex; flex-direction: column; align-items: center; gap: var(--e-2);
  padding: 0; cursor: pointer; font-family: inherit; text-align: center;
  background: none; border: 0; color: inherit;
  transition: var(--transi);
}
.pkp-mur--grand .pkp-cpt { width: calc(var(--e-48) * 2 + var(--e-10)); }
.pkp-mur--petit .pkp-cpt { width: calc(var(--e-48) + var(--e-20)); }
.pkp-cpt:not(:disabled):hover .pkp-rond { border-color: var(--violet-soft); }
.pkp-cpt:disabled { cursor: not-allowed; }

/* Le rond. ⚠️ `overflow: hidden` ET l'image en `cover` : un avatar Vinted n'est pas carré,
   et sans ça il déborde du cercle par un coin. */
.pkp-rond {
  position: relative; border-radius: 50%; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--e-8);
  line-height: var(--lh-un); color: var(--text-3);
  background: var(--surface-2);
  border: 1.5px dashed var(--border-strong);
  transition: var(--transi);
}
.pkp-rond img { width: 100%; height: 100%; object-fit: cover; }
.pkp-mur--grand .pkp-rond {
  width: calc(var(--e-48) * 2); height: calc(var(--e-48) * 2);
  font-size: var(--t-title);
}
.pkp-mur--petit .pkp-rond {
  width: var(--e-48); height: var(--e-48);
  font-size: var(--t-base); margin-bottom: var(--e-6);
}

/* ⚠️⚠️ EN SERVICE SE DIT PAR LE CERCLE, PAS PAR LA TEINTE DU FOND : l'ambre et l'accent
   sont le même doré sur certains thèmes, et un fond accentué se lirait « survolé ». Le
   trait plein contre le pointillé, lui, se voit dans les dix-sept. */
.pkp-cpt--on .pkp-rond { border-style: solid; border-color: var(--violet); }
.pkp-cpt--bloque { opacity: 0.42; }
/* ⚠️ Un compte disparu se dit par la couleur d'ALERTE, jamais par l'accent. */
.pkp-cpt--perdu .pkp-rond { border-style: solid; border-color: var(--amber); color: var(--amber); }
.pkp-cpt--perdu .pkp-cpt-nom, .pkp-cpt--perdu .pkp-cpt-etat { color: var(--amber); }

/* Le cadenas se pose PAR-DESSUS le visage : on veut savoir QUI est bloqué. */
.pkp-cadenas {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(var(--th-ombre), 0.55); color: var(--sur-sombre);
}
.pkp-cadenas svg { width: var(--e-18); height: var(--e-18); }

.pkp-cpt-nom { font-size: var(--t-meta); color: var(--text-2); line-height: var(--lh-serre); }
.pkp-mur--petit .pkp-cpt-nom { font-size: var(--t-mini); }
.pkp-cpt-etat { font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-serre); }

.pkp-bilan {
  text-align: center; margin-top: var(--e-16);
  font-size: var(--t-mini); letter-spacing: var(--ls-caps); color: var(--text-3);
}
/* Le second étage, sous son filet. */
.pkp-bas { margin-top: var(--e-22); padding-top: var(--e-20); border-top: 1px solid var(--border); }
.pkp-bilan--titre { margin-top: 0; margin-bottom: var(--e-16); }

/* ⚠️ LA RECHERCHE EST SOUS LES BULLES, et c'est demandé. L'usage la met au-dessus ; ici
   elle filtre ce qui est juste au-dessus d'elle, et on la trouve en descendant. */
.pkp-rech { display: flex; justify-content: center; margin-top: var(--e-18); }
.pkp-rech-champ {
  width: calc(var(--e-48) * 5); max-width: 100%;
  padding: var(--e-8) var(--e-12); font-family: inherit; font-size: var(--t-base);
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-pilule);
}
.pkp-rech-champ:focus { outline: none; border-color: var(--violet-soft); }

.pkp-vide { font-size: var(--t-base); color: var(--text-3); font-style: italic; }

.pk-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(206px, 1fr));
  gap: var(--e-14);
}

/* ⚠ LES TROIS RECETTES N’ONT PAS DE CARTE À ELLES : elles empruntent `.lib-fam-carte`,
   le mur des familles. Une carte maison (lettre, vues, ronds de comptes) a vécu ici le
   04/09 — Amadou : « ça doit être comme l’onglet familles, même config ». Elle est
   partie avec ses onze règles ; il ne reste rien à tenir de ce côté. */
.pk-pack {
  display: block; text-align: left; font-family: inherit; cursor: pointer; padding: 0;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-carte); overflow: hidden; color: inherit;
  transition: border-color var(--t-moyen), transform var(--t-moyen);
}
/* ⚠️ `:not(.pk-neuf)` : la carte « Nouveau pack » est en pointillé, la soulever la ferait
   passer pour une carte pleine. */
.pk-pack:not(.pk-neuf):hover { border-color: var(--violet-soft); transform: translateY(-3px); }

/* Les prises de vue, en bande. ⚠️ UNE CASE VIDE EST MONTRÉE, et c'est voulu : un pack à
   deux vues sur trois se voit d'un coup d'œil. Sans elle, il faudrait compter. */
/* ⚠️ LE NOMBRE DE COLONNES VIENT DU CONTENU (`--pk-cols`, posé par le rendu). Figé à
   trois, un pack de trois vues renvoyait « + une vue » à la ligne suivante et creusait
   deux trous à côté d'elle. */
.pk-vues { display: grid; grid-template-columns: repeat(var(--pk-cols, 3), 1fr);
           gap: var(--e-1); background: var(--border); }
.pk-vue {
  aspect-ratio: 3 / 4; position: relative; display: flex; align-items: flex-end;
  background: var(--surface) center/cover no-repeat;
}
.pk-vue span {
  font-size: var(--t-micro); color: var(--text-2); padding: var(--e-4) var(--e-6);
  line-height: var(--lh-serre);
  /* ⚠️ LE NOM SE LIT SUR N'IMPORTE QUELLE PHOTO : une plaque sombre, pas une couleur de
     texte. Les fonds mentent selon la clarté — même alpha, ×1,02 sur une nuit et ×2,78
     sur du sable. */
  background: rgba(var(--th-ombre), 0.55); width: 100%;
}
.pk-vue--nue { background: var(--surface-2); }
.pk-vue--nue span { background: none; color: var(--text-3); }
.pk-vue--plus {
  align-items: center; justify-content: center;
  border: 1px dashed var(--border-strong); background: transparent;
}
.pk-vue--plus span { background: none; color: var(--text-3); text-align: center; width: auto; }

.pk-bas { padding: var(--e-10) var(--e-12) var(--e-12); }
.pk-bas b { display: block; font-size: var(--t-base); font-weight: var(--fw-moyen); color: var(--text); }
.pk-type {
  display: inline-block; margin-top: var(--e-4);
  font-size: var(--t-mini); padding: var(--e-1) var(--e-8); border-radius: var(--r-pilule);
}
.pk-type--porte { background: var(--violet-tint); color: var(--violet-light); }
.pk-type--seul  { background: var(--surface); color: var(--text-3); }
.pk-sert {
  display: block; margin-top: var(--e-6);
  font-size: var(--t-mini); color: var(--text-3); line-height: var(--lh-serre);
}
.pk-sert i { font-style: italic; }
/* ⚠️ Une niche disparue se signale par sa COULEUR D'ALERTE, pas par l'accent : l'ambre et
   l'accent sont le même doré ici, et un texte accentué se lirait « sélectionné ». */
.pk-perdu { color: var(--amber); }

/* ⚠⚠ UN FILET EN POINTILLÉ A BESOIN DU FILET MOYEN. Mesuré le 04/09 : la carte héritait
   du `--border` de `.pk-pack` (alpha 0,114) et, en pointillé, elle DISPARAISSAIT — 192 px
   de carte invisible à côté d'une carte pleine. Le projet avait déjà tranché ailleurs :
   `.lib-niche--neuve`, la carte « Nouvelle niche », est en `--border-mid` (0,23).
   ⚠ ELLE N'EMPRUNTE PAS `_carteNouvelleNiche` pour autant : ce dessinateur rend une carte
   de 268 px, taillée pour le mur des niches. Dans cette grille-ci, la ligne s'étirerait à
   268 et les cartes de packs s'étireraient avec elle, bande de vues en haut et vide en
   bas. On emprunte la DÉCISION, pas la brique. */
.pk-neuf {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e-6); min-height: calc(var(--e-48) * 4);
  border-style: dashed; border-color: var(--border-mid);
  background: transparent; color: var(--text-3);
}
.pk-neuf:hover { border-color: var(--violet); color: var(--violet-light); }

/* ── L'ÉDITEUR ────────────────────────────────────────────────────────────── */
.pk-champ { margin-bottom: var(--e-16); }
.pk-nom-pack, .pk-nom, .pk-consigne {
  width: 100%; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-sm); color: var(--text); font-family: inherit;
  font-size: var(--t-base); padding: var(--e-8); line-height: var(--lh-normal);
}
.pk-nom-pack:focus, .pk-nom:focus, .pk-consigne:focus { outline: none; border-color: var(--violet); }
.pk-consigne { resize: vertical; font-size: var(--t-mini); margin-top: var(--e-4); }

.pk-titre-sec {
  font-size: var(--t-mini); letter-spacing: var(--ls-caps); text-transform: uppercase;
  color: var(--text-3); margin: var(--e-20) 0 var(--e-8);
}
.pk-duo { display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: var(--e-8); }
.pk-choix {
  display: block; text-align: left; font-family: inherit; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: var(--e-10) var(--e-12); color: var(--text); transition: var(--transi);
}
/* ⚠️ `:not(.active)` DEVANT `:hover` — la réparation retenue par le projet
   (`outils/verifier-survol-etat.py`) : sans elle, le doigt posé sur le choix RETENU lui
   enlève sa couleur, et on ne sait plus ce qu'on a choisi au moment où on le regarde. */
.pk-choix:not(.active):hover { border-color: var(--border-mid); background: var(--bg-hover); }
.pk-choix.active { border-color: var(--violet); background: var(--violet-tint); }
.pk-choix b { display: block; font-size: var(--t-base); font-weight: var(--fw-moyen); }
.pk-choix.active b { color: var(--violet-light); }
.pk-choix span { display: block; font-size: var(--t-mini); color: var(--text-3); margin-top: var(--e-2); }

.pk-niches { display: flex; flex-wrap: wrap; gap: var(--e-6); }
.pk-niche {
  font-family: inherit; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-pilule);
  padding: var(--e-4) var(--e-12); color: var(--text-2); font-size: var(--t-base);
  transition: var(--transi);
}
.pk-niche:not(.active):hover { border-color: var(--border-mid); color: var(--text); }
.pk-niche.active { border-color: var(--violet); background: var(--violet-tint); color: var(--violet-light); }
/* ⚠ UN COMPTE DÉJÀ PRIS RESTE LISIBLE, JUSTE ÉTEINT : le masquer ferait croire que le
   compte n'existe pas, alors qu'il a simplement déjà sa variante dans cette recette. */
.pk-niche--pris { opacity: 0.55; }
.pk-vide { font-size: var(--t-mini); color: var(--text-3); }
.pk-aide { font-size: var(--t-mini); color: var(--text-3); margin: var(--e-8) 0 0; line-height: var(--lh-normal); }

.pk-lignes { display: flex; flex-direction: column; gap: var(--e-8); }
.pk-ligne {
  display: flex; align-items: flex-start; gap: var(--e-10);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--e-10);
}
.pk-ligne-txt { flex: 1 1 auto; min-width: 0; }
/* La photo de départ : une vignette QUI EST le bouton. ⚠️ Un carré vide qui ne dit pas
   qu'il se clique ne se clique pas — d'où le pointillé et l'icône. */
.pk-tpl {
  flex: none; width: calc(var(--e-48) + var(--e-8)); aspect-ratio: 3 / 4;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  background: transparent center/cover no-repeat;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-3); cursor: pointer; transition: border-color var(--t-moyen);
}
.pk-tpl:hover { border-color: var(--violet-light); color: var(--text-2); }
.pk-tpl--pleine { border-style: solid; border-color: var(--border-mid); }
.pk-vue-x { flex: none; }
.pk-ajout { width: 100%; margin-top: var(--e-10); }
/* ⚠️ LA SUPPRESSION EST À GAUCHE, loin du geste qu'on fait vingt fois. */
.pk-suppr { margin-right: auto; color: var(--red); border-color: var(--red); }

/* ══ L'ÉCRAN « PRODUIT SEUL » ════════════════════════════════════════════════
   Amadou (04/09) : une SEULE carte, de haut en bas — le produit, ses vues, le prix et le
   bouton. Avant : deux colonnes côte à côte dont la gauche restait vide une fois le
   produit choisi.
   ⚠️ AUCUNE VALEUR BRUTE, tout passe par les jetons — c'est la règle du fichier. */
/* ══ UN SEUL ÉTAGE ═══════════════════════════════════════════════════════════
   Amadou (04/09) : « ça peut tenir en un étage, pas deux — l'espace disponible est
   gaspillé ». Le produit à gauche, ses vues à droite, le pied en travers.
   ⚠️ LA DROITE EST PLUS LARGE, ET C'EST VOULU : chaque vue porte deux lignes de texte,
   les photos n'en portent aucune. À largeur égale, les consignes se coupaient. */
.pv-deux {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
  gap: var(--e-22); align-items: stretch;
}
/* ⚠️⚠️ LES DEUX COLONNES S'ÉTIRENT, ET C'EST TOUT L'OBJET DE LA REFONTE. En `start`, la
   gauche s'arrêtait sous ses deux boutons : 73 px de contenu pour 321 px de colonne,
   soit 248 px de vide — exactement « l'espace disponible est gaspillé » d'Amadou. En
   colonne flex, la porte d'entrée peut prendre la place qui reste. */
.pv-col { min-width: 0; display: flex; flex-direction: column; }
/* ⚠️ SOUS 900 px LES DEUX COLONNES S'EMPILENT. Côte à côte sur un écran étroit, chaque
   moitié tombe sous 200 px et tout se coupe — le pire des deux mondes. */
@media (max-width: 900px) { .pv-deux { grid-template-columns: minmax(0, 1fr); } }

/* ── LA PORTE D'ENTRÉE : SEULE À L'ÉCRAN TANT QU'IL N'Y A RIEN ────────────────
   ⚠️⚠️ LA CLASSE MANQUAIT SUR L'ÉLÉMENT (04/09) : ces règles étaient écrites pour
   `.pv-vide`, mais le `div` ne portait que l'IDENTIFIANT `pv-vide`. Elles n'ont jamais
   rien stylé, et c'est `.upload-actions` (une grille 1,5fr / 1fr) qui rendait l'écran.
   Un sélecteur qui ne touche rien ne prévient pas : il faut regarder l'écran.

   ⚠️⚠️⚠️ DEUX FOIS REPRISE SUR CETTE SEULE ZONE, ET C'EST LA MÊME ERREUR DE HIÉRARCHIE.
   D'abord elle s'étirait à 238 px pour combler le vide d'une colonne : « beaucoup trop
   grande ». Puis, réduite à 132 px mais posée EN HAUT, elle accaparait encore l'œil :
   « le bouton Choisir un produit prime sur la drop zone ». Neuf fois sur dix le produit
   vient de la bibliothèque — c'est LUI le geste principal.
   Ordre définitif : la phrase, le bouton, puis la zone en bande fine. Elle reste large
   et déposable sur toute la ligne : on baisse son poids visuel, pas sa cible. */
.pv-vide {
  display: flex; flex-direction: column; align-items: center;
  padding: var(--e-24) 0 0;
}
/* ⚠️ LA PHRASE DIT CE QU'ON SE DEMANDE ICI : d'où viennent les vues. Un cadre vide ne
   l'apprend pas, et l'écran n'a rien d'autre à montrer à ce moment-là. */
.pv-vide-slog { margin: 0; font-size: var(--t-lead); color: var(--text); text-align: center; }
.pv-vide-s {
  margin: var(--e-6) 0 0; max-width: calc(var(--e-48) * 10);
  font-size: var(--t-base); color: var(--text-3); text-align: center;
}
/* ⚠️ `.upload-pick` EST EN `width: 100%` PARTOUT AILLEURS — voulu dans une colonne étroite,
   absurde ici : le bouton barrait toute la carte. On lui rend sa largeur naturelle, avec un
   plancher pour qu'il reste le geste le plus visible de l'écran. */
.pv-vide .upload-pick {
  width: auto; min-width: calc(var(--e-48) * 5); margin-top: var(--e-20);
}
/* ⚠️⚠️ DEUX CLASSES DANS LE SÉLECTEUR, ET C'EST OBLIGATOIRE. `.upload-actions .dropzone`
   pose `min-height: 38px` et `padding: 0 14px` avec une force de (0,2,0) : écrite sur la
   seule classe `.pv-vide-zone` (0,1,0), ma règle perdait et la zone retombait à 84 px.
   Mesuré à l'écran, pas relu. */
.pv-vide .pv-vide-zone {
  width: 100%; margin-top: var(--e-16);
  display: flex; align-items: center; justify-content: center; gap: var(--e-6);
  min-height: var(--e-32); padding: var(--e-8) var(--e-16);
  font-size: var(--t-meta);
}
.pv-vide-ic { color: var(--text-3); flex: none; }
/* ⚠️⚠️ LE SURVOL DE LA BRIQUE EST TAILLÉ POUR UNE GRANDE ZONE, PAS POUR UNE BANDE
   SECONDAIRE. `.dropzone:hover` remplit de `--violet-tint` (l'accent à 16 %) : la bande
   devenait un bandeau plein, PLUS voyant que le bouton juste au-dessus — l'inverse exact
   de la hiérarchie qu'on venait de poser. Amadou (04/09) : « la zone glisse tes photos ici
   s'éclaire trop, ça doit être plus discret ».
   Ici le survol ne fait qu'affermir le trait et poser un voile à peine perceptible.
   ⚠️ LE `dragover` GARDE TOUTE SA FORCE, et c'est voulu : c'est le seul instant où la zone
   doit dire « lâche ici », et à ce moment-là on ne regarde plus le bouton. */
/* ⚠️⚠️⚠️ `:not(.dragover)` DEVANT `:hover`, ET CE N'EST PAS DÉCORATIF. Sans lui, le survol
   discret (0,3,0) écrasait `.dropzone.dragover` (0,2,0) — et comme on survole forcément la
   zone au moment où on lâche, le signal « lâche ici » disparaissait pile quand il sert.
   Mesuré : le fond retombait à 3 % de voile au lieu de l'accent à 26 %.
   C'est la réparation que le projet a retenue (`outils/verifier-survol-etat.py`) : elle
   tient même si quelqu'un déplace les règles plus tard, là où l'ordre seul se casserait. */
.pv-vide .pv-vide-zone:not(.dragover):hover {
  border-color: var(--violet-tint-strong);
  background: rgba(var(--th-voile), 0.03);
}
/* Et le dépôt reprend toute sa force, écrit ICI pour ne dépendre d'aucun ordre. */
.pv-vide .pv-vide-zone.dragover {
  border-color: var(--violet-light); border-style: solid;
  background: var(--violet-tint-strong);
}

/* ── LE BANDEAU DU PRODUIT, AU-DESSUS DES DEUX COLONNES ──────────────────────
   ⚠️⚠️ IL ÉTAIT DANS LA COLONNE DE GAUCHE, et c'est LUI qui décalait tout : la gauche
   commençait par une ligne de 52 px que la droite n'avait pas, donc les deux contenus ne
   tombaient jamais sur la même ligne. Amadou (04/09) : « tout doit être aligné, donc la
   partie de gauche et droite ». En bandeau, les deux colonnes partent ensemble — et la
   niche n'est plus nommée deux fois. */
.pv-produit {
  display: flex; align-items: center; gap: var(--e-12);
  padding: var(--e-10) var(--e-12); margin-bottom: var(--e-16);
  background: var(--surface-2); border-radius: var(--r-lg);
}
.pv-produit-vign {
  width: 44px; height: 52px; flex: none; border-radius: var(--photo-rayon);
  background: var(--surface) center/cover no-repeat;
}
.pv-produit-txt { flex: 1 1 auto; min-width: 0; }
/* ⚠️ `min-width:0` PLUS L'ELLIPSE : un nom SHEIN fait cent caractères et pousserait le
   bouton « Changer » hors de la carte. */
.pv-produit-nom, .pv-produit-niche {
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pv-produit-nom   { font-size: var(--t-body); color: var(--text); }
.pv-produit-niche { font-size: var(--t-base); color: var(--text-3); flex: 0 1 auto; }
.pv-produit-chg   { flex: none; }
/* La niche et le lien qui mène à ses réglages, sur la même ligne sous le nom. */
.pv-produit-bas { display: flex; align-items: baseline; gap: var(--e-6); min-width: 0; }
.pv-produit-bas .pv-vues-sous { flex: none; }
/* ⚠️ LE SÉPARATEUR EST EN CSS, PAS DANS LE TEXTE. Écrit en dur, il resterait quand la
   phrase de repli (« vues d'origine — range-le dans une niche ») remplace le lien. */
.pv-produit-bas .pv-vues-sous::before { content: '·'; margin-right: var(--e-6); }

/* Les photos de référence, discrètes : ce ne sont pas elles qu'on regarde ici. */
/* ⚠️ La grille des photos est vide au départ : sans ça elle réserve une hauteur pour
   rien, et c'est exactement le vide qu'on vient de retirer. */
#pv-preview-dress:empty { display: none; }

/* ── Les vues ─────────────────────────────────────────────────────────────── */
/* Le titre et le compte sur une ligne — `field-label` porte déjà le style du titre. */
/* ⚠️ PLUS DE `margin-top` NÉGATIF : la sous-ligne ne vit plus sous l'en-tête des vues,
   elle a déménagé dans le bandeau du produit (voir plus haut). */
.pv-vues-sous { font-size: var(--t-base); color: var(--text-3); }
/* Le lien ressemble à un lien : souligné, pas un bouton de plus. */
.pv-vues-lien {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--text-2); border-bottom: 1px solid var(--border-strong);
}
.pv-vues-lien:hover { color: var(--text); border-bottom-color: var(--violet-light); }
.pv-vues-compte { flex: none; font-size: var(--t-base); color: var(--text-3); }

/* ⚠️ EN LISTE, PAS EN GRILLE. Trois cartes côte à côte dans une demi-largeur écrasent
   les consignes sur trois lignes ; empilées, chacune tient sur deux et la colonne se
   remplit au lieu de laisser du vide sous elles. */
/* ⚠️⚠️ AUCUN `margin-top` ICI, ET C'EST CE QUI ALIGNE LES DEUX COLONNES. `card-header`
   pose déjà `margin-bottom: var(--e-18)` des deux côtés : tout écart ajouté d'un seul
   côté décale ce contenu-là de sa valeur, et le décalage ne se voit qu'à l'écran. */
.pv-view-grid { display: flex; flex-direction: column; gap: var(--e-8); }
/* ⚠️ UNE CARTE, PAS UNE PASTILLE. La vue porte son nom ET sa consigne : deux lignes de
   texte ne tiennent pas dans une pastille, et c'est la consigne qui aide à choisir. */
.pv-view-grid .pv-vue {
  /* ⚠️⚠️⚠️ QUATRE PROPRIÉTÉS REPRISES À LA FAMILLE DES PASTILLES, ET ELLES SONT VITALES.
     Ces cartes portent encore `.prod-view-chip` — sept lectures du code s'appuient dessus,
     dont le clic, le compte et le coût. Or cette famille (une liste de 17 sélecteurs, plus
     haut dans la feuille) impose `height: 30px`, `white-space: nowrap`, `line-height: 1` et
     `display: inline-flex`. Sans les reprendre ICI, la carte s'écrase à 30 px de haut, sur
     une seule ligne, et la consigne disparaît — c'est exactement ce qui vient de se
     reproduire en retirant l'ancien bloc. On ne peut pas quitter la famille (le ruban
     compact de l'en-tête mannequin s'en sert), donc on la surcharge, et on l'écrit. */
  height: auto; white-space: normal; line-height: var(--lh-normal);
  display: flex; align-items: flex-start; gap: var(--e-10);
  padding: var(--e-12); text-align: left; cursor: pointer;
  background: transparent; border: 1px solid var(--border-mid);
  border-radius: var(--r-lg); color: inherit; font-family: inherit;
  transition: border-color var(--t-moyen), background var(--t-moyen);
}
/* ⚠️⚠️⚠️ L'ORDRE COMPTE, ET C'EST UN DÉFAUT DÉJÀ VÉCU. `:hover` et `.active` ont la même
   force : écrit après, le survol EFFAÇAIT la bordure de la vue sélectionnée — exactement
   ce qu'Amadou avait signalé sur les cartes de niche. `.active` passe donc en dernier, et
   son survol a sa propre règle. Trouvé par `outils/verifier-survol-etat.py`, pas à l'œil. */
/* ⚠️ `:not(.active)` DEVANT `:hover`, ET PAS UN SIMPLE ORDRE. C'est la réparation que le
   projet a retenue (`outils/verifier-survol-etat.py`) : elle tient même si quelqu'un
   déplace les règles plus tard, là où l'ordre seul se casserait au premier remaniement. */
.pv-view-grid .pv-vue:not(.active):hover { border-color: var(--border-strong); }
.pv-view-grid .pv-vue.active {
  border-color: var(--violet); background: var(--violet-tint);
}
.pv-view-grid .pv-vue.active:hover { border-color: var(--violet-light); }
.pv-vue-case {
  flex: none; width: 18px; height: 18px; margin-top: var(--e-1);
  border: 1px solid var(--border-strong); border-radius: var(--r-xs);
  display: flex; align-items: center; justify-content: center; color: transparent;
}
.pv-vue.active .pv-vue-case { border-color: var(--violet); color: var(--violet-light); }
/* ⚠️ LA COCHE OCCUPE SA PLACE EN PERMANENCE, SEULE SA COULEUR CHANGE. Dans l'ancien
   écran elle était `display: none` puis affichée à la sélection : le texte sautait d'un
   cran à chaque clic. Ici la case hérite `color: transparent`, la coche est invisible
   sans bouger, et `.active` lui rend sa couleur. Rien ne se déplace. */
.pv-vue-coche { display: flex; }
.pv-vue-txt { min-width: 0; }
.pv-vue-n { display: block; font-size: var(--t-base); color: var(--text); }
/* ⚠️⚠️ LA COUPE EST DANS LA MÊME RÈGLE QUE `display`, ET C'EST OBLIGATOIRE. Écrite dans
   une règle séparée plus haut, elle était annulée par le `display: block` d'ici — deux
   règles de même force, la dernière gagne. C'est la collision de cascade classique, et
   elle ne se voit pas à la lecture : il faut regarder l'écran.
   ⚠️ DEUX LIGNES AU PLUS : au-delà, les cartes grandissent sans fin et la rangée devient
   un pavé. Le nom et la première idée suffisent à choisir. */
.pv-vue-s {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-serre);
}

/* ⚠️ LE SCAN A DESCENDU DANS LE PIED (04/09) : c'est une option de GÉNÉRATION, comme le
   prix, pas une vue. Sous les vues il rallongeait la colonne de droite d'une quarantaine
   de pixels que la gauche n'avait pas. */
.pv-scan {
  display: flex; align-items: flex-start; gap: var(--e-8); cursor: pointer;
  flex: 0 1 auto; min-width: 0;
  font-size: var(--t-base); color: var(--text-2);
}
.pv-scan-txt  { display: flex; flex-direction: column; min-width: 0; }
.pv-scan-aide { font-size: var(--t-meta); color: var(--text-3); line-height: var(--lh-serre); }

/* ── Le pied : le prix à gauche, le geste à droite ─────────────────────────
   ⚠️ On EMPRUNTE `generate-block` à « Mis en scène » ; on n'ajoute que le prix à sa
   gauche, sans toucher au bouton qui garde exactement le même aspect qu'ailleurs. */
/* ⚠️⚠️ `flex-direction: row` EST OBLIGATOIRE ICI. `generate-block`, la brique empruntée,
   est en COLONNE : sans le dire, le prix se posait AU-DESSUS du bouton et centré, à
   côté de rien. Même piège que la famille des pastilles — on emprunte, donc on reprend
   explicitement ce que la brique impose et qu'on ne veut pas. */
.pv-generate-block {
  display: flex; flex-direction: row; align-items: center; gap: var(--e-16);
  margin-top: var(--e-20); padding-top: var(--e-18);
  border-top: 1px solid var(--border);
}
/* ⚠️ C'EST LE PRIX QUI POUSSE, PAS LE BOUTON. Avec `margin-left: auto` sur le bouton, le
   prix restait collé au scan et le chiffre se lisait à côté d'une case à cocher. */
.pv-generate-block .pv-cout { margin-left: auto; }
.pv-generate-block .pv-generate-cta { flex: 0 0 auto; width: auto; }
.pv-cout { flex: none; display: flex; flex-direction: column; }
.pv-cout-cle { font-size: var(--t-base); color: var(--text-3); }
.pv-cout-val { font-size: var(--t-xl); color: var(--text); font-variant-numeric: tabular-nums; }

/* ── Partie Génération : le rayon posé, puis les neuf champs du profil ──────────
   ⚠️ AUCUNE VALEUR BRUTE : tout passe par les jetons, comme le reste du fichier. */
/* ── Génération : le rayon en bandeau, puis les consignes repliées ─────────────
   ⚠️⚠️ NEUF ZONES DE TEXTE OUVERTES, C'ÉTAIT UN MUR (Amadou, 03/09 : « illisible, moche
   visuellement »). Une ligne par consigne, son début en aperçu sur UNE seule ligne, et
   une seule dépliée à la fois. ⚠️ Aucune valeur brute : tout passe par les jetons. */
.nial-rayon {
  display: flex; align-items: center; gap: var(--e-12);
  margin-top: var(--e-4); padding: var(--e-10) var(--e-14);
  border-radius: var(--r-moyen); background: var(--surface-2);
}
.nial-rayon-txt { flex: 1 1 auto; min-width: 0; }
.nial-rayon-l { font-size: var(--t-mini); color: var(--text-3); }
.nial-rayon-val {
  font-size: var(--t-corps); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nial-rayon-vide { color: var(--text-3); font-style: italic; }

/* Le bouton « Affiner », aligné à droite sous le champ. */
.nial-affiner { display: flex; justify-content: flex-end; margin-top: var(--e-8); }

/* ⚠️ LES SUGGESTIONS ONT ÉTÉ RETIRÉES (Amadou, 03/09) : « le fait d'avoir des suggestions
   fixes ne sert à rien ». Une liste écrite d'avance ne peut pas savoir ce que SES niches
   ont de particulier — sa capture le montrait : il tape « Le sac » dans une niche Robes et
   les quatre phrases sur les robes restent là. Il reste le champ, son exemple en gris et
   la phrase qui dit ce qui est déjà géré. Une aide qui n'aide pas est du bruit. */

/* ⚠️ Les styles du repli à neuf lignes ont été RETIRÉS avec lui (03/09) : la partie
   Génération ne porte plus que le rayon et une consigne. Du CSS qui ne style plus rien
   se fait recopier par le suivant qui cherche un motif — mieux vaut qu'il n'existe pas. */
/* L'ASSISTANCE : un bouton discret, et les propositions posées dessous.
   ⚠️ Elles se lisent comme du texte à choisir, pas comme des boutons d'action : ce sont
   des phrases, alignées à gauche, sur plusieurs lignes s'il le faut. */
.nial-vue-pied { display: flex; justify-content: flex-end; margin-top: var(--e-4); }
.nial-proposer {
  background: transparent; border: 1px solid var(--border); border-radius: var(--r-pilule);
  color: var(--text-3); font-family: inherit; font-size: var(--t-micro);
  padding: var(--e-2) var(--e-10); cursor: pointer; transition: var(--transi);
}
.nial-proposer:hover { border-color: var(--violet); color: var(--violet-light); }
.nial-proposer:disabled { opacity: 0.5; cursor: default; }
.nial-props { display: flex; flex-direction: column; gap: var(--e-4); margin-top: var(--e-4); }
.nial-prop {
  text-align: left; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-sm); color: var(--text-2); font-family: inherit;
  font-size: var(--t-mini); line-height: var(--lh-serre);
  padding: var(--e-6) var(--e-8); cursor: pointer; transition: var(--transi);
}
.nial-prop:hover { border-color: var(--violet); background: var(--bg-hover); color: var(--text); }
.nial-vue-haut { display: flex; align-items: center; gap: var(--e-8); }
.nial-vue {
  display: flex; flex-direction: column; align-items: stretch;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: var(--e-6) var(--e-8);
}
.nial-rang {
  flex: 0 0 var(--e-22); width: var(--e-22); height: var(--e-22); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--violet-tint); color: var(--violet-light);
  font-size: var(--t-mini); line-height: var(--lh-un);
}
.nial-nom {
  flex: 1 1 auto; min-width: 0; background: transparent; border: 0;
  border-bottom: 1px solid transparent; color: var(--text);
  font-family: inherit; font-size: var(--t-base); padding: var(--e-2);
}
.nial-nom:focus { outline: none; border-bottom-color: var(--violet); }
/* ⚠️ L'ÉTIQUETTE DU MODE SE LIT, ELLE NE SE CLIQUE PAS. Amadou (02/09) : « ça doit être
   déduit par le logiciel ». Elle est donc en retrait — même graisse, couleur de note — et
   elle porte sa raison en infobulle. Ce qui vient du REPLI plutôt que du nom est en
   pointillé : une déduction devinée doit se distinguer d'une déduction lue. */
.nial-mode {
  flex: 0 0 auto; font-size: var(--t-mini); color: var(--text-3);
  padding: var(--e-2) var(--e-8); border-radius: var(--r-pilule);
  border: 1px solid transparent; line-height: var(--lh-un); white-space: nowrap;
  cursor: help;
}
.nial-mode--scene { color: var(--violet-light); background: var(--violet-tint); }
.nial-mode--devine { border-style: dashed; border-color: var(--border-mid); }
.nial-ico {
  background: transparent; border: 0; color: var(--text-3); cursor: pointer;
  padding: var(--e-4); border-radius: var(--r-micro); line-height: var(--lh-un);
  display: flex; transition: var(--transi-vif);
}
.nial-ico:hover { color: var(--text); background: var(--bg-hover); }
/* ⚠️ LA CROIX EST ROUGE AU SURVOL, comme partout ailleurs dans le site : c'est le seul
   geste de cette fenêtre qui retire quelque chose. */
.nial-ico--x:hover { color: var(--red); }
.nial-ico:disabled { opacity: 0.3; cursor: default; }
.nial-ico:disabled:hover { color: var(--text-3); background: transparent; }
.nial-plus {
  width: 100%; margin-top: var(--e-8); background: transparent;
  border: 1px dashed var(--border-mid); border-radius: var(--r-md);
  color: var(--text-2); font-family: inherit; font-size: var(--t-meta);
  padding: var(--e-8); cursor: pointer; transition: var(--transi);
}
.nial-plus:hover { border-color: var(--violet); color: var(--violet-light); }

.nial-pied { padding: var(--e-14) var(--e-22); border-top: 1px solid var(--border); flex-shrink: 0; align-items: center; }
.nial-etat { margin-right: auto; font-size: var(--t-meta); color: var(--text-3); }

/* ══ LA POIGNÉE « … » D'UNE CARTE DE NICHE ════════════════════════════════════
   Amadou (02/09) : « avec mon Mac […] je n'ai pas accès au clic droit ». Elle n'apparaît
   qu'au survol ou au clavier : une commande visible en permanence sur chaque carte
   redeviendrait le bouton permanent qu'on a retiré le 23/08. */
.lib-niche-poi {
  position: absolute; top: var(--e-8); right: var(--e-8); z-index: 2;
  width: var(--e-24); height: var(--e-24); border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-2); cursor: pointer;
  opacity: 0; transition: opacity var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.lib-niche:not(.lib-niche--on):not(.selected):hover .lib-niche-poi,
.lib-niche-poi:focus-visible { opacity: 1; }
.lib-niche-poi:hover { color: var(--text); border-color: var(--border-mid); }
/* En mode sélection on coche des cartes : une poignée qui ouvre un menu par-dessus
   n'aurait aucun sens, et elle recouvrirait la pastille. */
.lib-niche.select-mode .lib-niche-poi { display: none; }
/* Le doigt n'a pas de survol : sur écran tactile, la poignée reste posée. */
@media (hover: none) {
  .lib-niche-poi { opacity: 1; }
}

/* ══ STUDIO — LES PROJETS ════════════════════════════════════════════════════
   Amadou (26/08) : « je dois pouvoir faire des projets, comme sur ChatGPT ».
   Un projet se replie : dix projets ouverts rendraient la colonne illisible, et
   c'est le repli qui fait la différence entre un rangement et une liste de plus. */
.studio-projet-neuf {
  display: flex; align-items: center; gap: var(--e-8);
  width: 100%; height: 32px;
  margin-top: var(--e-6);
  padding: 0 var(--e-10);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: none;
  color: var(--th-texte-3);
  font-family: inherit; font-size: var(--t-meta);
  cursor: pointer;
  transition: color var(--t-bref) var(--c-pose), border-color var(--t-bref) var(--c-pose),
              transform var(--t-bref) var(--c-rebond);
}
.studio-projet-neuf:hover { color: var(--th-texte); border-color: var(--border-mid); }

.studio-projet-tete {
  display: flex; align-items: center; gap: var(--e-6);
  padding: var(--e-6) var(--e-8);
  border-radius: var(--r-md);
  cursor: pointer;
  color: var(--th-texte-2);
  font-size: var(--t-meta);
  transition: background var(--t-bref) var(--c-pose), color var(--t-bref) var(--c-pose);
}
.studio-projet-tete:hover { background: rgba(var(--th-voile), .05); color: var(--th-texte); }
.studio-projet-nom { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Le compte des conversations : une information, pas une alerte — donc pas de pastille. */
.studio-projet-n { color: var(--th-texte-3); font-size: var(--t-nano); flex: 0 0 auto; }
.studio-projet-chev {
  width: 0; height: 0; flex: 0 0 auto;
  border-left: 4px solid currentColor;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transition: transform var(--t-bref) var(--c-pose);
}
.studio-projet.ouvert .studio-projet-chev { transform: rotate(90deg); }
/* ⚠️ `display: none` et non une hauteur animée : une liste de longueur inconnue ne
   peut pas s'animer proprement sans mesurer, et une mesure à chaque rendu coûterait
   plus cher que le pli lui-même. */
.studio-projet-corps { display: none; padding-left: var(--e-10); }
.studio-projet.ouvert .studio-projet-corps { display: block; }

/* ══ STUDIO — TOUS LES ASCENSEURS, UNE SEULE RÈGLE ═══════════════════════════
   ⚠️⚠️ IL Y EN A QUATRE DANS CET ÉCRAN, et je les ai corrigés un par un, à trois
   reprises, à chaque fois qu'Amadou en voyait un : le fil, le champ de saisie,
   puis la liste des conversations — celui-là longeait toute la colonne de gauche
   avec le pouce clair du réglage global, soit un trait blanc franc du haut en bas.
   ⭐ Un défaut de style se répète sur TOUS les porteurs de la même propriété.
   La bonne réponse n'était pas de corriger celui qu'on a sous les yeux mais de
   chercher `overflow-y: auto` dans tout l'écran — d'où cette règle unique, qui
   couvre aussi le corps du raisonnement, que personne n'avait encore vu.
   ⚠️ Sur un thème sombre, ce qui compte n'est pas l'opacité mais l'ÉCART avec le
   fond : un voile blanc à 9 % sur du presque-noir donne déjà un trait franc. D'où
   5 % au repos, et rien qui l'allume tant qu'on ne vise pas le pouce lui-même.
   ⚠️ `scrollbar-color` (Firefox) ET `::-webkit-scrollbar` (Chrome/Brave) : les deux
   moteurs ne lisent pas le même, et n'en poser qu'un laisse l'autre au trait clair
   du système. */
.studio-history-list,
.studio-chat-messages,
.studio-prompt-input,
.studio-pense-corps {
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--th-voile), .06) transparent;
}
.studio-history-list::-webkit-scrollbar,
.studio-chat-messages::-webkit-scrollbar,
.studio-prompt-input::-webkit-scrollbar,
.studio-pense-corps::-webkit-scrollbar { width: var(--e-4); }

.studio-history-list::-webkit-scrollbar-track,
.studio-chat-messages::-webkit-scrollbar-track,
.studio-prompt-input::-webkit-scrollbar-track,
.studio-pense-corps::-webkit-scrollbar-track { background: transparent; }

.studio-history-list::-webkit-scrollbar-thumb,
.studio-chat-messages::-webkit-scrollbar-thumb,
.studio-prompt-input::-webkit-scrollbar-thumb,
.studio-pense-corps::-webkit-scrollbar-thumb {
  background: rgba(var(--th-voile), .05);
  border-radius: var(--r-pilule);
  transition: background var(--t-moyen) var(--c-pose);
}
.studio-history-list::-webkit-scrollbar-thumb:hover,
.studio-chat-messages::-webkit-scrollbar-thumb:hover,
.studio-prompt-input::-webkit-scrollbar-thumb:hover,
.studio-pense-corps::-webkit-scrollbar-thumb:hover { background: rgba(var(--th-voile), .13); }

/* ⚠️ LA CRÊTE DU TEXTE QUI S'ÉCRIT. Amadou (26/08) : « il faut que le texte soit
   doux lorsqu'il arrive, avec un petit effet de couleur au début, en fonction du
   thème ». Les derniers caractères portent l'accent puis reviennent au texte
   normal — c'est ce qui fait qu'on suit la ligne en train de s'écrire au lieu de
   relire le paragraphe entier à chaque image.
   ⚠️ La transition est sur la COULEUR seule : animer l'opacité ferait clignoter le
   texte déjà lu à chaque nouvelle image, puisque le markdown est refait en entier.
   ⚠️ L'accent CLAIR, pas l'accent plein : sur les thèmes sombres, l'accent plein
   sur un fond noir est moins lisible que le texte normal — la douceur se retourne
   contre la lecture. */
.studio-msg-text.md .md-crete {
  color: var(--th-accent-clair);
  animation: studioCrete .9s var(--c-pose) forwards;
}
@keyframes studioCrete {
  from { color: var(--th-accent-clair); }
  to   { color: inherit; }
}
@media (prefers-reduced-motion: reduce) {
  .studio-msg-text.md .md-crete { animation: none; color: inherit; }
}

/* ══ L'AVIS DE VERSION ════════════════════════════════════════════════════════
   ⚠️ EN BAS À GAUCHE, pas en haut au milieu : une page laissée ouverte n'est pas en
   panne, et une bannière qui barre l'écran pour dire « recharge quand tu veux »
   interrompt plus qu'elle n'aide. Discret, mais permanent tant qu'on ne l'a pas
   traité — c'est justement l'information qu'on ne doit pas rater. */
/* ══ LA BULLE « NOUVELLE VERSION », ACCROCHÉE AU LOGO ════════════════════════
   Amadou (27/08) : « que ça soit une bulle qui sorte de l'onglet du logo à gauche, une
   bulle stylisée, et que l'on puisse recharger d'ici. Parce que là, ce n'est pas
   esthétique. »
   L'ancien bandeau flottait en bas à gauche, sans lien avec quoi que ce soit. Le logo
   EST déjà le bouton « recharger » du site : la bulle le désigne, et le geste devient
   évident.
   ⚠️ `position: absolute` sur un parent en `position: relative` — c'est `.sidebar-logo`
   qui devient le repère. Sans ça la bulle se placerait par rapport à la page et
   repartirait dans un coin, ce qu'on vient justement de corriger. */
/* ══ « NOUVELLE VERSION » : L'ÉTOILE BRILLE ══════════════════════════════════
   Amadou (27/08), après trois essais de bulle : « on va arrêter tout ça. Lorsqu'il y a
   une mise à jour, l'étoile doit briller. »
   Le logo EST le bouton « recharger » du site. Un halo dessus dit à la fois « il y a du
   neuf » et « c'est ici qu'on appuie ». Le bandeau du coin, la bulle à pointe et le
   nuage de BD expliquaient tous un geste que l'objet désignait déjà.
   ⚠️ Il respire lentement : un halo FIXE se confond avec un état de survol, et le survol
   du logo porte déjà son propre effet (`.sidebar-logo:hover .brand-mark`).
   ⚠️ Rien à positionner, rien à mesurer, rien qui pousse la navigation : ça marche barre
   dépliée, barre repliée, et à tous les crans de police. */
/* ⚠️⚠️⚠️ LE HALO N'ÉTAIT PAS FAIBLE : IL ÉTAIT COUPÉ. Amadou (27/08) : « la lueur de
   l'étoile n'est pas assez forte et il n'y a pas assez de mouvement ». J'allais monter
   l'opacité — mesuré au navigateur, l'étoile n'avait que 4 px de place au-dessus et en
   dessous avant l'`overflow: hidden` de `.sidebar-logo` : un flou de 28 px était rogné à
   4. Aucune opacité n'aurait rattrapé ça. C'est le même piège que la bulle de version, qui
   se dessinait entière (280 × 111, opacité 1) et disparaissait dans ce même `overflow`.
   On ouvre donc le cadre — mais SEULEMENT quand l'étoile brille, pour ne toucher à rien le
   reste du temps. L'état replié n'en souffre pas : `.sidebar.collapsed .brand-word` porte
   déjà son propre `overflow: hidden` et sa largeur nulle.
   ⚠️ Il reste 14 px au-dessus avant le bord de `.sidebar`, qui doit garder son découpage
   puisqu'il défile : la lueur porte donc surtout sur les côtés et vers le bas. */
.sidebar-logo--neuf { overflow: visible; }

/* ⚠️⚠️⚠️ SACCADÉE PARCE QU'ELLE FAISAIT REPEINDRE À CHAQUE IMAGE. Amadou (27/08) :
   « l'animation de l'étoile est saccadée ». Relevé sur l'animation elle-même, les
   propriétés qu'elle faisait varier étaient `filter`, `transform` et `box-shadow`. Deux
   sont ruineuses : un `drop-shadow` est un FLOU GAUSSIEN, et il y en avait DEUX,
   recalculés soixante fois par seconde ; l'étalement d'un `box-shadow` repeint lui aussi.
   Le navigateur ne sait animer sans repeindre que DEUX propriétés : `transform` et
   `opacity`. Tout le reste passe par le fil principal, celui qui dessine aussi la page.

   On garde donc exactement le même geste — deux battements, deux ondes, puis le silence —
   mais chaque morceau ne bouge plus que par l'échelle et l'opacité :
     · l'étoile        → `transform` seule
     · le halo         → un disque en dégradé FIXE (`::before`), échelle + opacité
     · l'onde          → un anneau FIXE (`::after`), échelle + opacité
   Le halo n'est plus un filtre : il est dessiné une fois, et on le fait respirer. */
.sidebar-logo--neuf .brand-mark {
  position: relative;
  z-index: 0;                    /* pour que les deux calques restent DERRIÈRE l'étoile et DEVANT le fond du bouton */
  filter: none;                  /* ⚠️ le halo passe par ::before — plus aucun flou recalculé */
  /* ⚠️⚠️ ET ON COUPE LES TRANSITIONS. `.brand-mark` transitionne `filter` : tant que la
     transition existe, le moindre changement d'état relance un double flou — et le passage
     à l'état « nouvelle version » en déclenchait un lui-même. Pendant que l'étoile brille,
     ce sont les images-clés qui commandent, rien d'autre. */
  transition: none;
  animation: velboMajBat 2.4s var(--c-rebond) infinite;
  will-change: transform;
}
.sidebar-logo--neuf .brand-mark::before,
.sidebar-logo--neuf .brand-mark::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  z-index: -1;
}
/* Le halo. Le dégradé s'éteint à 70 % du rayon : ce qui déborde est déjà transparent, donc
   le bord de la barre le coupe sans que ça se voie — un flou se coupe invisiblement, un
   trait net non. */
.sidebar-logo--neuf .brand-mark::before {
  inset: -10px;
  background: radial-gradient(circle,
              rgba(var(--th-accent-rgb), .6) 0%,
              rgba(var(--th-accent-rgb), 0) 70%);
  animation: velboMajHalo 2.4s var(--c-rebond) infinite;
  will-change: opacity, transform;
}
/* L'onde. ⚠️ POUSSÉE DE 3 px VERS LE BAS ET BORNÉE À 1,6×, pour la même raison qu'avant :
   l'étoile n'a que 9 px de place au-dessus d'elle avant le bord de `.sidebar`, qui doit
   garder son découpage puisque la barre défile. À 1,6 elle monte de 17 × 0,6 − 3 = 7,2 px,
   plus le demi-trait : elle frôle le bord sans jamais le toucher. En bas elle a 287 px. */
.sidebar-logo--neuf .brand-mark::after {
  inset: 0;
  border: 2px solid rgba(var(--th-accent-rgb), .75);
  animation: velboMajOnde 2.4s var(--c-pose) infinite;
  will-change: transform, opacity;
}

/* Deux battements rapprochés, puis un repos : c'est le rythme qui se repère, pas
   l'intensité. Une respiration régulière se lit comme un état de survol et se fond dans le
   décor — c'était le défaut de la toute première version. */
@keyframes velboMajBat {
  0%, 50%, 100% { transform: scale(1); }
  12%           { transform: scale(1.22); }
  24%           { transform: scale(1); }
  36%           { transform: scale(1.12); }
}
@keyframes velboMajHalo {
  0%, 50%, 100% { opacity: .42; transform: scale(1); }
  12%           { opacity: 1;   transform: scale(1.3); }
  24%           { opacity: .55; transform: scale(1.04); }
  36%           { opacity: .85; transform: scale(1.18); }
}
/* ⚠️ Les remises à zéro à 22,01 % et 46,01 % sont instantanées exprès : sans elles, on
   verrait l'anneau RÉTRÉCIR pour revenir à son point de départ. */
@keyframes velboMajOnde {
  0%, 7%       { transform: translateY(3px) scale(1);   opacity: .75; }
  22%          { transform: translateY(3px) scale(1.6); opacity: 0; }
  22.01%       { transform: translateY(3px) scale(1);   opacity: 0; }
  31%          { transform: translateY(3px) scale(1);   opacity: .6; }
  46%          { transform: translateY(3px) scale(1.5); opacity: 0; }
  46.01%, 100% { transform: translateY(3px) scale(1);   opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar-logo--neuf .brand-mark { animation: none; }
  .sidebar-logo--neuf .brand-mark::before { animation: none; opacity: .9; transform: scale(1.15); }
  .sidebar-logo--neuf .brand-mark::after  { animation: none; opacity: 0; }
}

/* ══ STUDIO — LE PANNEAU DE CONSIGNES D'UN PROJET ════════════════════════════
   ⚠️⚠️ C'ÉTAIT UNE BOÎTE À UNE LIGNE. Amadou (26/08) : « ça doit être beaucoup plus
   gros, là c'est vraiment tout petit ». J'avais réutilisé la boîte de saisie de nom
   du site — celle qui attend trois mots. On demande ici un paragraphe de contexte :
   dans un champ d'une ligne on ne voit jamais ce qu'on écrit, donc on n'écrit rien,
   et le projet reste un dossier.
   ⚠️ La largeur est bornée en `ch` et non en pixels : ce qui compte pour écrire un
   paragraphe est le nombre de caractères par ligne, pas la taille de l'écran. */
.studio-cons { width: min(72ch, 92vw); max-width: none; }
.studio-cons .studio-cons-zone {
  width: 100%;
  min-height: var(--e-48);
  height: 30vh;
  max-height: 46vh;
  resize: vertical;
  padding: var(--e-12) var(--e-14);
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background: rgba(var(--th-voile), .05);
  color: var(--th-texte);
  font-family: inherit;
  font-size: var(--t-small);
  line-height: var(--lh-aere);
}
.studio-cons .studio-cons-zone:focus {
  outline: none;
  border-color: rgba(var(--th-accent-rgb), .5);
  background: rgba(var(--th-voile), .07);
}
.studio-cons .studio-cons-zone::placeholder { color: var(--th-texte-3); }
/* La proposition à gauche, les décisions à droite : on ne met pas « propose-moi un
   texte » à côté d'« Enregistrer », sinon on le clique en croyant valider. */
.studio-cons-pied { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); }
.studio-cons-actions { display: flex; align-items: center; gap: var(--e-8); }
.studio-cons .studio-cons-suggerer:disabled { opacity: .55; cursor: default; }

/* ══════════════════════════════════════════════════════════════════════════════
   LE WIDGET DE CRÉATION — posé le 02/09/2026
   Amadou : « refais l'interface de la création de compte en faisant un widget. Je
   veux que tout soit épuré, tout soit propre, les transitions fluides et pas
   saccadées. » Trois moments : avant, pendant, après.

   ⚠️⚠️ ON N'ANIME QUE `transform` ET `opacity`. Tout le reste (filter, box-shadow,
   width, background) repeint à chaque image — c'est ce qui rendait les animations
   saccadées ([[velbo-fluidite-transitions]]).
   ⚠️ Entrée sur `--c-pose`, sortie sur `--c-sortie`. Les inverser fait « tomber »
   ce qui arrive et « flotter » ce qui part.
   ⚠️ AUCUNE VALEUR BRUTE : tout vient des échelles de la bibliothèque.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⚠️ `.crw` n'a plus aucun porteur : la carte de création a rendu sa coquille le
   08/09. On retire la règle plutôt que de la laisser attendre — une classe morte au
   nom évident finit par être recopiée sur autre chose. Ses ENFANTS (`.crw-pile`,
   `.crw-vue`, `.crw-corps`, `.crw-e`…) restent : la frise de la création en cours
   les porte toujours. */
.crw-tete{display:flex;align-items:center;gap:var(--e-8);padding:var(--e-12) var(--e-12) var(--e-8)}
.crw-tete h3{margin:0;font-size:var(--t-titre);font-weight:600;letter-spacing:-.01em;color:var(--cok-text)}
.crw-tete p{margin:2px 0 0;font-size:var(--t-mini);color:var(--cok-text-3)}
.crw-ico{display:grid;place-items:center;width:34px;height:34px;flex:0 0 34px;
   border-radius:var(--r-md);background:var(--cok-accent-bg);color:var(--cok-accent)}

/* ⚠️ LA COQUILLE SUIT LE MOMENT AFFICHÉ. Empilés en grille, les trois moments
   imposaient à la carte la hauteur du PLUS GRAND : 93 px de vide sous le bouton au
   moment 1 (mesuré dans le navigateur). Ils sont donc superposés en absolu, et la
   hauteur est posée par `crwHauteur()`. */
/* ⚠️⚠️⚠️ LA VUE PORTE SA PROPRE HAUTEUR, ET C'EST VITAL (corrigé le 02/09/2026).
   Première écriture : les vues étaient en `position:absolute` et une fonction JS posait
   la hauteur de la coquille. Mesuré au banc d'essai : la hauteur n'arrive qu'APRÈS un
   `requestAnimationFrame` — or dans l'écran réel le widget est inséré par `innerHTML`
   et PERSONNE n'appelait cette fonction. La coquille serait restée à 0 px, en
   `overflow:hidden` : le widget entier invisible, sans la moindre erreur.
   Et le positionnement absolu ne servait à rien : on n'émet qu'UNE vue à la fois.
   La coquille prend donc naturellement la hauteur de son contenu — rien à calculer,
   rien à clipper le jour où un incident s'ajoute en cours de route. */
.crw-pile{position:relative}
.crw-vue{padding:0 var(--e-12) var(--e-12);
   opacity:0;transform:translateY(6px);
   transition:opacity var(--d-base) var(--c-sortie),transform var(--d-base) var(--c-sortie)}
.crw-vue[data-actif]{opacity:1;transform:none;
   transition:opacity var(--d-mid) var(--c-pose),transform var(--d-mid) var(--c-pose)}

/* ── MOMENT 1 · PRÊT ? ────────────────────────────────────────────────────── */
/* 128 px : les cinq jauges tiennent sur UNE ligne. À 150 px elles passaient à 4 + 1,
   et la cinquième seule au bout d'une ligne se lit comme une erreur. */
.crw-jauges{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));
   gap:var(--e-4);margin-bottom:var(--e-10)}
.crw-j{display:flex;align-items:center;gap:var(--e-6);padding:var(--e-6) var(--e-8);
   background:var(--surface-2);border:1px solid var(--cok-border);border-radius:var(--r-md);
   transition:transform var(--d-fast) var(--c-pose)}
.crw-j:hover{transform:translateY(-1px)}
.crw-j .p{display:grid;place-items:center;width:26px;height:26px;flex:0 0 26px;border-radius:50%}
.crw-j .t{min-width:0}
.crw-j .t b{display:block;font-size:var(--t-base);font-weight:600;line-height:1.25;color:var(--cok-text);
   white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.crw-j .t span{display:block;font-size:var(--t-micro);color:var(--cok-text-3);line-height:1.3;
   white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.crw-j.ok  .p{background:var(--cok-green-bg);color:var(--cok-green)}
.crw-j.bas .p{background:var(--cok-warn-bg);color:var(--cok-amber)}
.crw-j.non .p{background:var(--cok-red-bg);color:var(--cok-red)}
.crw-j.non{border-color:color-mix(in srgb,var(--cok-red) 32%,transparent)}
.crw-j.vide .p{background:var(--surface);color:var(--cok-text-3)}

.crw-lancer{display:flex;align-items:center;gap:var(--e-8);flex-wrap:wrap}
/* ⚠️ LE CHOIX DE LA MACHINE, DANS LA MÊME RANGÉE QUE LE BOUTON. Il change ce que
   « Créer le compte » va faire : le poser ailleurs, c'est laisser lancer une création
   sur la mauvaise machine sans avoir vu le réglage. On EMPRUNTE la graduation de
   Commandes (`.cok-cmd-groups` / `.cok-cmd-grp`), déjà habillée par `.cp-poste-grad`
   et `.cp-poste-g` — aucune valeur brute ici, seulement la place dans la rangée. */
.crw-poste{flex:0 0 auto;margin:0}
.crw-nb{display:flex;align-items:center;background:var(--surface-2);
   border:1px solid var(--cok-border);border-radius:var(--r-pilule);overflow:hidden}
.crw-nb button{appearance:none;border:0;background:transparent;color:var(--cok-text-2);
   cursor:pointer;width:34px;height:34px;font-size:var(--t-moyen);line-height:1;
   transition:transform var(--d-fast) var(--c-pose)}
.crw-nb button:hover{transform:scale(1.14);color:var(--cok-text)}
.crw-nb button:active{transform:scale(.94)}
.crw-nb input{width:46px;border:0;background:transparent;color:var(--cok-text);text-align:center;
   font:600 var(--t-moyen)/1 inherit;-moz-appearance:textfield}
.crw-nb input::-webkit-outer-spin-button,
.crw-nb input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.crw-go{flex:1 1 190px;display:inline-flex;align-items:center;justify-content:center;
   gap:var(--e-6);min-height:38px;padding:0 var(--e-12);border:0;border-radius:var(--r-pilule);
   cursor:pointer;background:var(--cok-accent-solid);color:#fff;font:600 var(--t-body)/1 inherit;
   transition:transform var(--d-fast) var(--c-pose)}
.crw-go:hover:not(:disabled){transform:translateY(-1px)}
.crw-go:active:not(:disabled){transform:translateY(0) scale(.985)}
.crw-go:disabled{background:var(--surface-2);color:var(--cok-text-3);cursor:not-allowed}
.crw-frein{flex-basis:100%;margin:var(--e-4) 0 0;font-size:var(--t-mini);color:var(--cok-amber)}

/* ── MOMENT 2 · EN COURS ──────────────────────────────────────────────────── */
.crw-frise{display:flex;align-items:flex-start;margin-bottom:var(--e-10)}
.crw-e{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;
   gap:var(--e-4);position:relative;text-align:center;cursor:pointer;background:none;border:0;padding:0}
/* Le trait de liaison : un pseudo-élément, pas une bordure — il ne pousse rien. */
.crw-e::before{content:"";position:absolute;top:13px;left:calc(-50% + 14px);
   width:calc(100% - 28px);height:2px;background:var(--cok-border);
   transform-origin:left center;transform:scaleX(0);
   transition:transform var(--d-slow) var(--c-pose)}
.crw-e:first-child::before{display:none}
.crw-e.fait::before,.crw-e.encours::before,.crw-e.bloque::before{transform:scaleX(1)}
.crw-e.fait::before,.crw-e.encours::before{background:var(--cok-green)}
.crw-e.bloque::before{background:var(--cok-red)}
.crw-e .r{display:grid;place-items:center;width:26px;height:26px;border-radius:50%;
   background:var(--surface-2);border:2px solid var(--cok-border);color:var(--cok-text-3);
   position:relative;z-index:1;transition:transform var(--d-base) var(--c-rebond)}
.crw-e .n{font-size:var(--t-micro);color:var(--cok-text-3);line-height:1.25;
   overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.crw-e.fait .r{background:var(--cok-green-bg);border-color:var(--cok-green);color:var(--cok-green)}
.crw-e.fait .n{color:var(--cok-text-2)}
.crw-e.encours .r{background:var(--cok-accent-bg);border-color:var(--cok-accent);
   color:var(--cok-accent);transform:scale(1.14)}
.crw-e.encours .n{color:var(--cok-text);font-weight:600}
.crw-e.bloque .r{background:var(--cok-red-bg);border-color:var(--cok-red);color:var(--cok-red)}
.crw-e.bloque .n{color:var(--cok-red)}
.crw-e.ouverte .n{color:var(--cok-text);font-weight:600}
/* Le pouls — transform et opacity seuls, donc aucune repeinte. */
.crw-e.encours .r::after{content:"";position:absolute;inset:-2px;border-radius:50%;
   border:2px solid var(--cok-accent);animation:crwPouls 1.9s var(--c-pose) infinite}
@keyframes crwPouls{0%{transform:scale(1);opacity:.55}70%{transform:scale(1.5);opacity:0}100%{opacity:0}}

.crw-dit{display:flex;align-items:center;gap:var(--e-8);padding:var(--e-8) var(--e-10);
   background:var(--surface-2);border:1px solid var(--cok-border);border-radius:var(--r-lg)}
.crw-dit.rate{border-color:color-mix(in srgb,var(--cok-red) 32%,transparent)}
.crw-dit .b{width:8px;height:8px;flex:0 0 8px;border-radius:50%;background:var(--cok-accent);
   animation:crwRespire 1.8s var(--c-pose) infinite}
.crw-dit.rate .b{background:var(--cok-red);animation:none}
.crw-dit.calme .b{animation:none;background:var(--cok-green)}
@keyframes crwRespire{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(.55);opacity:.45}}
.crw-dit p{margin:0;font-size:var(--t-base);color:var(--cok-text-2)}
.crw-dit p b{color:var(--cok-text);font-weight:600}

/* ⚠️ UN INCIDENT N'EST PAS UNE ÉTAPE. Le téléphone et le captcha arrivent quand
   Vinted le décide : les mettre dans la frise ferait croire à un parcours cassé
   (règle d'Amadou, 12/08). Ils vivent ici, à part. */
.crw-incidents{display:grid;gap:var(--e-4);margin-top:var(--e-8)}
.crw-inc{display:flex;align-items:center;gap:var(--e-6);padding:var(--e-6) var(--e-8);
   border-radius:var(--r-md);font-size:var(--t-mini);color:var(--cok-text);
   background:var(--cok-warn-bg);
   border:1px solid color-mix(in srgb,var(--cok-amber) 30%,transparent)}
.crw-inc.fait{background:var(--cok-green-bg);
   border-color:color-mix(in srgb,var(--cok-green) 30%,transparent)}
.crw-inc .i{flex:0 0 auto;display:grid;place-items:center;color:var(--cok-amber)}
.crw-inc.fait .i{color:var(--cok-green)}
.crw-inc b{font-weight:600}
.crw-inc .toi{margin-left:auto;flex:0 0 auto;padding:2px var(--e-6);border-radius:var(--r-pilule);
   background:var(--cok-amber);color:#1a1206;font-size:var(--t-nano);font-weight:700;letter-spacing:.03em}

.crw-detail{display:flex;align-items:center;gap:var(--e-8);margin-top:var(--e-8);
   padding:var(--e-8) var(--e-10);background:var(--surface-2);
   border:1px solid var(--cok-border-2);border-radius:var(--r-lg)}
.crw-detail .x{min-width:0;flex:1 1 auto}
.crw-detail .x b{display:block;font-size:var(--t-base);color:var(--cok-text)}
.crw-detail .x span{display:block;font-size:var(--t-mini);color:var(--cok-text-3)}
.crw-detail .x i{display:block;font-size:var(--t-mini);color:var(--cok-text-2);font-style:normal;margin-top:2px}

.crw-actions{display:flex;gap:var(--e-6);flex-wrap:wrap;margin-top:var(--e-8);
   align-items:flex-start}
/* ⚠️⚠️⚠️ UN BOUTON NE GRANDIT PAS (corrigé le 03/09/2026). J'avais écrit
   `flex:1 1 140px`, pensé pour une RANGÉE horizontale. Mais « Voir son écran » atterrit
   SEUL dans une colonne (`.cok-horlo > * { flex-direction:column }` +
   `#cp-compte-etat { flex:1 }`) : il s'étirait alors sur toute la hauteur de la grille,
   fixée par la fiche d'identité d'à côté. Résultat vu par Amadou : un bouton pour
   agrandir l'écran PLUS GRAND que l'écran, et « Actualiser »/« Abandonner » à 380 px
   chacun.
   `flex:0 0 auto` + `align-self:flex-start` : il prend la taille de son texte, où qu'on
   le pose. `max-width` borne le cas d'une rangée très large. */
.crw-b{flex:0 0 auto;align-self:flex-start;max-width:100%;
   min-height:36px;height:36px;display:inline-flex;align-items:center;justify-content:center;
   gap:var(--e-4);padding:0 var(--e-12);border-radius:var(--r-pilule);cursor:pointer;
   background:var(--surface-2);border:1px solid var(--cok-border-2);color:var(--cok-text);
   font:600 var(--t-base)/1 inherit;white-space:nowrap;
   transition:transform var(--d-fast) var(--c-pose)}
.crw-b:hover{transform:translateY(-1px)}
.crw-b.pri{background:var(--cok-accent-solid);border-color:transparent;color:#fff}
/* Le geste principal d'un moment peut, lui, prendre la largeur : il est seul et c'est
   la seule chose à faire. `.crw-actions--large` le dit explicitement, au lieu de le
   laisser dépendre du conteneur — c'est cette dépendance qui a produit le bouton géant. */
.crw-actions--large .crw-b{flex:1 1 auto}
.crw-b.danger{color:var(--cok-red);border-color:color-mix(in srgb,var(--cok-red) 30%,transparent)}

/* ── MOMENT 3 · NÉ ────────────────────────────────────────────────────────── */
.crw-ne{display:flex;align-items:center;gap:var(--e-10);padding:var(--e-10);
   background:var(--surface-2);border-radius:var(--r-lg);margin-bottom:var(--e-8);
   border:1px solid color-mix(in srgb,var(--cok-green) 26%,transparent)}
.crw-ne.rate{border-color:color-mix(in srgb,var(--cok-red) 30%,transparent)}
.crw-ne .v{width:46px;height:46px;flex:0 0 46px;border-radius:50%;display:grid;place-items:center;
   background:var(--cok-green-bg);color:var(--cok-green)}
.crw-ne.rate .v{background:var(--cok-red-bg);color:var(--cok-red)}
.crw-ne .q{min-width:0;flex:1 1 auto}
.crw-ne .q b{display:block;font-size:var(--t-moyen);font-weight:600;color:var(--cok-text)}
.crw-ne .q span{display:block;font-size:var(--t-mini);color:var(--cok-text-3);
   white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.crw-faits{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));
   gap:var(--e-4);margin-bottom:var(--e-10)}
.crw-f{padding:var(--e-6) var(--e-8);background:var(--surface-2);
   border:1px solid var(--cok-border);border-radius:var(--r-md)}
.crw-f .l{font-size:var(--t-nano);color:var(--cok-text-3);text-transform:uppercase;letter-spacing:.05em}
.crw-f .v{font-size:var(--t-base);font-weight:600;margin-top:1px;color:var(--cok-text);
   white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ── ÉTROIT ───────────────────────────────────────────────────────────────── */
@media (max-width:560px){
  .crw-tete{padding:var(--e-10) var(--e-8) var(--e-6)}
  .crw-vue{padding:0 var(--e-8) var(--e-10)}
  /* Six pastilles côte à côte à 360 px, ce sont six libellés illisibles. */
  /* ⚠️ L'ÉCART VAUT LA LONGUEUR DU TRAIT. Avec 4 px d'écart et un trait de 12 px, la
     liaison passait DERRIÈRE la pastille du dessus : on voyait des ronds empilés,
     pas un chemin. Les deux valeurs doivent être la même. */
  .crw-frise{flex-direction:column;gap:var(--e-6)}
  .crw-e{flex-direction:row;align-items:center;gap:var(--e-8);text-align:left;width:100%}
  .crw-e::before{top:auto;left:12px;bottom:100%;width:2px;height:var(--e-6);
     transform-origin:center bottom;transform:scaleY(0)}
  .crw-e.fait::before,.crw-e.encours::before,.crw-e.bloque::before{transform:scaleY(1)}
  .crw-e .n{white-space:normal;max-width:none}
  .crw-ne{gap:var(--e-8)}
  .crw-go{flex-basis:100%}
}
@media (prefers-reduced-motion:reduce){
  .crw-e.encours .r::after,.crw-dit .b{animation:none}
  .crw-vue,.crw-pile,.crw-e::before,.crw-e .r,.crw-j,.crw-go,.crw-b{transition:none}
}

/* ⚠️⚠️⚠️ LES BLOCS ARRIVENT ENSEMBLE, PAS EN CASCADE (02/09/2026).
   Amadou : « il y a plusieurs choses qui s'affichent, mais pas en même temps, ce qui
   fait un décalage visuellement. » La carte naissait avec deux emplacements en attente
   (les jauges, « où ce compte va naître »), et chacun se remplissait quand SA requête
   revenait : trois arrivées séparées, et la carte qui grandit à chaque fois.
   ⚠️ L'ÉTAT PAR DÉFAUT EST VISIBLE. C'est le JavaScript qui pose `data-attente`, et il
   programme sa levée DANS LE MÊME GESTE. Si le script ne tourne pas, ou tombe entre les
   deux, le corps reste visible — on ne refait pas la coquille invisible de ce matin. */
.crw-corps{transition:opacity var(--d-mid) var(--c-pose)}
.crw-corps[data-attente]{opacity:0}
@media (prefers-reduced-motion:reduce){ .crw-corps{transition:none} }

/* La pastille « en direct » du bouton d'écran : elle ne s'allume que quand une image
   est réellement arrivée — un point qui clignote sur un écran vide serait un mensonge. */
.crw-direct{width:7px;height:7px;border-radius:50%;background:var(--cok-green);
   margin-left:var(--e-4);flex:0 0 7px;animation:crwRespire 1.8s var(--c-pose) infinite}
@media (prefers-reduced-motion:reduce){ .crw-direct{animation:none} }

/* Une jauge qui ouvre ce qu'elle mesure (le domaine). Elle reste une jauge : même
   fond, même taille — seul le curseur et un filet plus net disent qu'on peut cliquer.
   ⚠️ `appearance:none` et la police héritée : sans eux, un <button> reprend le style
   natif du navigateur et la jauge cesse d'être la jumelle des quatre autres. */
.crw-j.cliquable{appearance:none;cursor:pointer;font:inherit;text-align:left;width:100%;
   border-color:var(--cok-border-2)}
.crw-j.cliquable:hover{border-color:var(--cok-accent)}

/* ⚠️⚠️⚠️ CETTE RÈGLE MASQUAIT LA CARTE « CRÉER UN COMPTE » DEPUIS LE 03/09/2026.
   Elle disait : « quand `#cp-compte-etat` est vide, replie la grille ET cache
   `.cok-horlo-g` ». À l'époque cette colonne ne portait QUE l'écran de diffusion, et
   la cacher vide était juste. Mais elle porte AUSSI `#cp-compte` — la carte de
   lancement, celle qui contient tout le tunnel. Or `#cp-compte-etat` est vide dès
   qu'aucune création ne tourne (`_cpSuiviHTML(null)` rend une chaîne vide) : c'est
   donc l'état NORMAL de l'écran, et la carte disparaissait avec la colonne.
   Le dernier ordre de création date du 03/09 — le jour même. Personne n'a pu lancer
   de création depuis cet écran pendant cinq jours, et rien nulle part ne le disait :
   un `:has()` ne laisse aucune trace, ne lève aucune erreur, n'écrit dans aucun
   journal. C'est le défaut le plus silencieux qu'on ait vu ici.
   ⚠️ LA RÈGLE VISE MAINTENANT CE QU'ELLE VOULAIT VRAIMENT VISER : la zone d'écran,
   pas la colonne. Vide, l'écran se retire ; la colonne garde ce qu'elle a. Et elle a
   toujours quelque chose — la carte quand rien ne tourne, l'écran quand ça tourne. */
#cp-compte-etat:empty { display: none; }

/* ⚠️ SANS LA COLONNE D'IDENTITÉ, LA GRILLE N'A PLUS QU'UNE COLONNE. Laisser
   `1fr 1fr` garderait une colonne fantôme vide : le tunnel resterait à la moitié de
   la largeur, et les cartes de famille à cinq par rangée au lieu de neuf. */
/* ⚠️ LA MARGE DE 26 px SÉPARAIT DEUX COLONNES QUI N'EXISTENT PLUS. Sans la fiche à
   droite, elle ne fait qu'éloigner le rail des onglets. */
.cok-horlo--seul { grid-template-columns: minmax(0, 1fr); margin-top: var(--e-12); }
/* ⚠️⚠️ LE TUNNEL GARDE LA MÊME HAUTEUR D'UN TEMPS À L'AUTRE. Sans plancher, chaque
   glissement changerait la hauteur de la page — le pied remonterait puis
   redescendrait, et l'œil perdrait le fil du mouvement.
   ⚠️ LE PLANCHER VAUT LA HAUTEUR RÉELLE DU TEMPS LE PLUS GRAND, PAS UNE MARGE DE
   SÉCURITÉ. À 27 rem il dépassait le temps 1 de trois centimètres : un vide sous les
   cartes, et le pied qui flottait au milieu de rien. Le dosage fait ~5 rem, deux
   rangées de cartes 17 rem, les écarts le reste — 23,5 rem. Un plancher trop haut
   fabrique exactement le vide qu'on cherche à supprimer. */
/* ⚠️ LE PLANCHER DONNE LA PLACE, `align-content` LA RÉPARTIT. Les deux vont
   ensemble : un plancher seul creuse un vide sous le contenu (c'est ce qu'on a eu
   trois fois aujourd'hui), une répartition seule n'a rien à répartir. Ici les
   étiquettes se centrent dans la hauteur du temps le plus grand. */
.cok-horlo--seul .crea-hublot { min-height: 17rem; }
.cok-horlo--seul .crea-t { display: flex; flex-direction: column; }
/* Le pied suit le contenu au lieu de rester collé au plancher. */
.cok-horlo--seul .crea-pied { margin-top: var(--e-12); padding-top: var(--e-12); }

/* ══ LE TUNNEL DE CRÉATION — QUATRE TEMPS (08/09/2026) ═══════════════════════
   Amadou : « à chaque étape, ça glisse vers la droite ». Une question par temps.
   ⚠️ AUCUNE VALEUR BRUTE ICI : que des jetons. La bibliothèque du 13/08 tient. */
.crea-rail { display: flex; gap: var(--e-4); margin-bottom: var(--e-16); }
.crea-rt   { flex: 1 1 0; display: flex; flex-direction: column; gap: var(--e-8);
             min-width: 0; cursor: default; }
.crea-rt-b { height: var(--e-2); border-radius: var(--r-pilule);
             background: var(--border); transition: background var(--t-moyen) var(--c-pose); }
.crea-rt.faite .crea-rt-b { background: var(--green); }
.crea-rt.ici   .crea-rt-b { background: var(--cok-accent); }
/* ⚠️⚠️ LA COUPE SE POSE SUR LE TEXTE, PAS SUR LA BOÎTE. Un enfant flex ne rétrécit
   pas sous la largeur de son contenu tant qu'il n'a pas `min-width: 0` : un nom long
   déborderait sur le temps d'à côté au lieu de se couper. */
.crea-rt-n { display: flex; align-items: center; gap: var(--e-6); min-width: 0;
             font-size: var(--t-mini); font-weight: var(--fw-fort);
             color: var(--cok-text-3); line-height: var(--lh-un); }
.crea-rt-n span { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crea-rt.ici   .crea-rt-n { color: var(--cok-text); }
.crea-rt.faite .crea-rt-n { color: var(--cok-text-2); }
/* ⚠️ La pastille numérotée est partie avec les chiffres : plus aucun `.crea-rt-p`
   n'est fabriqué. On retire ses quatre règles plutôt que de les laisser attendre —
   du CSS mort dont le nom fait autorité finit par être recopié. */
.crea-rt:not(.ici):not(.faite) { cursor: default; }
.crea-rt.faite { cursor: pointer; }

/* ⚠️⚠️⚠️ PAS DE `flex-basis` SUR LES TEMPS. Une base de 100 % l'emporterait sur la
   largeur en ligne et chaque temps ferait quatre fois la piste : les boutons du
   dernier tomberaient hors de l'écran, sans qu'aucune erreur ne le dise. */
.crea-hublot { overflow: hidden; }
.crea-piste  { display: flex; width: 400%;
               transition: transform var(--t-moyen) var(--c-pose); }
.crea-t      { width: 25%; min-width: 0; }
@media (prefers-reduced-motion: reduce) { .crea-piste { transition: none; } }

/* ── TEMPS 1 · le dosage en haut, les cartes dessous ── */
.crea-dos { background: var(--surface-2); border: 1px solid var(--cok-border);
            border-radius: var(--r-carte); padding: var(--e-12) var(--e-16) var(--e-14);
            margin-bottom: var(--e-16); flex: 0 0 auto; }
.crea-dos-h { display: flex; align-items: baseline; justify-content: space-between;
              gap: var(--e-12); margin-bottom: var(--e-10); }
.crea-dos-t { font-size: var(--t-meta); font-weight: var(--fw-fort); color: var(--cok-text-2); }
.crea-dos-x { appearance: none; border: 0; background: none; cursor: pointer;
              font: inherit; font-size: var(--t-mini); font-weight: var(--fw-fort);
              color: var(--cok-accent); padding: 0; text-decoration: underline; }
.crea-dos-barre { display: flex; height: var(--e-10); gap: var(--e-2);
                  border-radius: var(--r-pilule); overflow: hidden; background: var(--surface); }
.crea-dos-seg { transition: width var(--t-moyen) var(--c-pose); }
/* ⚠️ La légende se colle à la barre : elle la LIT, elle ne la commente pas. */
.crea-dos-lg { display: flex; flex-wrap: wrap; gap: var(--e-4) var(--e-16); margin-top: var(--e-6); }
.crea-dos-l  { display: flex; align-items: center; gap: var(--e-6);
               font-size: var(--t-mini); color: var(--cok-text-2); }
.crea-dos-l i { width: var(--e-8); height: var(--e-8); border-radius: var(--r-micro); flex: 0 0 auto; }
.crea-dos-n  { margin: var(--e-10) 0 0; font-size: var(--t-mini);
               color: var(--cok-text-3); line-height: var(--lh-normal); }
.crea-curseurs { display: flex; flex-direction: column; gap: var(--e-8); margin-top: var(--e-12); }
.crea-cur { display: grid; grid-template-columns: 1fr var(--e-48) var(--e-40);
            align-items: center; gap: var(--e-12); }
.crea-cur label  { font-size: var(--t-mini); color: var(--cok-text-2);
                   white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crea-cur input  { width: 100%; }
.crea-cur output { font-size: var(--t-mini); font-weight: var(--fw-fort); text-align: right;
                   font-variant-numeric: tabular-nums; color: var(--cok-text); }

/* Les cartes de la Bibliothèque, en plus petit — même dessinateur, même silhouette. */
/* ── LES FAMILLES, EN ÉTIQUETTES ────────────────────────────────────────────
   Amadou : « la sélection des familles prend trop de place ». Dix-sept CARTES, même
   petites, font deux rangées de 104 px — 214 px pour poser une question. La carte de
   la Bibliothèque empile trois rangées de contenu : logo, nom, compte. Elle est faite
   pour feuilleter un catalogue, pas pour choisir en un clic.
   ⚠️ ON EMPRUNTE LES PIÈCES DU SÉLECTEUR VALIDÉ LE MATIN MÊME (`.cp-fam-l`) : logo de
   16 px, nom, compte discret. Seule la mise en page change — en enfilade au lieu
   d'une colonne. Dix-sept étiquettes tiennent en deux rangées de 30 px.
   ⚠️⚠️ LE CHOISI SE DISTINGUE PAR LA FORME, PAS PAR LA SEULE TEINTE : l'étoile marque
   la prioritaire, le filet plein les secondaires. Sur le thème par défaut l'ambre et
   l'accent sont deux dorés — une couleur seule ne se lit pas sur les dix-sept thèmes. */
/* ⚠️⚠️ LES ÉTIQUETTES OCCUPENT LA PLACE, ELLES NE SE TASSENT PAS EN HAUT. Amadou :
   « c'est trop entassé, il y a de la place en dessous, utilise-la ». `flex: 1` donne
   au bloc toute la hauteur qui reste du temps, et `align-content: center` y répartit
   les rangées au lieu de les empiler contre le dosage. Le vide ne se remplit pas
   avec du contenu en plus — il se remplit avec de l'air entre ce qui existe. */
.crea-fams { display: flex; flex-wrap: wrap; justify-content: center;
             align-content: center; flex: 1 1 auto;
             gap: var(--e-10) var(--e-8); padding: var(--e-2); }
.crea-fam-c { display: inline-flex; align-items: center; gap: var(--e-8);
              font: inherit; font-size: var(--t-base); cursor: pointer;
              padding: var(--e-10) var(--e-16); border-radius: var(--r-pilule);
              border: 1px solid var(--cok-border); background: var(--surface-2);
              color: var(--cok-text-2); white-space: nowrap;
              transition: border-color var(--t-bref) var(--c-pose),
                          color var(--t-bref) var(--c-pose),
                          background var(--t-bref) var(--c-pose); }
.crea-fam-c:hover { color: var(--cok-text); border-color: var(--cok-text-3); }
.crea-fam-c:focus-visible { outline: 2px solid var(--cok-accent); outline-offset: 2px; }
/* Une famille sans pack libre reste ATTEIGNABLE : atténuée, jamais désactivée — c'est
   en la choisissant qu'on apprend qu'il faudra lui monter un pack. */
.crea-fam-c.vide { opacity: .62; }
.crea-fam-i { display: grid; place-items: center; flex: 0 0 var(--e-18);
              width: var(--e-18); height: var(--e-18); opacity: .7; }
.crea-fam-i svg { width: var(--e-18); height: var(--e-18); }
.crea-fam-n { font-size: var(--t-meta); font-weight: var(--fw-fort);
              color: var(--cok-text-3); font-variant-numeric: tabular-nums; }
.crea-fam-c--sec { border-color: var(--violet-soft); color: var(--cok-text); }
.crea-fam-c--sec .crea-fam-i { opacity: 1; color: var(--cok-accent); }
.crea-fam-c--pri { border-color: var(--cok-accent); background: var(--cok-accent-bg);
                   color: var(--cok-text); font-weight: var(--fw-fort); opacity: 1; }
.crea-fam-c--pri .crea-fam-i { opacity: 1; color: var(--cok-accent); }
.crea-fam-c--pri::before { content: "★"; font-size: var(--t-mini); color: var(--cok-accent); }
/* ⚠️ SEPT RÈGLES RETIRÉES AVEC LES CARTES. `.crea-fams .lib-fam-carte-*` et
   `.crea-fc--*` habillaient la carte de la Bibliothèque et sa pastille ; plus aucune
   n'est fabriquée depuis que les familles sont des étiquettes. Du CSS mort qui vise
   une classe encore VIVANTE ailleurs est le pire des deux : il ne casse rien, et le
   jour où quelqu'un pose une `.lib-fam-carte` ici, elle hérite d'un habillage
   fantôme. */

/* ── TEMPS 2 ── */
.crea-mach { display: flex; align-items: center; gap: var(--e-8);
             margin: var(--e-12) 0 var(--e-20); font-size: var(--t-meta); color: var(--cok-text-2); }
.crea-cb   { display: flex; align-items: center; gap: var(--e-16); flex-wrap: wrap; }
.crea-cb-t { font-size: var(--t-meta); color: var(--cok-text-2); }

/* ── TEMPS 3 · le visage ── */
.crea-vis   { display: grid; grid-template-columns: 7rem 1fr; gap: var(--e-20); align-items: start; }
.crea-vis-av { width: 7rem; height: 7rem; border-radius: var(--r-pilule); overflow: hidden;
               background: var(--surface-2); border: 1px solid var(--border);
               display: grid; place-items: center;
               font-size: var(--t-title); font-weight: var(--fw-gras); color: var(--cok-accent); }
.crea-vis-av img { width: 100%; height: 100%; object-fit: cover; }
.crea-vis-n { font-size: var(--t-body); font-weight: var(--fw-fort); margin: 0 0 var(--e-4); }
.crea-vis-f { display: inline-flex; align-items: center; gap: var(--e-6); margin: 0 0 var(--e-12);
              font-size: var(--t-mini); font-weight: var(--fw-fort); color: var(--cok-accent); }
.crea-vis-fi { display: inline-flex; width: var(--e-14); height: var(--e-14); }
.crea-vis-fi svg { width: 100%; height: 100%; }
.crea-vis-b { background: var(--surface-2); border: 1px solid var(--cok-border);
              border-radius: var(--r-md); padding: var(--e-12); margin: 0 0 var(--e-16);
              font-size: var(--t-meta); color: var(--cok-text-2); line-height: var(--lh-aere); }
.crea-chrono   { display: flex; align-items: center; gap: var(--e-12); flex-wrap: wrap; }
.crea-chrono-p { flex: 1 1 8rem; height: var(--e-2); border-radius: var(--r-pilule);
                 overflow: hidden; background: var(--border); }
.crea-chrono-j { height: 100%; background: var(--cok-accent); transition: width 1s linear; }
.crea-chrono.pris .crea-chrono-j { background: var(--green); }
.crea-chrono-t { font-size: var(--t-mini); color: var(--cok-text-3);
                 white-space: nowrap; font-variant-numeric: tabular-nums; }
.crea-chrono-b { appearance: none; cursor: pointer; font: inherit;
                 font-size: var(--t-mini); font-weight: var(--fw-fort);
                 background: var(--surface-2); border: 1px solid var(--border);
                 color: var(--cok-text-2); padding: var(--e-6) var(--e-12);
                 border-radius: var(--r-pilule); white-space: nowrap; }
.crea-chrono-b:hover { color: var(--cok-text); border-color: var(--violet-soft); }
.crea-vide { font-size: var(--t-meta); color: var(--amber); margin: 0; }

/* ── TEMPS 4 · le récapitulatif ── */
.crea-recap { display: flex; flex-direction: column; gap: var(--e-1);
              background: var(--cok-border); border: 1px solid var(--cok-border);
              border-radius: var(--r-carte); overflow: hidden; margin: var(--e-16) 0 0; }
.crea-rc { display: grid; grid-template-columns: 9rem 1fr; gap: var(--e-16);
           padding: var(--e-10) var(--e-16); background: var(--surface); align-items: baseline; }
.crea-rc dt { font-size: var(--t-mini); color: var(--cok-text-3);
              text-transform: uppercase; letter-spacing: var(--ls-caps); font-weight: var(--fw-fort); }
.crea-rc dd { margin: 0; font-size: var(--t-meta); color: var(--cok-text); }

/* ── LA BARRE DU BAS ── */
.crea-pied { display: flex; align-items: center; justify-content: space-between;
             gap: var(--e-16); margin-top: var(--e-16);
             padding-top: var(--e-16); border-top: 1px solid var(--cok-border); }
.crea-frein { margin: 0; font-size: var(--t-mini); color: var(--amber); }
.crea-nav   { display: flex; gap: var(--e-8); flex: 0 0 auto; }
.crea-btn { appearance: none; cursor: pointer; font: inherit;
            font-size: var(--t-meta); font-weight: var(--fw-fort);
            border-radius: var(--r-pilule); padding: var(--e-8) var(--e-20);
            border: 1px solid var(--border); background: none; color: var(--cok-text-2); }
.crea-btn:hover:not(:disabled) { color: var(--cok-text); border-color: var(--cok-text-3); }
.crea-btn:disabled { opacity: .34; cursor: not-allowed; }
.crea-btn--pri { background: var(--cok-accent); color: var(--sur-accent); border-color: var(--cok-accent); }

@media (max-width: 40rem) {
  .crea-vis { grid-template-columns: 1fr; }
  .crea-rc  { grid-template-columns: 1fr; gap: var(--e-4); }
  .crea-rt-n span { display: none; }
  .crea-pied { flex-direction: column; align-items: stretch; }
  .crea-nav  { justify-content: flex-end; }
}

/* ══ L'ÉCRAN DE PENDANT — LA FRISE SUR DEUX LIGNES, ET LES VUES QUI GLISSENT ═══
   Amadou, 08/09 : « je veux aussi que ça soit une succession d'étapes […] et au
   milieu l'écran pour voir ce qui se passe en temps réel ».
   ⚠️ La ligne du bas garde la MÊME largeur et se déplace en entier : elle rentre à
   gauche de `--cpp-decal` et ressort à droite d'autant (marge droite négative). Le
   décalage dit que c'est la SUITE, pas une seconde série. */
.cpp-rail { --cpp-decal: var(--e-20); flex-direction: column; gap: var(--e-12); }
.cpp-l { display: flex; align-items: flex-start; min-width: 0; }
.cpp-l--bas { margin-left: var(--cpp-decal); margin-right: calc(var(--cpp-decal) * -1); }
/* ⚠️ LE TRAIT DE LIAISON NE REMONTE PAS À LA LIGNE D'AVANT. Le premier temps de
   chaque ligne n'a rien à sa gauche : sans ça, un trait partait vers le vide. */
.cpp-l > .crw-e:first-child::before { display: none; }
/* Un incident n'est pas une étape : l'italique le dit sans lui prendre de place. */
.cpp-e--inc .n { font-style: italic; }
.crw-e .toi { display: block; margin-top: var(--e-2); font-size: var(--t-micro);
              font-weight: var(--fw-fort); color: var(--amber); line-height: var(--lh-un); }

/* ⚠️⚠️⚠️ PAS DE `flex-basis` SUR LES VUES. Une base de 100 % l'emporte sur la largeur
   en ligne : chaque vue ferait N fois la piste, et les commandes du dernier temps
   tomberaient hors de l'écran sans qu'aucune erreur ne le dise. */
.cpp-hublot { overflow: hidden; margin-bottom: var(--e-12); }
.cpp-piste  { display: flex; transition: transform var(--t-long) var(--c-pose); }
/* ⚠️ La largeur vient du JS (une part de la piste), pas d'ici : elle dépend du
   nombre de temps, qui change à chaque création. */
.cpp-v      { flex: 0 0 auto; min-width: 0; }
@media (prefers-reduced-motion: reduce) { .cpp-piste { transition: none; } }

.cpp-v-h { display: flex; align-items: baseline; gap: var(--e-8); margin-bottom: var(--e-8); }
.cpp-v-h b { font-size: var(--t-small); font-weight: var(--fw-fort); color: var(--cok-text); }
.cpp-v-e { font-size: var(--t-mini); color: var(--cok-text-3); }
.cpp-v-e.fait    { color: var(--green); }
.cpp-v-e.encours { color: var(--cok-accent); }
.cpp-v-e.bloque  { color: var(--red); }
.cpp-v-t { margin-left: auto; font-size: var(--t-mini); color: var(--cok-text-3);
           font-variant-numeric: tabular-nums; }
.cpp-v-c { display: grid; grid-template-columns: 1.15fr 1fr; gap: var(--e-16); align-items: start; }
.cpp-v-d { margin: 0; font-size: var(--t-meta); color: var(--cok-text-2);
           line-height: var(--lh-aere); }

/* L'écran du navigateur, en direct. */
.cpp-ec { border: 1px solid var(--border); border-radius: var(--r-carte);
          overflow: hidden; background: var(--surface-2); }
.cpp-ec img { display: block; width: 100%; height: auto; }
.cpp-ec--vide { display: grid; place-items: center; min-height: 8rem;
                padding: var(--e-16); text-align: center;
                font-size: var(--t-mini); color: var(--cok-text-3); }
.cpp-ec-l { display: inline-flex; align-items: center; gap: var(--e-6);
            margin-top: var(--e-6); font-size: var(--t-micro);
            letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--cok-accent); }
.cpp-ec-l i { width: var(--e-6); height: var(--e-6); border-radius: var(--r-pilule);
              background: var(--cok-accent); }

/* ⚠️ QUAND LE TRAVAIL N'EST PLUS DANS VINTED, LE CADRE CHANGE. « Sa fiche » s'écrit
   chez nous : lui donner une fenêtre de navigateur montrerait un écran qui n'existe
   pas. Plus de barre d'adresse, le panneau de Velbo à la place. */
.cpp-vlb { border: 1px solid var(--border); border-radius: var(--r-carte); overflow: hidden; }
.cpp-vlb-h { padding: var(--e-6) var(--e-10); background: var(--surface-2);
             border-bottom: 1px solid var(--cok-border);
             font-size: var(--t-mini); font-weight: var(--fw-fort); color: var(--cok-text-3); }
.cpp-vlb-c { padding: var(--e-16); min-height: 6rem; display: grid; place-items: center;
             text-align: center; font-size: var(--t-mini); color: var(--cok-text-2);
             line-height: var(--lh-aere); }

@media (max-width: 44rem) {
  .cpp-v-c { grid-template-columns: 1fr; }
  .cpp-l--bas { margin-left: var(--e-10); margin-right: calc(var(--e-10) * -1); }
}
