
@font-face{font-family:'Departure Mono';font-display:swap;
  src:url('https://cdn.jsdelivr.net/gh/projectnoonnu/2409-1@1.0/DepartureMono-Regular.woff2') format('woff2')}

/* ============================================================
   TOKENS
   ============================================================ */
:root{
  /* easing — repris du skill awwwards */
  --e-out:cubic-bezier(.16,1,.3,1);
  --e-io:cubic-bezier(.76,0,.24,1);
  --e-back:cubic-bezier(.34,1.56,.64,1);
  --e-expo-io:cubic-bezier(.87,0,.13,1);

  /* échelle typo fluide */
  --t-display:clamp(2.6rem,13cqi,4.4rem);
  --t-h1:clamp(1.7rem,7cqi,2.4rem);
  --t-h2:clamp(1.15rem,4.6cqi,1.5rem);
  --t-body:clamp(.95rem,3.5cqi,1.05rem);
  --t-label:clamp(.62rem,2.4cqi,.72rem);
  --t-micro:clamp(.55rem,2cqi,.63rem);

  /* coque par défaut — MER SOMBRE
     Profonde, bleu-vert, riche. Elle doit tenir aussi bien pour un
     panthéon grec que pour des super-héros : c'est de l'eau, pas un thème. */
  --bg:oklch(.166 .062 236);
  --abyss:oklch(.095 .05 244);
  --surf:oklch(.216 .066 234);
  --elev:oklch(.268 .07 232);
  --ink:oklch(.955 .014 235);
  --ink2:oklch(.715 .032 235);
  --ink3:oklch(.505 .036 238);
  --line:oklch(.84 .07 225/.16);
  --acc:oklch(.8 .13 191);
  --acc2:oklch(.56 .16 268);
  --card-r:12px;
  --dom-font:"Boldonse",Impact,sans-serif; --dom-tracking:-.01em;
  --dom-bg:oklch(.26 .06 240); --dom-ink:oklch(.96 .014 235);
  --q-bg:oklch(.17 .05 243); --q-ink:oklch(.96 .014 235);
}

/* ---- Domaines : chaque domaine repeint la coque ------------- */
[data-dom="sportifs"]{
  --abyss:oklch(.08 .04 255);
  --bg:oklch(.15 .06 255); --surf:oklch(.2 .07 255); --elev:oklch(.26 .075 255);
  --ink:oklch(.97 .015 90); --ink2:oklch(.74 .025 90); --ink3:oklch(.52 .025 90);
  --line:oklch(.98 0 0/.12);
  --acc:oklch(.78 .15 85); --acc2:oklch(.55 .18 25); --acc3:oklch(.68 .17 145);
  --dom-bg:oklch(.4 .15 255); --dom-ink:oklch(.97 .02 90);
  --dom-font:'Space Mono','Departure Mono',monospace;
  --dom-tracking:.02em;
}
[data-dom="france"]{
  --abyss:oklch(.09 .05 260);
  --bg:oklch(.15 .05 260); --surf:oklch(.2 .06 260); --elev:oklch(.26 .07 260);
  --ink:oklch(.98 .01 260); --ink2:oklch(.74 .03 260); --ink3:oklch(.52 .03 260);
  --line:oklch(.98 0 0/.12);
  --acc:oklch(.62 .18 260); --acc2:oklch(.6 .21 25); --acc3:oklch(.97 .008 260);
  --dom-bg:oklch(.32 .14 260); --dom-ink:oklch(.98 .01 260);
  --dom-font:'Playwrite FR Trad',cursive;
  --dom-tracking:.04em;
}
[data-dom="supermarche"]{
  --abyss:oklch(.1 .02 35);
  --bg:oklch(.16 .015 35); --surf:oklch(.21 .02 35); --elev:oklch(.27 .025 35);
  --ink:oklch(.99 .01 35); --ink2:oklch(.74 .02 35); --ink3:oklch(.52 .02 35);
  --line:oklch(.98 0 0/.11);
  --acc:oklch(.86 .18 95); --acc2:oklch(.6 .2 25);
  --dom-bg:oklch(.55 .19 35); --dom-ink:oklch(.99 .01 35);
  /* Abril Fatface : display serif à fort contraste, esprit devanture de
     magasin à l'ancienne — déjà chargé (voir le <link> Google Fonts) mais
     resté inutilisé depuis un précédent essai sur France. Remplace Handjet,
     qui lisait plutôt "afficheur digital" que "commerce". */
  --dom-font:'Abril Fatface',"Zodiak",Georgia,serif;
  --dom-tracking:0;
}
[data-dom="pocket"]{
  --abyss:oklch(.12 .035 62);
  --bg:oklch(.19 .03 62); --surf:oklch(.245 .036 62); --elev:oklch(.3 .04 62);
  --ink:oklch(.97 .012 82); --ink2:oklch(.72 .03 72); --ink3:oklch(.52 .03 72);
  --line:oklch(.98 0 0/.12);
  --acc:oklch(.84 .17 89); --acc2:oklch(.6 .22 29);
  --dom-bg:oklch(.5 .15 85); --dom-ink:oklch(.16 .03 85);
  --dom-font:'Pixelify Sans','Departure Mono',monospace;
  --dom-tracking:0;
}

*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  background:var(--bg);color:var(--ink);
  font-family:'Zodiak',Georgia,serif;
  overflow:hidden;
  transition:background .7s var(--e-io),color .7s var(--e-io);
  -webkit-font-smoothing:antialiased;
}
/* fond d'ambiance qui déborde de la colonne portrait — SANS filter:blur().
   Cette couche est plein écran ET animée en transform pour toujours (voir
   @keyframes drift), donc Firefox devait refaire le flou à chaque image,
   indéfiniment, sur chaque écran : sluggish signalé sur Firefox desktop,
   absent du prévisualiseur (qui n'a pas cet élément). Les radial-gradient
   finissent déjà sur transparent — la douceur vient de leur propre dégradé,
   pas d'un flou après coup. */
body::before{
  content:'';position:fixed;inset:-20%;z-index:0;pointer-events:none;
  background:
    radial-gradient(ellipse 62% 42% at 20% 12%,color-mix(in oklch,var(--acc),transparent 78%),transparent 62%),
    radial-gradient(ellipse 58% 46% at 84% 74%,color-mix(in oklch,var(--acc2),transparent 80%),transparent 62%),
    linear-gradient(180deg,transparent 30%,color-mix(in oklch,var(--abyss),transparent 25%) 100%);
  transition:opacity .7s var(--e-io);
  animation:drift 26s ease-in-out infinite alternate;
}
@keyframes drift{to{transform:translate3d(2%,-2.5%,0) scale(1.06)}}

button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
input{font:inherit;color:inherit;background:none;border:0;outline:0}

/* ============================================================
   COLONNE PORTRAIT
   ============================================================ */
#app{
  position:relative;z-index:1;
  width:min(520px,100vw);height:100dvh;margin-inline:auto;
  container-type:inline-size;container-name:col;
  overflow:clip;isolation:isolate;
  box-shadow:0 0 0 1px var(--line),0 30px 120px oklch(0 0 0/.55);
  background:color-mix(in oklch,var(--bg),transparent 12%);
}
#app.shake{animation:shake .38s var(--e-out)}
@keyframes shake{
  0%,100%{transform:translate3d(0,0,0)}
  15%{transform:translate3d(-7px,3px,0)}
  32%{transform:translate3d(6px,-4px,0)}
  52%{transform:translate3d(-4px,-2px,0)}
  74%{transform:translate3d(3px,2px,0)}
}
.screen{
  position:absolute;inset:0;display:flex;flex-direction:column;
  padding:max(18px,env(safe-area-inset-top)) 18px 18px;
  opacity:0;visibility:hidden;transform:translateY(14px);
  transition:opacity .42s var(--e-out),transform .42s var(--e-out),visibility .42s;
}
.screen[data-on]{opacity:1;visibility:visible;transform:none}

/* ============================================================
   CHROME — le bruit vit ici
   ============================================================ */
.logo{
  font-family:'Boldonse',Impact,sans-serif;font-weight:400;
  line-height:1;letter-spacing:-.035em;text-transform:uppercase;
  font-size:var(--t-display);
}
.logo em{font-style:normal;display:block}
.logo .l2{color:var(--acc)}
.logo .l4{
  -webkit-text-stroke:2px var(--ink);color:transparent;
  paint-order:stroke fill;
}
.label{
  font-family:'Departure Mono',ui-monospace,monospace;
  font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink3);line-height:1.2;
}
.mono{font-family:'Departure Mono',ui-monospace,monospace;letter-spacing:.06em}

.btn{
  font-family:'Boldonse',Impact,sans-serif;text-transform:uppercase;
  letter-spacing:-.01em;font-size:1rem;text-decoration:none;
  padding:15px 22px;background:var(--ink);color:var(--bg);
  border-radius:2px;position:relative;overflow:hidden;
  transition:transform .18s var(--e-back),filter .18s;
}
.btn:hover{transform:translateY(-2px) scale(1.015)}
.btn:active{transform:translateY(1px) scale(.985)}
.btn.ghost{background:none;color:var(--ink);box-shadow:inset 0 0 0 1.5px var(--line)}
/* CTA principal (connexion, ouverture de saison…) — mérite plus de présence
   qu'un .btn neutre : dégradé sur les couleurs d'accent du thème courant +
   halo + badge d'icône, pour rester cohérent skin par skin. */
.btn-cta{
  display:inline-flex;align-items:center;gap:14px;padding:10px 26px 10px 10px;
  background:linear-gradient(135deg,var(--acc),var(--acc2));color:var(--bg);
  box-shadow:0 10px 34px -10px color-mix(in oklch,var(--acc2),transparent 25%),
    inset 0 0 0 1px oklch(1 0 0/.14);
}
.btn-cta .badge{
  width:40px;height:40px;flex:none;display:grid;place-items:center;
  background:oklch(1 0 0/.16);border-radius:50%;
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.22);
  transition:background .2s,transform .3s var(--e-back);
}
.btn-cta .seal{color:var(--bg);width:22px;height:22px}
.btn-cta:hover{
  box-shadow:0 14px 44px -8px color-mix(in oklch,var(--acc2),transparent 10%),
    inset 0 0 0 1px oklch(1 0 0/.22);
}
.btn-cta:hover .badge{background:oklch(1 0 0/.24);transform:rotate(-8deg) scale(1.08)}
/* option secondaire discrète (ex. "Mode invité" sous un vrai bouton) —
   jamais aussi lourde qu'un .btn, sinon les deux se disputent l'attention.
   Pas de soulignement statique : un trait qui se déploie au survol, plus
   proche de ce qu'on voit sur les CTA secondaires soignés (awwwards-like)
   que d'un lien de formulaire par défaut. */
.linklike{
  position:relative;font-family:"Rock Salt","La Belle Aurore",cursive;
  font-size:.95rem;letter-spacing:0;text-transform:none;
  color:var(--ink3);text-decoration:none;background:none;padding:6px 1px;
}
.linklike::after{
  content:'';position:absolute;left:0;right:100%;bottom:2px;height:1px;
  background:currentColor;transition:right .3s var(--e-out);
}
.linklike:hover{color:var(--ink2)}
.linklike:hover::after{right:0}

/* barre du haut */
.topbar{display:flex;align-items:center;gap:10px;padding-bottom:14px}
.topbar .sp{margin-left:auto}
.iconbtn{width:34px;height:34px;display:grid;place-items:center;border-radius:2px;
  box-shadow:inset 0 0 0 1px var(--line);transition:background .2s}
.iconbtn:hover{background:var(--surf)}
.seal{width:22px;height:22px;display:block;color:var(--acc)}
.seal-lg{width:64px;height:64px}

/* ============================================================
   ÉCRAN TITRE
   ============================================================ */
#s-title{justify-content:center;gap:24px}
#s-title .logo{font-size:clamp(2.9rem,15cqi,5rem)}
.title-rule{height:2px;background:var(--ink);transform-origin:left;animation:ruleIn .9s .15s var(--e-expo-io) both}
@keyframes ruleIn{from{transform:scaleX(0)}}
/* entrée échelonnée des CTA de connexion — suit le trait de titre plutôt que
   d'apparaître instantanément avec le reste, ~150ms d'écart entre chaque */
.rise-in{animation:riseIn .7s var(--e-out) both}
@keyframes riseIn{from{opacity:0;transform:translateY(14px)}}
.tagline{font-size:var(--t-body);color:var(--ink2);max-width:32ch;text-wrap:pretty;line-height:1.5}

/* ============================================================
   CHOIX DU BOOSTER — 3 proposés, 1 seul ouvrable
   ============================================================ */
.picks{display:flex;flex-direction:column;gap:12px;flex:1;justify-content:center}
.pick{
  position:relative;height:clamp(96px,15dvh,132px);
  border-radius:3px;overflow:hidden;text-align:left;
  padding:15px 17px;display:flex;flex-direction:column;justify-content:space-between;
  color:var(--p-ink);background:var(--p-bg);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.16),0 12px 34px oklch(0 0 0/.42);
  transition:transform .3s var(--e-back),box-shadow .3s var(--e-out);
  isolation:isolate;
}
.pick::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(115deg,transparent 30%,oklch(1 0 0/.24) 48%,transparent 62%);
  background-size:260% 100%;background-position:120% 0;
  transition:background-position .8s var(--e-out);
}
.pick:hover{transform:translateY(-4px) scale(1.012)}
.pick:hover::after{background-position:-40% 0}
.pick .pname{font-family:"Boldonse",Impact,sans-serif;font-size:1.3rem;line-height:.95;
  text-transform:uppercase;letter-spacing:-.02em;position:relative;z-index:3}
.pick .pseal{position:absolute;right:-10px;bottom:-16px;width:100px;height:100px;opacity:.2;color:currentColor;z-index:1}
.pick .prow{display:flex;align-items:center;gap:8px;position:relative;z-index:3}
.pick[data-dead]{animation:destroy .66s var(--e-expo-io) forwards;pointer-events:none}
@keyframes destroy{
  0%{transform:none;filter:none}
  10%{transform:scale(1.06);filter:brightness(7) saturate(0)}
  20%{transform:scale(.96) skewX(-4deg);filter:brightness(.18) grayscale(1)}
  100%{transform:translateX(-135%) scale(.88) rotate(-6deg);opacity:0;filter:grayscale(1) brightness(.18)}
}
.pick[data-chosen]{animation:chosen .66s var(--e-expo-io) forwards;z-index:5}
@keyframes chosen{
  0%{transform:none}
  26%{transform:scale(1.09)}
  100%{transform:scale(1.7);opacity:0;filter:brightness(3)}
}
.streak{display:flex;align-items:center;gap:7px;padding-top:14px}
.streak i{width:7px;height:7px;background:var(--ink3);display:block;border-radius:50%}
.streak i.on{background:var(--acc);box-shadow:0 0 10px var(--acc)}

/* ============================================================
   LA CARTE
   ============================================================ */
.stage{flex:1;display:grid;place-items:center;perspective:1400px;position:relative;min-height:0}
.card{
  --w:min(344px,86cqi);
  width:var(--w);aspect-ratio:63/88;position:relative;
  transform-style:preserve-3d;
  transition:transform .74s var(--e-io);
  will-change:transform;
}
.card.flip{transform:rotateY(180deg)}
.face{
  position:absolute;inset:0;backface-visibility:hidden;
  border-radius:var(--card-r);overflow:hidden;
  background:var(--surf);
  box-shadow:0 18px 50px oklch(0 0 0/.5);
  display:flex;flex-direction:column;
}
.face.back{transform:rotateY(180deg)}

/* --- dos --- */
.cardback{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.07) 7px 14px),
    radial-gradient(ellipse at 50% 38%,color-mix(in oklch,var(--dom-bg),white 12%),transparent 62%),
    linear-gradient(160deg,color-mix(in oklch,var(--dom-bg),black 22%),var(--dom-bg));
  color:var(--dom-ink);
  display:grid;place-items:center;
  box-shadow:inset 0 0 0 1px var(--line),0 18px 50px oklch(0 0 0/.5);
}
.cardback .seal-lg{opacity:.62}

/* SPORTIFS — le dos de carte reprenait juste --dom-bg (un bleu plat, "un
   carré uni" au retour du joueur) : chaque rareté prend maintenant la
   couleur d'un des 4 anneaux, la mythique les 4 à la fois — cohérent avec
   l'échelle d'intensité déjà utilisée ailleurs (qbg --op/--sp par rareté). */
[data-dom="sportifs"] .card[data-rar="commune"] .cardback{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.07) 7px 14px),
    radial-gradient(ellipse at 50% 38%,color-mix(in oklch,#0081c8,white 18%),transparent 62%),
    linear-gradient(160deg,color-mix(in oklch,#0081c8,black 35%),color-mix(in oklch,#0081c8,black 12%));
}
[data-dom="sportifs"] .card[data-rar="rare"] .cardback{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.07) 7px 14px),
    radial-gradient(ellipse at 50% 38%,color-mix(in oklch,#fcb131,white 18%),transparent 62%),
    linear-gradient(160deg,color-mix(in oklch,#fcb131,black 40%),color-mix(in oklch,#fcb131,black 18%));
}
[data-dom="sportifs"] .card[data-rar="epique"] .cardback{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.07) 7px 14px),
    radial-gradient(ellipse at 50% 38%,color-mix(in oklch,#00a651,white 18%),transparent 62%),
    linear-gradient(160deg,color-mix(in oklch,#00a651,black 38%),color-mix(in oklch,#00a651,black 14%));
}
[data-dom="sportifs"] .card[data-rar="mythique"] .cardback{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.1) 7px 14px),
    conic-gradient(from 210deg at 50% 45%,#0081c8,#fcb131,#00a651,#ee334e,#0081c8);
}
/* les anneaux ont des couleurs fixes (pas currentColor) : sur un fond
   déjà teinté d'une des 4 mêmes couleurs, l'anneau assorti se noyait
   dedans — une simple ombre ne suffit pas (elle n'éclaire rien DANS la
   forme), il faut un halo clair autour de chaque trait + une opacité
   presque pleine plutôt que le ~50% générique des autres decks. */
[data-dom="sportifs"] .cardback .seal-lg{
  opacity:1 !important;
  filter:drop-shadow(0 0 2px oklch(1 0 0/.9)) drop-shadow(0 2px 10px oklch(0 0 0/.6));
  animation:sealPulseSportifs 3s var(--e-io) infinite;
}
@keyframes sealPulseSportifs{0%,100%{transform:scale(1)}50%{transform:scale(1.075)}}

/* --- recto --- */
.art{position:relative;flex:1;min-height:0;overflow:hidden;background:var(--elev)}
.art img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 1.2s var(--e-out),filter .5s}
.art::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:3;
  background:radial-gradient(ellipse at 50% 42%,transparent 46%,oklch(0 0 0/.46) 100%);
}
[data-dom="sportifs"] .art img{filter:contrast(1.14) saturate(1.2)}
/* le pied de carte retombait sur --surf tel quel : un bloc plat, sans
   rapport avec la texture rayée utilisée partout ailleurs sur ce deck
   (dos de carte, .art) — même motif ici, plus assombri pour que le texte
   blanc reste lisible sur toutes les couleurs de rareté. */
[data-dom="sportifs"] .cardfoot{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.05) 7px 14px),
    oklch(0 0 0/.6);
}
[data-dom="sportifs"] .card[data-rar="mythique"] .cardfoot{
  background:
    repeating-linear-gradient(45deg,transparent 0 7px,oklch(1 0 0/.05) 7px 14px),
    linear-gradient(0deg,oklch(0 0 0/.68) 58%,transparent);
}
/* le cadre couleur-rareté vivait sur .art::before (juste la photo) —
   comme .front porte déjà SA PROPRE bordure de rareté (générique, tous
   domaines confondus : anneau doré mythique, liseré fin rare...), ça
   dessinait un rectangle DANS un rectangle dès que le pied de carte
   entrait dans le cadre (le pied n'est pas dans .art, donc jamais bordé
   pareil — la jonction se voyait comme un carré flottant). Déplacé sur
   .front::after, qui couvre déjà toute la carte (pied compris) pour les
   autres raretés — un seul rectangle, plus de doublon. */
[data-dom="sportifs"] .card .front::after{
  content:"";position:absolute;inset:0;z-index:6;pointer-events:none;border-radius:var(--card-r);
}
[data-dom="sportifs"] .card[data-rar="commune"] .front::after{box-shadow:inset 0 0 0 3px #0081c8}
[data-dom="sportifs"] .card[data-rar="rare"] .front::after{box-shadow:inset 0 0 0 3px #fcb131}
[data-dom="sportifs"] .card[data-rar="epique"] .front::after{box-shadow:inset 0 0 0 3px #00a651}
[data-dom="sportifs"] .card[data-rar="mythique"] .front::after{
  background:
    linear-gradient(90deg,#0081c8 0 25%,#fcb131 25% 50%,#00a651 50% 75%,#ee334e 75% 100%) top/100% 5px no-repeat,
    linear-gradient(90deg,#0081c8 0 25%,#fcb131 25% 50%,#00a651 50% 75%,#ee334e 75% 100%) bottom/100% 5px no-repeat,
    linear-gradient(180deg,#0081c8 0 25%,#fcb131 25% 50%,#00a651 50% 75%,#ee334e 75% 100%) left/5px 100% no-repeat,
    linear-gradient(180deg,#0081c8 0 25%,#fcb131 25% 50%,#00a651 50% 75%,#ee334e 75% 100%) right/5px 100% no-repeat;
  box-shadow:none;
}
[data-dom="pocket"] .art img{filter:saturate(1.22) contrast(1.06)}
/* portraits/gravures : correction légère, pas de traitement lourd type cosplay */
[data-dom="france"] .art img{filter:sepia(.18) saturate(1.1) contrast(1.08)}
[data-dom="france"] .art::before{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:linear-gradient(90deg,
    oklch(.55 .19 260/.22) 0 6%,transparent 6% 94%,oklch(.6 .21 25/.22) 94% 100%);
}
/* le bandeau d'info coupait le portrait net, en rectangle plein — d'autant
   plus visible depuis que le liseré tricolore encadre toute la carte. Il
   sort du flux flex (chevauche le bas de l'image en position absolue) et
   se fond dedans par dégradé plutôt que par un bloc opaque séparé.
   NE PAS ajouter "position:relative" sur .cardfront ici : la règle
   partagée .cardfront{position:absolute;inset:0;overflow:hidden} (tout en
   bas du fichier) est ce qui verrouille la carte à une taille fixe et
   coupe les images trop hautes — un override par domaine, même juste sur
   "position", l'écrase et laisse l'image dicter la hauteur de la carte
   (régression vécue : Charlemagne étirait toute la carte à 574px). Un
   élément position:absolute est déjà son propre contexte de positionnement
   pour ses enfants, donc .cardfoot ci-dessous s'ancre correctement sans
   qu'on y touche. */
[data-dom="france"] .cardfoot{
  position:absolute;left:0;right:0;bottom:0;
  background:linear-gradient(0deg,var(--surf) 60%,transparent);
  box-shadow:none;
}
/* les logos sont sur fond blanc/transparent : cover les écraserait, on les
   pose entiers sur un fond dédié plutôt que de les recadrer comme une photo.
   Fond "ticket de caisse" : papier clair, fines lignes d'imprimante
   thermique horizontales — le dégradé sombre précédent ne racontait rien
   du deck, ce papier fait immédiatement penser à une note de caisse. */
[data-dom="supermarche"] .art{
  background:
    repeating-linear-gradient(0deg,oklch(0 0 0/.05) 0 1px,transparent 1px 4px),
    radial-gradient(ellipse 90% 70% at 50% 50%,oklch(.95 .012 80),oklch(.9 .015 75));
}
[data-dom="supermarche"] .art img{
  object-fit:contain;padding:14%;filter:drop-shadow(0 2px 8px oklch(0 0 0/.28));
}

.cardfoot{padding:10px 12px 11px;display:flex;flex-direction:column;gap:4px;
  background:var(--surf);box-shadow:0 -1px 0 var(--line);position:relative;z-index:4}
.cname{
  font-family:var(--dom-font);letter-spacing:var(--dom-tracking);
  font-size:clamp(1.1rem,5.4cqi,1.45rem);line-height:.98;text-transform:uppercase;
  text-wrap:balance;
}
/* France : Playwrite est une cursive — la forcer en capitales la rend
   méconnaissable et surtout beaucoup plus large, au point de wrapper sur
   2 lignes et de heurter la signature au-dessus. Casse naturelle + un cran
   plus petit pour retrouver une seule ligne lisible. */
[data-dom="france"] .cname{
  text-transform:none;font-size:clamp(.95rem,4.6cqi,1.25rem);letter-spacing:0;
}
.crow{display:flex;align-items:center;gap:7px}
.crow .sp{margin-left:auto}
.cno{font-family:"Departure Mono",monospace;font-size:var(--t-micro);color:var(--ink3);letter-spacing:.1em}
/* Supermarché : un vrai petit code-barres (motif décoratif, pas un
   encodage EAN réel) posé en tampon dans le coin du pied de carte, comme
   une étiquette de prix — son haut aligné sur celui de "SUPERMARCHÉS", pas
   coincé dans la ligne rareté/numéro. On lui réserve de la place à droite
   du pied (padding-right) et il sort du flux (position:absolute) pour ne
   plus dépendre de la hauteur du texte du numéro. */
[data-dom="supermarche"] .cardfoot{padding-right:66px}
[data-dom="supermarche"] .cno{
  position:absolute;top:10px;right:12px;
  display:flex;flex-direction:column;align-items:stretch;gap:3px;
}
[data-dom="supermarche"] .cno::before{
  content:"";display:block;width:100%;height:20px;border-radius:1px;
  background-color:#fff;
  background-image:repeating-linear-gradient(90deg,
    #000 0 1px,#fff 1px 2px,
    #000 2px 4px,#fff 4px 5px,
    #000 5px 6px,#fff 6px 8px,
    #000 8px 9px,#fff 9px 11px,
    #000 11px 12px,#fff 12px 14px,
    #000 14px 15px,#fff 15px 17px);
  background-size:17px 100%;background-repeat:repeat-x;
}
.rar{font-family:"Departure Mono",monospace;font-size:var(--t-micro);
  letter-spacing:.15em;text-transform:uppercase;color:var(--r-ink)}
.dot{width:6px;height:6px;border-radius:50%;background:var(--r-ink);flex:none}

/* réponse manuscrite qui s'imprime */
.ink{
  font-family:"Rock Salt","La Belle Aurore",cursive;
  font-size:.72rem;line-height:1.2;color:var(--acc);
  transform:rotate(-1.6deg);transform-origin:left center;
  min-height:1.25em;white-space:nowrap;overflow:hidden;
  clip-path:inset(0 100% 0 0);
}

/* ============================================================
   RARETÉ = traitement, pas cadre
   ============================================================ */
.card[data-rar="commune"]{--r-ink:var(--ink3)}
.card[data-rar="rare"]{--r-ink:oklch(.84 .035 250)}
.card[data-rar="epique"]{--r-ink:oklch(.78 .17 300)}
.card[data-rar="mythique"]{--r-ink:oklch(.84 .17 88)}

/* Supermarché : le mat de la carte (.face, donc .cardfoot et le cadre
   autour de .art) passe en papier de ticket de caisse — clair, encre
   foncée — plutôt que la coque sombre générique. Scopé à la carte elle-
   même (:is() couvre les deux placements possibles de data-dom, voir la
   note plus haut sur le halo mythique France) : le reste de l'UI du deck
   (menus, boutons) garde sa palette sombre habituelle, seule la carte
   change. Le verso (.face.back) n'est pas concerné : il a déjà ses propres
   --q-bg/--q-ink indépendants (voir plus bas, "le verso est toujours
   sombre"). */
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"]),
:is([data-dom="supermarche"] .spoilcard,.spoilcard[data-dom="supermarche"]){
  --surf:oklch(.93 .015 75);
  --elev:oklch(.87 .02 70);
  --ink:oklch(.24 .02 40);
  --ink2:oklch(.42 .025 40);
  --ink3:oklch(.52 .02 40);
  --line:oklch(.3 .02 40/.16);
}
/* les teintes --r-ink par rareté étaient calées pour rester lisibles sur
   fond sombre (claires, peu saturées) — trop pâles sur le papier clair
   ci-dessus, on les assombrit pour ce deck précis. */
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="rare"],
:is([data-dom="supermarche"] .spoilcard,.spoilcard[data-dom="supermarche"])[data-rar="rare"]{--r-ink:oklch(.52 .1 250)}
/* teinte alignée sur la bordure rouge "promo" plus bas (hue 25), pas le
   violet générique d'origine — c'était l'incohérence qui rendait le
   texte "ÉPIQUE" peu lisible/déconnecté de sa bordure. */
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="epique"],
:is([data-dom="supermarche"] .spoilcard,.spoilcard[data-dom="supermarche"])[data-rar="epique"]{--r-ink:oklch(.5 .19 25)}
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="mythique"],
:is([data-dom="supermarche"] .spoilcard,.spoilcard[data-dom="supermarche"])[data-rar="mythique"]{--r-ink:oklch(.5 .15 88)}

/* Supermarché : le halo générique (--emis) se voit mal sur un fond papier
   clair — bordure façon étiquette de prix, une couleur par rareté, pour
   qu'on identifie la rareté au premier coup d'œil sans lire le texte.
   Palette "étiquette" (gris -> bleu -> rouge promo -> or), pas les anneaux
   olympiques de Sportifs. Commune et rare n'avaient pas de .front::after
   dans la règle générique (seuls épique/mythique en créent un) : on le
   crée ici pour les 4 raretés, scopé à ce deck. */
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"]) .front::after{
  content:"";position:absolute;inset:0;z-index:6;pointer-events:none;border-radius:var(--card-r);
}
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="commune"] .front::after{
  box-shadow:inset 0 0 0 2px oklch(.55 .02 40/.55);
}
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="rare"] .front::after{
  box-shadow:inset 0 0 0 2.5px oklch(.42 .16 250);
}
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="epique"] .front::after{
  box-shadow:inset 0 0 0 2.5px oklch(.5 .2 25);
}
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="mythique"] .front::after{
  background:
    linear-gradient(90deg,oklch(.7 .15 88) 0 100%) top/100% 4px no-repeat,
    linear-gradient(90deg,oklch(.7 .15 88) 0 100%) bottom/100% 4px no-repeat,
    linear-gradient(180deg,oklch(.7 .15 88) 0 100%) left/4px 100% no-repeat,
    linear-gradient(180deg,oklch(.7 .15 88) 0 100%) right/4px 100% no-repeat;
  box-shadow:none;
}
/* Il existe déjà une vraie couche foil partagée (.holo, voir plus bas
   "PASSE 3" — Sportifs et France l'utilisent déjà pour leur propre
   déclinaison mythique/épique). Ma première tentative réinventait un
   calque séparé sur .front::after/.art::before, invisible ou décalé du
   rythme existant. On branche plutôt les DEUX raretés dessus, comme les
   autres domaines. */
/* épique : le foil générique tourne déjà (holoTurn, conic-gradient) mais
   en mix-blend-mode:screen — invisible sur notre papier clair (screen
   n'éclaircit que ce qui est déjà sombre). Seul le blend passe en
   multiply pour rester visible ici ; le mouvement/la géométrie restent
   ceux du générique, inchangés. */
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="epique"] .holo{
  mix-blend-mode:multiply;opacity:.6;
}
/* mythique : même bande et même rythme que le foil doré générique
   (foilSlide, hérité tel quel), seule la teinte passe au rouge scanner —
   clin d'œil douchette de caisse cohérent avec le code-barres du pied. */
:is([data-dom="supermarche"] .card,.card[data-dom="supermarche"])[data-rar="mythique"] .holo{
  background:linear-gradient(115deg,transparent 43%,oklch(.6 .22 25/.75) 50%,transparent 57%);
}

.card[data-rar="rare"] .front{box-shadow:0 0 0 1.5px oklch(.86 .04 250/.6),0 18px 50px oklch(0 0 0/.5)}
.card[data-rar="epique"] .front::after,
.card[data-rar="mythique"] .front::after{
  content:"";position:absolute;inset:0;z-index:6;pointer-events:none;border-radius:var(--card-r);
}
.card[data-rar="mythique"] .front::after{
  /* le rai animé vivait ici (background-position, repeint à chaque image) —
     déplacé plus bas sur .holo en transform (composé par le GPU), voir la
     note "derniers balayages convertis en transform". Ne reste ici que
     l'anneau (box-shadow), statique et gratuit. */
  box-shadow:inset 0 0 0 2px oklch(.86 .17 88/.9),inset 0 0 44px oklch(.86 .17 88/.24);
}
/* mythique : l'illustration déborde */
.card[data-rar="mythique"] .art img{transform:scale(1.16)}
.card[data-rar="mythique"] .cardfoot{background:linear-gradient(0deg,var(--surf) 58%,transparent)}
.card[data-rar="mythique"] .art::after{
  background:radial-gradient(ellipse at 50% 36%,transparent 36%,oklch(0 0 0/.62) 100%)}
/* un fond plat (carte "bg" pour logo à fond transparent) n'a pas besoin
   d'un vignettage photo — ça assombrit les coins d'une plaque censée être
   unie, lu comme un bug plutôt qu'un effet. */
.card[data-rar] .art.flat-bg::after{display:none}

/* carte ratée */
.card[data-lost] .front{filter:grayscale(1) brightness(.4) contrast(1.2)}
.card[data-lost] .front::after{display:none}

/* ============================================================
   LE VERSO : question + saisie + chrono
   ============================================================ */
.qside{padding:16px 15px 14px;display:flex;flex-direction:column;height:100%;gap:10px;
  position:relative;z-index:2}
/* voile de lisibilite : juste assez pour que la question tienne sur le fond anime */
.face.back::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(ellipse 85% 60% at 50% 46%,
    color-mix(in oklch,var(--surf),transparent 8%) 30%,
    color-mix(in oklch,var(--surf),transparent 52%) 100%)}
.qhead{display:flex;align-items:center;gap:8px}
.qhead .sp{margin-left:auto}
.qtext{
  font-family:"Zodiak",Georgia,serif;font-weight:700;
  font-size:clamp(1.02rem,4.4cqi,1.22rem);line-height:1.22;
  text-wrap:balance;flex:1;display:flex;align-items:center;
  letter-spacing:-.012em;
}
.qform{position:relative}
.qinput{
  width:100%;padding:11px 12px;
  font-family:"Departure Mono",monospace;font-size:.92rem;letter-spacing:.04em;
  background:var(--elev);box-shadow:inset 0 0 0 1.5px var(--line);
  border-radius:2px;caret-color:var(--acc);
}
.qinput:focus{box-shadow:inset 0 0 0 1.5px var(--acc)}
.qinput::placeholder{color:var(--ink3);opacity:.7}
.sugg{position:absolute;bottom:calc(100% + 6px);left:0;right:0;
  display:flex;flex-direction:column;gap:2px;z-index:9}
.sugg button{
  text-align:left;padding:8px 11px;background:var(--elev);
  font-family:"Departure Mono",monospace;font-size:.8rem;
  box-shadow:inset 0 0 0 1px var(--line);
  transition:background .15s,transform .15s var(--e-out);
}
.sugg button:hover{background:var(--acc);color:var(--bg);transform:translateX(3px)}

/* chrono : anneau, jamais de chiffres */
.ring{width:30px;height:30px;flex:none;transform:rotate(-90deg)}
.ring circle{fill:none;stroke-width:3}
.ring .bg{stroke:var(--line)}
.ring .fg{stroke:var(--acc);stroke-dasharray:81.68;stroke-linecap:butt;
  transition:stroke .3s}
.ring.run .fg{animation:tick var(--dur,30s) linear forwards}
@keyframes tick{from{stroke-dashoffset:0}to{stroke-dashoffset:81.68}}
.ring.warn .fg{stroke:oklch(.68 .22 26)}

/* ============================================================
   LE THÉÂTRE DE LA QUESTION — fonds domaine x rareté
   ============================================================ */
.qbg{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none;border-radius:var(--card-r)}
/* -40% partout coûtait la même surface peinte à toutes les couches pour
   un gain qui ne profitait qu'à une couche en rotation à 360° — aucune
   des couches actuelles ne tourne (translate/scale/opacity seulement),
   donc la marge resserrée suffit partout, sans exception à prévoir. */
.qbg span{position:absolute;inset:-18%;display:block;opacity:var(--op,.3)}
.qbg[data-rar="commune"]{--op:.20;--sp:26s;--amp:1}
.qbg[data-rar="rare"]{--op:.32;--sp:16s;--amp:1.5}
.qbg[data-rar="epique"]{--op:.46;--sp:8s;--amp:2.2}
.qbg[data-rar="mythique"]{--op:.62;--sp:4s;--amp:3.4}

/* — SPORTIFS : lignes de piste qui défilent -> lueur de projecteurs de stade — */
[data-dom="sportifs"] .qbg .l1{
  background-image:repeating-linear-gradient(100deg,oklch(1 0 0/.35) 0 3px,transparent 3px 34px);
  animation:slide var(--sp) linear infinite;
}
[data-dom="sportifs"] .qbg .l2{
  background:radial-gradient(ellipse 70% 45% at 50% 100%,oklch(.78 .15 85/.5),transparent 65%);
  animation:breathe calc(var(--sp)*.6) ease-in-out infinite alternate;
}
/* — FRANCE : poussière dorée -> bande tricolore, jamais de rotation
   (comics avait besoin d'un inset:-30% surdimensionné pour caler un spin,
   on ne reproduit pas ce coût ici) — */
[data-dom="france"] .qbg .l1{
  background-image:radial-gradient(circle,oklch(.9 .1 92/.7) 1.2px,transparent 1.8px);
  background-size:26px 26px;
  animation:floatUp var(--sp) linear infinite;
}
[data-dom="france"] .qbg .l2{
  background:repeating-linear-gradient(90deg,
    oklch(.55 .19 260/.5) 0 8%,oklch(.97 0 0/.4) 8% 16%,oklch(.6 .21 25/.5) 16% 24%);
  animation:slide calc(var(--sp)*.6) linear infinite;
}
/* — SUPERMARCHÉ : code-barres qui défile -> rayons qui montent — */
[data-dom="supermarche"] .qbg .l1{
  background-image:repeating-linear-gradient(90deg,oklch(0 0 0/.55) 0 2px,transparent 2px 6px);
  animation:slide var(--sp) linear infinite;
}
[data-dom="supermarche"] .qbg .l2{
  background:repeating-linear-gradient(0deg,oklch(.86 .18 95/.35) 0 40px,transparent 40px 80px);
  animation:floatUp calc(var(--sp)*.7) linear infinite;
}
/* — POCKET : pixels -> herbes -> arène -> apparition — */
[data-dom="pocket"] .qbg .l1{
  background-image:linear-gradient(oklch(.84 .17 89/.4) 2px,transparent 2px),
                   linear-gradient(90deg,oklch(.84 .17 89/.4) 2px,transparent 2px);
  background-size:18px 18px;
  animation:floatUp var(--sp) linear infinite;
}
[data-dom="pocket"] .qbg .l2{
  background:repeating-linear-gradient(78deg,oklch(.6 .22 29/.45) 0 6px,transparent 6px 26px);
  animation:slide calc(var(--sp)*.5) linear infinite;
}

@keyframes floatUp{to{transform:translate3d(0,-22px,0)}}
@keyframes breathe{to{transform:translate3d(4%,-5%,0) scale(1.2)}}
@keyframes slide{to{transform:translate3d(-26px,0,0)}}

/* la mythique a droit à sa propre catastrophe */
.qbg .l3{display:none}
.qbg[data-rar="mythique"] .l3{display:block;opacity:1}
[data-dom="sportifs"] .qbg[data-rar="mythique"] .l3{
  background:radial-gradient(circle at 50% 42%,oklch(.86 .17 88/.95) 0%,transparent 32%);
  animation:pulse 1.5s var(--e-io) infinite;
}
/* le drapeau ne doit jamais sauter d'un état à l'autre : steps(1) donnait un
   blink brut (bug remonté en test, visible côté question). L'apparition et
   la disparition passent maintenant par --e-io, comme le reste des
   transitions du jeu — même idée de flash que "pulse", juste plus lente et
   sans le hard cut. */
@keyframes bolt{
  0%,70%{opacity:0} 85%{opacity:1} 100%{opacity:0}
}
[data-dom="france"] .qbg[data-rar="mythique"] .l3{
  background:linear-gradient(90deg,oklch(.55 .19 260/.9) 0 32%,oklch(.97 0 0/.9) 32% 68%,oklch(.6 .21 25/.9) 68% 100%);
  animation:bolt 2.6s var(--e-io) infinite;
}
[data-dom="supermarche"] .qbg[data-rar="mythique"] .l3{
  background:radial-gradient(circle at 50% 45%,oklch(.86 .18 95/.9) 0%,transparent 30%);
  animation:pulse 1.3s var(--e-io) infinite;
}
[data-dom="pocket"] .qbg[data-rar="mythique"] .l3{
  background:radial-gradient(circle at 50% 45%,oklch(1 0 0/.9) 0%,transparent 26%);
  animation:pulse 1.7s var(--e-io) infinite;
}
@keyframes pulse{0%,100%{transform:scale(.6);opacity:0}50%{transform:scale(1.5);opacity:.85}}

/* ============================================================
   IMPACT FRAMES
   ============================================================ */
#impact{position:absolute;inset:0;z-index:60;pointer-events:none;opacity:0}
#impact.go{animation:impactFlash .34s steps(1) forwards}
@keyframes impactFlash{
  0%{opacity:0;background:oklch(1 0 0)}
  6%{opacity:1;background:oklch(1 0 0)}
  22%{opacity:1;background:oklch(1 0 0)}      /* freeze-frame ~110ms */
  30%{opacity:.25;background:var(--acc)}
  55%{opacity:.55;background:oklch(1 0 0)}
  100%{opacity:0}
}
#impact.soft{animation-duration:.2s}
#speed{position:absolute;inset:-30%;z-index:59;pointer-events:none;opacity:0;
  background:repeating-conic-gradient(from 0deg at 50% 50%,
    oklch(1 0 0/.55) 0deg 1.1deg,transparent 1.1deg 5deg)}
#speed.go{animation:speedIn .42s var(--e-out) forwards}
@keyframes speedIn{
  0%{opacity:.85;transform:scale(.35)}
  100%{opacity:0;transform:scale(1.5)}
}

/* ============================================================
   COLLECTION
   ============================================================ */
#s-coll{overflow:hidden}
.collscroll{flex:1;overflow-y:auto;overscroll-behavior:contain;padding-bottom:24px}
.collscroll::-webkit-scrollbar{width:0}
.sect{padding:20px 0 8px;position:relative}
.secthd{display:flex;align-items:center;gap:9px;padding-bottom:12px;position:sticky;top:0;
  background:linear-gradient(var(--bg) 62%,transparent);z-index:3;padding-top:6px}
.sectname{font-family:"Boldonse",Impact,sans-serif;font-size:1.05rem;text-transform:uppercase;letter-spacing:-.02em}
.count{font-family:"Departure Mono",monospace;font-size:var(--t-label);color:var(--ink2);letter-spacing:.1em}
.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}
.mini{
  aspect-ratio:63/88;border-radius:5px;overflow:hidden;position:relative;
  background:var(--elev);box-shadow:inset 0 0 0 1px var(--line);
  animation:popIn .5s var(--e-out) both;animation-delay:calc(var(--i)*28ms);
}
@keyframes popIn{from{opacity:0;transform:translateY(14px) scale(.94)}}
.mini img{width:100%;height:100%;object-fit:cover}
.mini.owned[data-r="epique"]{box-shadow:inset 0 0 0 1.5px oklch(.78 .17 300/.8)}
.mini.owned[data-r="mythique"]{box-shadow:inset 0 0 0 2px oklch(.84 .17 88/.9)}
.mini .num{position:absolute;left:3px;bottom:2px;font-family:"Departure Mono",monospace;
  font-size:.5rem;color:oklch(1 0 0/.8);text-shadow:0 1px 3px oklch(0 0 0/.9);letter-spacing:.06em}
.mini .dup{position:absolute;right:3px;top:3px;background:var(--acc);color:var(--bg);
  font-family:"Departure Mono",monospace;font-size:.5rem;padding:1px 3px;border-radius:2px}
/* silhouette : la carte ratée reste visible, et vide */
.mini.miss{display:grid;place-items:center;background:
  repeating-linear-gradient(45deg,transparent 0 5px,var(--line) 5px 6px)}
.mini.miss img{display:none}
.mini.miss .seal{width:40%;height:40%;opacity:.3;color:var(--ink3)}
.mini.miss .num{color:var(--ink3);text-shadow:none}

/* ============================================================
   DIVERS
   ============================================================ */
.center{display:grid;place-items:center;flex:1;text-align:center;gap:18px}
.hint{font-size:var(--t-label);color:var(--ink3);font-family:"Departure Mono",monospace;
  letter-spacing:.12em;text-transform:uppercase;animation:blink 2.4s ease-in-out infinite}
@keyframes blink{0%,100%{opacity:.35}50%{opacity:1}}
.progress{display:flex;gap:3px;padding-bottom:12px}
.progress i{flex:1;height:2px;background:var(--line);display:block}
.progress i.done{background:var(--ink3)}
.progress i.win{background:var(--acc)}
.progress i.now{background:var(--ink)}


/* ============================================================
   LA SCÈNE DE LA QUESTION
   Le verso est toujours sombre et saturé, même quand le domaine
   a une coque claire : sinon les effets ne se voient pas, et le
   moment perd sa tension.
   ============================================================ */
[data-dom="sportifs"]{--q-bg:oklch(.16 .045 250);--q-ink:oklch(.97 .015 90)}
[data-dom="france"]{--q-bg:oklch(.2 .06 258);--q-ink:oklch(.97 .02 260)}
[data-dom="supermarche"]{--q-bg:oklch(.18 .02 35);--q-ink:oklch(.97 .02 35)}
[data-dom="pocket"]{--q-bg:oklch(.215 .05 58);--q-ink:oklch(.97 .02 86)}

.face.back{background:var(--q-bg);color:var(--q-ink)}
.face.back::before{
  background:radial-gradient(ellipse 92% 64% at 50% 46%,
    color-mix(in oklch,var(--q-bg),transparent 26%) 34%,
    color-mix(in oklch,var(--q-bg),transparent 64%) 100%);
}
.qtext{color:var(--q-ink)}
.qinput{background:oklch(0 0 0/.36);color:var(--q-ink);
  box-shadow:inset 0 0 0 1.5px oklch(1 0 0/.2)}
.qinput::placeholder{color:oklch(1 0 0/.42)}
.qinput:focus{box-shadow:inset 0 0 0 1.5px var(--acc)}
.sugg button{background:oklch(.14 .02 264/.94);color:var(--q-ink);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.18)}
.ring .bg{stroke:oklch(1 0 0/.18)}

/* intensités relevées : sur fond sombre on peut enfin pousser */
.qbg[data-rar="commune"]{--op:.30;--sp:26s}
.qbg[data-rar="rare"]{--op:.44;--sp:16s}
.qbg[data-rar="epique"]{--op:.60;--sp:8s}
.qbg[data-rar="mythique"]{--op:.78;--sp:4s}

/* même correctif que la première définition de bolt plus haut : cette
   redéfinition (override verso sombre) reproduisait le même hard cut. */
@keyframes bolt{
  0%,70%{opacity:0} 85%{opacity:1} 100%{opacity:0}
}


/* la réponse trouvée signe l'illustration, comme à la main sur une vignette */
.ink{
  position:absolute;left:13px;bottom:11px;z-index:5;
  font-size:.95rem;line-height:1;
  color:oklch(.99 .03 92/.96);
  text-shadow:0 1px 2px oklch(0 0 0/.9),0 6px 18px oklch(0 0 0/.7);
  transform:rotate(-3.4deg);transform-origin:left bottom;
  min-height:0;
}
.ink:empty{display:none}

/* signature du contributeur — coin opposé à .ink pour ne jamais se
   chevaucher avec la main qui écrit le nom */
.credit{
  position:absolute;right:9px;bottom:9px;z-index:5;
  width:24px;height:24px;border-radius:50%;
  background:oklch(0 0 0/.55);
  box-shadow:0 1px 3px oklch(0 0 0/.6),inset 0 0 0 1px oklch(1 0 0/.22);
  display:grid;place-items:center;
}
.credit[hidden]{display:none}
.credit img{width:19px;height:19px;object-fit:contain;display:block}
.credit img[hidden]{display:none}
.credit span{
  font-family:'Boldonse',Impact,sans-serif;font-size:.68rem;
  color:oklch(.97 .01 90);line-height:1;
}


/* le pied de carte reste propre sous les traitements */
.cardfoot{position:relative;z-index:7}


/* chaque domaine occupe une bande plein-format : jamais deux domaines
   mélangés dans une même grille */
.collscroll{margin-inline:-18px;padding-inline:0}
.sect{padding:18px 18px 22px;background:var(--bg);color:var(--ink);margin:0}
.sect+.sect{box-shadow:0 -1px 0 oklch(0 0 0/.35)}
.secthd{background:linear-gradient(var(--bg) 68%,transparent);padding-top:8px;top:-1px}
.sect .sectname{color:var(--ink)}
.sect .count{color:var(--ink2)}


/* ════════════════════════════════════════════════════════════
   PASSE 2 — retours de François
   ════════════════════════════════════════════════════════════ */

/* ---- le nom du deck survolé, en header, dans SA police ---- */
.deckname{
  min-height:1.35em;
  font-family:var(--dom-font);letter-spacing:var(--dom-tracking);
  font-size:clamp(1.25rem,7cqi,2.05rem);line-height:1.05;
  text-transform:uppercase;color:var(--acc);text-align:center;
  transition:opacity .25s var(--e-out);
}
.deckname:empty::after{content:"\00a0"}
/* France : même souci que .cname (voir plus haut) — Playwrite est une
   cursive, la mettre en capitales la rend illisible et bien plus large.
   data-dom est posé ICI directement sur #deckname (index.html ~L630), pas
   sur un ancêtre — sélecteur sur le même composé, pas de descendant. */
.deckname[data-dom="france"]{text-transform:none;letter-spacing:0}

/* ---- 4 decks vus de la tranche, en profondeur ---- */
.spines{
  flex:1;display:flex;align-items:center;justify-content:center;
  gap:clamp(7px,2.6cqi,16px);
  perspective:1100px;perspective-origin:50% 44%;
  padding:12px 0;
}
.spine{
  position:relative;overflow:hidden;cursor:pointer;
  width:clamp(48px,13.5cqi,70px);
  height:calc(clamp(200px,44cqi,300px) * var(--hh));
  border-radius:3px 7px 7px 3px;
  color:var(--p-ink);
  background:linear-gradient(100deg,
    color-mix(in oklch,var(--p-bg),black 42%) 0 8%,
    var(--p-bg) 8% 64%,
    color-mix(in oklch,var(--p-bg),black 28%) 100%);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.16),-10px 18px 34px oklch(0 0 0/.55);
  transform:rotateY(-26deg) translateZ(calc(var(--i) * -7px)) translateY(calc(var(--i) * 5px - 8px));
  transition:transform .5s var(--e-back),box-shadow .4s var(--e-out),filter .4s;
}
.spine .edge{position:absolute;left:0;top:0;bottom:0;width:8px;
  background:linear-gradient(90deg,oklch(1 0 0/.55),oklch(1 0 0/0))}
.spine .sseal{
  position:absolute;left:52%;top:44%;width:200%;height:auto;aspect-ratio:1;
  transform:translate(-50%,-50%) rotate(90deg);
  opacity:.26;color:currentColor;pointer-events:none;
}
.spine .stag{
  position:absolute;left:50%;bottom:13px;max-height:76%;overflow:hidden;
  writing-mode:vertical-rl;transform:translateX(-50%) rotate(180deg);
  font-family:"Departure Mono",monospace;font-size:clamp(.5rem,1.9cqi,.63rem);
  letter-spacing:.2em;text-transform:uppercase;opacity:.75;white-space:nowrap;
}
.spine:hover,.spine:focus-visible{
  outline:none;
  transform:rotateY(-8deg) translateZ(48px) translateY(-18px);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.34),-16px 32px 58px oklch(0 0 0/.66);
}
.spine[data-off]{filter:grayscale(.85) brightness(.46);cursor:default}
.spine[data-off]:hover{transform:rotateY(-26deg) translateZ(calc(var(--i) * -7px)) translateY(calc(var(--i) * 5px - 8px));
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.16),-10px 18px 34px oklch(0 0 0/.55)}
.spine[data-taken]{box-shadow:inset 0 0 0 2px var(--acc),-10px 18px 34px oklch(0 0 0/.55)}
.spine[data-dead]{animation:destroy .66s var(--e-expo-io) forwards;pointer-events:none}
.spine[data-chosen]{animation:chosen .66s var(--e-expo-io) forwards;z-index:5}

/* ---- la carte : 35:50, cadre franc ---- */
.card{--w:min(336px,82cqi);aspect-ratio:35/50}
.cardfront{
  padding:var(--frame);
  display:flex;flex-direction:column;gap:clamp(7px,2cqi,10px);
  background:linear-gradient(168deg,var(--elev),var(--surf));
  --frame:clamp(9px,2.6cqi,14px);
}
.art{border-radius:4px}
.art::after{
  background:
    linear-gradient(180deg,oklch(0 0 0/.58) 0%,transparent 36%),
    radial-gradient(ellipse at 50% 44%,transparent 48%,oklch(0 0 0/.44) 100%);
}
.cardfoot{background:none;box-shadow:none;padding:0 2px 1px;gap:5px}

/* le titre : en haut à gauche, grand, manuscrit — c'est LUI le nom de la carte */
.ink{
  position:absolute;left:0;right:12%;top:0;bottom:auto;
  padding:clamp(9px,2.9cqi,15px) clamp(11px,3.4cqi,17px) clamp(4px,1.4cqi,8px);
  font-size:clamp(1.2rem,6.6cqi,1.95rem);line-height:1.18;
  white-space:normal;text-align:left;overflow:visible;
  hyphens:auto;overflow-wrap:break-word;
  transform:rotate(-2.6deg);transform-origin:left top;
  color:oklch(.99 .028 92/.97);
  text-shadow:0 2px 4px oklch(0 0 0/.9),0 10px 28px oklch(0 0 0/.75);
  z-index:6;
}
/* variante demandée par carte (titlepos:"bottom" dans cards.csv) — un
   portrait qui occupe le haut de l'image préfère la signature en bas. */
.ink.bottom{
  top:auto;bottom:0;
  padding:clamp(4px,1.4cqi,8px) clamp(11px,3.4cqi,17px) clamp(9px,2.9cqi,15px);
  transform-origin:left bottom;
}
/* France : .cardfoot est passé en overlay absolu (voir plus haut) et
   chevauche désormais le bas de .art — sans ce décalage, une signature
   "bottom" atterrit exactement sous l'étiquette et les deux se mélangent. */
[data-dom="france"] .ink.bottom{bottom:70px}
/* pied : ligne de type + rareté + numéro, tout en plus grand */
.cname{font-size:clamp(.8rem,3.2cqi,.98rem);opacity:.9;line-height:1.1}
.rar{font-size:clamp(.66rem,2.7cqi,.82rem);letter-spacing:.2em}
.cno{font-size:clamp(.62rem,2.5cqi,.76rem)}
.dot{width:7px;height:7px}
.crow{gap:9px}

/* la mythique déborde du cadre */
.card[data-rar="mythique"] .art{
  margin:calc(-1 * var(--frame)) calc(-1 * var(--frame)) 0;
  border-radius:var(--card-r) var(--card-r) 4px 4px;
}

/* ---- le dos : sceau à 80%, qui respire ---- */
.cardback .seal-lg{width:80%;height:auto;aspect-ratio:1;opacity:.5;
  animation:sealPulse 3s var(--e-io) infinite}
@keyframes sealPulse{
  0%,100%{transform:scale(1);opacity:.4}
  50%{transform:scale(1.075);opacity:.74}
}

/* ---- la question prend la police du deck, et se centre ---- */
.qside{justify-content:space-between}
.qtext{
  font-family:var(--dom-font);letter-spacing:var(--dom-tracking);
  font-weight:400;text-align:center;justify-content:center;
  align-self:center;max-width:96%;
  font-size:clamp(1rem,5cqi,1.32rem);line-height:1.24;
}
[data-dom="pocket"] .qtext{font-size:clamp(.86rem,4.3cqi,1.12rem);line-height:1.42}
[data-dom="sportifs"] .qtext{font-family:'Space Mono',"Zodiak",Georgia,serif;font-weight:700}
/* Abril Fatface est un display à fort contraste — illisible sur un
   paragraphe de question, on retombe sur le serif de corps déjà chargé */
[data-dom="france"] .qtext{font-family:"Zodiak",Georgia,serif;font-weight:400;font-style:italic}
/* Abril Fatface (--dom-font du deck) reste réservé au nom/signature — sur
   un paragraphe de question entier, ce display à fort contraste est
   illisible (même limite que France plus haut, cause du commentaire
   d'origine sur Abril). */
[data-dom="supermarche"] .qtext{
  font-family:"Zodiak",Georgia,serif;font-size:clamp(1rem,5cqi,1.28rem);line-height:1.28;
}

/* ---- la face qui n'est pas tournée vers nous n'intercepte rien ----
   (sans ça, les clics tombant sur la moitié basse du recto étaient
   avalés par le champ de saisie du verso, invisible mais présent) */
.card:not(.flip) .face.back{pointer-events:none}
.card.flip .face.front{pointer-events:none}

/* France : une pointe tricolore qui bat en éventail à côté de la signature
   manuscrite — se greffe sur le déclencheur ".write" déjà posé en JS pour
   la réussite, aucun nouvel état à gérer côté script. */
[data-dom="france"] .ink::after{
  content:"";position:absolute;left:calc(100% + 8px);top:.15em;width:16px;height:11px;
  background:linear-gradient(90deg,oklch(.55 .19 260) 0 33%,oklch(.97 0 0) 33% 66%,oklch(.6 .21 25) 66% 100%);
  box-shadow:0 1px 3px oklch(0 0 0/.5);opacity:0;transform-origin:left center;
}
[data-dom="france"] .ink.write::after{animation:flagWave .5s var(--e-back) .15s both}
@keyframes flagWave{
  0%{opacity:0;transform:scaleX(0) rotate(0deg)}
  45%{opacity:1;transform:scaleX(1) rotate(-10deg)}
  70%{transform:scaleX(1) rotate(8deg)}
  100%{opacity:1;transform:scaleX(1) rotate(0deg)}
}

/* France : sur un échec, une lame tricolore balaie la carte juste avant
   qu'elle ne parte comme d'habitude — surcouche sur ".vanish", pas un
   remplacement (le reste du jeu garde le même comportement). */
[data-dom="france"] .card.guillotine::before{
  content:"";position:absolute;left:-8%;right:-8%;top:-16%;height:5px;z-index:20;
  background:linear-gradient(90deg,oklch(.55 .19 260),oklch(.97 0 0),oklch(.6 .21 25));
  box-shadow:0 0 14px 2px oklch(1 1 1/.65);
  animation:guillotineBlade .5s var(--e-io) forwards;
}
@keyframes guillotineBlade{to{top:106%}}

/* ---- l'échec : la carte est détruite, la réponse n'est jamais donnée ---- */
.card.vanish{animation:vanish .64s var(--e-expo-io) forwards;pointer-events:none}
@keyframes vanish{
  0%{opacity:1;filter:none}
  12%{filter:brightness(3.4) saturate(0)}
  28%{transform:rotateY(180deg) scale(.96) rotate(-2deg);filter:brightness(.22) grayscale(1)}
  100%{transform:rotateY(180deg) translateY(52px) scale(.8) rotate(-8deg);
       opacity:0;filter:grayscale(1) brightness(.18)}
}

/* ---- BUG ÉPIQUE : le mix-blend-mode sur la face avant cassait le
   preserve-3d de la carte, donc backface-visibility ne masquait plus
   le recto et la question restait invisible. Le blend est déplacé
   DANS l'illustration, dans un groupe isolé, où il ne peut plus
   contaminer la composition 3D de la carte. ---- */
.card[data-rar="epique"] .front::after,
.card[data-rar="epique"] .front::before{content:none;background:none;mix-blend-mode:normal;
  -webkit-mask-image:none;mask-image:none}
.card[data-rar="epique"] .front{box-shadow:0 0 0 1.5px oklch(.8 .18 300/.7),0 18px 50px oklch(0 0 0/.5)}

.art{isolation:isolate}
.holo{display:none;position:absolute;inset:0;z-index:4;pointer-events:none}
.card[data-rar="epique"] .holo{
  display:block;
  -webkit-mask-image:radial-gradient(ellipse 74% 58% at 50% 44%,transparent 24%,#000 96%);
  mask-image:radial-gradient(ellipse 74% 58% at 50% 44%,transparent 24%,#000 96%);
}


/* tranches plus hautes, et une ombre au sol pour asseoir la profondeur */
.spine{height:calc(clamp(238px,56cqi,340px) * var(--hh))}
.spines{position:relative}
.spines::after{
  content:"";position:absolute;left:50%;top:50%;translate:-50% 0;
  width:min(78%,340px);height:26px;margin-top:calc(clamp(238px,56cqi,340px) * .5);
  background:radial-gradient(ellipse 50% 50% at 50% 50%,oklch(0 0 0/.6),transparent 72%);
  filter:blur(7px);pointer-events:none;
}


/* les tranches méritent plus de présence, et les sceaux plus de lisibilité */
.spine{height:calc(clamp(280px,66cqi,400px) * var(--hh));
  width:clamp(54px,15cqi,78px)}
.spines::after{margin-top:calc(clamp(280px,66cqi,400px) * .5);width:min(84%,380px)}
.spine .sseal{opacity:.34;width:215%}
.spine .stag{font-size:clamp(.52rem,2.1cqi,.68rem)}
/* un peu plus de matière dans l'eau */
body::before{opacity:.9}


/* cadre plus franc, et le pied profite enfin de la place gagnée */
.cardfront{--frame:clamp(12px,3.6cqi,19px)}
.cname{font-size:clamp(.92rem,3.9cqi,1.18rem);opacity:.95;letter-spacing:.01em}
.rar{font-size:clamp(.74rem,3.1cqi,.94rem);letter-spacing:.22em}
.cno{font-size:clamp(.7rem,2.9cqi,.88rem)}
.dot{width:8px;height:8px}
.cardfoot{gap:6px;padding:6px 11px 9px}


body::before{
  opacity:1;
  background:
    radial-gradient(ellipse 66% 44% at 18% 10%,color-mix(in oklch,var(--acc),transparent 66%),transparent 64%),
    radial-gradient(ellipse 60% 48% at 86% 72%,color-mix(in oklch,var(--acc2),transparent 68%),transparent 64%),
    radial-gradient(ellipse 90% 60% at 50% 118%,color-mix(in oklch,var(--abyss),transparent 10%),transparent 70%),
    linear-gradient(180deg,transparent 22%,color-mix(in oklch,var(--abyss),transparent 34%) 100%);
}


/* ════════════════════════════════════════════════════════════
   PASSE 3 — quatre logos animés + booster 3D au survol,
   et une mer qui ne s'arrête jamais de bouger
   ════════════════════════════════════════════════════════════ */

/* ---- LA MER : toujours en mouvement, de plus en plus agitée ----
   --fx pilote la vitesse et l'amplitude. 0 = calme plat,
   3 = houle (mythique, ou série de réussites). */
:root{--fx-sp:1;--fx-op:.5;--fx-amp:1}
[data-fx="1"]{--fx-sp:.7;--fx-op:.66;--fx-amp:1.5}
[data-fx="2"]{--fx-sp:.46;--fx-op:.82;--fx-amp:2.2}
[data-fx="3"]{--fx-sp:.28;--fx-op:1;--fx-amp:3.2}

#sea{position:fixed;inset:-25%;z-index:0;pointer-events:none;overflow:hidden;
  transition:opacity .8s var(--e-io)}
#sea span{position:absolute;inset:-10%;display:block;will-change:transform}
/* courants profonds */
#sea .c1{
  background:
    radial-gradient(ellipse 44% 30% at 30% 26%,color-mix(in oklch,var(--acc),transparent 74%),transparent 66%),
    radial-gradient(ellipse 38% 26% at 74% 62%,color-mix(in oklch,var(--acc2),transparent 72%),transparent 66%);
  /* filter:blur() retiré ici (voir PASSE 4 plus bas, qui repasse en
     filter:none) : plein écran + transform animé pour toujours, donc
     reflouté à chaque image indéfiniment tant qu'un écran est ouvert. */
  opacity:var(--fx-op);
  animation:seaDrift calc(38s * var(--fx-sp)) ease-in-out infinite alternate;
}
/* houle : bandes obliques lentes */
#sea .c2{
  background:repeating-linear-gradient(112deg,
    color-mix(in oklch,var(--acc),transparent 92%) 0 2px,
    transparent 2px 46px);
  opacity:calc(var(--fx-op) * .8);
  animation:seaSwell calc(26s * var(--fx-sp)) linear infinite;
}
/* caustiques : lumière qui tremble à la surface */
#sea .c3{
  background:repeating-conic-gradient(from 0deg at 50% 42%,
    color-mix(in oklch,var(--acc),transparent 93%) 0deg 1.6deg,transparent 1.6deg 9deg);
  /* filter:blur() retiré ici aussi — voir PASSE 4, qui remplace même ce
     fond par un second courant radial (déjà doux, jamais flouté). */
  opacity:calc(var(--fx-op) * .55);
  animation:seaTurn calc(90s * var(--fx-sp)) linear infinite;
}
/* particules qui remontent */
#sea .c4{
  background-image:radial-gradient(circle,color-mix(in oklch,var(--acc),transparent 62%) 1.2px,transparent 1.6px);
  background-size:88px 88px;
  opacity:calc(var(--fx-op) * .5);
  animation:seaRise calc(22s * var(--fx-sp)) linear infinite;
}
@keyframes seaDrift{
  to{transform:translate3d(calc(2.2% * var(--fx-amp)),calc(-2.6% * var(--fx-amp)),0) scale(1.09)}}
@keyframes seaSwell{
  to{transform:translate3d(calc(-46px * var(--fx-amp)),calc(18px * var(--fx-amp)),0)}}
@keyframes seaTurn{to{transform:rotate(360deg)}}
@keyframes seaRise{to{transform:translate3d(0,-88px,0)}}
/* houle forte : la coque elle-même roule très légèrement */
[data-fx="3"] #app{animation:hull 7s ease-in-out infinite alternate}
@keyframes hull{to{transform:translate3d(0,-3px,0) rotate(.22deg)}}

/* ---- L'ÉCRAN DE CHOIX : 4 logos, et le booster en 3D au survol ---- */
.spines,.spine{all:unset}                       /* on abandonne les tranches */
.decks{
  flex:1;display:grid;grid-template-columns:repeat(4,1fr);
  align-items:center;gap:clamp(4px,1.6cqi,10px);
  perspective:900px;perspective-origin:50% 46%;
}
.deck{
  position:relative;display:grid;place-items:center;
  aspect-ratio:3/4;cursor:pointer;background:none;border:0;
  transform-style:preserve-3d;
}
.deck .dseal{
  width:74%;height:auto;aspect-ratio:1;color:var(--p-bg);
  filter:drop-shadow(0 6px 18px oklch(0 0 0/.6));
  transition:opacity .34s var(--e-out),transform .44s var(--e-out);
}
.deck[data-dom="sportifs"] .dseal{animation:idleSportifs 1.7s var(--e-out) infinite}
.deck[data-dom="france"]   .dseal{animation:idleFrance 7s var(--e-io) infinite}
.deck[data-dom="supermarche"]   .dseal{animation:idleSupermarche 2.2s steps(4) infinite}
.deck[data-dom="pocket"]   .dseal{animation:idlePocket 1.9s steps(8) infinite}
/* battement de cœur : montée franche, redescente, pause — le tempo d'un
   effort physique, pas une simple respiration comme les autres decks */
@keyframes idleSportifs{0%,100%{transform:scale(1)}14%{transform:scale(1.12)}28%{transform:scale(1)}40%{transform:scale(1.07)}55%,100%{transform:scale(1)}}
@keyframes idleFrance{0%,100%{transform:rotate(-2deg)}50%{transform:rotate(2deg)}}
@keyframes idleSupermarche{0%,100%{opacity:1;transform:translate3d(0,0,0)}50%{opacity:.55;transform:translate3d(0,-3%,0)}}
@keyframes idlePocket{0%,100%{transform:translate3d(0,4%,0)}50%{transform:translate3d(0,-6%,0)}}

/* le booster, en volume, qui monte au survol */
.boost{
  position:absolute;inset:0;display:grid;place-items:center;
  opacity:0;pointer-events:none;transform-style:preserve-3d;
  transition:opacity .32s var(--e-out);
}
.bx{
  position:relative;width:64%;aspect-ratio:7/10;transform-style:preserve-3d;
  transform:rotateY(-28deg) rotateX(9deg) scale(.72);
  transition:transform .55s var(--e-back);
}
.bf{
  position:absolute;inset:0;transform:translateZ(7px);border-radius:4px;overflow:hidden;
  display:grid;place-items:center;
  background:linear-gradient(152deg,
    color-mix(in oklch,var(--p-bg),white 18%) 0%,var(--p-bg) 44%,
    color-mix(in oklch,var(--p-bg),black 38%) 100%);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.3),0 20px 38px oklch(0 0 0/.66);
}
.bf::after{                                    /* rai de foil sur l'emballage */
  content:"";position:absolute;inset:0;
  /* fond/animation posés plus bas (.boostzone.on .bf::after, en transform) */
}
.bf .bseal{width:76%;height:auto;aspect-ratio:1;color:var(--p-ink);opacity:.9}
.bs{
  position:absolute;top:0;bottom:0;right:0;width:14px;border-radius:0 4px 4px 0;
  transform-origin:right center;transform:rotateY(90deg) translateZ(7px);
  background:linear-gradient(180deg,
    color-mix(in oklch,var(--p-bg),black 26%),color-mix(in oklch,var(--p-bg),black 58%));
}
.deck:hover .boost,.deck:focus-visible .boost{opacity:1}
.deck:hover .bx,.deck:focus-visible .bx{
  transform:rotateY(-20deg) rotateX(7deg) scale(1) translateZ(30px);
  animation:boostFloat 3.2s var(--e-io) infinite alternate;
}
@keyframes boostFloat{
  from{transform:rotateY(-22deg) rotateX(7deg) scale(1) translateZ(30px) translateY(0)}
  to{transform:rotateY(-13deg) rotateX(4deg) scale(1.03) translateZ(38px) translateY(-9px)}
}
.deck:hover .dseal,.deck:focus-visible .dseal{opacity:0;transform:scale(1.3)}
.deck:focus-visible{outline:none}

.deck[data-off]{cursor:default}
.deck[data-off] .dseal{color:var(--ink3);opacity:.34;animation-play-state:paused}
.deck[data-off]:hover .dseal{opacity:.34;transform:none}
.deck[data-off]:hover .boost{opacity:0}
.deck[data-taken] .dseal{color:var(--acc)}
.deck .dtag{
  position:absolute;bottom:2px;left:0;right:0;text-align:center;
  font-family:"Departure Mono",monospace;font-size:clamp(.44rem,1.7cqi,.56rem);
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink3);
}
.deck[data-dead]{animation:destroy .66s var(--e-expo-io) forwards;pointer-events:none}
.deck[data-chosen]{animation:chosen .66s var(--e-expo-io) forwards;z-index:5}


/* les logos prennent de la place, et le booster sort du rang au survol */
.decks{gap:clamp(2px,1cqi,8px);align-items:center}
.deck{aspect-ratio:auto;height:clamp(132px,38cqi,210px)}
.deck .dseal{width:92%}
.deck:hover,.deck:focus-visible{z-index:6}
.bx{width:88%}
.deck:hover .bx,.deck:focus-visible .bx{
  transform:rotateY(-20deg) rotateX(7deg) scale(1.42) translateZ(46px);
}
@keyframes boostFloat{
  from{transform:rotateY(-23deg) rotateX(8deg) scale(1.4) translateZ(44px) translateY(0)}
  to{transform:rotateY(-12deg) rotateX(4deg) scale(1.48) translateZ(56px) translateY(-11px)}
}
.bf .bseal{width:70%}
.dtag{bottom:-4px}


/* le booster se lève AU-DESSUS de la rangée : les icônes descendent
   pour lui laisser la place */
.decks{
  align-items:end;
  padding-top:clamp(150px,44cqi,252px);
  padding-bottom:clamp(8px,3.5cqi,24px);
  perspective:1000px;perspective-origin:50% 34%;
}
.boost{
  position:absolute;inset:auto auto calc(100% + 14px) 50%;
  translate:-50% 0;
  width:clamp(114px,33cqi,172px);aspect-ratio:7/10;
  display:grid;place-items:center;
}
.bx{width:100%;transform:rotateY(-26deg) rotateX(9deg) scale(.8)}
.deck:hover .bx,.deck:focus-visible .bx{
  transform:rotateY(-19deg) rotateX(7deg) scale(1) translateZ(24px);
}
@keyframes boostFloat{
  from{transform:rotateY(-22deg) rotateX(8deg) scale(1) translateZ(22px) translateY(0)}
  to{transform:rotateY(-11deg) rotateX(4deg) scale(1.04) translateZ(34px) translateY(-12px)}
}
/* une ombre portée au sol, sous le booster suspendu */
.boost::after{
  content:"";position:absolute;left:50%;top:calc(100% + 6px);translate:-50% 0;
  width:62%;height:16px;border-radius:50%;
  background:radial-gradient(ellipse 50% 50% at 50% 50%,oklch(0 0 0/.62),transparent 72%);
  filter:blur(5px);
}


/* ---- le booster flotte au-dessus de la rangée, centré sur elle ---- */
.boostzone{
  position:relative;display:grid;place-items:center;flex:none;
  height:clamp(158px,46cqi,262px);
  perspective:1000px;perspective-origin:50% 46%;
  opacity:0;pointer-events:none;
  transition:opacity .3s var(--e-out);
}
.boostzone.on{opacity:1}
.boostzone .bx{
  width:clamp(120px,34cqi,178px);aspect-ratio:7/10;position:relative;transform-style:preserve-3d;
  transform:rotateY(-24deg) rotateX(8deg) scale(.9);
  transition:transform .5s var(--e-back);
}
.boostzone.on .bx{animation:boostFloat 3.2s var(--e-io) infinite alternate}
.boostzone::after{
  content:"";position:absolute;left:50%;bottom:6px;translate:-50% 0;
  width:clamp(84px,24cqi,128px);height:16px;border-radius:50%;
  background:radial-gradient(ellipse 50% 50% at 50% 50%,oklch(0 0 0/.6),transparent 72%);
  filter:blur(6px);opacity:0;transition:opacity .3s;
}
.boostzone.on::after{opacity:1}
@keyframes boostFloat{
  from{transform:rotateY(-24deg) rotateX(8deg) scale(1) translateY(0)}
  to{transform:rotateY(-12deg) rotateX(4deg) scale(1.05) translateY(-13px)}
}
/* la rangée reprend sa place, sans réserve au-dessus */
.decks{padding-top:0;padding-bottom:clamp(8px,3.5cqi,24px);align-items:center;flex:none;
  height:clamp(120px,34cqi,190px)}
.deck{height:100%}
.deck .boost{display:none}


/* l'icône survolée reste visible et se soulève : c'est le booster
   au-dessus qui prend le relais, pas elle qui s'efface */
.deck:hover .dseal,.deck:focus-visible .dseal{
  opacity:1;transform:translateY(-7px) scale(1.1);
  filter:drop-shadow(0 12px 22px oklch(0 0 0/.7)) brightness(1.18);
}
.deck[data-off]:hover .dseal{transform:none;filter:none;opacity:.34}
/* le groupe booster + icônes est centré dans la colonne */
.boostzone{margin-top:auto}
.decks{margin-bottom:auto}


/* ════════════════════════════════════════════════════════════
   PASSE 4 — performance + fond unifié
   ════════════════════════════════════════════════════════════ */

/* 1. UN SEUL FOND, CONTINU.
   La colonne n'a plus de fond ni de liseré : la mer traverse toute
   la page, il n'y a plus une zone « dehors » et une zone « dedans ». */
#app{background:none;box-shadow:none}
body::before{display:none}            /* doublon de #sea : supprimé */

/* 2. PERFORMANCE.
   Plus AUCUN filter:blur animé, ni gradient conique tournant, ni
   propriété custom animée dans un dégradé : ces trois-là forcent une
   rastérisation complète à chaque image. Tout passe par transform et
   opacity, seules propriétés réellement composées par le GPU.
   Les dégradés radiaux sont déjà doux : ils n'ont pas besoin de flou. */
#sea{inset:0;contain:strict}
#sea span{inset:-16%;will-change:transform;backface-visibility:hidden}

#sea .c1{
  filter:none;
  background:
    radial-gradient(ellipse 46% 34% at 28% 22%,color-mix(in oklch,var(--acc),transparent 72%),transparent 70%),
    radial-gradient(ellipse 40% 30% at 76% 66%,color-mix(in oklch,var(--acc2),transparent 70%),transparent 70%),
    radial-gradient(ellipse 80% 46% at 50% 106%,color-mix(in oklch,var(--abyss),transparent 20%),transparent 72%);
  opacity:var(--fx-op);
  animation:seaDrift calc(38s * var(--fx-sp)) ease-in-out infinite alternate;
}
#sea .c2{
  background:repeating-linear-gradient(112deg,
    color-mix(in oklch,var(--acc),transparent 94%) 0 2px,transparent 2px 52px);
  opacity:calc(var(--fx-op) * .7);
  animation:seaSwell calc(26s * var(--fx-sp)) linear infinite;
}
/* les caustiques coniques floutées coûtaient trop cher : remplacées par
   un second courant radial, qui tourne en transform (donc composé) */
#sea .c3{
  filter:none;
  background:radial-gradient(ellipse 34% 22% at 62% 34%,
    color-mix(in oklch,var(--acc),transparent 82%),transparent 72%);
  opacity:calc(var(--fx-op) * .7);
  animation:seaTurn calc(120s * var(--fx-sp)) linear infinite;
}
#sea .c4{
  background-image:radial-gradient(circle,color-mix(in oklch,var(--acc),transparent 66%) 1.2px,transparent 1.6px);
  background-size:96px 96px;
  opacity:calc(var(--fx-op) * .42);
  animation:seaRise calc(22s * var(--fx-sp)) linear infinite;
}

/* 3. L'HOLO ÉPIQUE tournait via une propriété custom animée dans un
   conic-gradient : repeinte intégrale à chaque image, sous un blend et
   un masque. Le dégradé est désormais figé et c'est la couche qui
   tourne — une rotation, ça se compose. */
.card[data-rar="epique"] .holo{
  background:conic-gradient(from 0deg,
    oklch(.8 .2 20/.5),oklch(.85 .2 90/.5),oklch(.85 .2 160/.5),
    oklch(.8 .2 240/.5),oklch(.82 .2 320/.5),oklch(.8 .2 20/.5));
  inset:-30%;
  will-change:transform;
  animation:holoTurn 8s linear infinite;
}
@keyframes holoTurn{to{transform:rotate(360deg)}}

/* 4. les fonds de question restent dans la carte, pas au-delà */
.qbg span{inset:-18%}

/* 5. sur mouvement réduit, la mer s'arrête complètement */
@media (prefers-reduced-motion:reduce){
  #sea span{animation:none}
}


/* ---- la mer prend les couleurs du deck survolé ----
   Une couche dédiée dont seule l'opacité s'anime : le dégradé n'est
   rastérisé qu'au changement de couleur, jamais image par image. */
#sea .tint{
  opacity:0;transition:opacity .45s var(--e-out);
  background:
    radial-gradient(ellipse 58% 40% at 28% 24%,color-mix(in oklch,var(--tint,transparent),transparent 52%),transparent 72%),
    radial-gradient(ellipse 50% 36% at 76% 70%,color-mix(in oklch,var(--tint2,transparent),transparent 60%),transparent 72%);
  animation:seaDrift calc(32s * var(--fx-sp)) ease-in-out infinite alternate;
}
#sea.tinted .tint{opacity:1}

/* ---- le booster gagne en hauteur et le bloc se recentre ---- */
.boostzone{height:clamp(196px,55cqi,318px)}
.boostzone .bx{width:clamp(142px,40cqi,214px);aspect-ratio:7/10.4}
.boostzone::after{width:clamp(96px,27cqi,146px)}
/* le groupe booster + icônes est centré dans l'espace restant */
.boostzone{margin-top:auto;margin-bottom:0}
.decks{margin-top:0;margin-bottom:auto}


/* ---- derniers balayages convertis en transform ----
   `background-position` repeint la surface à chaque image ; une
   translation est composée par le GPU. Le foil mythique tourne donc
   sur la couche .holo (le rai du booster suit juste en dessous). */
.card[data-rar="mythique"] .holo{
  display:block;inset:-45%;will-change:transform;
  background:linear-gradient(115deg,transparent 43%,oklch(.96 .12 88/.45) 50%,transparent 57%);
  animation:foilSlide 3.8s var(--e-io) infinite;
  mix-blend-mode:normal;opacity:1;
  -webkit-mask-image:none;mask-image:none;
}
@keyframes foilSlide{0%,62%{transform:translate3d(-72%,0,0)}100%{transform:translate3d(72%,0,0)}}
/* SPORTIFS : trois ratés avant celle-ci — toujours UN SEUL calque animé
   (fond en grille, fond en défilé, puis des groupes de box-shadow). Même
   avec 3 groupes à des délais différents, chaque groupe restait 8-9
   points qui clignotent PILE ensemble (ils partagent un seul élément/
   animation) — encore perceptible comme "ça pulse par paquets", pas
   "chaque particule a son timer". Le CSS pur plafonne à 3 calques
   indépendants (l'élément + ::before + ::after) ; pour un VRAI timer par
   particule il faut un vrai élément par particule. D'où de vraies
   balises <i> injectées par JS (voir card-render.js/applySparkle),
   chacune avec sa propre durée + délai aléatoires en style inline. */
[data-dom="sportifs"] .card[data-rar="epique"] .holo{
  /* le générique tournait sur lui-même (holoTurn, cf. plus haut) — jamais
     annulé ici, donc les particules (ses enfants) tournaient WITH it.
     will-change reste inutile aussi une fois qu'on n'anime plus rien ici. */
  background:none;-webkit-mask-image:none;mask-image:none;
  opacity:1;mix-blend-mode:normal;position:absolute;inset:0;
  animation:none;will-change:auto;
}
[data-dom="sportifs"] .card[data-rar="epique"] .holo i{
  position:absolute;width:4.5px;height:4.5px;border-radius:50%;
  mix-blend-mode:screen;opacity:0;
  left:var(--x);top:var(--y);background:var(--c);
  animation:sparkleDot var(--dur,2.4s) ease-in-out infinite;
  animation-delay:var(--delay,0s);
}
@keyframes sparkleDot{0%,100%{opacity:0}50%{opacity:1}}
[data-dom="sportifs"] .card[data-rar="mythique"] .holo{
  background:linear-gradient(115deg,
    transparent 34%,
    #0081c8 40% 46%,#fcb131 46% 52%,#00a651 52% 58%,#ee334e 58% 64%,
    transparent 66%);
  mix-blend-mode:screen;
  opacity:.85;
}
/* FRANCE : même foil à bandes que les JO ci-dessus, en bleu-blanc-rouge. Trois
   bandes au lieu de quatre, donc plus larges (7% contre 6%) pour que le rai
   garde la même emprise. Tout est hérité de .card[data-rar="mythique"] .holo :
   on ne redéfinit que la peinture, le balayage reste le foilSlide générique en
   transform. Les tokens sont STATIQUES ici — une propriété personnalisée dans
   un dégradé ne coûte que si on l'anime, ce qu'on ne fait pas. */
[data-dom="france"] .card[data-rar="mythique"] .holo{
  background:linear-gradient(115deg,
    transparent 36%,
    var(--acc) 42% 49%,oklch(.95 .01 260/.62) 49% 56%,var(--acc2) 56% 63%,
    transparent 69%);
  mix-blend-mode:screen;
  /* La bande BLANCHE porte son propre alpha, en plus de l'opacité du calque :
     en `screen` un blanc plein vire au blanc pur et effaçait complètement le
     visage à mi-course. Les deux bandes colorées, elles, restent pleines —
     c'est le même équilibre que les JO, où aucune teinte n'est aussi claire. */
  opacity:.78;
}

.bf::after{animation:none;opacity:0;transition:opacity .3s}
.boostzone.on .bf::after{
  opacity:1;background:linear-gradient(115deg,transparent 42%,oklch(1 0 0/.42) 50%,transparent 58%);
  background-size:auto;width:260%;left:-80%;right:auto;
  animation:foilSlide 3.4s var(--e-io) infinite;
}


/* ---- QUIZZ traverse la palette des quatre domaines ----
   Cinq teintes, chacune tenue puis fondue vers la suivante.
   `color` sur trois lettres : repeinture minuscule, aucun coût. */
@keyframes quizzCycle{
   0%, 13%{color:oklch(.8 .13 191)}    /* écume — la coque neutre */
  20%, 33%{color:oklch(.76 .15 74)}    /* or       — Dieux Antiques */
  40%, 53%{color:oklch(.82 .16 88)}    /* jaune    — Pokémon 151    */
  60%, 73%{color:oklch(.62 .18 260)}   /* bleu     — Rois & Présidents */
  80%, 93%{color:oklch(.86 .18 95)}    /* code-barres — Supermarchés */
 100%     {color:oklch(.8 .13 191)}
}
#s-title .logo .l2{
  animation:quizzCycle 13s cubic-bezier(.65,0,.35,1) infinite;
}


/* ---- le booster est dimensionné PAR SA HAUTEUR ----
   En le dimensionnant par la largeur, sa hauteur (ratio 7/10.4)
   dépassait celle de sa zone : il débordait sur la rangée d'icônes
   et n'était donc jamais centré. */
.pickstage{
  flex:1;min-height:0;display:flex;flex-direction:column;
  justify-content:flex-start;padding-top:clamp(6px,2.4cqi,22px);
  gap:clamp(4px,1.6cqi,14px);
}
.boostzone{
  /* marge auto en haut : avec la marge auto symétrique de .decks plus bas,
     l'espace libre de .pickstage se répartit des deux côtés, ce qui centre
     le deck+son nom entre le titre et la rangée de sceaux. */
  margin:auto 0 0;flex:none;
  height:clamp(200px,54cqi,320px);
}
.boostzone .bx{
  height:88%;width:auto;aspect-ratio:7/10.4;
}
/* la rangée de sceaux descend vers le tiers inférieur de l'écran (zone
   naturelle du pouce sur mobile) plutôt que de coller sous le deck 3D —
   une marge auto absorbe l'espace flexible restant dans .pickstage. */
.decks{margin:auto 0 0;flex:none;padding-bottom:0}
.boostzone::after{bottom:2px}


/* ════════════════════════════════════════════════════════════
   PASSE 5 — compatibilité Firefox
   ════════════════════════════════════════════════════════════ */

/* 1. L'écriture manuscrite passait par une propriété custom enregistrée
   (@property) interpolée dans un clip-path. Firefox ne l'a supportée que
   tardivement : sans elle, l'animation saute au lieu de balayer.
   On anime désormais `clip-path` directement — compris partout. */
.ink{clip-path:inset(0 100% 0 0)}
.ink.write{animation:inkWrite .6s var(--e-io) forwards}
@keyframes inkWrite{
  from{clip-path:inset(0 100% 0 0)}
  to  {clip-path:inset(0 0 0 0)}
}

/* 2. `contain:strict` inclut la containment de TAILLE, ce qui peut faire
   collapser un élément dimensionné par ses insets. On garde seulement
   ce qui sert à isoler le rendu. */
#sea{contain:layout paint style}

/* 3. L'holo épique reste en blend mais dans un groupe explicitement isolé,
   et jamais sur une face 3D (cf. le bug de la carte épique). */
.art{isolation:isolate}
.card[data-rar="epique"] .holo{mix-blend-mode:screen;opacity:.5}


/* ════════════════════════════════════════════════════════════
   PASSE 6 — rythme des animations
   ════════════════════════════════════════════════════════════ */

/* QUIZZ change de couleur plus souvent */
#s-title .logo .l2{animation-duration:8s}

/* le retournement doit durer exactement FLIP_MS côté JS */
.card{transition:transform .6s var(--e-io)}

/* Les deux couches d'impact partaient ensemble mais ne duraient pas
   pareil (.34s contre .42s), d'où le décalage. Elles sont désormais
   calées sur la même durée, avec un pic blanc net puis une retombée. */
#impact.go{animation:impactFlash .4s linear forwards}
#impact.soft{animation-duration:.26s}
@keyframes impactFlash{
  0%  {opacity:0;background:oklch(1 0 0)}
  4%  {opacity:1;background:oklch(1 0 0)}
  26% {opacity:1;background:oklch(1 0 0)}   /* arrêt sur image */
  34% {opacity:.5;background:var(--acc)}
  62% {opacity:.22;background:oklch(1 0 0)}
  100%{opacity:0}
}
#speed.go{animation:speedIn .4s var(--e-out) forwards}

/* ---- la carte gagnée descend, la suivante remonte ---- */
.cardwrap{perspective:1400px;display:grid;place-items:center}
.cardwrap.tuck{animation:cardTuck .32s var(--e-in) forwards}
.cardwrap.rise{animation:cardRise .46s var(--e-back) both}
@keyframes cardTuck{
  from{transform:translate3d(0,0,0) scale(1);opacity:1}
  to  {transform:translate3d(0,42%,0) scale(.88);opacity:0}
}
@keyframes cardRise{
  from{transform:translate3d(0,38%,0) scale(.9);opacity:0}
  to  {transform:translate3d(0,0,0) scale(1);opacity:1}
}


/* ════════════════════════════════════════════════════════════
   PASSE 7
   ════════════════════════════════════════════════════════════ */

/* 1. LE TREMBLEMENT ÉTAIT ÉCRASÉ.
   `[data-fx="3"] #app{animation:hull}` avait la même spécificité que
   `#app.shake` et venait après : passer en fx 3 juste après l'impact
   tuait le tremblement, qui rejouait 1,6 s plus tard quand fx
   redescendait — donc APRÈS l'écriture. La houle de fond part sur la
   mer, plus sur la colonne : plus aucun conflit. */
[data-fx="3"] #app{animation:none}
[data-fx="3"] #sea{animation:hull 7s ease-in-out infinite alternate}

/* 2. SURIMPRESSION DE LA FACE AVANT (Firefox).
   `backface-visibility` n'est pas honoré ici : la face avant
   transparaissait en miroir derrière la question. On masque
   explicitement la face qui tourne le dos, avec un délai calé sur la
   moitié du retournement — soit l'instant précis où elle est de champ,
   donc invisible de toute façon. */
.face{transition:visibility 0s linear .3s}
.card:not(.flip) .face.back{visibility:hidden}
.card.flip .face.front{visibility:hidden}


/* ---- bordure de la face arrière ----
   Même épaisseur que le cadre du recto, sombre, mais teintée par la
   rareté : la couleur est dérivée de --r-ink assombrie, donc elle suit
   automatiquement commune / rare / épique / mythique. */
.card{--frame:clamp(12px,3.6cqi,19px)}
.face.back{
  border:var(--frame) solid color-mix(in oklch,var(--r-ink),black 80%);
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.07),0 18px 50px oklch(0 0 0/.5);
}


/* ════════════════════════════════════════════════════════════
   LOT 2 — LE DUEL
   ════════════════════════════════════════════════════════════ */

/* ---- entrée en duel, depuis la collection ---- */
.collfoot{display:flex;flex-wrap:wrap;gap:8px;padding-top:10px;flex:none}
.collfoot .btn{flex:1;padding:13px 12px;font-size:.92rem}
/* Un 3e bouton (le chantier ligues, ajouté aux deux emplacements qui avaient
   déjà "Défier les Pafs" / "Défier un ami") passe sur sa propre ligne, pleine
   largeur : à deux, les libellés tenaient à 50% chacun ; à trois répartis en
   1/3, "Ligues (expérimental)" débordait de son bouton sur un écran de
   téléphone (375px). Générique par position plutôt que par id, pour rester
   correct si un futur 3e bouton apparaît ailleurs. */
.collfoot .btn:nth-child(3):last-child{flex-basis:100%}
.btn[disabled]{opacity:.3;cursor:default;pointer-events:none}
#duel-entry[hidden]{display:none !important}

/* ---- POSER SA MISE : cinq emplacements fixes ---- */
.slots{
  flex:none;display:grid;grid-template-columns:repeat(5,1fr);
  gap:clamp(4px,1.6cqi,9px);
  padding:clamp(8px,2.6cqi,14px) 0 2px;
}
.slot{
  aspect-ratio:35/50;border-radius:5px;position:relative;
  box-shadow:inset 0 0 0 1.5px var(--line);
  background:color-mix(in oklch,var(--surf),transparent 55%);
  transition:box-shadow .25s var(--e-out);
}
.slot.filled{box-shadow:inset 0 0 0 1.5px color-mix(in oklch,var(--acc),transparent 40%)}
.slot .pc{position:absolute;inset:0;animation:slotDrop .42s var(--e-back) both}
@keyframes slotDrop{
  from{transform:translate3d(0,-46px,0) scale(.82) rotate(-8deg);opacity:0}
  to  {transform:translate3d(0,0,0) scale(1) rotate(var(--tilt,0deg));opacity:1}
}
.slots.locked .slot .pc{animation:slotSnap .3s var(--e-expo-io) both}
@keyframes slotSnap{to{transform:none}}
/* dans la grille, une carte déjà misée s'efface */
#stake-grid .mini.staked{opacity:.22;filter:grayscale(1)}
#stake-grid .mini.miss{pointer-events:none}
#stake-grid .mini.owned{cursor:pointer}

/* ---- DOS DE CARTE EMPILABLE (piles, emplacements, vol) ---- */
.pc{
  border-radius:5px;overflow:hidden;display:grid;place-items:center;
  color:var(--pi,oklch(.96 .01 240));
  background:
    repeating-linear-gradient(45deg,transparent 0 5px,oklch(1 0 0/.08) 5px 10px),
    linear-gradient(160deg,color-mix(in oklch,var(--pb,var(--elev)),black 24%),var(--pb,var(--elev)));
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.2),0 5px 12px oklch(0 0 0/.55);
}
.pc svg{width:54%;height:auto;aspect-ratio:1;opacity:.55}

/* ---- LA TABLE ---- */
#s-duel{gap:2px}
.foe,.me{display:flex;align-items:center;gap:9px;flex:none;padding:2px 0}
.me{justify-content:flex-end}
.avatar{width:26px;height:26px;color:var(--acc);flex:none}
.foename{
  font-family:"Boldonse",Impact,sans-serif;font-size:clamp(.86rem,3.6cqi,1.05rem);
  text-transform:uppercase;letter-spacing:-.01em;
}
.pilecount{font-size:clamp(1rem,4.4cqi,1.3rem);color:var(--acc)}
.foe.busy .avatar{animation:foeThink .9s var(--e-io) infinite alternate}
@keyframes foeThink{to{opacity:.35;transform:scale(.92)}}

/* deux paquets posés à plat, en perspective */
.pilezone{flex:none;display:grid;place-items:center;perspective:900px}
.pilezone.top{height:clamp(56px,15cqi,84px);perspective-origin:50% 10%}
.pilezone.bottom{height:clamp(66px,18cqi,98px);perspective-origin:50% 90%}
.pile{
  position:relative;width:clamp(58px,16cqi,84px);aspect-ratio:35/50;
  transform-style:preserve-3d;
}
.pilezone.top .pile{transform:rotateX(64deg) scale(.84)}
.pilezone.bottom .pile{transform:rotateX(-64deg)}
.pile .pc{
  position:absolute;inset:0;
  transform:translateZ(calc(var(--k) * 3.4px))
            translate(calc(var(--dx) * 1px),calc(var(--dy) * 1px))
            rotate(calc(var(--rz) * 1deg));
  animation:pileLand .34s var(--e-back) both;
}
@keyframes pileLand{from{opacity:0;transform:translateZ(calc(var(--k) * 3.4px)) scale(1.3)}}
.pile:empty::after{
  content:"";position:absolute;inset:0;border-radius:5px;
  box-shadow:inset 0 0 0 1.5px var(--line);
}

/* le centre : carte active, pioches et chrono */
.tablemid{flex:1;min-height:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:clamp(6px,2cqi,12px)}
.tablemid .cardwrap{flex:1;min-height:0;display:grid;place-items:center;width:100%}
#d-card{--w:min(292px,74cqi)}
.decks2{display:flex;align-items:center;gap:clamp(10px,4cqi,22px);flex:none}
.deckstub{
  width:clamp(30px,8.5cqi,44px);aspect-ratio:35/50;border-radius:4px;position:relative;
  box-shadow:inset 0 0 0 1.5px var(--line);
  background:color-mix(in oklch,var(--surf),transparent 40%);
  transition:opacity .3s;
}
.deckstub[data-n="0"]{opacity:.22}
.deckstub::after{
  content:attr(data-n);position:absolute;inset:0;display:grid;place-items:center;
  font-family:"Departure Mono",monospace;font-size:clamp(.6rem,2.4cqi,.75rem);
  color:var(--ink2);
}
.ring.big{width:clamp(38px,11cqi,52px);height:clamp(38px,11cqi,52px)}
.ring.big .fg{stroke-dasharray:119.38;stroke-width:3.4}
.ring.big.run .fg{animation:tickBig var(--dur,90s) linear forwards}
@keyframes tickBig{from{stroke-dashoffset:0}to{stroke-dashoffset:119.38}}

/* la carte qui vole du centre vers une pile */
.flyer{position:absolute;inset:0;pointer-events:none;z-index:40}
.flyer .pc{position:absolute;will-change:transform}

/* ---- HOULE MAXIMALE (fx 4) ----
   Le roulis va sur la table, JAMAIS sur #app : `#app.shake` et une règle
   `[data-fx] #app{animation}` ont la même spécificité, et la seconde
   écraserait le tremblement d'impact (bug déjà payé au lot 1). */
[data-fx="4"]{--fx-sp:.17;--fx-op:1;--fx-amp:4.6}
[data-fx="4"] #sea{animation:hull 3.2s ease-in-out infinite alternate}
[data-fx="4"] .tablemid{animation:tableRoll 4.6s ease-in-out infinite alternate}
@keyframes tableRoll{
  from{transform:rotate(-.45deg) translate3d(0,0,0)}
  to  {transform:rotate(.45deg) translate3d(0,-5px,0)}
}
.ring.big.warn .fg{stroke:oklch(.68 .22 26)}

/* ---- LE BUTIN ---- */
.spoilstage{flex:1;min-height:0;display:grid;place-items:center;position:relative}
.spoilcard{
  --w:min(300px,76cqi);width:var(--w);aspect-ratio:35/50;position:relative;
  border-radius:var(--card-r);overflow:hidden;
  display:flex;flex-direction:column;padding:var(--frame);
  gap:clamp(7px,2cqi,10px);
  background:linear-gradient(168deg,var(--elev),var(--surf));
  box-shadow:0 18px 50px oklch(0 0 0/.55);
}
.spoilcard.in{animation:spoilSlam .34s var(--e-expo-io) both}
.spoilcard.out{animation:spoilOut .3s var(--e-in) both}
.spoilcard.lost{animation:spoilTorn .5s var(--e-expo-io) both}
@keyframes spoilSlam{
  from{transform:scale(1.5) rotate(-4deg);opacity:0}
  60% {transform:scale(.97) rotate(.6deg);opacity:1}
  to  {transform:none;opacity:1}
}
@keyframes spoilOut{to{transform:translate3d(0,-30px,0) scale(.94);opacity:0}}
@keyframes spoilTorn{
  0%  {transform:none;opacity:1;filter:grayscale(1) brightness(.55)}
  18% {transform:translate3d(-7px,0,0) rotate(-1.5deg);filter:grayscale(1) brightness(2.4)}
  100%{transform:translate3d(140%,44px,0) rotate(15deg) scale(.8);opacity:0;
       filter:grayscale(1) brightness(.28)}
}
.spoilcard .art{flex:1;min-height:0;border-radius:4px}
.spoilcard .cardfoot{background:none;box-shadow:none;padding:0 2px 1px}


/* ════════════════════════════════════════════════════════════
   LOT 2 — passe 2 (retours François)
   ════════════════════════════════════════════════════════════ */

/* 1. LES PAQUETS PRENNENT DE LA PLACE */
.pilezone{position:relative}
.pilezone.top{height:clamp(78px,21cqi,112px)}
.pilezone.bottom{height:clamp(90px,24cqi,128px)}
.pile{width:clamp(80px,23cqi,116px)}
.pile .pc{transform:translateZ(calc(var(--k) * 4.2px))
          translate(calc(var(--dx) * 1px),calc(var(--dy) * 1px))
          rotate(calc(var(--rz) * 1deg))}
@keyframes pileLand{from{opacity:0;transform:translateZ(calc(var(--k) * 4.2px)) scale(1.3)}}
#d-card{--w:min(268px,70cqi)}

/* 2. L'ADVERSAIRE N'EST PAS UN TITRE DE PAGE.
   Étiquette de joueur, discrète, en mono — pas une display de header. */
.foe,.me{gap:8px;padding:0}
.foename{
  font-family:"Departure Mono",ui-monospace,monospace;
  font-size:clamp(.66rem,2.7cqi,.8rem);
  letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink2);font-weight:400;
}
.avatar{width:19px;height:19px;color:var(--ink2)}
.foe.busy .avatar{color:var(--acc)}
.pilecount{font-size:clamp(1.15rem,5cqi,1.5rem);color:var(--acc);line-height:1}

/* 3. LA CARTE QUE L'ADVERSAIRE EXAMINE.
   Sans ça, on ne comprend pas qu'il travaille sur une de NOS cartes. */
.exam{
  position:absolute;left:9%;top:50%;translate:0 -50%;
  width:clamp(44px,12.5cqi,62px);aspect-ratio:35/50;
  opacity:0;transition:opacity .3s var(--e-out);pointer-events:none;
}
.exam.on{opacity:1}
.exam .pc{
  width:100%;height:100%;
  animation:examPeek 1.15s var(--e-io) infinite alternate;
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.28),
             0 6px 16px oklch(0 0 0/.6),
             0 0 0 2px color-mix(in oklch,var(--acc),transparent 55%);
}
@keyframes examPeek{
  from{transform:rotate(-9deg) translateY(0) scale(1)}
  to  {transform:rotate(-4deg) translateY(-6px) scale(1.06)}
}
.exam.giveback .pc{animation:examBack .38s var(--e-in) forwards}
@keyframes examBack{to{transform:translateY(46px) rotate(4deg) scale(.8);opacity:0}}

/* 4. MA PIOCHE EST VIDE : la carte se retire, on regarde l'adversaire finir */
.cardwrap.spent{animation:cardTuck .32s var(--e-in) forwards}
.tablemid.waiting .decks2{animation:waitPulse 1.6s ease-in-out infinite alternate}
@keyframes waitPulse{to{opacity:.55}}

/* 5. LE RÉCAPITULATIF FINAL — l'écran ne se termine plus sur du vide */
.recap{
  width:100%;display:flex;flex-direction:column;gap:clamp(10px,3cqi,18px);
  padding:0 2px;animation:recapIn .5s var(--e-out) both;
}
@keyframes recapIn{from{opacity:0;transform:translateY(18px)}}
.recaprow{display:flex;flex-direction:column;gap:7px}
.recaphd{display:flex;align-items:baseline;gap:9px}
.recaplabel{
  font-family:"Departure Mono",monospace;font-size:clamp(.6rem,2.5cqi,.74rem);
  letter-spacing:.2em;text-transform:uppercase;color:var(--ink3);
}
.recapn{
  font-family:"Boldonse",Impact,sans-serif;font-size:clamp(1.4rem,6.5cqi,2rem);
  line-height:1;margin-left:auto;
}
.recaprow.win .recapn{color:var(--acc)}
.recaprow.loss .recapn{color:oklch(.64 .2 26)}
.recapgrid{display:grid;grid-template-columns:repeat(5,1fr);gap:6px}
.recapgrid .rc{
  aspect-ratio:35/50;border-radius:4px;overflow:hidden;position:relative;
  background:var(--elev);box-shadow:inset 0 0 0 1px var(--line);
  animation:popIn .42s var(--e-out) both;animation-delay:calc(var(--i) * 55ms);
}
.recapgrid .rc img{width:100%;height:100%;object-fit:cover;display:block}
.recaprow.win .rc{box-shadow:inset 0 0 0 1.5px color-mix(in oklch,var(--acc),transparent 45%)}
.recaprow.loss .rc img{filter:grayscale(1) brightness(.45)}
.recaprow:empty,.recaprow.vide{display:none}
.spoilstage{align-items:center}


/* ---- CORRECTION DE PERSPECTIVE ----
   Les deux paquets reposent sur LA MÊME table : ils s'inclinent donc dans
   le même sens. Mon paquet était en rotateX négatif, donc retourné à
   l'envers. Ce qui distingue le proche du lointain, c'est l'échelle et la
   position dans le cadre, jamais le signe de la rotation. */
.pilezone{perspective:820px;perspective-origin:50% 50%}
.pilezone.top .pile{transform:rotateX(58deg) scale(.78)}
.pilezone.bottom .pile{transform:rotateX(58deg) scale(1.18)}

/* assez grands pour qu'on lise le volume */
.pile{width:clamp(96px,27cqi,138px)}
.pile .pc{transform:translateZ(calc(var(--k) * 5px))
          translate(calc(var(--dx) * 1px),calc(var(--dy) * 1px))
          rotate(calc(var(--rz) * 1deg))}
@keyframes pileLand{from{opacity:0;transform:translateZ(calc(var(--k) * 5px)) scale(1.3)}}
.pilezone.top{height:clamp(84px,23cqi,118px)}
.pilezone.bottom{height:clamp(104px,28cqi,146px)}
/* le liseré du paquet vide suit la même inclinaison */
.pile:empty::after{box-shadow:inset 0 0 0 2px var(--line)}


/* le paquet proche débordait de sa zone et se faisait couper par
   l'overflow de la colonne : on tempère l'échelle et on lui donne l'air */
.pilezone.bottom .pile{transform:rotateX(58deg) scale(1.04)}
.pilezone.bottom{height:clamp(112px,30cqi,150px)}
.pilezone.top{height:clamp(88px,24cqi,124px)}
#d-card{--w:min(250px,66cqi)}
.me{padding-top:2px}


/* pendant l'attente, la carte ne laisse pas un trou : le chrono et les
   pioches remontent au centre de la table, et la carte examinée par
   l'adversaire prend de l'ampleur — c'est lui qu'on regarde maintenant */
.tablemid.waiting .cardwrap{flex:0 0 0;height:0;overflow:visible}
.tablemid.waiting .decks2{gap:clamp(14px,5cqi,28px)}
.tablemid.waiting .ring.big{width:clamp(56px,16cqi,76px);height:clamp(56px,16cqi,76px)}


/* ---- L'ÉTAT D'ATTENTE, SANS ANIMATION ----
   `height:0` + `overflow:hidden` + `opacity:0` : la carte ne peut plus
   peindre, quoi qu'il arrive aux animations. */
.tablemid.waiting .cardwrap{
  flex:0 0 0;height:0;overflow:hidden;opacity:0;pointer-events:none;
  transition:opacity .22s var(--e-out);
}

/* ---- LA TABLE EN PERSPECTIVE ----
   Un vrai sol qui fuit vers un horizon, comme sur une table de TCG en 3D.
   C'est lui qui installe l'espace : sans plan de référence, deux paquets
   inclinés dans le vide ne se lisent pas comme de la profondeur. */
.floor{
  position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0;
  perspective:460px;perspective-origin:50% 20%;
}
.floor .grid3d{
  position:absolute;left:-80%;right:-80%;top:19%;bottom:-80%;
  transform-origin:50% 0%;transform:rotateX(75deg);
  background:
    repeating-linear-gradient(90deg,color-mix(in oklch,var(--acc),transparent 82%) 0 1px,transparent 1px 54px),
    repeating-linear-gradient(0deg,color-mix(in oklch,var(--acc),transparent 86%) 0 1px,transparent 1px 54px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 16%,#000 72%,transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 16%,#000 72%,transparent 100%);
}
/* la ligne d'horizon : c'est elle qui vend la profondeur */
.floor .glow{
  position:absolute;left:-25%;right:-25%;top:11%;height:20%;
  background:
    radial-gradient(ellipse 52% 100% at 50% 100%,color-mix(in oklch,var(--acc),transparent 74%),transparent 72%),
    linear-gradient(to bottom,transparent 78%,color-mix(in oklch,var(--acc),transparent 62%) 96%,transparent 100%);
}
/* tout le jeu passe devant le sol — la carte tirée masque la table */
#s-duel .foe,#s-duel .me,#s-duel .pilezone,#s-duel .tablemid,#s-duel .flyer{
  position:relative;z-index:1;
}
#s-duel .flyer{position:absolute;z-index:40}
/* la carte active projette son ombre sur le sol : elle est POSÉE dessus */
#d-card .face{box-shadow:0 26px 46px oklch(0 0 0/.66),0 6px 14px oklch(0 0 0/.5)}


/* l'horizon doit passer AU-DESSUS du paquet adverse, sinon celui-ci
   flotte dans le ciel au lieu d'être posé sur la table */
.floor{perspective:430px;perspective-origin:50% 8%}
.floor .grid3d{
  top:7%;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 12%,#000 74%,transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 12%,#000 74%,transparent 100%);
  background:
    repeating-linear-gradient(90deg,color-mix(in oklch,var(--acc),transparent 86%) 0 1px,transparent 1px 54px),
    repeating-linear-gradient(0deg,color-mix(in oklch,var(--acc),transparent 90%) 0 1px,transparent 1px 54px);
}
.floor .glow{
  top:0;height:13%;
  background:
    radial-gradient(ellipse 46% 100% at 50% 100%,color-mix(in oklch,var(--acc),transparent 76%),transparent 74%),
    linear-gradient(to bottom,transparent 72%,color-mix(in oklch,var(--acc),transparent 66%) 95%,transparent 100%);
}


/* ════════════════════════════════════════════════════════════
   LA TABLE — UN SEUL ESPACE 3D
   Le sol et les deux paquets partagent désormais LE MÊME plan :
   même perspective, même rotation. C'est la seule façon d'obtenir des
   cartes réellement parallèles aux lignes de fuite — auparavant le sol
   était en perspective 430px/75deg et les paquets en 820px/58deg, donc
   dans deux espaces incompatibles.
   ════════════════════════════════════════════════════════════ */
.table3d{
  position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0;
  perspective:460px;perspective-origin:50% 3%;
}
.table3d .plane{
  position:absolute;left:50%;top:12%;
  width:1300px;margin-left:-650px;height:440px;
  transform-origin:50% 0%;transform:rotateX(74deg);
  transform-style:preserve-3d;
}
.plane .grid3d{
  position:absolute;inset:0;
  background:
    repeating-linear-gradient(90deg,color-mix(in oklch,var(--acc),transparent 84%) 0 1px,transparent 1px 54px),
    repeating-linear-gradient(0deg,color-mix(in oklch,var(--acc),transparent 88%) 0 1px,transparent 1px 54px);
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 9%,#000 78%,transparent 100%);
  mask-image:linear-gradient(to bottom,transparent 0,#000 9%,#000 78%,transparent 100%);
}
/* l'horizon reste hors du plan, strictement AU-DESSUS du paquet lointain */
.table3d .glow{
  position:absolute;left:-25%;right:-25%;top:0;height:15%;z-index:1;
  background:
    radial-gradient(ellipse 44% 100% at 50% 100%,color-mix(in oklch,var(--acc),transparent 74%),transparent 74%),
    linear-gradient(to bottom,transparent 74%,color-mix(in oklch,var(--acc),transparent 64%) 96%,transparent 100%);
}

/* les paquets sont POSÉS dans le plan : ils héritent donc de son
   inclinaison et s'alignent d'eux-mêmes sur les lignes de fuite */
.plane .pile{
  position:absolute;left:50%;margin-left:-78px;
  width:156px;aspect-ratio:35/50;
  transform-style:preserve-3d;transform:none;
}
.plane .pile.far{top:26px}      /* loin : juste sous l'horizon */
.plane .pile.near{top:268px}    /* près du joueur */
.plane .pile .pc{
  position:absolute;inset:0;
  transform:translateZ(calc(var(--k) * 6px))
            translate(calc(var(--dx) * 1px),calc(var(--dy) * 1px))
            rotate(calc(var(--rz) * 1deg));
  animation:pileLand .34s var(--e-back) both;
}
@keyframes pileLand{from{opacity:0;transform:translateZ(calc(var(--k) * 6px)) scale(1.25)}}
.plane .pile:empty::after{
  content:"";position:absolute;inset:0;border-radius:6px;
  box-shadow:inset 0 0 0 2px var(--line);
}

/* la carte examinée par l'adversaire reste DROITE et au-dessus de
   l'horizon : c'est une carte qu'il tient en main, pas posée sur la table */
#s-duel .exam{
  position:absolute;left:5%;top:4%;translate:none;
  width:clamp(52px,15cqi,74px);aspect-ratio:35/50;z-index:2;
}

/* la question doit se LIRE : plus grande, et bien au-dessus de la table */
#s-duel{gap:0}
#s-duel .foe{flex:none;padding:2px 0 0;min-height:24px;z-index:3}
#s-duel .tablemid{flex:1;min-height:0;justify-content:center;z-index:2}
#d-card{--w:min(304px,82cqi)}
#s-duel .me{flex:none;padding:0 0 2px;z-index:3}
#s-duel .decks2{margin-top:auto}


/* recalibrage : avec perspective:460px le paquet proche arrivait
   pratiquement sur la caméra (mesuré à 6066px de large). On éloigne le
   point de vue et on raccourcit la profondeur du plan. */
.table3d{perspective:1000px;perspective-origin:50% 10%}
.table3d .plane{top:14%;height:400px;width:1100px;margin-left:-550px;
  transform:rotateX(70deg)}
.plane .pile{width:132px;margin-left:-66px}
.plane .pile.far{top:14px}
.plane .pile.near{top:236px}
.plane .grid3d{
  background:
    repeating-linear-gradient(90deg,color-mix(in oklch,var(--acc),transparent 86%) 0 1px,transparent 1px 44px),
    repeating-linear-gradient(0deg,color-mix(in oklch,var(--acc),transparent 90%) 0 1px,transparent 1px 44px);
}


/* profondeur réelle : le plan est long, les paquets sont à ses deux bouts.
   Le lointain est petit et juste sous l'horizon, le proche est grand et
   près du joueur — c'est la perspective qui produit l'écart de taille,
   plus aucune mise à l'échelle manuelle. */
.table3d{perspective:1000px;perspective-origin:50% 10%}
.table3d .plane{top:14%;height:700px;width:1400px;margin-left:-700px;
  transform:rotateX(70deg)}
.table3d .glow{top:0;height:12%}
.plane .pile{width:96px;margin-left:-48px}
.plane .pile.far{top:70px}
.plane .pile.near{top:560px}
/* la carte se centre franchement : elle masque la table, c'est voulu */
#s-duel .decks2{margin-top:0}
.tablemid{gap:clamp(8px,2.6cqi,16px)}


/* le paquet proche débordait sous la colonne : on le recule un peu
   sur le plan (il reste le plus grand des deux, c'est la perspective
   qui s'en charge) */
.plane .pile{width:88px;margin-left:-44px}
.plane .pile.near{top:462px}
.plane .pile.far{top:64px}


/* mon paquet était intégralement caché derrière la carte : on l'avance
   vers le joueur pour qu'il dépasse sous elle — on doit voir sa propre
   pile grossir */
.plane .pile.near{top:534px}


/* le paquet adverse remonte : il doit rester visible entre l'horizon et
   le haut de la carte, sinon on ne voit pas non plus SA pile grossir */
.plane .pile.far{top:38px}
.tablemid{padding-top:clamp(6px,2cqi,14px)}


/* la table était construite en pixels fixes : sur un écran plus court,
   le paquet proche débordait. Toute la géométrie 3D passe en unités
   relatives à la hauteur, donc la scène entière se met à l'échelle. */
.table3d{perspective:116dvh;perspective-origin:50% 10%}
.table3d .plane{top:14%;height:81dvh;width:1400px;margin-left:-700px}
.plane .pile{width:min(88px,21cqi);margin-left:min(-44px,-10.5cqi)}
.plane .pile.far{top:4.4dvh}
.plane .pile.near{top:61dvh}


/* la carte examinée mordait sur le nom de l'adversaire */
#s-duel .exam{top:7.5%;left:4%}


/* ---- LE NOM VIT À CÔTÉ DE SON PAQUET, PAS EN HEADER ----
   Sorti du flux : c'est une étiquette de joueur posée près de sa pile
   de cartes gagnées, plus une barre de titre en haut de page. */
#s-duel .foe{
  position:absolute;left:14px;top:15.5%;z-index:3;
  flex-direction:column;align-items:flex-start;gap:3px;
  width:min(120px,30cqi);
}
#s-duel .foe .avatar{width:17px;height:17px}
#s-duel .foe .foename{font-size:clamp(.6rem,2.4cqi,.72rem);letter-spacing:.13em;line-height:1.1}
#s-duel .foe .sp{display:none}
#s-duel .foe .pilecount{font-size:clamp(1.05rem,4.4cqi,1.32rem)}
#s-duel .foe > .avatar + .foename{margin-top:1px}
/* symétrie : mon score se pose près de MA pile */
#s-duel .me{
  position:absolute;right:14px;top:62%;z-index:3;
  flex-direction:column;align-items:flex-end;gap:2px;
}
/* la table récupère toute la hauteur puisque les étiquettes sont sorties du flux */
#s-duel .tablemid{padding-top:clamp(20px,6cqi,42px);padding-bottom:clamp(4px,1.5cqi,10px)}

/* ---- LA CARTE EXAMINÉE : juste au-dessus de sa pile ---- */
#s-duel .exam{
  left:50%;translate:-50% 0;top:6.4%;
  width:clamp(54px,15.5cqi,76px);
}


/* ---- LE NOM : grand, à DROITE du paquet, dans la police du titre ---- */
#s-duel .foe{
  left:auto;right:14px;top:14.5%;
  align-items:flex-end;text-align:right;
  width:min(132px,33cqi);gap:1px;
}
#s-duel .foe .foename{
  font-family:"Boldonse",Impact,sans-serif;
  font-size:clamp(.95rem,4.4cqi,1.3rem);
  letter-spacing:-.01em;line-height:1;
  text-transform:uppercase;color:var(--ink);
}
#s-duel .foe .avatar{width:21px;height:21px}
#s-duel .foe .pilecount{
  font-family:"Boldonse",Impact,sans-serif;
  font-size:clamp(1.3rem,5.6cqi,1.7rem);color:var(--acc);
}
/* mon score adopte la même écriture, en face */
#s-duel .me{left:14px;right:auto;top:60%;align-items:flex-start}
#s-duel .me .pilecount{
  font-family:"Boldonse",Impact,sans-serif;
  font-size:clamp(1.3rem,5.6cqi,1.7rem);
}

/* ---- LA RÉSOLUTION DE LA CARTE EXAMINÉE ----
   Il faut voir SANS AMBIGUÏTÉ si elle est prise ou rendue. */
#s-duel .exam{width:clamp(64px,19cqi,94px)}
.exam .pc{transition:box-shadow .2s}
.exam.won .pc{
  animation:examWon .58s var(--e-expo-io) forwards;
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.4),0 0 0 3px var(--acc),
             0 0 26px color-mix(in oklch,var(--acc),transparent 30%);
}
.exam.lost .pc{
  animation:examLost .58s var(--e-in) forwards;
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.3),0 0 0 3px oklch(.62 .23 26),
             0 0 22px oklch(.62 .23 26/.6);
}
@keyframes examWon{
  0%  {transform:rotate(-7deg) scale(1);filter:none}
  16% {transform:rotate(0deg) scale(1.22);filter:brightness(2.6) saturate(1.4)}
  34% {transform:rotate(1deg) scale(1.05);filter:brightness(1.2)}
  100%{transform:translateY(72px) rotate(3deg) scale(.5);opacity:0;filter:none}
}
@keyframes examLost{
  0%  {transform:rotate(-7deg) scale(1);filter:none}
  12% {transform:rotate(-7deg) scale(1.08);filter:brightness(1.9) saturate(.25)}
  28% {transform:translateX(-9px) rotate(-13deg)}
  42% {transform:translateX(9px) rotate(-1deg)}
  56% {transform:translateX(-5px) rotate(-9deg)}
  100%{transform:translateY(64px) rotate(17deg) scale(.78);opacity:0;
       filter:grayscale(1) brightness(.35)}
}


/* « SCOTTSBURY » débordait de sa boîte : on l'élargit, on autorise le
   retour à la ligne, et on ajuste le corps pour tenir à côté du paquet */
#s-duel .foe{width:min(152px,38cqi)}
#s-duel .foe .foename{
  font-size:clamp(.8rem,3.6cqi,1.1rem);
  white-space:normal;overflow-wrap:anywhere;text-wrap:balance;
}


/* ---- HALO ÉMISSIF PAR RARETÉ ----
   commune : rien. rare : lueur discrète. épique : émissif franc.
   mythique : émissif + anneau holographique qui tourne.
   Le halo est une lueur portée, jamais un flou animé : l'anneau
   mythique tourne en `transform`, donc composé par le GPU. */
.card,.spoilcard{--emis:0 0 0 transparent}
.card[data-rar="rare"],.spoilcard[data-rar="rare"]{
  --emis:0 0 16px color-mix(in oklch,var(--r-ink),transparent 74%);
}
.card[data-rar="epique"],.spoilcard[data-rar="epique"]{
  --emis:0 0 9px color-mix(in oklch,var(--r-ink),transparent 46%),
         0 0 34px color-mix(in oklch,var(--r-ink),transparent 66%);
}
.card[data-rar="mythique"],.spoilcard[data-rar="mythique"]{
  --emis:0 0 11px color-mix(in oklch,var(--r-ink),transparent 34%),
         0 0 46px color-mix(in oklch,var(--r-ink),transparent 54%);
}
/* France : halo tricolore par rareté plutôt que la teinte générique de
   --r-ink — demandé explicitement (blanc/bleu/rouge/tricolore). Ne touche
   que le halo, pas --r-ink lui-même (pastille/étiquette de rareté gardent
   leur couleur habituelle, seul l'effet porté change ici). */
[data-dom="france"] .card[data-rar="commune"],[data-dom="france"] .spoilcard[data-rar="commune"]{
  --emis:0 0 14px oklch(.97 0 0/.5);
}
[data-dom="france"] .card[data-rar="rare"],[data-dom="france"] .spoilcard[data-rar="rare"]{
  --emis:0 0 16px oklch(.62 .18 260/.55);
}
[data-dom="france"] .card[data-rar="epique"],[data-dom="france"] .spoilcard[data-rar="epique"]{
  --emis:0 0 9px oklch(.6 .21 25/.55),0 0 34px oklch(.6 .21 25/.4);
}
[data-dom="france"] .card[data-rar="mythique"],[data-dom="france"] .spoilcard[data-rar="mythique"]{
  /* halo neutre ici — le tricolore mythique se joue sur l'anneau spatial
     ci-dessous, pas sur un box-shadow (qui ne peut que mélanger les
     couleurs en un flou uniforme, jamais les séparer gauche/droite). */
  --emis:0 0 18px oklch(.97 0 0/.45);
}
.face.back{
  box-shadow:inset 0 0 0 1px oklch(1 0 0/.09),var(--emis),0 18px 50px oklch(0 0 0/.5);
}
.face.front{box-shadow:var(--emis),0 18px 50px oklch(0 0 0/.5)}
#d-card .face{box-shadow:inset 0 0 0 1px oklch(1 0 0/.09),var(--emis),
  0 26px 46px oklch(0 0 0/.66),0 6px 14px oklch(0 0 0/.5)}
.spoilcard{box-shadow:var(--emis),0 18px 50px oklch(0 0 0/.55)}

/* l'anneau holographique de la mythique, derrière la carte */
.card[data-rar="mythique"] .face::before,
.spoilcard[data-rar="mythique"]::before{
  content:"";position:absolute;inset:-7px;z-index:-1;border-radius:calc(var(--card-r) + 5px);
  background:conic-gradient(from 0deg,
    oklch(.86 .2 20/.85),oklch(.9 .19 92/.85),oklch(.87 .2 160/.85),
    oklch(.84 .2 244/.85),oklch(.87 .2 320/.85),oklch(.86 .2 20/.85));
  animation:holoTurn 6s linear infinite;
  will-change:transform;
}
.card[data-rar="mythique"] .face,
.spoilcard[data-rar="mythique"]{isolation:auto}
/* France mythique : bande spatiale bleu/blanc/rouge, gauche→droite, fixe
   — pas l'anneau arc-en-ciel générique (son jaune/vert dénature l'identité
   France) ni une rotation (on veut lire 3 bandes nettes, pas un mélange).
   data-dom vit tantôt sur un ANCÊTRE (<html> au butin), tantôt sur .card
   LUI-MÊME (#d-card en duel, voir index.html ~L1156, pour ne teinter que
   la carte et pas toute la table) — :is() couvre les deux placements. */
:is([data-dom="france"] .card, .card[data-dom="france"])[data-rar="mythique"] .face::before,
:is([data-dom="france"] .spoilcard, .spoilcard[data-dom="france"])[data-rar="mythique"]::before{
  background:linear-gradient(90deg,
    oklch(.62 .18 260) 0 30%,oklch(.97 0 0) 30% 70%,oklch(.6 .21 25) 70% 100%);
  animation:none;
}
/* le vrai "liseré doré" visible même en previsualiseur/duel vient d'ICI,
   pas de l'anneau ci-dessus : .front::after est un effet "foil" séparé
   (bordure incrustée + reflet diagonal), câblé en dur sur --r-ink mythique
   (oklch(.86 .17 88), or) sans passer par --emis — jamais couvert par les
   overrides du dessus. border-image sépare enfin les 3 couleurs (un
   box-shadow inset ne peut que les mélanger). */
:is([data-dom="france"] .card, .card[data-dom="france"])[data-rar="mythique"] .front::after{
  border:2px solid transparent;
  border-image:linear-gradient(90deg,
    oklch(.62 .18 260) 0 33%,oklch(.97 0 0) 33% 66%,oklch(.6 .21 25) 66% 100%) 1;
  box-shadow:inset 0 0 44px oklch(.97 0 0/.24);
  background:linear-gradient(115deg,transparent 38%,oklch(1 0 0/.30) 50%,transparent 62%);
  background-size:250% 100%;
}

/* les pastilles de rareté du pied prennent la même lueur */
.card[data-rar="epique"] .dot,.card[data-rar="mythique"] .dot,
.spoilcard[data-rar="epique"] .dot,.spoilcard[data-rar="mythique"] .dot{
  box-shadow:0 0 8px var(--r-ink);
}


/* les boutons de partage prennent la couleur d'accent — et dans un en-tête
   de deck, c'est donc celle du domaine */
.sharebtn{color:var(--acc);transition:color .2s,box-shadow .2s,background .2s}
.sharebtn:hover{background:color-mix(in oklch,var(--acc),transparent 86%);
  box-shadow:inset 0 0 0 1.5px color-mix(in oklch,var(--acc),transparent 55%)}
.sharebtn.ok{box-shadow:inset 0 0 0 1.5px var(--acc),0 0 14px color-mix(in oklch,var(--acc),transparent 60%)}
/* celui d'un deck est plus discret que celui de la collection */
.secthd .sharebtn{width:27px;height:27px;margin-left:9px;flex:none}
.secthd .sharebtn .seal{width:17px;height:17px}


/* ---- LISIBILITÉ DES QUESTIONS ----
   Sur les polices pixel, « Forme finale » se lisait « Forme anale » : le
   « fi » se soude. On coupe les ligatures et on aère l'interlettrage, plus
   fortement sur les polices pixel (Pokémon, Supermarchés) que sur les
   autres domaines. Le nom de carte, lui, garde son tracking serré. */
.qtext{
  font-variant-ligatures:none;
  -webkit-font-feature-settings:"liga" 0,"clig" 0;
  font-feature-settings:"liga" 0,"clig" 0;
  letter-spacing:.04em;
}
[data-dom="sportifs"] .qtext{letter-spacing:.01em}
[data-dom="france"]   .qtext{letter-spacing:.006em}
[data-dom="supermarche"]   .qtext{letter-spacing:.05em}
[data-dom="pocket"]   .qtext{letter-spacing:.08em;word-spacing:.16em}


/* ---- LISIBILITÉ SUR LES MYTHIQUES ----
   L'holo traverse toute la face et mangeait la question. Plutôt que
   d'atténuer l'effet, on renforce le voile SOUS le texte : le cœur devient
   presque opaque, les bords laissent l'holo respirer. Une ombre portée sur
   les lettres finit le travail. */
.qtext{text-shadow:0 1px 2px oklch(0 0 0/.5),0 0 10px oklch(0 0 0/.35)}
.qhead .rar,.qhead .seal{filter:drop-shadow(0 1px 2px oklch(0 0 0/.75))}

.card[data-rar="mythique"] .face.back::before{
  /* noyau sombre juste sous le texte, puis on rend la main à l'holo :
     il doit rester visible autour, c'est tout l'intérêt de la mythique */
  background:radial-gradient(ellipse 74% 40% at 50% 46%,
    color-mix(in oklch,var(--q-bg),transparent 10%) 38%,
    color-mix(in oklch,var(--q-bg),transparent 55%) 72%,
    color-mix(in oklch,var(--q-bg),transparent 82%) 100%);
}
.card[data-rar="mythique"] .qtext{
  text-shadow:0 1px 2px oklch(0 0 0/.9),0 0 9px oklch(0 0 0/.85),
              0 0 24px oklch(0 0 0/.65);
}
.card[data-rar="mythique"] .qinput{
  background:oklch(0 0 0/.55);
  box-shadow:inset 0 0 0 1.5px oklch(1 0 0/.28);
}
.card[data-rar="mythique"] .qinput::placeholder{color:oklch(1 0 0/.5)}
/* l'épique a un holo plus discret, mais il mérite le même filet */
.card[data-rar="epique"] .qtext{
  text-shadow:0 1px 2px oklch(0 0 0/.75),0 0 10px oklch(0 0 0/.55);
}

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

/* ── lot 3 : connexion + avatar ── */
/* le contenu (10 formes + 10 couleurs + aperçu) dépasse la hauteur sur petit écran ;
   overflow:visible sur .screen le rendrait inatteignable, scopé ici seulement. */
#s-avatar{overflow-y:auto}
#login-form{width:min(280px,80cqi)}
#login-go{margin-top:4px}
.avatar-preview{width:72px;height:72px;display:grid;place-items:center}
.avatar-preview svg{width:56px;height:56px}
.avatar-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;width:min(320px,88cqi)}
.avshape,.avcolor{
  aspect-ratio:1;border-radius:3px;display:grid;place-items:center;cursor:pointer;
  background:var(--elev);box-shadow:inset 0 0 0 1.5px var(--line);
}
.avshape svg{width:60%;height:60%}
.avshape[data-on],.avcolor[data-on]{box-shadow:inset 0 0 0 2px var(--acc)}
.avcolor{padding:0}

/* ── lot 3 : sous-titre d'un bot (ex. TurboMwet "(pas une IA)"), en plus petit
   et un cran plus discret que le nom, sur sa propre ligne ── */
.bottag{display:block;font-size:.62em;opacity:.7;letter-spacing:.08em;font-weight:400}

/* ── accueil : "Departure Mono" reste utilisée partout ailleurs (numéros de
   carte, minuteur de duel...), mais pas ici — retour explicite du joueur.
   Le compte à rebours n'est plus une petite ligne mono discrète : c'est le
   seul contenu de l'écran quand il n'y a rien à ouvrir, il doit peser. */
#picktimer-boostcount{
  font-family:'Bebas Neue',Impact,sans-serif;
  font-size:clamp(1.4rem,5.5cqi,2.2rem);
  letter-spacing:.06em;color:var(--ink2);
}
.nextgrant-count{
  font-family:'Bebas Neue',Impact,sans-serif;
  font-size:clamp(2.4rem,11cqi,4.4rem);
  letter-spacing:.05em;line-height:1;
  color:var(--acc);text-shadow:0 0 28px color-mix(in oklch,var(--acc),transparent 40%);
}
/* le picker remplace entièrement le booster + les decks par le compte à
   rebours quand il n'y a rien à ouvrir — pas une rangée grisée en plus */
.picktimer{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;gap:10px;text-align:center}
.picktimer .logo{font-size:var(--t-h2,2rem)}
/* sous les 5 cartes nécessaires pour miser : les boutons de duel restent
   là (on peut toujours aller voir), mais une flèche discrète-mais-lisible
   explique pourquoi on n'ira pas plus loin tout seul */
.stealhint{display:flex;flex-direction:column;align-items:center;gap:4px;opacity:.6;color:var(--ink2);
  font-family:'Bebas Neue',Impact,sans-serif;font-size:clamp(1.05rem,4cqi,1.5rem);
  letter-spacing:.03em;line-height:1.1;text-align:center;margin-top:8px}
.stealarrow{width:20px;height:32px}

/* ── lot 3, étape B : salon réseau ── */
#lobby-menu{display:flex;flex-direction:column;gap:12px;align-items:center}
#lobby-join-code{width:min(160px,60cqi);text-align:center;text-transform:uppercase;letter-spacing:.2em}
#lobby-code{font-size:var(--t-h1);letter-spacing:.15em}
.coderow{display:flex;align-items:center;gap:10px}


/* compléments de structure (le recto et le dos partagent une face 3D) */
.face.front{display:block}
.cardback,.cardfront{position:absolute;inset:0;border-radius:var(--card-r);overflow:hidden}
.cardfront{display:flex;flex-direction:column}
[hidden]{display:none !important}
.hd{display:flex;flex-direction:column;gap:5px;padding-bottom:4px}
.stack{display:flex;flex-direction:column;gap:14px}

/* PERF — Firefox signalé lent spécifiquement au tournage de carte et sur
   les épiques/mythiques : ces deux raretés portent chacune un anneau qui
   tourne en continu (conic-gradient composé en transform — déjà la bonne
   technique), et l'épique y ajoute un mask-image + mix-blend-mode:screen
   (nécessaires au rendu, vérifié : sans eux l'anneau devient une bande
   dure et moche, voir capture testée). Résultat : PENDANT le tournage 3D
   du carton (.card{transition:transform .74s}, voir askCard()/resolve()
   dans index.html qui posent/retirent .turning pour cette durée), Firefox
   composait le carton en train de tourner ET son anneau interne en train
   de tourner/se blend/se masquer, en même temps — on met juste l'anneau
   en pause le temps du tournage, il n'est visible qu'une fois la carte
   face à l'écran de toute façon. Doit être la dernière règle du fichier :
   `animation` (raccourci) réinitialise implicitement animation-play-state,
   donc toute règle qui pose `animation:...` avec la même spécificité,
   plus loin dans la cascade, écraserait silencieusement la pause. */
.card.turning .holo,.card.turning .face::before{animation-play-state:paused}

/* Bandeau "rendu logiciel détecté" — voir checkGpuAccel() dans index.html.
   En bas d'écran (jamais sur le titre/logo), deux temps : le constat, puis
   un vrai bouton vers sa propre page (perf-help.html) plutôt qu'un détail
   replié ici. Couleurs fixes (pas --acc/--acc2, qui changent par domaine) :
   ce bandeau plane au-dessus de tous les écrans, sa couleur ne doit pas
   sauter selon le deck survolé. */
.perfwarn{
  position:fixed;left:0;right:0;bottom:0;z-index:80;
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:11px clamp(14px,4cqi,22px);
  background:oklch(.22 .04 55);color:oklch(.92 .025 80);
  box-shadow:0 -2px 14px oklch(0 0 0/.45);
  font-size:var(--t-label);line-height:1.4;
}
.perfwarn-msg{flex:1;min-width:200px}
.perfwarn-fix{
  flex:none;font:inherit;font-weight:600;white-space:nowrap;
  color:oklch(.22 .04 55);background:oklch(.92 .025 80);
  border-radius:6px;padding:7px 14px;text-decoration:none;
  transition:transform .15s var(--e-out),background .15s var(--e-out);
}
.perfwarn-fix:hover{background:oklch(1 0 0);transform:translateY(-1px)}
.perfwarn-x{
  flex:none;background:none;border:0;color:inherit;font-size:1.3rem;line-height:1;
  cursor:pointer;padding:2px 6px;opacity:.7;
}
.perfwarn-x:hover{opacity:1}
