/* =============================================================================
   ARENA-BOARD.CSS — habillage du tapis de combat (feuille PARTAGÉE)
   -----------------------------------------------------------------------------
   Copie de WaifuCatchManager/public/arena-board.css, à un seul détail près :
   chaque règle est enfermée dans `:where(#bbRoot, .bb-skin)`. Au WCM la page
   N'EST que le plateau, donc des noms comme `.card` ou `.row` ne gênent personne ;
   le Dex, lui, est un site entier où `.card` désigne déjà la carte de COLLECTION.
   Servie telle quelle, cette feuille repeindrait toute la collection en cartes de combat.
   `:where()` est choisi pour sa spécificité NULLE : la cascade interne de la
   feuille reste rigoureusement identique à celle du WCM.

   DEUX CROCHETS :
     • `#bbRoot`   — le plateau de combat lui-même ;
     • `.bb-skin`  — tout conteneur du Dex qui réclame le VISUEL OFFICIEL des cartes
                     (sélecteur de deck, vitrine « Mes Decks »). Comme la spécificité
                     reste nulle, dex.css impose la taille et la grille sans surenchère.

   ⚠️ NE PAS ÉDITER ICI. On corrige la feuille du WCM, puis on rejoue :
        python scope-board-css.py <wcm>/public/arena-board.css <dex>/css/arena-board.css
   ============================================================================= */
/* Visuel du plateau — extrait de tcg-board-mockup.html (maquette validée) */
/* ⚠️ `*{box-sizing:border-box}` RETIRÉ le 2026-08-02.
   POURQUOI. Comme la règle `html,body` ci-dessous, elle est en TÊTE de feuille : le script de
   cloisonnement (scope-board-css.py) ne l'enfermait pas dans `:where(#bbRoot, .bb-skin)` et la
   recopiait telle quelle dans le Dex — un sélecteur universel servi à TOUT un site par une
   feuille censée ne concerner que le tapis.
   Elle ne manque à personne : les DEUX seuls hôtes qui chargent cette feuille la déclarent
   déjà eux-mêmes, et AVANT elle.
     · Dex  : waifudex/css/dex.css l.47 `*{ box-sizing: border-box; }`  (index.html l.30, puis
              arena-board.css l.34)
     · Labo : WaifuCatchManager/public/combat-arena.css l.56, même règle (combat-arena.html
              l.8, puis arena-board.css l.9)
   (WaifuCatchManager/public/index.html a la sienne l.11 mais ne charge pas cette feuille ;
   WaifuCatch-Central/public/overlay.html ne charge pas le plateau.) */
/* ⚠️ PLUS AUCUN background / color / font-family ICI (retirés le 2026-08-01).
   POURQUOI. Cette règle est en TÊTE de feuille, avant la première section : le script de
   cloisonnement (scope-board-css.py) ne l'enfermait pas dans `:where(#bbRoot, .bb-skin)`
   et la recopiait telle quelle dans css/arena-board.css du Dex. Or le Dex charge dex.css
   PUIS arena-board.css, à spécificité égale (0,0,1) : c'est cette règle qui gagnait. Tout
   le site — landing, grille, modales, boutique — s'affichait donc sur le fond du TAPIS DE
   COMBAT, en Segoe UI et texte #eee, et le raccourci `background` remettait en prime
   `background-attachment` à `scroll`, annulant le parallaxe `fixed` de dex.css.
   Au labo (combat-arena.html), ces trois déclarations ne servaient déjà à rien : la page
   redéclare `html, body` dans un <style> inline APRÈS les feuilles, donc c'est son fond
   #0a0e1c qui s'applique. On ne garde ici que ce qui sert vraiment au plateau —
   `overflow-x:hidden` en particulier, car le tapis est incliné (rotateX) et peut déborder. */
html,body{margin:0;min-height:100%;overflow-x:hidden}
/* `clip` AU LIEU DE `hidden` (2026-08-02) — même contention, sans casser position:sticky.
   LE DÉFAUT. `overflow-x:hidden` sur html ET body fait de la page un CONTENEUR DE
   DÉFILEMENT : tout `position:sticky` du site cesse de coller. Le Dex en compte quatre
   (dex.css l.81 en-tête, 1254, 5686, 5704) et cette feuille est chargée sur toutes ses pages
   (index.html l.34) : une feuille de tapis de combat cassait les en-têtes collants du site.
   POURQUOI ON NE SUPPRIME PAS LA RÈGLE. La contention est PORTANTE : `fitBoard`
   (arena-board.js) laisse volontairement le tapis déborder sur les côtés en portrait
   (« le tapis est censé occuper toute la largeur (et déborder légèrement sur les côtés) »)
   et son plancher d'échelle est 0,80 en portrait / 0,26 sur écran court. Mesuré au
   navigateur sur la charpente réelle de bbMountBoard, cartes comprises : 39 px de débordement
   à 375 px de large, 62 px à 1265 px. Retirer la règle, c'est une barre de défilement
   horizontale pendant tout le combat, mobile compris.
   CE QUI CHANGE. `overflow: clip` découpe SANS créer de conteneur de défilement — la
   contention reste, le sticky revient. Mesuré (Chrome, page témoin : en-tête sticky + bloc de
   3000 px, on scrolle à 2000 px en X puis 500 px en Y) :
     · aucune règle ............ scrollX=2000 (déborde)      top de l'en-tête =    0 (sticky OK)
     · html,body overflow-x:hidden  scrollX=0 (contenu)      top de l'en-tête = -500 (CASSÉ)
     · html seul ............... scrollX=2000 (déborde)      top =    0
     · body seul ............... scrollX=2000 (déborde)      top =    0
     · html,body overflow-x:clip .. scrollX=0 (contenu)      top =    0 (les deux à la fois)
   Et sur la charpente réelle du tapis à 375 px : `hidden` et `clip` donnent EXACTEMENT les
   mêmes nombres (largeur de document 375, débordement 0, tapis 0→375, 39 px découpés).
   `@supports` : un navigateur qui ignore `clip` garde la ligne `hidden` ci-dessus, donc le
   comportement d'aujourd'hui au pixel près — aucune régression possible. */
@supports (overflow-x: clip){ html,body{overflow-x:clip} }







/* ============ SCÈNE ============ */
:where(#bbRoot, .bb-skin) .scene{ perspective:2800px; perspective-origin:50% 42%; padding:10px 10px 12px; display:flex; justify-content:center }
:where(#bbRoot, .bb-skin) .mat{ width:min(900px,96vw); transform:rotateX(20deg); transform-origin:center 62%;
  border-radius:20px; position:relative; overflow:hidden;
  border:2px solid #3d5a8a; box-shadow:0 40px 70px -25px #000, 0 0 0 6px rgba(0,0,0,.35);
  display:flex; flex-direction:column }
:where(#bbRoot, .bb-skin) .half{ position:relative; padding:12px 24px 14px; display:flex; flex-direction:column; align-items:center; gap:8px }
/* ---- TAPIS PERSONNALISABLES (2026-07-25) ----
   Chaque moitié est un TAPIS : la TEINTE DE CAMP (halo bleu chez moi / rosé chez l'adversaire)
   reste FIXE quel que soit le tapis — on sait toujours qui est qui — et le skin change le
   MONDE en dessous via 3 variables : --matA/--matB (dégradé de fond) et --matPat (motif).
   Les skins .matskin-* sont gagnés sur les BOSS (catalogue /global-settings/mats). */
:where(#bbRoot, .bb-skin) .half.opp{ background:radial-gradient(120% 90% at 50% 0%, rgba(255,90,120,.10), transparent 62%),
  var(--matPat, repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px)),
  linear-gradient(180deg, var(--matA,#3a1c2c), var(--matB,#1a1020)) }
:where(#bbRoot, .bb-skin) .half.opp::before{content:"GOTAGA"; position:absolute; left:50%; top:52%; transform:translate(-50%,-50%);
  font-weight:900; font-size:2rem; letter-spacing:.4em; color:rgba(255,160,180,.07); pointer-events:none; white-space:nowrap}
:where(#bbRoot, .bb-skin) .half.me{ background:radial-gradient(120% 90% at 50% 100%, rgba(120,160,255,.12), transparent 62%),
  var(--matPat, repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px)),
  linear-gradient(180deg, var(--matA,#101a30), var(--matB,#1c2b4a)) }
:where(#bbRoot, .bb-skin) .half.me::before{content:"WAIFUCATCH"; position:absolute; left:50%; top:48%; transform:translate(-50%,-50%);
  font-weight:900; font-size:2rem; letter-spacing:.4em; color:rgba(180,210,255,.07); pointer-events:none; white-space:nowrap}
/* Les 8 tapis gagnables (tiers de boss 1→5). Motifs 100% CSS : zéro téléchargement. */
:where(#bbRoot, .bb-skin) .half.matskin-foret{ --matA:#16301e; --matB:#0a1810;
  --matPat:repeating-linear-gradient(115deg, rgba(120,220,150,.05) 0 3px, transparent 3px 26px),
           repeating-linear-gradient(65deg, rgba(60,160,90,.04) 0 2px, transparent 2px 22px) }
:where(#bbRoot, .bb-skin) .half.matskin-ocean{ --matA:#0c2536; --matB:#061019;
  --matPat:repeating-radial-gradient(120% 60% at 50% 120%, rgba(90,200,235,.05) 0 2px, transparent 2px 34px) }
:where(#bbRoot, .bb-skin) .half.matskin-volcan{ --matA:#33150e; --matB:#150705;
  --matPat:radial-gradient(3px 3px at 18% 42%, rgba(255,140,60,.28), transparent 60%),
           radial-gradient(2px 2px at 66% 70%, rgba(255,110,40,.22), transparent 60%),
           radial-gradient(2px 2px at 84% 30%, rgba(255,170,80,.18), transparent 60%),
           repeating-linear-gradient(0deg, rgba(255,90,30,.04) 0 2px, transparent 2px 30px) }
:where(#bbRoot, .bb-skin) .half.matskin-blizzard{ --matA:#1d2a3c; --matB:#0d1420;
  --matPat:repeating-linear-gradient(45deg, rgba(190,230,255,.05) 0 2px, transparent 2px 18px),
           repeating-linear-gradient(-45deg, rgba(190,230,255,.05) 0 2px, transparent 2px 18px) }
:where(#bbRoot, .bb-skin) .half.matskin-orage{ --matA:#241d3e; --matB:#0e0b1c;
  --matPat:repeating-linear-gradient(72deg, rgba(190,160,255,.06) 0 2px, transparent 2px 40px),
           radial-gradient(4px 4px at 76% 24%, rgba(230,210,255,.25), transparent 60%) }
:where(#bbRoot, .bb-skin) .half.matskin-sanctuaire{ --matA:#33290f; --matB:#171106;
  --matPat:radial-gradient(140% 80% at 50% 50%, rgba(255,225,140,.07), transparent 60%),
           repeating-conic-gradient(from 0deg at 50% 50%, rgba(255,220,130,.03) 0deg 6deg, transparent 6deg 30deg) }
:where(#bbRoot, .bb-skin) .half.matskin-crepuscule{ --matA:#38102a; --matB:#140713;
  --matPat:repeating-linear-gradient(160deg, rgba(255,90,140,.05) 0 3px, transparent 3px 30px),
           radial-gradient(120% 70% at 50% 30%, rgba(180,40,90,.10), transparent 65%) }
:where(#bbRoot, .bb-skin) .half.matskin-nebuleuse{ --matA:#171238; --matB:#070514;
  --matPat:radial-gradient(2px 2px at 12% 30%, rgba(255,255,255,.35), transparent 60%),
           radial-gradient(1.5px 1.5px at 38% 74%, rgba(180,210,255,.30), transparent 60%),
           radial-gradient(2px 2px at 58% 22%, rgba(255,230,200,.28), transparent 60%),
           radial-gradient(1.5px 1.5px at 82% 58%, rgba(200,180,255,.30), transparent 60%),
           radial-gradient(2.5px 2.5px at 92% 12%, rgba(255,255,255,.22), transparent 60%),
           radial-gradient(160% 90% at 30% 40%, rgba(120,80,220,.10), transparent 60%) }
:where(#bbRoot, .bb-skin) .turnbar{ position:relative; z-index:5; display:flex; align-items:center; justify-content:center; gap:10px; padding:6px 0;
  background:linear-gradient(90deg,transparent,rgba(20,30,60,.9),transparent);
  border-top:1px solid rgba(160,200,255,.35); border-bottom:1px solid rgba(160,200,255,.35); box-shadow:0 0 20px rgba(120,170,255,.35) }
:where(#bbRoot, .bb-skin) .turnbar .n{ font-size:.6rem; letter-spacing:.14em; color:#9fb4dd; background:rgba(0,0,0,.35); padding:2px 9px; border-radius:99px }
:where(#bbRoot, .bb-skin) .turnbar .msg{ font-weight:900; font-size:.82rem; color:#7cf0a0; text-shadow:0 0 12px rgba(90,240,150,.5) }
:where(#bbRoot, .bb-skin) .row{display:flex; gap:12px; justify-content:center; align-items:flex-end; position:relative; z-index:2}
:where(#bbRoot, .bb-skin) .tag{display:inline-flex; align-items:center; font-size:.72rem; font-weight:800; letter-spacing:.06em; padding:3px 14px; border-radius:99px; position:relative; z-index:2}
:where(#bbRoot, .bb-skin) .tag.o{background:rgba(255,90,120,.18); color:#ff9db0; border:1px solid rgba(255,120,140,.5)}
:where(#bbRoot, .bb-skin) .tag.m{background:rgba(90,190,255,.18); color:#9fd8ff; border:1px solid rgba(120,200,255,.5)}
:where(#bbRoot, .bb-skin) .elan{ position:relative; z-index:4; display:flex; align-items:center; gap:8px; width:min(430px,80%) }
:where(#bbRoot, .bb-skin) .elan .lbl{ font-size:.6rem; font-weight:900; letter-spacing:.12em; color:#ffd76a; white-space:nowrap }
:where(#bbRoot, .bb-skin) .elan .track{ flex:1; height:10px; border-radius:99px; background:rgba(0,0,0,.55); border:1px solid rgba(255,215,106,.3); overflow:hidden }
:where(#bbRoot, .bb-skin) .elan .fill{ height:100%; border-radius:99px; background:linear-gradient(90deg,#7a5cff,#c86bff,#ffd76a) }
:where(#bbRoot, .bb-skin) .elan .pct{ font-size:.6rem; font-weight:800; color:#cbbfe8; min-width:30px; text-align:right }
:where(#bbRoot, .bb-skin) .elan.full .track{ border-color:#ffd76a; box-shadow:0 0 16px rgba(255,215,106,.6) }
:where(#bbRoot, .bb-skin) .elan.full .fill{ background:linear-gradient(90deg,#ffd76a,#fff3b0,#ffd76a) }
:where(#bbRoot, .bb-skin) .elan.full .lbl{ animation:blink 1s ease-in-out infinite }
@keyframes blink{ 50%{opacity:.45} }

/* ============ CARTE ============ */
:where(#bbRoot, .bb-skin) .cw{ position:relative; display:inline-block }
:where(#bbRoot, .bb-skin) .cw .card{ position:relative; z-index:2 }
:where(#bbRoot, .bb-skin) .card{ width:152px; aspect-ratio:3/4.35; border-radius:10px; overflow:hidden;
  border:1.5px solid var(--rc,#888); background:linear-gradient(180deg,#1a2033,#0d1120);
  box-shadow:0 10px 18px -8px #000, 0 0 0 1px rgba(0,0,0,.5) }
:where(#bbRoot, .bb-skin) .card.active{ width:182px; box-shadow:0 20px 28px -10px #000, 0 0 24px -6px var(--glow,#7ad4ff) }
:where(#bbRoot, .bb-skin) .card img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 16% }
:where(#bbRoot, .bb-skin) .card .scrim{ position:absolute; left:0;right:0;bottom:0;height:54%; z-index:1;
  background:linear-gradient(180deg,transparent,rgba(8,10,20,.72) 40%,rgba(8,10,20,.97)) }
:where(#bbRoot, .bb-skin) .card .el{ position:absolute; top:5px; left:5px; z-index:3; width:21px; height:21px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; font-size:11px;
  background:radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--elc,#888) 75%, #fff), color-mix(in srgb, var(--elc,#888) 85%, #000));
  border:1px solid rgba(255,255,255,.55) }
:where(#bbRoot, .bb-skin) .card.active .el{ width:25px; height:25px; font-size:13px }
/* 2e ELEMENT (2026-08-01) : pastille SOUS la premiere, legerement plus petite — elle
   dit "secondaire" sans voler la lecture du type principal. */
:where(#bbRoot, .bb-skin) .card .el2{ top:29px; width:17px; height:17px; font-size:9px; opacity:.92 }
:where(#bbRoot, .bb-skin) .card.active .el2{ top:34px; width:21px; height:21px; font-size:11px }
/* ═══ ILLUSTRATION DANS LA PASTILLE (2026-08-06) ═══════════════════════════════════
   L'emoji (`.elfb`) et l'image (`.elimg`) coexistent dans le MÊME `.el` ; c'est
   `has-elimg`, posée par le `onload` de l'image (cf. bbElIcon), qui bascule de l'un à
   l'autre. Sans image servie, aucune de ces règles ne s'active et la pastille reste
   celle d'avant.
   POURQUOI `em` ET PAS `px` : `.el` existe en CINQ tailles (banc 21 px, active 25 px,
   `.el2` 17 et 21 px, portrait 17/20 px) et chacune porte DÉJÀ son `font-size` accordé.
   Dimensionner l'icône en `em` la fait suivre les cinq d'un seul coup — et suivre aussi
   le `font-size` EN LIGNE de la 2e pastille de maîtresse, qu'aucune règle ne cible.
   1,5 em tient ~78 % du diamètre. Le plateau est RÉDUIT par `fitBoard` (mesuré : ×0,51
   avec la barre d'outils, ×0,644 en mode officiel, ×0,80 en portrait), donc chaque pixel
   compte : à ×0,644 la pastille de banc fait 14,1 px à l'écran et le dessin 9,9 px.
   `object-fit:contain` : ces illustrations sont carrées mais on ne PARIE pas dessus —
   une future planche mal recadrée déborderait en `cover`.

   ⚠️ `position:static; inset:auto` — CE N'EST PAS DÉCORATIF, C'EST LE CORRECTIF.
   `.card img` (l'ART DE LA CARTE, plus haut) dit `position:absolute; inset:0;
   width:100%; height:100%` et capture TOUT `<img>` posé dans une carte, y compris
   celui-ci. Nos `width`/`height`/`object-fit` l'emportent par spécificité, mais PAS
   `position` ni `inset` : l'icône partait donc hors flux, collée en HAUT À GAUCHE du
   disque, et le centrage flex de `.el` devenait inerte. Mesuré au navigateur avant le
   correctif : marge gauche 0,5 px contre 2,7 px à droite, haut 0,5 contre bas 2,3 — sur
   un disque de 11 px, un décalage d'un cinquième du diamètre. Un test de « l'image
   déborde-t-elle ? » passe au vert dans cet état : il faut mesurer les QUATRE marges.
   `max-width/height:100 %` : en portrait la pastille tombe à 17 px et le liseré passe à
   2 px, la boîte de contenu ne fait donc plus que 13 px pour une icône de 1,5 em = 13,5 px.
   Sans plafond, l'icône mordait le liseré coloré d'un quart de pixel de chaque côté —
   justement l'information qu'on lui demande de préserver. */
:where(#bbRoot, .bb-skin) .card .el .elfb{ font-style:normal; line-height:1 }
:where(#bbRoot, .bb-skin) .card .el.has-elimg .elfb{ display:none }
:where(#bbRoot, .bb-skin) .card .el .elimg{ position:static; inset:auto;
  width:1.5em; height:1.5em; max-width:100%; max-height:100%; object-fit:contain; display:block;
  filter:drop-shadow(0 1px 1px rgba(0,0,0,.55)) }
/* ⚠️ LE DISQUE S'ASSOMBRIT — ET CE N'EST PAS UN GOÛT, C'EST UNE MESURE.
   Le fond de `.el` est la COULEUR DE L'ÉLÉMENT ; les illustrations sont, elles aussi,
   aux couleurs de leur élément. Une flamme orange sur un disque orange ne se voit pas.
   Contraste WCAG du dessin contre son fond, moyenné sur les pixels opaques des dix
   planches 64 px (relevé au navigateur, canvas, alpha > 160) :
       fond COULEUR : fire 1,03 · water 1,08 · nature 1,06 · earth 1,16 · normal 1,19 ·
                      ice 1,23 · light 1,53 · lightning 1,55 · dark 1,62 · wind 1,79
       fond SOMBRE  : dark 3,30 · fire 7,10 · wind 7,44 · lightning 8,21 · earth 8,78 ·
                      ice 8,80 · nature 9,04 · water 10,43 · light 10,98 · normal 13,65
   1,00 = strictement invisible : les six premiers éléments étaient ILLISIBLES. Sur fond
   sombre le pire cas (dark) passe 3,30, au-dessus du seuil AA « non-texte » (3,0).
   L'INFORMATION DE COULEUR N'EST PAS PERDUE : elle passe dans le LISERÉ.
   ⚠️ Mais un liseré de 1 px ne survit PAS à la réduction du plateau : `fitBoard` peint
   la scène à ×0,51 … ×0,80, donc 1 px de bordure devient 0,5 à 0,8 px à l'écran — une
   ligne sous-pixel, quasi effacée par l'antialiasing, alors que le disque COLORÉ qu'elle
   remplace se lisait, lui, en un coup d'œil. D'où 2 px ici : ×0,51 il reste 1,0 px plein,
   ×0,80 1,6 px. `box-sizing:border-box` étant global, la pastille ne change pas de taille.
   Portée volontairement limitée à `.has-elimg` : sans image servie, la pastille garde
   son disque coloré et son emoji, au pixel près comme aujourd'hui. */
:where(#bbRoot, .bb-skin) .card .el.has-elimg{ background:radial-gradient(circle at 38% 30%, rgba(16,18,30,.80), rgba(5,7,14,.94));
  border-width:2px; border-color:color-mix(in srgb, var(--elc,#888) 82%, #fff) }
/* La MAÎTRESSE (`.ms-el`) n'a pas de disque derrière elle : son icône se pose à même
   l'illustration, donc un poil plus grande et davantage détourée pour rester lisible
   sur un art clair.
   ⚠️ MÊME `position:static` QUE CI-DESSUS, et ici le dégât était pire : `.ms-el` n'a
   AUCUNE largeur propre (`position:absolute; top:4px; left:5px; font-size:.8rem`), elle
   se dimensionne sur son contenu. L'image partant hors flux, la pastille tombait à
   0 × 0 px (mesuré ; 18 × 17 px avant le lot) — l'icône restait visible par accident,
   mais l'infobulle `title` « Feu / Foudre… » n'avait plus AUCUNE surface à survoler. */
:where(#bbRoot, .bb-skin) .ms-el .elfb{ font-style:normal; line-height:1 }
:where(#bbRoot, .bb-skin) .ms-el.has-elimg .elfb{ display:none }
:where(#bbRoot, .bb-skin) .ms-el .elimg{ position:static; inset:auto;
  width:1.25em; height:1.25em; object-fit:contain; display:block;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.85)) }
:where(#bbRoot, .bb-skin) .card .hp{ position:absolute; top:5px; right:5px; z-index:3; display:flex; align-items:baseline; gap:2px;
  background:rgba(8,8,18,.82); border:1px solid rgba(255,255,255,.20); border-radius:6px; padding:1px 5px; font-weight:900; color:#fff }
/* LOGOS DE STATS COLORÉS (2026-08-01) : ♥ vert / ⚔ rouge / 🛡 bleu. Le glyphe porte un
   VS15 implicite via `font-variant-emoji:text` + une teinte forcée, sinon 🛡 s'affiche en
   emoji couleur et ignore le `color:`. Les CHIFFRES restent blancs (demande admin). */
:where(#bbRoot, .bb-skin) .card .hp i{ font-style:normal; font-size:.62rem; color:#57d98a; text-shadow:0 0 5px rgba(87,217,138,.55) }
:where(#bbRoot, .bb-skin) .card .hp b{ font-size:.74rem; text-shadow:0 0 6px rgba(255,90,110,.6) }
:where(#bbRoot, .bb-skin) .card.active .hp{ padding:2px 7px } :where(#bbRoot, .bb-skin) .card.active .hp i{ font-size:.54rem } :where(#bbRoot, .bb-skin) .card.active .hp b{ font-size:.94rem }
/* POLICE DE CARTE À COLLECTIONNER (2026-08-01, demande admin : « un truc plus Yu-Gi-Oh ou
   Pokémon »). Une SERIF humaniste pour le NOM et le texte d'ambiance — c'est elle qui donne
   l'air « carte imprimée ». Les CHIFFRES gardent la sans-serif tabulaire : sur une carte de
   190 px, une serif chiffrée devient illisible. Aucune police externe (le Dex ne doit pas
   dépendre d'un CDN) : uniquement des faces présentes sur Windows/macOS/Linux, avec un
   repli MINCHO pour le japonais — sans lui, la version JP retombait sur du gothique. */
:where(#bbRoot, .bb-skin) .card{ --tcg-serif:'Palatino Linotype','Book Antiqua',Palatino,'Yu Mincho','Hiragino Mincho ProN','Noto Serif JP',Georgia,'Times New Roman',serif }
:where(#bbRoot, .bb-skin) .card .nm{ position:absolute; left:0; right:0; bottom:30px; z-index:3; text-align:center; font-size:.64rem; font-weight:800;
  font-family:var(--tcg-serif); letter-spacing:.015em;
  color:#fff; text-shadow:0 1px 3px #000; padding:0 3px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
/* TEXTE D'AMBIANCE — la citation de la carte, gravée sous les attaques comme sur une vraie
   carte TCG. 52 caractères au maximum dans le catalogue : deux lignes suffisent, la 3e est
   coupée proprement plutôt que de manger l'illustration. */
/* `margin-bottom` : le bloc d'attaques est ancré EN BAS, donc cette marge repousse le texte
   d'ambiance vers le haut. Sans elle il mordait de 3 px sur le nom (mesuré au navigateur) —
   6 px couvrent aussi la carte AGRANDIE, dont le nom remonte à 34 px. */
:where(#bbRoot, .bb-skin) .card .cardatks .cardflav{ quotes:none; margin-top:3px; margin-bottom:6px; padding:2px 3px 0;
  font-family:var(--tcg-serif); font-style:italic; font-size:.4rem; line-height:1.25;
  color:#e4ebff; opacity:.86; text-align:center; text-shadow:0 1px 2px #000, 0 0 5px #000;
  border-top:1px solid color-mix(in srgb, var(--rc,#fff) 26%, transparent);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }
:where(#bbRoot, .bb-skin) .card.active .cardatks .cardflav{ font-size:.54rem }
:where(#bbRoot, .bb-skin) .card.active .nm{ font-size:.8rem; bottom:34px }
:where(#bbRoot, .bb-skin) .card .rar{ position:absolute; left:0;right:0; bottom:19px; z-index:3; text-align:center; font-size:.5rem; font-weight:800;
  letter-spacing:.14em; text-transform:uppercase; color:var(--rc,#aaa);
  text-shadow:0 0 8px color-mix(in srgb,var(--rc,#888) 70%, transparent), 0 1px 2px #000 }
:where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.55rem; bottom:22px }
:where(#bbRoot, .bb-skin) .card .st{ position:absolute; left:0; right:0; bottom:5px; z-index:3; display:flex; justify-content:center; gap:7px;
  font-size:.5rem; font-weight:800; color:#cfe0ff; text-shadow:0 1px 2px #000 }
:where(#bbRoot, .bb-skin) .card.active .st{ font-size:.58rem; gap:9px; bottom:6px }
:where(#bbRoot, .bb-skin) .card .st i{ font-style:normal; margin-right:2px; font-variant-emoji:text }
:where(#bbRoot, .bb-skin) .card .st .ic-atk{ color:#ff6b6b; text-shadow:0 0 5px rgba(255,107,107,.5) }
:where(#bbRoot, .bb-skin) .card .st .ic-def{ color:#5aa9ff; text-shadow:0 0 5px rgba(90,169,255,.5) }

/* ÉTAT ANNONCÉ SUR L'ATTAQUE (2026-08-01) : symbole + chance, pour choisir en connaissance
   de cause. `.coin` (50 %) prend un liseré ambré — l'incertitude doit sauter aux yeux ;
   les effets garantis restent discrets. <s> est neutralisé (pas de barré). */
/* PUCE D'ÉTAT — SANS CADRE (2026-08-01, demande admin : « trop gros avec ce carré autour »).
   Le fond + le liseré doublaient la hauteur de la ligne d'attaque et attiraient plus l'œil
   que le nom de l'attaque. La COULEUR seule porte désormais l'information : ambre = pari
   (pile ou face), gris clair = effet garanti. Plus léger, et l'écart reste immédiat. */
:where(#bbRoot, .bb-skin) .cardatks .atk-eff{ flex:0 0 auto; text-decoration:none; margin:0 3px; padding:0;
  font-size:.62em; font-weight:900; letter-spacing:-.02em; white-space:nowrap;
  background:none; color:#c9d4ea; font-variant-numeric:tabular-nums;
  text-shadow:0 1px 2px #000 }
:where(#bbRoot, .bb-skin) .cardatks .atk-eff.coin{ color:#ffc76b; text-shadow:0 0 5px rgba(255,183,77,.5), 0 1px 2px #000 }
:where(#bbRoot, .bb-skin) .card.back{ background:repeating-linear-gradient(45deg,rgba(150,110,255,.28) 0 7px,transparent 7px 14px),linear-gradient(160deg,#2a2f5e,#141a38);
  border-color:rgba(170,140,255,.5); display:flex;align-items:center;justify-content:center;color:rgba(200,180,255,.65);font-size:1.3rem}

/* ============================================================
   ✨ ULTIME PRÊT — la carte prend l'ÉCLAT d'une apparition d'overlay :
   cadre épais de rareté + double halo qui PULSE (valeurs exactes de l'overlay Central)
   ============================================================ */
:where(#bbRoot, .bb-skin) .card.ultglow{ border-width:3px }
:where(#bbRoot, .bb-skin) .card.ultglow.r-divine{ animation:lpDiv 1.2s ease-in-out infinite }
@keyframes lpDiv{
  0%{   box-shadow:0 0 20px rgba(224,64,251,.7), 0 0 50px rgba(224,64,251,.35); border-color:#e040fb }
  50%{  box-shadow:0 0 28px rgba(179,136,255,.8), 0 0 62px rgba(179,136,255,.42); border-color:#b388ff }
  100%{ box-shadow:0 0 20px rgba(224,64,251,.7), 0 0 50px rgba(224,64,251,.35); border-color:#e040fb } }
:where(#bbRoot, .bb-skin) .card.ultglow.r-celestial{ animation:lpCel 1s ease-in-out infinite }
@keyframes lpCel{
  0%{   box-shadow:0 0 25px rgba(0,229,255,.8), 0 0 60px rgba(0,229,255,.4); border-color:#00e5ff }
  50%{  box-shadow:0 0 35px rgba(132,255,255,.9), 0 0 75px rgba(132,255,255,.45); border-color:#84ffff }
  100%{ box-shadow:0 0 25px rgba(0,229,255,.8), 0 0 60px rgba(0,229,255,.4); border-color:#00e5ff } }
:where(#bbRoot, .bb-skin) .card.ultglow.r-mythic{ animation:lpMyth 1.5s ease-in-out infinite }
@keyframes lpMyth{
  0%{   box-shadow:0 0 20px rgba(255,82,82,.7), 0 0 50px rgba(255,82,82,.35); border-color:#ff5252 }
  50%{  box-shadow:0 0 25px rgba(255,152,0,.7), 0 0 55px rgba(255,152,0,.35); border-color:#ff9800 }
  100%{ box-shadow:0 0 20px rgba(255,82,82,.7), 0 0 50px rgba(255,82,82,.35); border-color:#ff5252 } }

/* JOUABLE / BLOQUÉE */
:where(#bbRoot, .bb-skin) .card.playable{ box-shadow:0 0 0 2px rgba(120,245,175,.8), 0 0 22px -1px rgba(80,240,150,.55), 0 10px 18px -8px #000;
  animation:playPulse 1.6s ease-in-out infinite }
@keyframes playPulse{ 50%{ box-shadow:0 0 0 2px rgba(150,255,200,.95), 0 0 30px 2px rgba(80,240,150,.75), 0 10px 18px -8px #000 } }
:where(#bbRoot, .bb-skin) .card.locked{ filter:grayscale(.95) brightness(.45); opacity:.6; box-shadow:0 6px 14px -8px #000 }
:where(#bbRoot, .bb-skin) .cw.locked .lockicon{ position:absolute; left:50%; top:46%; translate:-50% -50%; z-index:9; font-family:Orbitron,system-ui,sans-serif; font-weight:900; font-size:1.15rem; letter-spacing:.12em; color:#fff; text-shadow:0 2px 6px #000, 0 0 14px rgba(255,80,80,.9) }

/* ============================================================
   🔥 EMBRASEMENT « ULTIME PRÊT » — la carte est entourée de feu
   (base floue + langues de flammes tout autour)
   ============================================================ */
:where(#bbRoot, .bb-skin) .cw.onfire::before{ content:''; position:absolute; inset:-13px; border-radius:20px; z-index:0; pointer-events:none;
  background:
    radial-gradient(55% 70% at 15% 100%, rgba(255,110,0,.95), transparent 62%),
    radial-gradient(55% 78% at 50% 100%, rgba(255,190,50,1), transparent 64%),
    radial-gradient(55% 70% at 85% 100%, rgba(255,110,0,.95), transparent 62%),
    radial-gradient(45% 60% at 0% 55%, rgba(255,140,0,.8), transparent 60%),
    radial-gradient(45% 60% at 100% 55%, rgba(255,140,0,.8), transparent 60%),
    radial-gradient(70% 45% at 50% 0%, rgba(255,120,0,.7), transparent 62%);
  filter:blur(9px); animation:fireBreath 1.05s ease-in-out infinite alternate }
@keyframes fireBreath{ from{ transform:scale(1) translateY(0); opacity:.85 } to{ transform:scale(1.045) translateY(-3px); opacity:1 } }
/* langues de flammes qui lèchent la carte */
:where(#bbRoot, .bb-skin) .fire{ position:absolute; inset:-13px; z-index:1; pointer-events:none }
:where(#bbRoot, .bb-skin) .fire i{ position:absolute; width:16px; height:24px;
  background:radial-gradient(ellipse at 50% 82%, #fffbe6 0%, #ffd54f 24%, #ff9800 54%, #ff3d00 80%, transparent 93%);
  border-radius:50% 50% 50% 50%/72% 72% 28% 28%;
  filter:blur(1.2px); animation:tongue 1s ease-in-out infinite }
@keyframes tongue{ 0%{ transform:translateY(8px) scaleY(.6) scaleX(.95); opacity:.15 }
  35%{ opacity:1 } 100%{ transform:translateY(-22px) scaleY(1.35) scaleX(.6); opacity:0 } }

/* ============================================================
   😴 ÉTOURDIE — proche du sommeil : Zzz qui montent, carte assoupie
   ============================================================ */
:where(#bbRoot, .bb-skin) .aura{ position:absolute; inset:-14px; pointer-events:none; z-index:7 }
:where(#bbRoot, .bb-skin) .aura i{ position:absolute; display:block }
:where(#bbRoot, .bb-skin) .aura.sleep i{ font-size:15px; font-weight:900; font-style:normal; color:#dbe7ff; opacity:0;
  text-shadow:0 0 10px rgba(150,190,255,.95), 0 2px 3px #000; animation:zzz 3.4s ease-in-out infinite }
@keyframes zzz{ 0%{ opacity:0; transform:translate(0,10px) scale(.6) rotate(-8deg) }
  22%{ opacity:1 } 100%{ opacity:0; transform:translate(16px,-30px) scale(1.15) rotate(10deg) } }
/* la carte "dodeline" doucement + se ternit (elle dort, elle ne joue pas) */
:where(#bbRoot, .bb-skin) .card.asleep{ filter:saturate(.55) brightness(.82); animation:sway 3.4s ease-in-out infinite }
@keyframes sway{ 0%,100%{ transform:rotate(0deg) } 50%{ transform:rotate(-1.4deg) } }

/* ============================================================
   🌀 ÉTOURDIE (STUN) — spirales qui tournent autour de la carte
   ============================================================ */
/* les spirales restent DANS la carte (inset:0) pour ne pas déborder sur les voisines */
:where(#bbRoot, .bb-skin) .aura.stun{ inset:0 }
:where(#bbRoot, .bb-skin) .aura.stun i{ font-size:15px; font-style:normal; color:#d3b4ff; opacity:.95;
  text-shadow:0 0 10px rgba(185,130,255,.95), 0 2px 3px #000;
  animation:spin 1.5s linear infinite }
@keyframes spin{ from{ transform:rotate(0deg) } to{ transform:rotate(360deg) } }
/* la carte ne bouge PAS en continu : petite secousse de rappel toutes les ~4 s */
:where(#bbRoot, .bb-skin) .card.stunned{ filter:saturate(.75) brightness(.92); animation:wobble 4s ease-in-out infinite }
@keyframes wobble{ 0%,72%,100%{ transform:rotate(0deg) }
  76%{ transform:rotate(-2deg) } 80%{ transform:rotate(2deg) }
  84%{ transform:rotate(-1.3deg) } 88%{ transform:rotate(1.3deg) } 92%{ transform:rotate(0deg) } }

/* ============================================================
   💧 EMPREINTE ÉLÉMENTAIRE — vraies gouttes d'eau
   ============================================================ */
:where(#bbRoot, .bb-skin) .aura.mark i{ width:13px; height:13px;
  border-radius:50% 50% 50% 0;   /* goutte pointue */
  background:radial-gradient(circle at 34% 30%, rgba(255,255,255,.98) 0%, rgba(190,235,255,.95) 18%,
    var(--mk,#29b6f6) 52%, color-mix(in srgb, var(--mk,#29b6f6) 55%, #000) 92%);
  box-shadow:inset -2px -2px 4px rgba(0,0,0,.28), 0 0 9px color-mix(in srgb,var(--mk,#29b6f6) 75%, transparent);
  animation:drop 2.4s ease-in-out infinite }
/* l'empreinte est un effet NÉGATIF → les gouttes RUISSELLENT vers le bas */
@keyframes drop{ 0%{ opacity:0; transform:translateY(-20px) rotate(-45deg) scale(.55) }
  28%{ opacity:1 } 100%{ opacity:0; transform:translateY(24px) rotate(-45deg) scale(1.05) } }

/* 🔥 BRÛLURE — c'est un MALUS, donc ça DESCEND : braises qui tombent (pas un embrasement) */
:where(#bbRoot, .bb-skin) .aura.burn i{ width:7px; height:8px; top:6px;
  border-radius:50% 50% 50% 50%/60% 60% 40% 40%;
  background:radial-gradient(circle at 45% 35%, #ffd08a, #ff6d00 45%, #b71c1c 82%, transparent 94%);
  box-shadow:0 0 6px rgba(255,90,0,.65); animation:emberFall 1.5s ease-in infinite }
@keyframes emberFall{ 0%{ transform:translateY(-10px) scale(.5); opacity:0 } 25%{ opacity:1 }
  100%{ transform:translateY(26px) scale(.85); opacity:0 } }

/* ===== BARRE D'ACTIONS ===== */
:where(#bbRoot, .bb-skin) .actions{ display:flex; gap:10px; flex-wrap:wrap; justify-content:center; padding:6px 14px 22px; max-width:900px; margin:0 auto }
:where(#bbRoot, .bb-skin) .atk{ position:relative; flex:1 1 210px; max-width:270px; text-align:left; cursor:pointer; border-radius:12px;
  padding:9px 13px 9px 42px; color:#fff;
  background:linear-gradient(135deg, color-mix(in srgb,var(--ael) 34%,#161f38), #111a30);
  border:1px solid color-mix(in srgb,var(--ael) 65%, transparent) }
:where(#bbRoot, .bb-skin) .atk .pip{ position:absolute; left:11px; top:50%; translate:0 -50%; width:24px;height:24px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;font-size:12px;
  background:radial-gradient(circle at 35% 30%, color-mix(in srgb,var(--ael) 75%,#fff), color-mix(in srgb,var(--ael) 85%,#000)) }
:where(#bbRoot, .bb-skin) .atk .an{ display:block; font-weight:800; font-size:.86rem }
:where(#bbRoot, .bb-skin) .atk .ad{ display:block; font-size:.68rem; color:#b9c6e6 }
:where(#bbRoot, .bb-skin) .atk .reac{ display:block; font-size:.64rem; font-weight:800; color:#ffd76a; margin-top:1px }
:where(#bbRoot, .bb-skin) .ultbtn{ cursor:pointer; border-radius:12px; padding:9px 20px; font-weight:900; color:#3a2a00;
  background:linear-gradient(180deg,#ffe07a,#ffb300); border:1px solid #fff3b0;
  box-shadow:0 0 20px -3px rgba(255,193,0,.75); animation:ultGlow 1.1s ease-in-out infinite }
@keyframes ultGlow{ 50%{ box-shadow:0 0 30px 0 rgba(255,193,0,.95) } }
:where(#bbRoot, .bb-skin) .ultbtn small{ display:block; font-size:.62rem; font-weight:700; opacity:.75 }
:where(#bbRoot, .bb-skin) .giveup{ cursor:pointer; border-radius:12px; padding:9px 15px; font-weight:700; font-size:.8rem;
  color:#ffb4b4; background:rgba(50,18,22,.7); border:1px solid rgba(255,120,120,.35) }
:where(#bbRoot, .bb-skin) .legend{ max-width:900px; margin:0 auto 30px; padding:0 16px; display:flex; gap:14px; flex-wrap:wrap; font-size:.72rem; color:#9aa3c0 }
:where(#bbRoot, .bb-skin) .legend b{ color:#dfe6ff }

/* ANIMATIONS DE COMBAT */
:where(#bbRoot, .bb-skin) .lungeUp{ animation:lungeUp .5s cubic-bezier(.3,-.4,.3,1.4) }
@keyframes lungeUp{ 40%{transform:translateY(-30px) scale(1.05)} 100%{transform:none} }
:where(#bbRoot, .bb-skin) .hit{ animation:hitShake .42s ease }
@keyframes hitShake{ 15%{transform:translateX(-7px)} 30%{transform:translateX(7px)} 45%{transform:translateX(-5px)} 60%{transform:translateX(5px)} 100%{transform:none} }
:where(#bbRoot, .bb-skin) .card .flash{ position:absolute; inset:0; z-index:5; background:radial-gradient(circle,rgba(255,80,80,.85),transparent 65%); opacity:0; pointer-events:none }
:where(#bbRoot, .bb-skin) .card.hit .flash{ animation:flashFade .42s ease }
@keyframes flashFade{ 0%{opacity:.9} 100%{opacity:0} }
:where(#bbRoot, .bb-skin) .ko{ animation:koFade .8s ease forwards }
@keyframes koFade{ to{opacity:.32; filter:grayscale(1) brightness(.5); transform:rotate(-5deg) scale(.94)} }
:where(#bbRoot, .bb-skin) .enter{ animation:enterCard .65s cubic-bezier(.2,.9,.3,1.3) }
@keyframes enterCard{ 0%{opacity:0; transform:translateY(38px) scale(.8)} 60%{transform:translateY(-5px) scale(1.04)} 100%{opacity:1; transform:none} }
:where(#bbRoot, .bb-skin) .dmg{ position:absolute; left:50%; top:30%; translate:-50% 0; z-index:9; font-weight:900; font-size:1.6rem; color:#fff;
  text-shadow:0 2px 0 #000, 0 0 12px rgba(255,90,90,.95); animation:dmgFloat 1.1s ease-out forwards; pointer-events:none }
@keyframes dmgFloat{ 0%{opacity:0;transform:translateY(8px) scale(.6)} 25%{opacity:1;transform:translateY(-6px) scale(1.2)} 100%{opacity:0;transform:translateY(-46px) scale(.95)} }
:where(#bbRoot, .bb-skin) .rarpop{ position:absolute; left:50%; top:50%; translate:-50% -50%; z-index:12; text-align:center; pointer-events:none; animation:rarPop 2.2s ease forwards }
:where(#bbRoot, .bb-skin) .rarpop b{ display:block; font-size:.9rem; font-weight:900; letter-spacing:.2em; text-transform:uppercase; color:var(--rc,#fff); text-shadow:0 0 14px var(--rc,#fff), 0 2px 4px #000 }
:where(#bbRoot, .bb-skin) .rarpop i{ display:block; font-style:normal; font-size:.58rem; color:#fff; opacity:.85 }
@keyframes rarPop{ 0%{opacity:0;transform:translate(-50%,-50%) scale(.5)} 18%{opacity:1;transform:translate(-50%,-50%) scale(1.08)} 30%{transform:translate(-50%,-50%) scale(1)} 80%{opacity:1} 100%{opacity:0;transform:translate(-50%,-58%) scale(1)} }

/* ============================================================
   AJOUTS PROPRES À L'ARÈNE (hors maquette)
   ============================================================ */
/* le conteneur du plateau ne doit plus imposer son ancien décor */
#bbRoot.bb{ background:none; border:0; padding:0; overflow:visible; display:block }
:where(#bbRoot, .bb-skin) .scene{ perspective:2800px; perspective-origin:50% 42%; padding:8px 6px 10px; display:flex; justify-content:center }
:where(#bbRoot, .bb-skin) .half{ position:relative }

/* EMPLACEMENT CARTE MAÎTRESSE — haut-gauche de chaque tapis (spec COMBAT-MAITRESSE.md) */
:where(#bbRoot, .bb-skin) .masterslot{ position:absolute; top:10px; left:12px; z-index:6 }
:where(#bbRoot, .bb-skin) .ms-empty{ width:74px; aspect-ratio:3/4.35; border-radius:9px; display:flex; flex-direction:column;
  align-items:center; justify-content:center; gap:3px; font-size:1rem; color:rgba(200,215,255,.35);
  border:1.5px dashed rgba(160,190,255,.30); background:rgba(10,14,28,.35) }
:where(#bbRoot, .bb-skin) .ms-empty span{ font-size:.4rem; font-weight:800; letter-spacing:.12em }

/* repli quand l'illustration n'est pas dispo */
:where(#bbRoot, .bb-skin) .card .artfb{ position:absolute; inset:0; z-index:0; display:flex; align-items:center; justify-content:center;
  font-family:'Orbitron',system-ui,sans-serif; font-weight:800; font-size:2rem;
  color:color-mix(in srgb, var(--rc,#888) 70%, #fff);
  background:linear-gradient(135deg, color-mix(in srgb, var(--elc,#888) 30%, #141a2e), #0b0f1b) }
:where(#bbRoot, .bb-skin) .card img{ z-index:0 }
:where(#bbRoot, .bb-skin) .card .crown{ position:absolute; top:-9px; left:50%; transform:translateX(-50%); z-index:5; font-size:1.05rem;
  filter:drop-shadow(0 2px 5px rgba(0,0,0,.85)) }

/* brillance d'Ultime par défaut (raretés sans pulsation dédiée) */
:where(#bbRoot, .bb-skin) .card.ultglow{ border-width:3px; animation:lpGeneric 1.4s ease-in-out infinite }
@keyframes lpGeneric{
  0%,100%{ box-shadow:0 0 18px color-mix(in srgb,var(--rc,#fff) 65%,transparent), 0 0 44px color-mix(in srgb,var(--rc,#fff) 30%,transparent) }
  50%    { box-shadow:0 0 26px color-mix(in srgb,var(--rc,#fff) 85%,transparent), 0 0 58px color-mix(in srgb,var(--rc,#fff) 42%,transparent) } }

/* bandeau de tour : bbPaintBanner réécrit className -> on style .bb-banner directement */
:where(#bbRoot, .bb-skin) #bbBanner.bb-banner{ position:relative; z-index:5; display:flex; align-items:center; justify-content:center;
  gap:10px; padding:6px 12px; margin:0; border-radius:0; min-width:0; font-size:.82rem; font-weight:900;
  background:linear-gradient(90deg,transparent,rgba(20,30,60,.92),transparent);
  border-top:1px solid rgba(160,200,255,.35); border-bottom:1px solid rgba(160,200,255,.35);
  box-shadow:0 0 20px rgba(120,170,255,.3) }

/* barre d'actions sous le plateau */
:where(#bbRoot, .bb-skin) #bbActions{ display:flex; gap:10px; flex-wrap:wrap; justify-content:center; padding:8px 14px 24px; max-width:900px; margin:0 auto }

/* ============================================================
   CORRECTIFS retour admin
   ============================================================ */

/* 1) EMPREINTE = emoji de l'ÉLÉMENT qui tombe (plus de « goutte d'eau jaune ») */
:where(#bbRoot, .bb-skin) .aura.mark i{ width:auto; height:auto; border-radius:0; background:none; box-shadow:none;
  font-size:16px; line-height:1; font-style:normal;
  text-shadow:0 0 9px var(--mk,#29b6f6), 0 0 18px var(--mk,#29b6f6), 0 1px 3px #000;
  animation:markFall 2.4s ease-in infinite }
@keyframes markFall{ 0%{ opacity:0; transform:translateY(-18px) scale(.55) } 28%{ opacity:1 }
  100%{ opacity:0; transform:translateY(24px) scale(1.05) } }

/* 2) CHIFFRES DE DÉGÂTS — gros, nets, au-dessus de la carte */
#bbRoot .bb-fx{ position:absolute; inset:0; z-index:20; pointer-events:none; overflow:visible }

/* ═══ ILLUSTRATION D'ÉLÉMENT À L'IMPACT (2026-08-06) ══════════════════════════════
   L'`<img>` 256 px que `bbImpact` glisse DANS `.bb-impact`. Le corps de `.bb-impact`
   (anneau, emoji, teinte `--ic`) vit dans les feuilles d'HÔTE — dex.css et
   combat-arena.css — et n'est pas dupliqué ici : on ne pose que le calque image, dans
   la feuille PARTAGÉE, pour que les deux hôtes le reçoivent d'un seul geste.
   `has-elart` n'apparaît qu'au `load` réel : sans les fichiers, ces règles dorment et
   l'emoji d'impact reste seul, exactement comme avant.
   ⚠️ `animation:none` sur le `::after` n'est PAS décoratif : `.bb-impact::after` porte
   `animation:bbImpactEmo … forwards`, et une animation écrase une simple déclaration
   `opacity`. Sans couper l'animation, l'emoji resterait visible SOUS l'illustration.
   Le `content:''` évite en prime de garder un glyphe dans l'arbre d'accessibilité.
   Pas de `mix-blend-mode` : ces planches ont un fond TRANSPARENT et des couleurs déjà
   saturées — en `screen` elles blanchissaient sur un art clair (essayé, abandonné).

   ⚠️ CENTRAGE EXPLICITE (`left/top 50 %` + `translate(-50 %,-50 %)` dans CHAQUE image
   clé). Même piège que les pastilles : `.card img` impose `inset:0` à tout `<img>` de la
   carte. Avec une largeur de 78 % et les quatre `inset` à zéro, la boîte est sur-
   contrainte — en LTR c'est `left` qui gagne — et l'illustration se collait en HAUT À
   GAUCHE de l'anneau. Mesuré avant le correctif : 3,6 px à gauche contre 22,8 px à
   droite, 5 px en haut contre 56,9 px EN BAS. Le coup de feu partait dans le coin au
   lieu d'éclater au point d'impact. `right/bottom:auto` lève la sur-contrainte. */
#bbRoot .bb-impact .bb-elart{ position:absolute; left:50%; top:50%; right:auto; bottom:auto;
  width:78%; max-width:112px; height:auto;
  object-fit:contain; opacity:0; pointer-events:none;
  filter:drop-shadow(0 0 9px var(--ic,#fff)) drop-shadow(0 2px 4px rgba(0,0,0,.75));
  animation:bbElArtHit .56s cubic-bezier(.2,.9,.3,1) forwards }
#bbRoot .bb-impact.has-elart::after{ animation:none; opacity:0; content:'' }
@keyframes bbElArtHit{
  0%   { opacity:0;   transform:translate(-50%,-50%) scale(.42) rotate(-9deg) }
  26%  { opacity:.98; transform:translate(-50%,-50%) scale(1.08) rotate(0deg) }
  60%  { opacity:.85; transform:translate(-50%,-50%) scale(1) }
  100% { opacity:0;   transform:translate(-50%,-50%) scale(1.2) } }

/* ═══ ANIMATIONS D'EFFET (2026-08-06) — les 6 planches WebP de `bbEffetAnim` ═════════
   burn · stun · sleep · crit · shield · defdown. 192×192, 25 images, 750 ms, LOOP=1.

   ⚠️ CES PLANCHES ONT UN FOND NOIR, PAS TRANSPARENT. Sans `mix-blend-mode:screen` on
   voit un CARRÉ NOIR posé sur la carte. En `screen`, le noir est l'élément neutre
   (résultat = fond) : il disparaît, et seules les lueurs s'ajoutent à l'illustration.
   C'est aussi pourquoi elles ne peuvent PAS vivre dans `.bb-fx` comme `.bb-elart` :
   `.bb-fx` porte `z-index:20`, donc contexte d'empilement, donc GROUPE DE FUSION ISOLÉ —
   le fond de composition y est transparent et `screen` ne retire alors plus rien. Fille
   directe de `.card` (`position:relative; z-index:2`, l. 133), la fusion se fait contre
   l'illustration de la carte : c'est le rendu voulu.
   (Différence assumée avec `.bb-elart`, dont les planches d'ÉLÉMENT ont, elles, un fond
   transparent et blanchissaient en `screen` — essayé, abandonné, cf. plus haut.)

   LES CHIFFRES RESTENT INTOUCHÉS : cette couche vit DANS la carte (`.card`, z-index 2
   sous `.cw`) alors que les flottants de dégâts vivent dans `.bb-fx-out`, SŒUR de la
   carte en z-index 30. Aucune valeur de `.bb-float` n'est modifiée par ce bloc.

   ⚠️ MÊME PIÈGE DE SUR-CONTRAINTE que `.bb-elart` : `.card img` impose `inset:0` +
   `width/height:100%` à tout `<img>` de la carte (et `z-index:0`, plus bas). D'où
   `right/bottom:auto` et `height:auto` — sans eux la planche se colle en haut à gauche
   et s'étire. `opacity:0` par défaut, `.on` posé au `load` réel : sans les fichiers, rien
   ne s'affiche et le plateau garde son rendu actuel.

   ⚠️ SÉLECTEUR VOLONTAIREMENT LARGE (`#bbRoot .bb-fxanim`, pas `#bbRoot .card .bb-fxanim`).
   Aujourd'hui TOUS les appelants de `bbEffetAnim` passent une `.card` (bbCardEl /
   bbNamedEl / bbActiveEl / bbActiveOrAnyEl n'en rendent pas d'autre — vérifié). Mais
   `.ms-card img` et `.bi-card img` posent, eux aussi, `position:absolute; inset:0;
   width/height:100%` : le jour où une planche atterrirait sur une carte de MAÎTRESSE ou
   sur la fiche d'inspection, un sélecteur trop étroit la laisserait s'étirer SANS
   `mix-blend-mode` — c'est-à-dire un CARRÉ NOIR plein cadre. Spécificité (1,0,1) : elle
   passe devant `.card img` / `.ms-card img` (0,1,1) partout, y compris dans la copie
   cloisonnée du Dex où `:where()` ne pèse rien. */
#bbRoot .bb-fxanim{ position:absolute; left:50%; top:50%; right:auto; bottom:auto;
  width:112%; max-width:none; height:auto; z-index:22;
  transform:translate(-50%,-50%); transform-origin:50% 50%;
  object-fit:contain; pointer-events:none; opacity:0;
  mix-blend-mode:screen }
/* Le fondu d'entrée/sortie est porté par le CSS (la planche, elle, ne sait pas s'éteindre :
   sa dernière image reste à l'écran jusqu'au retrait). 750 ms de planche →
   apparition immédiate, extinction sur les 150 dernières millisecondes.
   ⚠️ CETTE ANIMATION ET LE RETRAIT JS DÉMARRENT AU MÊME INSTANT — la classe `.on` et le
   minuteur de 900 ms sont posés TOUS DEUX dans `onload` (cf. bbEffetAnim). Ils étaient
   désynchronisés : le minuteur partait de la CRÉATION de l'`<img>`, donc un téléchargement
   de 600 ms (mesuré : première occurrence d'un effet, 39 à 154 Ko) coupait la planche à
   301 ms sur 750 et supprimait le fondu de sortie. Si l'un des deux repart de la création,
   le défaut revient. */
#bbRoot .bb-fxanim.on{ animation:bbFxAnimVie .9s linear forwards }
@keyframes bbFxAnimVie{
  0%   { opacity:0 }
  6%   { opacity:1 }
  83%  { opacity:1 }
  100% { opacity:0 } }
#bbRoot .bb-float{ position:absolute; left:50%; top:24%; white-space:nowrap; text-align:center;
  animation:bbFloatUp 1.2s ease-out forwards }
@keyframes bbFloatUp{
  0%   { opacity:0; transform:translate(-50%,10px) scale(.55) rotate(var(--flip,0deg)) }
  20%  { opacity:1; transform:translate(-50%,-8px) scale(1.22) rotate(var(--flip,0deg)) }
  35%  { transform:translate(-50%,-12px) scale(1) rotate(var(--flip,0deg)) }
  100% { opacity:0; transform:translate(-50%,-58px) scale(.95) rotate(var(--flip,0deg)) } }
#bbRoot .bb-dmg{ display:block; font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:1.8rem;
  color:#fff; text-shadow:0 2px 0 #000, 0 0 14px rgba(255,80,80,1), 0 0 32px rgba(255,50,50,.85) }
#bbRoot .bb-dmg.big{ font-size:2.4rem }
#bbRoot .bb-crit{ display:block; font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:.92rem;
  letter-spacing:.14em; color:#ffd24a; text-shadow:0 2px 5px #000, 0 0 16px #ffd24a }
#bbRoot .bb-adv{ display:block; font-size:.74rem; font-weight:800; text-shadow:0 1px 3px #000 }
#bbRoot .bb-adv.up{ color:#7cf0a0 } #bbRoot .bb-adv.down{ color:#9fb0c8 }
#bbRoot .bb-reaction{ display:block; font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:1.1rem;
  color:#fff3b0; text-shadow:0 0 14px #ffd76a, 0 2px 4px #000 }
#bbRoot .bb-ko{ display:block; font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:1.5rem;
  letter-spacing:.16em; color:#fff; text-shadow:0 2px 6px #000, 0 0 18px rgba(255,60,60,1) }
#bbRoot .bb-eff{ display:block; font-size:1.15rem; text-shadow:0 1px 3px #000 }
#bbRoot .bb-tag-txt{ display:block; font-size:.72rem; font-weight:700; color:#cfe0ff; text-shadow:0 1px 3px #000 }

/* 3) plus d'air entre la carte au front et le banc */
:where(#bbRoot, .bb-skin) .half .row + .row{ margin-top:20px }

/* ============================================================
   ANIMATIONS DE COMBAT — le JS pose des classes `bb-*` (héritées du site)
   mais la nouvelle carte s'appelle `.card` : il faut les re-cibler ici,
   sinon attaques / impacts / K.O. ne s'animent pas du tout.
   ============================================================ */
:where(#bbRoot, .bb-skin) .card.bb-lunge-up{ animation:cardLungeUp .45s cubic-bezier(.3,-.4,.3,1.4) }
:where(#bbRoot, .bb-skin) .card.bb-lunge-down{ animation:cardLungeDown .45s cubic-bezier(.3,-.4,.3,1.4) }
@keyframes cardLungeUp{ 40%{ transform:translateY(-30px) scale(1.06) } 100%{ transform:none } }
@keyframes cardLungeDown{ 40%{ transform:translateY(30px) scale(1.06) } 100%{ transform:none } }

:where(#bbRoot, .bb-skin) .card.bb-hit{ animation:cardHit .4s ease }
@keyframes cardHit{ 15%{ transform:translateX(-7px) } 30%{ transform:translateX(7px) }
  45%{ transform:translateX(-5px) } 60%{ transform:translateX(5px) } 100%{ transform:none } }
/* éclair rouge d'impact */
:where(#bbRoot, .bb-skin) .card.bb-hit .flash{ animation:cardFlash .4s ease }
@keyframes cardFlash{ 0%{ opacity:.85 } 100%{ opacity:0 } }

/* K.O. */
:where(#bbRoot, .bb-skin) .card.bb-faint{ opacity:.42; filter:grayscale(.95) brightness(.5); transform:rotate(-4deg) scale(.96);
  transition:opacity .5s, filter .5s, transform .5s }
/* entrée en jeu (switch / relève après K.O.) */
:where(#bbRoot, .bb-skin) .card.bb-flip, :where(#bbRoot, .bb-skin) .card.bb-switch-in{ animation:cardEnter .6s cubic-bezier(.2,.9,.3,1.3) }
@keyframes cardEnter{ 0%{ opacity:0; transform:translateY(34px) scale(.82) }
  60%{ transform:translateY(-5px) scale(1.04) } 100%{ opacity:1; transform:none } }
:where(#bbRoot, .bb-skin) .card.bb-revive{ animation:cardRevive .9s ease }
@keyframes cardRevive{ 0%{ filter:brightness(2.2) saturate(1.6) } 100%{ filter:none } }

/* « à qui le tour » (le JS pose bb-turn, la maquette utilisait .turn) */
:where(#bbRoot, .bb-skin) .card.bb-turn, :where(#bbRoot, .bb-skin) .card.turn{ outline:2px solid #ffd24a; outline-offset:2px }
/* carte du banc cliquable pour l'échange */
:where(#bbRoot, .bb-skin) .card.bb-switchable{ cursor:pointer }
:where(#bbRoot, .bb-skin) .card.bb-switchable:hover{ filter:brightness(1.12) }

/* ============================================================
   PASSE « retour 1080p » — lisibilité, orientation, tour
   ============================================================ */

/* 1) TOUR = le TAPIS s'éclaire (plus la carte). Discret mais évident. */
:where(#bbRoot, .bb-skin) .half.turnactive.me{  box-shadow: inset 0 0 70px -18px rgba(120,200,255,.85) }
:where(#bbRoot, .bb-skin) .half.turnactive.opp{ box-shadow: inset 0 0 70px -18px rgba(255,120,150,.85) }
/* ⚠️ SUPPRIMÉ (2026-07-23) : un ancien liseré de 3 px qui utilisait `.half::after`.
   Comme `::after` porte désormais le LIQUIDE de la jauge d'Élan, cette règle — plus
   spécifique — imposait `height:3px` et écrasait le liquide DU CÔTÉ DU JOUEUR ACTIF.
   D'où une jauge qui « ne se remplissait pas ». L'indicateur de tour est l'anneau
   lumineux (`.half.turnactive` box-shadow) : ce liseré ne servait plus. */

/* 2) CARTE JOUABLE : halo à la COULEUR DE SA RARETÉ (et non plus un vert générique).
      N'est posé que sur MES cartes → l'adversaire ne sait pas ce que je peux jouer. */
:where(#bbRoot, .bb-skin) .card.playable{ animation:none;
  box-shadow:0 0 0 2px var(--rc,#fff), 0 0 20px -2px var(--rc,#fff), 0 10px 18px -8px #000 }
:where(#bbRoot, .bb-skin) .card.active.playable{ box-shadow:0 0 0 2.5px var(--rc,#fff), 0 0 28px -2px var(--rc,#fff), 0 18px 26px -10px #000 }

/* 3) TENIR DANS L'ÉCRAN : tailles proportionnelles à la hauteur dispo */
:where(#bbRoot, .bb-skin) .card{ width:clamp(84px, 9.2vh, 130px) }
:where(#bbRoot, .bb-skin) .card.active{ width:clamp(104px, 11.6vh, 160px) }
:where(#bbRoot, .bb-skin) .half{ padding:8px 18px 10px; gap:5px }
:where(#bbRoot, .bb-skin) .half .row + .row{ margin-top:clamp(6px, 1.2vh, 16px) }
:where(#bbRoot, .bb-skin) .elan{ height:auto }
:where(#bbRoot, .bb-skin) .elan .track{ height:8px }
:where(#bbRoot, .bb-skin) .mat{ padding:0 }

/* 4) LES CARTES ADVERSES SONT TOURNÉES VERS LEUR PROPRIÉTAIRE (convention plateau) */
:where(#bbRoot, .bb-skin) .half.opp .cw{ transform:rotate(180deg) }
/* …mais les chiffres de dégâts doivent rester lisibles pour nous */
:where(#bbRoot, .bb-skin) .half.opp .bb-float{ --flip:180deg }

/* 5) EMPLACEMENT MAÎTRESSE : vraie taille de carte + placé côté centre, en miroir */
:where(#bbRoot, .bb-skin) .masterslot{ position:absolute; z-index:6 }
:where(#bbRoot, .bb-skin) .half.me  .masterslot{ top:10px;    left:14px }
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ bottom:10px; left:14px; transform:rotate(180deg) }
:where(#bbRoot, .bb-skin) .ms-empty{ width:clamp(84px, 9.2vh, 130px); aspect-ratio:3/4.35; border-radius:10px;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px;
  font-size:1.5rem; color:rgba(200,215,255,.4);
  border:2px dashed rgba(160,190,255,.35); background:rgba(10,14,28,.45) }
:where(#bbRoot, .bb-skin) .ms-empty span{ font-size:.5rem; font-weight:800; letter-spacing:.14em }

/* 6) FICHE DE CARTE : barre latérale À GAUCHE (au lieu d'une fenêtre au centre) */
/* Panneau FLOTTANT : ni plein écran ni pleine hauteur — on doit continuer à voir le combat.
   Pas de voile sombre non plus, il assombrissait tout le plateau pour rien. */
:where(#bbRoot, .bb-skin) .bb-inspect{ justify-content:flex-start; align-items:center; background:none; pointer-events:none }
/* ⚠️ FOND + PADDING (2026-07-30) : sans eux le panneau était TRANSPARENT — nom, classe,
   stats et liste d'attaques flottaient à même le tapis, illisibles. Seule la carte (elle,
   habillée) se voyait. */
:where(#bbRoot, .bb-skin) .bb-inspect-card{ pointer-events:auto; width:min(310px,88vw); max-width:none;
  max-height:88vh; overflow-y:auto; margin-left:14px; border-radius:16px;
  padding:14px 14px 12px; text-align:center;
  background:linear-gradient(180deg, rgba(16,22,44,.97), rgba(9,12,26,.98));
  border:1px solid rgba(150,180,255,.22);
  box-shadow:0 18px 60px rgba(0,0,0,.6); animation:sideIn .2s ease }
/* Hiérarchie du texte : sans ces règles tout sortait à la même taille, sans respiration. */
:where(#bbRoot, .bb-skin) .bb-inspect-name{ font-size:1.02rem; font-weight:800; color:#eaf1ff; line-height:1.25 }
:where(#bbRoot, .bb-skin) .bb-inspect-meta{ font-size:.68rem; color:#9fb0d0; margin-top:3px; letter-spacing:.02em }
:where(#bbRoot, .bb-skin) .bb-inspect-quote{ font-size:.68rem; font-style:italic; color:#8f9fbe; margin-top:6px; line-height:1.4 }
:where(#bbRoot, .bb-skin) .bb-inspect-stats{ display:flex; justify-content:center; gap:12px; margin-top:8px;
  font-size:.66rem; color:#c3cee6 }
:where(#bbRoot, .bb-skin) .bb-inspect-stats b{ font-size:.82rem; color:#fff; margin-left:3px; font-variant-numeric:tabular-nums }
:where(#bbRoot, .bb-skin) .bb-inspect-head{ margin:12px 0 6px; font-size:.6rem; font-weight:800; letter-spacing:.14em;
  text-transform:uppercase; color:#7f8fb0 }
:where(#bbRoot, .bb-skin) .bb-inspect-switch, :where(#bbRoot, .bb-skin) .bb-inspect-close{
  width:100%; margin-top:8px; padding:8px 12px; border-radius:10px; cursor:pointer;
  font-size:.76rem; font-weight:700;
  background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.20); color:#dbe4f7 }
:where(#bbRoot, .bb-skin) .bb-inspect-switch{ border-color:rgba(122,212,255,.55); color:#bfe9ff }
:where(#bbRoot, .bb-skin) .bb-inspect-switch:disabled{ opacity:.45; cursor:not-allowed }
:where(#bbRoot, .bb-skin) .bb-inspect-switch:not(:disabled):hover, :where(#bbRoot, .bb-skin) .bb-inspect-close:hover{ background:rgba(255,255,255,.12) }
@keyframes sideIn{ from{ transform:translateX(-24px); opacity:0 } to{ transform:none; opacity:1 } }
/* la VRAIE carte, à plat (hors du tapis : aucune perspective ne s'applique ici) */
:where(#bbRoot, .bb-skin) .bb-inspect-real{ display:flex; justify-content:center; margin:2px 0 8px }
:where(#bbRoot, .bb-skin) .bb-inspect-real .cw{ transform:none }
:where(#bbRoot, .bb-skin) .bb-inspect-real .card{ width:150px; cursor:default }
:where(#bbRoot, .bb-skin) .bb-inspect-real .card.active{ animation:none }
/* description d'effet sous chaque attaque */
:where(#bbRoot, .bb-skin) .bb-inspect-atk{ flex-wrap:wrap }
:where(#bbRoot, .bb-skin) .bb-inspect-atk .ad{ flex:0 0 100%; font-size:.63rem; color:#9fb0d0; margin-top:2px }
:where(#bbRoot, .bb-skin) .bb-inspect-badges{ display:flex; flex-wrap:wrap; gap:5px; justify-content:center; margin:8px 0 4px }
:where(#bbRoot, .bb-skin) .bb-inspect-badges span{ font-size:.62rem; font-weight:800; padding:3px 8px; border-radius:99px;
  background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.18) }
:where(#bbRoot, .bb-skin) .bb-inspect-badges .bad{ border-color:#ff7043; color:#ffbfa8 }
:where(#bbRoot, .bb-skin) .bb-inspect-badges .good{ border-color:#5cf0a0; color:#b6ffd6 }

/* ---- CORRECTIFS mise en page (retour captures 1080p) ---- */
/* le tapis doit garder de la marge, sinon overflow:hidden COUPE les cartes du banc */
:where(#bbRoot, .bb-skin) .mat{ padding:10px 22px 14px; overflow:visible }
:where(#bbRoot, .bb-skin) .half{ padding:6px 14px 8px }

/* la barre d'actions faisait 216 px : compactée sur une ligne */
:where(#bbRoot, .bb-skin) #bbActions{ display:flex; gap:8px; flex-wrap:wrap; justify-content:center; align-items:center;
  padding:8px 12px 6px; max-width:940px; margin:0 auto }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk{ flex:0 1 220px; max-width:240px; padding:7px 11px }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ font-size:.8rem }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-line, :where(#bbRoot, .bb-skin) #bbActions .bb-atk-eff{ font-size:.62rem }
:where(#bbRoot, .bb-skin) #bbActions .bb-ult{ padding:8px 15px; font-size:.85rem }
:where(#bbRoot, .bb-skin) #bbActions .bb-forfeit{ padding:7px 12px; font-size:.75rem }
/* l'Élan est déjà affiché sur chaque tapis : pas de doublon sous le plateau */
:where(#bbRoot, .bb-skin) #bbActions .bb-elan{ display:none }
:where(#bbRoot, .bb-skin) #bbActions .bb-switch-hint{ font-size:.66rem; flex-basis:100%; text-align:center; margin:0 }
/* pas de vide résiduel sous le plateau */
:where(#bbRoot, .bb-skin) .arena-wrap{ padding-bottom:14px }

/* .scene est en flex : sans ceci, la hauteur posée par fitBoard() ÉTIRE le tapis
   et ses cartes débordent. On laisse le tapis à sa hauteur naturelle. */
:where(#bbRoot, .bb-skin) .scene{ align-items:flex-start }

/* ---- Maîtresse adverse : à SA gauche, donc à NOTRE droite (vrai miroir) ---- */
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:auto; right:14px; bottom:10px; transform:rotate(180deg) }

/* ---- La barre d'attaques ne doit plus POUSSER le plateau ----
   Elle apparaît/disparaît selon le tour : en flux, elle changeait la hauteur et
   faisait sauter la mise à l'échelle. On la superpose au bas du plateau. */
#bbRoot{ position:relative; padding-bottom:104px }   /* = ACTIONS_RESERVE dans combat-arena.html */
/* largeur BORNEE et centree : en pleine largeur d'ecran, l'astuce et « Abandonner »
   partaient hors du plateau, en bas a droite. */
:where(#bbRoot, .bb-skin) #bbActions{ position:absolute; left:50%; transform:translateX(-50%); bottom:0;
  width:min(720px,94vw); height:104px; z-index:30;
  display:flex; align-items:center; justify-content:center; flex-wrap:wrap; gap:7px 10px;
  background:linear-gradient(180deg,rgba(8,10,20,0),rgba(8,10,20,.82) 40%,rgba(8,10,20,.94));
  border-radius:0 0 16px 16px; pointer-events:none }
:where(#bbRoot, .bb-skin) #bbActions > *{ pointer-events:auto }
:where(#bbRoot, .bb-skin) #bbActions:empty{ display:none }

/* ---- MODE OFFICIEL : on masque les commandes de test, il ne reste que le jeu ---- */
body.officiel .arena-bar, body.officiel .arena-title{ display:none }
body.officiel .arena-wrap{ max-width:none; padding:0 }
body.officiel #arenaMount{ margin:0 }
/* cadre 16:9 (ou 9:16 en portrait) comme le vrai jeu */
/* max-width:none -> sans lui, une regle plus specifique bornait le plateau a 980px.
   flex-start -> le centrage vertical laissait ~113px de vide EN HAUT, que fitBoard
   comptait comme place prise : le plateau se reduisait au lieu de grandir. */
body.officiel #bbRoot{ width:100vw; max-width:none; min-height:100vh;
  display:flex; flex-direction:column; justify-content:flex-start; padding-top:8px }
:where(#bbRoot, .bb-skin) .officiel-exit{ position:fixed; top:10px; right:12px; z-index:9999; cursor:pointer; font-size:.72rem;
  padding:6px 11px; border-radius:8px; color:#cdd6f4; background:rgba(20,26,48,.85);
  border:1px solid rgba(255,255,255,.18); opacity:.35; transition:opacity .2s }
:where(#bbRoot, .bb-skin) .officiel-exit:hover{ opacity:1 }

/* l'astuce « clique une carte du banc » prend sa propre ligne, sous les attaques */
:where(#bbRoot, .bb-skin) #bbActions .bb-hint, :where(#bbRoot, .bb-skin) #bbActions .bb-switch-hint{ flex:0 0 100%; text-align:center; margin:0 }

/* ==========================================================================
   MOBILE PORTRAIT (9:16) — approche Pokémon TCG Live
   Principe : on NE réduit PAS le plateau pour le faire tenir (cartes de 9 px).
   On fixe des tailles de cartes LISIBLES, on laisse le tapis déborder sur les
   côtés (il est rogné, comme chez Pokémon) et on aplatit la perspective.
   ========================================================================== */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .scene{ perspective:1600px; perspective-origin:50% 46%; padding:4px 0 6px; overflow:hidden }
  :where(#bbRoot, .bb-skin) .mat{ width:100vw; transform:rotateX(12deg); transform-origin:center 58%;
        border-radius:14px; border-width:1.5px }
  :where(#bbRoot, .bb-skin) .half{ padding:6px 4px 8px; gap:4px }
  :where(#bbRoot, .bb-skin) .half::before{ font-size:1.15rem; letter-spacing:.28em }

  /* cartes : taille FIXE lisible, plus de rétrécissement à l'infini */
  :where(#bbRoot, .bb-skin) .card{ width:84px; border-radius:8px }
  :where(#bbRoot, .bb-skin) .card.active{ width:112px }
  :where(#bbRoot, .bb-skin) .row{ gap:6px }
  :where(#bbRoot, .bb-skin) .card .nm{ font-size:.55rem; bottom:24px }
  :where(#bbRoot, .bb-skin) .card.active .nm{ font-size:.66rem; bottom:27px }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.42rem; bottom:15px; letter-spacing:.09em }
  :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.47rem; bottom:18px }
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.43rem; gap:5px }
  :where(#bbRoot, .bb-skin) .card.active .st{ font-size:.48rem; gap:6px }
  :where(#bbRoot, .bb-skin) .card .el{ width:17px; height:17px; font-size:9px }
  :where(#bbRoot, .bb-skin) .card.active .el{ width:20px; height:20px; font-size:11px }
  :where(#bbRoot, .bb-skin) .card .hp b{ font-size:.62rem } :where(#bbRoot, .bb-skin) .card.active .hp b{ font-size:.76rem }

  /* bandeaux compactés */
  :where(#bbRoot, .bb-skin) .tag{ font-size:.6rem; padding:2px 10px }
  :where(#bbRoot, .bb-skin) .elan{ width:94%; gap:6px }
  :where(#bbRoot, .bb-skin) .elan .track{ height:7px }
  :where(#bbRoot, .bb-skin) .elan .lbl, :where(#bbRoot, .bb-skin) .elan .pct{ font-size:.5rem }
  :where(#bbRoot, .bb-skin) .turnbar{ padding:3px 0; gap:6px }
  :where(#bbRoot, .bb-skin) .turnbar .n{ font-size:.52rem; padding:1px 7px }
  :where(#bbRoot, .bb-skin) .turnbar .msg{ font-size:.66rem }

  /* maîtresse : vignette d'angle, elle ne doit pas voler de la largeur aux cartes */
  :where(#bbRoot, .bb-skin) .masterslot{ transform:scale(.62); transform-origin:top left }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform:rotate(180deg) scale(.62); transform-origin:bottom right }

  /* barre d'actions : pleine largeur, basse, compacte */
  #bbRoot{ padding-bottom:64px }
  :where(#bbRoot, .bb-skin) #bbActions{ width:100vw; height:64px; gap:4px 6px; padding:0 6px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-switch-hint{ font-size:.56rem }

  /* fiche de carte : feuille basse, elle ne recouvre plus le plateau */
  :where(#bbRoot, .bb-skin) .bb-inspect{ align-items:flex-end }
  :where(#bbRoot, .bb-skin) .bb-inspect-card{ margin:0 auto 0; width:100vw; max-height:62vh; border-radius:16px 16px 0 0 }
  :where(#bbRoot, .bb-skin) .bb-inspect-real .card{ width:120px }
}

/* ==========================================================================
   FLANCS — remplir la largeur perdue en 16:9
   Le tapis fait ~1,19:1, un ecran 16:9 fait 1,86:1 : la hauteur etait pleine
   a 93% pendant que 48% de la largeur restait noire. Pseudo + Elan passent
   donc sur les cotes (comme deck/defausse/recompenses chez Pokemon) : on gagne
   ~2 lignes de hauteur ET on occupe les flancs.
   Cote choisi = MIROIR de la maitresse : la mienne a gauche -> mon flanc a
   droite ; celle de l'adversaire a droite -> son flanc a gauche.
   ========================================================================== */
:where(#bbRoot, .bb-skin) .flank{ position:absolute; top:50%; transform:translateY(-50%); z-index:6;
  width:190px; display:flex; flex-direction:column; align-items:center; gap:7px }
:where(#bbRoot, .bb-skin) .half.me  .flank{ right:18px }
:where(#bbRoot, .bb-skin) .half.opp .flank{ left:18px }
:where(#bbRoot, .bb-skin) .flank .elan{ width:100%; gap:6px }
:where(#bbRoot, .bb-skin) .flank .tag{ font-size:.68rem }
/* le tapis doit etre assez large pour loger flanc + cartes + maitresse */
:where(#bbRoot, .bb-skin) .mat{ width:min(1240px,96vw) }

/* en portrait, pas de flancs : on repasse en colonne (la largeur y est deja pleine) */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .flank{ position:static; transform:none; width:94%; margin:0 auto }
  :where(#bbRoot, .bb-skin) .half.me .flank, :where(#bbRoot, .bb-skin) .half.opp .flank{ right:auto; left:auto }
}

/* ==========================================================================
   MENU D'ATTAQUES SUR LE PLATEAU (remplace la barre sous le jeu)
   Clic sur ma carte active -> il s'ouvre au-dessus d'elle ; clic dans le vide -> il se ferme.
   ========================================================================== */
#bbRoot{ padding-bottom:0 }
:where(#bbRoot, .bb-skin) #bbActions{ position:absolute; transform:translate(-50%,-100%); z-index:60;
  width:auto; height:auto; max-width:min(560px,92vw); padding:9px 10px;
  display:none; flex-direction:column; align-items:center; gap:7px;
  background:linear-gradient(180deg,rgba(18,24,46,.97),rgba(10,14,30,.98));
  border:1px solid rgba(150,190,255,.34); border-radius:14px;
  box-shadow:0 18px 46px rgba(0,0,0,.72), 0 0 0 1px rgba(0,0,0,.5) }
:where(#bbRoot, .bb-skin) #bbActions.open{ display:flex }
:where(#bbRoot, .bb-skin) #bbActions::after{ content:""; position:absolute; left:50%; bottom:-8px; transform:translateX(-50%);
  border:8px solid transparent; border-top-color:rgba(150,190,255,.34); border-bottom:0 }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-row{ display:flex; flex-wrap:wrap; gap:7px; justify-content:center }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk{ flex:0 1 auto; max-width:230px }

/* ---- commandes permanentes DANS la barre de tour : son + abandon ---- */
:where(#bbRoot, .bb-skin) .bb-barctl{ position:absolute; right:12px; top:50%; transform:translateY(-50%);
  display:flex; align-items:center; gap:7px }
:where(#bbRoot, .bb-skin) .bb-snd{ cursor:pointer; background:rgba(0,0,0,.35); border:1px solid rgba(255,255,255,.18);
  color:#dfe8ff; border-radius:8px; padding:2px 7px; font-size:.8rem; line-height:1.3 }
:where(#bbRoot, .bb-skin) .bb-vol{ width:74px; accent-color:#7fb2ff; cursor:pointer }
:where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ cursor:pointer; font-size:.66rem; font-weight:700; padding:3px 9px; border-radius:8px;
  color:#ffb4b4; background:rgba(60,20,26,.75); border:1px solid rgba(255,120,120,.4) }

/* ---- cartes PLUS GRANDES et rangees mieux separees ---- */
:where(#bbRoot, .bb-skin) .card{ width:170px }
:where(#bbRoot, .bb-skin) .card.active{ width:208px }
:where(#bbRoot, .bb-skin) .half{ gap:14px }
:where(#bbRoot, .bb-skin) .half.opp .row + .row{ margin-top:6px }
:where(#bbRoot, .bb-skin) .half.me  .row + .row{ margin-top:6px }

/* ---- flancs et maitresse RAPPROCHES du jeu (ils partaient aux extremes) ---- */
:where(#bbRoot, .bb-skin) .half.me  .flank{ right:8% }
:where(#bbRoot, .bb-skin) .half.opp .flank{ left:8% }
:where(#bbRoot, .bb-skin) .half.me  .masterslot{ left:8% }
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:auto; right:8% }

/* ---- une carte qui attaque passe AU-DESSUS de la barre centrale, pas dessous ---- */
:where(#bbRoot, .bb-skin) .row{ z-index:5 }
:where(#bbRoot, .bb-skin) .turnbar{ z-index:4 }

/* Tapis PLUS LARGE : la hauteur est le facteur limitant, donc agrandir le tapis ne coute
   rien en echelle et remplace les bandes NOIRES par du tapis (c'est ce que fait Pokemon).
   Les flancs, poses en %, s'ecartent avec lui. */
:where(#bbRoot, .bb-skin) .mat{ width:min(1600px,96vw) }
:where(#bbRoot, .bb-skin) .half.opp .row + .row{ margin-top:12px }
:where(#bbRoot, .bb-skin) .half.me  .row + .row{ margin-top:12px }

/* ==========================================================================
   DISPOSITION v3 — tapis resserre, infos de tour a GAUCHE, options en menu
   ========================================================================== */
/* Tapis moins large : a 1600px il etait surtout VIDE, et poussait Elan/maitresse
   loin des cartes. On resserre pour que tout soit pres du jeu. */
:where(#bbRoot, .bb-skin) .mat{ width:min(1150px,96vw); background:#0a0e1c; gap:16px }

/* plus de bande pleine largeur entre les deux tapis : juste une couture sombre.
   Les cartes des deux camps ne se touchent pas, sans grand vide au milieu. */
:where(#bbRoot, .bb-skin) .turnbar{ position:absolute; left:14px; top:50%; transform:translateY(-50%);
  z-index:40; display:flex; flex-direction:column; align-items:flex-start; gap:6px;
  padding:10px 13px; width:auto; border:1px solid rgba(160,200,255,.3); border-radius:12px;
  background:linear-gradient(180deg,rgba(16,22,44,.94),rgba(9,13,28,.96));
  box-shadow:0 10px 30px rgba(0,0,0,.55) }
:where(#bbRoot, .bb-skin) .turnbar .bb-turnnum{ font-size:.6rem; letter-spacing:.14em; color:#9fb4dd }
:where(#bbRoot, .bb-skin) .turnbar .bb-turnmsg{ font-weight:900; font-size:.8rem; line-height:1.25; max-width:160px }
:where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ margin-top:2px }

/* CONTOUR DU TAPIS ALLUME du cote de celui qui joue : lisible d'un coup d'oeil */
:where(#bbRoot, .bb-skin) .mat.turn-me{ border-color:#7fd4ff; box-shadow:0 40px 70px -25px #000, 0 0 26px rgba(120,200,255,.55), inset 0 -3px 0 rgba(120,200,255,.5) }
:where(#bbRoot, .bb-skin) .mat.turn-opp{ border-color:#ff8fa8; box-shadow:0 40px 70px -25px #000, 0 0 26px rgba(255,120,150,.45), inset 0 3px 0 rgba(255,140,170,.5) }

/* cartes du banc mieux espacees */
:where(#bbRoot, .bb-skin) .row{ gap:22px }

/* Elan + maitresse RAPPROCHES des cartes (le tapis resserre fait le reste) */
:where(#bbRoot, .bb-skin) .half.me  .flank{ right:14px }
:where(#bbRoot, .bb-skin) .half.opp .flank{ left:14px }
:where(#bbRoot, .bb-skin) .half.me  .masterslot{ left:14px }
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:auto; right:14px }
:where(#bbRoot, .bb-skin) .flank{ width:170px }

/* ---- menu OPTIONS (3 barres) ---- */
:where(#bbRoot, .bb-skin) .bb-menu{ position:absolute; left:12px; top:10px; z-index:70; cursor:pointer;
  width:34px; height:34px; border-radius:9px; font-size:1rem; line-height:1;
  color:#dfe8ff; background:rgba(16,22,44,.9); border:1px solid rgba(255,255,255,.18) }
:where(#bbRoot, .bb-skin) .bb-menu:hover{ background:rgba(30,40,76,.95) }
:where(#bbRoot, .bb-skin) .bb-opts{ position:absolute; left:12px; top:50px; z-index:71; width:238px; padding:11px 12px;
  border-radius:12px; background:linear-gradient(180deg,rgba(18,24,46,.98),rgba(10,14,30,.99));
  border:1px solid rgba(150,190,255,.32); box-shadow:0 18px 46px rgba(0,0,0,.7) }
:where(#bbRoot, .bb-skin) .bb-opts-h{ font-weight:900; font-size:.74rem; letter-spacing:.1em; text-transform:uppercase;
  color:#9fb4dd; margin-bottom:8px }
:where(#bbRoot, .bb-skin) .bb-opt{ display:flex; align-items:center; justify-content:space-between; gap:9px; margin:7px 0; font-size:.74rem }
:where(#bbRoot, .bb-skin) .bb-opt input[type=range]{ width:112px; accent-color:#7fb2ff }
:where(#bbRoot, .bb-skin) .bb-opt select{ background:#131a33; color:#e8ecf5; border:1px solid #33406b; border-radius:7px; padding:2px 6px; font-size:.72rem }
:where(#bbRoot, .bb-skin) .bb-opt-btn{ cursor:pointer; background:rgba(0,0,0,.35); border:1px solid rgba(255,255,255,.18);
  color:#dfe8ff; border-radius:8px; padding:2px 9px; font-size:.85rem }

/* ---- repere SURPRISE sur mes cartes de banc ---- */
:where(#bbRoot, .bb-skin) .seenmk{ position:absolute; top:5px; left:50%; transform:translateX(-50%); z-index:4;
  font-size:.62rem; line-height:1; padding:2px 5px; border-radius:99px;
  background:rgba(6,9,18,.82); border:1px solid rgba(255,255,255,.22) }
:where(#bbRoot, .bb-skin) .seenmk.secret{ border-color:#7fd4a0; color:#bdf2d4 }
:where(#bbRoot, .bb-skin) .seenmk.shown{ border-color:#ffab6b; color:#ffd6b3 }

/* en portrait, les infos de tour reprennent leur place en bande */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .turnbar{ position:static; transform:none; flex-direction:row; align-items:center;
    justify-content:center; width:auto; margin:2px 6px; padding:4px 8px }
  :where(#bbRoot, .bb-skin) .turnbar .bb-turnmsg{ max-width:none }
  :where(#bbRoot, .bb-skin) .row{ gap:6px }
  :where(#bbRoot, .bb-skin) .flank{ width:94% }
}

/* La feuille d'origine impose `min-width:60%` a .bb-banner : la barre de tour
   s'etirait sur toute la largeur au lieu de rester une petite etiquette a gauche. */
:where(#bbRoot, .bb-skin) .turnbar.bb-banner{ min-width:0; margin:0; border-radius:12px; text-align:left }

/* Elan et maitresse ancres AUX CARTES (pas aux bords du tapis) : ils restent colles
   au jeu meme si on elargit le tapis pour remplir l'ecran.
   Demi-largeur d'une rangee de banc ~= (3x170 + 2x22)/2 = 277px. */
:where(#bbRoot, .bb-skin) .mat{ width:min(1500px,96vw) }
:where(#bbRoot, .bb-skin) .half.me  .flank{ right:auto; left:calc(50% + 300px) }
:where(#bbRoot, .bb-skin) .half.opp .flank{ left:auto;  right:calc(50% + 300px) }
:where(#bbRoot, .bb-skin) .half.me  .masterslot{ left:auto; right:calc(50% + 300px) }
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ right:auto; left:calc(50% + 300px) }
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .half.me .flank, :where(#bbRoot, .bb-skin) .half.opp .flank{ left:auto; right:auto }
  :where(#bbRoot, .bb-skin) .half.me .masterslot, :where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:6px; right:auto }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:auto; right:6px }
}

/* Une regle #bbBanner.bb-banner{position:relative} (passe precedente) l'emportait sur
   `.turnbar` : selecteur d'ID contre selecteur de classe. On repasse par l'ID. */
:where(#bbRoot, .bb-skin) #bbBanner.turnbar{ position:absolute; left:14px; top:50%; transform:translateY(-50%);
  width:auto; max-width:190px; min-width:0; margin:0 }
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar{ position:static; transform:none; max-width:none; margin:2px 6px }
}

/* ==========================================================================
   PORTRAIT — REAFFIRME EN DERNIER
   Les agrandissements de cartes (170/208px) ont ete ajoutes APRES le bloc portrait
   et l'ecrasaient : en 390x844 on repassait a 214px et 498px de debordement.
   A CSS egal, c'est la DERNIERE regle qui gagne : ce bloc doit rester en fin de fichier.
   ========================================================================== */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .mat{ width:100vw; gap:8px }
  :where(#bbRoot, .bb-skin) .card{ width:84px }
  :where(#bbRoot, .bb-skin) .card.active{ width:112px }
  :where(#bbRoot, .bb-skin) .row{ gap:8px }
  :where(#bbRoot, .bb-skin) .half{ gap:4px }
  :where(#bbRoot, .bb-skin) .half.opp .row + .row, :where(#bbRoot, .bb-skin) .half.me .row + .row{ margin-top:4px }
  :where(#bbRoot, .bb-skin) .flank{ width:94%; position:static; transform:none }
  :where(#bbRoot, .bb-skin) .half.me .flank, :where(#bbRoot, .bb-skin) .half.opp .flank{ left:auto; right:auto }
  :where(#bbRoot, .bb-skin) .masterslot{ transform:scale(.62); transform-origin:top left }
  :where(#bbRoot, .bb-skin) .half.me .masterslot{ left:6px; right:auto }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:auto; right:6px; transform:rotate(180deg) scale(.62); transform-origin:bottom right }
  :where(#bbRoot, .bb-skin) .bb-menu{ left:6px; top:6px; width:30px; height:30px }
  :where(#bbRoot, .bb-skin) .bb-opts{ left:6px; top:42px; width:min(238px,90vw) }
}

/* ==========================================================================
   v4 — tapis COLLES, cartes decollees des bords, boite « tour » sur le tapis
   ========================================================================== */
/* Les deux tapis se touchent : l'ecart doit venir du REMBOURRAGE interieur,
   pas d'un vide entre les deux (sinon on voit une couture beante). */
:where(#bbRoot, .bb-skin) .mat{ gap:0 }
:where(#bbRoot, .bb-skin) .half{ padding:26px 22px }
:where(#bbRoot, .bb-skin) .half.opp{ padding-bottom:34px }   /* la carte au front ne colle plus a la couture */
:where(#bbRoot, .bb-skin) .half.me{ padding-top:34px }

/* Boite « tour » : posee sur MON tapis, contre la couture, a gauche.
   Ancree a une moitie de tapis (hauteur stable) et non plus a #bbRoot, dont la
   hauteur changeait a chaque repaint : la boite sautait dans tous les sens. */
:where(#bbRoot, .bb-skin) #bbBanner.turnbar{ position:absolute; top:6px; left:18px; transform:none;
  width:auto; max-width:180px; min-width:0; margin:0; z-index:30;
  flex-direction:column; align-items:flex-start; gap:5px; padding:8px 11px }
:where(#bbRoot, .bb-skin) .half.me .flank{ top:58% }        /* laisse la place a la boite « tour » */

@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar{ position:static; max-width:none; margin:2px auto; flex-direction:row;
    align-items:center; justify-content:center; padding:4px 8px }
  :where(#bbRoot, .bb-skin) .half{ padding:8px 4px }
  :where(#bbRoot, .bb-skin) .half.opp{ padding-bottom:12px } :where(#bbRoot, .bb-skin) .half.me{ padding-top:12px }
  :where(#bbRoot, .bb-skin) .half.me .flank{ top:auto }
}

/* ==========================================================================
   v5 — attaques EN BAS DE L'ECRAN, boite « tour » pres du menu, vide du haut
   ========================================================================== */
/* Le pivot a 62% laissait ~85px de vide AU-DESSUS du tapis (la rotation 3D
   raccourcit la projection, et le reste se mettait en haut). Pivot en HAUT :
   le bord haut ne bouge plus, le reste passe en bas ou fitBoard le reprend. */
:where(#bbRoot, .bb-skin) .mat{ transform-origin:center top }

/* ATTAQUES : simple barre en BAS DE L'ECRAN, pas une bulle ancree a la carte. */
:where(#bbRoot, .bb-skin) #bbActions{ position:fixed; left:50%; bottom:16px; top:auto;
  transform:translateX(-50%); z-index:80;
  width:auto; max-width:min(880px,94vw); height:auto; padding:10px 12px;
  flex-direction:row; flex-wrap:wrap; align-items:center; justify-content:center; gap:8px }
:where(#bbRoot, .bb-skin) #bbActions::after{ content:none }   /* plus de fleche : la barre n'est plus ancree */

/* BOITE « TOUR » : haut-gauche DU TAPIS, juste sous le menu ☰ — numero + abandon. */
:where(#bbRoot, .bb-skin) #bbBanner.turnbar{ position:absolute; top:8px; left:14px; transform:none;
  flex-direction:row; align-items:center; gap:8px; padding:5px 10px;
  width:auto; max-width:none; min-width:0; margin:0; z-index:30 }
:where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-turnnum{ font-size:.66rem; letter-spacing:.12em }
:where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-forfeit{ margin:0 }
:where(#bbRoot, .bb-skin) .half.me .flank{ top:50% }          /* la boite a quitte mon tapis : Elan re-centre */

/* MENU ☰ ramene pres du plateau (il etait colle au coin de l'ecran) */
:where(#bbRoot, .bb-skin) .bb-menu{ left:50%; margin-left:-740px; top:14px }
:where(#bbRoot, .bb-skin) .bb-opts{ left:50%; margin-left:-740px; top:54px }

@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .mat{ transform-origin:center 58% }
  :where(#bbRoot, .bb-skin) #bbActions{ bottom:6px; max-width:98vw; padding:6px }
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar{ position:static; margin:2px auto; justify-content:center }
  :where(#bbRoot, .bb-skin) .bb-menu{ left:6px; margin-left:0; top:6px }
  :where(#bbRoot, .bb-skin) .bb-opts{ left:6px; margin-left:0; top:42px }
}

/* ---- CHOIX DE LA CARTE APRES UN K.O. (2026-07-23) ----
   Avant, le moteur promouvait automatiquement la suivante du deck. Le joueur choisit
   desormais : les cartes eligibles pulsent, tout le reste est inerte. */
:where(#bbRoot, .bb-skin) .card.promotable{ cursor:pointer; border-color:#7cf0a0;
  animation:promoPulse 1.1s ease-in-out infinite }
@keyframes promoPulse{
  0%,100%{ box-shadow:0 10px 18px -8px #000, 0 0 14px rgba(124,240,160,.55) }
  50%    { box-shadow:0 10px 18px -8px #000, 0 0 30px rgba(124,240,160,.95) } }
:where(#bbRoot, .bb-skin) .bb-promo-ask{ font-weight:800; font-size:.82rem; color:#bdf2d4; text-align:center;
  padding:2px 6px; text-shadow:0 0 12px rgba(124,240,160,.5) }

/* ==========================================================================
   v6 — retours de jeu du 2026-07-23
   ========================================================================== */

/* 1) CARTES ADVERSES REMISES A L'ENDROIT (le user revient sur sa demande :
   les retourner rendait la lecture plus difficile qu'autre chose). */
:where(#bbRoot, .bb-skin) .half.opp .cw{ transform:none }
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform:none }

/* 2) LE TOUR SE LIT SUR LE CAMP, pas sur le contour global du tapis :
   allumer tout le tapis ne disait pas DE QUI c'etait le tour. */
:where(#bbRoot, .bb-skin) .mat.turn-me, :where(#bbRoot, .bb-skin) .mat.turn-opp{ border-color:#3d5a8a; box-shadow:0 40px 70px -25px #000, 0 0 0 6px rgba(0,0,0,.35) }
:where(#bbRoot, .bb-skin) .half{ transition:box-shadow .25s, filter .25s }
:where(#bbRoot, .bb-skin) .half.turnactive{ box-shadow:inset 0 0 0 3px rgba(140,210,255,.85), inset 0 0 42px rgba(90,170,255,.35) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive{ box-shadow:inset 0 0 0 3px rgba(255,150,180,.85), inset 0 0 42px rgba(255,90,130,.30) }
:where(#bbRoot, .bb-skin) .half:not(.turnactive){ filter:saturate(.75) brightness(.86) }   /* le camp inactif recule */

/* 3) ELAN = LIQUIDE qui monte dans le tapis (fini la barre).
   Sous les cartes (z-index 1), donc les motifs du tapis restent visibles. */
:where(#bbRoot, .bb-skin) .elan .track, :where(#bbRoot, .bb-skin) .elan .pct, :where(#bbRoot, .bb-skin) .elan .lbl{ display:none }   /* l'ancienne barre disparait */
/* DISCRET : la 1re version etait trop opaque et son bord dore net se lisait comme un
   separateur au milieu du tapis (le 2e joueur demarre a 35 % d'Elan, donc c'etait visible
   des le tour 1 et passait pour un bug). Ici : voile leger + bord FONDU, aucune ligne dure. */
:where(#bbRoot, .bb-skin) .half::after{ content:""; position:absolute; left:0; right:0; height:var(--elan,0%);
  z-index:1; pointer-events:none; transition:height .65s cubic-bezier(.4,1.2,.5,1);
  background:linear-gradient(0deg, rgba(190,150,255,.16), rgba(255,215,106,.13) 62%, rgba(255,215,106,0) 100%) }
:where(#bbRoot, .bb-skin) .half.me::after{ bottom:0 }
:where(#bbRoot, .bb-skin) .half.opp::after{ top:0; transform:scaleY(-1); transform-origin:center }
:where(#bbRoot, .bb-skin) .half.elanfull::after{ background:linear-gradient(0deg, rgba(255,215,106,.30), rgba(255,240,180,.18) 70%, rgba(255,215,106,0) 100%);
  animation:elanShimmer 1.4s ease-in-out infinite }
@keyframes elanShimmer{ 50%{ filter:brightness(1.35) } }

/* 4) ENTREE D'UNE NOUVELLE CARTE AU FRONT (avant : saut d'image, sans transition) */
:where(#bbRoot, .bb-skin) .card.bb-enter{ animation:cardEnter .5s cubic-bezier(.2,1.4,.4,1) }
@keyframes cardEnter{
  0%  { transform:translateY(26px) scale(.72); opacity:0; filter:brightness(2.2) }
  60% { transform:translateY(-4px) scale(1.06); opacity:1; filter:brightness(1.3) }
  100%{ transform:none; opacity:1; filter:none } }

/* 5) EMPLACEMENT MAITRESSE PLUS GRAND (encore juge trop petit).
   Il fait la taille d'une VRAIE carte de banc : c'en est une, a terme. */
:where(#bbRoot, .bb-skin) .ms-empty{ width:clamp(130px, 13vh, 178px) }
:where(#bbRoot, .bb-skin) .ms-empty span{ font-size:.62rem }

/* 6) BOUTON PARAMETRES SUR LE TAPIS, a gauche de la boite « tour » */
:where(#bbRoot, .bb-skin) .mat > .bb-menu{ position:absolute; top:10px; left:14px; margin-left:0; z-index:45;
  display:flex; align-items:center; justify-content:center }
:where(#bbRoot, .bb-skin) .mat > .bb-opts{ position:absolute; top:52px; left:14px; margin-left:0; z-index:46 }
:where(#bbRoot, .bb-skin) #bbBanner.turnbar{ left:58px }        /* laisse la place au bouton ☰ */

@media (prefers-reduced-motion:reduce){
  :where(#bbRoot, .bb-skin) .card.bb-enter{ animation:none } :where(#bbRoot, .bb-skin) .half.elanfull::after{ animation:none } }

/* ==========================================================================
   ELAN — SURFACE DE LIQUIDE qui ONDULE (« comme dans un verre »)
   Deux vagues SVG en repeat-x, decalees en vitesse et en sens : le decalage des
   deux periodes donne une houle irreguliere plutot qu'un defilement mecanique.
   SVG INLINE en data-uri : aucune requete reseau.
   ========================================================================== */
:where(#bbRoot, .bb-skin) .elanwave{ position:absolute; left:0; right:0; height:18px; z-index:2; pointer-events:none;
  transition:bottom .65s cubic-bezier(.4,1.2,.5,1), top .65s cubic-bezier(.4,1.2,.5,1) }
:where(#bbRoot, .bb-skin) .elanwave::before, :where(#bbRoot, .bb-skin) .elanwave::after{ content:""; position:absolute; inset:0;
  background-repeat:repeat-x; background-position:0 bottom }
:where(#bbRoot, .bb-skin) .elanwave::before{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='18'><path d='M0 10 q30 -9 60 0 t60 0 t60 0 t60 0 V18 H0 Z' fill='%23ffd76a' opacity='0.34'/></svg>");
  background-size:240px 18px; animation:elanWaveA 6.5s linear infinite }
:where(#bbRoot, .bb-skin) .elanwave::after{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='18'><path d='M0 11 q22.5 -7 45 0 t45 0 t45 0 t45 0 V18 H0 Z' fill='%23c8a3ff' opacity='0.30'/></svg>");
  background-size:180px 18px; animation:elanWaveB 9.5s linear infinite reverse }
@keyframes elanWaveA{ to{ background-position:240px bottom } }
@keyframes elanWaveB{ to{ background-position:180px bottom } }

/* le niveau : la surface se pose PILE en haut du liquide, et se mire cote adverse */
:where(#bbRoot, .bb-skin) .half.me  .elanwave{ bottom:var(--elan,0%) }
:where(#bbRoot, .bb-skin) .half.opp .elanwave{ top:var(--elan,0%); transform:scaleY(-1) }
:where(#bbRoot, .bb-skin) .half.elanzero .elanwave{ opacity:0 }                 /* verre vide (ancienne jauge) */
:where(#bbRoot, .bb-skin) .half.elanfull .elanwave{ filter:brightness(1.5) saturate(1.2) }

@media (prefers-reduced-motion:reduce){
  :where(#bbRoot, .bb-skin) .elanwave::before, :where(#bbRoot, .bb-skin) .elanwave::after{ animation:none } }

/* ==========================================================================
   v7 — corrections mesurees
   ========================================================================== */

/* 1) MAITRESSE ADVERSE : elle heritait de `top:10px` (regle de base) ET de `bottom:10px`
   (regle miroir) -> avec les DEUX ancrages, la boite s'etirait sur toute la hauteur du
   camp (mesure : 436 px au lieu de 154). On repose les 4 cotes explicitement.
   Miroir : la mienne touche la couture par le HAUT, la sienne par le BAS. */
:where(#bbRoot, .bb-skin) .half.me .masterslot{
  top:10px; bottom:auto; left:auto; right:calc(50% + 300px);
}
:where(#bbRoot, .bb-skin) .half.opp .masterslot{
  top:auto; bottom:10px; right:auto; left:calc(50% + 300px);
}

/* 2) LE TAPIS N'A PLUS DE MARGE INTERNE : les camps allaient jusqu'a 15 px du bord,
   donc la jauge ne partait pas du bas du tapis. Les camps ont deja leur propre marge. */
:where(#bbRoot, .bb-skin) .mat{ padding:0 }

/* 3) JAUGE VISIBLE : la version « discrete » etait devenue invisible. Niveau franc,
   mais toujours SANS liseré dur (c'est le degrade qui s'eteint vers le haut). */
:where(#bbRoot, .bb-skin) .half::after{
  background:linear-gradient(0deg, rgba(190,150,255,.42), rgba(200,150,255,.30) 40%,
                                   rgba(255,215,106,.22) 78%, rgba(255,215,106,0) 100%) }
:where(#bbRoot, .bb-skin) .half.elanfull::after{
  background:linear-gradient(0deg, rgba(255,200,90,.55), rgba(255,225,140,.34) 60%,
                                   rgba(255,240,180,0) 100%) }
:where(#bbRoot, .bb-skin) .elanwave::before{ opacity:.85 }
:where(#bbRoot, .bb-skin) .elanwave::after{ opacity:.7 }

@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .half.me .masterslot{ top:6px; bottom:auto; left:6px; right:auto }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ top:auto; bottom:6px; left:auto; right:6px }
}

/* ==========================================================================
   v8 — jauge lisible, tour sans ambiguite
   ========================================================================== */

/* 1) LE CHIFFRE REVIENT. Sans lui on devine (« c'est quoi, 40 % ? »). La BARRE reste
   masquee : c'est le liquide qui porte l'information, le chiffre ne fait que la confirmer. */
:where(#bbRoot, .bb-skin) .elan .pct{ display:inline-block; font-size:.72rem; font-weight:900; color:#ffd76a;
  background:rgba(8,10,20,.7); border:1px solid rgba(255,215,106,.45);
  border-radius:99px; padding:2px 10px; min-width:0; text-align:center }
:where(#bbRoot, .bb-skin) .elan .lbl{ display:inline-block; font-size:.55rem }
:where(#bbRoot, .bb-skin) .elan{ justify-content:center }
:where(#bbRoot, .bb-skin) .elan.full .pct{ color:#2a1c00; background:linear-gradient(180deg,#ffe07a,#ffb300); border-color:#fff3b0 }

/* 2) LIQUIDE FRANC : la version precedente etait trop transparente pour se lire d'un
   coup d'oeil. Fond net en bas, extinction douce vers la surface (aucun liseré dur). */
:where(#bbRoot, .bb-skin) .half::after{
  background:linear-gradient(0deg, rgba(160,110,255,.62), rgba(190,140,255,.44) 38%,
                                   rgba(255,215,106,.26) 76%, rgba(255,215,106,0) 100%) }
:where(#bbRoot, .bb-skin) .half.elanfull::after{
  background:linear-gradient(0deg, rgba(255,190,60,.72), rgba(255,220,120,.46) 55%,
                                   rgba(255,240,180,0) 100%) }
:where(#bbRoot, .bb-skin) .elanwave::before{ opacity:1 }
:where(#bbRoot, .bb-skin) .elanwave::after{ opacity:.85 }

/* 3) A QUI LE TOUR : le camp actif est CERNÉ et PULSE, l'autre s'efface nettement.
   Les deux etats se ressemblaient trop pour se distinguer d'un coup d'oeil. */
:where(#bbRoot, .bb-skin) .half.turnactive{ animation:none } /* voir ::before ci-dessous (perf 2026-07-29) */
:where(#bbRoot, .bb-skin) .half.turnactive::before{ content:""; position:absolute; inset:0; z-index:6; pointer-events:none;
  border-radius:inherit; box-shadow:inset 0 0 0 4px currentColor; color:transparent;
  animation:turnRingOp 1.9s ease-in-out infinite; will-change:opacity }
:where(#bbRoot, .bb-skin) .half.me.turnactive::before{ color:var(--turnMe,#7fd4ff) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive::before{ color:var(--turnOpp,#ff8fa8) }
@keyframes turnRingOp{ 0%,100%{ opacity:.45 } 50%{ opacity:1 } }
:where(#bbRoot, .bb-skin) .half.me.turnactive{ box-shadow:inset 0 0 0 5px rgba(120,225,255,.95), inset 0 0 70px rgba(60,170,255,.45) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive{ box-shadow:inset 0 0 0 5px rgba(255,120,160,.95), inset 0 0 70px rgba(255,70,120,.40) }
@keyframes turnRing{ 50%{ filter:brightness(1.14) } }
:where(#bbRoot, .bb-skin) .half:not(.turnactive){ filter:saturate(.45) brightness(.62); box-shadow:none }

/* ==========================================================================
   v9 — le liquide RESPECTE LA GRAVITE, et plus aucun grisage
   ========================================================================== */

/* 1) Les DEUX jauges montent DEPUIS LE BAS de leur camp. Cote adverse elle partait
   du HAUT (miroir logique, mais un liquide accroche au plafond se lit comme un bug :
   c'est ce qui donnait cette bande doree en haut du tapis). Les deux niveaux se
   rejoignent maintenant de part et d'autre de la couture, comme un meme bassin. */
:where(#bbRoot, .bb-skin) .half.opp::after{ top:auto; bottom:0; transform:none }
:where(#bbRoot, .bb-skin) .half.opp .elanwave{ top:auto; bottom:var(--elan,0%); transform:none }

/* 2) PLUS DE GRISAGE du camp inactif : ca donnait une impression de partie terminee.
   C'est l'anneau lumineux du camp ACTIF qui porte l'information, a lui seul. */
:where(#bbRoot, .bb-skin) .half:not(.turnactive){ filter:none; box-shadow:none }
:where(#bbRoot, .bb-skin) .half.me.turnactive{ box-shadow:inset 0 0 0 5px rgba(120,225,255,.95), inset 0 0 80px rgba(60,170,255,.40) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive{ box-shadow:inset 0 0 0 5px rgba(255,120,160,.95), inset 0 0 80px rgba(255,70,120,.35) }

/* ==========================================================================
   v10 — LE LIQUIDE EST UN SEUL VOLUME
   Avant : corps en degrade qui s'eteignait vers le haut + vague d'une AUTRE couleur
   et d'une autre opacite -> on voyait deux decorations superposees, pas un niveau
   qui monte. Ici : corps UNIFORME et vague de la MEME couleur -> la vague EST la
   surface du corps. Une carte du jeu reste lisible par-dessus (z-index 5 vs 1-2).
   ========================================================================== */
:where(#bbRoot, .bb-skin) .half{ --liq:139,92,246; --liqA:.50 }          /* violet d'Elan */
:where(#bbRoot, .bb-skin) .half.elanfull{ --liq:255,196,60; --liqA:.62 } /* dore quand l'Ultime est pret */

/* corps : couleur PLEINE, aucun fondu (c'est ce qui donnait l'aspect « decor ») */
:where(#bbRoot, .bb-skin) .half::after{ background:rgba(var(--liq), var(--liqA)) }
:where(#bbRoot, .bb-skin) .half.elanfull::after{ background:rgba(var(--liq), var(--liqA)) }

/* surface : meme couleur, donc elle prolonge le corps au lieu de flotter dessus.
   Deux crêtes de longueurs differentes = houle irreguliere. */
:where(#bbRoot, .bb-skin) .elanwave{ height:14px }
:where(#bbRoot, .bb-skin) .elanwave::before{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='14'><path d='M0 8 q30 -8 60 0 t60 0 t60 0 t60 0 V14 H0 Z' fill='white'/></svg>");
  background-size:240px 14px; opacity:1;
  /* la teinte vient du corps : on recolore la forme blanche */
  filter:none; mix-blend-mode:normal;
  background-color:transparent }
:where(#bbRoot, .bb-skin) .elanwave::after{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='170' height='14'><path d='M0 9 q21 -6 42.5 0 t42.5 0 t42.5 0 t42.5 0 V14 H0 Z' fill='white'/></svg>");
  background-size:170px 14px; opacity:.55 }
/* recoloration : on peint la vague avec la couleur du liquide via un calque teinte */
:where(#bbRoot, .bb-skin) .elanwave::before, :where(#bbRoot, .bb-skin) .elanwave::after{
  -webkit-mask-image:var(--wm); mask-image:var(--wm);
  -webkit-mask-repeat:repeat-x; mask-repeat:repeat-x;
  -webkit-mask-position:0 bottom; mask-position:0 bottom }
:where(#bbRoot, .bb-skin) .elanwave::before{ --wm:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='14'><path d='M0 8 q30 -8 60 0 t60 0 t60 0 t60 0 V14 H0 Z' fill='black'/></svg>");
  -webkit-mask-size:240px 14px; mask-size:240px 14px;
  background-image:none; background-color:rgba(var(--liq), var(--liqA)) }
:where(#bbRoot, .bb-skin) .elanwave::after{ --wm:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='170' height='14'><path d='M0 9 q21 -6 42.5 0 t42.5 0 t42.5 0 t42.5 0 V14 H0 Z' fill='black'/></svg>");
  -webkit-mask-size:170px 14px; mask-size:170px 14px;
  background-image:none; background-color:rgba(var(--liq), calc(var(--liqA) * .8)) }
@keyframes elanWaveA{ to{ -webkit-mask-position:240px bottom; mask-position:240px bottom } }
@keyframes elanWaveB{ to{ -webkit-mask-position:170px bottom; mask-position:170px bottom } }

/* ==========================================================================
   v11 — L'ELAN QUITTE LE TAPIS : c'est un VERRE dans le flanc
   Constat a l'ecran : cote adverse, le niveau montait depuis le bas de SON camp,
   c'est-a-dire depuis la couture centrale -> une grosse bande pleine en travers du
   plateau. Aucun reglage ne pouvait corriger ca, la geometrie l'imposait.
   Le recipient est donc explicite : un verre vertical, a cote du pseudo.
   ========================================================================== */
/* on neutralise completement l'ancien remplissage du tapis */
:where(#bbRoot, .bb-skin) .half::after{ content:none !important }
:where(#bbRoot, .bb-skin) .elanwave{ display:none !important }

:where(#bbRoot, .bb-skin) .elan{ display:flex; align-items:center; gap:10px; justify-content:center }
:where(#bbRoot, .bb-skin) .elan-txt{ display:flex; flex-direction:column; align-items:flex-start; gap:2px }
:where(#bbRoot, .bb-skin) .elan .lbl{ display:block; font-size:.52rem; font-weight:900; letter-spacing:.14em; color:#c9b6ff }
:where(#bbRoot, .bb-skin) .elan .pct{ display:block; font-size:.95rem; font-weight:900; color:#e6dcff;
  background:none; border:0; padding:0 }
:where(#bbRoot, .bb-skin) .elan.full .lbl{ color:#ffd76a } :where(#bbRoot, .bb-skin) .elan.full .pct{ color:#ffe07a; background:none }

/* le VERRE */
:where(#bbRoot, .bb-skin) .glass{ position:relative; width:34px; height:76px; border-radius:7px 7px 10px 10px;
  background:linear-gradient(180deg, rgba(10,14,28,.85), rgba(20,26,50,.9));
  border:2px solid rgba(190,170,255,.55); overflow:hidden; flex:0 0 auto;
  box-shadow:inset 0 2px 6px rgba(0,0,0,.6) }
:where(#bbRoot, .bb-skin) .glass-liq{ position:absolute; left:0; right:0; bottom:0; height:var(--lvl,0%);
  background:linear-gradient(180deg,#a678ff,#7a4dff);
  transition:height .6s cubic-bezier(.4,1.3,.5,1) }
/* la SURFACE : deux crêtes de la meme couleur que le liquide, donc c'est bien le
   dessus du liquide qui bouge — pas un decor pose par-dessus */
:where(#bbRoot, .bb-skin) .glass-wave{ position:absolute; left:-50%; right:-50%; height:8px; bottom:var(--lvl,0%);
  transition:bottom .6s cubic-bezier(.4,1.3,.5,1) }
:where(#bbRoot, .bb-skin) .glass-wave::before, :where(#bbRoot, .bb-skin) .glass-wave::after{ content:""; position:absolute; inset:0;
  background-repeat:repeat-x; background-position:0 bottom }
:where(#bbRoot, .bb-skin) .glass-wave::before{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='8'><path d='M0 5 q5 -5 10 0 t10 0 t10 0 t10 0 V8 H0 Z' fill='%23a678ff'/></svg>");
  background-size:40px 8px; animation:glassA 2.4s linear infinite }
:where(#bbRoot, .bb-skin) .glass-wave::after{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='8'><path d='M0 6 q3.5 -4 7 0 t7 0 t7 0 t7 0 V8 H0 Z' fill='%238a5cff'/></svg>");
  background-size:28px 8px; opacity:.8; animation:glassB 3.6s linear infinite reverse }
@keyframes glassA{ to{ background-position:40px bottom } }
@keyframes glassB{ to{ background-position:28px bottom } }
/* reflet du verre */
:where(#bbRoot, .bb-skin) .glass-shine{ position:absolute; left:3px; top:4px; width:6px; bottom:6px; border-radius:4px;
  background:linear-gradient(180deg, rgba(255,255,255,.30), rgba(255,255,255,.05)) }

/* ULTIME PRET : le verre deborde de lumiere doree */
:where(#bbRoot, .bb-skin) .elan.full .glass{ border-color:#ffd76a; box-shadow:0 0 16px rgba(255,215,106,.75), inset 0 2px 6px rgba(0,0,0,.5) }
:where(#bbRoot, .bb-skin) .elan.full .glass-liq{ background:linear-gradient(180deg,#ffe07a,#ffb300) }
:where(#bbRoot, .bb-skin) .elan.full .glass-wave::before{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='8'><path d='M0 5 q5 -5 10 0 t10 0 t10 0 t10 0 V8 H0 Z' fill='%23ffe07a'/></svg>") }
:where(#bbRoot, .bb-skin) .elan.full .glass-wave::after{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='28' height='8'><path d='M0 6 q3.5 -4 7 0 t7 0 t7 0 t7 0 V8 H0 Z' fill='%23ffc94d'/></svg>") }

@media (prefers-reduced-motion:reduce){
  :where(#bbRoot, .bb-skin) .glass-wave::before, :where(#bbRoot, .bb-skin) .glass-wave::after{ animation:none } }

/* ---- CARTE MAITRESSE (P1) : vignette dans l'emplacement dedie ---- */
:where(#bbRoot, .bb-skin) .ms-card{ position:relative; width:clamp(130px,13vh,178px); aspect-ratio:3/4.35;
  border-radius:10px; overflow:hidden; border:2px solid var(--rc,#888);
  background:linear-gradient(180deg,#1a2033,#0d1120);
  box-shadow:0 10px 20px -8px #000, 0 0 18px -6px var(--rc,#888) }
:where(#bbRoot, .bb-skin) .ms-card img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 16% }
:where(#bbRoot, .bb-skin) .ms-scrim{ position:absolute; left:0; right:0; bottom:0; height:56%; z-index:1;
  background:linear-gradient(180deg,transparent,rgba(8,10,20,.75) 40%,rgba(8,10,20,.97)) }
:where(#bbRoot, .bb-skin) .ms-crown{ position:absolute; top:4px; right:5px; z-index:3; font-size:.8rem;
  filter:drop-shadow(0 0 5px rgba(255,215,106,.9)) }
:where(#bbRoot, .bb-skin) .ms-el{ position:absolute; top:4px; left:5px; z-index:3; font-size:.8rem }
:where(#bbRoot, .bb-skin) .ms-nm{ position:absolute; left:0; right:0; bottom:20px; z-index:3; text-align:center;
  font-size:.64rem; font-weight:800; color:#fff; text-shadow:0 1px 3px #000;
  padding:0 3px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
:where(#bbRoot, .bb-skin) .ms-pas{ position:absolute; left:3px; right:3px; bottom:5px; z-index:3; text-align:center;
  font-size:.44rem; font-weight:800; letter-spacing:.02em; color:#bdf2d4;
  text-shadow:0 1px 2px #000; line-height:1.15;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden }

/* ---- CAPACITE ACTIVE de la maitresse (P2) ----
   Sous chaque carte maitresse : une PASTILLE D'ETAT en lecture seule (info publique).
   Le declenchement vit dans le MENU D'ACTIONS (.bb-abl, pleine taille et lisible). */
:where(#bbRoot, .bb-skin) .masterslot{ display:flex; flex-direction:column; align-items:center; gap:4px }
:where(#bbRoot, .bb-skin) .ms-abl{ display:block; max-width:100%; padding:3px 8px; border-radius:999px;
  border:1px solid #3a4568; background:linear-gradient(180deg,#232a44,#161c30);
  color:#8e97b5; font-size:.72rem; font-weight:800; letter-spacing:.02em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:default }
:where(#bbRoot, .bb-skin) .ms-abl b{ font-weight:900; color:#c6cde6 }
:where(#bbRoot, .bb-skin) .ms-abl.rdy{ color:#ffe9ad; border-color:#8a6d2f;
  background:linear-gradient(180deg,#3a3116,#241d0b);
  box-shadow:0 0 10px -3px rgba(255,215,106,.55) }
/* Le tapis adverse est pivote a 180 : on contre-pivote la pastille pour la garder lisible. */
:where(#bbRoot, .bb-skin) .half.opp .ms-abl{ transform:rotate(180deg) }

/* ---- ECRAN D'INTRO (P5) : VS maitresses -> choix de l'ordre -> de ----
   Voile plein ecran par-dessus le plateau (position:fixed : la scene est mise a l'echelle,
   un absolute dans #bbRoot heriterait de la transformation). */
:where(#bbRoot, .bb-skin) .bb-intro{ position:fixed; inset:0; z-index:80; display:flex; align-items:center; justify-content:center;
  background:rgba(5,7,16,.88); backdrop-filter:blur(6px); animation:biFade .4s ease }
@keyframes biFade{ from{ opacity:0 } to{ opacity:1 } }
:where(#bbRoot, .bb-skin) .bi-vs-wrap{ display:flex; align-items:center; gap:clamp(18px,6vw,72px); padding:16px }
:where(#bbRoot, .bb-skin) .bi-side{ display:flex; flex-direction:column; align-items:center; gap:10px }
:where(#bbRoot, .bb-skin) .bi-side:first-child{ animation:biFromLeft .55s cubic-bezier(.2,.9,.25,1) }
:where(#bbRoot, .bb-skin) .bi-side:last-child{ animation:biFromRight .55s cubic-bezier(.2,.9,.25,1) }
@keyframes biFromLeft{ from{ transform:translateX(-60px); opacity:0 } to{ transform:none; opacity:1 } }
@keyframes biFromRight{ from{ transform:translateX(60px); opacity:0 } to{ transform:none; opacity:1 } }
:where(#bbRoot, .bb-skin) .bi-card{ position:relative; width:clamp(120px,22vw,190px); aspect-ratio:3/4.2; border-radius:12px;
  overflow:hidden; border:2px solid var(--rc,#888); background:linear-gradient(180deg,#1a2033,#0d1120);
  box-shadow:0 16px 40px -12px #000, 0 0 26px -6px var(--rc,#888) }
:where(#bbRoot, .bb-skin) .bi-card img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 16% }
:where(#bbRoot, .bb-skin) .bi-card.bi-none{ display:flex; align-items:center; justify-content:center; font-size:2rem; color:#39406a }
:where(#bbRoot, .bb-skin) .bi-crown{ position:absolute; top:6px; right:7px; font-size:1.05rem; filter:drop-shadow(0 0 6px rgba(255,215,106,.9)) }
:where(#bbRoot, .bb-skin) .bi-mname{ position:absolute; left:0; right:0; bottom:0; padding:14px 4px 6px; text-align:center;
  font-weight:800; font-size:.9rem; color:#fff; text-shadow:0 1px 3px #000;
  background:linear-gradient(180deg,transparent,rgba(8,10,20,.92)) }
:where(#bbRoot, .bb-skin) .bi-player{ font-weight:800; font-size:1rem; color:#cfd6f2; text-shadow:0 1px 3px #000 }
:where(#bbRoot, .bb-skin) .bi-vs{ font-size:clamp(2rem,7vw,3.6rem); font-weight:900; font-style:italic; color:#ffe9ad;
  text-shadow:0 0 22px rgba(255,215,106,.55), 0 3px 6px #000; animation:biVs .7s cubic-bezier(.2,.9,.25,1) }
@keyframes biVs{ from{ transform:scale(2.4); opacity:0 } to{ transform:scale(1); opacity:1 } }

/* Choix de l'ordre */
:where(#bbRoot, .bb-skin) .bi-order{ max-width:min(92vw,620px); text-align:center; padding:10px }
:where(#bbRoot, .bb-skin) .bi-order h3{ margin:0 0 6px; font-size:1.15rem; color:#ffe9ad }
:where(#bbRoot, .bb-skin) .bi-order p{ margin:0 0 14px; font-size:.8rem; color:#9aa3c4 }
:where(#bbRoot, .bb-skin) .bi-tiles{ display:flex; flex-wrap:wrap; gap:10px; justify-content:center; margin-bottom:16px }
:where(#bbRoot, .bb-skin) .bi-tile{ position:relative; width:clamp(84px,18vw,118px); aspect-ratio:3/4.2; border-radius:10px;
  overflow:hidden; border:2px solid var(--rc,#888); background:#0d1120; cursor:pointer; padding:0;
  box-shadow:0 8px 18px -8px #000; transition:transform .15s ease, box-shadow .15s ease }
:where(#bbRoot, .bb-skin) .bi-tile:hover{ transform:translateY(-4px); box-shadow:0 12px 22px -8px #000, 0 0 16px -4px var(--rc,#888) }
:where(#bbRoot, .bb-skin) .bi-tile img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 16% }
:where(#bbRoot, .bb-skin) .bi-tile .bi-tname{ position:absolute; left:0; right:0; bottom:0; padding:12px 3px 4px; font-size:.62rem;
  font-weight:800; color:#fff; text-shadow:0 1px 2px #000;
  background:linear-gradient(180deg,transparent,rgba(8,10,20,.92)); white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
:where(#bbRoot, .bb-skin) .bi-tile .bi-ord{ position:absolute; top:5px; left:5px; z-index:2; width:24px; height:24px; border-radius:50%;
  display:flex; align-items:center; justify-content:center; font-weight:900; font-size:.85rem;
  color:#1a1405; background:#ffe9ad; box-shadow:0 0 10px rgba(255,215,106,.7); opacity:0; transform:scale(.4);
  transition:opacity .15s ease, transform .15s ease }
:where(#bbRoot, .bb-skin) .bi-tile.picked .bi-ord{ opacity:1; transform:scale(1) }
:where(#bbRoot, .bb-skin) .bi-tile.picked{ outline:2px solid #ffe9ad; outline-offset:2px }
:where(#bbRoot, .bb-skin) .bi-btns{ display:flex; gap:10px; justify-content:center }
:where(#bbRoot, .bb-skin) .bi-btns .btn{ padding:8px 16px; border-radius:10px; border:1px solid #3a4568; cursor:pointer;
  background:linear-gradient(180deg,#232a44,#161c30); color:#cfd6f2; font-weight:800 }
:where(#bbRoot, .bb-skin) .bi-btns .btn.primary{ border-color:#8a6d2f; background:linear-gradient(180deg,#3a3116,#241d0b); color:#ffe9ad;
  box-shadow:0 0 12px -4px rgba(255,215,106,.6) }
:where(#bbRoot, .bb-skin) .bi-btns .btn:hover{ filter:brightness(1.15) }

/* De / Initiative */
:where(#bbRoot, .bb-skin) .bi-dicewrap{ flex-direction:column; gap:14px }
:where(#bbRoot, .bb-skin) .bi-die{ font-size:clamp(3rem,10vw,4.6rem); animation:biRoll .9s cubic-bezier(.3,.8,.4,1.2) }
:where(#bbRoot, .bb-skin) .bi-die.init{ animation:biPulse .9s ease }
@keyframes biRoll{ 0%{ transform:rotate(0) scale(.4); opacity:0 } 60%{ transform:rotate(540deg) scale(1.15); opacity:1 } 100%{ transform:rotate(720deg) scale(1) } }
@keyframes biPulse{ 0%{ transform:scale(.4); opacity:0 } 55%{ transform:scale(1.3) } 100%{ transform:scale(1); opacity:1 } }
:where(#bbRoot, .bb-skin) .bi-who{ min-height:1.6em; font-weight:900; font-size:clamp(1rem,3.4vw,1.5rem); color:#ffe9ad;
  text-shadow:0 0 18px rgba(255,215,106,.5), 0 2px 5px #000; opacity:0; transform:translateY(8px);
  transition:opacity .3s ease, transform .3s ease }
:where(#bbRoot, .bb-skin) .bb-intro.done .bi-who{ opacity:1; transform:none }

/* Bouton de capacite dans le MENU D'ACTIONS : meme langage que l'Ultime, en dore « royal ». */
:where(#bbRoot, .bb-skin) .bb-abl{ display:block; width:100%; margin-top:6px; padding:7px 10px; border-radius:10px;
  border:1px solid #8a6d2f; background:linear-gradient(180deg,#3a3116,#241d0b);
  color:#ffe9ad; font-weight:800; cursor:pointer; text-align:center;
  box-shadow:0 0 12px -4px rgba(255,215,106,.6) }
:where(#bbRoot, .bb-skin) .bb-abl:hover{ filter:brightness(1.15) }
:where(#bbRoot, .bb-skin) .bb-abl .bb-atk-name{ display:block; font-size:.88rem }
:where(#bbRoot, .bb-skin) .bb-abl .bb-atk-line{ display:block; font-size:.66rem; opacity:.85; font-weight:600 }
/* La maitresse AGIT : pulse dore le temps de l'animation. */
:where(#bbRoot, .bb-skin) .ms-card.ms-act{ animation:msAct .9s ease }
@keyframes msAct{
  0%{ transform:scale(1); box-shadow:0 10px 20px -8px #000, 0 0 18px -6px var(--rc,#888) }
  35%{ transform:scale(1.07); box-shadow:0 10px 26px -8px #000, 0 0 30px -2px rgba(255,215,106,.95) }
  100%{ transform:scale(1); box-shadow:0 10px 20px -8px #000, 0 0 18px -6px var(--rc,#888) }
}

/* ---- LISIBILITE : compenser la mise a l'echelle du plateau ----
   fitBoard reduit la scene (~x0.69 sur 1920x1030). Un texte de 8 px CSS finit donc a
   5,5 px REELS a l'ecran. Mesure avant : rarete 6.0px, stats 6.4px, nom maitresse 7.0px.
   On remonte les plus petits pour repasser au-dessus de ~8 px reels. */
:where(#bbRoot, .bb-skin) .card .rar{ font-size:.72rem; bottom:18px; letter-spacing:.10em }
:where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.78rem; bottom:21px }
:where(#bbRoot, .bb-skin) .card .st{ font-size:.68rem; gap:8px }
:where(#bbRoot, .bb-skin) .card.active .st{ font-size:.74rem; gap:10px }
:where(#bbRoot, .bb-skin) .card .nm{ font-size:.78rem; bottom:32px }
:where(#bbRoot, .bb-skin) .card.active .nm{ font-size:.92rem; bottom:36px }
:where(#bbRoot, .bb-skin) .ms-nm{ font-size:.82rem; bottom:22px }
:where(#bbRoot, .bb-skin) .ms-pas{ font-size:.56rem }
:where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-turnnum{ font-size:.86rem }
:where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ font-size:.78rem }
:where(#bbRoot, .bb-skin) .elan .lbl{ font-size:.62rem }
:where(#bbRoot, .bb-skin) .elan .pct{ font-size:1.05rem }

/* ---- EFFETS DE STATUT : tailles remontees ----
   Mesure a l'ecran : braises de brulure a 2x2 px (invisibles). Deux causes cumulees —
   le plateau est mis a l'echelle (~x0.69, moins encore sur petite fenetre) ET l'animation
   demarre a scale(.5). Les valeurs CSS doivent donc etre genereuses. */
:where(#bbRoot, .bb-skin) .aura.burn i{ width:13px; height:15px }
@keyframes emberFall{ 0%{ transform:translateY(-14px) scale(.75); opacity:0 } 25%{ opacity:1 }
  100%{ transform:translateY(34px) scale(1.05); opacity:0 } }
:where(#bbRoot, .bb-skin) .aura.stun i{ font-size:24px }
:where(#bbRoot, .bb-skin) .aura.mark i{ font-size:19px }

/* ---- ECRANS COURTS (paysage < 620 px de haut) ----
   Mesure : en 760x430 le menu d'attaques recouvrait le bas du plateau. La hauteur
   disponible est trop faible pour la bande reservee ET un menu pleine taille : on
   compacte le menu plutot que d'ecraser encore le plateau. */
@media (orientation:landscape) and (max-height:620px){
  :where(#bbRoot, .bb-skin) #bbActions{ bottom:6px; padding:5px 7px; gap:5px; max-width:min(680px,96vw) }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk{ max-width:170px; padding:5px 8px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ font-size:.74rem }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-line, :where(#bbRoot, .bb-skin) #bbActions .bb-atk-eff{ font-size:.6rem }
  :where(#bbRoot, .bb-skin) #bbActions .bb-ult{ padding:5px 12px; font-size:.8rem }
  :where(#bbRoot, .bb-skin) .bb-promo-ask{ font-size:.72rem }
}

/* ---- MAITRESSE A LA TAILLE D'UNE VRAIE CARTE ----
   Mesure : 78 px contre 120 px pour une carte de jeu (65 %). Les deux maitresses font bien
   la MEME taille entre elles — le probleme etait qu'elles etaient petites face aux cartes.
   C'EST une carte : elle doit avoir le format d'une carte de banc. */
:where(#bbRoot, .bb-skin) .ms-card, :where(#bbRoot, .bb-skin) .ms-empty{ width:170px }

/* ---- PLUS DE BANDE VIDE SOUS LE TAPIS ----
   Le menu d'attaques etait fixe en bas de l'ECRAN, ce qui obligeait a reserver 96 px sous le
   plateau — visibles en permanence, menu ferme (mesure : 117 px de vide). Il revient dans le
   flux, juste sous le tapis : plus de reserve, donc plus de vide. */
:where(#bbRoot, .bb-skin) #bbActions{ position:static; transform:none; margin:10px auto 0; max-width:min(880px,94vw) }
#bbRoot{ padding-bottom:0 }

/* ---- ☰ ET BOITE DE TOUR : ENCASTRES DANS LE TAPIS ----
   Ils faisaient « collés par-dessus » : fond opaque, bord clair et grosse ombre portee les
   detachaient de la surface. Ici ils sont CREUSES dans le tapis (fond sombre translucide,
   ombre INTERNE, pas de halo) : ils appartiennent au plateau au lieu de flotter dessus. */
:where(#bbRoot, .bb-skin) #bbBanner.turnbar{
  background:rgba(6,10,22,.55);
  border:1px solid rgba(255,255,255,.10);
  box-shadow:inset 0 2px 6px rgba(0,0,0,.55), inset 0 -1px 0 rgba(255,255,255,.06);
  backdrop-filter:blur(2px); border-radius:10px }
:where(#bbRoot, .bb-skin) .mat > .bb-menu{
  background:rgba(6,10,22,.55);
  border:1px solid rgba(255,255,255,.10);
  box-shadow:inset 0 2px 6px rgba(0,0,0,.55); border-radius:9px; color:#cfe0ff }
:where(#bbRoot, .bb-skin) .mat > .bb-menu:hover{ background:rgba(20,30,58,.7) }
:where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ background:rgba(60,20,26,.55); box-shadow:inset 0 1px 4px rgba(0,0,0,.5) }

/* ---- ECRANS PEU HAUTS (paysage, < 820 px) : COMPACTER plutot que REDUIRE ----
   Mesure en 1280x720 : le plateau tombait a l'echelle 0.447 et les stats a 5,3 px REELS.
   Reduire davantage rend tout illisible ; on diminue donc les tailles a la SOURCE pour que
   fitBoard n'ait presque plus a reduire. 1280x720 est une resolution tres courante. */
@media (orientation:landscape) and (max-height:820px){
  :where(#bbRoot, .bb-skin) .card{ width:132px }
  :where(#bbRoot, .bb-skin) .card.active{ width:158px }
  :where(#bbRoot, .bb-skin) .half{ padding:14px 16px; gap:8px }
  :where(#bbRoot, .bb-skin) .half.opp{ padding-bottom:20px } :where(#bbRoot, .bb-skin) .half.me{ padding-top:20px }
  :where(#bbRoot, .bb-skin) .half.opp .row + .row, :where(#bbRoot, .bb-skin) .half.me .row + .row{ margin-top:6px }
  :where(#bbRoot, .bb-skin) .row{ gap:14px }
  :where(#bbRoot, .bb-skin) .ms-empty, :where(#bbRoot, .bb-skin) .ms-card{ width:clamp(96px, 11vh, 124px) }
  :where(#bbRoot, .bb-skin) .glass{ width:28px; height:62px }
  :where(#bbRoot, .bb-skin) .flank{ width:140px }
  :where(#bbRoot, .bb-skin) .half.me .flank{ left:calc(50% + 250px) } :where(#bbRoot, .bb-skin) .half.opp .flank{ right:calc(50% + 250px) }
  :where(#bbRoot, .bb-skin) .half.me .masterslot{ right:calc(50% + 250px) } :where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:calc(50% + 250px) }
  :where(#bbRoot, .bb-skin) .card .nm{ font-size:.9rem } :where(#bbRoot, .bb-skin) .card.active .nm{ font-size:1.04rem }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.82rem } :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.88rem }
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.78rem } :where(#bbRoot, .bb-skin) .card.active .st{ font-size:.84rem }
  :where(#bbRoot, .bb-skin) .ms-nm{ font-size:.92rem }
}

/* ==========================================================================
   PORTRAIT — REAFFIRME EN DERNIER (2e fois : le piege s'est reproduit)
   Les tailles de texte remontees pour compenser la mise a l'echelle du bureau
   ecrasaient le bloc portrait -> en 390x844 : textes a 14,7 px sur des cartes de
   114 px, et 80 px de debordement. TOUTE nouvelle regle de taille doit etre
   ajoutee AVANT ce bloc, jamais apres.
   ========================================================================== */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .card .nm{ font-size:.55rem; bottom:24px }
  :where(#bbRoot, .bb-skin) .card.active .nm{ font-size:.66rem; bottom:27px }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.42rem; bottom:15px; letter-spacing:.09em }
  :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.47rem; bottom:18px }
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.43rem; gap:5px }
  :where(#bbRoot, .bb-skin) .card.active .st{ font-size:.48rem; gap:6px }
  :where(#bbRoot, .bb-skin) .ms-nm{ font-size:.62rem; bottom:14px }
  :where(#bbRoot, .bb-skin) .ms-pas{ font-size:.42rem }
  /* la maitresse gardait un scale(.62) EN PLUS de sa largeur -> elle tombait a 49 % d'une
     carte de banc. La largeur suffit : c'est une carte, elle doit en avoir le format. */
  /* MAITRESSES : mesure -> celle de l'adversaire sortait du tapis (366→431 pour un tapis
     qui s'arrete a 382). En portrait le tapis fait 100vw et la perspective retrecit les
     bords : on les ancre en POURCENTAGE, pas en pixels, et on borne leur largeur. */
  :where(#bbRoot, .bb-skin) .masterslot{ transform:none }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform:rotate(180deg) }
  /* ANCRAGE AU CENTRE, pas au bord : le tapis est incline (perspective) et `overflow:hidden`
     coupe ce qui depasse — une maitresse posee a 4 % du bord se retrouvait rognee (mesure :
     366→431 pour un tapis s'arretant a 382). Ancree au centre, elle suit le retrecissement. */
  :where(#bbRoot, .bb-skin) .half.me  .masterslot{ left:calc(50% - 158px); right:auto }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ left:auto; right:calc(50% - 158px) }
  :where(#bbRoot, .bb-skin) .ms-card, :where(#bbRoot, .bb-skin) .ms-empty{ width:min(64px, 17vw) }
  /* stats mesurees a 6,2 px REELS (l'echelle portrait vaut ~0.81) : sous le seuil de lecture */
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.56rem; gap:4px }
  :where(#bbRoot, .bb-skin) .card.active .st{ font-size:.62rem; gap:5px }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.52rem }
  :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.58rem }
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-turnnum{ font-size:.6rem }
  :where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ font-size:.56rem }
  :where(#bbRoot, .bb-skin) .elan .lbl{ font-size:.45rem }
  :where(#bbRoot, .bb-skin) .elan .pct{ font-size:.72rem }
  :where(#bbRoot, .bb-skin) .glass{ width:24px; height:54px }
  :where(#bbRoot, .bb-skin) .ms-card{ width:clamp(64px, 8vh, 88px) }
}

/* Le plateau se recale quand le menu d'attaques s'ouvre/se ferme : transition pour que
   ce soit un GLISSEMENT et non un saut (le saut a chaque tour avait deja ete signale). */
/* ⚠️ PAS DE TRANSITION SUR .scene — supprimee le 2026-07-23.
   fitBoard remet `transform` a vide, LIT `offsetHeight` (ce qui force un recalcul de style),
   puis la reapplique : le navigateur voit donc none -> scale(k) a CHAQUE redessin et
   redeclenche la transition en boucle. Mesure : 2 animations en cours en permanence et une
   transformation calculee bloquee a l'identite, donc un plateau JAMAIS mis a l'echelle
   (menu rejete 392 px hors de l'ecran). C'etait aussi une cause du « toutes les cartes
   bougent » : c'est le plateau entier qui s'animait a chaque tour. */

/* ==========================================================================
   v12 — LE TAPIS REDEVIENT UN SEUL OBJET
   ========================================================================== */
/* Le camp actif portait un CADRE INTERIEUR de 5 px : ca decoupait le plateau en DEUX
   boites au lieu d'un tapis. On remplace par une teinte + une lueur diffuse, sans arete. */
:where(#bbRoot, .bb-skin) .half.turnactive{ box-shadow:none; animation:none }
:where(#bbRoot, .bb-skin) .half.me.turnactive{
  background-image:radial-gradient(120% 90% at 50% 100%, rgba(120,225,255,.30), transparent 62%),
    repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px),
    linear-gradient(180deg,#101a30,#1c2b4a) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive{
  background-image:radial-gradient(120% 90% at 50% 0%, rgba(255,120,160,.28), transparent 62%),
    repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px),
    linear-gradient(180deg,#3a1c2c,#1a1020) }
/* c'est le CONTOUR DU TAPIS ENTIER qui s'allume : un seul objet, une seule bordure */
:where(#bbRoot, .bb-skin) .mat{ transition:border-color .3s, box-shadow .3s }
:where(#bbRoot, .bb-skin) .mat.turn-me{ border-color:#7fd4ff; box-shadow:0 40px 70px -25px #000, 0 0 26px rgba(120,200,255,.45) }
:where(#bbRoot, .bb-skin) .mat.turn-opp{ border-color:#ff8fa8; box-shadow:0 40px 70px -25px #000, 0 0 26px rgba(255,120,150,.40) }

/* ==========================================================================
   v13 — deux causes precises, trouvees a la mesure
   ========================================================================== */
/* 1) La maitresse adverse sortait du tapis (mesure : 337→401 pour un tapis s'arretant a 381).
   Cause : un `transform-origin: bottom right` residuel. Une rotation de 180 deg autour d'un
   COIN deplace l'element de toute sa largeur ; autour du CENTRE, elle ne bouge pas. */
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform-origin:center center !important }
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform:rotate(180deg); transform-origin:center center }
}

/* 2) Le cadre du camp actif survivait a son annulation : `.half.me.turnactive` (0,3,0) est
   plus specifique que `.half.turnactive` (0,2,0). On annule au meme niveau de specificite. */
:where(#bbRoot, .bb-skin) .half.me.turnactive, :where(#bbRoot, .bb-skin) .half.opp.turnactive{ box-shadow:none }

/* ==========================================================================
   v14 — LES ATTAQUES PAR-DESSUS LE JEU (plus de bande qui prend de la place)
   Elles etaient dans le flux, sous le tapis : ca creait une bande permanente et
   repoussait le plateau. Elles se posent maintenant EN SURIMPRESSION sur le bas du
   plateau, la ou il n'y a que du tapis. Zero place prise, zero vide en bas.
   ========================================================================== */
:where(#bbRoot, .bb-skin) #bbActions{ position:absolute; left:50%; transform:translateX(-50%);
  bottom:8px; top:auto; margin:0; z-index:70;
  width:auto; max-width:min(860px,94vw); padding:8px 10px;
  background:linear-gradient(180deg, rgba(10,14,30,.86), rgba(6,9,20,.94));
  border:1px solid rgba(150,190,255,.28); border-radius:14px;
  box-shadow:0 14px 40px rgba(0,0,0,.6) }
#bbRoot{ position:relative; padding-bottom:0 }
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) #bbActions{ bottom:6px; max-width:96vw; padding:6px 7px }
}

/* ---- PORTRAIT : liberer le bas du tapis pour le menu d'attaques ----
   La bande « Toi + Elan » occupait une RANGEE entiere sous les cartes. Compactee dans le
   coin, elle rend cette place au jeu — et le menu peut s'y poser sans couvrir le banc. */
@media (orientation:portrait) and (max-width:560px){
  /* La bande « Toi + Elan » repasse dans le FLUX : posee en absolu dans un coin, elle
     CHEVAUCHAIT les cartes du banc (constate a l'ecran). Elle reprend sa rangee, compacte. */
  :where(#bbRoot, .bb-skin) .flank{ position:static; width:auto; flex-direction:row; align-items:center;
    gap:6px; margin:0 auto }
  :where(#bbRoot, .bb-skin) .half.me .flank, :where(#bbRoot, .bb-skin) .half.opp .flank{ left:auto; right:auto }
  :where(#bbRoot, .bb-skin) .elan{ gap:5px } :where(#bbRoot, .bb-skin) .elan-txt{ flex-direction:row; align-items:baseline; gap:4px }
  :where(#bbRoot, .bb-skin) .glass{ width:18px; height:40px }
  :where(#bbRoot, .bb-skin) .tag{ font-size:.52rem; padding:1px 7px }
  /* menu compact : une seule rangee d'attaques, pour ne mordre que sur le bas du tapis */
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk{ max-width:150px; padding:4px 7px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ font-size:.72rem }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-line, :where(#bbRoot, .bb-skin) #bbActions .bb-atk-eff{ font-size:.58rem }
}

/* ---- PORTRAIT : menu d'attaques compacte pour tenir sous les cartes ----
   Mesure : le menu descendait a 855 px dans un ecran de 844 (11 px de trop). Les cartes du
   banc se projettent deja 34 px sous le tapis (perspective), il reste donc peu de place. */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) #bbActions{ padding:5px 6px; gap:5px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk{ padding:3px 6px; max-width:140px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ font-size:.68rem; line-height:1.15 }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-line{ font-size:.55rem; line-height:1.1 }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-eff{ font-size:.52rem; line-height:1.1 }
  :where(#bbRoot, .bb-skin) #bbActions .bb-ult{ padding:4px 10px; font-size:.72rem }
}

/* ---- PORTRAIT : PLUS D'INCLINAISON 3D ----
   Sur 390 px de large, la perspective plongeante coute plus qu'elle n'apporte : les cartes
   du bas, plus PROCHES du regard, se projettent SOUS leur position de mise en page (mesure :
   cartes a 744 pour un tapis s'arretant a 686). Tout ce qui suit dans le flux se retrouve
   donc PAR-DESSUS elles a l'ecran — bande « Toi/Elan », menu d'attaques… insoluble tant que
   position calculee et position affichee different. A plat, les deux coincident. */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .scene{ perspective:none }
  :where(#bbRoot, .bb-skin) .mat{ transform:none }
  :where(#bbRoot, .bb-skin) .half.opp .cw{ transform:none }
}

/* La bande « Toi + Elan » gardait un `transform: translateY(-50%)` (heritage de son ancrage
   vertical centre). Repassee en flux, ce decalage la REMONTAIT sur les cartes du banc. */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .flank{ transform:none; top:auto; bottom:auto }
}

/* Les deux attaques COTE A COTE en portrait, comme en horizontal : `.bb-atk` porte un
   `flex:1 1 200px` (feuille d'origine) — deux boutons demandent donc 400 px et passaient
   a la ligne sur 390 px de large. On reduit la base : ils tiennent sur une rangee. */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk{ flex:1 1 130px; min-width:0 }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
}

/* CENTRAGE SANS BRIDER LA LARGEUR.
   `left:50% + translateX(-50%)` sur un element en position absolue limite la largeur
   disponible a la MOITIE du conteneur (mesure : 195 px sur 390) : les deux attaques
   passaient a la ligne alors qu'elles tiennent cote a cote. `left:0; right:0` + marges
   automatiques centrent sans rien brider. */
:where(#bbRoot, .bb-skin) #bbActions{ left:0; right:0; transform:none; width:fit-content; margin-inline:auto }

/* `width:fit-content` restait a 204 px (mesure) : la largeur maximale du contenu se calcule
   sur la rangee interne, elle-meme deja bornee. On donne donc une largeur EXPLICITE en
   portrait, et on interdit le retour a la ligne : les deux attaques partagent la place. */
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) #bbActions{ width:min(374px, 96vw) }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-row{ flex-wrap:nowrap; width:100% }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk{ max-width:none }
}

/* Stats mesurees a 7,9 px reels sur bureau (echelle 0.665) : juste sous le seuil de lecture. */
:where(#bbRoot, .bb-skin) .card .st{ font-size:.74rem }
:where(#bbRoot, .bb-skin) .card.active .st{ font-size:.80rem }

/* ---- ECRANS COURTS : tailles REAFFIRMEES ----
   La regle globale `.card .st` ajoutee plus haut ecrasait le bloc « ecran court » (meme
   specificite, ecrite apres). Mesure en 1280x720 : stats 7,3 px et tour 7,9 px, sous le
   seuil. L'echelle y tombe a 0.571, il faut donc des valeurs source plus genereuses. */
@media (orientation:landscape) and (max-height:820px){
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.88rem } :where(#bbRoot, .bb-skin) .card.active .st{ font-size:.94rem }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.90rem } :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.96rem }
  :where(#bbRoot, .bb-skin) .card .nm{ font-size:.98rem } :where(#bbRoot, .bb-skin) .card.active .nm{ font-size:1.10rem }
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-turnnum{ font-size:1.00rem }
  :where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ font-size:.90rem }
  :where(#bbRoot, .bb-skin) .ms-nm{ font-size:1.00rem }
}

/* ==========================================================================
   ECRANS TRES COURTS (paysage < 560 px de haut) — mobile en paysage surtout.
   Mesure : textes a 3,9 px et cartes de 45 px. Cause STRUCTURELLE : on empile
   [carte active + banc] DEUX fois dans 390 px, soit une hauteur naturelle de 959 px
   pour 258 px disponibles. Meme sans reduire, c'etait perdu.
   Solution : le banc passe A COTE de la carte active (une seule hauteur de carte par
   camp au lieu de deux) et le menu passe EN SURIMPRESSION (plus de bande reservee).
   ========================================================================== */
@media (orientation:landscape) and (max-height:560px){
  :where(#bbRoot, .bb-skin) .half{ flex-direction:row; flex-wrap:nowrap; align-items:center; justify-content:center;
    gap:10px; padding:6px 10px }
  :where(#bbRoot, .bb-skin) .half.opp{ padding-bottom:8px } :where(#bbRoot, .bb-skin) .half.me{ padding-top:8px }
  :where(#bbRoot, .bb-skin) .row{ gap:6px; margin:0 !important }
  :where(#bbRoot, .bb-skin) .card{ width:74px } :where(#bbRoot, .bb-skin) .card.active{ width:88px }
  :where(#bbRoot, .bb-skin) .ms-card, :where(#bbRoot, .bb-skin) .ms-empty{ width:62px }
  :where(#bbRoot, .bb-skin) .masterslot{ position:static; transform:none }
  :where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform:rotate(180deg) }
  :where(#bbRoot, .bb-skin) .flank{ position:static; width:auto; flex-direction:column; gap:2px; transform:none }
  :where(#bbRoot, .bb-skin) .glass{ width:16px; height:34px }
  :where(#bbRoot, .bb-skin) .tag{ font-size:.5rem; padding:1px 6px }
  /* textes : l'echelle remonte a ~0.6, il faut des valeurs source generees en consequence */
  :where(#bbRoot, .bb-skin) .card .nm{ font-size:1.05rem; bottom:22px } :where(#bbRoot, .bb-skin) .card.active .nm{ font-size:1.15rem; bottom:25px }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.98rem; bottom:12px } :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:1.04rem; bottom:14px }
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.94rem; gap:5px } :where(#bbRoot, .bb-skin) .card.active .st{ font-size:1.00rem; gap:6px }
  :where(#bbRoot, .bb-skin) .card .hp b{ font-size:1.05rem } :where(#bbRoot, .bb-skin) .card.active .hp b{ font-size:1.15rem }
  :where(#bbRoot, .bb-skin) .ms-nm{ font-size:1.00rem } :where(#bbRoot, .bb-skin) .ms-pas{ display:none }
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-turnnum{ font-size:1.05rem }
  :where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ font-size:.95rem }
  :where(#bbRoot, .bb-skin) .elan .lbl{ font-size:.8rem } :where(#bbRoot, .bb-skin) .elan .pct{ font-size:1.15rem }
  /* menu EN SURIMPRESSION : il ne prend plus de hauteur */
  :where(#bbRoot, .bb-skin) #bbActions{ padding:4px 6px; gap:4px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk{ max-width:150px; padding:3px 6px }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ font-size:.92rem } 
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-line{ font-size:.78rem } :where(#bbRoot, .bb-skin) #bbActions .bb-atk-eff{ font-size:.74rem }
}

/* ---- ECRANS TRES COURTS : correction des tailles et du recouvrement ----
   La disposition en rangee a supprime le besoin de reduire (echelle 1.01 au lieu de 0.26) :
   les tailles calculees pour une echelle de 0.6 debordaient donc des cartes (mesure : 16 px
   de texte sur une carte de 94 px). Valeurs recalculees pour une echelle de 1. */
@media (orientation:landscape) and (max-height:560px){
  :where(#bbRoot, .bb-skin) .card .nm{ font-size:.56rem; bottom:19px } :where(#bbRoot, .bb-skin) .card.active .nm{ font-size:.62rem; bottom:21px }
  :where(#bbRoot, .bb-skin) .card .rar{ font-size:.50rem; bottom:11px } :where(#bbRoot, .bb-skin) .card.active .rar{ font-size:.54rem; bottom:12px }
  :where(#bbRoot, .bb-skin) .card .st{ font-size:.50rem; gap:4px } :where(#bbRoot, .bb-skin) .card.active .st{ font-size:.54rem; gap:5px }
  :where(#bbRoot, .bb-skin) .card .hp b{ font-size:.62rem } :where(#bbRoot, .bb-skin) .card.active .hp b{ font-size:.68rem }
  :where(#bbRoot, .bb-skin) .card .hp i{ font-size:.42rem }
  :where(#bbRoot, .bb-skin) .ms-nm{ font-size:.52rem; bottom:8px }
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar .bb-turnnum{ font-size:.60rem }
  :where(#bbRoot, .bb-skin) .turnbar .bb-forfeit{ font-size:.56rem; padding:2px 7px }
  :where(#bbRoot, .bb-skin) .elan .lbl{ font-size:.48rem } :where(#bbRoot, .bb-skin) .elan .pct{ font-size:.62rem }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-name{ font-size:.60rem }
  :where(#bbRoot, .bb-skin) #bbActions .bb-atk-line{ font-size:.50rem } :where(#bbRoot, .bb-skin) #bbActions .bb-atk-eff{ font-size:.48rem }

  /* la barre de tour recouvrait la maitresse adverse (elle est absolue en haut a gauche,
     et le camp adverse commence desormais par sa maitresse au meme endroit).
     On la fait courir SUR TOUTE la largeur et le contenu demarre en dessous. */
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar{ left:0; right:0; top:0; width:auto; max-width:none; border-radius:0 0 10px 10px;
    justify-content:center; padding:3px 8px }
  :where(#bbRoot, .bb-skin) .mat > .bb-menu{ top:2px; left:6px; width:26px; height:26px; font-size:.85rem }
  :where(#bbRoot, .bb-skin) .mat > .bb-opts{ top:32px; left:6px }
  :where(#bbRoot, .bb-skin) .half.opp{ padding-top:32px }
}

/* ═══════════ VFX « AAA » (2026-07-26) ═══════════
   1) PROJECTILES ELEMENTAIRES : orbes en position:fixed dans <body> (coordonnees ECRAN,
      hors de la scene inclinee) — un style par element + traine de particules.
   2) HOLO DE RARETE : reflet anime sur la carte ACTIVE des hautes raretes.
   3) AMBIANCES DE TAPIS : derive lente du motif (background-position par COUCHE :
      la teinte de camp et le fond restent immobiles, seul le motif vit). */
:where(#bbRoot, .bb-skin) .bb-orb{ position:fixed; z-index:400; width:26px; height:26px; border-radius:50%;
  pointer-events:none; will-change:transform;
  background:radial-gradient(circle at 38% 34%, #fff, var(--oc,#cfd8ff) 45%, transparent 72%);
  box-shadow:0 0 14px 3px var(--og,rgba(190,205,255,.75)), 0 0 34px 10px var(--og2,rgba(190,205,255,.30)) }
:where(#bbRoot, .bb-skin) .bb-orb-big{ width:38px; height:38px }
:where(#bbRoot, .bb-skin) .bb-orb-trail{ position:fixed; z-index:399; width:9px; height:9px; border-radius:50%;
  pointer-events:none; transform:translate(-50%,-50%);
  background:var(--oc,#cfd8ff); opacity:.75; box-shadow:0 0 10px 2px var(--og,rgba(190,205,255,.6));
  animation:orbTrailFade .42s ease-out forwards }
@keyframes orbTrailFade{ to{ opacity:0; transform:translate(-50%,-50%) scale(.3) } }
:where(#bbRoot, .bb-skin) .bb-orb-fire{ --oc:#ff8a50; --og:rgba(255,110,40,.85); --og2:rgba(255,90,20,.35) }
:where(#bbRoot, .bb-skin) .bb-orb-water{ --oc:#4fc3f7; --og:rgba(60,170,240,.85); --og2:rgba(60,170,240,.35); border-radius:58% 42% 60% 40%/60% 55% 45% 40% }
:where(#bbRoot, .bb-skin) .bb-orb-lightning{ --oc:#ffe95c; --og:rgba(255,230,80,.9); --og2:rgba(255,230,80,.35) }
:where(#bbRoot, .bb-skin) .bb-orb-ice{ --oc:#b3e5fc; --og:rgba(160,220,255,.85); --og2:rgba(160,220,255,.35); border-radius:18%; transform:rotate(45deg) }
:where(#bbRoot, .bb-skin) .bb-orb-nature{ --oc:#81c784; --og:rgba(100,200,110,.85); --og2:rgba(100,200,110,.35); border-radius:70% 30% 65% 35%/55% 60% 40% 45% }
:where(#bbRoot, .bb-skin) .bb-orb-dark{ --oc:#7e57c2; --og:rgba(110,60,190,.85); --og2:rgba(90,40,160,.4);
  background:radial-gradient(circle at 38% 34%, #2a1745, #12081f 55%, transparent 75%) }
:where(#bbRoot, .bb-skin) .bb-orb-light{ --oc:#fff6c9; --og:rgba(255,240,170,.95); --og2:rgba(255,240,170,.4) }
:where(#bbRoot, .bb-skin) .bb-orb-wind{ --oc:#c5f2e6; --og:rgba(150,230,205,.7); --og2:rgba(150,230,205,.28);
  background:radial-gradient(circle at 50% 50%, transparent 30%, rgba(220,255,245,.85) 42%, transparent 60%) }
:where(#bbRoot, .bb-skin) .bb-orb-earth{ --oc:#bc8b5a; --og:rgba(160,110,60,.8); --og2:rgba(130,90,50,.35); border-radius:42% 58% 50% 50%/55% 42% 58% 45% }
:where(#bbRoot, .bb-skin) .bb-orb-generic{ --oc:#e8ecf7; --og:rgba(220,228,247,.8); --og2:rgba(220,228,247,.3) }

/* HOLO DE RARETE : balayage lumineux en boucle sur la carte ACTIVE (mythique et au-dela +
   legendaire, plus discret). Un seul element anime a l'ecran -> zero souci de perf. */
:where(#bbRoot, .bb-skin) .card.active.rar-legendary::after, :where(#bbRoot, .bb-skin) .card.active.rar-mythic::after, :where(#bbRoot, .bb-skin) .card.active.rar-divine::after, :where(#bbRoot, .bb-skin) .card.active.rar-celestial::after{
  content:""; position:absolute; inset:0; z-index:6; border-radius:inherit; pointer-events:none;
  background:linear-gradient(115deg, transparent 32%, rgba(255,255,255,.14) 44%,
    rgba(255,255,255,.30) 50%, rgba(255,255,255,.14) 56%, transparent 68%);
  background-size:280% 100%; mix-blend-mode:screen;
  animation:holoSweep 3.4s cubic-bezier(.5,.1,.5,.9) infinite }
:where(#bbRoot, .bb-skin) .card.active.rar-legendary::after{ animation-duration:4.6s; opacity:.6 }
:where(#bbRoot, .bb-skin) .card.active.rar-divine::after{
  background:linear-gradient(115deg, transparent 30%, rgba(255,170,250,.18) 44%,
    rgba(210,180,255,.34) 50%, rgba(160,220,255,.18) 56%, transparent 70%);
  background-size:280% 100% }
:where(#bbRoot, .bb-skin) .card.active.rar-celestial::after{
  background:linear-gradient(115deg, transparent 28%, rgba(140,255,255,.20) 42%,
    rgba(255,255,255,.36) 50%, rgba(190,160,255,.20) 58%, transparent 72%);
  background-size:280% 100%; animation-duration:2.8s }
@keyframes holoSweep{ 0%{ background-position:120% 0 } 55%{ background-position:-60% 0 } 100%{ background-position:-60% 0 } }

/* AMBIANCES DE TAPIS : seule la COUCHE MOTIF derive (position par couche :
   camp fixe / motif anime / fond fixe). Lent et discret — un tapis vit, il ne clignote pas. */
:where(#bbRoot, .bb-skin) .half.matskin-nebuleuse{ animation:matDrift 90s linear infinite }
:where(#bbRoot, .bb-skin) .half.matskin-ocean{ animation:matDrift 60s linear infinite }
:where(#bbRoot, .bb-skin) .half.matskin-foret{ animation:matDrift 120s linear infinite }
@keyframes matDrift{
  from{ background-position:50% 0%, 0px 0px, 0 0 }
  to  { background-position:50% 0%, 340px 180px, 0 0 }
}
/* Volcan : les braises PULSENT (halo interieur chaud qui respire). */
:where(#bbRoot, .bb-skin) .half.matskin-volcan{ animation:matEmber 5.5s ease-in-out infinite alternate }
@keyframes matEmber{
  from{ box-shadow:inset 0 0 60px -30px rgba(255,90,20,.18) }
  to  { box-shadow:inset 0 0 90px -25px rgba(255,120,40,.34) }
}
/* Accessibilite : pas d'animations decoratives si l'utilisateur les refuse. */
@media (prefers-reduced-motion: reduce){
  :where(#bbRoot, .bb-skin) .half[class*="matskin-"]{ animation:none }
  :where(#bbRoot, .bb-skin) .card.active[class*="rar-"]::after{ animation:none; content:none }
}
/* Le pulse volcan cede la place au halo de tour (les deux vivent sur box-shadow inset). */
:where(#bbRoot, .bb-skin) .half.matskin-volcan.turnactive{ animation:none }

/* ═══════════ INTRO PAR TAPIS + PARALLAXE DES ARTS (2026-07-26) ═══════════ */
/* Balayage lumineux one-shot a l'entree du plateau (une passe par moitie). */
:where(#bbRoot, .bb-skin) .mat-intro-sweep{ position:absolute; inset:0; z-index:4; pointer-events:none; overflow:hidden;
  background:linear-gradient(105deg, transparent 30%, rgba(255,255,255,.10) 46%,
    rgba(255,255,255,.22) 50%, rgba(255,255,255,.10) 54%, transparent 70%);
  background-size:260% 100%; background-position:130% 0;
  animation:matSweep 1.15s cubic-bezier(.4,.1,.4,1) forwards }
@keyframes matSweep{ to{ background-position:-130% 0 } }
/* Particules d'entree (braises/flocons/etoiles selon le tapis) — animees en WAAPI. */
:where(#bbRoot, .bb-skin) .mat-intro-p{ position:absolute; z-index:4; pointer-events:none; line-height:1;
  text-shadow:0 0 8px currentColor; opacity:0; user-select:none }

/* PARALLAXE + RESPIRATION de l'art des cartes ACTIVES : zoom lent alterne (keyframes)
   + suivi de souris via --px/--py — les keyframes LISENT les variables, donc les deux
   effets se cumulent sans se battre. scale >= 1.045 : jamais de bord d'image visible. */
:where(#bbRoot, .bb-skin) .card.active img{ will-change:transform;
  animation:artBreathe 7s ease-in-out infinite alternate }
@keyframes artBreathe{
  from{ transform:translate(var(--px,0px), var(--py,0px)) scale(1.045) }
  to  { transform:translate(var(--px,0px), var(--py,0px)) scale(1.085) }
}
@media (prefers-reduced-motion: reduce){
  :where(#bbRoot, .bb-skin) .card.active img{ animation:none }
  :where(#bbRoot, .bb-skin) .mat-intro-sweep, :where(#bbRoot, .bb-skin) .mat-intro-p{ display:none }
}

/* ═══════════ RETOURS PLAYTEST ADMIN (2026-07-26) ═══════════ */
/* 1. Le menu d'attaques est un TIROIR DU PLATEAU : meme cadre que le jeu (bord assorti,
   angles bas arrondis, fond verre), et bbPlaceActions le fait chevaucher le bord bas. */
:where(#bbRoot, .bb-skin) #bbActions{ border:2px solid #3d5a8a; border-top:none; border-radius:0 0 18px 18px;
  background:linear-gradient(180deg, rgba(10,14,26,.55), rgba(8,10,20,.94) 55%);
  backdrop-filter:blur(7px); box-shadow:0 18px 34px -18px #000 }
/* 2. COINS ARRONDIS du contour de tour : l'anneau (box-shadow inset) suit desormais la
   courbure du plateau — les moities heritent du rayon du .mat (20px - 2px de bord). */
:where(#bbRoot, .bb-skin) .half.opp{ border-radius:18px 18px 0 0 }
:where(#bbRoot, .bb-skin) .half.me{ border-radius:0 0 18px 18px }
/* 3. VERRE D'ELAN : la vague chevauche le haut du liquide de 3px — plus de couture entre
   la surface et la jauge (les deux hauteurs s'arrondissaient au pixel pres, chacun de
   son cote, et laissaient un trait). */
/* ⚠️ HAUTEUR PROPORTIONNELLE, PAS ABSOLUE (retour admin 2026-08-07, capture à l'appui :
   « la jauge est marquée d'une ligne de pixel mal positionnée ou qui n'a rien à faire là »).
   Ce `height:10px` était FIXE alors que le tube, lui, rétrécit à chaque palier — mesuré
   sur le vrai CSS, à 95 % de remplissage :
       bureau  76px → 13 %      ≤1200px 62px → 16 %      ≤1000px 54px → 19 %
       ≤760px  40px → 25 %      ≤420px  34px → 29 %
   À 13 % la vague se lit comme la SURFACE d'un liquide. À 29 % elle occupe presque un
   tiers du verre : l'œil n'y voit plus une surface mais un trait clair posé en travers,
   et c'est exactement ce que l'admin voit sur son téléphone. Le défaut ne se voyait pas
   au bureau — d'où quatre relectures qui l'ont manqué.
   Ce n'est PAS la couture transparente du PLAYTEST v19 : celle-là est toujours corrigée
   (la vague mord d'1 px sur le liquide, vérifié à 8 niveaux de remplissage).
   13 % garde le rendu du bureau au pixel près (13 % de 76 = 9,9 px, contre 10 avant) et
   ramène le téléphone à ~4,4 px. Le plancher de 3 px évite qu'elle disparaisse tout à
   fait sur les très petits écrans. */
:where(#bbRoot, .bb-skin) .glass-wave{ height:max(3px, 13%) } /* `bottom` unifié en fin de fichier (voir PLAYTEST v19) */
/* 4. EFFETS D'ATTAQUE EN COULEUR : vert = aide le lanceur, orange = nuit a la cible,
   dore = bonus de critique. Menu d'attaques ET fiche de carte. */
:where(#bbRoot, .bb-skin) .bb-atk-eff.eff-buff, :where(#bbRoot, .bb-skin) .bb-inspect-atk .ad.eff-buff{ color:#7ef2a8 }
:where(#bbRoot, .bb-skin) .bb-atk-eff.eff-debuff, :where(#bbRoot, .bb-skin) .bb-inspect-atk .ad.eff-debuff{ color:#ffab76 }
:where(#bbRoot, .bb-skin) .bb-atk-eff.eff-crit, :where(#bbRoot, .bb-skin) .bb-inspect-atk .ad.eff-crit{ color:#ffd76a }
/* 5. MINUTEUR DE TOUR dans la boite de tour ; alerte sous 10 s. */
:where(#bbRoot, .bb-skin) #bbTurnLeft{ margin-left:10px; font-weight:900; font-size:.8rem; color:#cfd6f2;
  padding:2px 8px; border-radius:999px; background:rgba(0,0,0,.35); border:1px solid rgba(255,255,255,.14) }
:where(#bbRoot, .bb-skin) #bbTurnLeft.late{ color:#ff8a80; border-color:rgba(255,110,110,.6); animation:turnLate 1s steps(2) infinite }
@keyframes turnLate{ 50%{ background:rgba(255,60,60,.28) } }
/* 6. IDENTITE DU JOUEUR dans l'intro VS : avatar (image Twitch si dispo, sinon initiale). */
:where(#bbRoot, .bb-skin) .bi-idrow{ display:flex; align-items:center; gap:9px; margin-bottom:10px }
:where(#bbRoot, .bb-skin) .bi-ava{ width:44px; height:44px; border-radius:50%; overflow:hidden; flex:0 0 auto;
  display:flex; align-items:center; justify-content:center; font-weight:900; font-size:1.2rem;
  color:#fff; background:linear-gradient(135deg,#2a3558,#161c30);
  border:2px solid rgba(190,205,255,.55); box-shadow:0 0 14px -4px rgba(190,205,255,.7) }
:where(#bbRoot, .bb-skin) .bi-ava img{ width:100%; height:100%; object-fit:cover }
/* Respiration adoucie (le suivi souris a ete retire — cf. combat-arena.html). */
@keyframes artBreathe{
  from{ transform:scale(1.04) }
  to  { transform:scale(1.07) }
}

/* ═══════════ RETOURS PLAYTEST v2 (2026-07-26) ═══════════ */
/* 1. PASTILLES D'ETAT sur les cartes : rouge = malus, vert = bonus, element = empreinte.
   Colonne sous le badge d'element, lisible meme plateau reduit. */
:where(#bbRoot, .bb-skin) .stpills{ position:absolute; left:4px; top:32px; z-index:5; display:flex; flex-direction:column;
  gap:3px; align-items:flex-start; pointer-events:none; max-width:92% }
:where(#bbRoot, .bb-skin) .card.active .stpills{ top:38px }
:where(#bbRoot, .bb-skin) .bb-st{ display:inline-flex; align-items:center; gap:4px; padding:2px 7px; border-radius:999px;
  font-size:.6rem; line-height:1.1; background:rgba(8,10,20,.78); border:1px solid rgba(255,255,255,.18);
  text-shadow:0 1px 2px #000; backdrop-filter:blur(3px) }
:where(#bbRoot, .bb-skin) .card.active .bb-st{ font-size:.68rem }
:where(#bbRoot, .bb-skin) .bb-st b{ font-weight:800; color:#fff }
:where(#bbRoot, .bb-skin) .bb-st.st-buff{ border-color:rgba(105,240,174,.65); box-shadow:0 0 8px -2px rgba(105,240,174,.5) }
:where(#bbRoot, .bb-skin) .bb-st.st-debuff{ border-color:rgba(255,110,90,.7); box-shadow:0 0 8px -2px rgba(255,110,90,.55);
  background:rgba(60,12,8,.8) }
:where(#bbRoot, .bb-skin) .bb-st.st-mark{ border-color:var(--el,#29b6f6); box-shadow:0 0 8px -2px var(--el,#29b6f6) }
/* 2. ANNONCE D'ATTAQUE : le nom flotte sur l'attaquant au depart du coup. */
:where(#bbRoot, .bb-skin) .bb-actname{ font-weight:900; font-size:.9rem; color:#ffe9ad; letter-spacing:.03em;
  text-shadow:0 0 10px rgba(255,215,106,.6), 0 2px 4px #000; white-space:nowrap }
/* 3. MENU D'ATTAQUES EN SURVOL au-dessus de la carte active : panneau flottant a degrade
   leger (dissocie des cartes), tous coins arrondis — plus un tiroir de bord. */
:where(#bbRoot, .bb-skin) #bbActions{ border:1px solid rgba(140,170,230,.35); border-radius:14px;
  background:linear-gradient(180deg, rgba(16,22,40,.86), rgba(8,10,20,.94));
  box-shadow:0 14px 34px -12px #000, 0 0 24px -10px rgba(120,160,255,.45) }
/* 4. CONTOUR DE TOUR : anneau NET autour du tapis du joueur actif — y compris la COUTURE
   centrale entre les deux camps — couleur PERSONNALISABLE (--turnMe/--turnOpp, options ☰).
   En fin de fichier : prime sur les variantes de mise en page plus haut. */
#bbRoot{ --turnMe:#7fd4ff; --turnOpp:#ff8fa8 }
:where(#bbRoot, .bb-skin) .half.me.turnactive{ box-shadow:
  inset 0 0 0 4px var(--turnMe,#7fd4ff),
  inset 0 0 64px -14px color-mix(in srgb, var(--turnMe,#7fd4ff) 55%, transparent) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive{ box-shadow:
  inset 0 0 0 4px var(--turnOpp,#ff8fa8),
  inset 0 0 64px -14px color-mix(in srgb, var(--turnOpp,#ff8fa8) 55%, transparent) }
:where(#bbRoot, .bb-skin) .mat.turn-me{ border-color:var(--turnMe,#7fd4ff) }
:where(#bbRoot, .bb-skin) .mat.turn-opp{ border-color:var(--turnOpp,#ff8fa8) }

/* ═══════════ RETOURS PLAYTEST v3 (2026-07-26) ═══════════ */
/* COHERENCE OVERLAY <-> JEU : le voile bas des cartes du plateau est TEINTE a la couleur
   de rarete, exactement comme la carte de spawn de l'overlay (degrade bas -> nom, tres
   transparent en haut). Une seule identite visuelle partout. */
:where(#bbRoot, .bb-skin) .card .scrim{ background:linear-gradient(to top,
  color-mix(in srgb, var(--rc,#888) 52%, #05070f) 0%,
  color-mix(in srgb, var(--rc,#888) 26%, rgba(6,8,16,.38)) 42%,
  transparent 75%) }
/* Pastille de PASSIF (permanente, doree) — complement des pastilles d'etat. */
:where(#bbRoot, .bb-skin) .bb-st.st-pass{ border-color:rgba(255,215,106,.6); box-shadow:0 0 8px -2px rgba(255,215,106,.5) }
:where(#bbRoot, .bb-skin) .bb-st.st-pass b{ color:#ffe9ad }
/* Citation dans la fiche de carte (meme matiere que l'overlay de spawn). */
:where(#bbRoot, .bb-skin) .bb-inspect-quote{ font-style:italic; font-size:.72rem; color:#aab3d4; text-align:center;
  margin:4px 12px 2px; line-height:1.35 }

/* ═══════════ POLISH v5 : ULTIME + REACTION + AIDE (2026-07-26) ═══════════ */
/* Flash dore plein plateau quand une ULTIME frappe. */
:where(#bbRoot, .bb-skin) .bb-ultflash{ position:absolute; inset:0; z-index:120; pointer-events:none; border-radius:inherit;
  background:radial-gradient(120% 100% at 50% 50%, rgba(255,225,130,.42), rgba(255,190,60,.18) 55%, transparent 80%);
  animation:ultFlash .65s ease-out forwards }
@keyframes ultFlash{ 0%{ opacity:0 } 18%{ opacity:1 } 100%{ opacity:0 } }
/* Banniere centrale de REACTION — grande, brulante, breve. */
:where(#bbRoot, .bb-skin) .bb-reactbanner{ position:absolute; left:50%; top:44%; transform:translate(-50%,-50%) scale(.6);
  z-index:130; pointer-events:none; font-weight:900; font-size:clamp(1.3rem,4vw,2.2rem);
  letter-spacing:.12em; color:#ffe9ad; white-space:nowrap;
  text-shadow:0 0 24px rgba(255,215,106,.85), 0 0 60px rgba(255,160,40,.5), 0 3px 8px #000;
  animation:reactBanner 1.25s cubic-bezier(.2,1.4,.4,1) forwards }
@keyframes reactBanner{
  0%{ transform:translate(-50%,-50%) scale(.5); opacity:0 }
  18%{ transform:translate(-50%,-50%) scale(1.12); opacity:1 }
  30%{ transform:translate(-50%,-50%) scale(1) }
  78%{ opacity:1 }
  100%{ transform:translate(-50%,-56%) scale(1); opacity:0 }
}
/* Bouton large du menu Options (Regles rapides) + liste des regles. */
:where(#bbRoot, .bb-skin) .bb-opt-wide{ display:block; width:100%; margin-top:8px; padding:7px 10px; border-radius:9px;
  border:1px solid #3a4568; background:linear-gradient(180deg,#232a44,#161c30); color:#cfd6f2;
  font-weight:800; cursor:pointer; text-align:center }
:where(#bbRoot, .bb-skin) .bb-opt-wide:hover{ filter:brightness(1.2) }
:where(#bbRoot, .bb-skin) .bb-rules .bb-rules-list{ text-align:left; margin:10px 4px 6px; max-height:52vh; overflow:auto }
:where(#bbRoot, .bb-skin) .bb-rules .bb-rules-list p{ margin:0 0 9px; font-size:.8rem; line-height:1.45; color:#c7cee8 }
:where(#bbRoot, .bb-skin) .bb-rules .bb-rules-list b{ color:#ffe9ad }

/* ═══════════ v6 : ECRAN DE DUEL + TOAST DANS LE COMBAT + PASTILLES CLIQUABLES ═══════════ */
/* Deux panneaux pleine hauteur qui CLAQUENT depuis les cotes, seam diagonale au centre,
   art de maitresse en grand, bandeau de nom incline aux couleurs du joueur, VS geant. */
:where(#bbRoot, .bb-skin) .bi-duel{ position:absolute; inset:0; overflow:hidden; background:#05070f }
:where(#bbRoot, .bb-skin) .bi-panel{ position:absolute; top:0; bottom:0; width:60%; overflow:hidden }
/* 2026-07-28 (retour admin : « le VS n'est pas centré, les deux cartes sont mal
   réparties ») — la diagonale de séparation allait de 60 % en HAUT à 50,4 % en BAS :
   le panneau du joueur mangeait ~10 % de l'écran à l'adversaire, et le « VS » (à 50 %)
   tombait à côté de la jointure. Elle est désormais SYMÉTRIQUE autour de 50 %
   (55 % en haut → 45 % en bas), les deux panneaux occupant la même surface.
   Repères : panneau large de 60 %, `me` ancré à gauche (0→60 %), `opp` à droite
   (40→100 %) — d'où les pourcentages LOCAUX ci-dessous. */
:where(#bbRoot, .bb-skin) .bi-panel.me{ left:0; z-index:2; clip-path:polygon(0 0, 91.7% 0, 75% 100%, 0 100%);
  transform:translateX(-101%); animation:biSlamL .5s cubic-bezier(.2,.9,.3,1) forwards }
:where(#bbRoot, .bb-skin) .bi-panel.opp{ right:0; z-index:1; clip-path:polygon(24% 0, 100% 0, 100% 100%, 7.4% 100%);
  transform:translateX(101%); animation:biSlamR .5s .1s cubic-bezier(.2,.9,.3,1) forwards }
@keyframes biSlamL{ to{ transform:translateX(0) } }
@keyframes biSlamR{ to{ transform:translateX(0) } }
:where(#bbRoot, .bb-skin) .bi-art{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  object-position:center 12%; filter:saturate(1.12) contrast(1.04);
  animation:biArtDrift 3.4s ease-out forwards }
@keyframes biArtDrift{ from{ transform:scale(1.14) } to{ transform:scale(1.02) } }
:where(#bbRoot, .bb-skin) .bi-art.bi-artnone{ display:flex; align-items:center; justify-content:center; font-size:4rem;
  color:#2b3358; background:linear-gradient(180deg,#141a30,#0a0e1e) }
:where(#bbRoot, .bb-skin) .bi-veil{ position:absolute; inset:0;
  background:linear-gradient(180deg, color-mix(in srgb, var(--pc,#7fd4ff) 34%, transparent) 0%, transparent 34%),
             linear-gradient(0deg, rgba(5,7,16,.88) 0%, rgba(5,7,16,.25) 42%, transparent 70%) }
:where(#bbRoot, .bb-skin) .bi-panel.me .bi-veil{ box-shadow:inset -14px 0 40px -18px var(--pc,#7fd4ff) }
:where(#bbRoot, .bb-skin) .bi-panel.opp .bi-veil{ box-shadow:inset 14px 0 40px -18px var(--pc,#ff8fa8) }
:where(#bbRoot, .bb-skin) .bi-nameband{ position:absolute; top:26px; display:flex; align-items:center; gap:12px;
  padding:8px 34px 8px 18px; transform:skewX(-12deg);
  background:linear-gradient(90deg, color-mix(in srgb, var(--pc,#7fd4ff) 82%, #000) , color-mix(in srgb, var(--pc,#7fd4ff) 35%, transparent) 78%, transparent);
  box-shadow:0 6px 22px -8px #000 }
:where(#bbRoot, .bb-skin) .bi-panel.me .bi-nameband{ left:-8px }
:where(#bbRoot, .bb-skin) .bi-panel.opp .bi-nameband{ right:-8px; transform:skewX(-12deg);
  background:linear-gradient(270deg, color-mix(in srgb, var(--pc,#ff8fa8) 82%, #000), color-mix(in srgb, var(--pc,#ff8fa8) 35%, transparent) 78%, transparent);
  padding:8px 18px 8px 34px }
:where(#bbRoot, .bb-skin) .bi-nameband > *{ transform:skewX(12deg) }
:where(#bbRoot, .bb-skin) .bi-pname{ font-weight:900; font-size:clamp(1.1rem,3.4vw,2rem); letter-spacing:.08em;
  text-transform:uppercase; color:#fff; text-shadow:0 2px 6px #000; white-space:nowrap }
:where(#bbRoot, .bb-skin) .bi-mastertag{ position:absolute; bottom:26px; padding:6px 16px; border-radius:999px;
  font-weight:800; font-size:clamp(.8rem,1.8vw,1.05rem); color:#ffe9ad;
  background:rgba(8,10,20,.72); border:1px solid rgba(255,215,106,.5);
  text-shadow:0 1px 3px #000; backdrop-filter:blur(4px) }
:where(#bbRoot, .bb-skin) .bi-panel.me .bi-mastertag{ left:20px }
:where(#bbRoot, .bb-skin) .bi-panel.opp .bi-mastertag{ right:20px }
:where(#bbRoot, .bb-skin) .bi-duel .bi-vs{ position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  z-index:5; font-size:clamp(3rem,9vw,5.4rem); font-weight:900; font-style:italic; color:#ffe9ad;
  text-shadow:0 0 30px rgba(255,215,106,.75), 0 0 80px rgba(255,140,40,.45), 0 4px 10px #000;
  animation:biVsSlam .55s .3s cubic-bezier(.2,1.5,.4,1) backwards }
@keyframes biVsSlam{ from{ transform:translate(-50%,-50%) scale(3) rotate(-8deg); opacity:0 }
  to{ transform:translate(-50%,-50%) scale(1) rotate(0) } }
:where(#bbRoot, .bb-skin) .bi-ember{ position:absolute; bottom:-12px; width:5px; height:5px; border-radius:50%;
  background:#ffb45c; box-shadow:0 0 10px 2px rgba(255,150,60,.7); pointer-events:none;
  animation-name:biEmberUp; animation-timing-function:linear; opacity:.9 }
@keyframes biEmberUp{ to{ transform:translateY(-106vh); opacity:0 } }
/* Toast : DANS le combat (sous la barre de tour), plus jamais hors plateau (ref Pokemon). */
:where(#bbRoot, .bb-skin) .bb-toast{ bottom:auto; top:56px; z-index:135; background:rgba(12,16,32,.94);
  border:1px solid rgba(140,170,230,.45); box-shadow:0 10px 26px -10px #000 }
/* Pastilles cliquables : le clic montre l'explication (le survol n'existe pas sur mobile). */
:where(#bbRoot, .bb-skin) .stpills .bb-st{ pointer-events:auto; cursor:help }
@media (prefers-reduced-motion: reduce){ :where(#bbRoot, .bb-skin) .bi-ember, :where(#bbRoot, .bb-skin) .bi-art{ animation:none } }


/* ==== PLAYTEST v7 : tout l'UTILISABLE s'allume pendant MON tour ==== */
/* La lueur « jouable » RESPIRE (comme le choix de promotion) : une pulsation lente à la
   couleur de rareté — statique, elle passait pour de la décoration. */
:where(#bbRoot, .bb-skin) .card.playable{ animation:usablePulse 1.6s ease-in-out infinite }
:where(#bbRoot, .bb-skin) .card.active.playable{ animation:usablePulseBig 1.6s ease-in-out infinite }
@keyframes usablePulse{
  0%,100%{ box-shadow:0 0 0 2px var(--rc,#fff), 0 0 14px -2px var(--rc,#fff), 0 10px 18px -8px #000 }
  50%{ box-shadow:0 0 0 2.5px var(--rc,#fff), 0 0 30px 0 var(--rc,#fff), 0 10px 18px -8px #000 }
}
@keyframes usablePulseBig{
  0%,100%{ box-shadow:0 0 0 2.5px var(--rc,#fff), 0 0 18px -2px var(--rc,#fff), 0 18px 26px -10px #000 }
  50%{ box-shadow:0 0 0 3px var(--rc,#fff), 0 0 38px 2px var(--rc,#fff), 0 18px 26px -10px #000 }
}
/* MAÎTRESSE prête : aura DORÉE qui respire — « on peut faire quelque chose ici ». */
:where(#bbRoot, .bb-skin) .ms-card.can-abl{ cursor:pointer; animation:ablPulse 1.5s ease-in-out infinite }
@keyframes ablPulse{
  0%,100%{ box-shadow:0 0 0 2px rgba(255,215,120,.75), 0 0 16px -2px rgba(255,200,90,.6) }
  50%{ box-shadow:0 0 0 3px rgba(255,225,140,.95), 0 0 34px 2px rgba(255,205,95,.85) }
}


/* ==== PLAYTEST v8 ==== */
/* PILE OU FACE : pièce 3D aux couleurs des deux camps (vars --turnMe/--turnOpp du plateau). */
:where(#bbRoot, .bb-skin) .bi-coin{ width:clamp(92px,14vh,128px); aspect-ratio:1; perspective:640px }
:where(#bbRoot, .bb-skin) .bi-coin-inner{ position:relative; width:100%; height:100%; transform-style:preserve-3d;
  animation:coinSpin 1s cubic-bezier(.32,.72,.28,1) forwards }
:where(#bbRoot, .bb-skin) .bi-coin.opp .bi-coin-inner{ animation-name:coinSpinOpp }
@keyframes coinSpin{ from{ transform:rotateY(0) } to{ transform:rotateY(1800deg) } }
@keyframes coinSpinOpp{ from{ transform:rotateY(0) } to{ transform:rotateY(1980deg) } }
:where(#bbRoot, .bb-skin) .bi-face{ position:absolute; inset:0; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:2.4rem;
  backface-visibility:hidden; border:4px solid rgba(255,255,255,.28);
  box-shadow:inset 0 0 26px rgba(0,0,0,.5), 0 10px 34px -10px #000 }
:where(#bbRoot, .bb-skin) .bi-face.me{ color:#071c2c;
  background:radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--turnMe,#7fd4ff) 55%, #fff), var(--turnMe,#7fd4ff) 62%, color-mix(in srgb, var(--turnMe,#7fd4ff) 45%, #000)) }
:where(#bbRoot, .bb-skin) .bi-face.opp{ transform:rotateY(180deg); color:#2c0714;
  background:radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--turnOpp,#ff8fa8) 55%, #fff), var(--turnOpp,#ff8fa8) 62%, color-mix(in srgb, var(--turnOpp,#ff8fa8) 45%, #000)) }

/* POPOVER de capacité de maîtresse — ancré à sa carte. */
:where(#bbRoot, .bb-skin) .bb-ablpop{ position:absolute; z-index:70; width:min(280px,46vw); padding:11px 13px; border-radius:12px;
  background:linear-gradient(180deg,rgba(24,31,58,.97),rgba(13,18,38,.99));
  border:1.5px solid rgba(255,216,138,.45);
  box-shadow:0 12px 30px -10px rgba(0,0,0,.8), 0 0 22px -6px rgba(255,190,85,.45);
  animation:apPop .16s ease-out }
@keyframes apPop{ from{ opacity:0; transform:translateY(6px) scale(.96) } }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-name{ font-weight:900; color:#ffe9ad; margin-bottom:4px; font-size:.92rem }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-desc{ font-size:.8rem; color:#dfe6ff; line-height:1.35; margin-bottom:4px }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-note{ font-size:.68rem; color:#9aa6cc; margin-bottom:9px }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-btns{ display:flex; gap:8px }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-use{ flex:1; padding:8px 10px; border-radius:9px; border:1px solid #ffd88a; cursor:pointer;
  background:linear-gradient(180deg,#ffd88a,#f7b04e); color:#3a2405; font-weight:900; font-size:.85rem }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-use:hover{ filter:brightness(1.08) }
:where(#bbRoot, .bb-skin) .bb-ablpop .ap-close{ padding:8px 11px; border-radius:9px; border:1px solid rgba(255,255,255,.16);
  background:rgba(255,255,255,.06); color:#cdd6f4; cursor:pointer }

/* CUT-IN de capacité : bande + portrait + nom — l'action de la maîtresse SE VOIT. */
:where(#bbRoot, .bb-skin) .bb-cutin{ position:absolute; left:0; right:0; top:37%; height:92px; z-index:60; pointer-events:none;
  overflow:hidden; animation:ciFade .25s ease-in 1.25s forwards }
@keyframes ciFade{ to{ opacity:0 } }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-band{ position:absolute; inset:0;
  background:linear-gradient(90deg,transparent, rgba(10,14,30,.94) 16%, rgba(10,14,30,.94) 84%, transparent);
  border-top:1px solid rgba(255,255,255,.18); border-bottom:1px solid rgba(255,255,255,.18);
  transform:scaleX(0); animation:ciBand .22s ease-out forwards }
@keyframes ciBand{ to{ transform:scaleX(1) } }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-inner{ position:relative; height:100%; display:flex; gap:13px; align-items:center; justify-content:center;
  animation:ciSlide .32s cubic-bezier(.2,.9,.25,1) both .08s }
:where(#bbRoot, .bb-skin) .bb-cutin.opp .ci-inner{ animation-name:ciSlideOpp }
@keyframes ciSlide{ from{ transform:translateX(-70px); opacity:0 } to{ transform:none; opacity:1 } }
@keyframes ciSlideOpp{ from{ transform:translateX(70px); opacity:0 } to{ transform:none; opacity:1 } }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-art{ width:64px; height:64px; border-radius:50%; object-fit:cover; object-position:center 18%;
  border:2px solid #ffd88a; box-shadow:0 0 18px -2px rgba(255,190,85,.7); background:#141a30 }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-none{ display:flex; align-items:center; justify-content:center; font-size:1.7rem }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-txt{ display:flex; flex-direction:column; color:#ffe9c4; text-align:left }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-txt b{ font-size:1.02rem; letter-spacing:.4px }
:where(#bbRoot, .bb-skin) .bb-cutin .ci-txt span{ font-size:.8rem; color:#ffd88a; font-weight:700 }

/* MALUS : le flottant COULE en rouge (les bonus montent en vert) + victime maudite. */
#bbRoot .bb-float.malus{ animation:bbFloatSink 1.25s ease-out forwards }
@keyframes bbFloatSink{
  0%   { opacity:0; transform:translate(-50%,-10px) scale(.6) rotate(var(--flip,0deg)) }
  20%  { opacity:1; transform:translate(-50%,4px) scale(1.15) rotate(var(--flip,0deg)) }
  100% { opacity:0; transform:translate(-50%,52px) scale(.92) rotate(var(--flip,0deg)) } }
#bbRoot .bb-float.malus .bb-efftxt{ color:#ff9c9c; font-weight:900 }
#bbRoot .bb-float.malus .bb-eff{ filter:drop-shadow(0 0 8px rgba(255,60,70,.9)) }
#bbRoot .bb-float.boon .bb-efftxt{ color:#9df2b0; font-weight:900 }
#bbRoot .bb-float.boon .bb-eff{ filter:drop-shadow(0 0 8px rgba(80,240,150,.9)) }
#bbRoot .bb-efftxt{ display:inline-block; margin-left:5px; font-size:.85rem; text-shadow:0 2px 4px #000 }
:where(#bbRoot, .bb-skin) .card.bb-cursed{ box-shadow:0 0 0 3px rgba(255,85,102,.8), 0 0 26px -2px rgba(255,51,72,.9) !important;
  filter:saturate(1.25) }

/* PANNEAU D'ATTAQUES façon Pokémon : boîte à bord épais, liste avec curseur ▶. */
:where(#bbRoot, .bb-skin) #bbActions{ height:auto; min-height:0; padding:9px 12px 10px; width:min(660px,92vw);
  background:linear-gradient(180deg,rgba(16,24,50,.96),rgba(10,15,34,.985));
  border:2px solid rgba(214,226,255,.3); border-radius:14px;
  box-shadow:inset 0 0 0 2px rgba(0,0,0,.55), inset 0 0 0 3px rgba(255,255,255,.06), 0 14px 34px -14px rgba(0,0,0,.85) }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-row{ display:grid; grid-template-columns:1fr 1fr; gap:6px 8px; width:100% }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk{ display:flex; flex-direction:column; align-items:flex-start; text-align:left;
  max-width:none; flex:auto; position:relative; padding:6px 10px 6px 24px; border-radius:10px;
  border:1px solid rgba(255,255,255,.14); background:rgba(255,255,255,.05) }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk::before{ content:'▶'; position:absolute; left:8px; top:50%; transform:translateY(-50%);
  font-size:.62rem; color:var(--el,#9fd4ff); opacity:0; transition:opacity .12s }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk:hover::before, :where(#bbRoot, .bb-skin) #bbActions .bb-atk:focus::before{ opacity:1 }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk:hover{ background:rgba(255,255,255,.1) }
:where(#bbRoot, .bb-skin) #bbActions .bb-ult{ width:100%; margin-top:3px }


/* ==== PLAYTEST v9 ==== */
/* DÉGÂTS ADVERSES DANS MON SENS : les cartes adverses ne sont plus retournées (règle
   transform:none) mais les COMPENSATIONS de l'ancien plateau retourné restaient →
   flottants et pastille de capacité à l'envers. On aligne TOUT sur le sens du joueur. */
:where(#bbRoot, .bb-skin) .half.opp .cw{ transform:none !important }
:where(#bbRoot, .bb-skin) .half.opp .masterslot{ transform:none !important }
:where(#bbRoot, .bb-skin) .half.opp .ms-abl{ transform:none !important }
:where(#bbRoot, .bb-skin) .half.opp .bb-float{ --flip:0deg }

/* K.O. : l'écriteau vit DANS la carte (il suit le FLIP) — centré, lisible. */
:where(#bbRoot, .bb-skin) .card .lockicon{ position:absolute; inset:auto 0 42% 0; z-index:6; text-align:center;
  font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:.95rem; letter-spacing:.14em;
  color:#ff9db0; text-shadow:0 2px 0 #000, 0 0 14px rgba(255,60,90,.85) }
:where(#bbRoot, .bb-skin) .cw.locked > .lockicon{ display:none } /* l'ancien écriteau du support ne doit plus jamais s'afficher */

/* DESCRIPTION SUR LA CARTE (réf. overlay) : passif écrit sur la carte active. */
:where(#bbRoot, .bb-skin) .card .carddesc{ position:absolute; left:5px; right:5px; bottom:52px; z-index:3; text-align:center;
  font-size:.46rem; line-height:1.3; font-weight:700; color:#ffe9ad;
  text-shadow:0 1px 3px #000, 0 0 8px #000; pointer-events:none }
:where(#bbRoot, .bb-skin) .card.active .carddesc{ font-size:.52rem; bottom:58px }

/* CUT-IN : le camp est nommé et coloré — la capacité ADVERSE ne se confond plus avec la mienne. */
:where(#bbRoot, .bb-skin) .bb-cutin .ci-side{ font-style:normal; font-size:.66rem; font-weight:800; color:var(--turnMe,#7fd4ff) }
:where(#bbRoot, .bb-skin) .bb-cutin.opp .ci-side{ color:var(--turnOpp,#ff8fa8) }
:where(#bbRoot, .bb-skin) .bb-cutin.opp .ci-band{ background:linear-gradient(90deg,transparent, rgba(34,10,20,.94) 16%, rgba(34,10,20,.94) 84%, transparent) }
:where(#bbRoot, .bb-skin) .bb-cutin.opp .ci-art{ border-color:var(--turnOpp,#ff8fa8); box-shadow:0 0 18px -2px color-mix(in srgb, var(--turnOpp,#ff8fa8) 70%, transparent) }

/* PANNEAU D'ATTAQUES : en bas du plateau, SANS cadre — un dégradé seul le dissocie. */
:where(#bbRoot, .bb-skin) #bbActions{ top:auto; bottom:0; border:none; border-radius:0 0 18px 18px; box-shadow:none;
  width:min(760px,96vw); padding:14px 18px 12px;
  background:linear-gradient(180deg, rgba(8,10,20,0), rgba(8,10,22,.88) 26%, rgba(6,8,18,.97)) }


/* ==== PLAYTEST v10 ==== */
/* Pastilles VRAIMENT discrètes : petites puces en ligne, l'art respire. */
#bbRoot .stpills{ gap:3px }
#bbRoot .bb-st{ padding:2px 5px; font-size:.5rem; border-radius:8px; line-height:1.1 }
#bbRoot .bb-st b{ font-size:.54rem }

/* Panneau d'attaques : compact, centré, dégradé doux — il vit SUR le tapis. */
:where(#bbRoot, .bb-skin) #bbActions{ width:min(600px,86vw); border-radius:12px; padding:10px 14px;
  background:linear-gradient(180deg, rgba(8,10,20,.14), rgba(8,10,22,.82) 34%, rgba(6,8,18,.94));
  backdrop-filter:blur(3px) }


/* ==== PLAYTEST v12 ==== */
/* Bannière d'action AUTOMATIQUE : rouge d'alerte, personne ne peut la rater. */
:where(#bbRoot, .bb-skin) .bb-autobanner{ color:#ffb3b3 !important; border-color:rgba(255,90,100,.65) !important;
  text-shadow:0 2px 0 #000, 0 0 18px rgba(255,60,70,.9) !important; font-size:1.05rem !important }
/* Sous-étiquette de phase (entrée gratuite / échange payant). */
#bbRoot .bb-subtag{ display:block; margin-top:2px; font-size:.62rem; font-weight:700;
  color:#c9d2ee; opacity:.9; text-shadow:0 1px 3px #000 }
/* L'effet de la capacité dans le cut-in. */
:where(#bbRoot, .bb-skin) .bb-cutin .ci-desc{ font-style:normal; font-size:.72rem; color:#dfe6ff; max-width:420px }
:where(#bbRoot, .bb-skin) .bb-cutin{ height:104px }

/* ==== PLAYTEST v13 ==== */
/* Le compte à rebours sous alerte GROSSIT : l'action auto ne doit JAMAIS surprendre. */
:where(#bbRoot, .bb-skin) #bbTurnLeft.late{ font-size:1rem; padding:2px 8px; background:rgba(80,10,16,.55);
  box-shadow:0 0 14px -2px rgba(255,70,80,.7) }


/* ==== PLAYTEST v14 ==== */
/* Bannière verte de DÉBUT DE TOUR : impossible de rater que c'est à soi. */
:where(#bbRoot, .bb-skin) .bb-yourturn{ color:#a5f2be !important; border-color:rgba(90,240,150,.6) !important;
  text-shadow:0 2px 0 #000, 0 0 18px rgba(70,230,140,.9) !important }


/* ==== PLAYTEST v16 ==== */
/* Le verre d'Élan se clique (explication au toast). */
#bbRoot .elan{ pointer-events:auto; cursor:help }

/* Panneau d'attaques : dégradé TEINTÉ à la rareté de la carte active — même langage
   visuel que le scrim des cartes (color-mix avec --rc). */
:where(#bbRoot, .bb-skin) #bbActions{ background:linear-gradient(180deg,
    rgba(8,10,20,0),
    color-mix(in srgb, var(--rc,#3a4a7a) 26%, rgba(8,10,22,.88)) 30%,
    color-mix(in srgb, var(--rc,#3a4a7a) 36%, rgba(6,8,18,.97))) }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk{ border-color:color-mix(in srgb, var(--rc,#fff) 34%, transparent) }

/* Bannières harmonisées : plus de texte nu qui flotte — une plaque de verre sombre
   arrondie, liseré à la couleur du message (même identité que le panneau/les fiches). */
:where(#bbRoot, .bb-skin) .bb-reactbanner{ padding:10px 26px; border-radius:14px;
  background:linear-gradient(180deg, rgba(14,18,38,.92), rgba(8,11,26,.96));
  border:1.5px solid rgba(255,215,106,.5);
  box-shadow:0 14px 40px -12px rgba(0,0,0,.85), 0 0 30px -8px rgba(255,190,80,.5) }
:where(#bbRoot, .bb-skin) .bb-yourturn{ border-color:rgba(90,240,150,.55) !important;
  box-shadow:0 14px 40px -12px rgba(0,0,0,.85), 0 0 30px -8px rgba(70,230,140,.5) !important;
  font-size:1.15rem !important }
:where(#bbRoot, .bb-skin) .bb-autobanner{ border-color:rgba(255,90,100,.6) !important;
  box-shadow:0 14px 40px -12px rgba(0,0,0,.85), 0 0 30px -8px rgba(255,60,70,.55) !important }

/* Étiquettes Passif/Capacité de la maîtresse : deux teintes distinctes, lisibles. */
:where(#bbRoot, .bb-skin) .ms-pas{ color:#ffe9ad }
:where(#bbRoot, .bb-skin) .ms-abl{ color:#cfe0ff }

/* ==== PLAYTEST v18 ==== */
/* CAPACITÉ DE MAÎTRESSE : elle flottait SOUS la carte (« aucun sens » — retour admin).
   Elle vit maintenant DANS la carte, en bandeau bas, comme le passif juste au-dessus. */
:where(#bbRoot, .bb-skin) .ms-card .ms-abl{ position:absolute; left:3px; right:3px; bottom:3px; z-index:4;
  display:block; max-width:none; padding:2px 5px; border-radius:6px;
  font-size:.44rem; letter-spacing:0; line-height:1.2;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
/* …et le passif remonte pour lui laisser la place. */
:where(#bbRoot, .bb-skin) .ms-card .ms-pas{ bottom:17px }
:where(#bbRoot, .bb-skin) .ms-card .ms-nm{ bottom:32px }
/* Prête : le bandeau s'allume (même langage que l'aura dorée de la carte). */
:where(#bbRoot, .bb-skin) .ms-card .ms-abl.rdy{ border-color:rgba(255,215,138,.8) }

/* DESCRIPTION DE CARTE : toute carte active en porte une — son passif, ou son RÔLE.
   Le rôle est en gris clair pour rester secondaire face au doré d'un passif. */
:where(#bbRoot, .bb-skin) .card .carddesc.role{ color:#c3cbe6; font-weight:600 }


/* ==== PLAYTEST v19 ==== */
/* ÉLAN — la vague de surface était posée EXACTEMENT au niveau du liquide : au rendu,
   l'arrondi sous-pixel laissait une ligne transparente d'1 px entre les deux
   (« un espace vide comme un trait de pixel manquant » — retour admin). On la fait
   mordre d'1 px sur le liquide : la surface reste au bon niveau, la couture disparaît. */
/* Couture du verre : la vague mord d'1 px sur le liquide (l'arrondi sous-pixel laissait
   un trait transparent entre les deux). ⚠️ Doit rester la SEULE règle de `bottom` pour
   `.glass-wave` — une plus ancienne à -3px vivait plus haut dans ce fichier. */
:where(#bbRoot, .bb-skin) .glass-wave{ bottom:calc(var(--lvl,0%) - 1px) }
/* VERRE VIDE : pas de liquide, donc pas de surface. Sans ça, la vague décalée sous le
   niveau 0 dessinait une bande violette au fond du tube (retour admin, jauge à 0 %). */
:where(#bbRoot, .bb-skin) .half.elanzero .glass-wave{ display:none }
:where(#bbRoot, .bb-skin) .half.elanzero .glass-liq{ display:none }

/* LA CARTE MONTRE SES ATTAQUES (toutes) — bandeau bas, façon carte de TCG. */
:where(#bbRoot, .bb-skin) .card .cardatks{ position:absolute; left:4px; right:4px; bottom:46px; z-index:3;
  display:flex; flex-direction:column; gap:2px; pointer-events:none }
:where(#bbRoot, .bb-skin) .card .cardatks i{ display:flex; align-items:baseline; justify-content:space-between; gap:4px;
  font-style:normal; padding:1px 5px; border-radius:4px;
  background:linear-gradient(90deg, rgba(6,9,20,.86), rgba(6,9,20,.58));
  border-left:2px solid var(--el,#888) }
/* `flex:1 1 auto` + `min-width:0` (2026-08-01) : sans ça, le nom était le SEUL élément
   compressible de la ligne et la puce d'état l'écrasait à 11 px (« Spores soporifiques »
   réduit à un caractère). Il occupe maintenant la place restante et s'abrège proprement. */
:where(#bbRoot, .bb-skin) .card .cardatks b{ flex:1 1 auto; min-width:0;
  font-size:.44rem; font-weight:800; color:#eef3ff; letter-spacing:.01em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; text-shadow:0 1px 2px #000 }
:where(#bbRoot, .bb-skin) .card .cardatks em{ font-style:normal; font-size:.42rem; font-weight:900; color:var(--el,#cfe0ff); flex:0 0 auto }
:where(#bbRoot, .bb-skin) .card.active .cardatks b{ font-size:.5rem } :where(#bbRoot, .bb-skin) .card.active .cardatks em{ font-size:.48rem }
:where(#bbRoot, .bb-skin) .card.active .cardatks{ bottom:52px }

/* MAÎTRESSE : libellés courts, deux lignes discrètes qui ne mangent plus l'art. */
:where(#bbRoot, .bb-skin) .ms-card .ms-pas, :where(#bbRoot, .bb-skin) .ms-card .ms-abl{ font-size:.42rem; padding:1px 4px }


/* ==== PLAYTEST v20 ==== */
/* LES ATTAQUES FONT PARTIE DE LA CARTE (retour admin : « elles se démarquent beaucoup
   trop, aucune synergie visuelle avec le reste »). On abandonne les puces encadrées au
   profit de deux lignes posées SUR le voile de la carte : même famille de caractères,
   même ombre portée et même teinte de rareté (--rc) que le nom et les stats. */
:where(#bbRoot, .bb-skin) .card .cardatks{ left:6px; right:6px; gap:0; background:none; border:0 }
:where(#bbRoot, .bb-skin) .card .cardatks i{ background:none; border:0; padding:0 1px;
  border-bottom:1px solid color-mix(in srgb, var(--rc,#fff) 22%, transparent) }
:where(#bbRoot, .bb-skin) .card .cardatks i:last-child{ border-bottom:0 }
:where(#bbRoot, .bb-skin) .card .cardatks b{ font-weight:700; color:#e8eeff; text-shadow:0 1px 2px #000, 0 0 6px #000 }
:where(#bbRoot, .bb-skin) .card .cardatks em{ color:#dfe7ff; opacity:.92; font-weight:800;
  text-shadow:0 1px 2px #000, 0 0 6px #000 }
/* Un point de couleur d'élément AVANT le nom : discret, mais on lit l'élément d'un œil. */
:where(#bbRoot, .bb-skin) .card .cardatks b::before{ content:'●'; margin-right:3px; font-size:.7em; color:var(--el,#888);
  text-shadow:0 0 5px var(--el,#888) }
/* VOILE DU BAS (revu 2026-08-01, demande admin : « le dégradé ne couvre pas les attaques
   et il n'est pas très dégradé »). Il montait à 54 % de la carte et devenait transparent à
   62 % de LUI-MÊME, soit ~33 % de la carte — exactement là où commence le bloc d'attaques :
   le texte se retrouvait sur l'illustration nue. Deux corrections :
   1. hauteur 54 % → 74 %, pour englober attaques ET texte d'ambiance ;
   2. six paliers au lieu de trois, jusqu'à `transparent 100%` — la transition devient
      longue et douce au lieu de casser net. */
/* ⚠️ La hauteur relevée ne vise QUE les cartes qui portent du texte (grandes cartes du Dex,
   carte active du plateau). Les cartes de BANC n'affichent ni attaques ni citation : leur
   appliquer un voile de 74 % les aurait assombries sans aucune raison. */
:where(#bbRoot, .bb-skin) .card.active .scrim{ height:74% }
:where(#bbRoot, .bb-skin) .card .scrim{ background:linear-gradient(0deg,
  color-mix(in srgb, var(--rc,#000) 58%, rgba(4,6,14,.97)) 0%,
  color-mix(in srgb, var(--rc,#000) 46%, rgba(4,6,14,.92)) 20%,
  color-mix(in srgb, var(--rc,#000) 34%, rgba(4,6,14,.78)) 40%,
  color-mix(in srgb, var(--rc,#000) 24%, rgba(4,6,14,.55)) 58%,
  color-mix(in srgb, var(--rc,#000) 14%, rgba(4,6,14,.30)) 76%,
  color-mix(in srgb, var(--rc,#000) 6%,  rgba(4,6,14,.12)) 89%,
  transparent 100%) }

/* CARTE MAÎTRESSE : deux pastilles en coin, l'art respire à nouveau. */
:where(#bbRoot, .bb-skin) .ms-card .ms-pas{ left:auto; right:4px; bottom:auto; top:4px; width:14px; height:14px;
  display:flex; align-items:center; justify-content:center; border-radius:50%;
  font-size:.5rem; background:rgba(8,10,20,.8); border:1px solid rgba(255,215,138,.55);
  color:#ffe9ad; text-shadow:none; cursor:help }
:where(#bbRoot, .bb-skin) .ms-card .ms-abl{ left:4px; right:auto; bottom:4px; width:auto; padding:1px 5px;
  border-radius:999px; font-size:.46rem; line-height:1.25 }
:where(#bbRoot, .bb-skin) .ms-card .ms-abl b{ margin-left:2px }
:where(#bbRoot, .bb-skin) .ms-card .ms-nm{ bottom:5px; left:22px; right:6px; text-align:right }


/* ==== PLAYTEST v21 ==== */
/* PIÈCE D'ÉTAT : elle tourne au-dessus de la cible puis retombe ✔ / ✘. */
:where(#bbRoot, .bb-skin) .bb-scoin{ position:absolute; left:50%; top:6%; z-index:24; width:30px; height:30px;
  margin-left:-15px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-size:.9rem; background:radial-gradient(circle at 34% 30%, #fff6cf, #e8b84b 62%, #8a6a1e);
  border:2px solid rgba(255,240,190,.85); box-shadow:0 6px 16px -4px #000, 0 0 16px -2px rgba(255,200,90,.8);
  animation:scoinSpin .62s cubic-bezier(.3,.8,.35,1) }
@keyframes scoinSpin{
  0%{ transform:translateY(10px) rotateY(0) scale(.6); opacity:0 }
  25%{ opacity:1 }
  100%{ transform:translateY(-4px) rotateY(1440deg) scale(1); opacity:1 } }
:where(#bbRoot, .bb-skin) .bb-scoin.done{ animation:scoinLand .3s ease-out }
@keyframes scoinLand{ 0%{ transform:scale(1.25) } 100%{ transform:scale(1) } }
:where(#bbRoot, .bb-skin) .bb-scoin.win{ background:radial-gradient(circle at 34% 30%, #d8ffe4, #57d98a 62%, #1f7a45);
  border-color:rgba(190,255,215,.9); box-shadow:0 6px 16px -4px #000, 0 0 18px -2px rgba(90,240,150,.85) }
:where(#bbRoot, .bb-skin) .bb-scoin.lose{ background:radial-gradient(circle at 34% 30%, #ffe0e0, #d96a6a 62%, #7a1f1f);
  border-color:rgba(255,200,200,.85); box-shadow:0 6px 16px -4px #000, 0 0 14px -2px rgba(255,90,90,.7) }
:where(#bbRoot, .bb-skin) .bb-scoin .sc-res{ font-weight:900; font-size:1rem; color:#0a1018; text-shadow:none }
/* La chance ANNONCÉE pendant que la pièce tourne (2026-08-01) : le joueur voit le pari
   qu'il prend au moment même du tirage. Masquée si l'effet est garanti (Ultime) ou bloqué
   (immunité) — il n'y a alors aucun pari. */
:where(#bbRoot, .bb-skin) .bb-scoin .sc-pct{ position:absolute; left:50%; top:104%; transform:translateX(-50%);
  font-size:.52rem; font-weight:900; color:#ffd79a; white-space:nowrap;
  text-shadow:0 1px 3px #000; font-variant-numeric:tabular-nums }

/* MAÎTRESSE : ses deux lignes reprennent EXACTEMENT le style des attaques d'une carte. */
:where(#bbRoot, .bb-skin) .ms-card .ms-lines{ position:absolute; left:5px; right:5px; bottom:20px; z-index:3;
  display:flex; flex-direction:column; gap:0; pointer-events:none }
:where(#bbRoot, .bb-skin) .ms-card .ms-lines i{ display:flex; align-items:baseline; justify-content:space-between; gap:4px;
  font-style:normal; padding:0 1px;
  border-bottom:1px solid color-mix(in srgb, var(--rc,#fff) 22%, transparent) }
:where(#bbRoot, .bb-skin) .ms-card .ms-lines i:last-child{ border-bottom:0 }
:where(#bbRoot, .bb-skin) .ms-card .ms-lines b{ font-size:.42rem; font-weight:700; color:#e8eeff; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; text-shadow:0 1px 2px #000, 0 0 6px #000 }
:where(#bbRoot, .bb-skin) .ms-card .ms-lines em{ font-style:normal; font-size:.4rem; font-weight:800; color:#dfe7ff;
  flex:0 0 auto; text-shadow:0 1px 2px #000, 0 0 6px #000 }
:where(#bbRoot, .bb-skin) .ms-card .ms-lines .ms-ablrow.rdy b{ color:#ffe9ad }
:where(#bbRoot, .bb-skin) .ms-card .ms-lines .ms-ablrow.rdy em{ color:#ffd76a }
:where(#bbRoot, .bb-skin) .ms-card .ms-nm{ bottom:5px; left:6px; right:6px; text-align:center }

/* Le passif d'une carte de combat : même famille que ses attaques, en doré discret. */
:where(#bbRoot, .bb-skin) .card .cardatks u{ display:block; text-decoration:none; padding:1px 1px 0;
  font-size:.42rem; font-weight:700; color:#ffe1a8; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; text-shadow:0 1px 2px #000, 0 0 6px #000 }
:where(#bbRoot, .bb-skin) .card.active .cardatks u{ font-size:.48rem }


/* ==== PLAYTEST v23 ==== */
/* PHASE EN COURS dans la barre de tour : discrète mais toujours là. */
:where(#bbRoot, .bb-skin) .bb-phase{ margin-left:8px; padding:2px 8px; border-radius:999px; font-size:.62rem;
  font-weight:800; letter-spacing:.02em; color:#c3cbe6;
  background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.12) }
:where(#bbRoot, .bb-skin) .bb-phase.mine{ color:#a5f2be; border-color:rgba(90,240,150,.45);
  background:rgba(40,120,80,.22) }

/* Bannière de DÉBUT de tour : titre + sous-titre de phase. */
:where(#bbRoot, .bb-skin) .bb-yourturn i{ display:block; margin-top:3px; font-style:normal; font-size:.62rem;
  font-weight:700; color:#cfe6d8; letter-spacing:.02em }
/* Bannière de FIN de tour : sobre, elle ne doit pas voler la vedette. */
:where(#bbRoot, .bb-skin) .bb-endturn{ font-size:.95rem !important; color:#c3cbe6 !important;
  border-color:rgba(255,255,255,.2) !important;
  box-shadow:0 14px 40px -12px rgba(0,0,0,.85) !important;
  text-shadow:0 2px 6px #000 !important }

/* Le cut-in reste plus longtemps : on retarde son effacement d'autant. */
:where(#bbRoot, .bb-skin) .bb-cutin{ animation:ciFade .3s ease-in 2.6s forwards }


/* ==== PERF 2026-07-29 — accessibilité : couverture complète ====
   Les blocs `prefers-reduced-motion` existants ne couvraient qu'un tiers des animations
   (turnRing, pulsations de cartes, holos, clignotements restaient actifs). Ce bloc final
   neutralise TOUT ce qui boucle, sans toucher aux transitions ponctuelles utiles. */
@media (prefers-reduced-motion: reduce){
  .bb *, .bb *::before, .bb *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
  }
}


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-02 — (2) LE CADRE FANTÔME QUI SORT DU PLATEAU
   ==========================================================================
   SYMPTÔME (retour admin) : « un grand rectangle en perspective, tracé en cyan, traverse
   le plateau et sort de ses limites » ; impossible de cliquer dessus.

   ÉLÉMENT IDENTIFIÉ : `.half.turnactive::before` (bloc « v8 », plus haut dans ce fichier).
   C'est l'anneau « c'est ton tour » : `box-shadow: inset 0 0 0 4px currentColor`, teinté
   `--turnMe` (#7fd4ff, CYAN) sur mon camp et `--turnOpp` sur celui d'en face, avec
   `pointer-events:none` — d'où l'impossibilité de cliquer dessus.

   POURQUOI IL SORT DU PLATEAU (mesuré au navigateur, pas déduit).
   Le filigrane du tapis — `.half.opp::before` / `.half.me::before` (« GOTAGA » /
   « WAIFUCATCH », en tête de feuille) — porte `transform:translate(-50%,-50%)` et a
   EXACTEMENT la même spécificité (0,2,1) que `.half.turnactive::before`. Ce dernier,
   écrit plus bas, écrase bien `left`/`top` (via son `inset:0`) mais N'ÉCRASE PAS le
   `transform` : l'anneau hérite donc du recentrage du filigrane et se retrouve décalé
   d'une DEMI-LARGEUR et d'une DEMI-HAUTEUR de lui-même. Style calculé relevé sur un
   écran 1920 : `transform: matrix(1,0,0,1,-429.5,-317)` pour une moitié de 859×634.
   Comme il vit sous la perspective du tapis (`.scene{perspective}` + `.mat{rotateX(20deg)}`),
   ce décalage se projette en un grand quadrilatère incliné : lignes relevées à x=71 et
   x=957 alors que la moitié commence à x=415. Plus l'écran est grand, plus le décalage
   (proportionnel à la taille de la moitié) est spectaculaire — d'où le lien avec (1).

   POURQUOI ON LE SUPPRIME AU LIEU DE LE RECALER.
   Ce cadre a DÉJÀ été jugé et retiré : le bloc « v12 — LE TAPIS REDEVIENT UN SEUL OBJET »
   l'annule explicitement (« Le camp actif portait un CADRE INTERIEUR de 5 px : ça
   découpait le plateau en DEUX boîtes au lieu d'un tapis »), et « v13 » le réaffirme à
   spécificité égale. Mais ces deux annulations visent `.half.turnactive` — l'ÉLÉMENT —,
   alors que la passe perf du 2026-07-29 avait déplacé l'anneau sur un `::before` : elles
   ne l'atteignent plus. Le recaler ferait donc RÉAPPARAÎTRE le défaut que v12 a corrigé.
   Le tour reste parfaitement lisible sans lui : contour du tapis (`.mat.turn-me` /
   `.mat.turn-opp`), teinte de fond du camp actif, et `filter:saturate(.45) brightness(.62)`
   sur le camp inactif.
   Bénéfice annexe : on supprime du même coup une animation en boucle (`turnRingOp`) et son
   `will-change:opacity`, donc une couche de composition permanente sous transformation 3D. */
:where(#bbRoot, .bb-skin) .half.turnactive::before{ content:none }


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-02 — (1) LE PLATEAU EST TROP PETIT SUR PC
   ==========================================================================
   MESURES (Dex, modale de combat, écran 1920×1080, moteur Chromium) :
     modale 920×869 → corps utile 903×788 ; plateau naturel 863×1290 ;
     fitBoard : k_h = 674/1290 = 0,52 et k_w = 851/863 = 0,99 → k = 0,52 ;
     RENDU RÉEL : 451×674, cartes de 89 px — sur un écran de 1896 px de large.
   Deux causes, aucune n'est « le plateau est mal dimensionné » :

   a) L'HÔTE EST TROP PETIT. Dans le Dex le plateau vit dans `.modal.modal-board`
      (dex.css : `max-width:920px`, `max-height:88vh`). fitBoard ne peut pas dépasser son
      conteneur : il réduit donc le plateau pour tenir dans 903×788 et le dessine « petit
      au centre de la modale ». On rend la fenêtre à la mesure de l'écran.
      ⚠️ SÉLECTEUR PRÉFIXÉ `body` À DESSEIN : `scope-board-css.py` laisse passer sans
      cloisonnement les règles qui commencent par `body`. Un sélecteur cloisonné en
      `:where(#bbRoot, .bb-skin) .modal-board` ne pourrait PAS marcher : la modale est un
      ANCÊTRE du plateau, pas un descendant.

   b) LE TAPIS N'ATTEIGNAIT JAMAIS SA LARGEUR DÉCLARÉE. `.mat` est un enfant flex de
      `.scene` : avec le `flex-shrink:1` par défaut il était écrasé à sa largeur MINIMALE
      (mesuré : 863 px pour un `width:min(1500px,96vw)` — la déclaration était donc morte).
      Or c'est la HAUTEUR qui limite l'échelle (k_h = 0,52 contre k_w = 0,99) : élargir le
      tapis ne coûte RIEN en taille de carte et remplace des bandes NOIRES par du tapis.
      C'est exactement l'intention notée plus haut dans ce fichier (« Tapis PLUS LARGE :
      la hauteur est le facteur limitant… c'est ce que fait Pokemon »), jamais appliquée
      faute de ce `flex-shrink`.

   PÉRIMÈTRE — ON N'ÉLARGIT QUE SUR GRAND ÉCRAN, ON NE RÉTRÉCIT NULLE PART.
   `min-width:1200px` ne peut pas co-exister avec le bloc mobile
   `(orientation:portrait) and (max-width:560px)`, ni avec `(max-height:620px)` grâce à
   `min-height:760px` : le rendu mobile et celui des écrans courts (overlay) sont
   strictement inchangés. En dessous de 1200 px, dex.css garde entièrement la main.
   Ce bloc ne touche AUCUNE taille de carte ni de texte : il peut donc rester après le
   bloc « PORTRAIT — RÉAFFIRMÉ EN DERNIER » sans le contredire.
   ========================================================================== */
@media (min-width:1200px) and (min-height:760px){
  /* (a) la modale du Dex prend la place de l'écran (elle reste centrée et bornée) */
  body .modal.modal-board{ max-width:min(1580px, 94vw); max-height:95vh }
  /* (b) le tapis cesse d'être comprimé et prend enfin la largeur qu'il déclare.
     Le 3e terme `100%` (= la largeur utile de `.scene`, donc du conteneur hôte) est une
     SÉCURITÉ : sans lui, `flex-shrink:0` sur un écran de 1200 à 1560 px de large ferait
     dépasser le tapis de son conteneur, et `.modal-body` (overflow-y:auto → overflow-x:auto
     dans le Dex) afficherait une barre de défilement horizontale le temps que fitBoard
     remette le plateau à l'échelle. Avec `100%` le tapis ne peut jamais dépasser. */
  :where(#bbRoot, .bb-skin) .mat{ flex-shrink:0; width:min(1500px, 96vw, 100%) }
}


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-02 (2e retour) — (1) LES COMMANDES SONT PARTIES AU BORD
   ==========================================================================
   SYMPTÔME : « Abandonner » et l'indicateur de tour sont loin du champ de combat depuis
   le lot « échelle PC » ; il faut balayer l'écran des yeux.

   CAUSE, MESURÉE (harnais reproduisant la modale du Dex, 1920×1080, Chromium ;
   même DOM que `bbMountBoard`, même `fitBoard`) :
     AVANT 6f0f68c : tapis 863 px de mise en page → ☰ à x=685, boîte « tour » à x=714.
     APRÈS  6f0f68c : tapis 1500 px               → ☰ à x=459, boîte « tour » à x=489.
     → 226 px de dérive vers la GAUCHE, à l'écran, pour les deux.
   Le coupable n'est pas la taille du plateau mais l'ANCRAGE : `.mat > .bb-menu`
   (`left:14px`, bloc « v6 ») et `#bbBanner.turnbar` (`left:58px`, même bloc) sont ancrés
   au BORD GAUCHE du tapis. Le tapis a gagné 637 px de large (min(1500px…) enfin appliqué),
   donc son bord gauche s'est éloigné de 318 px de mise en page du centre — c'est cette
   moitié-là que les commandes ont suivie.
   L'Élan et la maîtresse, eux, N'ONT PAS bougé : ils sont ancrés au CENTRE
   (`calc(50% + 300px)`), pour la raison déjà écrite plus haut dans ce fichier —
   « Elan et maitresse ancres AUX CARTES (pas aux bords du tapis) : ils restent colles au
   jeu meme si on elargit le tapis pour remplir l'ecran ». Les commandes n'avaient jamais
   reçu ce traitement.

   CORRECTIF : même ancrage que l'Élan. `--bbCtlX` place le bloc [☰ + boîte « tour »] par
   rapport au CENTRE, pas au bord. Géométrie du tapis à 1500 px (mesures ci-dessus) :
     zone de cartes   = 50% ± 277 px   (banc de 3 : 3×170 + 2×22, équipe de 4)
     colonne de flanc = 50% − 470 px → 50% − 300 px   (pseudo + verre d'Élan)
   La boîte se cale donc juste AU-DESSUS de la colonne de flanc, bord droit ALIGNÉ sur le
   bord intérieur de cette colonne (50% − 300 px) : elle ne peut pas toucher les cartes
   (23 px de marge avant 50% − 277 px) et le flanc est, lui, centré verticalement —
   aucun recouvrement non plus de ce côté.
   `width:240px` + `flex-wrap:wrap` : sans largeur bornée la boîte mesure 311 px de mise en
   page (mesuré) et ne PEUT PAS se rapprocher davantage sans mordre sur le banc. Sur deux
   lignes elle tient dans la colonne libre. Elle ne rétrécit rien : c'est un retour à la
   ligne, aucune taille de texte n'est réduite.
   `max(14px, …)` : c'est un PLANCHER, jamais un éloignement. Si le tapis est étroit
   (labo hors mode officiel : `#arenaMount .bb{max-width:980px}`), la valeur retombe
   exactement sur celles d'aujourd'hui — ☰ à 14 px, boîte à 58 px.
   PÉRIMÈTRE : `min-width:1000px` exclut le bloc mobile
   `(orientation:portrait) and (max-width:560px)` ; `min-height:620px` exclut le bloc
   `(orientation:landscape) and (max-height:560px)`, qui fait courir la boîte « tour » sur
   TOUTE la largeur (`left:0;right:0;width:auto`) — une largeur de 240 px la casserait.
   Les bornes sont plus basses que celles du lot « échelle PC » (1200/760) À DESSEIN :
   en dessous, le tapis reste petit, `max()` retombe donc sur le PLANCHER et les commandes
   ne bougent PAS d'un pixel — seule la largeur bornée s'applique, et elle ne peut que
   RÉDUIRE le recouvrement du banc déjà présent aujourd'hui (mesuré en 1280×720 :
   la boîte passe de 331 px à 240 px de large, recouvrement du banc 171 px → 80 px).
   Aucune taille de carte ni de texte de carte n'est touchée : ce bloc peut donc rester
   après « PORTRAIT — RÉAFFIRMÉ EN DERNIER » sans le contredire. */
@media (min-width:1000px) and (min-height:620px){
  :where(#bbRoot, .bb-skin) .mat{ --bbCtlX: max(14px, calc(50% - 584px)) }   /* 540 (boîte) + 34 (☰) + 10 (écart) */
  :where(#bbRoot, .bb-skin) .mat > .bb-menu{ left:var(--bbCtlX) }
  :where(#bbRoot, .bb-skin) .mat > .bb-opts{ left:var(--bbCtlX) }
  /* `.half` et `.mat` ont la MÊME largeur de bloc conteneur (le tapis n'a pas de padding,
     `box-sizing:border-box` : la boîte de padding du tapis = la boîte de bordure de la
     moitié). Les deux `50%` désignent donc bien le même axe. */
  :where(#bbRoot, .bb-skin) #bbBanner.turnbar{ left:calc(var(--bbCtlX) + 44px); width:240px;
    flex-wrap:wrap; align-content:flex-start; row-gap:4px }
}


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-02 (2e retour) — (2) LISIBILITÉ DU TOUR
   ==========================================================================
   ÉTAT DES LIEUX de l'anneau `.half.turnactive::before` demandé : il n'est PAS « peu
   visible », il ne s'affiche plus du tout — le lot précédent l'a neutralisé
   (`content:none`, bloc « (2) LE CADRE FANTÔME », plus haut) parce qu'il héritait du
   `transform:translate(-50%,-50%)` du filigrane et sortait du plateau. Le rétablir
   ferait revenir DEUX défauts déjà jugés : le quadrilatère fantôme, et le « cadre
   intérieur qui découpe le plateau en deux boîtes » que le bloc « v12 » avait retiré.
   On renforce donc le tour AILLEURS, sans réintroduire d'arête.

   (a) LA PHASE EST LE TEXTE LE PLUS PETIT DU PLATEAU. C'est pourtant lui qui ANNONCE le
   tour (« ⏳ Tour adverse » / « ◆ Phase principale » / « 💀 Choisis ta carte », posé par
   `bbPaintBanner`). Mesuré à l'écran, modale du Dex en 1920×1080, échelle fitBoard 0,668 :
     .bb-phase   9,92 px CSS → 6,6 px RÉELS      ← sous le seuil de lecture retenu ici (~8)
     .bb-turnnum 13,76 px    → 9,2 px
     .bb-forfeit 12,48 px    → 8,3 px
   `.bb-phase` (bloc « PLAYTEST v23 ») a été écrit APRÈS la passe « LISIBILITÉ : compenser
   la mise à l'échelle du plateau » et n'a donc jamais reçu sa correction. On l'aligne sur
   `.bb-turnnum` : .86rem par défaut, et 1,00rem dans la bande 620→820 px de haut où cette
   même passe avait dû monter `.bb-turnnum` à 1,00rem (l'échelle y tombe à ~0,57) —
   en dessous de 620 px l'échelle remonte à ~1 et la valeur d'origine reprend la main.

   (b) QUI JOUE, LU SUR LA BOÎTE ELLE-MÊME. `bbPaintBanner` pose déjà
   `bb-banner-mine` / `bb-banner-their` / `bb-banner-neutral` sur `#bbBanner` — AUCUNE
   règle ne s'en servait (vérifié : zéro occurrence de `bb-banner-` dans cette feuille).
   La boîte prend donc la couleur du camp qui joue, avec EXACTEMENT la palette déjà en
   service pour le tour : `--turnMe` #7fd4ff et `--turnOpp` #ff8fa8 (bloc « v8 »), les
   mêmes que le contour du tapis `.mat.turn-me` / `.mat.turn-opp`. Un liseré et un halo :
   pas de nouvelle forme, pas de clignotement.
   Volontairement HORS media query : c'est une pure couleur, sans géométrie, donc utile
   aussi en mobile et sans risque pour lui.

   (c) LE CAMP ACTIF SE DÉTACHE PLUS FRANCHEMENT, et son TAPIS ÉQUIPÉ CESSE DE DISPARAÎTRE.
   Les règles `.half.me.turnactive` / `.half.opp.turnactive` du bloc « v12 » réécrivent
   `background-image` avec le motif et le dégradé du tapis CLASSIQUE EN DUR, au lieu de
   `var(--matPat)` / `var(--matA,--matB)`. Conséquence mesurée (camp `matskin-foret`,
   `getComputedStyle().backgroundImage`) :
     camp en attente  → repeating-linear-gradient(115deg, rgba(120,220,150,.05) …)  ← forêt
     camp qui joue    → repeating-linear-gradient(135deg, rgba(255,255,255,.02) …)  ← classique
   Autrement dit le tapis gagné sur les boss s'efface du camp dont c'est le tour, et
   revient quand la main change : le plateau clignote entre deux décors à chaque tour.
   On réécrit les deux règles avec les variables — le skin est conservé — et on en profite
   pour monter la lueur du camp actif de .30/.28 à .42/.40 : c'est le MÊME halo, plus
   franc, toujours sans arête. Le camp en attente n'est pas grisé (le bloc « v9 » avait
   retiré ce grisage : « ca donnait une impression de partie terminee »).

   (d) LE CONTOUR DU TAPIS À L'ÉCHELLE DU GRAND ÉCRAN. Sur un tapis de 1500 px, un halo de
   26 px ne se voit plus ; il passe à 46 px et la bordure à 3 px (`box-sizing:border-box` :
   aucun décalage de mise en page). Uniquement sur grand écran. */
/* ⚠️ ORDRE OBLIGATOIRE des quatre règles qui suivent : à spécificité égale c'est la
   DERNIÈRE qui gagne, et les trois dernières RÉAFFIRMENT la valeur d'origine (.62rem) ou
   la valeur de leur bande. Un 1280×500 satisfait à la fois « bande 620→820 » et « écran
   court » : c'est bien « écran court » qui doit l'emporter, donc être écrit après. */
:where(#bbRoot, .bb-skin) .bb-phase{ font-size:.86rem }
@media (orientation:landscape) and (min-width:1200px) and (max-height:820px){
  :where(#bbRoot, .bb-skin) .bb-phase{ font-size:1.00rem }   /* l'échelle y tombe à ~0,57 (cf. bloc « ECRANS PEU HAUTS ») */
}
@media (orientation:landscape) and (max-height:620px){
  :where(#bbRoot, .bb-skin) .bb-phase{ font-size:.62rem }   /* écrans courts : l'échelle y remonte à ~1, valeur d'origine */
}
@media (orientation:portrait) and (max-width:560px){
  :where(#bbRoot, .bb-skin) .bb-phase{ font-size:.62rem }   /* valeur d'origine RÉAFFIRMÉE : le portrait ne change pas */
}

:where(#bbRoot, .bb-skin) #bbBanner.bb-banner-mine{ border-color:rgba(127,212,255,.55);
  box-shadow:inset 0 2px 6px rgba(0,0,0,.55), 0 0 16px -3px rgba(127,212,255,.55) }
:where(#bbRoot, .bb-skin) #bbBanner.bb-banner-their{ border-color:rgba(255,143,168,.5);
  box-shadow:inset 0 2px 6px rgba(0,0,0,.55), 0 0 16px -3px rgba(255,143,168,.45) }

:where(#bbRoot, .bb-skin) .half.me.turnactive{
  background-image:radial-gradient(120% 90% at 50% 100%, rgba(120,225,255,.42), transparent 62%),
    var(--matPat, repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px)),
    linear-gradient(180deg, var(--matA,#101a30), var(--matB,#1c2b4a)) }
:where(#bbRoot, .bb-skin) .half.opp.turnactive{
  background-image:radial-gradient(120% 90% at 50% 0%, rgba(255,120,160,.40), transparent 62%),
    var(--matPat, repeating-linear-gradient(135deg, rgba(255,255,255,.02) 0 12px, transparent 12px 24px)),
    linear-gradient(180deg, var(--matA,#3a1c2c), var(--matB,#1a1020)) }

@media (min-width:1200px) and (min-height:760px){
  :where(#bbRoot, .bb-skin) .mat{ border-width:3px }
  :where(#bbRoot, .bb-skin) .mat.turn-me{ box-shadow:0 40px 70px -25px #000, 0 0 46px rgba(120,200,255,.55) }
  :where(#bbRoot, .bb-skin) .mat.turn-opp{ box-shadow:0 40px 70px -25px #000, 0 0 46px rgba(255,120,150,.50) }
}


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-03 — (1) LE PLATEAU DOIT REMPLIR LE SALON
   ==========================================================================
   RETOUR : « une fois le salon en plein écran, le plateau doit remplir la place ; cartes
   et textes doivent grandir avec le viewport, sur mobile ET sur PC ; sur mobile il faut
   lire sans zoomer, comme sur les captures Pokémon ».

   CE QUI SE PASSAIT — mesuré au navigateur, pas déduit. Harnais chargeant CE fichier et
   arena-board.js, DOM réel de `bbMountBoard`, hôte = modale plein écran du Dex :
     1920×1080 : échelle fitBoard 0,663 — tapis 1178×875 dans 1920×1080 ; nom de la carte
                 active à 9,8 px RÉELS, rareté 8,3 px, stats 8,5 px.
     1280×720  : échelle 0,518 — tapis 719×491, cartes de 90 px.
     375×812   : échelle 0,800 (le PLANCHER) — tapis 300×604, 168 px de vide sous le tapis.

   DEUX CAUSES, aucune n'est « les cartes sont trop petites en CSS ».

   (a) 124 px RÉSERVÉS POUR RIEN — corrigé dans arena-board.js (`fitBoard`), pas ici.
       `ACTIONS_RESERVE` retirait 124 px de la hauteur disponible pour le menu d'attaques,
       alors que le bloc « v14 » de CE fichier l'a repassé en `position:absolute` DANS le
       plateau. Mesuré après correctif — c'est lui qui porte l'essentiel du gain, cartes
       ET textes, sur TOUS les régimes (c'est ça, « grandir avec le viewport » : l'échelle
       est une fonction de la hauteur de la fenêtre) :
         1920×1080  k 0,663 → 0,759   carte active 156 → 179 px   nom 9,8 → 11,2 px réels
         1280×720   k 0,518 → 0,648
         375×812    k 0,800 → 0,946   carte active  90 → 106 px   nom 8,4 → 10,0 px réels

   (b) LES TEXTES DE CARTE SONT EN `rem`, DONC INDÉPENDANTS DE LA CARTE. Le nom d'une
       carte active vaut .92rem — 14,72 px — que la carte fasse 202 px (bureau large) ou
       103 px (mobile). Sur le grand écran, où la carte est deux fois plus large, le texte
       n'occupe donc que 7,2 % de sa largeur, contre 10,3 % en portrait : c'est LÀ que le
       texte paraît minuscule. On l'exprime en `cqw` — pourcentage de la largeur de la
       CARTE elle-même, via `container-type:inline-size` posé sur `.card`.

   POURQUOI `max(<valeur d'aujourd'hui>, N cqw)` ET PAS `N cqw` SEUL.
   `max()` rend la règle MONOTONE : elle ne peut que grandir, jamais rétrécir. Sans elle,
   un ratio unique aurait rapetissé les régimes déjà généreux (en 1280×720 le bloc
   « ECRANS PEU HAUTS » met le nom à 1,04rem sur une carte de 155 px, soit 10,7 %).
   POURQUOI LE BLOC EST BORNÉ À `min-width:1200px` ET `min-height:760px`.
   C'est la borne DÉJÀ utilisée par le lot « échelle PC » du 2026-08-02, et elle exclut
   par construction TOUS les autres régimes de tailles de cette feuille :
     · `(orientation:portrait) and (max-width:560px)`      — exclu par min-width:1200px
     · `(orientation:landscape) and (max-height:820px)`    — exclu par min-height:760px
     · `(orientation:landscape) and (max-height:620px)`    — idem
   Le rendu mobile, celui des écrans courts et celui du labo hors grand écran sont donc
   strictement inchangés : ils gardent leurs proportions, déjà correctes, et encaissent
   le gain du correctif (a).

   MESURES DU BLOC (1920×1080, après correctif (a), échelle 0,759) :
     nom carte active   14,7 → 19,2 px CSS   (11,2 → 14,6 px RÉELS)
     nom carte de banc  12,5 → 16,0 px CSS   ( 9,5 → 12,1 px RÉELS)
     rareté active      12,5 → 13,3 px       ( 9,5 → 10,1 px)
     stats active       12,8 → 14,5 px       ( 9,7 → 11,0 px)
   Débordement vérifié au navigateur (largeur du TEXTE relevée par `Range`, comparée à la
   largeur utile de la carte) : 180 px de texte pour 202 px de carte sur le nom le plus
   long du jeu d'essai — aucun débordement, et `.nm` porte de toute façon
   `white-space:nowrap; text-overflow:ellipsis`.

   PÉRIMÈTRE — `#bbRoot` EN TÊTE DE CHAQUE SÉLECTEUR, À DESSEIN.
   1. `scope-board-css.py` laisse passer sans cloisonnement les sélecteurs commençant par
      `#bbRoot` : la copie du Dex reste identique, et ces règles ne touchent que le
      PLATEAU DE COMBAT — jamais les conteneurs `.bb-skin` du Dex (sélecteur de deck,
      vitrine « Mes Decks »), dont dex.css impose les dimensions de carte.
   2. Spécificité (1,2,0) : elles gagnent sans avoir à être placées avant le bloc
      « PORTRAIT — RÉAFFIRMÉ EN DERNIER »… ce qui serait sans objet ici, puisque la borne
      `min-width:1200px` interdit à ce bloc de les rencontrer.
   ========================================================================== */
@media (min-width:1200px) and (min-height:760px){
  #bbRoot .card{ container-type:inline-size }
  /* ⚠️ LES ANCRAGES `bottom` SUIVENT, SINON LA PILE SE CHEVAUCHE. Nom, rareté et stats
     sont trois boîtes absolues empilées par leur `bottom` en PIXELS : grossir la police
     sans écarter les ancrages fait monter chaque boîte dans celle du dessus. Mesuré au
     navigateur AVANT tout changement, la pile était DÉJÀ au contact (rareté et stats se
     recouvraient de 2 px, le nom mordait de 1,6 px sur le bloc d'attaques) ; avec les
     nouvelles tailles le recouvrement passait à 8 px sous le bloc d'attaques.
     Les ancrages sont donc exprimés dans la MÊME unité que les polices — `max()` là
     encore, pour ne jamais rapprocher ce qui est déjà écarté. Mesuré après : plus aucun
     recouvrement, ni sur la carte active ni sur les cartes de banc. */
  #bbRoot .card .nm{ font-size:max(.78rem, 9.6cqw); bottom:max(32px, 20cqw) }
  #bbRoot .card.active .nm{ font-size:max(.92rem, 9.6cqw); bottom:max(36px, 20cqw) }
  #bbRoot .card .rar{ font-size:max(.72rem, 6.6cqw); bottom:max(18px, 11.5cqw) }
  #bbRoot .card.active .rar{ font-size:max(.78rem, 6.6cqw); bottom:max(21px, 11.5cqw) }
  #bbRoot .card .st{ font-size:max(.74rem, 7.2cqw) }
  #bbRoot .card.active .st{ font-size:max(.80rem, 7.2cqw) }
  #bbRoot .card .hp b{ font-size:max(.74rem, 8.2cqw) }
  #bbRoot .card.active .hp b{ font-size:max(.94rem, 8.2cqw) }
  #bbRoot .card .hp i{ font-size:max(.62rem, 6.4cqw) }
  #bbRoot .card.active .hp i{ font-size:max(.54rem, 6.4cqw) }
  #bbRoot .card.active .cardatks{ bottom:max(52px, 33cqw) }
}


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-03 — (2) QUI JOUE, SANS AMBIGUÏTÉ
   ==========================================================================
   RETOUR : « je veux savoir SANS AMBIGUÏTÉ qui joue ; Pokémon affiche une bannière
   pleine largeur "Tour de l'adversaire" et un écran "L'adversaire a la main" ».

   ÉTAT DES LIEUX, RELEVÉ AU NAVIGATEUR (et non déduit du fichier), pendant MON tour :
     getComputedStyle(#bbEnemy).filter    = none
     getComputedStyle(#bbEnemy).boxShadow = none
   Le camp en attente n'est donc distingué par RIEN. Le commentaire du lot précédent
   affirmait le contraire (« et `filter:saturate(.45) brightness(.62)` sur le camp
   inactif ») : cette règle existe bien — bloc « v8 » — mais le bloc « v9 » la remet à
   `filter:none` quinze lignes plus bas, à spécificité égale, donc en dernier. Elle est
   morte depuis. Restent le liseré du tapis (1,5 px, ramenés à 1 px réel par l'échelle)
   et la teinte de fond du camp actif. Sur un téléphone, ce n'est rien.

   (a) BANDEAU PLEINE LARGEUR SUR LA COUTURE — `.bb-turnflag`.
   Posé par `bbMountBoard` ENTRE les deux moitiés (donc DANS LE FLUX : il ne peut
   recouvrir aucune carte, contrairement à une bande flottante — les deux moitiés n'ont
   pas la même hauteur, mesuré 456 px contre 540 px en 1920×1080, aucun `top:%` ne tombe
   sur la couture). Il est rempli par `bbPaintBanner` avec le message `msg` que celui-ci
   calculait déjà… sans l'afficher depuis le 2026-07-26. Aucune clé i18n nouvelle :
   `your_turn`, `opp_turn`, `battle_over`, `ph_promo` sont toutes déjà servies.
   Taille RELATIVE au viewport, comme le réclame le point (1) :
   `clamp(.72rem, 1.9vh, 1.25rem)` → mesuré 20,5 px CSS en 1920×1080 (15,4 px réels à
   l'échelle 0,75) et 15,4 px CSS en 375×812 (14,1 px réels). C'est le plus grand texte
   du plateau, des deux côtés, contre 9,1 px réels pour l'ancienne pastille de phase.
   Coût : ~26 px de hauteur de mise en page, soit 2 % d'échelle — repris vingt fois par
   le correctif (1a).

   (b) LE CAMP QUI ATTEND RECULE, SANS « PARTIE TERMINÉE ».
   Le bloc « v9 » avait retiré le grisage parce qu'à `saturate(.45) brightness(.62)` « ça
   donnait une impression de partie terminee ». On ne le rétablit pas : valeur beaucoup
   plus douce (.78 / .86) et surtout appliquée aux SEULES RANGÉES DE CARTES (`.row`), pas
   à la moitié entière — le tapis gagné sur les boss garde donc exactement ses couleurs,
   ce qui était l'autre grief (bloc « (c) » du 2026-08-02). Une ombre interne creuse en
   plus la moitié en attente : elle est « dans l'ombre », pas « éteinte ».

   PÉRIMÈTRE : règles préfixées `#bbRoot` (cf. bloc (1)). Elles ne touchent ni l'overlay
   Twitch de WaifuCatch-Central (qui ne charge pas cette feuille) ni les vitrines
   `.bb-skin` du Dex. Le labo (combat-arena.html) monte le MÊME `#bbRoot` et en hérite :
   c'est voulu, c'est son « rendu tel que les joueurs le verront ».
   ========================================================================== */
#bbRoot .mat > .bb-turnflag{
  position:relative; z-index:3; flex:0 0 auto; display:flex; align-items:center; justify-content:center;
  padding:4px 10px; min-height:1.6em; overflow:hidden;
  border-top:1px solid rgba(255,255,255,.10); border-bottom:1px solid rgba(255,255,255,.10);
  background:linear-gradient(90deg, transparent, rgba(6,10,22,.72) 18%, rgba(6,10,22,.72) 82%, transparent);
  --tfC:#ffe9ad }
/* Entre le montage (`bbMountBoard`) et la première peinture (`bbPaintBanner`) la bande est
   VIDE : sans ceci, le tapis porterait une barre de 27 px sans texte pendant tout l'écran
   d'intro (VS, puis pièce), soit ~5 s en PvP. */
#bbRoot .mat > .bb-turnflag:empty{ display:none }
#bbRoot .bb-turnflag .bb-turnflag-txt{
  font-weight:900; letter-spacing:.06em; text-transform:uppercase;
  /* `min(1.9vh, 3.3vw)` et pas `1.9vh` seul : la hauteur commande la taille (le bandeau doit
     rester lisible sur un grand écran), mais c'est la LARGEUR qui décide s'il tient. Mesuré
     en 375×812 : à 1,9vh (15,4 px) « 🟢 À TON TOUR — CHOISIS TON ATTAQUE » réclame 379 px
     pour 353 px disponibles → coupé aux points de suspension. À `min(…,3,3vw)` (12,4 px) le
     texte mesure 283 px : il tient en entier, avec de la marge pour les traductions plus
     longues (en/ja/rcf). En 1920×1080 `3,3vw` vaut 63 px : c'est `1,9vh` (20,5 px) qui
     l'emporte, la valeur du grand écran est donc inchangée. */
  font-size:clamp(.66rem, min(1.9vh, 3.3vw), 1.25rem); line-height:1.25; color:var(--tfC);
  text-shadow:0 0 14px color-mix(in srgb, var(--tfC) 55%, transparent), 0 2px 4px #000;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100% }
/* ⚠️ `.mat >` OBLIGATOIRE sur les trois modificateurs. La règle de base ci-dessus vaut
   (1,2,0) : sans le `.mat >`, `#bbRoot .bb-turnflag-their` ne pèse que (1,1,0) et se fait
   battre par elle — mesuré au navigateur, la bande restait DORÉE pendant le tour adverse
   (`getComputedStyle(.bb-turnflag-txt).color` = rgb(255,233,173) au lieu de #ff8fa8),
   c'est-à-dire exactement le défaut que ce bloc corrige. */
#bbRoot .mat > .bb-turnflag-mine{ --tfC:var(--turnMe,#7fd4ff) }
#bbRoot .mat > .bb-turnflag-their{ --tfC:var(--turnOpp,#ff8fa8) }
#bbRoot .mat > .bb-turnflag-neutral{ --tfC:#ffe9ad }
/* Le liseré prend la couleur du camp : la bande EST le repère, on la voit du coin de l'œil. */
#bbRoot .mat > .bb-turnflag-mine, #bbRoot .mat > .bb-turnflag-their{
  border-top-color:color-mix(in srgb, var(--tfC) 55%, transparent);
  border-bottom-color:color-mix(in srgb, var(--tfC) 55%, transparent);
  box-shadow:0 0 22px -6px color-mix(in srgb, var(--tfC) 70%, transparent) }
/* ENTRÉE : le texte monte et un balayage traverse la bande, vers le camp qui prend la
   main. Jouée UNE FOIS par bascule — `bbPaintBanner` ne réécrit que si le texte change,
   sinon la bande se relancerait à chaque sondage (1,6 s). Aucune animation en boucle. */
#bbRoot .bb-turnflag-in .bb-turnflag-txt{ animation:tfIn .55s cubic-bezier(.2,.9,.25,1) }
#bbRoot .bb-turnflag-in::after{ content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(90deg, transparent, color-mix(in srgb, var(--tfC) 45%, transparent), transparent);
  animation:tfSweep .6s ease-out forwards }
@keyframes tfIn{ from{ opacity:0; transform:translateY(6px) scale(.94) } to{ opacity:1; transform:none } }
@keyframes tfSweep{ from{ transform:translateX(-100%) } to{ transform:translateX(100%); opacity:0 } }
/* Le camp qui ATTEND recule — cartes seulement, le tapis garde son skin. */
#bbRoot .half:not(.turnactive){ box-shadow:inset 0 0 110px -28px rgba(0,0,0,.85) }
#bbRoot .half:not(.turnactive) .row{ filter:saturate(.78) brightness(.86) }
#bbRoot .half.turnactive .row{ filter:none }
/* « L'ADVERSAIRE A LA MAIN » : sous-titre de la bande de fin de MON tour (bbEndTurnBanner). */
#bbRoot .bb-endturn i{ display:block; margin-top:4px; font-style:normal; font-weight:800;
  font-size:.62em; letter-spacing:.06em; color:var(--turnOpp,#ff8fa8) }
#bbRoot .bb-endturn-opp{ border-color:color-mix(in srgb, var(--turnOpp,#ff8fa8) 55%, transparent) !important;
  box-shadow:0 14px 40px -12px rgba(0,0,0,.85), 0 0 30px -8px color-mix(in srgb, var(--turnOpp,#ff8fa8) 50%, transparent) !important }


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-03 — (3) LA PIÈCE DE DÉPART
   ==========================================================================
   RETOUR : « soigne l'animation du tirage — la pièce a choisi, tu commences ».
   AVANT : la pièce tournait sur place (`rotateY(0→1800deg)`, 1 s) puis s'arrêtait net ;
   rien ne disait qu'elle avait ATTERRI, et le verdict apparaissait à côté, sans lien.
   MAINTENANT, sans toucher au minutage de `introDice` (verdict à 1000 ms, sortie à
   2600 ms — la pièce se pose donc exactement quand le verdict tombe) :
     · elle est LANCÉE : `coinToss` la fait monter puis redescendre pendant qu'elle tourne ;
     · une ombre au sol (`.bi-coin-shadow`) se resserre et s'éclaircit au sommet du lancer,
       se rouvre à l'atterrissage — c'est elle qui donne le poids ;
     · une onde (`.bi-coin-ring`) part au moment du verdict, à la couleur du camp gagnant ;
     · `.bb-intro.done` allume la pièce d'un halo de cette même couleur, et le verdict
       MONTE vers elle au lieu d'apparaître.
   La couleur du gagnant vient de `--turnMe` / `--turnOpp`, les deux variables déjà
   utilisées par les faces de la pièce et par le contour du tapis : aucune teinte nouvelle.
   AUCUNE chaîne affichée n'est ajoutée : `coin_me`, `coin_opp`, `init_me`, `init_opp`
   sont les clés déjà en service.
   TAILLE RELATIVE (point (1) du même retour) : `clamp(118px, 24vmin, 208px)` au lieu de
   `clamp(92px, 14vh, 128px)`. Mesuré : 208 px de pièce en 1920×1080 (contre 128) et
   90 px en 375×812 (contre 92 — `vmin` suit la petite dimension, le mobile ne bouge pas).
   ACCESSIBILITÉ : `#bbIntro` est ajouté à `#bbRoot`, qui porte la classe `.bb` — le bloc
   final `prefers-reduced-motion` de cette feuille neutralise donc déjà tout ce qui suit.
   ========================================================================== */
#bbRoot .bi-coinstage{ position:relative; display:flex; flex-direction:column;
  align-items:center; justify-content:flex-end; --coinC:var(--turnMe,#7fd4ff) }
#bbRoot .bi-coinstage.win-opp{ --coinC:var(--turnOpp,#ff8fa8) }
#bbRoot .bi-coinstage .bi-coin{ width:clamp(118px,24vmin,208px); animation:coinToss 1s cubic-bezier(.32,.72,.28,1) }
/* Le « sol » est une FLAQUE DE LUMIÈRE à la couleur du camp gagnant, pas une ombre noire :
   le voile d'intro est déjà à rgba(5,7,16,.88) — mesuré au navigateur, une ombre sombre y
   est rigoureusement invisible. La flaque se resserre quand la pièce monte et se rouvre
   quand elle retombe : c'est elle qui donne le poids et le point d'atterrissage. */
#bbRoot .bi-coin-shadow{ display:block; margin-top:clamp(10px,2.4vmin,20px);
  width:clamp(84px,17vmin,150px); height:clamp(9px,1.8vmin,16px); border-radius:50%;
  background:radial-gradient(50% 50% at 50% 50%, color-mix(in srgb, var(--coinC) 55%, transparent), transparent 72%);
  animation:coinShadow 1s cubic-bezier(.32,.72,.28,1) }
#bbRoot .bi-coin-ring{ position:absolute; left:50%; top:50%; width:100%; aspect-ratio:1;
  transform:translate(-50%,-50%) scale(.35); border-radius:50%; pointer-events:none; opacity:0;
  border:3px solid color-mix(in srgb, var(--coinC) 85%, transparent) }
#bbRoot .bb-intro.done .bi-coin-ring{ animation:coinRing .75s ease-out forwards }
#bbRoot .bb-intro.done .bi-coinstage .bi-coin{ animation:coinLand .5s ease-out forwards;
  filter:drop-shadow(0 0 26px color-mix(in srgb, var(--coinC) 75%, transparent)) }
@keyframes coinToss{
  0%  { transform:translateY(0) scale(.55); opacity:0 }
  18% { opacity:1 }
  45% { transform:translateY(-16%) scale(1.12) }
  100%{ transform:translateY(0) scale(1); opacity:1 } }
@keyframes coinShadow{
  0%  { transform:scaleX(1) scaleY(1); opacity:.75 }
  45% { transform:scaleX(.55) scaleY(.6); opacity:.28 }
  100%{ transform:scaleX(1) scaleY(1); opacity:.75 } }
@keyframes coinRing{
  0%  { opacity:.95; transform:translate(-50%,-50%) scale(.4) }
  100%{ opacity:0;   transform:translate(-50%,-50%) scale(1.7) } }
@keyframes coinLand{
  0%  { transform:scale(1) }
  38% { transform:scale(1.08) }
  100%{ transform:scale(1.04) } }
/* Le verdict MONTE vers la pièce au lieu de simplement apparaître. */
#bbRoot .bb-intro.done .bi-who{ animation:coinVerdict .45s cubic-bezier(.2,1.3,.4,1) }
@keyframes coinVerdict{ from{ opacity:0; transform:translateY(14px) scale(.9) } to{ opacity:1; transform:none } }


/* ==========================================================================
   PLAYTEST ADMIN 2026-08-03 — LISIBILITÉ EN JEU (6 retours)
   ==========================================================================
   « je joue et je ne comprends pas ce qui se passe ». Six points, une seule cause
   commune : l'information EXISTE (le moteur l'envoie, le JS la rend) mais elle est
   soit tranchée, soit collée, soit trop brève pour être lue. Rien ici ne touche à
   une règle : uniquement de la mise en page et du minutage d'affichage.
   ========================================================================== */

/* ─────────────────────────────────────────────────────────────────────────
   (5) POLICE — « pour les lettres cela ne passe pas, pour les chiffres c'est bon »
   -------------------------------------------------------------------------
   La serif `--tcg-serif` (Palatino) avait été posée le 2026-08-01 pour un rendu
   « carte imprimée ». Elle habillait EXACTEMENT ce que l'admin trouve illisible —
   le NOM de la carte et le TEXTE D'AMBIANCE — et rien d'autre : les chiffres, eux,
   étaient restés en sans-serif tabulaire.
   VERDICT APPLIQUÉ : la serif passe aux CHIFFRES et aux STATS, le TEXTE revient à
   une sans-serif nette. `lining-nums tabular-nums` est OBLIGATOIRE avec Palatino :
   sa fonte de chiffres par défaut est ANCIENNE (chiffres bas de casse, à jambages
   descendants) — sans cette ligne, « 96/140 » sauterait au-dessus et au-dessous de
   la ligne de base et serait pire qu'avant.
   AUCUNE POLICE EXTERNE : que des faces présentes sur Windows/macOS/Linux, plus les
   replis japonais (le Dex est servi en JA et ne doit dépendre d'aucun CDN).

   MISE À JOUR 2026-08-04 — UNE SEULE POLICE DE TEXTE POUR TOUT LE JEU.
   `--tcg-sans` valait `system-ui` : nette, mais c'est la police de l'OS, sans caractère,
   et surtout ce n'était PAS celle du Dex (qui tournait sur Rajdhani/Orbitron via un CDN).
   Deux surfaces du même jeu, deux typographies. Cette pile est donc alignée sur
   `--font-ui` de waifudex/css/dex.css : les DEUX seuls hôtes de cette feuille — le Dex
   (index.html l.34) et le labo WCM (combat-arena.html l.9) — écrivent dans la même voix.
   ⚠️ L'overlay Twitch (WaifuCatch-Central/public/overlay.html) ne charge PAS cette feuille
   — vérifié : 0 occurrence d'`arena-board` dans le fichier. Il redessine ses propres cartes
   dans un <style> inline, avec son propre @import Google Fonts (Rajdhani + Orbitron). Rien
   ici ne l'atteint, ni en bien ni en mal : sa typographie reste à traiter chez lui.
   ⚠️ Les CHIFFRES ne bougent pas : `--tcg-num` et `--tcg-serif` sont inchangés — c'est
   exactement ce que l'admin dit trouver réussi sur les cartes.

   MISE À JOUR 2026-08-05 — TROISIÈME PASSE, ET UNE SEULE SOURCE.
   La pile Trebuchet MS posée le 2026-08-04 a été REJETÉE (« la police d'écriture ne me
   plaît pas »), comme la serif Palatino avant elle. On arrête de chercher une police
   « de caractère » : `--tcg-sans` prend une PILE SYSTÈME NEUTRE, `system-ui` en tête.
   SURTOUT, la valeur n'est plus RECOPIÉE ici : elle est lue dans `--font-ui`, la variable
   centrale de dex.css. Le littéral qui suit n'est plus qu'un REPLI, pour les hôtes qui
   ne chargent pas dex.css.
     · Dex   (index.html : dex.css PUIS arena-board.css) → `--font-ui` est définie sur
       `:root`, donc héritée ici : changer la police du jeu = éditer UNE ligne de dex.css.
     · Labo  (combat-arena.html) → `--font-ui` n'existe pas, le repli s'applique. Il est
       écrit à l'identique de dex.css : les deux surfaces restent d'accord.
   Les deux déclarations ci-dessous doivent rester identiques (`#bbRoot,.bb-skin` couvre
   le plateau et les grilles `.bb-skin` du Dex ; `.card` couvre une carte montée hors de
   ces deux crochets, ce qui arrive au labo).
   ───────────────────────────────────────────────────────────────────────── */
#bbRoot, .bb-skin{
  --tcg-sans:var(--font-ui, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
             'Hiragino Sans', 'Noto Sans JP', 'Yu Gothic UI', Meiryo,
             'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif);
  --tcg-num:'Palatino Linotype','Book Antiqua',Palatino,Georgia,'Times New Roman',serif }
:where(#bbRoot, .bb-skin) .card{ --tcg-sans:var(--font-ui, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
       'Hiragino Sans', 'Noto Sans JP', 'Yu Gothic UI', Meiryo,
       'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif) }
/* TEXTE → sans-serif (nom de la carte, citation, nom d'attaque, passif, rareté) */
:where(#bbRoot, .bb-skin) .card .nm{ font-family:var(--tcg-sans); letter-spacing:0 }
:where(#bbRoot, .bb-skin) .card .cardatks .cardflav{ font-family:var(--tcg-sans) }
:where(#bbRoot, .bb-skin) .card .cardatks b{ font-family:var(--tcg-sans) }
:where(#bbRoot, .bb-skin) .card .cardatks u{ font-family:var(--tcg-sans) }
:where(#bbRoot, .bb-skin) .card .rar{ font-family:var(--tcg-sans) }
/* CHIFFRES ET STATS → serif, avec des chiffres ALIGNÉS et de largeur fixe */
:where(#bbRoot, .bb-skin) .card .hp b, :where(#bbRoot, .bb-skin) .card .hp em, :where(#bbRoot, .bb-skin) .card .st, :where(#bbRoot, .bb-skin) .card .cardatks em{
  font-family:var(--tcg-serif); font-variant-numeric:lining-nums tabular-nums }
:where(#bbRoot, .bb-skin) .bb-inspect-stats b{ font-family:var(--tcg-num); font-variant-numeric:lining-nums tabular-nums }

/* ─────────────────────────────────────────────────────────────────────────
   (2) BARRE DE VIE — REPRISE 2026-08-06, référence demandée : POKÉMON TCG POCKET
   -------------------------------------------------------------------------
   RETOUR ADMIN après une vraie partie : « elle fonctionne mais ne convainc pas ».
   RELEVÉ AU NAVIGATEUR AVANT CORRECTION (harnais servant CETTE feuille, carte de
   banc 172×249 et carte active 210×304 en 1280×900 ; 86×124 et 114×164 en 375×812) :
     · hauteur 5 px / 7 px = 2,01 % / 2,30 % de la hauteur de carte (4 px / 5 px, soit
       3,23 % / 3,05 %, sur téléphone) — sous le seuil où l'œil lit « jauge » ;
     · `top:0; left:0; right:0`, `border-radius:0 px` : collée aux trois bords, elle se
       confond avec le liseré de rareté de la carte au lieu d'être un instrument ;
     · remplissage en dégradé PASTEL vertical `#9dffc8 → #2fd97a`, `box-shadow:none` :
       aucun contour, donc rien qui la détache d'une illustration claire ;
     · le chiffre de PV est une SECONDE boîte, 8 px plus bas, coins à 6 px : deux objets
       sans rapport visuel là où Pokémon n'en montre qu'un.

   CE QUI CARACTÉRISE LA JAUGE DE TCG POCKET — et ce qu'on en transpose :
     (a) une CAPSULE posée sur son propre socle sombre, jamais peinte à même l'art :
         ici rentrée de 2,4 % sur les trois bords, `border-radius:99px`, socle
         quasi opaque + double cerne (noir dehors, blanc dedans) ;
     (b) une ÉPAISSEUR de jauge — environ 4 % de la hauteur de la carte ;
     (c) une COULEUR FRANCHE : deux teintes séparées par une cassure NETTE à 46 %
         (le reflet d'une capsule), pas un dégradé mou ; vert → ambre → rouge ;
     (d) la PERTE lue par une bande CLAIRE qui recule. Le fantôme passe du rouge au
         BLANC : chez Pokémon le morceau qui vient de partir s'ÉCLAIRE. Le rouge reste
         réservé au danger (PV bas) — le garder aux deux endroits, c'était deux
         messages contradictoires dans 7 px de haut ;
     (e) le CHIFFRE rattaché à la jauge : même gouttière (2,4 %), mêmes coins ronds,
         même socle, et un cerne noir sous le glyphe.

   CE QU'ON N'A **PAS** COPIÉ, ET POURQUOI :
     · Pokémon place la jauge SOUS la carte. Interdit ici : `.card` porte
       `overflow:hidden` et c'est `bbCardHTML` (arena-board.js) qui pose l'élément —
       or le JS est hors périmètre de ce lot. Et le bas de nos cartes est plein (nom,
       rareté, stats, et le bloc d'attaques sur la carte active). La capsule reste donc
       en haut, seule bande libre, mais DÉTACHÉE du bord.
     · Nos cartes portent en plus des pastilles d'ÉLÉMENT, de 2e élément et d'ÉTAT que
       Pokémon n'a pas : toute cette colonne descend d'un cran sous la capsule.

   POURQUOI DES POURCENTAGES ET PAS DES PIXELS. Cette feuille définit QUATRE tailles de
   carte (170/208 px bureau, 132/158 px paysage court, 84/112 px portrait, 74/88 px
   paysage très court) : une hauteur en px donnait une jauge de 2 % ici et de 7 % là.
   Exprimée en % de la hauteur de la carte — le `top`/`height` d'un absolu se résout sur
   la hauteur du bloc conteneur, définie ici par `aspect-ratio` — la même règle donne
   3,7 à 4,0 % PARTOUT, sans une seule surcharge par média. Le `clamp()` pose un plancher
   de 5 px (lisible sur la plus petite carte) et un plafond de 12 px (au-delà, la capsule
   mange l'illustration). MESURÉ APRÈS, cf. le tableau en fin de section.
   ───────────────────────────────────────────────────────────────────────── */
:where(#bbRoot, .bb-skin) .card .hpbar{ position:absolute; top:1.7%; left:2.4%; right:2.4%;
  height:clamp(5px, 3.7%, 12px); z-index:4;
  overflow:hidden; pointer-events:none; border-radius:99px;
  background:rgba(2,4,10,.92);
  /* Le double cerne est ce qui la rend lisible sur une illustration BLANCHE : le cerne
     noir extérieur la découpe du fond, le liseré blanc intérieur redonne la silhouette
     de capsule quand le fond est sombre. Calculé sur les couleurs réellement composées,
     art blanc (#ffffff) : contraste socle/illustration 17,74:1 (15,71:1 avant ce lot). */
  box-shadow:0 0 0 1px rgba(0,0,0,.90), inset 0 0 0 1px rgba(255,255,255,.30),
             0 2px 6px -2px rgba(0,0,0,.85) }
:where(#bbRoot, .bb-skin) .card.active .hpbar{ height:clamp(6px, 3.9%, 14px) }
/* Les couches gardent des bouts CARRÉS : c'est la capsule qui les découpe
   (`overflow:hidden` + `border-radius`), donc le bord d'attaque du remplissage reste
   une coupe nette — on lit le niveau exact, pas un bout arrondi qui triche. */
:where(#bbRoot, .bb-skin) .card .hpbar i{ position:absolute; left:0; top:0; bottom:0; display:block }
/* Le fantôme est SOUS le remplissage : ce qu'on voit dépasser, c'est la vie perdue.
   BLANC (et non plus rouge) + halo : sur 9 px de haut, c'est le seul contraste qui
   se voit à coup sûr contre le vert du remplissage ET contre le socle noir.
   La DURÉE ne change pas (0,75 s + 0,14 s d'attente) : la perte doit rester aussi
   longue à lire qu'avant. */
:where(#bbRoot, .bb-skin) .card .bb-hpghost{ background:linear-gradient(180deg,#ffffff 0 46%,#ffd8d8 46%);
  box-shadow:0 0 7px rgba(255,255,255,.85);
  transition:width .75s cubic-bezier(.35,0,.2,1) .14s }
/* `inset -2px 0 0` = le bord d'attaque clair de la jauge : il dit où on en est même
   quand la barre est presque pleine et que la cassure de brillance suffit mal. */
:where(#bbRoot, .bb-skin) .card .bb-hpfill{ background:linear-gradient(180deg,#6cf09b 0 46%,#12b44c 46%);
  box-shadow:inset -2px 0 0 rgba(255,255,255,.65);
  transition:width .16s linear }
/* `.high` est ÉCRITE EXPLICITEMENT : le labo (combat-arena.css l.373) porte encore un
   `.bb-hpfill.high` de l'ancien plateau, à spécificité (0,2,0) comme `.card .bb-hpfill`.
   L'ordre de chargement nous donnerait raison (arena-board.css est la seconde feuille),
   mais on ne fait pas reposer une couleur de barre de vie sur un ordre de <link>. */
:where(#bbRoot, .bb-skin) .card .bb-hpfill.high{ background:linear-gradient(180deg,#6cf09b 0 46%,#12b44c 46%) }
:where(#bbRoot, .bb-skin) .card .bb-hpfill.mid{ background:linear-gradient(180deg,#ffd95c 0 46%,#df8a00 46%) }
:where(#bbRoot, .bb-skin) .card .bb-hpfill.low{ background:linear-gradient(180deg,#ff8f7c 0 46%,#d01c1c 46%);
  animation:hpLowPulse 1.05s ease-in-out infinite }
@keyframes hpLowPulse{ 50%{ filter:brightness(1.45) } }
/* ---- SOUS 20 %, C'EST LE SOCLE QUI ALERTE ----
   Conséquence directe de l'arrondi : à 1 ou 2 PV, le remplissage ne fait plus que
   quelques dixièmes de pixel et disparaît DANS le bout rond de la capsule. La couleur
   ne peut donc pas reposer sur lui seul. Le socle prend le relais — il fait toute la
   largeur, il est toujours visible. `:has()` est ignoré par un navigateur qui ne le
   connaît pas : on retombe alors exactement sur le socle neutre, jamais sur du cassé. */
:where(#bbRoot, .bb-skin) .card .hpbar:has(.bb-hpfill.low){ background:rgba(44,4,6,.92);
  box-shadow:0 0 0 1px rgba(0,0,0,.90), inset 0 0 0 1px rgba(255,130,130,.45),
             0 0 9px -2px rgba(255,60,60,.85) }
/* Le MAXIMUM à côté du courant, sur la grande carte : « 96/140 » se lit d'un coup. */
:where(#bbRoot, .bb-skin) .card .hp em{ font-style:normal; font-size:.5rem; font-weight:800; opacity:.7; margin-left:1px }
:where(#bbRoot, .bb-skin) .card.active .hp em{ font-size:.62rem }
/* ---- LE CHIFFRE APPARTIENT À LA JAUGE ----
   Même gouttière que la capsule (2,4 %, plancher 4 px pour les cartes de téléphone),
   mêmes coins ronds, même socle : les deux boîtes se lisent comme un seul instrument.
   Le cerne noir sous le glyphe remplace le halo ROUGE de l'ancienne version — sur une
   illustration claire le halo rouge délavait le chiffre au lieu de l'aider, et il
   contredisait le code couleur (rouge = danger, cf. `.bb-hpfill.low`). */
:where(#bbRoot, .bb-skin) .card .hp{ border-radius:99px; padding:1px 6px;
  background:rgba(3,5,12,.88); border:1px solid rgba(255,255,255,.26);
  box-shadow:0 2px 6px -2px rgba(0,0,0,.85) }
:where(#bbRoot, .bb-skin) .card.active .hp{ padding:2px 8px }
:where(#bbRoot, .bb-skin) .card .hp b{ text-shadow:0 0 3px #000, 0 1px 2px #000 }
:where(#bbRoot, .bb-skin) .card .hp i{ text-shadow:0 0 4px rgba(87,217,138,.6), 0 1px 2px #000 }
/* ---- LA COLONNE DE PASTILLES PASSE SOUS LA CAPSULE ----
   `5,4 %` = `1,7 %` (haut de la capsule) + `3,7 %` (sa hauteur) ; le `+4px` absorbe le
   plancher du `clamp()` sur les petites cartes ET donne la respiration. Les décalages
   qui suivent (24/29 px pour le 2e élément, 27/33 px pour les pastilles d'état) sont
   EXACTEMENT ceux d'avant ce lot — la colonne descend d'un bloc, elle ne se réorganise
   pas.

   ⚠️ `#bbRoot` EN TÊTE, ET CE N'EST PAS DÉCORATIF. Ces cinq règles DÉPLACENT des éléments
   qui existent aussi HORS du tapis : la fiche de carte du Dex et la vitrine « Mes Decks »
   montent le visuel officiel dans un conteneur `.bb-skin` (dex.js `officialCardHTML`), et
   cette carte-là porte bien `.el` / `.el2` mais **aucune** `.hpbar` — vérifié dans le
   rendu : ni `hpbar`, ni `.hp`, ni `.stpills`. Sans le crochet, la pastille d'élément du
   Dex descendait de 9 px pour laisser la place à une barre qui n'y est pas.
   `scope-board-css.py` laisse volontairement passer les sélecteurs commençant par
   `#bbRoot` : ils ne toucheront jamais `.bb-skin`. Le tapis, lui, est TOUJOURS sous
   `#bbRoot` — `bbMountBoard` (arena-board.js) le crée avec cet id, au labo comme au Dex.

   ⚠️ `.el2` doit rester APRÈS `.el` : à spécificité égale, c'est la dernière règle qui
   gagne. Le bloc portrait en fin de feuille ne redéclare donc plus `.card .el` (il le
   faisait, et écrasait au passage le `top` du 2e élément — sur téléphone les deux
   pastilles d'élément se superposaient exactement : relevé `.el2` offsetTop = 7 px,
   identique à celui de `.el`). */
/* HORS TAPIS (fiche de carte du Dex, « Mes Decks », constructeur de deck) : on REDIT
   les valeurs d'avant ce lot. Sans ces trois lignes la carte du Dex remonterait à
   `top:5px` / `top:29px` (la déclaration d'origine, l. ~141), soit un déplacement de
   3 px qui n'a rien à voir avec la barre de vie. */
:where(#bbRoot, .bb-skin) .card .el, :where(#bbRoot, .bb-skin) .card .hp{ top:8px }
:where(#bbRoot, .bb-skin) .card .el2{ top:32px }
:where(#bbRoot, .bb-skin) .card.active .el2{ top:37px }
#bbRoot .card .el, #bbRoot .card .hp{ top:calc(5.4% + 4px) }
#bbRoot .card .el{ left:max(4px, 2.4%) }
#bbRoot .card .hp{ right:max(4px, 2.4%) }
#bbRoot .card .el2{ top:calc(5.4% + 28px) }
#bbRoot .card.active .el2{ top:calc(5.4% + 33px) }
#bbRoot .stpills{ top:calc(5.4% + 31px) }
#bbRoot .card.active .stpills{ top:calc(5.4% + 37px) }

/* ─────────────────────────────────────────────────────────────────────────
   (1) DÉGÂTS ET SOINS — « mal affichés, impossible de bien comprendre »
   -------------------------------------------------------------------------
   · La couche `.bb-fx-out` vit HORS de la carte : `.card` porte `overflow:hidden` et
     rabotait les flottants LARGES — 28,5 px mesurés sur un nom d'attaque long, carte de
     banc, 1280x900 (cf. le relevé complet dans bbCardHTML).
   · Chaque flottant est empilé sous les précédents (`--off`, posé par bbFloat à partir
     de leurs hauteurs RÉELLES) et part 0,22 s plus tard : deux messages ne se recouvrent
     plus. Mesuré au navigateur sur 5 scénarios (jusqu'au pire cas : 6 flottants d'un
     seul coup, carte active / banc / adverse), 5 relevés chacun entre 400 et 2100 ms :
     0 paire de boîtes sécantes, et 57,7 px de dépassement maximal sous `#bbRoot` —
     à l'intérieur des 104 px réservés au menu d'actions.
   · Durée 1,8 s au lieu de 1,2 s.
   · Une PLAQUE sombre teintée par nature (rouge = je perds, vert = je gagne,
     ambre = état) : sur une illustration claire, le texte blanc disparaissait.
   · `.bb-who` nomme la carte visée, `.bb-adv b` porte le multiplicateur.
   ───────────────────────────────────────────────────────────────────────── */
#bbRoot .bb-fx-out{ position:absolute; inset:0; z-index:30; pointer-events:none; overflow:visible }
#bbRoot .bb-float{ --fc:#dfe8ff;
  top:calc(22% + var(--off,0px));
  padding:3px 9px 4px; border-radius:10px; max-width:220px;
  background:linear-gradient(180deg, rgba(6,9,20,.80), rgba(6,9,20,.62));
  border:1px solid color-mix(in srgb, var(--fc) 50%, transparent);
  box-shadow:0 6px 18px -8px #000, 0 0 16px -6px color-mix(in srgb, var(--fc) 55%, transparent);
  animation:bbFloatUp 1.8s ease-out forwards }
#bbRoot .bb-float.malus{ animation:bbFloatSink 1.8s ease-out forwards }
#bbRoot .bb-float-dmg, #bbRoot .bb-float-crit, #bbRoot .bb-float-burn, #bbRoot .bb-float-ko{ --fc:#ff6b7f }
#bbRoot .bb-float-heal, #bbRoot .bb-float-boon{ --fc:#5cf0a0 }
#bbRoot .bb-float-malus, #bbRoot .bb-float-stun{ --fc:#ffab6b }
#bbRoot .bb-float-act{ --fc:#ffd76a }
/* À QUI : le nom est lu dans la carte visée, il ne peut pas se tromper de cible. */
#bbRoot .bb-who{ display:block; font-family:var(--tcg-sans); font-size:.58rem; font-weight:800;
  letter-spacing:.04em; color:color-mix(in srgb, var(--fc) 72%, #ffffff);
  text-shadow:0 1px 3px #000; max-width:100%; margin:0 auto 1px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
/* POURQUOI : « ⬆ super efficace ×1,20 » — le multiplicateur en chiffres serif. */
#bbRoot .bb-adv b{ font-family:var(--tcg-num); font-variant-numeric:lining-nums tabular-nums;
  font-weight:900; margin-left:3px }
#bbRoot .bb-efftxt{ font-family:var(--tcg-sans) }
#bbRoot .bb-dmg, #bbRoot .bb-dmg.big{ font-variant-numeric:lining-nums tabular-nums }

/* ─────────────────────────────────────────────────────────────────────────
   (3) FAIBLESSES — visibles AVANT de choisir l'attaque
   -------------------------------------------------------------------------
   Pastille de multiplicateur sur chaque bouton d'attaque (contre la carte adverse
   active) et tableau complet dans la fiche d'inspection. Vert = ça fait mal,
   gris = c'est encaissé. Le bouton avantageux prend en plus un liseré vert : on
   voit le bon choix sans lire un seul chiffre.
   ───────────────────────────────────────────────────────────────────────── */
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-mult{ margin-left:6px; padding:0 6px; border-radius:99px;
  font-family:var(--tcg-num); font-variant-numeric:lining-nums tabular-nums;
  font-weight:900; border:1px solid currentColor; white-space:nowrap }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-mult.up{ color:#7cf0a0; background:rgba(80,240,150,.15) }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk-mult.down{ color:#9fb0c8; background:rgba(160,180,210,.12) }
:where(#bbRoot, .bb-skin) #bbActions .bb-atk.bb-atk-up{ border-color:rgba(105,240,174,.55);
  box-shadow:0 0 14px -5px rgba(80,240,150,.85) }
#bbRoot .bb-inspect-weak{ display:flex; flex-direction:column; gap:3px;
  margin-top:8px; align-items:center }
#bbRoot .bb-inspect-weak .wkrow{ display:flex; flex-wrap:wrap; gap:4px;
  justify-content:center; align-items:center; font-size:.62rem; font-weight:900 }
#bbRoot .bb-inspect-weak .wkrow.up{ color:#7cf0a0 }
#bbRoot .bb-inspect-weak .wkrow.down{ color:#9fb0c8 }
#bbRoot .bb-inspect-weak .wk{ display:inline-flex; align-items:center; gap:3px;
  padding:1px 6px; border-radius:99px; background:rgba(255,255,255,.06);
  border:1px solid currentColor }
#bbRoot .bb-inspect-weak .wk b{ font-family:var(--tcg-num); font-weight:900;
  font-variant-numeric:lining-nums tabular-nums }

/* ─────────────────────────────────────────────────────────────────────────
   (4) « AVALANCHE49 » — la ligne d'attaque de la fiche n'avait AUCUNE mise en page
   -------------------------------------------------------------------------
   `.bb-inspect-atk` ne recevait que `flex-wrap:wrap` (inerte sur un bloc) et ses
   enfants `.pip` / `.an` / `.ap` / `.ad` n'étaient stylés que sous `.atk`, la classe
   de l'ANCIEN bouton d'attaque — que cette fiche ne porte pas. Quatre spans nus se
   suivaient sans le moindre espace : « ❄Avalanche49🎯 Critique — … ».
   Elle devient une vraie grille : pastille · NOM · séparateur · PUISSANCE nommée,
   puis la ligne d'effet en pleine largeur, son emoji dans sa propre colonne.
   ───────────────────────────────────────────────────────────────────────── */
#bbRoot .bb-inspect-atks{ display:flex; flex-direction:column; gap:5px }
#bbRoot .bb-inspect-atk{ display:grid; grid-template-columns:auto 1fr auto auto;
  align-items:center; gap:0 7px; padding:6px 9px; text-align:left; border-radius:10px;
  background:linear-gradient(135deg, color-mix(in srgb,var(--ael,#888) 16%, rgba(255,255,255,.04)), rgba(255,255,255,.03));
  border:1px solid color-mix(in srgb,var(--ael,#888) 45%, transparent) }
#bbRoot .bb-inspect-atk .pip{ position:static; translate:none; width:21px; height:21px;
  border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:11px;
  background:radial-gradient(circle at 35% 30%, color-mix(in srgb,var(--ael,#888) 75%,#fff),
                                               color-mix(in srgb,var(--ael,#888) 85%,#000)) }
#bbRoot .bb-inspect-atk .an{ display:block; font-family:var(--tcg-sans); font-weight:800;
  font-size:.8rem; color:#eaf1ff; line-height:1.2 }
#bbRoot .bb-inspect-atk .asep{ color:#66748f; font-weight:900 }
#bbRoot .bb-inspect-atk .ap{ font-family:var(--tcg-num); font-weight:900; font-size:.8rem;
  font-variant-numeric:lining-nums tabular-nums; color:#fff; white-space:nowrap;
  padding:1px 8px; border-radius:99px; background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.20) }
/* La ligne d'effet passe SOUS, en pleine largeur — son emoji ne peut plus se coller
   au nombre qui la précédait. */
#bbRoot .bb-inspect-atk .ad{ grid-column:1 / -1; display:flex; align-items:flex-start; gap:6px;
  flex:none; margin-top:5px; font-family:var(--tcg-sans); font-size:.64rem; line-height:1.35 }
#bbRoot .bb-inspect-atk .adi{ font-style:normal; flex:0 0 auto; font-size:.85rem; line-height:1.15 }
#bbRoot .bb-inspect-atk .adt{ flex:1 1 auto; min-width:0 }
/* Légende « 💥 = puissance de l'attaque », à droite du titre « Attaques ». */
#bbRoot .bb-inspect-head{ display:flex; align-items:baseline; justify-content:space-between; gap:8px }
#bbRoot .bb-inspect-legend{ font-size:.55rem; font-weight:700; letter-spacing:.02em;
  text-transform:none; color:#8fa2c4; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }

/* ─────────────────────────────────────────────────────────────────────────
   (6) EMPREINTES — « des symboles sans savoir ce qu'ils font ni combien de tours »
   -------------------------------------------------------------------------
   La pastille prend la teinte de son élément et, sur la carte ACTIVE, écrit son
   nom + sa durée (au banc elle garde le chiffre seul, faute de place). La fiche
   d'inspection ajoute deux notes en clair, sous le badge.
   ───────────────────────────────────────────────────────────────────────── */
/* ⚠️ `box-sizing:border-box` N'EST PAS COSMÉTIQUE : sans lui le `max-width:100%` de la
   ligne suivante ne sert à RIEN. La pastille est en `content-box` par défaut ; 100 % borne
   alors sa BOÎTE DE CONTENU, et les 7 px de rembourrage de chaque côté plus la bordure
   s'ajoutent PAR-DESSUS. Mesuré sur un écran 412×915, carte active, pastille
   « ⚡ Empreinte Foudre · 3 tour(s) » : conteneur `.stpills` 103 px, pastille 119 px, donc
   10 px DEHORS de la carte (les autres pastilles, plus courtes, ne le montraient pas —
   « 🛡 Bouclier 18 » 69 px, « 🔥 Brûlure · 2 tour(s) » 98 px). En `border-box` la pastille
   retombe à 103 px et finit 6 px À L'INTÉRIEUR du bord. Le texte reste coupé par
   l'ellipsis de `.bb-st b` (33 px cachés) : il n'y a pas la place sur un téléphone, mais
   la phrase entière reste accessible — infobulle au survol, toast au clic (bbWireInspect,
   contrôlé : un clic sur la pastille affiche bien « Empreinte Eau — la frapper avec un
   élément réactif déclenche… »). */
#bbRoot .card.active .bb-st{ font-size:.58rem; padding:2px 7px; max-width:100%; box-sizing:border-box }
#bbRoot .bb-st b{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font-family:var(--tcg-sans) }
#bbRoot .bb-st.st-mark{ background:color-mix(in srgb, var(--el,#29b6f6) 26%, rgba(6,8,18,.88));
  color:#f2f7ff }
#bbRoot .bb-inspect-badges .note{ flex:0 0 100%; padding:1px 2px; border:0; background:none;
  font-family:var(--tcg-sans); font-size:.6rem; font-weight:600; line-height:1.35;
  color:#93a4c4; text-align:center }

/* ─────────────────────────────────────────────────────────────────────────
   MOBILE (portrait ≤ 560 px) — la carte tombe autour de 100 px de large : la
   plaque des flottants s'y ajuste, rien ne déborde.
   -------------------------------------------------------------------------
   2026-08-06 — TROIS RÈGLES RETIRÉES D'ICI, ET C'EST VOULU :
     · `.card .hpbar{height:4px}` / `.card.active .hpbar{height:5px}` — la hauteur est
       désormais un `clamp(5px, 3,7 %, 12px)` calculé sur la carte elle-même. Mesuré en
       375×812 : 5 px sur la carte de banc (86×124) et 6,4 px sur la carte active
       (114×164), soit 4,0 % et 3,9 % — la MÊME proportion que sur grand écran, alors
       que ces deux lignes donnaient 3,2 % et 3,0 %.
     · `.card .el, .card .hp{top:7px}` — remplacée par l'ancrage en % de la section
       « BARRE DE VIE ». Elle avait un effet de bord : venant APRÈS `.card .el2`, à
       spécificité égale, elle ramenait AUSSI le 2e élément à 7 px. Sur téléphone les
       deux pastilles d'élément se superposaient donc exactement (relevé au navigateur :
       `.el2` offsetTop = 7 px, comme `.el`), et une carte à double élément n'affichait
       plus que sa seconde teinte. Corrigé par simple remise en ordre.
   ───────────────────────────────────────────────────────────────────────── */
@media (orientation:portrait) and (max-width:560px){
  #bbRoot .bb-float{ max-width:150px; padding:2px 7px 3px }
  #bbRoot .bb-who{ font-size:.5rem }
  #bbRoot .bb-inspect-legend{ font-size:.5rem }
}


/* ═══════════════════════════════════════════════════════════════════════════
   PLAYTEST ADMIN 2026-08-07 — (2) LE GAIN D'ÉLAN SE VOIT, (3) LA PIÈCE PORTE
   LES DEUX VISAGES
   ═══════════════════════════════════════════════════════════════════════════

   (2) « TOUJOURS PAS DE VISUEL DE DÉGÂTS D'ÉLAN »
   -----------------------------------------------
   L'Élan monte à chaque coup et déclenche l'Ultime à 100 %, mais la jauge n'était
   redessinée qu'au repeint FINAL du lot : le joueur voyait un verre au niveau
   changé, jamais un GAIN. `bbElanPop` pose maintenant le chiffre AU-DESSUS du
   verre concerné — c'est là que le regard va chercher sa jauge, et c'est la seule
   zone de l'écran encore libre pendant un coup (la carte porte déjà les dégâts,
   l'état et le soin).
   Le chiffre lui-même n'est affiché que si le miroir client retombe EXACTEMENT
   sur le total publié par le serveur (cf. bbElanPlan) : ce style ne sert donc
   jamais à afficher une valeur douteuse.
   ANCRAGE : `.elan` porte déjà `position:relative` (en tête de feuille), la
   pastille se cale donc sur le verre sans toucher au flux du flanc.

   (3) LA PIÈCE DE DÉPART
   ----------------------
   « Elle doit porter l'avatar de chaque joueur au lieu de la lettre dans un rond. »
   La photo entre dans `.bi-face` (cf. `faceHTML`), mais SANS la remplir : 86 % de
   la face, ce qui laisse un anneau de la couleur du camp tout autour. La pièce
   reste donc lisible comme pièce — deux camps, deux teintes — et le `box-shadow`
   inset qui lui donne son creux garde de la place pour se voir.
   Hôte sans `BOARD_HOST.avatar` (labo WCM, overlay Twitch) : aucune image n'est
   produite, ces règles ne s'appliquent à rien et le rendu est inchangé.
   ═══════════════════════════════════════════════════════════════════════════ */

/* (2) LE CHIFFRE D'ÉLAN
   `left` / `top` sont posés EN PIXELS par `bbElanPop`, relativement à `#bbRoot` (qui
   porte `position:relative`, l. 730) : la pastille n'est donc fille NI de la jauge — que
   `bbPaint` reconstruit au repeint final — NI de `.scene`, qui devient `overflow:hidden`
   en portrait. Le `translate(-50%, …)` des étapes ci-dessous la recentre sur la jauge. */
:where(#bbRoot, .bb-skin) .bb-elanpop{ position:absolute; z-index:140;
  pointer-events:none; white-space:nowrap;
  font-family:'Orbitron',system-ui,sans-serif; font-weight:900; font-size:.68rem;
  letter-spacing:.04em; color:#e9dcff;
  text-shadow:0 0 10px rgba(166,120,255,.95), 0 2px 4px rgba(0,0,0,.9);
  animation:elanPop 1.5s ease-out forwards }
/* L'ULTIME DÉCHAÎNÉ VIDE LA JAUGE : le « −100 » prend la teinte dorée de l'Ultime,
   pour qu'une DÉPENSE ne se lise jamais comme un gain. */
:where(#bbRoot, .bb-skin) .bb-elanpop.down{ color:#ffe07a;
  text-shadow:0 0 10px rgba(255,190,60,.95), 0 2px 4px rgba(0,0,0,.9) }
@keyframes elanPop{
  0%  { opacity:0; transform:translate(-50%,10px) scale(.8) }
  16% { opacity:1; transform:translate(-50%,-2px) scale(1.1) }
  28% { opacity:1; transform:translate(-50%,0) scale(1) }
  72% { opacity:1; transform:translate(-50%,-14px) scale(1) }
  100%{ opacity:0; transform:translate(-50%,-30px) scale(1) } }
/* Le VERRE s'allume au moment du gain — la pastille dit combien, le halo dit « ici ».
   La transition est posée à part : elle n'écrase aucun `box-shadow` existant, et
   `.elan.full .glass` (Ultime prêt) garde le sien. */
:where(#bbRoot, .bb-skin) .elan .glass{ transition:box-shadow .25s ease }
:where(#bbRoot, .bb-skin) .elan.bb-elangain .glass{ box-shadow:0 0 20px rgba(166,120,255,.85), inset 0 2px 6px rgba(0,0,0,.6) }
:where(#bbRoot, .bb-skin) .elan.full.bb-elangain .glass{ box-shadow:0 0 22px rgba(255,215,106,.9), inset 0 2px 6px rgba(0,0,0,.5) }

/* (3) L'AVATAR SUR LA FACE DE LA PIÈCE */
:where(#bbRoot, .bb-skin) .bi-face .bi-facepic{ display:block; width:86%; height:86%; border-radius:50%;
  object-fit:cover; box-shadow:0 2px 12px rgba(0,0,0,.6) }

/* ACCESSIBILITÉ — le bloc global `.bb *` réduit toute animation à 0,01 ms : la
   pastille d'Élan, qui finit à `opacity:0`, disparaîtrait AVANT d'être lue. On la
   fige donc visible ; c'est le `setTimeout` de `bbElanPop` (1,5 s) qui la retire.
   Spécificité (1,0,1) contre (0,1,0) : cette règle gagne, `!important` compris. */
@media (prefers-reduced-motion: reduce){
  #bbRoot .bb-elanpop{ animation:none !important; opacity:1;
    transform:translate(-50%,-12px) }
}

/* MOBILE PORTRAIT — la pastille rétrécit avec le reste des libellés du flanc.
   (Aucune règle de POSITION ici : la pastille vit dans `#bbRoot`, hors de `.scene` et
   hors des flancs, donc ni le passage des flancs dans le flux ni l'`overflow:hidden` de
   `.scene` ne l'atteignent — cf. le commentaire de `bbElanPop`.) */
@media (orientation:portrait) and (max-width:560px){
  #bbRoot .bb-elanpop{ font-size:.58rem }
}

/* ============================================================================
   LIGNE DE COMMANDE UNIQUE (2026-08-07)
   ----------------------------------------------------------------------------
   RETOUR ADMIN, capture à l'appui : « sur la même ligne que "à ton tour", rangé à
   droite ou à gauche, il faudrait mettre Abandonner juste en emoji drapeau ; mettre
   le nombre de tour, la phase actuelle et les options (les 3 traits) aussi. »

   CE QUI CLOCHAIT : la même information vivait à TROIS endroits — la boîte `#bbBanner`
   ancrée en haut à gauche du tapis adverse (tour + phase + « 🏳 Abandonner » en toutes
   lettres), cette bande pleine largeur (le message « À TON TOUR »), et le ☰ flottant
   dans le coin. Sur un téléphone les trois se disputent le même quart d'écran.

   ORDRE DANS LE DOM, ET IL EST VOULU :  ☰ · Tour N · Phase · message · Mort subite · 🏳
   Le message prend la place restante et se centre dedans ; les deux groupes de commandes
   sont donc rangés aux extrémités, comme demandé.
   ============================================================================ */
#bbRoot .mat > .bb-turnflag{
  justify-content:flex-start; gap:6px; padding:3px 8px;
  /* La ligne porte maintenant un panneau d'options en descendant : plus de recadrage.
     Le TEXTE garde le sien (ellipsis), et le voile `::after` est en `inset:0`. */
  overflow:visible;
}
/* ⚠️ REMPLACE `:empty` — la ligne n'est PLUS jamais vide (elle porte ses boutons dès le
   montage), donc l'ancienne garde ne masquait plus rien et la barre serait restée
   affichée, sans texte, pendant tout l'écran d'intro (VS puis pièce : ~5 s en PvP).
   `data-msg` est posé par `bbPaintBanner` à la première peinture réelle. */
#bbRoot .mat > .bb-turnflag:not([data-msg]){ display:none }

/* Le message occupe le vide entre les deux groupes et se centre dedans. */
#bbRoot .bb-turnflag .bb-turnflag-txt{ flex:1 1 auto; text-align:center; min-width:0 }

/* ☰ : il quittait son ancrage absolu dans le coin du tapis pour rentrer dans la ligne. */
#bbRoot .bb-turnflag .bb-menu{
  position:static; flex:0 0 auto; order:-1;
  width:26px; height:26px; border-radius:7px; font-size:.85rem;
  display:flex; align-items:center; justify-content:center; padding:0;
}
/* Pastilles TOUR et PHASE : même famille que l'ancienne boîte, en plus compact. */
#bbRoot .bb-turnflag .bb-hud-turn, #bbRoot .bb-turnflag .bb-hud-phase, #bbRoot .bb-turnflag .bb-hud-sd{
  flex:0 0 auto; white-space:nowrap;
  font-size:clamp(.5rem, min(1.35vh, 2.3vw), .72rem); font-weight:800; letter-spacing:.08em;
  padding:2px 8px; border-radius:99px;
  background:rgba(0,0,0,.38); border:1px solid rgba(255,255,255,.10); color:#9fb4dd;
}
#bbRoot .bb-turnflag .bb-hud-phase.mine{ color:var(--tfC); border-color:color-mix(in srgb, var(--tfC) 40%, transparent) }
#bbRoot .bb-turnflag .bb-hud-sd{ color:#ffd76a; border-color:rgba(255,215,106,.45) }

/* DRAPEAU SEUL. 26 px de cible tactile minimum : c'est un bouton qui met fin au combat,
   il ne doit être ni manqué ni cliqué par accident — d'où la confirmation qui suit. */
#bbRoot .bb-turnflag .bb-hud-forfeit{
  flex:0 0 auto; order:99; cursor:pointer;
  width:26px; height:26px; padding:0; border-radius:7px; font-size:.85rem; line-height:1;
  display:flex; align-items:center; justify-content:center;
  color:#ffb9c4; background:rgba(0,0,0,.38); border:1px solid rgba(255,140,160,.28);
}
#bbRoot .bb-turnflag .bb-hud-forfeit:hover{ background:rgba(70,20,32,.85); border-color:rgba(255,140,160,.6) }
/* `hidden` doit gagner contre le `display:flex` ci-dessus (fin de combat, ligne vide). */
#bbRoot .bb-turnflag [hidden]{ display:none }

/* PANNEAU D'OPTIONS : il pendait sous le ☰ quand celui-ci vivait dans le coin. Le ☰ est
   maintenant au milieu du plateau ; un menu déroulant y serait à cheval sur la couture et
   couvrirait des cartes. On le centre — sur téléphone c'est de toute façon plus lisible
   qu'un panneau de coin, et ça évite tout conflit d'empilement avec `.half.me`. */
#bbRoot .bb-opts{
  left:50%; top:50%; transform:translate(-50%,-50%);
  max-height:82%; overflow-y:auto; z-index:90;
}
@media (max-width:760px){
  #bbRoot .mat > .bb-turnflag{ gap:4px; padding:2px 6px }
  #bbRoot .bb-turnflag .bb-menu, #bbRoot .bb-turnflag .bb-hud-forfeit{ width:24px; height:24px; font-size:.78rem }
  #bbRoot .bb-turnflag .bb-hud-turn, #bbRoot .bb-turnflag .bb-hud-phase, #bbRoot .bb-turnflag .bb-hud-sd{ padding:1px 6px; letter-spacing:.04em }
  #bbRoot .bb-opts{ width:min(268px, 88vw) }
}

/* ============================================================================
   BOÎTE DE CONFIRMATION D'ABANDON (2026-08-07)
   ----------------------------------------------------------------------------
   « Abandonner, une fois cliqué dessus, afficher une autre fenêtre pour confirmer
   si oui ou non le joueur veut abandonner. » Elle remplace la confirmation en deux
   temps sur le bouton, devenue impossible : le bouton n'est plus qu'un drapeau.
   Elle est posée dans `#bbRoot` (pas dans `.scene`, qui a `overflow:hidden`) pour
   couvrir le plateau entier, écran de fin exclu.
   ============================================================================ */
#bbRoot .bb-confirm{
  position:absolute; inset:0; z-index:120;
  display:flex; align-items:center; justify-content:center; padding:16px;
  background:rgba(4,6,14,.72); backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
}
#bbRoot .bb-confirm-card{
  width:min(340px, 92%); padding:18px 18px 14px; border-radius:14px; text-align:center;
  background:linear-gradient(180deg,rgba(20,26,50,.99),rgba(10,14,30,.99));
  border:1px solid rgba(255,140,160,.34); box-shadow:0 22px 60px rgba(0,0,0,.75);
}
#bbRoot .bb-confirm-t{ font-weight:900; font-size:.98rem; color:#ffd9e0; letter-spacing:.02em }
#bbRoot .bb-confirm-s{ margin-top:7px; font-size:.78rem; line-height:1.4; color:#a8b2cc }
#bbRoot .bb-confirm-b{ display:flex; gap:9px; margin-top:15px }
#bbRoot .bb-confirm-b button{ flex:1 1 0; cursor:pointer; padding:9px 10px; border-radius:9px;
  font-size:.82rem; font-weight:800; min-height:38px }
/* L'option SÛRE est la plus visible : « Annuler » est plein, « Abandonner » est discret.
   L'inverse (bouton rouge appelant) ferait cliquer par réflexe sur ce qui fait perdre. */
#bbRoot .bb-confirm-no{ color:#0a0e1c; background:linear-gradient(180deg,#cfe0ff,#9fb4dd); border:0 }
#bbRoot .bb-confirm-yes{ color:#ffb9c4; background:rgba(0,0,0,.35); border:1px solid rgba(255,140,160,.4) }
#bbRoot .bb-confirm-yes:hover{ background:rgba(70,20,32,.9) }
#bbRoot .bb-confirm-no:focus-visible, #bbRoot .bb-confirm-yes:focus-visible{ outline:2px solid #7fd4ff; outline-offset:2px }

/* ============================================================================
   QUI JOUE : LE CAMP EN ATTENTE S'ASSOMBRIT (2026-08-07)
   ----------------------------------------------------------------------------
   RETOUR ADMIN : « quand c'est le tour d'un joueur il n'est pas encore bien dissocié
   du joueur en attente ; il faudrait diminuer la lumière du tapis du joueur qui ne
   joue pas. »
   HISTORIQUE — ET C'EST POURQUOI ON PREND CETTE VOIE-LÀ : le plateau a déjà essayé
   deux fois de le dire par un LISERÉ autour du tapis actif, et deux fois ça a échoué
   (« sur un téléphone, un liseré de 1,5 px autour d'un tapis mis à l'échelle 0,95 ne
   se voit pas » — d'où l'ajout de la bande pleine largeur). Un contour ajoute de la
   lumière là où l'œil ne regarde pas ; RETIRER de la lumière sur toute une moitié se
   voit à n'importe quelle échelle, y compris du coin de l'œil.
   ON N'ASSOMBRIT PAS PENDANT L'INTRO NI APRÈS LA FIN : `.bb-turnflag-neutral` couvre
   « combat terminé », et sans `[data-msg]` (avant la première peinture) rien ne
   s'applique — sinon l'écran VS s'ouvrirait avec une moitié déjà éteinte.
   `filter` PLUTÔT QU'UNE SURCOUCHE `::after` : le tapis porte déjà des `::before`/
   `::after` (liquide d'Élan, voiles de skin) — en ajouter un troisième les empilerait,
   et une surcouche opaque aurait aussi éteint les flottants de dégâts qui passent
   au-dessus. `filter` agit sur la moitié et sur elle seule.
   ============================================================================ */
#bbRoot .mat > .half{ transition:filter .35s ease, opacity .35s ease }
/* C'est MON tour → la moitié adverse recule. */
#bbRoot .mat:has(> .bb-turnflag[data-msg].bb-turnflag-mine) > .half.opp, #bbRoot .mat:has(> .bb-turnflag[data-msg].bb-turnflag-their) > .half.me{
  filter:brightness(.62) saturate(.72);
}
/* REPLI pour les moteurs sans `:has()` — la classe est posée par bbPaintBanner sur `.mat`.
   Sans ça, un navigateur un peu ancien perdrait le signal SANS que rien ne le dise. */
#bbRoot .mat.bb-turn-mine  > .half.opp, #bbRoot .mat.bb-turn-their > .half.me{ filter:brightness(.62) saturate(.72) }
@media (prefers-reduced-motion:reduce){
  #bbRoot .mat > .half{ transition:none }
}

/* ── LIGNE UNIQUE SUR TÉLÉPHONE : le message cède la place, pas la pastille ──────────
   MESURÉ à 375×812 sur la vraie ligne : elle fait 373 px, occupés par ☰ (24) + « Tour 7 »
   (44) + « ◆ Phase principale » (101) + 🏳 (24) et leurs gouttières. Il reste 153 px au
   message, qui en réclame 287 : il manque 134 px. AUCUNE taille de police ne referme cet
   écart (même à .55rem il en faudrait encore ~230), donc la troncature « À TON TOUR — C… »
   n'était pas un défaut de réglage : quelque chose devait partir.
   CE QUI PART : le message, parce qu'il RÉPÈTE la pastille de phase (« ◆ Phase
   principale » / « ⏳ Tour adverse ») que l'admin a explicitement demandé de mettre là,
   et parce que le camp en attente s'assombrit désormais — deux signaux disent déjà à qui
   de jouer. La pastille reste : elle est plus courte ET plus précise (elle distingue
   phase principale, phase d'attaque et choix de carte).
   ⚠️ MASQUÉ VISUELLEMENT, PAS SUPPRIMÉ : la ligne porte `aria-live="polite"`, c'est elle
   qui annonce le changement de tour à un lecteur d'écran. `display:none` couperait cette
   annonce ; on le sort du flux en le gardant dans l'arbre d'accessibilité.
   Au-delà de 560 px le message revient : mesuré, il tient (548 px disponibles à 768). */
@media (max-width:560px){
  #bbRoot .bb-turnflag .bb-turnflag-txt{
    position:absolute; width:1px; height:1px; padding:0; margin:-1px;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap;
  }
  /* La pastille de phase se CENTRE dans la place libérée — `margin:auto` et non
     `flex:1`, qui l'étirait sur 257 px et donnait une barre vide au milieu de la ligne.
     `max-width` la borne pour que les traductions longues s'abrègent au lieu de pousser
     le drapeau hors de l'écran. */
  #bbRoot .bb-turnflag .bb-hud-phase{ margin-inline:auto; max-width:60%;
    overflow:hidden; text-overflow:ellipsis }
}

/* ============================================================================
   BANNIÈRE DE MAÎTRESSE : LA CARTE PENCHÉE, PLUS LE MÉDAILLON (2026-08-07)
   ----------------------------------------------------------------------------
   RETOUR ADMIN : « quand une maîtresse est en action on a droit à une bannière pour
   indiquer ce qu'elle fait, c'est trop bien ; sauf qu'au lieu d'un cercle affichant la
   carte, autant mettre la carte — elle est réduite mais dépasse à 50 % environ, et mise
   légèrement penchée d'un côté, c'est plus stylé. »

   CE QUI BLOQUAIT : `.bb-cutin` portait `overflow:hidden`. Aucune carte ne pouvait
   dépasser tant qu'il était là — c'est LUI le verrou, pas la taille du médaillon. On le
   lève. Ce qu'il rognait réellement, c'était la HAUTEUR (92 px) ; l'entrée en glissé de
   `.ci-inner` (translateX 70 px) reste, elle, très à l'intérieur du bandeau, qui court
   sur toute la largeur du plateau — donc rien d'autre ne s'échappe.

   PROPORTIONS : la carte fait 1,55× la hauteur du bandeau, donc elle en déborde d'environ
   la moitié, répartie en haut et en bas. Ratio 0,715 = celui des vraies cartes du jeu
   (63,5 × 88,97 mm), pour que la vignette du combat et la carte imprimée soient la même
   chose. `z-index` au-dessus du bandeau, sinon le voile du `.ci-band` la couperait net à
   la limite des 92 px.

   `pointer-events` reste à `none` (hérité de `.bb-cutin`) : la bannière est décorative,
   elle ne doit jamais intercepter un clic destiné à une carte du plateau.
   ============================================================================ */
#bbRoot .bb-cutin{ overflow:visible }
#bbRoot .bb-cutin .ci-art{
  position:relative; z-index:2;
  width:auto; height:155%; aspect-ratio:.715;
  border-radius:8px;                       /* coins de carte, plus de médaillon rond */
  object-fit:cover; object-position:center 22%;
  border:2px solid #ffd88a;
  box-shadow:0 10px 26px -6px rgba(0,0,0,.85), 0 0 22px -4px rgba(255,190,85,.75);
  /* Penchée d'un côté — et du CÔTÉ DU CAMP : la mienne s'incline vers la gauche, celle de
     l'adversaire vers la droite, dans le sens de son glissé d'entrée. Le mouvement se lit
     comme un seul geste au lieu de deux. */
  transform:rotate(-6deg);
  transform-origin:center 60%;
}
#bbRoot .bb-cutin.opp .ci-art{ transform:rotate(6deg) }
/* Repli sans illustration : le 👑 garde la forme de carte, sinon la bannière change de
   silhouette selon que la maîtresse a une image ou non. */
#bbRoot .bb-cutin .ci-none{
  height:155%; aspect-ratio:.715; border-radius:8px;
  background:linear-gradient(180deg,#1b2242,#0d1226);
  font-size:2rem; transform:rotate(-6deg);
}
#bbRoot .bb-cutin.opp .ci-none{ transform:rotate(6deg) }
/* La carte penchée mange de la largeur : le texte reprend la sienne pour ne pas se faire
   pousser hors du bandeau sur les écrans étroits. */
@media (max-width:760px){
  #bbRoot .bb-cutin .ci-art, #bbRoot .bb-cutin .ci-none{ height:135% }
  #bbRoot .bb-cutin .ci-inner{ gap:9px }
  #bbRoot .bb-cutin .ci-desc{ display:none }   /* la description passe à la trappe avant le nom */
}

/* ============================================================================
   CHRONO DE TOUR (2026-08-07)
   ----------------------------------------------------------------------------
   « Il faut afficher le temps pour chaque joueur afin de faire une action ; il y a
   normalement une limite de temps, elle n'est pas affichée. » 45 s pour jouer,
   20 s pour choisir sa carte après un K.O. — les deux existaient, aucune ne se voyait.
   Même famille visuelle que les pastilles Tour et Phase : le chrono n'est pas une alarme
   permanente, c'est une information de plus sur la ligne. Il ne se met à crier que sur le
   dernier quart du temps accordé.
   ============================================================================ */
#bbRoot .bb-turnflag .bb-hud-time{
  flex:0 0 auto; order:98; white-space:nowrap;
  font-size:clamp(.5rem, min(1.35vh, 2.3vw), .72rem); font-weight:800; letter-spacing:.06em;
  padding:2px 8px; border-radius:99px;
  background:rgba(0,0,0,.38); border:1px solid rgba(255,255,255,.10); color:#9fb4dd;
  /* Chiffres à chasse fixe : sans ça la pastille se dilate à chaque seconde (2 → 1 chiffre)
     et pousse le drapeau d'un pixel en boucle. */
  font-variant-numeric:tabular-nums;
}
/* C'est MON temps qui s'écoule : la pastille prend la couleur de mon tour. */
#bbRoot .bb-turnflag .bb-hud-time.mine{ color:var(--tfC); border-color:color-mix(in srgb, var(--tfC) 38%, transparent) }
/* Dernier quart : rouge et pulsation. Le seuil est calculé sur `total` côté JS, donc il
   vaut ~11 s sur un tour de 45 s et ~5 s sur un choix de carte de 20 s. */
#bbRoot .bb-turnflag .bb-hud-time.urgent{
  color:#ffd0d6; background:rgba(90,16,30,.75); border-color:rgba(255,110,140,.65);
  animation:bbClockPulse .9s ease-in-out infinite;
}
@keyframes bbClockPulse{ 0%,100%{ opacity:1 } 50%{ opacity:.55 } }
@media (prefers-reduced-motion:reduce){
  #bbRoot .bb-turnflag .bb-hud-time.urgent{ animation:none }
}
/* Sur téléphone la ligne est déjà serrée : le chrono garde sa place (c'est une demande
   explicite), c'est la pastille de phase qui s'abrège la première — elle porte déjà
   `text-overflow:ellipsis` et un `max-width`. */
@media (max-width:560px){
  #bbRoot .bb-turnflag .bb-hud-time{ padding:1px 6px; letter-spacing:.02em }
  #bbRoot .bb-turnflag .bb-hud-phase{ max-width:42% }
}

/* ════════════════════════════════════════════════════════════════════════════════
   🪙 PILE OU FACE — LE VERDICT DU PARI (2026-08-08)

   Le moteur tire le sort dès qu'une capacité porte une `chance`, et pose
   `ev.coin = { win, pct }`. Le plateau ne lisait ce champ nulle part : un 50/50 raté
   posait un MALUS sur la carte du joueur sans la moindre explication — il concluait à un
   bug, pas à un pari perdu. La pièce rend le pari LISIBLE : elle tourne, se fige sur la
   face tirée, et annonce la chance annoncée.

   Placé au-dessus du cut-in de maîtresse (z-index 61 contre 60) : c'est le verdict, il ne
   doit jamais passer DERRIÈRE le bandeau qui l'annonce.
   Le vert et le rouge portent chacun un SYMBOLE (✦ / ✗) : la couleur seule ne suffit pas —
   un joueur daltonien lirait deux fois la même chose.
   ════════════════════════════════════════════════════════════════════════════════ */
:where(#bbRoot, .bb-skin) .bb-coin{ position:absolute; left:50%; top:44%; z-index:61; pointer-events:none;
  display:flex; flex-direction:column; align-items:center; gap:6px;
  transform:translate(-50%,-50%); animation:coinOut .3s ease-in 1.3s forwards }
@keyframes coinOut{ to{ opacity:0; transform:translate(-50%,-64%) } }
:where(#bbRoot, .bb-skin) .bb-coin-face{ width:58px; height:58px; border-radius:50%; display:flex; align-items:center; justify-content:center;
  font-size:1.7rem; font-weight:900; color:#101422; background:linear-gradient(160deg,#ffe6a8,#e0a83c);
  border:2px solid rgba(255,255,255,.6); box-shadow:0 6px 20px -4px rgba(0,0,0,.75);
  animation:coinSpin .62s cubic-bezier(.25,.9,.3,1) both }
/* La rotation sur Y donne l'illusion de la tranche : la pièce « tombe » face visible. */
@keyframes coinSpin{ from{ transform:rotateY(0) scale(.55); opacity:0 } to{ transform:rotateY(1080deg) scale(1); opacity:1 } }
:where(#bbRoot, .bb-skin) .bb-coin-txt{ font-size:.9rem; font-weight:800; letter-spacing:.03em; padding:2px 10px; border-radius:999px;
  background:rgba(10,14,30,.92); border:1px solid rgba(255,255,255,.2); white-space:nowrap;
  animation:coinTxt .25s ease-out both .5s }
@keyframes coinTxt{ from{ opacity:0; transform:translateY(-6px) } to{ opacity:1; transform:none } }
:where(#bbRoot, .bb-skin) .bb-coin-txt i{ font-style:normal; opacity:.72; font-weight:700 }
:where(#bbRoot, .bb-skin) .bb-coin.win .bb-coin-txt{ color:#8ff0a4; border-color:rgba(143,240,164,.5) }
:where(#bbRoot, .bb-skin) .bb-coin.lose .bb-coin-txt{ color:#ff9d9d; border-color:rgba(255,157,157,.5) }
:where(#bbRoot, .bb-skin) .bb-coin.lose .bb-coin-face{ background:linear-gradient(160deg,#c9ccd6,#7d8394) }
/* Mouvement réduit : on garde le VERDICT (qui est un renseignement), on retire le tournoiement
   (qui est un ornement). Le class `still` est posé par le JS, qui lit la même préférence. */
:where(#bbRoot, .bb-skin) .bb-coin.still .bb-coin-face{ animation:none }
:where(#bbRoot, .bb-skin) .bb-coin.still .bb-coin-txt{ animation:none }
@media (prefers-reduced-motion:reduce){
  :where(#bbRoot, .bb-skin) .bb-coin-face{ animation:none }
  :where(#bbRoot, .bb-skin) .bb-coin-txt{ animation:none }
  :where(#bbRoot, .bb-skin) .bb-coin{ animation-delay:1.3s }
}
