/* Polices intégrées à l'appli (licence OFL, voir fonts/) : le jeu fonctionne sans connexion */
@font-face{font-family:"Space Grotesk"; src:url("../fonts/SpaceGrotesk-Variable.ttf") format("truetype"); font-weight:300 700; font-display:swap}
@font-face{font-family:"Space Mono"; src:url("../fonts/SpaceMono-Regular.ttf") format("truetype"); font-weight:400; font-display:swap}
@font-face{font-family:"Space Mono"; src:url("../fonts/SpaceMono-Bold.ttf") format("truetype"); font-weight:700; font-display:swap}

:root{
  color-scheme:dark;
  --bg:#0b0f1a; --surface:#151b28; --cell:#262d3b; --cell-hl:#3b4559; --line:#2b3344;
  --ink:#eef1f7; --muted:#8a93a6;
  --p1:#e3dc8b; --p1-dark:#cbc374; --p2:#e0808f; --p2-dark:#c96b7a;
  --d1:#eef1f7; --d2:#9fb4d6; --d1-dark:#c5cbd8; --d2-dark:#7d94bb; --ok:#8fcab5; --bad:#ff6b6b; --gold:#b9a6f0;
  --tok-re:#a9c9f2; --tok-down:#8fcab5; --medal:#f2c76e;
  --mono:"Space Mono", ui-monospace, monospace;
  --key-h:2.625rem; --act-h:2.875rem; --die:3rem;
  /* espacements du jeu : joueurs/grille, grille/dés, dés/message, message/pavé (agrandis sur les écrans hauts, voir layout) */
  --g1:0.5rem; --g2:0.5rem; --g3:0.375rem; --g4:0.375rem;
  box-sizing:border-box;
}
*,*::before,*::after{box-sizing:inherit}
/* Taille de base de toute l'interface (tout est en rem) : agrandie sur tablette par applyScale (disposition.js) */
html{font-size:16px}
html,body{height:100%}
body{
  margin:0; background:var(--bg); color:var(--ink); overflow:hidden;
  font-family:"Space Grotesk", system-ui, sans-serif; font-size:1rem; line-height:1.4;
  -webkit-font-smoothing:antialiased;
}
.wrap{
  height:100vh; height:100dvh; overflow:auto;
  display:flex; align-items:flex-start; justify-content:center;
  padding:max(0.625rem, env(safe-area-inset-top)) 0.75rem max(0.625rem, env(safe-area-inset-bottom));
}
/* Centré en hauteur quand il y a la place ; plus haut que l'écran, le contenu commence en haut et se fait défiler.
   (Avec align-items:center, il débordait aussi par le haut, sans pouvoir y revenir : le logo était coupé sur un iPhone SE
   quand la carte Duel s'agrandissait pour le joueur 2 ; vu par Quentin le 16 octobre 2026.) */
.wrap > *{margin-top:auto; margin-bottom:auto}
button{
  font-family:inherit; font-size:1rem; font-weight:600; color:var(--ink);
  background:var(--surface); border:1px solid var(--line); border-radius:0.875rem;
  padding:0.75rem 1rem; cursor:pointer; touch-action:manipulation;
  transition:background .15s, transform .1s, opacity .15s;
}
button:active:not(:disabled){transform:scale(.97)}
button:focus-visible{outline:2px solid var(--ink); outline-offset:2px}
button:disabled{opacity:.28; cursor:default}
button.main{background:var(--ink); color:var(--bg); border-color:var(--ink)}

/* Accueil : titre + une carte à la fois (Qui joue ?, éditeur de profil, réglages) */
#home{width:100%; max-width:32.5rem}
/* Le cadre est porté par le conteneur des cartes : il reste en place quand les cartes glissent à l'intérieur */
#cards{position:relative; background:var(--surface); border-radius:1.25rem; border:1px solid var(--line)}
.setup-card{padding:1.25rem}
/* Titre : le logo dessiné par Quentin (img/logo-brique-a-brique.svg, 16 octobre 2026), inséré dans la page (index.html),
   son cadre resserré au plus juste. Il fait exactement la largeur du contenu du menu : ses bords s'alignent sur ceux du
   bouton « Commencer la partie » (marge intérieure des cartes, 1,25 rem, plus leur bordure de 1 px).
   À l'ouverture, les lettres sont là tout de suite (plus de fondu : Quentin, 16 octobre 2026), la brique jaune arrive
   par le haut, puis la rose par le bas. */
.title{margin:0 0 0.5rem; padding:0 calc(1.25rem + 1px); line-height:0}
.title .logo{display:block; width:100%; height:auto; overflow:visible}
/* Écrans très bas (iPhone SE avec les barres du navigateur…) : le logo est réduit à 12 % de la hauteur de l'écran, centré,
   et plus serré contre le menu ; il n'est alors plus aligné sur le bouton, mais le menu tient sans défiler
   (choix de Quentin, 16 octobre 2026 : 14 % laissait encore un petit défilement sur son iPhone SE) */
@media (max-height: 700px){
  .title{margin-bottom:0.25rem}
  .title .logo{width:auto; max-width:100%; height:12vh; height:12dvh; margin:0 auto}
}
.title .lg-brick{transform-box:fill-box; transform-origin:center}
.title .lg-y{animation:brickFromTop .75s cubic-bezier(.3,1.45,.5,1) .2s both}
.title .lg-p{animation:brickFromBottom .75s cubic-bezier(.3,1.45,.5,1) .45s both}
@keyframes brickFromTop{0%{opacity:0; transform:translateY(-160px) rotate(-10deg)} 50%{opacity:1} 100%{opacity:1; transform:none}}
@keyframes brickFromBottom{0%{opacity:0; transform:translateY(160px) rotate(10deg)} 50%{opacity:1} 100%{opacity:1; transform:none}}
.setup-card h2{font-family:var(--mono); font-size:.8rem; font-weight:400; text-transform:uppercase; letter-spacing:.1em; color:var(--muted); margin:0 0 0.625rem}
/* « Contre qui ? » : deux briques (13 octobre 2026). Le bouton porte le relief (tranche en bas, ombre, hauteur) ;
   ses deux faces complètes (grise et jaune) portent les couleurs, et seule la jaune apparaît ou disparaît en fondu :
   la brique change de couleur d'un bloc (fond, plots, image et texte ensemble). */
.choice{display:grid; grid-template-columns:1fr 1fr; gap:0.625rem; margin-bottom:1.5rem}
/* La brique choisie est enfoncée (à plat, tranche fine) ; l'autre est en relief (tranche épaisse, ombre), prête à être touchée */
.brick-opt{position:relative; min-height:6.4rem; padding:0; border:0; border-radius:0.75rem; text-align:left;
  background:#20283a; transform:translateY(-1px); box-shadow:0 0.625rem 1.125rem rgba(0,0,0,.45);
  transition:transform .3s cubic-bezier(.3,1.5,.5,1), box-shadow .3s, background-color .3s}
.brick-opt[aria-pressed="true"]{background:color-mix(in srgb, var(--p1-dark) 72%, #000); transform:translateY(3px); box-shadow:0 0 0 rgba(0,0,0,0)}
.brick-opt:active{transform:translateY(4px)}
.brick-opt .face{--c:#2c3445; --d:#232a38; position:absolute; left:0; right:0; top:0; bottom:7px; border-radius:0.75rem; padding:0.625rem;
  background:radial-gradient(circle at center, var(--d) 0 27%, transparent 29%) 0 0 / 1.6rem 1.6rem, var(--c);
  display:flex; flex-direction:column; justify-content:space-between; transition:bottom .3s cubic-bezier(.3,1.5,.5,1)}
.brick-opt[aria-pressed="true"] .face{bottom:3px}
.brick-opt .face.gold{--c:var(--p1); --d:var(--p1-dark); opacity:0; transition:opacity .3s, bottom .3s cubic-bezier(.3,1.5,.5,1)}
.brick-opt[aria-pressed="true"] .face.gold{opacity:1}
.brick-opt .ico{width:2.4rem; height:2.4rem; border-radius:50%; overflow:hidden; box-shadow:0 0 0 3px var(--c); background:#2f3747}
.brick-opt .ico svg{display:block; width:100%; height:100%}
.brick-opt .lbl{align-self:flex-start; background:var(--c); border-radius:0.375rem; padding:0.125rem 0.375rem 0.1875rem; line-height:1.2}
.brick-opt .lbl b{display:block; font-size:1rem; color:var(--ink)}
.brick-opt .lbl small{display:block; font-size:.75rem; font-weight:500; color:var(--muted)}
.brick-opt .gold .lbl b{color:#161b27}
.brick-opt .gold .lbl small{color:color-mix(in srgb, var(--p1-dark) 45%, #000)}
.names{display:grid; grid-template-rows:0fr; opacity:0; margin-bottom:0;
  transition:grid-template-rows .8s cubic-bezier(.2,.8,.2,1), opacity .6s ease, margin-bottom .8s cubic-bezier(.2,.8,.2,1)}
.names.open{grid-template-rows:1fr; opacity:1; margin-bottom:1.375rem}
.names-in{overflow:hidden; min-height:0; padding:2px}
.nf{display:flex; align-items:center; gap:0.5rem; background:var(--cell); border-radius:0.875rem; padding:0 0.75rem; border:2px solid transparent}
.nf:focus-within{border-color:var(--c)}
.nf input{width:100%; min-width:0; background:none; border:none; outline:none; color:var(--ink); font:600 1rem "Space Grotesk",system-ui,sans-serif; padding:0.8125rem 0}
.nf input::placeholder{color:var(--muted); font-weight:500}

/* Avatars : la taille se règle avec --av */
.av{display:block; width:var(--av, 2.5rem); height:var(--av, 2.5rem); border-radius:50%; flex:none}
.av svg{display:block; width:100%; height:100%}

/* Qui joue ? */
.who-grid{display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:0.625rem; margin-bottom:1rem}
.who-tile{position:relative; display:grid; justify-items:center; gap:0.5rem; padding:0.875rem 0.375rem 0.625rem; background:var(--cell); border-color:transparent; --av:4rem; min-width:0}
.who-tile .nm{max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.who-tile .plus{width:4rem; height:4rem; border-radius:50%; border:2px dashed var(--muted); display:grid; place-items:center; font-size:2rem; font-weight:400; color:var(--muted)}
.who-tile.add .nm{color:var(--muted)}
.who-tile .edit-badge{position:absolute; top:0.375rem; right:0.375rem; width:1.5rem; height:1.5rem; border-radius:50%; background:var(--ink); color:var(--bg); display:none; place-items:center}
#who.managing .who-tile .edit-badge{display:grid}
#who.managing .who-tile.add{display:none}
.manage{width:100%}

/* Éditeur de profil */
#editor .nf{margin-bottom:1.375rem}
.avatar-grid{display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:0.625rem; margin-bottom:1.375rem}
.avatar-grid button{padding:0.25rem; border:0.1875rem solid transparent; border-radius:50%; background:none; --av:100%}
.avatar-grid button .av{aspect-ratio:1; height:auto}
.avatar-grid button[aria-pressed="true"]{border-color:var(--p1)}
.editor-btns{display:grid; grid-template-columns:1fr 1.4fr; gap:0.5rem}
.editor-btns.solo{grid-template-columns:1fr}
.danger-link{display:block; margin:0.75rem auto 0; padding:0.5rem 0.875rem; background:none; border:none; border-radius:0.625rem; color:var(--bad); font-size:.9rem}
.danger-link.confirm{background:var(--bad); color:#2a0b0b}

/* Réglages : joueur actuel en haut, choix du joueur 2 en mode à deux */
.me{display:flex; align-items:center; gap:0.75rem; margin-bottom:0.75rem; --av:2.75rem}
.me-name{flex:1; min-width:0; font-size:1.15rem; font-weight:700; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.me-change{padding:0.5rem 0.875rem; font-size:.9rem; background:var(--cell); border-color:transparent}
/* Trophées et boutique du joueur, sous son prénom */
.me-links{display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; margin-bottom:1.25rem}
.me-link{display:flex; align-items:center; gap:0.5rem; padding:0.625rem 0.75rem; background:var(--cell); border-color:transparent; font-size:.92rem}
.me-link .cup, .me-link .coin{flex:none; width:1.25rem; height:1.25rem; color:var(--medal)}
.me-link .cup .b{fill:currentColor}
.me-link b{margin-left:auto; font-family:var(--mono); color:var(--medal)}
.coin{display:inline-block; flex:none}
.coin svg{display:block; width:100%; height:100%}
/* Les puces du joueur 2 tiennent sur une seule ligne qu'on fait glisser : le menu ne grandit jamais en hauteur.
   Un fondu à droite (.more) signale qu'il reste des puces cachées. */
.opp-grid{display:flex; gap:0.5rem; overflow-x:auto; overscroll-behavior-x:contain; scrollbar-width:none; padding:0.25rem; margin:-0.25rem}
.opp-grid::-webkit-scrollbar{display:none}
.opp-grid.more{-webkit-mask-image:linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); mask-image:linear-gradient(to right, #000 calc(100% - 2.5rem), transparent)}
.opp{flex:none; white-space:nowrap; display:flex; align-items:center; gap:0.5rem; padding:0.3125rem 0.875rem 0.3125rem 0.3125rem; background:var(--cell); border-color:transparent; border-radius:62.4375rem; --av:1.875rem}
.opp[aria-pressed="true"]{background:var(--ink); color:var(--bg)}
/* Puce de l'invité : « Invité » s'efface et la puce s'allonge pour laisser taper le prénom */
.opp.guest{gap:0; font-size:1rem; font-weight:600; color:var(--ink); border:1px solid transparent; cursor:pointer; transition:background .15s, border-color .15s}
.opp.guest .av{margin-right:0.5rem}
.opp.guest .lbl{max-width:5em; overflow:hidden; white-space:nowrap; transition:max-width .45s cubic-bezier(.2,.8,.2,1), opacity .25s}
.opp.guest input{width:0; min-width:0; padding:0; border:none; outline:none; background:none; color:inherit; font:inherit; transition:width .45s cubic-bezier(.2,.8,.2,1)}
.opp.guest input::placeholder{color:inherit; opacity:.5; font-weight:500}
.opp.guest.on{background:var(--ink); color:var(--bg)}
.opp.guest.open .lbl{max-width:0; opacity:0}
.opp.guest.open input{width:8.5em}
.opp.guest:focus-within{border-color:var(--p2)}

/* ===== Jeu : trois zones empilées (joueurs, plateau, commandes) ===== */
#game{display:grid; grid-template-columns:minmax(0,1fr); align-items:center; justify-items:center; width:100%; max-width:35rem}
#game .board-wrap{margin:var(--g1) 0 var(--g2)}

/* Joueurs */
.players{display:grid; width:100%; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:0.375rem}
/* Tuile sur deux lignes : avatar + prénom en haut, compteur « bloqué » + score en bas (tient sur les écrans étroits) */
/* Le fond et le contour sont dessinés par .pshape (voir shapeCards) : la tuile est découpée autour du bouton d'aide. */
.pcard{
  position:relative; isolation:isolate; min-width:0;
  padding:0.5625rem 0.6875rem; display:grid; grid-template-columns:auto minmax(0,1fr) auto; grid-template-areas:"av name name" "bl bl sc";
  align-items:center; gap:0.25rem 0.5rem;
}
.pshape{position:absolute; inset:0; width:100%; height:100%; z-index:-1; overflow:visible; pointer-events:none}
.pshape path{fill:var(--surface); stroke:var(--line); stroke-width:1; transition:stroke .2s}
.pcard.mirror .pshape{transform:scaleX(-1)}
.pcard.active .pshape path{stroke:var(--ink); stroke-width:2}
.pcard .av{grid-area:av; --av:2.25rem; box-shadow:0 0 0 2px var(--c)}
.pcard .name{grid-area:name; min-width:0; font-size:.95rem; font-weight:700; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.pcard .bl{grid-area:bl; align-self:end; padding-bottom:0.1875rem; font-family:var(--mono); font-size:.7rem; color:var(--muted); white-space:nowrap; line-height:1.2; transition:color .3s}
.pcard .bl.warn{color:var(--bad)}
.pcard .sc{grid-area:sc; position:relative; font-family:var(--mono); font-size:1.7rem; font-weight:700; line-height:1.05; color:var(--ink); white-space:nowrap}
/* Nombre qui défile (scores de la partie, points de la boutique : voir countTo dans outils.js) */
.count{position:relative}
.count .flash{position:absolute; right:100%; top:2px; margin-right:0.375rem; font-size:.95rem; font-weight:700; color:var(--ok);
  pointer-events:none; white-space:nowrap; animation:flashUp 1.4s ease-out forwards}
.count .flash.down{color:var(--bad)}
.count .num{display:inline-block; transition:color .3s}
.count.up .num{color:var(--ok); animation:pop .45s ease-out}
.count.down .num{color:var(--bad); animation:shake .45s ease-out}
@keyframes pop{40%{transform:scale(1.18)}}
@keyframes shake{20%{transform:translateX(-0.1875rem)} 45%{transform:translateX(0.1875rem)} 70%{transform:translateX(-2px)}}
@keyframes flashUp{0%{opacity:0; transform:translateY(0.375rem)} 20%{opacity:1; transform:translateY(0)} 75%{opacity:1} 100%{opacity:0; transform:translateY(-0.625rem)}}
/* Tuile du joueur 2 en miroir : chacun sa moitié d'écran, les deux scores côte à côte au centre */
.pcard.mirror{grid-template-columns:auto minmax(0,1fr) auto; grid-template-areas:"name name av" "sc bl bl"}
.pcard.mirror .name{text-align:right}
.pcard.mirror .bl{text-align:right}
.pcard.mirror .flash{right:auto; left:100%; margin:0 0 0 0.375rem}
/* Les prénoms s'arrêtent avant l'encoche des boutons du milieu (quitter, aide) ; valeur exacte posée par shapeCards */
.pcard .name{padding-right:1.875rem}
.pcard.mirror .name{padding:0 0 0 1.875rem}

/* Au milieu, en haut, entre les deux tuiles : quitter la partie, et l'aide « ? » (les mêmes règles que « Comment jouer ? ») */
.players-top{position:relative; width:100%}
.top-btns{position:absolute; top:0; left:50%; transform:translateX(-50%); display:flex; gap:0.25rem}
.help-btn, .quit-btn{width:1.875rem; height:1.875rem; padding:0; border-radius:0.5rem; display:grid; place-items:center; -webkit-tap-highlight-color:transparent}
.help-btn{background:var(--ok); border:2px solid var(--ok); color:#10261e; font-family:var(--mono); font-weight:700; font-size:.95rem}
.quit-btn{background:var(--cell); border:2px solid var(--cell); color:var(--ink)}
.quit-btn svg{width:1.125rem; height:1.125rem}
.help-btn:active:not(:disabled), .quit-btn:active:not(:disabled){transform:scale(.94)}

/* Plateau */
.board-wrap{position:relative; background:var(--surface); border-radius:1.125rem; padding:0.5rem; border:1px solid var(--line)}
/* Vol, recouvrement, fusion (coups.js) : une vraie petite brique en 3D posée sur le plateau pendant son saut, avec son ombre */
.cover-stage{position:absolute; z-index:1; pointer-events:none}
.cover-shadow{position:absolute; background:rgba(0,0,0,.6); border-radius:0.5rem; filter:blur(6px); opacity:0}
.cover-cube{position:absolute; transform-style:preserve-3d}
.cover-cube > *{position:absolute; left:0; top:0}
.cover-face{backface-visibility:hidden; -webkit-backface-visibility:hidden}
/* Tampon « Volé ! » qui s'écrase sur la brique à l'atterrissage, et petit choc du plateau */
.stamp{position:absolute; z-index:2; pointer-events:none; opacity:0; white-space:nowrap;
  font-family:var(--mono); font-weight:700; letter-spacing:.02em; color:var(--c);
  border:0.1875rem solid var(--c); border-radius:0.625rem; padding:.08em .45em; background:rgba(11,15,26,.85);
  box-shadow:0 0.375rem 1.125rem rgba(0,0,0,.45);
  transform:translate(-50%,-50%) rotate(-10deg); animation:stamp 1.4s cubic-bezier(.2,.8,.2,1) forwards}
@keyframes stamp{
  0%{opacity:0; transform:translate(-50%,-50%) rotate(-10deg) scale(2.4)}
  18%{opacity:1; transform:translate(-50%,-50%) rotate(-10deg) scale(.9)}
  28%{transform:translate(-50%,-50%) rotate(-10deg) scale(1.05)}
  38%,80%{opacity:1; transform:translate(-50%,-50%) rotate(-10deg) scale(1)}
  100%{opacity:0; transform:translate(-50%,-50%) rotate(-10deg) scale(1)}}
.board-wrap.thud{animation:thud .3s ease-out}
@keyframes thud{30%{transform:translateY(0.1875rem) scale(.995)} 65%{transform:translateY(-1px)}}
canvas{display:block; width:100%; aspect-ratio:1; touch-action:manipulation}

/* Panneau de commande */
.panel{display:flex; flex-direction:column; gap:0.375rem; width:100%; min-width:0}
.panel #msg{margin:calc(var(--g3) - 0.375rem) 0 calc(var(--g4) - 0.375rem)}
.eq{display:flex; align-items:center; justify-content:center; gap:0.625rem; position:relative}
/* Les dés en relief (16 octobre 2026, maquette _maquettes/des.html, version B choisie par Quentin) : comme les briques,
   une tranche plus foncée en bas (--cd), un reflet en haut à gauche et une ombre. Le chiffre est sur la face (.face),
   au-dessus de la tranche ; la face est coupée pour que les chiffres du lancer glissent dedans (voir rollAnim). */
.die{
  --c:var(--d1); --cd:var(--d1-dark); --edge:0.3125rem;
  /* coins moins arrondis qu'avant (0,875 rem), pour ressembler davantage à un dé (Quentin, 16 octobre 2026) */
  width:var(--die); height:var(--die); border-radius:0.5rem; display:grid; place-items:center; flex:none;
  font-family:var(--mono); font-size:calc(var(--die) * .57); font-weight:700; color:#151b28; border:none; padding:0 0 var(--edge); position:relative;
  background:radial-gradient(120% 90% at 30% 20%, rgba(255,255,255,.55), transparent 55%), var(--c);
  box-shadow:inset 0 calc(-1 * var(--edge)) 0 var(--cd), 0 0.375rem 0.625rem rgba(0,0,0,.45);
}
.die.d1{--c:var(--d1); --cd:var(--d1-dark)} .die.d2{--c:var(--d2); --cd:var(--d2-dark)}
.die .face{position:absolute; left:0; right:0; top:0; bottom:var(--edge); overflow:hidden; border-radius:0.5rem 0.5rem 0.375rem 0.375rem}
.die .num{position:absolute; inset:0; display:grid; place-items:center; line-height:1; text-shadow:0 1px 0 rgba(255,255,255,.5)}
/* à toi de lancer : les dés battent doucement (plus d'anneau blanc : invisible sur le dé blanc, il faisait un contour
   au seul dé bleu ; retiré à la demande de Quentin le 16 octobre 2026) */
.die.ready{animation:pulse 1s ease-in-out infinite}
@keyframes pulse{50%{transform:scale(1.07)}}
.die.pick{animation:wob .5s ease-in-out infinite alternate; outline:2px dashed var(--ink); outline-offset:0.25rem}
@keyframes wob{from{transform:rotate(-6deg)} to{transform:rotate(6deg)}}
.op{font-family:var(--mono); font-size:1.4rem; color:var(--muted)}
.ans{
  min-width:calc(var(--die) * 1.92); height:var(--die); padding:0 0.75rem; border-radius:0.875rem; background:var(--cell);
  display:flex; align-items:center; justify-content:center; gap:0.375rem;
  font-family:var(--mono); font-size:calc(var(--die) * .57); font-weight:700; color:var(--muted);
  border:2px solid transparent; transition:background .2s, border-color .2s;
}
.ans.active{border-color:var(--ink); color:var(--ink)}
.ans.ok{background:var(--ok); color:#10261e}
.ans.ko{background:var(--bad); color:#2a0b0b}
.ans.ai{color:var(--ink)}
.ans svg{width:1.375rem; height:1.375rem; flex:none}
.ans-txt{display:flex; align-items:center; justify-content:center; gap:0.375rem}

/* Le joker (15 octobre 2026, maquette _maquettes/echange.html) : face dorée sur un double joker ; pendant le roulement,
   la face joker garde la couleur du dé */
.die svg{width:62%; height:62%}
.die.joker{--c:var(--medal); --cd:#c99a3e; color:#2a1f05; animation:jokerHit .45s cubic-bezier(.3,1.6,.5,1);
  box-shadow:inset 0 calc(-1 * var(--edge)) 0 var(--cd), 0 0 0 0.1875rem var(--medal), 0 0 1.375rem var(--medal)}
@keyframes jokerHit{40%{transform:scale(1.25) rotate(-8deg)}}
/* Jeton « échange » gardé par un joueur : pastille dorée au coin extérieur haut de sa tuile (l'adversaire la voit) */
.tok-swap{position:absolute; top:-0.5625rem; left:-0.375rem; width:1.625rem; height:1.625rem; border-radius:50%; background:var(--medal); color:#2a1f05;
  display:grid; place-items:center; box-shadow:0 2px 8px rgba(0,0,0,.5); opacity:0; transform:scale(.3); pointer-events:none;
  transition:opacity .35s, transform .45s cubic-bezier(.3,1.6,.5,1); z-index:1}
.pcard.mirror .tok-swap{left:auto; right:-0.375rem}
.tok-swap svg{width:1rem; height:1rem}
.tok-swap b{position:absolute; bottom:-0.375rem; right:-0.375rem; font-family:var(--mono); font-size:.7rem; background:var(--bg); color:var(--medal); border-radius:0.5rem; padding:0 0.25rem; line-height:1.2}
.tok-swap b:empty{display:none}
.tok-swap.on{opacity:1; transform:scale(1)}
/* Interrupteur « échange » DANS la case de la réponse (idée de Quentin) : un bouton doré à droite de la case, qu'il faut
   POUSSER du doigt vers la gauche (un simple toucher ne suffit pas : pas d'échange par erreur). La case se teinte de doré
   à mesure ; lâché avant le bout, il revient à droite. La case garde sa taille : rien ne bouge sur la ligne.
   --x : position du bouton (0 à droite, négatif vers la gauche) ; --p : avancement (0 à 1), posés par commandes.js */
.ans{position:relative; overflow:hidden; --x:0px; --p:0; --k:calc(var(--die) - 0.5rem)}
/* à mesure qu'on pousse, la case se remplit du blanc du premier dé (plutôt que de doré : Quentin, 16 octobre 2026) */
.ans-fill{position:absolute; inset:0; background:var(--d1); opacity:var(--p); transition:opacity .3s; pointer-events:none}
.ans-txt{position:relative; opacity:calc(1 - var(--p)); transition:opacity .25s, transform .3s}
.swap-knob{position:absolute; right:2px; top:50%; width:var(--k); height:var(--k); padding:0; border:none; border-radius:0.6875rem;
  background:var(--medal); color:#2a1f05; display:grid; place-items:center; z-index:1; touch-action:none;
  transform:translate(var(--x), -50%) scale(.4); pointer-events:none}
/* caché pour de bon sans le jeton : la règle générale button:disabled (opacité 0,28) ne doit pas le faire réapparaître
   en transparence (vu par Quentin le 15 octobre 2026) ; visibility le retire tout à fait une fois le fondu fini */
.ans .swap-knob, .ans .swap-knob:disabled{opacity:0; visibility:hidden;
  transition:opacity .3s, visibility 0s linear .3s, transform .35s cubic-bezier(.3,1.4,.5,1), box-shadow .3s}
.swap-knob:active:not(:disabled){transform:translate(var(--x), -50%)}
.swap-knob svg{width:62%; height:62%}
.ans.has-swap .ans-txt{transform:translateX(calc(-1 * var(--k) / 2))}
.ans.has-swap .swap-knob{opacity:1; visibility:visible; transform:translate(var(--x), -50%) scale(1); pointer-events:auto; animation:knob 1.2s ease-in-out .4s infinite;
  transition:opacity .3s, visibility 0s, transform .35s cubic-bezier(.3,1.4,.5,1), box-shadow .3s}
.ans.go .swap-knob:disabled{opacity:1}
@keyframes knob{50%{box-shadow:0 0 0.875rem var(--medal)}}
.ans.dragging .swap-knob{transition:none; animation:none; box-shadow:0 0 1rem var(--medal)}
.ans.dragging .ans-txt, .ans.dragging .ans-fill{transition:none}
/* toucher sans pousser : petit coup vers la gauche pour montrer le geste */
.ans.hint .swap-knob{animation:knobHint .6s ease-in-out}
@keyframes knobHint{30%{transform:translate(calc(var(--x) - 0.875rem), -50%)} 60%{transform:translate(calc(var(--x) + 3px), -50%)}}
/* activé : il reste au bout, à gauche, pendant toute l'animation ; il disparaît avec le tour suivant */
.ans.go .swap-knob{animation:none; pointer-events:none}
.ans.go{--p:1}
/* Tour du plateau au début de l'échange (echange.js) : une toile sur tout le cadre du plateau */
.swap-trace{position:absolute; left:0; top:0; pointer-events:none; z-index:3}
/* Reflet de l'échange : deux bandes claires penchées qui traversent le plateau (voir sheen dans echange.js) */
.swap-sheen{position:absolute; overflow:hidden; border-radius:0.625rem; pointer-events:none; z-index:3}
.swap-sheen > div{position:absolute; left:0}
/* Message sur une seule ligne, de hauteur fixe : un message trop long est écrit plus petit (voir fitMsg), jamais sur deux lignes */
#msg{margin:0; height:calc(.85rem * 1.35); line-height:calc(.85rem * 1.35); white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  font-size:.85rem; text-align:center; color:#cfd5e2}

.keypad{display:grid; grid-template-columns:repeat(6, 1fr); gap:0.375rem}
.keypad button{height:var(--key-h); padding:0; font-family:var(--mono); font-size:1.3rem; background:var(--cell); border-color:transparent}
.keypad button.ok{background:var(--ok); color:#10261e; font-size:1.05rem}
.keypad button.v-fit{background:var(--ok); color:#10261e}
.keypad button.v-steal{background:var(--gold); color:#1f1638}

/* Pavé et boutons du bas superposés dans la même case : un seul des deux est visible (.panel.acting : les boutons).
   La zone garde toujours la hauteur du pavé, pour que rien ne bouge ; les boutons, centrés, font 1,5 fois une touche. */
.controls{display:grid}
.controls > *{grid-area:1 / 1}
.panel.acting .keypad, .panel:not(.acting) .actions{visibility:hidden}
.actions{display:grid; grid-template-columns:var(--tok-w) var(--tok-w) 1fr var(--tok-w); gap:0.375rem; --tok-w:calc(var(--act-h) * 1.35);
  align-self:center; height:calc(var(--key-h) * 1.5)}
/* placement (Poser, Tourner) en blanc, séparé des jetons par un petit espace */
#aPlace{margin-left:0.625rem; font-size:1.15rem}
.actions.no-tokens{grid-template-columns:1fr var(--tok-w)}
.actions.no-tokens #aPlace{margin-left:0}
#aRot{background:var(--ink); border-color:var(--ink); color:var(--bg)}
.actions button{height:100%; padding:0; display:grid; place-items:center; position:relative}
.actions button svg{width:1.75rem; height:1.75rem}
.actions button.on{background:var(--ink); color:var(--bg)}
.actions button.tint{background:var(--tint); border-color:var(--tint); color:#161b27}
.actions button.tint.on{box-shadow:0 0 0 0.1875rem var(--ink)}
.actions button.tint .badge{background:#161b27; color:var(--tint)}
.actions .badge{position:absolute; top:-0.375rem; right:-0.375rem; min-width:1.25rem; height:1.25rem; border-radius:0.625rem; background:var(--ink); color:var(--bg); font-family:var(--mono); font-size:.72rem; font-weight:700; display:grid; place-items:center; padding:0 0.25rem}
.actions button.on .badge{background:var(--bg); color:var(--ink); box-shadow:0 0 0 1px var(--ink)}
.actions button:disabled .badge{opacity:.8}

/* Appareil tenu couché : on demande de le remettre debout */
#rotateHint{position:fixed; inset:0; z-index:20; display:none; place-items:center; align-content:center; gap:1rem;
  background:var(--bg); color:var(--ink); text-align:center; padding:1.5rem}
#rotateHint p{margin:0; font-size:1.15rem; font-weight:700}
#rotateHint svg{color:var(--p1); animation:tilt 2.4s ease-in-out infinite}
@keyframes tilt{0%,25%{transform:rotate(-90deg)} 55%,100%{transform:rotate(0deg)}}
body.rotate #rotateHint{display:grid}

/* ===== Règles du jeu ===== */
.rules-link{background:none; border-color:var(--line); color:var(--ink); padding:0.75rem 0.875rem; font-size:.95rem}
.wide{display:block; width:100%}
/* Bas du menu : « Comment jouer ? », puis les boutons Sons et Vibrations (barrés et estompés quand ils sont coupés) */
.home-foot{display:flex; gap:0.5rem}
.home-foot #rulesBtn{flex:1}
.home-foot .toggle{flex:none; width:3rem; padding:0; display:grid; place-items:center; transition:color .25s, opacity .25s}
.home-foot .toggle svg{width:1.4rem; height:1.4rem}
.home-foot .toggle[aria-pressed="false"]{color:var(--muted); opacity:.75}
.home-foot .toggle .on, .home-foot .toggle .off{transition:opacity .25s}
.home-foot .toggle[aria-pressed="true"] .off, .home-foot .toggle[aria-pressed="false"] .on{opacity:0}

/* Menu du joueur : deux grandes tuiles, Duel et Défis */
.modes{display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; margin-bottom:0.75rem}
/* contenu aligné en haut : les titres des deux tuiles restent à la même hauteur, même si l'une a deux lignes dessous */
/* Duel et Aventure : deux briques en relief (13 octobre 2026) ; --c : couleur, --d : plots (posés sur le bouton) */
.brick-tile{--e:color-mix(in srgb, var(--d) 72%, #000); position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:0.625rem; min-height:8.25rem; padding:0.875rem 0.5rem; margin-bottom:0.375rem; border:0; border-radius:0.875rem;
  background:radial-gradient(circle at center, var(--d) 0 27%, transparent 29%) 0 0 / 1.6rem 1.6rem, var(--c);
  box-shadow:0 0.375rem 0 var(--e), 0 0.625rem 1.125rem rgba(0,0,0,.4);
  transition:transform .2s cubic-bezier(.3,1.5,.5,1), box-shadow .2s}
.brick-tile:active{transform:translateY(0.3125rem); box-shadow:0 1px 0 var(--e), 0 0.1875rem 0.375rem rgba(0,0,0,.3)}
/* l'image dans un rond sombre, le nom sur une pastille unie (comme le nombre de plots sur les briques du jeu) */
.bt-ico{width:3.4rem; height:3.4rem; border-radius:50%; background:#2f3747; display:grid; place-items:center; box-shadow:0 0 0 3px var(--c)}
.bt-ico svg{width:2.5rem; height:1.7rem}
.bt-lbl{background:var(--c); border-radius:0.4rem; padding:0.125rem 0.5rem 0.1875rem; text-align:center; line-height:1.15; color:#161b27}
.bt-lbl b{display:block; font-size:1.2rem}
.bt-lbl small{display:block; font-weight:600; font-size:.8rem; color:color-mix(in srgb, var(--d) 40%, #000)}
/* Bandeau des défis du jour, sous les deux tuiles ; le compte passe au vert quand les trois sont faits */
.day-link{display:flex; align-items:center; gap:0.5rem; width:100%; padding:0.75rem 0.875rem; margin-bottom:0.75rem; background:var(--cell); border-color:transparent; font-size:.95rem}
.day-link .cup{flex:none; width:1.35rem; height:1.35rem; color:var(--medal)}
.day-link b{margin-left:auto; font-family:var(--mono); color:var(--medal)}
.day-link.all .cup, .day-link.all b{color:var(--ok)}
/* Défis du jour et, à droite, le bouton de la roue de la fortune : il brille tant que la roue est disponible */
.day-row{display:flex; gap:0.5rem; margin-bottom:0.75rem}
.day-row .day-link{flex:1; width:auto; margin-bottom:0}
.wheel-btn{flex:none; position:relative; width:3.1rem; padding:0; border-radius:0.875rem; background:var(--cell); border-color:transparent;
  display:grid; place-items:center; color:var(--medal); transition:color .3s, opacity .3s}
.wheel-btn svg{width:1.6rem; height:1.6rem}
.wheel-btn.ready::after{content:''; position:absolute; inset:-2px; border-radius:1rem; box-shadow:0 0 0 2px var(--medal); animation:wheelGlow 1.6s ease-in-out infinite; pointer-events:none}
.wheel-btn.used{color:var(--muted); opacity:.7}
@keyframes wheelGlow{0%,100%{opacity:.15} 50%{opacity:.9}}

/* Fenêtre de la roue (roue.js) */
.roue-card{text-align:center; padding-bottom:1.25rem}
.roue-sub{margin:0 1.125rem 2.1rem; color:var(--muted); font-size:.9rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.wheel-wrap{position:relative; width:min(78vw, 19rem); aspect-ratio:1; margin:0 auto 1.25rem}
.wheel-wrap canvas{position:relative; width:100%; height:100%; display:block}
/* ombre portée : un rond fixe derrière la roue (une ombre sur la roue elle-même tournerait avec elle) */
.wheel-shadow{position:absolute; inset:3.6%; border-radius:50%; box-shadow:0 0.625rem 1.5rem rgba(0,0,0,.6), 0 0.1875rem 0.375rem rgba(0,0,0,.35)}
.pointer{position:absolute; left:50%; top:-1.25rem; width:1.625rem; height:2.75rem; transform:translateX(-50%); transform-origin:50% 20%; filter:drop-shadow(0 3px 4px rgba(0,0,0,.5))}
.pointer svg{display:block; width:100%; height:100%}
.pointer.flick{animation:flick .12s ease-out}
@keyframes flick{40%{transform:translateX(-50%) rotate(-14deg)}}
/* le rond du centre, posé par-dessus la roue (il ne tourne pas) : il rebondit doucement et un reflet le traverse */
.hub{position:absolute; left:50%; top:50%; width:27%; aspect-ratio:1; padding:0; transform:translate(-50%,-50%); border-radius:50%; overflow:hidden;
  background:var(--medal); color:#2b2110; font-weight:700; font-size:clamp(.75rem, 3.4vw, .95rem); border:4px solid #151b28;
  box-shadow:0 6px 14px rgba(0,0,0,.6), 0 2px 4px rgba(0,0,0,.4); transition:background-color .3s, color .3s}
.hub:disabled{background:var(--cell); color:var(--muted); cursor:default; opacity:1}
.hub:not(:disabled){animation:hubBounce 1.8s ease-in-out infinite}
.hub:not(:disabled):active{animation:none; transform:translate(-50%,-50%) scale(.94)}
@keyframes hubBounce{
  0%, 55%, 100%{transform:translate(-50%,-50%) scale(1)}
  20%{transform:translate(-50%,-50%) scale(1.05)}
  35%{transform:translate(-50%,-50%) scale(.985)}
  45%{transform:translate(-50%,-50%) scale(1.015)}}
.hub::after{content:''; position:absolute; inset:0; border-radius:50%; pointer-events:none; opacity:0;
  background:linear-gradient(115deg, transparent 0 38%, rgba(255,255,255,.6) 38% 47%, transparent 47% 53%, rgba(255,255,255,.4) 53% 57%, transparent 57%);
  background-size:300% 100%; background-repeat:no-repeat}
.hub:not(:disabled)::after{animation:hubShine 2.8s ease-in-out infinite}
@keyframes hubShine{0%{background-position:100% 0; opacity:1} 36%{background-position:0% 0; opacity:1} 37%, 100%{background-position:0% 0; opacity:0}}
.roue-result{height:1.9rem; font-family:var(--mono); font-weight:700; font-size:1.25rem; color:var(--medal); opacity:0; transform:scale(.6);
  transition:opacity .3s, transform .4s cubic-bezier(.3,1.6,.5,1)}
.roue-result.on{opacity:1; transform:none}
@media (prefers-reduced-motion: reduce){ .hub:not(:disabled), .hub:not(:disabled)::after, .wheel-btn.ready::after, .pointer.flick{animation:none} }

/* Terrain du duel : des puces, comme les rayons de la boutique */
/* Terrain du duel : des tuiles d'aperçu (la grille en miniature et le nom), sur une seule ligne qu'on fait glisser
   comme les puces du joueur 2 (le menu ne grandit pas), avec le même fondu à droite ; la choisie a un anneau clair */
.terrain-chips{display:flex; gap:0.5rem; overflow-x:auto; overscroll-behavior-x:contain; scrollbar-width:none; padding:0.25rem; margin:-0.25rem -0.25rem 1.125rem}
.terrain-chips::-webkit-scrollbar{display:none}
.terrain-chips.more{-webkit-mask-image:linear-gradient(to right, #000 calc(100% - 2.5rem), transparent); mask-image:linear-gradient(to right, #000 calc(100% - 2.5rem), transparent)}
.ter{flex:none; position:relative; width:5.2rem; display:flex; flex-direction:column; align-items:center; gap:0.3125rem; padding:0.375rem 0.375rem 0.4375rem;
  border:0; border-radius:0.75rem; background:var(--cell)}
.ter canvas{display:block; width:4.4rem; height:4.4rem; aspect-ratio:auto; border-radius:0.375rem}
.ter span{font-size:.72rem; line-height:1.15; min-height:2.3em; display:flex; align-items:center; text-align:center; color:var(--muted); transition:color .25s}
.ter::after{content:''; position:absolute; inset:0; border-radius:0.75rem; box-shadow:0 0 0 2px var(--ink); opacity:0; transition:opacity .25s; pointer-events:none}
.ter[aria-pressed="true"]::after{opacity:1}
.ter[aria-pressed="true"] span{color:var(--ink)}
/* En-tête des cartes Duel et Défis : retour au menu, titre */
.card-head{display:flex; align-items:center; gap:0.625rem; margin-bottom:1rem}
.back{width:2.5rem; height:2.5rem; padding:0; display:grid; place-items:center; flex:none; background:var(--cell); border-color:transparent}
.back svg{width:1.25rem; height:1.25rem}
.setup-card .card-title{margin:0; font-family:inherit; font-size:1.3rem; font-weight:700; text-transform:none; letter-spacing:0; color:var(--ink)}
#duelCard .main{margin-top:0.25rem}

/* Carte de l'aventure (refaite le 13 octobre 2026 avec Quentin, maquette _maquettes/ruban.html) :
   un fil par monde, un ruban entre deux mondes, des briques de formes variées à la couleur de leur monde, un ciel étoilé.
   --cs : taille d'un plot des briques des niveaux (réglée par carte.js selon la largeur) */
.map-total{margin-left:auto; display:flex; align-items:center; gap:0.375rem; font-family:var(--mono); font-size:1.05rem; color:var(--medal)}
.map-total .star{width:1.25rem; height:1.25rem}
.map-total .star svg{display:block; width:100%; height:100%}
.map-total .star.on{color:var(--medal)}
.map{--cs:1.375rem; position:relative; height:min(34rem, calc(100vh - 14rem)); height:min(34rem, calc(100dvh - 14rem)); min-height:16rem; overflow-x:hidden; overflow-y:auto; overscroll-behavior:contain;
  margin:0 -1.25rem -1.25rem; padding:0.5rem 1.25rem 1.25rem; border-top:1px solid var(--line); scrollbar-width:thin;
  background:radial-gradient(ellipse at 30% 20%, rgba(120,140,220,.10), transparent 60%), radial-gradient(ellipse at 80% 75%, rgba(220,120,170,.08), transparent 55%)}
/* ciel étoilé (choisi par Quentin) : de petites étoiles, certaines scintillent ; derrière tout, et il défile avec la carte */
.map-sky{position:absolute; left:0; top:0; width:100%; z-index:0; pointer-events:none}
.map-sky i{position:absolute; border-radius:50%; background:#fff}
.map-sky i.tw{animation:twinkle 3.2s ease-in-out infinite}
@keyframes twinkle{50%{opacity:.15; transform:scale(.6)}}
/* niveaux : une brique du jeu (dessinée par carte.js), décalée de --dx plots ; --bw × --bh : sa taille en plots */
/* pas de transition (celle des boutons) : une brique qui glisse à sa place arriverait après le tracé du chemin */
.map-lv{display:flex; flex-direction:column; align-items:center; gap:0.25rem; margin:0.375rem auto; padding:0.25rem; background:none; border:none;
  transform:translateX(calc(var(--dx) * var(--cs))); transition:none}
.map-lv:active:not(:disabled){transform:translateX(calc(var(--dx) * var(--cs))) scale(.95)}
.map-lv:disabled{opacity:1}
.map-lv .brick{position:relative; display:block; width:calc(var(--bw) * var(--cs)); height:calc(var(--bh) * var(--cs))}
.map-lv canvas{display:block; width:100%; height:100%}
.map-lv .stars .star{width:0.875rem; height:0.875rem}
/* niveau en cours : il sautille, sans halo (retiré à la demande de Quentin le 13 octobre 2026) */
.map-lv.cur .brick{animation:lvBounce 1.3s ease-in-out infinite}
@keyframes lvBounce{50%{transform:translateY(-0.3rem)}}
.map-fog{display:grid; place-items:center; min-height:5.5rem; margin-bottom:0.5rem; border-radius:1rem; text-align:center; padding:0.75rem;
  background:radial-gradient(ellipse at center, var(--cell-hl), transparent 70%); font-family:var(--mono); font-size:2rem; font-weight:700; color:var(--muted)}
.map-fog.end{font-family:inherit; font-size:1.1rem; color:var(--ink)}
.map-fog small{display:block; font-family:"Space Grotesk", system-ui, sans-serif; font-size:.85rem; font-weight:500; margin-top:0.25rem}
/* Chemin : un trait épais blanc peu opaque, en lacets, un par monde ; la partie parcourue se remplit de la couleur du monde */
.map-path{position:absolute; left:0; top:0; z-index:0; pointer-events:none; overflow:visible}
.map-path path{fill:none; stroke-width:0.875rem; stroke-linecap:round; stroke-linejoin:round}
.map-path .base{stroke:#fff; stroke-opacity:.12}
.map-path .fill{stroke-opacity:.6}
.map-lv, .map-fog{position:relative; z-index:1}
.map-lv .extra{display:contents}
/* L'animal du joueur, posé sur le niveau à jouer (placé par carte.js) ; le cercle a la couleur des briques du joueur */
.map-av{position:absolute; left:0; top:0; width:2.75rem; height:2.75rem; z-index:2; pointer-events:none}
.map-av .face{animation:avBob 1.8s ease-in-out infinite}
.map-av svg{display:block; width:100%; height:100%; border-radius:50%; box-shadow:0 0 0 0.1875rem var(--f), 0 0.25rem 0 0.1875rem rgba(0,0,0,.35)}
@keyframes avBob{50%{transform:translateY(-0.2rem)}}
.map-spark{position:absolute; left:0; top:0; width:0.4rem; height:0.4rem; margin:-0.2rem 0 0 -0.2rem; border-radius:0.1rem; z-index:5; pointer-events:none}

/* Pièces sur le chemin (10 ou 20 points) : elles flottent doucement ; l'animal les ramasse en passant (carte.js) */
.map-coin{position:absolute; z-index:2; width:1.625rem; height:1.625rem; margin:-0.8125rem 0 0 -0.8125rem; pointer-events:none; animation:coinBob 1.6s ease-in-out infinite; perspective:12.5rem}
.map-coin .spin{display:grid; place-items:center; width:100%; height:100%; border-radius:50%;
  background:radial-gradient(circle at 35% 30%, #fff3c4 0 16%, var(--medal) 42%, #d9a441 100%);
  box-shadow:inset 0 0 0 2px #c08a2e, inset 0 0 0 4px rgba(255,255,255,.25), 0 3px 0 #9c6b1c, 0 5px 9px rgba(0,0,0,.45)}
.map-coin b{font:700 0.625rem/1 var(--mono); color:#5a3d0c; letter-spacing:-.03em}
@keyframes coinBob{50%{transform:translateY(-3px)}}
.map-plus{position:absolute; z-index:5; font:700 1rem var(--mono); color:var(--medal); text-shadow:0 2px 0 rgba(0,0,0,.45); pointer-events:none; white-space:nowrap}
@media (prefers-reduced-motion: reduce){ .map-coin{animation:none} }

/* ---------- Ruban d'un monde : entre ses niveaux et ceux du monde d'avant ; il passe DEVANT l'animal, comme le haut d'une porte ---------- */
.map-rib{--c:var(--cell-hl); --d:var(--line); --e:#20283a;
  position:relative; z-index:3; height:5.25rem; margin:1.25rem -1.25rem 1rem; perspective:40rem; pointer-events:none}
.map-rib .tails{position:absolute; inset:0; width:100%; height:100%; overflow:visible}
.map-rib .tails .tl{fill:var(--d)} .map-rib .tails .fd{fill:var(--e)}
.map-rib .bandw{position:absolute; left:10.6%; right:10.6%; top:0.3rem; height:3.7rem; transform-origin:50% 50%}
.map-rib .band{position:absolute; inset:0; width:100%; height:100%; overflow:visible}
.map-rib .band .bd{fill:var(--c)}
/* ruban fermé : cadenas et « ??? » */
.map-rib .txt{position:absolute; inset:0 0 0.25rem; display:flex; align-items:center; justify-content:center; gap:0.625rem}
.map-rib:not(.closed) .txt{display:none}
.map-rib .ico{display:grid; place-items:center; width:2.5rem; height:2.5rem; border-radius:50%; background:rgba(255,255,255,.08); color:var(--muted); flex:none}
.map-rib .ico svg{width:62%; height:62%; overflow:visible}
.map-rib .t{line-height:1.05; color:#c3cad8; white-space:nowrap}
.map-rib .t small{display:block; font-family:var(--mono); font-size:.72rem; letter-spacing:.12em; text-transform:uppercase; opacity:.7}
.map-rib .t b{font-size:1.35rem; letter-spacing:.2em}
/* ruban ouvert : « MONDE n » en petit, le nom en grand en capitales, sur un arc qui suit l'arrondi du ruban (choix A de Quentin) */
.map-rib .title{position:absolute; inset:0; width:100%; height:100%; overflow:visible}
.map-rib .title text{font-family:"Space Grotesk", sans-serif; font-weight:700; fill:#161b27; letter-spacing:.06em}
.map-rib .title .emb{fill:#fff; fill-opacity:.35}
.map-rib .title .sub{font-family:var(--mono); font-weight:700; letter-spacing:.3em; fill-opacity:.62}
/* reflet qui traverse le ruban quand il se dévoile */
.map-rib .gleam{position:absolute; inset:0; overflow:hidden; border-radius:0.25rem; pointer-events:none}
.map-rib .gleam::before{content:""; position:absolute; top:-50%; bottom:-50%; left:-30%; width:22%; transform:skewX(-20deg) translateX(var(--g, -200%));
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent)}
/* nuages d'un monde fermé : derrière le ruban, devant les briques et l'animal ; ils flottent doucement */
.map-rib .clouds{position:absolute; left:0; right:0; bottom:3.4rem; height:0; overflow:visible}
.map-rib .cloud{position:absolute; display:block; animation:drift 7s ease-in-out infinite alternate}
.map-rib .cloud svg{display:block; width:100%; filter:drop-shadow(0 0.25rem 0.5rem rgba(0,0,0,.25))}
@keyframes drift{from{transform:translateX(-0.375rem)} to{transform:translateX(0.375rem)}}

/* ---------- Ouverture d'un niveau : l'animation du vol (comme .cover-stage / .cover-cube du plateau) ---------- */
.map-trace{position:absolute; z-index:4; pointer-events:none; overflow:visible}
.map-stage{position:absolute; left:0; top:0; width:100%; z-index:4; pointer-events:none}
.map-cube{position:absolute; transform-style:preserve-3d}
.map-cube > *{position:absolute; left:0; top:0}
.map-cube canvas{backface-visibility:hidden; -webkit-backface-visibility:hidden}
.map-shadow{position:absolute; border-radius:0.3rem; background:rgba(0,0,0,.55); opacity:0}
.map-part{position:absolute; left:0; top:0; width:calc(var(--cs) * .32); height:calc(var(--cs) * .32); margin:calc(var(--cs) * -.16) 0 0 calc(var(--cs) * -.16); border-radius:50%; z-index:4; pointer-events:none}
@media (prefers-reduced-motion: reduce){ .map-lv.cur .brick, .map-av .face, .map-sky i.tw, .map-rib .cloud{animation:none} }

/* Présentation d'un monde : sa phrase, puis l'explication reprise de « Comment jouer » (sans titre ni numéro) */
.intro-card{width:min(100%, 26rem)}
.intro-tag{margin:0 0 0.125rem; font-family:var(--mono); font-size:.75rem; text-transform:uppercase; letter-spacing:.1em; color:var(--medal)}
.intro-lead{margin:0 0 0.5rem; font-size:1.05rem; font-weight:700; line-height:1.4}
#introBody .rule{border-top:0; padding:0}
#introBody .rule h3{display:none}
.intro-foot{padding:0.25rem 1.125rem 1.125rem}

/* Fenêtre d'un niveau */
.lv-card{width:min(100%, 24rem)}
.lv-body{padding:0 1.125rem 1.125rem}
/* En-tête de la fenêtre d'un niveau : bandeau centré dans la couleur des briques du joueur (--f, posée par openLevel) */
.lv-card{overflow:hidden}
.lv-head{position:relative; padding:0.875rem 3.5rem 0.75rem; margin-bottom:1rem; text-align:center; background:var(--f, var(--p1)); color:#161b27}
.lv-head h2{margin:0; font-size:1.4rem}
.lv-world{margin:0.125rem 0 0; font-family:var(--mono); font-size:.75rem; text-transform:uppercase; letter-spacing:.08em; color:rgba(22,27,39,.7)}
.lv-head .rules-x{position:absolute; top:50%; right:0.75rem; margin-top:-1.25rem; background:rgba(22,27,39,.12); border-color:transparent; color:#161b27}
.lv-goal{margin:0 0 1rem; font-size:1.1rem; font-weight:700; line-height:1.35}
.lv-stars{list-style:none; margin:0 0 1.125rem; padding:0; display:grid; gap:0.375rem}
.lv-stars li{display:flex; align-items:center; gap:0.625rem; padding:0.5rem 0.625rem; background:var(--cell); border-radius:0.75rem; font-size:.9rem; color:#cfd5e2}
.lv-stars li.got{outline:2px solid var(--medal); outline-offset:-2px}

/* Étoiles des défis (allumées ou non) */
.stars{display:inline-flex; gap:0.125rem; vertical-align:middle}
.stars .star{display:block; width:1rem; height:1rem; color:var(--cell-hl)}
.stars .star.on{color:var(--medal)}
.stars .star svg{display:block; width:100%; height:100%}
.stars.big{gap:0.375rem}
.stars.big .star{width:2.25rem; height:2.25rem}

/* Barre du défi en cours, sous les joueurs : l'objectif sur une seule ligne (la grille ne doit pas rapetisser ;
   s'il ne tient pas, il défile, voir scrollGoal dans affichage.js), puis la progression à gauche,
   le tour et les étoiles encore possibles à droite (le tour est ce qui les fait s'éteindre). */
.defi-bar{display:grid; grid-template-columns:minmax(0,1fr) auto auto; grid-template-areas:"goal goal goal" "prog turn stars"; gap:0.125rem 0.5rem;
  align-items:center; margin-top:0.375rem; padding:0.375rem 0.6875rem; background:var(--surface); border:1px solid var(--line); border-radius:0.875rem}
.defi-bar[hidden]{display:none}
.db-goal{grid-area:goal; min-width:0; font-size:.82rem; font-weight:700; white-space:nowrap; overflow:hidden}
.db-goal span{display:inline-block}
.db-goal.cut{text-overflow:ellipsis}
.db-goal.cut span{display:inline}
.db-prog{grid-area:prog; font-family:var(--mono); font-size:.75rem; color:var(--muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.db-turn{grid-area:turn; font-family:var(--mono); font-size:.75rem; color:var(--muted); white-space:nowrap}
.defi-bar .stars{grid-area:stars}
/* colonne bornée à l'écran : une ligne qui ne se coupe pas (rayons de la boutique) défile au lieu d'élargir la fenêtre */
.quit-card{width:min(100%, 20rem); padding:1.25rem 1.125rem 1.125rem; text-align:center}
.quit-card h2{margin:0 0 0.375rem; font-size:1.3rem}
.quit-card p{margin:0 0 1.125rem; color:var(--muted)}
.quit-btns{display:grid; grid-template-columns:1fr 1fr; gap:0.5rem}
.quit-btns .main{grid-column:1 / -1}
.quit-btns button[hidden] + button{grid-column:1 / -1}
#rulesOverlay, #trophyOverlay, #dayOverlay, #roueOverlay, #shopOverlay, #levelOverlay, #introOverlay, #quitOverlay{position:fixed; inset:0; z-index:15; display:grid; grid-template-columns:minmax(0,1fr); place-items:center; padding:0.75rem;
  background:rgba(11,15,26,.55); -webkit-backdrop-filter:blur(0.4375rem); backdrop-filter:blur(0.4375rem); animation:fadeIn .25s ease-out}
.rules-card{width:min(100%, 32.5rem); max-height:min(92vh, 56.25rem); max-height:min(92dvh, 56.25rem); display:flex; flex-direction:column;
  background:var(--surface); border:1px solid var(--line); border-radius:1.375rem; box-shadow:0 1.25rem 3.75rem rgba(0,0,0,.5); animation:popIn .3s ease-out}
.rules-head{display:flex; align-items:center; justify-content:space-between; padding:1rem 1.125rem 0.5rem}
.rules-head h2{margin:0; font-size:1.4rem}
.rules-x{width:2.5rem; height:2.5rem; padding:0; border-radius:0.75rem; font-size:1.5rem; line-height:1}
.rules-body{overflow:auto; padding:0 1.125rem 0.875rem; overscroll-behavior:contain}
.rule{padding:0.875rem 0; border-top:1px solid var(--line)}
.rule:first-child{border-top:0; padding-top:0.25rem}
.rule h3{display:flex; align-items:center; gap:0.625rem; margin:0 0 0.5rem; font-size:1.05rem}
.rule .n{width:1.625rem; height:1.625rem; border-radius:0.5rem; background:var(--cell); display:grid; place-items:center; font-family:var(--mono); font-size:.85rem; color:var(--muted); flex:none}
.rule p{margin:0.375rem 0; color:#cfd5e2; font-size:.95rem; line-height:1.45}
.rule strong{color:var(--ink)}
.rule .note{font-size:.85rem; color:var(--muted)}
.rule .note:empty{display:none}
.rule .cap{font-size:.82rem; color:var(--muted); text-align:center; margin-top:0.25rem}
.steps{margin:0.25rem 0 0.625rem; padding-left:1.25rem; color:#cfd5e2; font-size:.95rem}
.steps li{margin:0.1875rem 0}
.ex-eq{display:flex; align-items:center; justify-content:center; gap:0.5rem; margin:0.375rem 0 0.625rem}
.ex-eq .die{width:2.5rem; height:2.5rem; font-size:1.3rem; border-radius:0.375rem}
.ex-eq .ans{min-width:4rem; height:2.5rem; font-size:1.3rem; border-radius:0.625rem; padding:0 0.625rem}
canvas.mini{display:block; width:100%; max-width:18.75rem; margin:0.375rem auto 0}
.pair{display:grid; grid-template-columns:1fr 1fr; gap:0.75rem; margin-top:0.375rem}
.pair figure{margin:0}
.pair figcaption{font-size:.82rem; color:var(--muted); text-align:center; margin-top:0.25rem}
.pair.one{grid-template-columns:1fr; margin-top:0.75rem}
.pair.one figure{display:grid; grid-template-columns:1fr 1fr; gap:0.75rem; align-items:center}
.pair.one figcaption{text-align:left; font-size:.88rem; color:#cfd5e2}
.good{color:var(--ok); font-weight:700}
.bad{color:var(--bad); font-weight:700}
.ico{display:inline-grid; place-items:center; width:1.875rem; height:1.875rem; border-radius:0.5625rem; background:var(--cell); color:var(--ink); vertical-align:middle; flex:none}
.ico svg{width:1.125rem; height:1.125rem}
.ico[data-ico=rot]{background:var(--ink); color:var(--bg)}
.ico.tok{border-radius:50%; background:var(--tok-re); color:#151b28}
.ico.tok[data-ico=tokdown]{background:var(--tok-down)}
.ico.joker{background:var(--medal); color:#2a1f05}
.legend{list-style:none; margin:0.25rem 0; padding:0; display:grid; gap:0.75rem}
.legend li{display:flex; gap:0.5rem; align-items:flex-start}
.legend li div{font-size:.9rem; color:#cfd5e2; line-height:1.4}
.legend strong{display:block; color:var(--ink)}
.points{list-style:none; margin:0.25rem 0; padding:0; display:grid; gap:0.375rem}
.points li{font-size:.92rem; color:#cfd5e2}
.points b{display:inline-block; min-width:2.875rem; font-family:var(--mono); color:var(--ok)}
.muted{color:var(--muted)}
.chip{font-family:var(--mono); font-size:.8rem; color:var(--bad); background:var(--cell); padding:1px 0.375rem; border-radius:0.375rem; white-space:nowrap}

/* ===== Trophées et records (même fenêtre que les règles) ===== */
.cup{display:block}
.cup svg{display:block; width:100%; height:100%}
.tro-sum{display:flex; gap:1.25rem; padding:0 1.125rem 0.625rem; font-size:.9rem; color:var(--muted)}
.tro-sum b{font-family:var(--mono); font-size:1.05rem; color:var(--medal); margin-right:0.25rem}
.tro-tabs{margin:0 1.125rem 0.75rem; grid-template-columns:repeat(3, 1fr)}
.tro-tabs button{text-align:center; padding:0.625rem; transition:background-color .25s, color .25s}
/* le contenu qui glisse d'un onglet à l'autre ne dépasse pas de la fenêtre (voir switchTab dans vitrine.js) */
#trophyOverlay .rules-card{overflow:hidden}
.tro-group{font-family:var(--mono); font-size:.75rem; font-weight:400; text-transform:uppercase; letter-spacing:.1em; color:var(--muted); margin:1.125rem 0 0.5rem}
.tro-group:first-child{margin-top:0.25rem}
.fam{display:flex; gap:0.75rem; align-items:flex-start; padding:0.625rem 0.75rem; background:var(--cell); border-radius:0.875rem; margin-bottom:0.5rem}
.fam > .cup{flex:none; width:2.25rem; height:2.25rem; padding:0.375rem; border-radius:0.625rem; background:var(--surface); color:var(--muted)}
.fam.some > .cup{color:var(--medal)}
.fam.all > .cup{background:var(--medal); color:#2b2110}
.fam.all > .cup .b{fill:currentColor}
.fam.secret > .cup{display:grid; place-items:center; font-family:var(--mono); font-weight:700; font-size:1.1rem}
.fam-main{flex:1; min-width:0}
.fam-name{font-weight:700; font-size:.98rem}
.fam-sub{font-size:.82rem; color:var(--muted); margin-top:1px}
.bar-row{display:flex; align-items:center; gap:0.5rem; margin-top:0.375rem}
.bar{flex:1; height:0.375rem; border-radius:0.1875rem; background:var(--surface); overflow:hidden}
.bar i{display:block; height:100%; background:var(--medal); border-radius:inherit}
.bar-n{font-family:var(--mono); font-size:.75rem; color:var(--muted); white-space:nowrap}
.chips{display:flex; flex-wrap:wrap; gap:0.25rem; margin-top:0.5rem}
.chips span{font-family:var(--mono); font-size:.72rem; font-weight:700; padding:1px 0.4375rem; border-radius:0.375rem; background:var(--surface); color:var(--muted)}
.chips span.on{background:var(--medal); color:#2b2110}
.recs{list-style:none; margin:0; padding:0; display:grid; gap:0.375rem}
.recs li{display:flex; justify-content:space-between; align-items:baseline; gap:0.75rem; padding:0.5rem 0.75rem; background:var(--cell); border-radius:0.75rem; font-size:.92rem}
.recs b{font-family:var(--mono); color:var(--medal); white-space:nowrap}
.recs small{color:var(--muted); font-weight:400}
.tro-empty{margin:0; padding:1.5rem 0.5rem; text-align:center; color:var(--muted)}

/* Onglet « Tables » : réussite par table (barres), les multiplications à travailler, puis la grille de chaque multiplication.
   Vert : 90 % et plus ; doré : 70 à 89 % ; rouge : moins de 70 % ; gris : jamais posée. Le pourcentage est toujours écrit. */
.lv-good{--lv:var(--ok)} .lv-fair{--lv:var(--medal)} .lv-weak{--lv:var(--bad)} .lv-none{--lv:var(--muted)}
.tb-rows{list-style:none; margin:0; padding:0; display:grid; gap:0.375rem}
.tb-row{display:grid; grid-template-columns:2.5rem 1fr 3rem 3rem; align-items:center; gap:0.5rem; padding:0.4375rem 0.75rem; background:var(--cell); border-radius:0.75rem; font-size:.92rem}
.tb-n{font-family:var(--mono); font-weight:700}
.tb-row .bar i{background:var(--lv)}
.tb-row b{font-family:var(--mono); text-align:right; white-space:nowrap}
.tb-row small{font-family:var(--mono); font-size:.72rem; color:var(--muted); text-align:right}
.tb-work{display:flex; flex-wrap:wrap; gap:0.375rem}
.tb-work span{display:flex; align-items:baseline; gap:0.5rem; padding:0.375rem 0.75rem; border-radius:0.75rem; background:var(--cell); border:2px solid var(--lv);
  font-family:var(--mono); font-weight:700}
.tb-work b{font-size:.78rem; color:var(--muted)}
.tb-grid{display:grid; grid-template-columns:1.25rem repeat(8, minmax(0, 1fr)); gap:3px; font-family:var(--mono)}
.tb-grid .h{display:grid; place-items:center; font-size:.75rem; font-weight:700; color:var(--muted)}
.tb-grid .c{display:grid; place-items:center; aspect-ratio:1; border-radius:0.375rem; font-size:.7rem; font-weight:700; color:#151b28;
  background:var(--lv)}
.tb-grid .c.lv-none{background:var(--cell)}
.tb-legend{display:flex; flex-wrap:wrap; gap:0.375rem 0.875rem; margin:0.625rem 0 0; font-size:.78rem; color:var(--muted)}
.tb-legend span{display:flex; align-items:center; gap:0.3125rem}
.tb-legend span::before{content:''; width:0.75rem; height:0.75rem; border-radius:0.1875rem; background:var(--lv)}
.tb-legend .lv-none::before{background:var(--cell); outline:1px solid var(--line)}

/* ===== Défis du jour (même fenêtre que les règles) : une ligne par mission, ses points à gauche ===== */
#daySum{justify-content:space-between}
.day-pts{flex:none; display:grid; place-items:center; width:2.25rem; height:2.25rem; border-radius:0.625rem; background:var(--surface);
  font-family:var(--mono); font-size:.82rem; font-weight:700; color:var(--medal)}
.day-pts svg{width:1.25rem; height:1.25rem}
.fam.all .day-pts{background:var(--ok); color:#13261b}
.day-tier{font-family:var(--mono); font-size:.7rem; text-transform:uppercase; letter-spacing:.1em; color:var(--muted)}
.fam.mission.all .day-tier{color:var(--ok)}
.fam.series > .cup{color:var(--medal)}

/* ===== Boutique (même fenêtre que les règles) ===== */
.shop-sum{display:flex; align-items:center; gap:0.375rem; padding:0 1.125rem 0.625rem; font-size:.9rem; color:var(--muted)}
.shop-sum .coin{width:1.15rem; height:1.15rem; color:var(--medal); margin-left:0.25rem}
.shop-sum b{font-family:var(--mono); font-size:1.05rem; color:var(--medal)}
/* après un achat, l'écart (« −150 ») s'affiche à droite du nombre, la pièce étant à gauche */
.shop-sum .flash{right:auto; left:100%; top:0; margin:0 0 0 0.375rem; font-family:var(--mono)}
/* un achat n'est pas une perte : le nombre et l'écart restent dorés (le rouge est pour les vols, en partie) */
.shop-sum .count.down .num, .shop-sum .flash.down{color:var(--medal)}
/* rayons : des puces qui passent à la ligne si besoin (toutes restent visibles) */
.shop-tabs{display:flex; flex-wrap:wrap; gap:0.375rem; padding:0 1.125rem 0.75rem}
.shop-tabs button{flex:none; padding:0.5rem 0.875rem; border-radius:62.4375rem; background:var(--cell); border-color:transparent; font-size:.9rem}
.shop-tabs button[aria-pressed="true"]{background:var(--ink); color:var(--bg)}
.shop-hint{margin:0.125rem 0 0.75rem; font-size:.85rem; color:var(--muted)}
.shop-grid{display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:0.625rem; padding-bottom:0.25rem}
.shop-item{display:grid; gap:0.375rem; align-content:start; padding:0.625rem; text-align:center; background:var(--cell); border:2px solid transparent; border-radius:0.875rem}
.shop-item .prev{display:grid; place-items:center; min-height:4.5rem}
.shop-item canvas{width:100%; aspect-ratio:auto}
.shop-item .av{--av:4.5rem}
.shop-item .nm{font-weight:700; font-size:.92rem}
.shop-item .st{display:flex; align-items:center; justify-content:center; gap:0.25rem; min-height:1.625rem; font-family:var(--mono); font-size:.82rem; font-weight:700; color:var(--medal)}
.shop-item .st .coin{width:0.95rem; height:0.95rem}
.shop-item .st > svg{width:1rem; height:1rem}
/* équipé : contour doré ; acheté : « Choisir » ; trop cher : grisé ; confirmation : bandeau doré */
.shop-item.on{border-color:var(--medal)}
.shop-item.on .st{color:var(--ok)}
.shop-item.own .st{color:var(--ink)}
.shop-item.poor .st{color:var(--muted)}
.shop-item.poor .prev{opacity:.5}
.shop-item.confirm{border-color:var(--ink)}
.shop-item.confirm .st{background:var(--medal); color:#2b2110; border-radius:0.5rem; padding:0 0.5rem}
.shop-item.nope{animation:shake .45s ease-out}
.shop-item.bought{animation:tileBought .5s ease-out}
@keyframes tileBought{40%{transform:scale(1.06)}}
/* aperçu des confettis */
.conf-prev{position:relative; display:block; width:100%; height:4.5rem}
.conf-prev i{position:absolute; width:0.5rem; height:0.8rem; border-radius:2px}

/* Annonce d'un trophée pendant la partie : carte en haut de l'écran, le jeu reste jouable dessous */
#troToast{position:fixed; z-index:12; left:0; right:0; top:max(0.75rem, env(safe-area-inset-top)); display:flex; justify-content:center; padding:0 1rem; pointer-events:none}
#toastConfetti{z-index:11}
/* pendant les annonces, le jeu est en pause : plateau et boutons ne répondent plus (voir annonce.js) */
body.tro-pause #game{pointer-events:none}
.tt-card{pointer-events:auto; cursor:pointer; width:min(100%, 22.5rem); display:flex; gap:0.875rem; align-items:center; padding:0.875rem 1rem;
  background:var(--surface); border:3px solid var(--medal); border-radius:1.125rem; box-shadow:0 0.75rem 2.5rem rgba(0,0,0,.55)}
.tt-card > .cup{flex:none; width:3.25rem; height:3.25rem; padding:0.625rem; border-radius:50%; background:var(--medal); color:#2b2110}
.tt-card > .cup .b{fill:currentColor}
.tt-txt{display:grid; gap:1px; min-width:0}
.tt-h{font-family:var(--mono); font-size:.72rem; text-transform:uppercase; letter-spacing:.1em; color:var(--medal)}
.tt-name{font-size:1.1rem; font-weight:700; line-height:1.25}
.tt-desc{font-size:.85rem; color:#cfd5e2; line-height:1.35}
.tt-pts{font-family:var(--mono); font-size:.85rem; color:var(--medal); margin-top:0.125rem}
#troToast.in .tt-card{animation:toastIn .55s cubic-bezier(.3,1.4,.5,1) both}
#troToast.in .tt-card > .cup{animation:cupPop .7s cubic-bezier(.3,1.6,.5,1) .2s both}
#troToast.out .tt-card{animation:toastOut .35s ease-in forwards}
@keyframes toastIn{from{opacity:0; transform:translateY(-120%) scale(.9)}}
@keyframes toastOut{to{opacity:0; transform:translateY(-60%) scale(.95)}}
@keyframes fadeOut{to{opacity:0}}
@keyframes cupPop{0%{transform:scale(.3) rotate(-25deg)} 100%{transform:none}}
/* Double joker : fenêtre au milieu de l'écran, sans confettis ; elle grandit en arrivant et s'efface en partant */
#jokerPop{position:fixed; z-index:12; inset:0; display:flex; align-items:center; justify-content:center; padding:0 1rem; pointer-events:none}
.jp-card{pointer-events:auto; cursor:pointer; width:min(100%, 17.5rem); display:grid; justify-items:center; gap:0.25rem; text-align:center; padding:1.125rem 1.25rem;
  background:var(--surface); border:3px solid var(--medal); border-radius:1.125rem; box-shadow:0 0.75rem 2.5rem rgba(0,0,0,.6)}
.jp-ico{width:3.5rem; height:3.5rem; padding:0.75rem; border-radius:50%; background:var(--medal); color:#2a1f05; margin-bottom:0.25rem}
.jp-ico svg{width:100%; height:100%}
.jp-name{font-size:1.15rem; font-weight:700; line-height:1.25}
#jokerPop.in .jp-card{animation:jokerIn .5s cubic-bezier(.3,1.5,.5,1) both}
#jokerPop.in .jp-ico{animation:cupPop .7s cubic-bezier(.3,1.6,.5,1) .15s both}
#jokerPop.out .jp-card{animation:jokerOut .3s ease-in forwards}
@keyframes jokerIn{from{opacity:0; transform:scale(.6)}}
@keyframes jokerOut{to{opacity:0; transform:scale(.92)}}

/* Fin de partie : fenêtre au centre, jeu flouté derrière */
/* La fenêtre se centre avec margin:auto (et non place-items) : si elle dépasse l'écran, on peut la faire défiler jusqu'en haut */
#endOverlay{position:fixed; inset:0; z-index:10; display:flex; overflow-y:auto; padding:1rem;
  background:rgba(11,15,26,.45); -webkit-backdrop-filter:blur(0.4375rem); backdrop-filter:blur(0.4375rem); animation:fadeIn .35s ease-out}
.end-card{width:min(100%, 22.5rem); margin:auto; background:var(--surface); border:1px solid var(--line); border-radius:1.375rem; padding:1.5rem 1.25rem 1.25rem;
  text-align:center; box-shadow:0 1.25rem 3.75rem rgba(0,0,0,.45); animation:popIn .35s ease-out}
.end-card{position:relative; overflow:hidden}
.end-card #endMsg{margin:0; font-size:1.75rem; font-weight:700; line-height:1.2; letter-spacing:-.01em}
.duel{display:grid; grid-template-columns:1fr auto 1fr; align-items:end; gap:0.5rem; margin-top:1rem}
.side{transition:opacity .5s, transform .5s}
.side .crown{display:block; height:1.875rem; margin:0 auto 2px; width:2.375rem; opacity:0}
.side .crown svg{width:2.375rem; height:1.75rem}
.side.win .crown{opacity:1; animation:crownDrop .6s cubic-bezier(.3,1.6,.5,1) both}
@keyframes crownDrop{0%{opacity:0; transform:translateY(-2.5rem) rotate(-14deg)} 100%{opacity:1; transform:none}}
.esc{font-family:var(--mono); font-weight:700; font-size:3.6rem; line-height:1; transition:font-size .5s}
.enm{font-size:.9rem; font-weight:700; margin-top:0.375rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.side.lose{opacity:.55}
.side.lose .esc{font-size:2.4rem}
.vs{font-family:var(--mono); font-weight:700; font-size:.8rem; color:var(--muted); padding-bottom:0.875rem}
.bilan{margin-top:1rem; background:var(--cell); border-radius:0.75rem; padding:0.625rem 0.75rem; font-size:.85rem; color:var(--ink)}
.bilan .row{display:flex; justify-content:center; gap:1.125rem; align-items:baseline; flex-wrap:wrap}
.bilan .row + .row{margin-top:0.375rem}
.bilan b{font-family:var(--mono); font-size:1.05rem; color:var(--ok); margin-right:0.25rem}
.bilan .tbl{display:grid; grid-template-columns:auto 1fr 1fr; gap:0.25rem 0.625rem; align-items:baseline}
.bilan .tbl .h{font-size:.72rem; color:var(--muted)}
.bilan .tbl .who{font-weight:700; text-align:left; max-width:6.875rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.bilan .tbl b{margin:0}
.end-card > *:not(.confetti){position:relative; z-index:1}
/* Nouveaux trophées : le bloc se déplie après les annonces (même mouvement que .names du menu) ;
   le toucher ouvre la vitrine */
.end-tro-wrap{display:grid; grid-template-rows:0fr; opacity:0; margin-top:0;
  transition:grid-template-rows .8s cubic-bezier(.2,.8,.2,1), opacity .6s ease .15s, margin-top .8s cubic-bezier(.2,.8,.2,1)}
.end-tro-wrap.open{grid-template-rows:1fr; opacity:1; margin-top:0.75rem}
/* marge intérieure compensée : le contour de sélection du bouton n'est pas coupé */
.end-tro-in{overflow:hidden; min-height:0; padding:4px; margin:-4px}
.end-tro{display:grid; gap:0.375rem; width:100%; padding:0.75rem; text-align:left; font-weight:500;
  background:var(--cell); border:2px solid var(--medal); border-radius:0.875rem}
.end-tro-h{font-weight:700; color:var(--medal); text-align:center}
.end-tro-t{display:flex; align-items:center; gap:0.5rem; font-size:.9rem}
.end-tro-t .cup{flex:none; width:1.25rem; height:1.25rem; color:var(--medal)}
.end-tro-t .cup .b{fill:currentColor}
.end-tro-t .nm{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.end-tro-t b{font-family:var(--mono); color:var(--medal)}
.end-tro-more, .end-tro-pts{font-size:.8rem; color:var(--muted); text-align:center}
.end-btns{display:grid; grid-template-columns:1fr 1.4fr; gap:0.625rem; margin-top:1rem}
/* boutons en attente pendant l'animation de fin et l'annonce des trophées */
.end-btns button:disabled{opacity:.45}
/* défi réussi : Carte, Rejouer, puis « Niveau suivant » en plus large */
.end-btns.three{grid-template-columns:1fr 1fr 1.6fr; gap:0.5rem}
.end-btns.three button{padding:0.75rem 0.5rem; font-size:.92rem}
/* aventure : le bouton principal (Rejouer, Réessayer ou Niveau suivant) est une brique rose en relief, avec ses plots,
   comme la tuile Aventure du menu ; son nom sur une pastille unie ; enfoncée quand on appuie (13 octobre 2026) */
.end-btns button.brick-btn{--c:var(--p2); --d:var(--p2-dark); --e:color-mix(in srgb, var(--d) 72%, #000);
  border:0; border-radius:0.75rem; color:#161b27; font-weight:700;
  background:radial-gradient(circle at center, var(--d) 0 27%, transparent 29%) center / 1.2rem 1.2rem, var(--c);
  box-shadow:0 0.3125rem 0 var(--e), 0 0.5rem 0.875rem rgba(0,0,0,.35); margin-bottom:0.3125rem;
  transition:transform .2s cubic-bezier(.3,1.5,.5,1), box-shadow .2s, opacity .3s}
.end-btns button.brick-btn:active:not(:disabled){transform:translateY(0.25rem); box-shadow:0 1px 0 var(--e), 0 0.1875rem 0.375rem rgba(0,0,0,.3)}
/* duel : Revanche ou Rejouer, en brique jaune comme la tuile Duel */
.end-btns button.brick-btn.duel-brick{--c:var(--p1); --d:var(--p1-dark)}
.end-btns button.brick-btn span{background:var(--c); border-radius:0.375rem; padding:0.0625rem 0.4375rem 0.125rem}

/* Fin d'un défi : le niveau, ses étoiles qui s'allument une à une, tours et points */
.end-defi{margin-top:0.75rem}
.ed-level{margin:0 0 0.875rem; font-size:.92rem; color:#cfd5e2; line-height:1.35}
.end-defi .stars.big{display:flex; justify-content:center; gap:0.5rem; margin-bottom:0.75rem}
.end-defi .stars.big .star{width:3.25rem; height:3.25rem}
.end-defi .star.on{opacity:0}
.end-defi.go .star.on{opacity:1; animation:starPop .5s cubic-bezier(.3,1.6,.5,1) both}
.end-defi.go .star.on:nth-child(2){animation-delay:.35s}
.end-defi.go .star.on:nth-child(3){animation-delay:.7s}
@keyframes starPop{0%{opacity:0; transform:scale(.2) rotate(-40deg)} 100%{opacity:1; transform:none}}
@media (prefers-reduced-motion: reduce){ .end-defi .star.on{opacity:1} .end-defi.go .star.on{animation:none} }
.ed-line{margin:0; font-size:.95rem}
.ed-line b{font-family:var(--mono)}
.ed-pts, .ed-rec{display:block; margin-top:0.25rem; font-family:var(--mono); font-weight:700; color:var(--medal)}
.ed-rec{font-family:inherit; font-weight:500; font-size:.85rem; color:var(--muted)}
.confetti{position:fixed; inset:0; z-index:5; pointer-events:none; overflow:hidden}
.confetti i{position:absolute; width:0.625rem; height:1rem; border-radius:2px; animation:fall linear both}
/* formes achetées dans la boutique */
.conf-prev i.star{width:0.85rem; height:0.85rem}
.conf-prev i.heart{width:0.85rem; height:0.75rem}
.confetti i.star, .conf-prev i.star{border-radius:0; clip-path:polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)}
.confetti i.heart, .conf-prev i.heart{border-radius:0; clip-path:polygon(50% 100%, 10% 62%, 0% 36%, 4% 15%, 18% 3%, 34% 2%, 50% 16%, 66% 2%, 82% 3%, 96% 15%, 100% 36%, 90% 62%)}
/* Bulles : rondes, avec un reflet ; mini-briques : deux plots de la même couleur sur le dessus */
.confetti i.bubble, .conf-prev i.bubble{border-radius:50%; opacity:.85; box-shadow:inset -0.125rem -0.125rem 0 rgba(0,0,0,.12), inset 0.15rem 0.15rem 0 rgba(255,255,255,.55)}
.confetti i.bubble{width:0.9rem; height:0.9rem}
.conf-prev i.bubble{width:0.8rem; height:0.8rem}
.confetti i.brick, .conf-prev i.brick{width:1rem; height:0.6rem; border-radius:2px; box-shadow:inset 0 -0.125rem 0 rgba(0,0,0,.18)}
.confetti i.brick::before, .confetti i.brick::after, .conf-prev i.brick::before, .conf-prev i.brick::after{content:''; position:absolute; top:-0.1875rem;
  width:0.28rem; height:0.22rem; border-radius:1px 1px 0 0; background:inherit}
.confetti i.brick::before, .conf-prev i.brick::before{left:0.12rem}
.confetti i.brick::after, .conf-prev i.brick::after{right:0.12rem}
.confetti i.star{width:1rem; height:1rem}
.confetti i.heart{width:1rem; height:0.9rem}
@keyframes fall{0%{opacity:0; transform:none} 4%{opacity:1} 100%{opacity:1; transform:translate(var(--drift), var(--fall)) rotate(var(--rot))}}
@keyframes fadeIn{from{opacity:0}}
@keyframes popIn{from{opacity:0; transform:translateY(0.625rem) scale(.97)}}
@keyframes stampSoft{0%,100%{opacity:0} 15%,80%{opacity:1}}
[hidden]{display:none !important}
@media (prefers-reduced-motion: reduce){ .title .lg-brick{animation:none} .side.win .crown{animation:none} .confetti{display:none}  .stamp{animation:stampSoft 1.25s forwards} .board-wrap.thud{animation:none}  #rotateHint svg{animation:none}  .names{transition:none} .opp.guest .lbl,.opp.guest input{transition:none}  .die.ready,.die.pick,#endOverlay,.end-card{animation:none} .pcard .flash{animation:none; opacity:0} .pcard .sc .num{animation:none} button{transition:none} .end-tro-wrap{transition:none} #troToast.in .tt-card,#troToast.in .tt-card > .cup{animation:none} #troToast.out .tt-card{animation:fadeOut .35s forwards} }
