/* ═══════════════════════════════════════════════════════════════════════════
   POLYGONARC — feuille de style v0.5 · direction artistique A « Encre franche »
   Tirée des références (docs/references) : contours noirs épais, filets en
   tirets-points, aplats rouge / bleu francs, cases rondes à double anneau,
   ombres pleines décalées, fond blanc quadrillé. Polices embarquées.
   ═══════════════════════════════════════════════════════════════════════════ */
@font-face { font-family: 'Archivo Black'; src: url('../polices/archivo-black-latin-400-normal.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: 'Archivo'; font-weight: 400; src: url('../polices/archivo-latin-400-normal.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: 'Archivo'; font-weight: 600; src: url('../polices/archivo-latin-600-normal.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: 'Archivo'; font-weight: 700; src: url('../polices/archivo-latin-700-normal.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: 'Archivo'; font-weight: 800; src: url('../polices/archivo-latin-800-normal.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: 'JetBrains Mono'; font-weight: 700; src: url('../polices/jetbrains-mono-latin-700-normal.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: 'Caveat'; font-weight: 700; src: url('../polices/caveat-latin-700-normal.woff2') format('woff2'); font-display: swap; }

:root {
  --ink: #111; --ink-2: #3d3d3d; --ink-3: #7a7a7a; --ink-4: #c9c9c9;
  --paper: #fbfbfa; --surface: #fff; --soft: #f1f0ec;
  --red: #ee1c24; --blue: #0a7bff; --green: #16a34a; --yellow: #f5b800;
  --red-d: #9e0b10; --blue-d: #0648a0; --green-d: #0c5f2b; --yellow-d: #8a6700;
  --red-l: #fbd3d4; --blue-l: #cfe4ff; --green-l: #cdebd8; --yellow-l: #fdefb8;
  --bonus: var(--blue); --malus: var(--red);
  --ok: #16a34a; --warn: #e09a00; --bad: #ee1c24;
  --title: 'Archivo Black', 'Arial Black', system-ui, sans-serif;
  --type: 'Archivo', system-ui, 'Segoe UI', sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, Consolas, monospace;
  --hand: 'Caveat', 'Segoe Print', cursive;
  --line: 4px; --radius: 16px; --shadow: 5px 5px 0 var(--ink); --shadow-s: 3px 3px 0 var(--ink);
  --cell: 64px; --gap: 10px;
}
* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  background: var(--paper); color: var(--ink); font-family: var(--type); overflow: hidden; -webkit-font-smoothing: antialiased;
  background-image: linear-gradient(rgba(0,0,0,.045) 1px, transparent 1px), linear-gradient(90deg, rgba(0,0,0,.045) 1px, transparent 1px);
  background-size: 32px 32px;
}
button { font: inherit; color: inherit; }
input, select, textarea { font: inherit; }
.hidden { display: none !important; }
#app { position: relative; height: 100dvh; width: 100%; overflow: hidden; }

/* ── Écrans ─────────────────────────────────────────────────────────────── */
.scr { position: absolute; inset: 0; display: flex; flex-direction: column; transition: opacity .2s, transform .2s; overflow: hidden; }
.scr.off { opacity: 0; pointer-events: none; transform: scale(.985); }
.scroll { overflow-y: auto; flex: 1; }
.page { width: 100%; max-width: 620px; margin: 0 auto; padding: 26px 18px 40px; display: flex; flex-direction: column; gap: 16px; }
.page.wide { max-width: 1040px; }

/* ── Titres ─────────────────────────────────────────────────────────────── */
.h1 { font-family: var(--title); font-size: 34px; letter-spacing: .01em; line-height: 1.05; }
.h2 { font-family: var(--title); font-size: 20px; }
.lbl { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 8px; }
.note { font-family: var(--hand); font-size: 23px; color: var(--red); line-height: 1.1; }
.muted { color: var(--ink-3); font-size: 13px; line-height: 1.5; }
.back { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 12px; font-weight: 700; letter-spacing: .1em; cursor: pointer; background: none; border: none; padding: 4px 0; align-self: flex-start; color: var(--ink-2); }
.back:hover { color: var(--ink); }

/* ── Boutons ────────────────────────────────────────────────────────────── */
.btn { display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%; padding: 14px 18px; border-radius: 14px;
  cursor: pointer; font-family: var(--title); font-size: 17px; letter-spacing: .02em; border: var(--line) solid var(--ink); text-align: left; transition: transform .08s, box-shadow .08s; }
.btn:active:not([disabled]) { transform: translate(3px, 3px); box-shadow: 1px 1px 0 var(--ink) !important; }
.btn[disabled] { opacity: .4; cursor: not-allowed; }
.btn-fill { background: var(--ink); color: #fff; box-shadow: var(--shadow); }
.btn-red { background: var(--red); color: #fff; box-shadow: var(--shadow); }
.btn-blue { background: var(--blue); color: #fff; box-shadow: var(--shadow); }
.btn-line { background: var(--surface); box-shadow: var(--shadow-s); }
.btn-ghost { background: transparent; border-width: 2px; border-style: dashed; font-family: var(--type); font-weight: 700; font-size: 14px; }
.btn.center { justify-content: center; }
.btn .sub { font-family: var(--mono); font-size: 10px; letter-spacing: .08em; opacity: .7; font-weight: 700; }
.icon-btn { background: var(--surface); border: 2px solid var(--ink); border-radius: 10px; cursor: pointer; padding: 6px 10px; display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .08em; }
.icon-btn:hover { background: var(--soft); }
.row { display: flex; gap: 10px; } .row > * { flex: 1; }

/* ── Encadrés ───────────────────────────────────────────────────────────── */
.panel { background: var(--surface); border: var(--line) solid var(--ink); border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow); }
.panel.dash { position: relative; }
.panel.dash::before { content: ""; position: absolute; inset: 6px; border: 2px dashed var(--ink-4); border-radius: 11px; pointer-events: none; }
.card-box { background: var(--surface); border: var(--line) solid var(--ink); border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow-s); }

/* ── Logo / accueil ─────────────────────────────────────────────────────── */
#menu .page { min-height: 100%; justify-content: center; max-width: 560px; }
.logo { text-align: center; margin: 6px 0 22px; }
.logo svg { display: block; margin: 0 auto 12px; }
/* Le mot POLYGONARC fait 366 px de large à 46 px : il ne tient PAS sur un
   téléphone de 360 px, où il reste 324 px une fois les marges enlevées. Il
   était coupé à droite — donc plus centré non plus. Capture de Gaëlle le
   08/10/2026 (docs\captures\v1.0\accueil_mobile_deborde_a_droite.jpg).
   `.scr` est en `overflow: hidden` : la page ne défilait donc PAS, et aucun
   contrôle de débordement horizontal ne pouvait le voir. Il a fallu mesurer la
   largeur du TEXTE lui-même, pas celle de sa boîte — une boîte de niveau bloc
   fait toujours la largeur du parent, elle ne déborde jamais.
   11vw tient depuis 300 px de large, et plafonne à 46 px au-delà de 418 px. */
/* CDC v5 § 17 : la PARTIE CLASSÉE est la grande porte de l'accueil, les deux
   autres passent dessous. Le sur-titre et le sous-titre tiennent le bouton :
   un bouton seul ne dit pas qu'il est « officiel », et c'est ce qui le
   distingue d'une partie publique. */
.classee { margin: 2px 0 4px; }
/* Privée et Publique vivent sur deux colonnes : leur sous-titre ne tient pas À
   CÔTÉ du libellé, il passe DESSOUS. Vu au rendu à 360 px, pas à la lecture :
   le bouton de droite sortait de l'écran. */
.btn.deux-lignes { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.btn.deux-lignes .sub { font-size: 9.5px; letter-spacing: .04em; line-height: 1.25; white-space: normal; }
.classee-sur { font-family: var(--mono); font-weight: 700; font-size: 12px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-3); text-align: center; margin-bottom: 8px; }
.classee-go { font-size: 22px; padding: 18px 16px; }
.classee-sous { font-family: var(--mono); font-size: 11px; color: var(--ink-3); text-align: center; margin-top: 7px; }

/* ── RECHERCHE D'ADVERSAIRES (CDC v5 § 18) ────────────────────────────────
   Le chrono est en chiffres TABULAIRES : sans ça « 00:09 » et « 00:11 » n'ont
   pas la même largeur, et le bloc tremble à chaque seconde. Un chrono qui
   saute se lit comme un bug. */
/* § 7 : la phrase qui remplace le chrono. Même place, même discrétion — ce
   n'est pas une alerte, c'est une information. */
.sans-chrono { font-family: var(--mono); font-size: 11px; letter-spacing: .04em; color: var(--ink-3); text-align: center; margin-top: 6px; line-height: 1.4; }
.sans-chrono.hidden { display: none; }
.recherche { border: 3px solid var(--ink); background: #fff; box-shadow: 5px 5px 0 var(--ink); padding: 18px 16px 16px; text-align: center; margin: 4px 0 14px; }
.recherche-titre { font-family: var(--mono); font-weight: 700; font-size: 12px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-3); }
.recherche-chrono { font-family: var(--mono); font-weight: 700; font-size: clamp(34px, 11vw, 46px); line-height: 1.1; letter-spacing: .06em; font-variant-numeric: tabular-nums; margin: 6px 0 2px; }
.recherche-etat { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); margin-bottom: 4px; }
/* § 1 : le format, lisible d'un coup d'oeil — c'est à ça qu'on s'engage. */
.recherche-format { font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink); margin-bottom: 14px; }
.recherche-annuler { font-size: 15px; padding: 13px 16px; }
/* ── L'INDICATEUR DE RECHERCHE (CDC v6 § 2) ───────────────────────────────
   Ce qui précédait écrivait des points dans `content` : « Recherche », puis
   « Recherche. », puis « Recherche.. ». Le texte était CENTRÉ, donc il
   se déplaçait d'un demi-caractère à chaque changement — c'est le « texte qui
   saute » du § 2, et c'est aussi quatre recalculs de mise en page par seconde.
   Ici : trois pastilles de taille FIXE, qui ne font varier que leur opacité et
   leur hauteur de quelques pixels. Rien ne change de largeur, donc rien ne
   bouge ; l'opacité et `transform` sont les deux seules propriétés que le
   navigateur sait animer sans refaire la mise en page.
   Jamais à zéro : une pastille qui s'éteint complètement clignote. Le creux
   est à 0,25 — on voit respirer, on ne voit pas clignoter. */
.recherche-titre { display: flex; align-items: center; justify-content: center; gap: 9px; }
.rech-pts { display: inline-flex; gap: 5px; align-items: center; }
.rech-pts i { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-3); opacity: .25; display: block;
  animation: rech-respire 1.4s ease-in-out infinite; will-change: opacity, transform; }
.rech-pts i:nth-child(2) { animation-delay: .18s; }
.rech-pts i:nth-child(3) { animation-delay: .36s; }
@keyframes rech-respire { 0%, 100% { opacity: .25; transform: translateY(0); } 45% { opacity: 1; transform: translateY(-2px); } }
/* Couper une animation ne se fait PAS en raccourcissant sa durée : sur une
   animation `infinite`, `.01ms` la rejoue des milliers de fois par seconde et
   l'effet est pire. On coupe la répétition. (règle du 03/10) */
@media (prefers-reduced-motion: reduce) { .rech-pts i { animation-iteration-count: 1 !important; opacity: .7; } }
body.calm .rech-pts i { animation-iteration-count: 1 !important; opacity: .7; }

/* ── LE POULS DU DIRECT (§ 1 et § 4) ──────────────────────────────────────
   Un point qui bat doucement à côté de « X en jeu » et de « liste en direct ».
   Il dit une chose et une seule : ce nombre est vivant, il n'est pas figé
   depuis l'ouverture de la page. Même règle que ci-dessus — opacité seule. */
.pouls { width: 7px; height: 7px; border-radius: 50%; background: var(--green, #16a34a); display: inline-block; flex: none;
  animation: pouls 2.2s ease-in-out infinite; }
@keyframes pouls { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .pouls { animation-iteration-count: 1 !important; opacity: .8; } }
body.calm .pouls { animation-iteration-count: 1 !important; opacity: .8; }
.enjeu { display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: 8px;
  font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--ink-3); letter-spacing: .06em;
  min-height: 16px; transition: opacity .3s ease; }
.enjeu.vide { opacity: 0; }
/* ── UNE LIGNE DE SALON (§ 3 et § 4) ──────────────────────────────────────
   Trouvé en regardant la capture, pas en relisant le code : `.wgame` n'avait
   AUCUN style — ni ici ni ailleurs. La liste « Regarder » s'affichait donc
   depuis le début en texte nu, avec « REJOINDRE › » collé à la fin de la
   phrase. Ça ne se voyait pas tant qu'on ne la regardait pas.
   Le § 3 demande « rejoindre une partie disponible en un clic » : il faut donc
   que la ligne RESSEMBLE à un bouton, en entier. */
.wgame { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 12px 14px; border: 3px solid var(--ink); border-radius: 14px; background: var(--surface);
  cursor: pointer; transition: transform .12s ease, box-shadow .12s ease; }
.wgame:hover { transform: translate(-1px, -1px); box-shadow: 3px 3px 0 var(--ink); }
.wgame:active { transform: translate(1px, 1px); box-shadow: none; }
.wgame .code { font-family: var(--mono); font-weight: 700; font-size: 17px; letter-spacing: .12em; }
.wgame .info { font-size: 13px; line-height: 1.5; color: var(--ink-2); min-width: 0; }
.wgame .go { font-family: var(--mono); font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; white-space: nowrap; }
.wgame .pips { display: inline-flex; gap: 4px; margin-left: 6px; vertical-align: middle; }
.wgame .pip { width: 9px; height: 9px; border-radius: 50%; border: 2px solid var(--ink); display: inline-block; }
.wsep { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); margin: 6px 0 2px; }
@media (max-width: 520px) {
  .wgame { grid-template-columns: auto minmax(0, 1fr); row-gap: 8px; }
  .wgame .go { grid-column: 1 / -1; text-align: right; }
}
.salons-tete { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.direct { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px;
  text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); }
/* L'état d'un salon (§ 4) : une pastille, pas une phrase noyée dans la ligne. */
.etat { display: inline-block; font-family: var(--mono); font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; padding: 2px 7px; border: 2px solid var(--ink); border-radius: 999px; background: #fff; }
.etat-attente { background: #e8f3ff; }
.etat-prete { background: #e6f7ec; }
.etat-en_cours { background: #fff3d6; }
.etat-terminee, .etat-fermee { background: #f0f0f0; color: var(--ink-3); }
.logo-title { font-family: var(--title); font-size: min(46px, 11vw); letter-spacing: .03em; line-height: 1; }
.logo-sub { font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--ink-3); letter-spacing: .2em; text-transform: uppercase; margin-top: 8px; }
.menu-list { display: flex; flex-direction: column; gap: 12px; }
.menu-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.vtag { font-family: var(--mono); font-size: 11px; text-align: center; color: var(--ink-3); letter-spacing: .1em; margin-top: 14px; }

/* ── Configuration ──────────────────────────────────────────────────────── */
.seg { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px; }
.seg button { padding: 11px 4px; border-radius: 12px; border: 3px solid var(--ink); background: var(--surface); cursor: pointer; font-family: var(--title); font-size: 17px; }
.seg.sm button { font-family: var(--type); font-weight: 700; font-size: 13px; padding: 8px 4px; border-width: 2px; }
.seg button.on { background: var(--ink); color: #fff; }
.seats { display: flex; flex-direction: column; gap: 10px; }
.seat { display: grid; grid-template-columns: 22px 1fr auto; gap: 10px; align-items: center; padding: 10px 12px; border: 3px solid var(--ink); border-radius: 14px; background: var(--surface); }
.seat .dot, .lobby-seat .dot { width: 22px; height: 22px; border-radius: 50%; border: 3px solid var(--ink); }
.seat input { width: 100%; border: none; border-bottom: 2px dashed var(--ink-4); background: transparent; padding: 4px 2px; font-weight: 800; font-size: 15px; }
.seat input:focus { outline: none; border-bottom-color: var(--ink); }
.seat-kind { display: flex; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
.seat-kind button { padding: 6px 9px; border-radius: 9px; border: 2px solid var(--ink); background: var(--surface); cursor: pointer; font-size: 12px; font-weight: 800; }
.seat-kind button.on { background: var(--ink); color: #fff; }
details.rules-box { border: 3px dashed var(--ink); border-radius: 14px; padding: 12px 14px; background: var(--surface); }
details.rules-box summary { cursor: pointer; font-family: var(--mono); font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.stepper-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 11px 0; border-bottom: 2px dashed var(--ink-4); }
.stepper-row:last-child { border-bottom: none; }
.stepper-row .t { font-weight: 800; font-size: 14px; }
.stepper-row .t small { display: block; font-family: var(--type); font-weight: 400; font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.stepper { display: flex; align-items: center; gap: 8px; }
.stepper button { width: 34px; height: 34px; border-radius: 50%; border: 3px solid var(--ink); background: var(--surface); cursor: pointer; font-size: 18px; font-weight: 900; line-height: 1; }
.stepper .v { font-family: var(--mono); font-weight: 700; font-size: 15px; min-width: 52px; text-align: center; }
@media (max-width: 520px) { .seat { grid-template-columns: 22px 1fr; } .seat-kind { grid-column: 1 / -1; } .seat-kind button { flex: 1; } }

/* ══════════════════════════ ÉCRAN DE PARTIE ═════════════════════════════ */
/* ── LE PLATEAU REPREND LA PLACE (CDC v5 § 29, § 31, § 32, 08/10/2026) ──
   Avant : 290 px d'infos à gauche, 300 px à droite, PLUS une colonne de chat
   de 320 px réservée en permanence sur grand écran. Mesuré à 1440 × 900 : le
   plateau occupait 336 px de large, soit 18 % de l'écran — « le plateau ne
   doit pas être écrasé par les cartes, le chat, les menus » (§ 31).
   Les colonnes maigrissent, le journal et les objectifs disparaissent, et le
   chat ne réserve plus rien : il se replie. */
/* ── CDC v6 § 5 : DEUX ZONES ──────────────────────────────────────────────
   Le plateau d'un côté, tout le reste de l'autre. L'ancienne grille en avait
   trois (actions à gauche, plateau au centre, cartes à droite) plus une barre
   en travers du haut : quatre endroits à regarder pour jouer un tour.
   Le réglage du § 5 déplace L'ENSEMBLE : c'est la même ligne `grid-template-areas`
   qui change, donc il est impossible que le plateau parte d'un côté en laissant
   un panneau de l'autre — le défaut que le § 5 nomme explicitement. */
#game { display: grid; grid-template-columns: minmax(0, 1fr) 320px; grid-template-rows: minmax(0, 1fr);
  grid-template-areas: "board info"; gap: 0 18px; padding: 12px 22px 18px; }
.gl-info { grid-area: info; display: flex; flex-direction: column; gap: 14px; min-height: 0; min-width: 0;
  overflow-y: auto; padding-right: 4px; }
/* Ne JAMAIS redéclarer `position` ici : `.scr` est en `position: absolute;
   inset: 0`, et un `position: relative` lui reprend sa hauteur — l'écran de
   partie s'écrase alors en haut et le plateau tombe à la case minimale (16 px).
   Vu à la capture, pas au raisonnement : la mesure disait « plateau 130 × 263 »
   sur un écran de 1440. C'est déjà un bloc positionné, les enfants absolus s'y
   accrochent sans qu'on touche à rien. */
/* § 16 : les deux colonnes échangent leur place d'un bloc. Une seule classe —
   rien ne peut rester en arrière. */
#game.plateau-droite { grid-template-columns: 320px minmax(0, 1fr);
  grid-template-areas: "info board"; }
.topbar { grid-area: top; display: flex; align-items: center; gap: 18px; padding: 0 0 2px; min-width: 0; }
/* En colonne, la barre du haut n'est plus une barre : elle se met debout. */
/* ── CE QUE LA PREMIÈRE CAPTURE A MONTRÉ (12/10/2026) ─────────────────────
   En colonne de 320 px, la rangée des joueurs continuait de s'étaler à
   l'horizontale : le quatrième adversaire sortait de l'écran par la droite, et
   on ne pouvait plus voir son score. Un rail qui défile n'est pas une réponse —
   il faut chercher son adversaire au doigt. Les pastilles passent donc en
   DEUX COLONNES, et le tour s'aligne à gauche comme tout le reste de la
   colonne. Vu à l'image, pas au raisonnement. */
.gl-info > .topbar { flex-direction: column; align-items: stretch; gap: 10px; }
.gl-info .players { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; overflow: visible; padding: 2px; justify-content: stretch; }
.gl-info .pchip { padding: 5px 10px 5px 5px; gap: 7px; min-width: 0; }
.gl-info .pchip .disc { width: 26px; height: 26px; }
.gl-info .pchip b { font-size: 12.5px; max-width: 100%; }
.gl-info .pchip small { font-size: 9.5px; }
.gl-info .turn-box { text-align: left; }
.gl-info .turn-who { font-size: 20px; white-space: normal; }
.gl-info .turn-tools { justify-content: flex-start; }
.gl-logo { display: flex; align-items: center; gap: 10px; font-family: var(--title); font-size: 22px; flex-shrink: 0; }
.players { display: flex; gap: 10px; flex: 1; justify-content: safe center; min-width: 0; overflow-x: auto; padding: 4px 6px 8px; }
.pchip { display: flex; align-items: center; gap: 9px; padding: 6px 14px 6px 6px; border: 3px solid var(--ink); border-radius: 999px; background: var(--surface); flex-shrink: 0; transition: transform .2s, box-shadow .2s; position: relative; }
.pchip.act { box-shadow: 4px 4px 0 var(--ink); transform: translateY(-2px); }
.pchip .disc { width: 32px; height: 32px; border-radius: 50%; background: var(--pc); border: 3px solid var(--ink); display: grid; place-items: center; flex-shrink: 0; }
.pchip .disc i { width: 11px; height: 11px; border-radius: 50%; background: #fff; border: 2px solid var(--ink); }
.pchip b { display: block; font-size: 14px; font-weight: 800; white-space: nowrap; max-width: 120px; overflow: hidden; text-overflow: ellipsis; }
.pchip small { font-family: var(--mono); font-size: 10px; font-weight: 700; color: var(--ink-3); white-space: nowrap; }
/* ── « L'ESPÈCE DE TRUC BLANC AU NIVEAU DE MON PSEUDO » (Gaëlle, 08/10) ───
   C'était un marqueur d'effet (bouclier, ×2, isolement, tempête) posé en
   `position: absolute; top: -9px` DEHORS de la pastille — et la bande des
   joueurs est en `overflow-x: auto`, ce qui rogne aussi le haut. On n'en
   voyait donc que le bas : un bout de blanc, sans nom, sans explication.
   **Un repère qu'on ne peut pas nommer n'informe pas, il inquiète.**
   Il rentre DANS la pastille, à la suite du nom, à sa taille normale. Rien ne
   dépasse, donc rien ne peut être rogné. */
.pchip .flags { display: inline-flex; gap: 4px; margin-left: 6px; vertical-align: -3px; }
.pchip .flags span { display: inline-flex; width: 17px; height: 17px; align-items: center; justify-content: center; }
.pchip .flags svg { width: 100%; height: 100%; display: block; }
.pchip .off { width: 9px; height: 9px; border-radius: 50%; background: var(--bad); border: 2px solid var(--ink); }
.turn-box { text-align: right; flex-shrink: 0; }
.turn-who { font-family: var(--title); font-size: 22px; line-height: 1; white-space: nowrap; }
.turn-sub { font-family: var(--mono); font-size: 11px; font-weight: 700; color: var(--ink-3); letter-spacing: .08em; margin-top: 5px; }
.turn-tools { display: flex; gap: 6px; justify-content: flex-end; margin-top: 8px; }

/* Sur grand écran, c'est `.gl-info` qui défile : deux ascenseurs côte à côte
   dans la même colonne, c'est un ascenseur de trop. */
.gl-left { grid-area: left; display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.gl-right { grid-area: right; display: flex; flex-direction: column; gap: 14px; min-width: 0; }

/* Panneau d'action */
.act-panel { text-align: center; }
.die { width: 86px; height: 86px; border: var(--line) solid var(--ink); border-radius: 18px; background: #fff; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr);
  place-items: center; padding: 13px; margin: 6px auto 12px; transform: rotate(-6deg); box-shadow: var(--shadow); cursor: default; }
.die i { width: 13px; height: 13px; border-radius: 50%; background: var(--ink); }
.die .q { grid-column: 1 / -1; grid-row: 1 / -1; font-family: var(--title); font-size: 30px; color: var(--ink-4); }
.die.go { cursor: pointer; animation: bob 1.2s ease-in-out infinite; }
.die.spin { animation: spin .5s cubic-bezier(.3,.7,.4,1); }
@keyframes spin { from { transform: rotate(-220deg) scale(.6) } to { transform: rotate(-6deg) scale(1) } }
@keyframes bob { 0%,100% { transform: rotate(-6deg) translateY(0) } 50% { transform: rotate(-3deg) translateY(-5px) } }
.act-msg { font-family: var(--title); font-size: 19px; line-height: 1.15; min-height: 22px; }
.act-note { font-family: var(--hand); font-size: 22px; color: var(--red); min-height: 26px; margin-top: 4px; }
.act-btns { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.act-btns .btn { justify-content: center; font-size: 16px; padding: 12px; }
.timer { display: flex; align-items: center; gap: 10px; justify-content: center; margin-top: 12px; font-family: var(--mono); font-weight: 700; font-size: 13px; }
.timer .bar { flex: 1; height: 10px; border: 2px solid var(--ink); border-radius: 6px; overflow: hidden; background: var(--soft); max-width: 160px; }
.timer .bar i { display: block; height: 100%; background: var(--ok); transition: width .25s linear, background .3s; }
.goals { font-size: 14px; line-height: 1.5; }
.goal { display: grid; grid-template-columns: 1fr auto; gap: 6px; align-items: center; margin-bottom: 9px; }
.goal b { font-weight: 800; }
.goal .v { font-family: var(--mono); font-weight: 700; font-size: 13px; }
.goal .tr { grid-column: 1 / -1; height: 10px; border: 2px solid var(--ink); border-radius: 6px; overflow: hidden; background: var(--soft); }
.goal .tr i { display: block; height: 100%; background: var(--pc, var(--ink)); transition: width .35s; }

/* Reprendre / Quitter une partie en cours — CDC § 53 (02/10/2026)
   ────────────────────────────────────────────────────────────────────────
   Il n'existait aucune regle pour `.encours` : les deux boutons se touchaient
   et la carte n'avait pas de cadre. Un bouton rouge colle a un bouton blanc,
   c'est un seul objet a l'oeil — et on clique sur le mauvais.
   Les deux actions sont donc : encadrees, espacees, et de formes differentes
   (plein contre contour). Sur telephone elles passent l'une sous l'autre. */
.encours { border: 3px solid var(--ink); background: var(--surface, #fff); padding: 12px 14px 14px; margin-bottom: 14px; box-shadow: 5px 5px 0 var(--ink); }
.encours .ec-t { font-family: var(--display); font-size: 16px; line-height: 1.2; }
.encours .ec-sub { font-family: var(--mono); font-size: 11.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); margin-top: 3px; }
.encours .ec-btns { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.encours .ec-btns .btn { margin: 0; }
@media (max-width: 460px) { .encours .ec-btns { grid-template-columns: 1fr; gap: 10px; } }

/* Plateau */
.board-stage { grid-area: board; position: relative; min-height: 0; min-width: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; touch-action: none; }
.board-zoom { transform-origin: center center; transition: transform .15s; will-change: transform; }
.board-frame { --pad-plateau: 24px; position: relative; background: var(--surface); border: 5px solid var(--ink); border-radius: 3px; padding: var(--pad-plateau); box-shadow: none; }
.board { position: relative; display: grid; gap: var(--gap); grid-template-columns: repeat(var(--cols), var(--cell)); }
.bdot { position: absolute; width: clamp(5px, calc(var(--cell, 60px) * 0.24), 15px); height: clamp(5px, calc(var(--cell, 60px) * 0.24), 15px); transform: translate(-50%, -50%);
  background: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M10 1 Q11 9 19 10 Q11 11 10 19 Q9 11 1 10 Q9 9 10 1 Z' fill='none' stroke='%23777' stroke-width='1.6' stroke-linejoin='round'/%3E%3C/svg%3E"); }
/* CDC § 04 (02/10/2026) : UNE case = UN cercle. La case portait son propre
   contour EN PLUS de celui du disque : deux anneaux concentriques, que
   personne n'avait demandés. Le contour et le retrait disparaissent ; le
   seul cercle qui reste est celui du disque, et c'est lui qui porte l'encre
   franche de la DA. L'écart entre les cases vient de --gap, pas d'un bord. */
.cell { width: var(--cell); height: var(--cell); border-radius: 50%; position: relative; }
/* LE PLATEAU DE LAUNHAS (maquette du 31/10/2026) : une case est un godet —
   fond gris clair, contour sombre plus épais en bas à droite (on la voit en
   creux), et un fin halo gris autour ; entre quatre cases, une petite étoile
   à quatre branches. Une case prise est pleine de la couleur du joueur. */
.cell .disc { width: 100%; height: 100%; border-radius: 50%; border: max(1.5px, calc(var(--cell) * .06)) solid #1d1d1d; background: #ececec; transition: background-color .35s; position: relative; display: grid; place-items: center;
  box-shadow: inset calc(var(--cell) * -.04) calc(var(--cell) * -.07) 0 rgba(0,0,0,.28), inset calc(var(--cell) * .03) calc(var(--cell) * .05) 0 #fff, 0 0 0 max(1px, calc(var(--gap) * .3)) #fff, 0 0 0 max(2px, calc(var(--gap) * .3 + 1.2px)) #c4c4c4; }
.cell[class*="o-"] .disc { box-shadow: inset calc(var(--cell) * -.04) calc(var(--cell) * -.07) 0 rgba(0,0,0,.22), 0 0 0 max(1px, calc(var(--gap) * .3)) #fff, 0 0 0 max(2px, calc(var(--gap) * .3 + 1.2px)) #c4c4c4; }
.cell.o-red .disc { background: var(--red); } .cell.o-blue .disc { background: var(--blue); } .cell.o-green .disc { background: var(--green); } .cell.o-yellow .disc { background: var(--yellow); }
.cell.x .disc { background: #1b1b1b; }
.cell.x .disc::after { content: "✕"; color: #777; font-size: calc(var(--cell) * .38); font-weight: 900; }
.cell.sp .disc::before { content: ""; position: absolute; inset: 12%; border-radius: 50%; border: 3px dashed #fff; }
.cell.mv, .cell.tg { cursor: pointer; }
.cell.mv .disc::after, .cell.tg .disc::after { content: ""; position: absolute; inset: -12%; border-radius: 50%; border: 4px dashed var(--hl, var(--ink)); background: color-mix(in srgb, var(--hl, #000) 14%, transparent); animation: ring 1.4s linear infinite; }
.cell.tg { --hl: #d49b00; }
.cell.mv:hover .disc, .cell.tg:hover .disc { filter: brightness(.93); }
/* Quand presque tout est visable, l'anneau ne distingue plus rien : on le
   remplace par un petit cercle INTÉRIEUR, sans animation et sans débordement.
   Premier essai : estomper les cases impossibles. Mauvais — pendant « choisis
   une case libre », les cases impossibles SONT le territoire, c'est-à-dire
   exactement ce qu'il faut regarder pour choisir où frapper. On ne touche donc
   à rien d'autre. (04/10/2026, carte à cible large sur le téléphone de Gaëlle.) */
#board.cibles-partout .cell.tg .disc::after { inset: 14%; border: 2px solid color-mix(in srgb, #d49b00 60%, transparent); border-radius: 50%; background: transparent; animation: none; }
.cell.sel .disc { box-shadow: 0 0 0 5px var(--yellow); }
@keyframes ring { to { transform: rotate(360deg) } }
.cell.flash .disc { animation: flash .7s ease-out; }
@keyframes flash { 0% { transform: scale(1.18); filter: brightness(1.5) } 100% { transform: scale(1); filter: none } }
.cell.dz .disc { box-shadow: inset 0 0 0 3px #fff; }
.cell .coord { display: none; }
/* Calques : tours et pions */
.layer { position: absolute; inset: var(--pad-plateau, 24px);  /* calques et pions suivent le rembourrage du cadre */ pointer-events: none; z-index: 2; }
.layer.under { z-index: 0; }
.board { z-index: 1; }
.seam { position: absolute; display: block; }
/* Maquette de Launhas (31/10/2026) : un plateau d'un seul tenant, sans pointillés entre les plaques. */
.seam { display: none; }
.seam.v { width: 0; border-left: 3px dashed var(--ink); transform: translateX(-1.5px); opacity: .55; }
.seam.h { height: 0; border-top: 3px dashed var(--ink); transform: translateY(-1.5px); opacity: .55; }
.tower-halo { position: absolute; background: var(--dc); border: 4px solid var(--ink); border-radius: 999px; }
.tower-icon { position: absolute; width: 30px; height: 34px; transform: translate(-50%, -50%); filter: drop-shadow(2px 2px 0 var(--ink)); }
/* Le pion est posé PAR-DESSUS le plateau (et non dans `.layer`, qui ne reçoit
   déjà plus les clics) : sans `pointer-events: none`, il avalait le clic sur sa
   propre case. Conséquence trouvée le 27/09 : impossible de désigner un pion
   adverse, donc « Déplacement d'adversaire » et « Ancrage » étaient injouables.
   Et l'anneau clignotant de son propre pion (`::before`, inset -4px) débordait
   sur les cases voisines, donc volait des clics de déplacement.
   Règle : TOUT ce qui se superpose au plateau est décoratif et laisse passer
   les clics — on ne vise jamais qu'une CASE. */
.pawn { position: absolute; z-index: 3; width: var(--cell); height: var(--cell); display: grid; place-items: center; pointer-events: none; transition: transform .32s cubic-bezier(.3,.8,.4,1); }
.pawn svg { width: 58%; height: 58%; overflow: visible; filter: drop-shadow(0 3px 0 rgba(0,0,0,.25)); }
.pawn.me::before { content: ""; position: absolute; inset: -4px; border-radius: 50%; border: 5px solid var(--pc); animation: pulse 1.3s ease-in-out infinite; }
.pawn.tp svg { animation: tp .45s ease-out; }
@keyframes tp { 0% { transform: scale(0) rotate(-90deg) } 70% { transform: scale(1.25) } 100% { transform: scale(1) } }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .35 } }
.zoom-ctl { position: absolute; right: 10px; bottom: 10px; display: flex; gap: 6px; z-index: 5; }
/* « Le système de zoom, enlève » (Launhas, 31/10/2026) : plus de boutons + / − / ⟲.
   Le pincement à deux doigts et Ctrl + molette restent, sans rien afficher. */
.zoom-ctl { display: none !important; }
.zoom-ctl button { width: 38px; height: 38px; border-radius: 10px; border: 3px solid var(--ink); background: var(--surface); font-weight: 900; font-size: 18px; cursor: pointer; box-shadow: var(--shadow-s); }
.board-stage.grab { cursor: grab; } .board-stage.grabbing { cursor: grabbing; }

/* Main de cartes */
.hand-panel { display: flex; flex-direction: column; flex-shrink: 0; }
.hand { position: relative; display: flex; flex-direction: column; gap: 0; padding: 6px 4px 10px; }
.hcard { position: relative; width: 180px; margin-left: 30px; cursor: pointer; transition: transform .15s, margin .15s; }
.hcard + .hcard { margin-top: -150px; }
.hcard:nth-child(even) { transform: rotate(3deg); margin-left: 60px; }
.hcard:nth-child(odd) { transform: rotate(-4deg); }
.hcard:hover, .hcard.sel { transform: translateX(-24px) rotate(0) !important; z-index: 5; }
.hcard.dim { filter: grayscale(.5) opacity(.75); }
.hand-empty { font-family: var(--hand); font-size: 22px; color: var(--ink-3); padding: 12px 0 0 6px; }

/* ── LES CARTES EN MAIN (CDC v5 § 10, § 11, § 27, 09/10/2026) ────────────
   « Les cartes doivent être petites lorsqu'elles sont affichées dans la
   colonne », « suffisamment petites pour ne pas prendre toute la place », et
   on doit « distinguer rapidement bonus, malus, cartes conservées, effets
   actifs ». D'où : des vignettes en rangée, un liseré bleu sur celles qu'on
   peut poser, et un bandeau ACTIF sur les effets qui attendent leur condition. */
.main-titre { font-family: var(--mono); font-size: 10px; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase; color: var(--ink-3); margin: 12px 0 5px; }
.main-rangee { display: flex; flex-wrap: wrap; gap: 7px; }
.mcard { position: relative; width: 62px; cursor: pointer; transition: transform .12s; }
.mcard .gcard { width: 100%; }
.mcard:hover { transform: translateY(-3px); }
.mcard.posable { outline: 3px solid var(--blue); outline-offset: 2px; border-radius: 9px; }
.mcard.actif { cursor: default; }
.mcard.actif .gcard { filter: saturate(.55); }
.mcard.actif:hover { transform: none; }
.actif-tag { position: absolute; top: -6px; left: 50%; transform: translateX(-50%);
  font-family: var(--mono); font-size: 8.5px; font-weight: 700; letter-spacing: .1em;
  background: var(--ink); color: #fff; border-radius: 999px; padding: 1px 6px; white-space: nowrap; }
.actif-txt { display: block; font-size: 9.5px; line-height: 1.25; color: var(--ink-3); text-align: center; margin-top: 3px; }
.main-aide { font-size: 12px; line-height: 1.4; color: var(--ink-3); margin: 8px 0 0; }
@media (max-width: 900px) { .mcard { width: 52px; } .main-titre { margin-top: 8px; } }
/* « Tri » (27/09/2026) : trois cartes à CHOISIR. L'éventail de l'ancienne main
   les empilait les unes sur les autres — on n'en lisait qu'une. Ici elles sont
   côte à côte, entières, et se soulèvent au survol. */
.hand.choix { flex-direction: row; gap: 7px; align-items: flex-start; }
.hand.choix .hcard, .hand.choix .hcard:nth-child(even), .hand.choix .hcard:nth-child(odd) {
  width: auto; flex: 1 1 0; min-width: 0; margin: 0 !important; transform: none !important; }
.hand.choix .hcard.sel { outline: 3px solid var(--yellow); outline-offset: 2px; border-radius: 10px; }
.hand.choix .hcard.sel:hover { transform: translateY(-7px) !important; }
.hand.choix .hcard .nm { font-size: 8px; }
.hand.choix .hcard .kind, .hand.choix .hcard .rare { display: none; }
.hand-use { margin-top: 12px; }
.gcard { position: relative; width: 100%; aspect-ratio: 190 / 250; }
.gcard svg { width: 100%; height: 100%; display: block; }
.gcard .nm { position: absolute; left: 12%; right: 8%; top: 76.5%; transform: rotate(-16.5deg); text-align: center; font-family: var(--title); font-size: 13px; color: #fff; text-shadow: 0 2px 0 var(--ink); line-height: 1.32; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gcard .ic { position: absolute; left: 18%; right: 12%; top: 28%; height: 38%; display: grid; place-items: center; font-family: var(--title); font-size: 38px; transform: rotate(-16.5deg); color: var(--ink); }
.gcard .kind { position: absolute; left: 10%; top: 9%; transform: rotate(-16.5deg); font-family: var(--mono); font-size: 10px; font-weight: 700; letter-spacing: .12em; color: #fff; }

/* Journal */
.journal { flex: 1; min-height: 120px; overflow-y: auto; }
.journal ol { list-style: none; display: flex; flex-direction: column; gap: 4px; font-size: 13px; line-height: 1.35; }
.journal li { padding: 2px 0 2px 9px; border-left: 4px solid var(--jc, var(--ink-4)); color: var(--ink-2); }
.journal li:first-child { color: var(--ink); font-weight: 700; }

/* Carte piochée / carte adverse */
.modal { position: absolute; inset: 0; z-index: 80; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 22px; padding: 16px; }
.modal.off { display: none; }
.wash { position: absolute; inset: 0; background: rgba(251,251,250,.88); backdrop-filter: blur(3px); }
.modal .who { position: relative; font-family: var(--title); font-size: 20px; }
.modal .bigcard { position: relative; width: min(260px, 64vw); animation: cardpop .4s cubic-bezier(.34,1.56,.64,1); }
.modal .bigcard .nm { font-size: 18px; }
.modal .bigcard .ic { font-size: 54px; }
.modal .desc { position: relative; max-width: 360px; text-align: center; font-size: 15px; line-height: 1.45; font-weight: 600; }
.modal .acts { position: relative; display: flex; gap: 10px; }
.modal .acts .btn { width: auto; padding: 13px 28px; }
@keyframes cardpop { from { transform: rotate(-8deg) scale(.6); opacity: 0 } to { transform: rotate(0) scale(1); opacity: 1 } }
.peek { position: absolute; right: 340px; top: 120px; z-index: 50; width: 150px; pointer-events: none; animation: peek 2.6s ease forwards; }
@keyframes peek { 0% { opacity: 0; transform: translateX(40px) rotate(8deg) } 10% { opacity: 1; transform: none } 80% { opacity: 1 } 100% { opacity: 0 } }

.banner { position: absolute; left: 50%; top: 45%; transform: translate(-50%, -50%); z-index: 70; pointer-events: none; padding: 16px 30px; border-radius: 18px;
  border: var(--line) solid var(--ink); background: var(--surface); box-shadow: 7px 7px 0 var(--pc, var(--ink)); font-family: var(--title); font-size: 30px; animation: banner 1.4s ease forwards; white-space: nowrap; }
.banner small { display: block; font-family: var(--hand); font-size: 22px; color: var(--red); text-align: center; }
@keyframes banner { 0% { opacity: 0; transform: translate(-50%, -40%) scale(.9) } 15% { opacity: 1; transform: translate(-50%, -50%) scale(1) } 75% { opacity: 1 } 100% { opacity: 0; transform: translate(-50%, -58%) } }
.pausebar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 60; background: var(--yellow); border: var(--line) solid var(--ink); box-shadow: var(--shadow); border-radius: 16px; padding: 14px 26px; font-family: var(--title); font-size: 22px;
  display: flex; flex-direction: column; align-items: center; gap: 12px; max-width: min(90vw, 420px); text-align: center; line-height: 1.25; }
/* Le bandeau explique maintenant POURQUOI et propose de reprendre : il lui
   faut de la place et un bouton cliquable au milieu d'une couche décorative. */
.pausebar button { font-size: 16px; pointer-events: auto; }
@media (max-width: 640px) { .pausebar { font-size: 17px; padding: 12px 18px; } }

#toasts { position: absolute; top: 80px; left: 50%; transform: translateX(-50%); z-index: 999; display: flex; flex-direction: column; gap: 6px; align-items: center; pointer-events: none; width: max-content; max-width: 92%; }
.toast { color: #fff; background: var(--ink); font-weight: 800; font-size: 13px; padding: 9px 16px; border-radius: 12px; border: 3px solid var(--ink); box-shadow: 3px 3px 0 rgba(0,0,0,.25); animation: toast 2.8s ease forwards; text-align: center; }
@keyframes toast { 0% { opacity: 0; transform: translateY(-6px) } 8% { opacity: 1; transform: none } 85% { opacity: 1 } 100% { opacity: 0 } }

/* Écran moyen paysage (tablette, petit portable) : 3 colonnes resserrées */
@media (min-width: 900px) and (max-width: 1240px) and (orientation: landscape) {
  #game { grid-template-columns: minmax(0, 1fr) 266px; gap: 0 12px; padding: 8px 12px 12px; }
  #game.plateau-droite { grid-template-columns: 266px minmax(0, 1fr); }
  .gl-logo span { display: none; }
  .pchip { padding: 4px 10px 4px 4px; } .pchip b { font-size: 12px; max-width: 90px; } .pchip small { font-size: 9px; }
  .turn-who { font-size: 18px; }
  .panel { padding: 12px; }
  .die { width: 66px; height: 66px; padding: 10px; } .die i { width: 10px; height: 10px; }
  .act-msg { font-size: 16px; }
  .hcard { width: 150px; margin-left: 20px; } .hcard + .hcard { margin-top: -125px; } .hcard:nth-child(even) { margin-left: 40px; }
  .peek { right: 260px; }
}
/* Petit écran ou portrait : pile verticale */
@media (max-width: 899px), (orientation: portrait) and (max-width: 1240px) {
  /* TÉLÉPHONE (03/10/2026, signalé par Gaëlle : « le rendu dé/pioche n'est pas
     très beau »). La rangée du plateau était à `minmax(60vh, 1fr)` : elle
     RÉSERVAIT 60 % de la hauteur quoi qu'il arrive, et les deux panneaux du bas
     n'avaient plus la place — ils débordaient de l'écran, et sur un téléphone
     un peu court ils se chevauchaient : le bouton « Piocher » passait sous la
     carte « LA PIOCHE ».
     `minmax(0, 1fr)` laisse le plateau CÉDER la place : les panneaux du bas
     sont servis en premier (ils portent les boutons), le plateau prend le
     reste. Il ne devient jamais minuscule pour autant — les boutons +, − et ↺
     sont là pour ça, et le plateau se fait glisser au doigt. */
  /* `display: contents` : la boîte des informations disparaît de la mise en
     page et ses trois blocs redeviennent des cases de CETTE grille, avec les
     `grid-area` qu'ils portent déjà. La pile réglée le 08/10 est intacte, et
     le § 5 est servi quand même : plateau en haut, tout le reste en dessous. */
  #game { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto auto; overflow-y: auto; grid-template-areas: "top" "board" "left" "right"; padding: 0 10px 10px; gap: 8px; }
  #game.plateau-droite { grid-template-columns: minmax(0, 1fr); grid-template-areas: "top" "board" "left" "right"; }
  .gl-info { display: contents; }
  /* ── LE PIÈGE DE `display: contents` (12/10/2026, vu à la capture) ───────
     `display: contents` retire la BOÎTE de la mise en page, pas le NOEUD du
     document : un sélecteur comme `.gl-info .players` continue de mordre.
     Les règles de la colonne (pastilles en deux colonnes, barre du haut
     debout, tour aligné à gauche) s'appliquaient donc aussi au téléphone, où
     elles n'ont aucun sens — pastilles hors écran, « Lancer le dé » coupé,
     plateau réduit à un timbre. On les annule ici, une par une.
     Règle à retenir : avec `display: contents`, on n'hérite pas de l'isolement
     qu'on croit avoir. */
  .gl-info > .topbar { flex-direction: row; align-items: flex-start; gap: 8px; }
  .gl-info .players { display: flex; flex-wrap: wrap; grid-template-columns: none; gap: 6px; overflow: visible; padding: 2px 2px 4px; }
  /* L'onglet du chat était à 66 % de la hauteur : sur la pile du téléphone,
     ces 66 % tombent exactement sur le panneau d'action et l'onglet recouvrait
     le dé. À 46 % il revient sur le plateau, qu'il ne gêne pas. */
  .chat-onglet { top: 46%; }
  .gl-info .pchip { padding: 3px 9px 3px 3px; gap: 6px; }
  .gl-info .pchip .disc { width: 22px; height: 22px; }
  .gl-info .pchip b { font-size: 12px; max-width: 76px; }
  .gl-info .pchip small { font-size: 9px; }
  .gl-info .turn-box { text-align: right; }
  .gl-info .turn-who { font-size: 15px; white-space: nowrap; }
  .gl-info .turn-tools { justify-content: flex-end; }
  .gl-logo span, .turn-tools .sub { display: none; }
  /* ── LA BARRE DU HAUT PRENAIT 300 px SUR 844 (08/10/2026) ──────────────
     Mesuré : le plateau ne gardait que 12 % de l'écran d'un téléphone, et le
     premier coupable était ici — « À TOI DE JOUER » sur une ligne, les deux
     boutons sur une autre, les pastilles des joueurs sur une troisième.
     Le § 29 dit « l'écran de partie doit principalement contenir le plateau ».
     Tout rentre donc sur UNE rangée : pastilles à gauche, tour et outils à
     droite, sans retour à la ligne. */
  /* `nowrap` a été essayé d'abord : les pastilles des joueurs passaient alors
     dans un rail qui défile, et il fallait faire glisser pour voir le score de
     l'adversaire. Un écran où il faut chercher son adversaire est pire qu'un
     écran d'un centimètre trop haut. On garde donc le retour à la ligne, et on
     gagne la hauteur en SERRANT, pas en entassant. */
  .topbar { gap: 8px; padding: 6px 0 2px; flex-wrap: wrap; align-items: flex-start; }
  .topbar .players { padding: 2px 2px 4px; gap: 6px; }
  .topbar .pchip { padding: 3px 9px 3px 3px; gap: 6px; }
  .topbar .pchip .disc { width: 22px; height: 22px; border-width: 2px; }
  .topbar .pchip .disc i { width: 8px; height: 8px; }
  .topbar .pchip b { font-size: 12px; max-width: 76px; }
  .topbar .pchip small { font-size: 9px; }
  .turn-who { font-size: 15px; }
  .turn-sub { font-size: 9.5px; margin-top: 2px; }
  .turn-tools { margin-top: 4px; gap: 4px; }
  .turn-tools .icon-btn { padding: 5px 8px; font-size: 10px; }
  .players { order: 3; flex-basis: 100%; justify-content: flex-start; }
  .turn-box { margin-left: auto; }
  .turn-who { font-size: 17px; }
  .gl-left { flex-direction: row; overflow: visible; padding: 0; gap: 10px; }
  .gl-left .panel { padding: 10px 12px; box-shadow: var(--shadow-s); border-width: 3px; }
  .act-panel { flex: 1; display: grid; grid-template-columns: auto 1fr; grid-template-areas: "die msg" "die btns"; column-gap: 12px; text-align: left; align-items: center; }
  .act-panel .die { grid-area: die; width: 56px; height: 56px; padding: 8px; margin: 0; border-width: 3px; box-shadow: none; }
  .act-panel .die i { width: 10px; height: 10px; }
  .act-panel .act-msg { grid-area: msg; font-size: 15px; }
  .act-panel .act-note { display: none; }
  /* Sans `min-width: 0`, une colonne de grille ne descend jamais sous la taille
     de son contenu : le bouton « Piocher » poussait la carte et sortait à
     droite. C'est le défaut classique des grilles, et il ne se voit qu'étroit. */
  .act-panel > * { min-width: 0; }
  .act-panel .act-btns { grid-area: btns; flex-direction: row; margin-top: 6px; min-width: 0; flex-wrap: wrap; }
  /* LE MODE « VISER » (04/10/2026, piste A de Gaëlle). Quand il faut pointer
     une case, le panneau de la carte et le bandeau des joueurs s'effacent : le
     plateau passe de 435 à 650 px de haut, et la case de 20 à 34 px. On ne le
     fait que sur écran étroit — ailleurs tout tient déjà. Le bouton « la
     carte » du panneau d'action la ramène. */
  #game.vise .hand-panel, #game.vise #players { display: none; }
  #game.vise .topbar { padding: 6px 0 4px; }
  .act-panel .act-btns .btn { flex: 1 1 auto; min-width: 0; }
  .act-panel .act-btns .btn { padding: 8px 10px; font-size: 13px; border-width: 3px; box-shadow: var(--shadow-s); }
  .act-panel .lbl, .act-panel .timer { display: none; }
  /* AJOUTER UN ENFANT À UNE GRILLE NOMMÉE, C'EST LA CASSER (12/10/2026).
     `#sans-chrono` est arrivé dans ce panneau sans zone : la grille lui a
     fabriqué une ligne de plus, « Lancer le dé » est sorti par la droite et le
     dé est tombé en bas. Vu à la capture du téléphone, invisible sur grand
     écran. Toute boîte posée dans une grille à zones nommées doit recevoir sa
     zone dans le même geste. */
  .act-panel .sans-chrono { grid-column: 1 / -1; text-align: left; margin-top: 4px; }
  .gl-right { flex-direction: row; align-items: stretch; padding: 0; }
  /* La pioche n'a plus de main depuis le § 05 : ce panneau ne porte qu'un
     compteur. Il ne mérite donc pas une rangée entière sur un téléphone — on le
     tient sur deux lignes, et ce qui dépasse se coupe proprement au lieu de
     pousser le reste hors de l'écran. */
  .hand-panel { flex: 1; min-height: 0; }
  /* Le texte « les cartes s'appliquent dès qu'on les pioche » prenait quatre
     lignes et un tiers de l'écran, pour une phrase qui ne change jamais. Sur un
     téléphone on garde ce qui BOUGE — le nombre de cartes — et on réduit le
     rappel : il est en entier dans les Règles et dans le livret. */
  .hand-panel .hand { flex: none; }
  .hand-panel .hand-empty { font-size: 12.5px; line-height: 1.4; }
  .hand-panel .hand-empty p:first-child { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .hand { flex-direction: row; overflow-x: auto; padding: 4px 4px 8px; gap: 8px; }
  .hcard, .hcard:nth-child(even) { width: 84px; margin: 0 !important; transform: none !important; flex-shrink: 0; }
  .hcard.sel { outline: 4px solid var(--yellow); border-radius: 10px; }
  .hcard.sel, .hcard:hover { transform: none !important; }
  .hcard .nm { font-size: 7px; } .hcard .ic { font-size: 20px; } .hcard .kind { display: none; }
  .peek { right: 16px; top: 90px; width: 110px; }
  .hand-panel > .lbl { margin-bottom: 2px; }
  /* Sur téléphone, chaque ligne de panneau est prise sur la HAUTEUR du plateau
     (§ 31). La ligne d'état se serre, sans disparaître : l'information qu'elle
     porte — tours en réserve, cartes restantes — n'est nulle part ailleurs. */
  .etat-ligne { margin-top: 4px; padding-top: 4px; font-size: 10px; letter-spacing: -.02em; }
  .hand-use { margin-top: 6px; }
  .hand-use .btn { padding: 8px; font-size: 13px; }
}

/* ── Fin de partie ──────────────────────────────────────────────────────── */
#victory { z-index: 200; background: var(--paper); }
.vic-head { text-align: center; }
.vic-tag { font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--ink-3); letter-spacing: .14em; }
.vic-name { font-family: var(--title); font-size: 52px; line-height: 1; margin: 6px 0; }
.vic-quote { font-family: var(--hand); font-size: 28px; }
table.rank { width: 100%; border-collapse: collapse; font-size: 13px; }
table.rank th { font-family: var(--mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); text-align: right; padding: 5px 6px; }
table.rank th:nth-child(-n+2) { text-align: left; }
table.rank td { padding: 9px 6px; border-top: 2px dashed var(--ink-4); text-align: right; font-family: var(--mono); font-weight: 700; }
table.rank td:nth-child(-n+2) { text-align: left; font-family: var(--type); font-weight: 800; }
table.rank tr.w td { background: var(--soft); }
.chart svg { width: 100%; height: auto; display: block; }

/* ── Tutoriel / règles / collection ─────────────────────────────────────── */
.tuto-dots { display: flex; gap: 5px; } .tuto-dots i { width: 24px; height: 6px; border-radius: 4px; background: var(--ink-4); } .tuto-dots i.on { background: var(--ink); }
.tuto-text { font-size: 15px; line-height: 1.7; color: var(--ink-2); } .tuto-text b { color: var(--ink); }
.sandbox { background: var(--surface); border: var(--line) solid var(--ink); border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow-s); display: flex; flex-direction: column; align-items: center; gap: 10px; }
.sandbox .board { --cell: 46px; --gap: 7px; }
/* ── L'ONGLET CARTES : UNE PISTE QUI S'ACCROCHE (CDC v5 § 21, 08/10/2026) ──
   Gaëlle : « plutôt que de faire défiler les cartes sur mobile on peut faire un
   système de swipe ? ». C'est `scroll-snap`, natif : le doigt pousse, le
   navigateur accroche la fiche suivante avec SON inertie. Pas une ligne de
   JavaScript pour le glissement — donc rien qui puisse tomber en panne le jour
   où un navigateur change sa gestion du toucher.
   `scroll-padding-inline` est ce qui centre la fiche accrochée : sans lui, la
   première et la dernière se collent au bord et on croit la piste cassée. */
.cartes-filtre { margin: 2px 0 10px; }
.cartes-piste { display: flex; gap: 14px; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-inline: 50%; padding: 6px 0 14px;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.cartes-piste::-webkit-scrollbar { display: none; }
.cartes-piste:focus-visible { outline: 3px solid var(--yellow); outline-offset: 4px; }
.cfiche { flex: 0 0 min(300px, 76vw); scroll-snap-align: center; scroll-snap-stop: always;
  border: var(--line) solid var(--ink); border-radius: 18px; background: var(--surface);
  box-shadow: var(--shadow); padding: 16px 16px 18px; display: flex; flex-direction: column;
  align-items: center; text-align: center; }
.cfiche-img { width: 100%; display: flex; justify-content: center; }
.cfiche-img .gcard { width: min(210px, 62vw); }
.cfiche-tag { font-family: var(--mono); font-size: 10.5px; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase; color: #fff; background: var(--blue); border: 2px solid var(--ink);
  border-radius: 999px; padding: 2px 10px; margin-top: 12px; }
.cfiche.malus .cfiche-tag { background: var(--red); }
.cfiche-nom { font-family: var(--title); font-size: 19px; line-height: 1.15; margin: 8px 0 2px; }
.cfiche-ex { font-family: var(--mono); font-size: 11.5px; font-weight: 700; color: var(--ink-3); }
.cfiche-effet { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); margin: 10px 0 0; }
.cartes-pied { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 2px; }
.cartes-pos { font-family: var(--mono); font-size: 13px; font-weight: 700; min-width: 86px; text-align: center;
  font-variant-numeric: tabular-nums; }
.cartes-aide { text-align: center; margin-top: 10px; }
/* ── LE SWIPE EST POUR LE TÉLÉPHONE, ET SEULEMENT POUR LUI ───────────────
   Gaëlle, 08/10 : « swipe uniquement sur la version mobile hein ». Elle a
   raison : glisser au doigt répond à un écran étroit, où une carte occupe tout.
   Sur un ordinateur, faire défiler trente fiches à la souris pour en trouver
   une est PIRE qu'une grille où on les voit toutes.
   Au-delà de 900 px, la piste redevient donc une grille : même balisage, même
   fiches, on désarme simplement l'accrochage et on laisse le retour à la ligne.
   Le pied (flèches et compteur) n'a plus de sens là : il disparaît. */
@media (min-width: 900px) {
  .cartes-piste { flex-wrap: wrap; overflow: visible; scroll-snap-type: none;
    scroll-padding-inline: 0; gap: 18px; justify-content: flex-start; }
  .cfiche { flex: 0 0 calc(25% - 14px); scroll-snap-align: none; }
  .cartes-pied, .cartes-aide { display: none; }
}
@media (min-width: 900px) and (max-width: 1240px) { .cfiche { flex-basis: calc(33.333% - 12px); } }
.rules-list { font-size: 15px; line-height: 1.7; color: var(--ink-2); padding-left: 20px; } .rules-list b { color: var(--ink); }
/* L'écran Règles n'est plus une liste : c'est le livret, construit par
   js/livret.js à partir du moteur. Mêmes blocs que le livret imprimable. */
/* ── § 22 : LES RÈGLES EN SECTIONS QU'ON OUVRE (09/10/2026) ──────────────
   Le § 22 montre une pile de boutons, pas un document. Fermé, chaque chapitre
   ne prend qu'une ligne ; ouvert, il se déroule en dessous. `grid-template-rows`
   à 0fr → 1fr anime la hauteur SANS la connaître : un `max-height` choisi au
   jugé coupe toujours le chapitre le plus long un jour. */
.rg-sec { border: 3px solid var(--ink); border-radius: 14px; background: var(--surface);
  box-shadow: 4px 4px 0 var(--ink); margin-bottom: 12px; overflow: hidden; }
.rg-tete { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 15px 16px; background: none; border: 0; cursor: pointer; text-align: left; }
.rg-tete:hover { background: var(--soft); }
.rg-nom { font-family: var(--title); font-size: 17px; color: var(--ink); }
.rg-chev { font-family: var(--mono); font-size: 22px; font-weight: 700; color: var(--ink-3); line-height: 1; transition: transform .2s; }
.rg-sec.ouvert .rg-chev { transform: rotate(45deg); }
.rg-sec.ouvert { box-shadow: 4px 4px 0 var(--red); border-color: var(--ink); }
/* Le corps n'a QU'UN enfant (`.rg-dedans`) : `grid-template-rows: 0fr` ne
   dimensionne que la PREMIÈRE rangée, et la première version laissait donc
   dépasser tous les paragraphes suivants — 4 865 px de haut pour neuf boutons
   censés être fermés. Mesuré, pas relu. */
.rg-corps { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .25s ease; }
.rg-sec.ouvert .rg-corps { grid-template-rows: 1fr; }
.rg-dedans { overflow: hidden; min-height: 0; }
.rg-sec.ouvert .rg-dedans { padding: 0 16px 14px; }
.rules-doc .rg-corps .lv-ch { margin-top: 0; }

/* ── § 8 : LE VERROU VISIBLE DE L'ACTION ─────────────────────────────────
   Pendant le verrou, les boutons ne répondent plus ET se voient éteints : un
   bouton qui refuse sans rien montrer, c'est ce qui faisait croire à une carte
   sautée. */
#game.verrou .act-btns .btn, #game.verrou .die { pointer-events: none; opacity: .5; filter: grayscale(.4); }
#game.verrou .act-btns .btn { transform: none; box-shadow: none; }

.rules-doc { font-size: 15px; line-height: 1.7; color: var(--ink-2); }
.rules-doc b { color: var(--ink); }
.rules-doc .lv-ch { margin-top: 26px; }
.rules-doc .lv-ch:first-child { margin-top: 10px; }
.rules-doc h3 { font-family: var(--title); font-size: 19px; color: var(--ink); margin: 0 0 8px;
  border-bottom: 3px solid var(--ink); padding-bottom: 5px; }
.rules-doc p { margin: 9px 0; }
.rules-doc ul { margin: 9px 0; padding-left: 20px; } .rules-doc li { margin: 6px 0; }
.rules-doc .lv-enc { border-left: 5px solid var(--red); background: var(--surface); padding: 10px 14px; margin: 14px 0;
  border-top: 1px solid var(--ink-4); border-right: 1px solid var(--ink-4); border-bottom: 1px solid var(--ink-4); }
.rules-doc .lv-table { width: 100%; border-collapse: collapse; margin: 12px 0; background: var(--surface); font-size: 14px; }
.rules-doc .lv-table th, .rules-doc .lv-table td { border: 2px solid var(--ink); padding: 6px 9px; text-align: left; }
.rules-doc .lv-table th { background: var(--ink); color: #fff; font-family: var(--title); font-size: 12px; letter-spacing: .04em; }
.rules-doc .lv-table tbody tr:nth-child(even) { background: var(--soft); }
#rules-livret { margin-top: 26px; text-decoration: none; }
@media (max-width: 560px) { .rules-doc .lv-table { font-size: 12.5px; } .rules-doc .lv-table th, .rules-doc .lv-table td { padding: 5px 6px; } }

/* ── En ligne / salon ───────────────────────────────────────────────────── */
.code-big { font-family: var(--title); font-size: 56px; letter-spacing: .18em; text-align: center; }
.link-row { display: flex; gap: 8px; align-items: center; }
.link-row input { flex: 1; min-width: 0; font-family: var(--mono); font-size: 12px; padding: 10px; border: 3px solid var(--ink); border-radius: 10px; background: var(--surface); }
.text-in { width: 100%; font-size: 16px; font-weight: 700; padding: 12px 14px; border: 3px solid var(--ink); border-radius: 12px; background: var(--surface); }
.text-in.code { font-family: var(--title); letter-spacing: .3em; text-transform: uppercase; text-align: center; font-size: 26px; }
.lobby-seat { display: grid; grid-template-columns: 22px 1fr auto; gap: 10px; align-items: center; padding: 12px 14px; border: 3px solid var(--ink); border-radius: 14px; background: var(--surface); font-weight: 800; }
.lobby-seat .st { font-family: var(--mono); font-size: 11px; color: var(--ink-3); } .lobby-seat .st.on { color: var(--ok); }
.lobby-seat button { padding: 5px 10px; font-size: 12px; font-weight: 800; border-radius: 9px; border: 2px solid var(--ink); background: var(--surface); cursor: pointer; }
.warn-box { border: 3px dashed var(--red); border-radius: 14px; padding: 14px; font-size: 14px; line-height: 1.55; background: #fff5f5; }
.warn-box code { font-family: var(--mono); background: var(--soft); padding: 1px 5px; border-radius: 4px; }

/* ── Réglages ───────────────────────────────────────────────────────────── */
.switch { width: 52px; height: 30px; border-radius: 16px; border: 3px solid var(--ink); background: var(--soft); position: relative; cursor: pointer; flex-shrink: 0; }
.switch i { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: #fff; border: 3px solid var(--ink); transition: left .15s; }
.switch.on { background: var(--ok); } .switch.on i { left: 24px; }

@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; } }
body.calm *, body.calm *::before, body.calm *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }


/* ── v0.7 : cartes rares ─────────────────────────────────────────────────── */
.gcard .rare{position:absolute;top:6%;right:7%;font:700 .52em/1 'Archivo Black',system-ui,sans-serif;
  letter-spacing:.09em;color:#f5b800;-webkit-text-stroke:.9px #111;paint-order:stroke;
  transform:rotate(-16.56deg);transform-origin:right top;pointer-events:none}
.tag-rare{display:inline-block;font:700 .82em/1.5 system-ui,sans-serif;letter-spacing:.06em;
  text-transform:uppercase;color:#111;background:#f5b800;border:2px solid #111;padding:0 6px}


/* ═══ COMPTE ET CLASSEMENT (27/09/2026) ═══════════════════════════════════ */
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.stat-t { border: 2px solid var(--ink); border-radius: 10px; background: var(--paper); padding: 8px 6px; text-align: center; }
.stat-t b { display: block; font-family: var(--title); font-size: 21px; line-height: 1.1; }
.stat-t span { display: block; font-size: 11px; color: var(--ink-3); margin-top: 2px; }
.mp-ligne { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: center;
  padding: 8px 0; border-bottom: 1px solid var(--ink-4); font-size: 13.5px; }
.mp-ligne:last-child { border-bottom: none; }
.mp-txt { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
.mp-plateau { width: 56px; flex: none; border: 2px solid var(--ink); border-radius: 8px; background: var(--surface);
  padding: 3px 3px 1px; cursor: pointer; display: block; transition: transform .08s, box-shadow .08s; }
.mp-plateau:hover { box-shadow: 2px 2px 0 var(--ink); transform: translate(-1px, -1px); }
.mp-plateau:active { transform: translate(1px, 1px); box-shadow: none; }
.mp-plateau svg { width: 100%; height: auto; display: block; }
.mp-plateau span { display: block; font-family: var(--mono); font-size: 9px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); text-align: center; padding: 2px 0 1px; }
.mp-issue { font-family: var(--title); font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
  border: 2px solid var(--ink); border-radius: 6px; padding: 1px 7px; }
.mp-issue.gagne { background: var(--green); color: #fff; }
.mp-issue.perdu { background: var(--surface); color: var(--ink-2); }
.mp-d { font-family: var(--mono); font-size: 12px; color: var(--ink-3); }
.mp-info { width: 100%; color: var(--ink-2); line-height: 1.45; }

/* ── Les filtres des statistiques (CDC § 11, 03/10/2026) ───────────────
   Sept filtres ne tiennent pas dans un `.seg` : il répartit ses boutons en
   colonnes égales, donc sept colonnes de 45 px sur un téléphone, illisibles.
   Ici ça passe à la ligne et chaque bouton garde la largeur de son texte. */
.filtres { display: flex; flex-wrap: wrap; gap: 6px; }
.filtres button { font-family: var(--type); font-weight: 700; font-size: 13px; padding: 7px 12px;
  border-radius: 999px; border: 2px solid var(--ink); background: var(--surface); cursor: pointer; }
.filtres button.on { background: var(--ink); color: #fff; }
.filtres button:disabled { opacity: .45; cursor: default; }
/* Ce qu'ÉTAIT la partie, dit sur la ligne : une partie sur l'appareil ou avec
   des bots ne rapporte jamais de points, et ça ne doit pas être à deviner. */
.mp-tag { font-family: var(--mono); font-size: 10px; letter-spacing: .04em; text-transform: uppercase;
  border: 2px solid var(--ink-3); border-radius: 999px; padding: 1px 7px; color: var(--ink-2); white-space: nowrap; }
.mp-tag.pts { border-color: var(--ink); color: var(--ink); font-weight: 700; }
.mp-tag.sans { border-style: dashed; }

/* ── LE CHAT (CDC § 55-57, 03/10/2026) ────────────────────────────
   Une fenêtre, pas un panneau : la grille de la partie est déjà juste sur un
   téléphone, et elle vient d'être réparée. */
/* ── LE CHAT RESTE AFFICHÉ (03/10/2026) ───────────────────────────────────
   Gaëlle : « le chat j'aimerais qu'il reste affiché, qu'on ait un chat en
   direct sans avoir à ouvrir fermer ».
   Sur un écran large il se détache en COLONNE à droite, toujours ouverte : plus
   de voile, plus de bouton « Fermer ». Sur un écran étroit il reste une boîte
   qu'on ouvre : une colonne permanente mangerait le plateau, et c'est
   exactement le chevauchement réparé le matin même sur téléphone. Le seuil est
   large (1100 px) parce qu'il faut la place du plateau ENTIER plus la colonne,
   pas seulement la colonne. */
@media (min-width: 1100px) {
  /* ── LE CHAT : UNE COLONNE QUAND IL EST OUVERT, RIEN QUAND IL EST REPLIÉ ──
     Première version : un tiroir qui GLISSAIT par-dessus la colonne de gauche,
     et je masquais celle-ci. Mesuré, c'était absurde : le panneau d'action — le
     dé, les boutons du tour — disparaissait. On ne cache pas au joueur ce avec
     quoi il joue pour faire de la place à un chat vide.
     Donc le chat devient une vraie COLONNE de la grille, et seulement quand il
     est ouvert. Replié, il n'existe pas : plus un pixel pris au plateau, et il
     ne recouvre rien. C'est les deux moitiés du § 13 — « fermé, il prend très
     peu de place ; ouvert, il se déroule sans masquer inutilement le plateau ». */
  #chat-modal { position: static; grid-area: chat; padding: 0; z-index: auto;
    align-items: stretch; justify-content: flex-start; min-height: 0; gap: 0; }
  #chat-modal .wash { display: none; }
  #chat-modal > .panel { width: 100% !important; height: 100%; max-height: none; overflow: auto; }
  #chat-modal [data-act="chat"].btn { display: none; }   /* le bouton « Fermer » du bas */
  #chat-modal .chat-liste { max-height: none; flex: 1 1 auto; }
  /* ── LE PLATEAU MINUSCULE SUR GRAND ÉCRAN (corrigé le 29/10/2026) ──────────
     Ce gabarit était resté celui d'AVANT le CDC v6 : quatre colonnes et des zones
     « top », « left », « right » qui n'existent plus depuis que l'écran tient en
     deux zones. La grille fabriquait alors des colonnes de secours, et le plateau
     tombait à 130 px de large sur un écran de 1920 — mesuré, puis vu à la
     capture. Le chat ouvert est maintenant une troisième colonne, collée au
     PLATEAU (c'est de ce côté qu'est son onglet), et il suit la bascule du § 5. */
  #game.chat-large { grid-template-columns: 300px minmax(0, 1fr) 320px; grid-template-rows: minmax(0, 1fr);
    grid-template-areas: "chat board info"; }
  #game.chat-large.plateau-droite { grid-template-columns: 320px minmax(0, 1fr) 300px;
    grid-template-areas: "info board chat"; }
  .chat-onglet.ouvert { transform: translateX(300px); }
}

/* ── L'ONGLET DU CHAT (CDC v5 § 13) ──────────────────────────────────────
   « Petit onglet sur le côté gauche. » Il se colle au bord de l'écran de
   partie, suit le tiroir quand il s'ouvre, et porte la pastille des messages
   non lus — on n'ouvre pas pour découvrir qu'il ne s'est rien dit. */
/* « Le chat l'icône est un peu haute » (Gaëlle, 08/10) : elle arrivait à
   hauteur du panneau d'action, où l'œil cherche le dé. Descendue au deux tiers
   de l'écran, elle est dans la zone du pouce et ne dispute rien à personne. */
.chat-onglet { position: absolute; left: 0; top: 66%; z-index: 61;
  display: flex; align-items: center; gap: 4px; padding: 14px 7px; border: 3px solid var(--ink);
  border-left: 0; border-radius: 0 14px 14px 0; background: var(--surface);
  box-shadow: 3px 3px 0 var(--ink); cursor: pointer; transition: transform .22s ease; }
.chat-onglet .bulle { font-size: 11px; letter-spacing: 1px; line-height: 1; }
.chat-onglet .pastille-n { margin-left: 0; }
.chat-onglet:hover { background: var(--soft); }
/* § 5 : « déplacer l'ensemble de la composition de façon cohérente ». L'onglet
   du chat fait partie de l'ensemble — laissé à gauche, il venait se coller
   par-dessus la colonne d'informations quand le plateau passait à droite.
   Vu à l'image après la bascule, pas en relisant la règle. */
#game.plateau-droite .chat-onglet { left: auto; right: 0; border-left: 3px solid var(--ink); border-right: 0;
  border-radius: 14px 0 0 14px; box-shadow: -3px 3px 0 var(--ink); }
#game.plateau-droite .chat-onglet.ouvert { transform: translateX(-300px); }

/* `[hidden]` pose `display: none` depuis la feuille du navigateur : une règle
   de CLASSE qui redonne `display: flex` la bat, et l'onglet réapparaît alors
   dans une partie locale, où il n'y a pas de chat. Vu à la capture. Règle
   générale : tout sélecteur qui pose un `display` doit rendre son `[hidden]`. */
.chat-onglet[hidden] { display: none; }
.chat-tete { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.chat-tete .lbl { margin: 0; }
.chat-fermer { font-size: 22px; line-height: 1; padding: 0 8px; background: none; border: 0; cursor: pointer; color: var(--ink-3); }
.chat-fermer:hover { color: var(--ink); }
.chat-garde { margin: 0; font-size: 12px; }

/* La ligne d'état qui remplace le bloc « Objectifs » (§ 12, § 29). */
.etat-ligne { margin-top: 8px; padding-top: 8px; border-top: 2px dashed var(--ink-4);
  font-family: var(--mono); font-size: 11.5px; font-weight: 700; color: var(--ink-3); text-align: center; }

.chat-liste { max-height: 46vh; overflow: auto; display: flex; flex-direction: column; gap: 7px;
  border: 2px solid var(--ink-4); border-radius: 12px; padding: 10px; background: var(--paper); }
.chat-l { font-size: 13.5px; line-height: 1.45; word-break: break-word; }
.chat-l b { font-family: var(--title); font-size: 12.5px; letter-spacing: .03em; }
.chat-l .pastille { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  border: 1.5px solid var(--ink); margin-right: 5px; vertical-align: baseline; }
.chat-l .h { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); margin-left: 5px; }
.chat-vide { color: var(--ink-3); font-size: 13px; }
.chat-envoi { display: flex; gap: 8px; align-items: stretch; }
/* `.btn` porte `width: 100%` : dans une rangée flex, ça lui donne une base de
   toute la largeur, et il pousse le champ hors de l'écran. Il faut le lui
   RETIRER, pas seulement l'empêcher de grandir. Même piège que les colonnes
   du panneau d'action le 03/10 au matin : ce qui ne peut pas rétrécir écrase
   son voisin au lieu de céder. */
.chat-envoi .text-in { flex: 1 1 auto; min-width: 0; }
.chat-envoi .btn { flex: 0 0 auto; width: auto; justify-content: center; padding: 12px 16px; font-size: 15px; }
/* Le compteur de messages non lus sur le bouton de la partie : on n'ouvre pas
   la fenêtre pour découvrir qu'il ne s'y est rien dit. */
.icon-btn .pastille-n { display: inline-block; min-width: 16px; margin-left: 5px; padding: 0 4px;
  border-radius: 999px; background: var(--red); color: #fff; font-family: var(--mono); font-size: 10px; }
/* ── CDC v6 § 12 : les deux classements côte à côte (13/10/2026) ──────────
   « À côté », pas « à la place ». Sur téléphone ils s'empilent, le mois
   d'abord : c'est celui qu'on vient regarder. */
.cl-deux { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
.cl-deux > div { min-width: 0; }
.cl-deux .lbl { margin-bottom: 8px; }
@media (max-width: 860px) { .cl-deux { grid-template-columns: 1fr; gap: 20px; } }
/* ── LE BANDEAU PERSONNEL (§ 12, proposition C — 13/10/2026) ──────────────
   Il répond à « où j'en suis », pas à « qui gagne ». Il est en jaune pour ne
   PAS ressembler à un tableau de plus : c'est un résumé, pas un classement.
   `flex-wrap` plutôt qu'une grille à colonnes fixes — les blocs sont de
   largeurs très différentes selon le pseudo, et sur téléphone ils passent à la
   ligne au lieu de se serrer à l'illisible. */
.cl-bandeau { display: flex; align-items: center; gap: 10px 44px; flex-wrap: wrap;
  border: var(--line) solid var(--ink); border-radius: 14px; background: var(--yellow-l);
  padding: 12px 16px; margin: 0 0 14px; box-shadow: 3px 3px 0 var(--ink); }
.cl-bandeau .q { font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3); display: block; }
.cl-bandeau b { font-family: var(--title); font-size: 19px; line-height: 1.2; }
.cl-bandeau .pas-classe { font-size: 14px; line-height: 1.45; max-width: 60ch; }
@media (max-width: 560px) { .cl-bandeau { gap: 8px 18px; } .cl-bandeau b { font-size: 17px; } }
table.cl { width: 100%; border-collapse: collapse; background: var(--surface); font-size: 14px;
  border: var(--line) solid var(--ink); }
table.cl th, table.cl td { border-bottom: 1px solid var(--ink-4); padding: 8px 10px; text-align: left; }
table.cl th { background: var(--ink); color: #fff; font-family: var(--title); font-size: 12px; letter-spacing: .05em; border-bottom: none; }
table.cl td:first-child { font-family: var(--mono); color: var(--ink-3); width: 2.5em; }
/* Sa propre ligne se repère d'un coup d'oeil : c'est la première chose qu'on
   cherche dans un classement. Doublée d'un trait, pas seulement d'une couleur. */
table.cl tr.moi { background: var(--yellow-l); box-shadow: inset 4px 0 0 var(--ink); }
table.cl tr.moi td { font-weight: 700; }
table.cl tbody tr:last-child td { border-bottom: none; }
@media (max-width: 560px) {
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  table.cl { font-size: 12.5px; } table.cl th, table.cl td { padding: 6px 6px; }
  table.cl th:nth-child(4), table.cl td:nth-child(4),
  table.cl th:nth-child(6), table.cl td:nth-child(6) { display: none; }
  .mp-plateau { width: 48px; }
}

/* ── LA LANGUE (27/09/2026) ───────────────────────────────────────────────
   Le bouton porte l'icône dessinée ET le nom de la langue écrit dans cette
   langue : à 20 px l'icône seule ne suffit pas à quelqu'un qui découvre
   l'écran, et le nom écrit évite d'ouvrir la fenêtre pour vérifier.
   L'icône est décorative — c'est le bouton qui reçoit les clics (§ 4 duodecies). */
.lang-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.retour-site { font-weight: 800; font-size: 14px; text-decoration: none; color: var(--ink); border: 3px solid var(--ink); border-radius: 999px; padding: 5px 13px; background: var(--surface); box-shadow: var(--shadow-s); }
.retour-site:hover { background: var(--soft); }
.lang-btn { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; padding: 6px 12px 6px 8px;
  background: var(--surface); border: 2px solid var(--ink); border-radius: 999px; font-family: var(--type); font-weight: 700; font-size: 14px; color: var(--ink); }
.lang-btn:hover { background: var(--soft); }
.lang-btn .lang-ic { width: 22px; height: 22px; display: block; flex: 0 0 22px; pointer-events: none; }
.lang-btn .lang-ic svg { width: 100%; height: 100%; display: block; }
/* Le globe ne dit pas quelle langue est en cours : c'est le texte qui s'en
   charge. En grand, le nom entier ; en étroit, les deux lettres — mais jamais
   rien, sinon le bouton ne renseigne plus sur rien. */
.lang-btn .lang-code { display: none; font-family: var(--mono); font-size: 12px; letter-spacing: .08em; }
.lang-list { display: flex; flex-direction: column; gap: 8px; }
.lang-opt { display: flex; align-items: center; gap: 12px; width: 100%; padding: 11px 14px; cursor: pointer;
  background: var(--surface); border: 3px solid var(--ink); border-radius: 14px; font-family: var(--title); font-size: 17px; color: var(--ink); text-align: left; }
.lang-opt:hover { background: var(--soft); }
.lang-opt.on { background: var(--ink); color: #fff; }
.lang-opt.on .muted { color: #cfcabb; }
.lang-opt .lang-tag { flex: 0 0 auto; min-width: 34px; text-align: center; padding: 3px 7px; border: 2px solid var(--ink); border-radius: 8px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .08em; pointer-events: none; }
.lang-opt.on .lang-tag { border-color: #fff; }
.lang-opt .muted { margin-left: auto; font-size: 11px; font-family: var(--mono); letter-spacing: .1em; text-transform: uppercase; }
@media (max-width: 520px) { .lang-btn .lang-nom { display: none; } .lang-btn .lang-code { display: inline; } .lang-btn { padding: 6px 10px 6px 8px; } }

/* ── UN CLIC = UNE ACTION (CDC v6 § 10, 12/10/2026) ───────────────────────
   L'état d'attente d'un bouton qui a parlé au serveur. Volontairement SANS
   animation : le § 2 reproche justement aux animations de sauter, ce n'est pas
   le moment d'en ajouter une qui clignote sous le doigt. Le bouton s'éteint,
   le curseur dit que ça travaille, et c'est tout.                            */
.attend { opacity: .75; cursor: progress; }
/* La petite roue qui tourne (Launhas, 31/10/2026) : on voit tout de suite que
   le clic est parti, même si le serveur met une seconde à répondre. */
.attend::after { content: ""; display: inline-block; width: .95em; height: .95em; margin-left: .55em; vertical-align: -.14em;
  border: 3px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: roue .7s linear infinite; }
@keyframes roue { to { transform: rotate(360deg); } }
/* La roue de toute l'application : en haut, au milieu, par-dessus tout. Elle
   ne bloque rien (pas de clic avalé) : on peut encore annuler ou revenir. */
.roue-globale { position: fixed; top: max(10px, env(safe-area-inset-top)); left: 50%; transform: translateX(-50%); z-index: 200; pointer-events: none;
  display: flex; align-items: center; gap: 9px; padding: 8px 16px 8px 12px; background: var(--ink); color: #fff; border-radius: 999px;
  font-family: var(--title); font-size: 14px; box-shadow: 0 4px 14px rgba(0,0,0,.25); animation: roueEntre .18s ease-out; }
.roue-globale[hidden] { display: none; }
.roue-globale i { width: 18px; height: 18px; border: 3px solid #fff; border-right-color: transparent; border-radius: 50%; animation: roue .7s linear infinite; }
@keyframes roueEntre { from { opacity: 0; transform: translate(-50%, -6px); } }
.attend:active { transform: none; }


/* ═══════════════════════════════════════════════════════════════════════════
   TÉLÉPHONE : LE PLATEAU À GAUCHE, LES INFORMATIONS À DROITE (29/10/2026)
   ───────────────────────────────────────────────────────────────────────────
   Demande de Launhas : « règle les interfaces téléphone, plateau à gauche,
   infos à droite ». Jusqu'ici le téléphone empilait tout (joueurs, plateau,
   action, cartes) et défilait. Il prend maintenant les DEUX ZONES du CDC v6
   § 5, comme le grand écran : le plateau d'un côté, une colonne étroite de
   l'autre, et rien ne défile sauf la colonne si elle déborde.
   Le réglage « plateau à droite » (§ 5) marche ici aussi : c'est la même
   ligne de gabarit qui bascule.
   Ce bloc vient APRÈS la pile du téléphone et en défait ce qui la faisait
   pile ; les réglages de détail qu'elle portait (pastilles serrées, mode
   « viser », dé réduit) restent valables. */
@media (max-width: 899px), (orientation: portrait) and (max-width: 1240px) {
  #game { --col-info: clamp(124px, 34vw, 236px); --marge-plateau: 6; --ombre-plateau: 4;
    grid-template-columns: minmax(0, 1fr) var(--col-info); grid-template-rows: minmax(0, 1fr);
    grid-template-areas: "board info"; overflow: hidden; padding: 6px 6px 8px; gap: 6px; }
  #game.plateau-droite { grid-template-columns: var(--col-info) minmax(0, 1fr); grid-template-areas: "info board"; }
  /* La colonne redevient une vraie boîte (elle était en `display: contents`). */
  .gl-info { display: flex; flex-direction: column; gap: 7px; overflow-y: auto; overflow-x: hidden; padding: 0 2px 6px 0; min-height: 0; }
  /* Le plateau prend toute sa colonne, avec un cadre fin : chaque pixel va aux cases. */
  .board-stage { --marge-plateau: 6; --ombre-plateau: 4; --case-min: 10; }
  .board-frame { --pad-plateau: 7px; border-width: 4px; box-shadow: none; border-radius: 3px; }
  .zoom-ctl { right: 4px; bottom: 4px; gap: 4px; }
  .zoom-ctl button { width: 32px; height: 32px; font-size: 16px; border-width: 2px; }
  /* Qui joue : les joueurs l'un sous l'autre, en entier — pas de rail à faire glisser. */
  .gl-info > .topbar { flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 6px; padding: 0; }
  .gl-info .players { order: 0; flex-basis: auto; display: flex; flex-direction: column; flex-wrap: nowrap; gap: 5px; padding: 0 3px 2px 0; }
  .gl-info .pchip { width: 100%; padding: 3px 6px 3px 3px; gap: 5px; box-sizing: border-box; }
  .gl-info .pchip.act { box-shadow: 3px 3px 0 var(--ink); transform: none; }
  .gl-info .pchip b { max-width: none; font-size: 11.5px; }
  .gl-info .pchip small { font-size: 8.5px; display: block; overflow: hidden; text-overflow: ellipsis; }
  .gl-info .pchip > div { min-width: 0; overflow: hidden; }
  .gl-info .turn-box { margin-left: 0; text-align: left; }
  .gl-info .turn-who { font-size: 14px; white-space: normal; line-height: 1.1; }
  .gl-info .turn-sub { font-size: 8.5px; }
  .gl-info .turn-tools { justify-content: stretch; flex-wrap: wrap; margin-top: 5px; }
  .gl-info .turn-tools .icon-btn { flex: 1 1 auto; padding: 4px 4px; font-size: 9px; text-align: center; }
  /* Quoi faire : le dé, le message, les boutons — en colonne, pleine largeur. */
  .gl-left { flex-direction: column; gap: 7px; }
  .gl-left .panel, .gl-right .panel { padding: 8px; }
  .act-panel { display: flex; flex-direction: column; align-items: stretch; text-align: center; }
  .act-panel .die { width: 50px; height: 50px; padding: 7px; margin: 2px auto 6px; }
  .act-panel .die i { width: 9px; height: 9px; }
  .act-panel .act-msg { font-size: 13.5px; line-height: 1.2; }
  .act-panel .act-btns { flex-direction: column; flex-wrap: nowrap; margin-top: 6px; gap: 6px; }
  .act-panel .act-btns .btn { width: 100%; padding: 8px 6px; font-size: 12.5px; white-space: normal; line-height: 1.15; }
  .act-panel .sans-chrono { font-size: 9px; text-align: center; }
  /* Avec quelles cartes : en grille, pas en rail. */
  .gl-right { flex-direction: column; gap: 7px; }
  .hand-panel { flex: none; }
  .hand { flex-direction: row; flex-wrap: wrap; overflow: visible; padding: 2px; gap: 6px; }
  .hcard, .hcard:nth-child(even) { width: calc(50% - 3px); min-width: 0; }
  .etat-ligne { font-size: 9px; }
  /* LE MODE « VISER » DANS CETTE DISPOSITION. Effacer la carte et les joueurs
     ne rendait plus rien au plateau : ici c'est la LARGEUR de la colonne qui
     borne la case, pas la hauteur. Pendant qu'on pointe une case, la colonne
     se rétrécit donc à ce qui reste (le message et les boutons), et le plateau
     prend la largeur libérée. Mesuré, plateau 2 joueurs sur 412 × 860 : case
     de 26 px, 32 px pendant qu'on vise. */
  #game.vise { --col-info: clamp(92px, 25vw, 150px); }
  #game.vise .act-panel .die { width: 34px; height: 34px; padding: 4px; }
  #game.vise .act-panel .die i { width: 6px; height: 6px; }
  /* Le chat : l'onglet reste au bord du PLATEAU, mais EN HAUT. À mi-hauteur il
     couvrait les deux premières colonnes de cases (vu à la capture 360 × 640) ;
     en haut il tombe dans le vide laissé par le plateau, qui est carré et centré. */
  .chat-onglet { top: 8px; padding: 10px 5px; }
}
/* Paysage sur un téléphone (peu de hauteur) : la colonne s'élargit, le plateau garde toute la hauteur. */
@media (max-height: 500px) and (orientation: landscape) {
  #game { --col-info: clamp(180px, 30vw, 280px); grid-template-columns: minmax(0, 1fr) var(--col-info); grid-template-rows: minmax(0, 1fr);
    grid-template-areas: "board info"; overflow: hidden; padding: 4px 6px; gap: 6px; }
  #game.plateau-droite { grid-template-columns: var(--col-info) minmax(0, 1fr); grid-template-areas: "info board"; }
  /* Peu de hauteur : les joueurs sur deux colonnes, le dé plus petit — le bouton
     d'action doit rester visible sans faire défiler la colonne. */
  .gl-info .players { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
  .gl-info .pchip { padding: 2px 4px 2px 2px; }
  .gl-info .pchip small { display: none; }
  .gl-info .turn-tools { flex-wrap: nowrap; }
  .act-panel .die { width: 38px; height: 38px; padding: 5px; margin: 0 auto 4px; }
  .act-panel .die i { width: 7px; height: 7px; }
  .act-panel .act-btns .btn { padding: 6px; }
  /* En paysage, le plateau prend toute la hauteur : le vide est sur les CÔTÉS.
     Les boutons de zoom s'y rangent en colonne, sinon ils couvrent des cases. */
  .zoom-ctl { flex-direction: column; right: 2px; bottom: 4px; }
  #game.plateau-droite .zoom-ctl { right: auto; left: 2px; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   LE TIROIR DU JEU — TÉLÉPHONE EN PORTRAIT (Launhas, 31/10/2026)
   ───────────────────────────────────────────────────────────────────────────
   Le plateau prend tout l'écran. Les joueurs, le dé et les cartes sortent du
   bord droit dans un tiroir, avec son onglet — comme le chat sort du bord
   gauche. Ailleurs (paysage, grand écran) la mise en page ne change pas. */
.tiroir-onglet { display: none; }
@media (orientation: portrait) and (max-width: 899px) {
  #game, #game.plateau-droite { grid-template-columns: minmax(0, 1fr); grid-template-areas: "board"; padding: 6px; }
  #game .gl-info { position: fixed; top: 0; right: 0; bottom: 0; z-index: 62; width: min(86vw, 340px); padding: 14px 14px 18px; gap: 10px;
    background: var(--paper); border-left: 4px solid var(--ink); box-shadow: -6px 0 0 rgba(0,0,0,.12);
    transform: translateX(105%); transition: transform .25s ease; overflow-y: auto; }
  #game.tiroir-ouvert .gl-info { transform: none; }
  /* Dans le tiroir, la place ne manque plus : on rend aux textes leur taille. */
  #game .gl-info .pchip b { font-size: 14px; }
  #game .gl-info .pchip small { font-size: 10px; }
  #game .gl-info .turn-who { font-size: 19px; }
  #game .gl-info .turn-sub { font-size: 10px; }
  #game .gl-info .turn-tools { flex-wrap: nowrap; }
  #game .gl-info .turn-tools .icon-btn { font-size: 11px; padding: 6px; }
  #game .act-panel .die { width: 64px; height: 64px; padding: 9px; }
  #game .act-panel .die i { width: 11px; height: 11px; }
  #game .act-panel .act-msg { font-size: 16px; }
  #game .act-panel .act-btns .btn { font-size: 15px; padding: 11px 8px; }
  /* Le mode « viser » cachait la carte et les joueurs pour donner la place au
     plateau ; dans le tiroir, ils ne prennent rien au plateau : on les garde. */
  #game.vise .hand-panel { display: flex; }
  #game.vise #players { display: flex; }
  /* En HAUT à droite, en face de l'onglet du chat : au milieu du bord, il couvrait
     la dernière colonne de cases d'un plateau de 14 × 14 (vu à la capture). */
  /* Couché à l'horizontale : debout, avec « À toi », il descendait sur le coin
     du plateau (vu à la capture, plateau 2 joueurs). */
  .tiroir-onglet { display: flex; flex-direction: row; align-items: center; gap: 7px; position: absolute; right: 0; top: 6px; z-index: 63;
    transform: none; padding: 6px 9px 6px 10px; border: 3px solid var(--ink); border-right: 0; border-radius: 14px 0 0 14px;
    background: var(--surface); box-shadow: -3px 3px 0 var(--ink); cursor: pointer; transition: transform .25s ease, background .2s; }
  .tiroir-onglet .tiroir-de { width: 24px; height: 24px; border: 3px solid var(--ink); border-radius: 7px; position: relative; background: #fff; }
  .tiroir-de i { position: absolute; width: 5px; height: 5px; border-radius: 50%; background: var(--ink); }
  .tiroir-de i:nth-child(1) { left: 3px; top: 3px; } .tiroir-de i:nth-child(2) { left: 8px; top: 8px; } .tiroir-de i:nth-child(3) { right: 3px; bottom: 3px; }
  .tiroir-onglet::after { content: ""; width: 12px; height: 12px; border-radius: 50%; background: var(--pc, var(--ink)); border: 2.5px solid var(--ink); }
  .tiroir-onglet.a-toi { background: var(--yellow); animation: tiroirAppel 1.1s ease-in-out infinite; }
  .tiroir-txt { font-family: var(--title); font-size: 13px; line-height: 1; white-space: nowrap; }
  .tiroir-txt:empty { display: none; }
  #game.tiroir-ouvert .tiroir-onglet { transform: translateX(calc(-1 * min(86vw, 340px))); animation: none; }
  #game .zoom-ctl { display: none; }
}
@keyframes tiroirAppel { 0%, 100% { background: var(--yellow); box-shadow: -3px 3px 0 var(--ink), 0 0 0 0 rgba(245,184,0,.6); }
  50% { background: #fff; box-shadow: -3px 3px 0 var(--ink), 0 0 0 9px rgba(245,184,0,0); } }
/* À TON TOUR, ÇA CLIGNOTE (Launhas, 31/10/2026) — sans rien déplacer à l'écran.
   Partout : le bouton d'action du panneau pulse. Sur téléphone en portrait :
   l'onglet du tiroir clignote en jaune avec « À toi ». */
#game.a-toi .act-panel { animation: aToi 1.1s ease-in-out infinite; }
@keyframes aToi { 0%, 100% { box-shadow: var(--shadow), 0 0 0 0 rgba(245,184,0,.75); } 50% { box-shadow: var(--shadow), 0 0 0 8px rgba(245,184,0,0); } }
@media (prefers-reduced-motion: reduce) { #game.a-toi .act-panel, .tiroir-onglet.a-toi { animation: none; } }

/* ── Outils de test (comptes à accès total, 31/10/2026) ───────────────── */
.outils-panel { position: relative; width: min(560px, 94vw); max-height: 82vh; overflow: auto; }
.outils-panel .ot-etat { font-size: 13px; margin: 6px 0 10px; }
.outils-panel .ot-titre { font-family: var(--mono, monospace); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; margin: 12px 0 6px; }
.outils-panel .ot-note { font-size: 12px; opacity: .75; text-transform: none; letter-spacing: 0; margin: 4px 0 0; }
.outils-panel .ot-ligne { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.outils-panel select { flex: 1; min-width: 0; padding: 6px; font: inherit; border: 2px solid var(--ink, #111); border-radius: 6px; background: #fff; }
.outils-panel .mini { padding: 6px 10px; font-size: 12px; border: 2px solid var(--ink, #111); border-radius: 6px; background: #fff; cursor: pointer; text-decoration: none; color: inherit; }
.outils-panel .mini.on { background: var(--ink, #111); color: #fff; }
#btn-outils-test { font-size: 11px; letter-spacing: .06em; }
.outil-bandeau { position: fixed; left: 50%; bottom: max(12px, env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 210; display: flex; gap: 10px; align-items: center;
  background: #111; color: #fff; padding: 8px 12px; border-radius: 10px; font-size: 13px; max-width: calc(100vw - 32px); }
.outil-bandeau[hidden], .outil-bandeau.hidden { display: none; }
.outil-bandeau .mini { padding: 4px 10px; font-size: 12px; border: 2px solid #fff; border-radius: 6px; background: transparent; color: #fff; cursor: pointer; }
