/* ==========================================================================
   Solcaz — jeux
   ========================================================================== */

/* --------------------------------------------------------------------------
   Coque de jeu commune
   -------------------------------------------------------------------------- */
.game {
  display: grid; grid-template-columns: 302px minmax(0, 1fr); gap: 16px;
  align-items: start;
}
.game--reverse { grid-template-columns: minmax(0,1fr) 302px; }
.game__panel {
  background: linear-gradient(180deg, var(--panel), var(--bg-1));
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: 16px;
  display: flex; flex-direction: column; gap: 13px;
  position: sticky; top: 0;
}
.game__board {
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(155,135,245,.07), transparent 60%),
    linear-gradient(180deg, var(--panel), var(--bg-1));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  min-height: 460px; position: relative; overflow: hidden;
  display: flex; flex-direction: column;
}
.game__head {
  display: flex; align-items: center; gap: 10px; padding: 13px 16px;
  border-bottom: 1px solid var(--line); flex: none; flex-wrap: wrap;
}
.game__name { font-weight: 750; font-size: 14px; letter-spacing: -.01em; }
.game__body { flex: 1; display: flex; flex-direction: column;
  padding: 18px; min-height: 0; }

@media (max-width: 1000px) {
  .game, .game--reverse { grid-template-columns: minmax(0,1fr); }
  .game__panel { position: static; order: 2; }
  .game__board { order: 1; min-height: 380px; }
}

/* --- historique de manches --- */
.history-strip { display: flex; gap: 5px; overflow-x: auto; padding: 2px;
  scrollbar-width: none; }
.history-strip::-webkit-scrollbar { display: none; }
.hchip {
  padding: 4px 9px; border-radius: 6px; font-family: var(--mono);
  font-size: 11.5px; font-weight: 700; flex: none;
  background: rgba(160,140,240,.07); color: var(--text-2); cursor: pointer;
  transition: transform .12s;
}
.hchip:hover { transform: translateY(-2px); }
.hchip--win { background: var(--violet-dim); color: var(--violet); }
.hchip--big { background: var(--gold-dim); color: var(--gold); }
.hchip--lose { background: rgba(255,79,110,.11); color: #ff8ba1; }

/* --------------------------------------------------------------------------
   Cartes a jouer

   Le carton est en CSS (la teinte du papier, le vernis, l'arrondi), la
   figure est en SVG (web/js/cards.js) et le dos est une image de fond
   vectorielle calculee une seule fois — `--pc-back`, posee sur la racine au
   premier rendu de carte. Trente cartes sur le tapis ne coutent donc qu'un
   seul dessin de dos.

   Une carte a deux faces et pivote sur son axe : le trou du croupier se
   retourne sur place au lieu de disparaitre et de revenir. `--dx/--dy` sont
   poses par le JS au moment de la donne : c'est le vecteur sabot -> place.
   -------------------------------------------------------------------------- */
.card-hand { display: flex; align-items: center; }
.card-hand > .pcard + .pcard { margin-left: -30px; }
.card-hand--tight > .pcard + .pcard { margin-left: -38px; }

.pcard {
  --w: 64px;
  width: var(--w); height: calc(var(--w) * 1.4);   /* le format 5/7 du poker */
  position: relative; flex: none;
  perspective: 1000px;
}
/* Deux ombres : le contact, net et serre, puis la portee, large et douce.
   Une seule ombre donne toujours l'impression d'une vignette collee.

   Elles sont posees sur les FACES, en box-shadow, et non sur la carte en
   drop-shadow. C'est la meme image a l'oeil, et ce n'est pas du tout le
   meme cout : un `filter` sort l'element du flux de composition et oblige
   le navigateur a re-calculer le flou de l'ombre a chaque image de
   l'animation. Vingt cartes qui volent depuis le sabot, cela faisait
   quarante flous recalcules soixante fois par seconde -- c'est ce qui
   faisait tomber le nombre d'images de la table. Une box-shadow, elle,
   est peinte une fois dans la couche de la carte, qui ne fait ensuite que
   se deplacer. */
.pcard__face {
  --pc-lift:
    0 1px 1px rgba(0,0,0,.55),
    0 calc(var(--w) * .12) calc(var(--w) * .17) calc(var(--w) * -.08)
      rgba(0,0,0,.72);
}
.pcard--sm { --w: 42px; }
.pcard--lg { --w: 80px; }

.pcard__inner {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transition: transform .55s cubic-bezier(.3, .9, .25, 1);
  transform: rotateY(0deg);
}
.pcard.is-down .pcard__inner { transform: rotateY(180deg); }

.pcard__face {
  position: absolute; inset: 0;
  /* 15/240 : le meme rayon que le dessin SVG, a toutes les tailles. */
  border-radius: calc(var(--w) * .0625);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
}

/* --- la face : un carton ivoire, pas un rectangle blanc --- */
.pcard__front {
  color: #17161f;
  background:
    radial-gradient(132% 100% at 18% 4%,
      #fffdf8 0%, #f9f5ec 44%, #ece5d5 100%);
  box-shadow:
    inset 0 0 0 1px rgba(58,46,26,.22),
    inset 0 0 0 2px rgba(255,255,255,.5),
    inset 0 -20px 28px -24px rgba(70,55,30,.55),
    var(--pc-lift);
}
.pcard--red .pcard__front { color: #c1102f; }
/* le vernis : une bande de lumiere en travers du carton */
.pcard__front::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(128deg,
    rgba(255,255,255,.5) 0%, rgba(255,255,255,.05) 25%,
    transparent 44%, rgba(120,100,60,.055) 100%);
}
.pcard__art {
  position: absolute; inset: 0; display: block;
  width: 100%; height: 100%; fill: none; stroke: none;
}
/* Le rang est du texte, pas un trace : il suit la police du site et reste
   donc coherent avec le reste de l'interface. */
.pcard__rank {
  font-family: var(--font); font-weight: 850; font-size: 38px;
  letter-spacing: -.02em;
}

/* --- le dos : le guillochis, servi en image de fond --- */
.pcard__back {
  transform: rotateY(180deg);
  background: var(--pc-back, none) center / 100% 100% no-repeat, #171034;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.55), var(--pc-lift);
}

/* --- l'envol depuis le sabot --- */
.pcard.is-dealt { animation: dealFly .46s cubic-bezier(.2,.85,.25,1) backwards; }
@keyframes dealFly {
  0%   { opacity: 0;
         transform: translate(var(--dx, 0), var(--dy, -60px))
                    rotate(-26deg) scale(.78); }
  40%  { opacity: 1; }
  78%  { transform: translate(0, 0) rotate(2.5deg) scale(1.03); }
  100% { transform: none; }
}
/* --- le retournement du trou --- */
.pcard.is-turning { animation: cardLift .6s var(--ease); z-index: 4; }
@keyframes cardLift {
  0%, 100% { translate: 0 0; }
  45%      { translate: 0 -10px; }
}

/* --------------------------------------------------------------------------
   Blackjack — le meuble

   Le tapis est un vrai meuble, empile de l'exterieur vers l'interieur :

     .bj-table          la caisse, son ombre au sol et sa baguette doree
       .bj-table__rail  le bandeau de cuir capitonne, avec sa couture
         .bj-table__inlay  le filet d'or qui separe le cuir du drap
           .bj-table__felt le feutre, et tout ce qui vit dessus

   Chaque couche a son propre eclairage : le cuir prend la lumiere par le
   haut, le feutre la recoit d'un plafonnier place au-dessus du croupier,
   et le vignettage referme l'ovale. C'est cette pile — et non un degrade
   unique — qui fait qu'un tapis a l'air d'un objet.
   -------------------------------------------------------------------------- */

.bj-page { display: flex; flex-direction: column; gap: 16px; }
.bj-page__main {
  display: flex; flex-direction: column; gap: 12px; min-width: 0;
}
.bj-stage { display: flex; justify-content: center; min-width: 0; }
.bj-dock { display: flex; }
/* Le rail : tout ce qui se mise, au meme endroit, toujours visible. */
.bj-rail {
  display: flex; flex-direction: column; gap: 13px; padding: 15px;
  background: linear-gradient(180deg, var(--panel), var(--bg-1));
  border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: inset 0 1px 0 rgba(160,140,240,.08);
}

.bj-page__head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bj-page__title {
  font-size: clamp(20px, 2.6vw, 28px); font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase; margin-right: auto;
  color: var(--text);
}
.bj-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 16px; border-radius: 99px; font-size: 13px; font-weight: 650;
  border: 1px solid var(--line-2); color: var(--text-2);
  background: rgba(160,140,240,.05); transition: .16s;
}
.pill:hover { color: var(--text); border-color: rgba(160,140,240,.35); }
.pill--violet {
  border-color: rgba(155,135,245,.55); color: #c5b6ff;
  background: rgba(155,135,245,.12);
}
.pill--violet:hover { background: rgba(155,135,245,.2); color: #ddd4ff; }
.pill__group {
  display: inline-flex; padding: 4px; gap: 4px; border-radius: 99px;
  border: 1px solid var(--line-2); background: rgba(160,140,240,.05);
}
.pill__group .pill { border: 0; padding: 6px 14px; background: transparent; }
.pill__group .pill.is-on { background: var(--violet-dim); color: #ddd4ff; }

/* --- la caisse --- */
.bj-table {
  /* Le « metal » de la table n'est pas du laiton : c'est le degrade de la
     marque — violet pale, violet, turquoise, emeraude — celui du jeton de
     l'en-tete et du dos des cartes. Toute la garniture du meuble en
     descend, et l'or ne sert plus qu'a ce qu'il signifie au blackjack :
     c'est ton tour, c'est un blackjack, c'est un gain. */
  --metal:   #cbbcff;               /* le clair du filet, celui du jeton */
  --metal-2: var(--violet-2);       /* son ombre */

  position: relative; width: 100%;
  aspect-ratio: 16 / 9; min-height: 460px;
  padding: clamp(10px, 1.5vw, 22px);          /* l'epaisseur du bandeau */
  border-radius: 44% / 32%;
  background: linear-gradient(180deg, #191231 0%, #0d0a1c 58%, #07050f 100%);
  /* L'ombre au sol se joue en deux temps : un contact serre sous la caisse,
     puis une nappe large et coloree qui fait « poser » le meuble au lieu de
     le laisser flotter. */
  box-shadow:
    0 60px 110px -52px rgba(0,0,0,1),
    0 26px 54px -34px rgba(66,34,132,.6);
  isolation: isolate;
}
/* la baguette doree, sur la tranche : un or qui tourne autour de l'ovale */
.bj-table::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  padding: 2px;
  background: conic-gradient(from 200deg,
    #2a1f56 0%, var(--metal) 12%, var(--metal-2) 25%, #1d1540 37%,
    #5fd0c4 50%, var(--green) 60%, #2a1f56 72%, var(--metal) 86%,
    #2a1f56 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none; z-index: 4;
}

/* --- le bandeau de cuir --- */
.bj-table__rail {
  position: relative; width: 100%; height: 100%;
  border-radius: inherit;
  padding: clamp(7px, 1vw, 14px);
  background:
    radial-gradient(120% 160% at 50% -24%, rgba(255,255,255,.11), transparent 44%),
    repeating-conic-gradient(from 0deg at 50% 50%,
      rgba(255,255,255,.022) 0deg 4deg, rgba(0,0,0,.05) 4deg 8deg),
    linear-gradient(180deg, #2b2249 0%, #1a1234 46%, #0d0a1d 100%);
  box-shadow:
    inset 0 2px 3px rgba(219,205,255,.14),
    inset 0 -12px 24px rgba(0,0,0,.72),
    inset 0 0 0 1px rgba(0,0,0,.5);
}
/* la couture du capitonnage */
.bj-table__rail::after {
  content: ""; position: absolute; inset: clamp(3px, .45vw, 6px);
  border-radius: inherit; pointer-events: none; z-index: 3;
  border: 1px dashed rgba(203,188,255,.20);
}

/* --- le filet d'or --- */
.bj-table__inlay {
  position: relative; width: 100%; height: 100%;
  border-radius: inherit; padding: 2px;
  background: linear-gradient(180deg,
    rgba(203,188,255,.70), rgba(155,135,245,.22) 46%, rgba(16,212,146,.42));
  box-shadow: 0 0 24px -8px rgba(0,0,0,.95);
}

/* --- le drap --- */
.bj-table__felt {
  position: relative; width: 100%; height: 100%;
  border-radius: inherit; overflow: hidden;
  background:
    radial-gradient(56% 40% at 50% 1%, rgba(150,120,255,.20), transparent 62%),
    radial-gradient(130% 92% at 50% 112%, rgba(52,32,110,.5), transparent 64%),
    linear-gradient(180deg, #251b4b 0%, #180f33 48%, #0e0920 100%);
  box-shadow: inset 0 0 60px rgba(0,0,0,.7);
  /* Tout ce qui vit sur le tapis (sieges, cartes, jetons, chrono) se mesure
     en `cqh` : une fraction de la HAUTEUR du feutre. Retrecir la table
     retrecit donc la donne avec elle, au lieu de laisser des cartes de
     taille fixe deborder d'un tapis devenu petit. */
  container-type: size;
}

/* Le grain du drap : un bruit fractal tisse, pas une image chargee.

   Sans `mix-blend-mode`, et c'est volontaire. Un mode de fusion force le
   navigateur a refondre TOUT le feutre des que le moindre pixel bouge
   dessus -- une carte, un jeton, le chrono du croupier. Le tapis entier
   etait donc recompose a chaque image d'animation. Le grain est desormais
   une simple couche translucide : posee une fois, elle ne coute plus rien
   pendant la donne. */
.bj-felt__nap {
  position: absolute; inset: 0; pointer-events: none;
  opacity: .09;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.4'/%3E%3C/svg%3E"),
    repeating-linear-gradient(0deg,
      rgba(255,255,255,.028) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg,
      rgba(0,0,0,.05) 0 1px, transparent 1px 3px);
  background-size: 180px 180px, auto, auto;
}
/* le cone du plafonnier, au-dessus du croupier */
.bj-felt__spot {
  position: absolute; left: 50%; top: -28%; transform: translateX(-50%);
  width: 80%; height: 102%; pointer-events: none;
  background: radial-gradient(closest-side ellipse at 50% 0%,
    rgba(236,224,255,.26), rgba(160,130,255,.09) 44%, transparent 74%);
}
/* le vignettage : ce qui referme l'ovale et concentre l'oeil au centre */
.bj-felt__vig {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(114% 94% at 50% 42%,
    transparent 46%, rgba(4,2,12,.5) 86%, rgba(2,1,8,.82) 100%);
}
/* le jeton de la marque, imprime en filigrane */
.bj-felt__mark {
  position: absolute; left: 50%; top: 52%;
  width: clamp(96px, 30cqh, 290px); aspect-ratio: 1;
  transform: translate(-50%, -50%);
  opacity: .085; pointer-events: none;
}
.bj-felt__mark svg { width: 100%; height: 100%; }

/* les arcs : etires avec le feutre, ce sont des lignes */
.bj-felt__arcs { position: absolute; inset: 0; pointer-events: none; }
.bj-felt__arcs svg { width: 100%; height: 100%; display: block; }

/* le lettrage : jamais etire, lui */
.bj-felt__type { position: absolute; pointer-events: none; user-select: none; }
.bj-felt__type svg { width: 100%; height: auto; display: block; }
.bj-felt__type--main { left: 11%; right: 11%; top: 35%; }
.bj-felt__type--sub  { left: 23%; right: 23%; top: 59%; }

/* Une gravure de tapis se lit, elle ne crie pas : les cartes tombent
   dessus a chaque manche, et un lettrage trop present donnerait un fond
   d'ecran, pas un feutre. */
.bj-print__main {
  font-family: var(--font); font-weight: 800; font-size: 46px;
  letter-spacing: 7px; fill: url(#bjInk); stroke: none; opacity: .82;
}
.bj-print__sub {
  font-family: var(--font); font-weight: 700; font-size: 19px;
  letter-spacing: 4.5px; fill: rgba(203,188,255,.34); stroke: none;
}
/* l'ombre portee dans le drap, posee sous l'or : le relief de l'impression */
.bj-print__main--shadow { fill: rgba(5,2,14,.55); }
.bj-print__sub--shadow  { fill: rgba(5,2,14,.35); }

/* --------------------------------------------------------------------------
   Le croupier
   -------------------------------------------------------------------------- */
.bj-dealer {
  position: absolute; left: 50%; top: 2.5%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  z-index: 6;
}
/* Le disque porte trois choses au meme endroit : le medaillon, l'anneau du
   chrono qui le cercle, et la pastille des secondes accrochee a son bord. */
.bj-dealer__disc {
  position: relative;
  width: clamp(46px, 11.5cqh, 100px); aspect-ratio: 1;
}
.bj-dealer__badge {
  position: absolute; inset: 0;
  filter: drop-shadow(0 14px 20px rgba(0,0,0,.75))
          drop-shadow(0 0 7px rgba(16,212,146,.35));
}
.bj-dealer.is-mine .bj-dealer__badge {
  filter: drop-shadow(0 14px 20px rgba(0,0,0,.75))
          drop-shadow(0 0 7px rgba(242,193,78,.45));
}
.bj-dealer__badge svg { width: 100%; height: 100%; }
/* l'aiguille : un arc conique pilote par --p, cercle autour du medaillon */
.bj-status__ring {
  position: absolute; inset: -15%; border-radius: 50%;
  background: conic-gradient(var(--green) calc(var(--p, 0) * 360deg),
                             rgba(160,140,240,.16) 0);
  /* `closest-side` est indispensable : sans lui, un radial-gradient mesure
     ses pourcentages jusqu'au COIN de la boite (r x 1,41), et la couronne
     tombait entierement hors du medaillon — invisible. */
  -webkit-mask: radial-gradient(circle closest-side, transparent 78%,
                                #000 80%, #000 96%, transparent 98%);
  mask: radial-gradient(circle closest-side, transparent 78%,
                        #000 80%, #000 96%, transparent 98%);
  /* Pas de drop-shadow ici : l'anneau change de valeur quatre fois par
     seconde pendant toute la manche, et un filtre sur un degrade conique
     masque se recalcule a chaque pas. Le halo vert est passe sur le
     medaillon, juste en dessous, ou il ne bouge jamais. */
  transition: background .25s linear;
}
.bj-dealer.is-mine .bj-status__ring {
  background: conic-gradient(var(--gold) calc(var(--p, 0) * 360deg),
                             rgba(160,140,240,.14) 0);
}
/* les secondes, en pastille sur la tranche du medaillon */
.bj-status__count {
  position: absolute; right: -14%; bottom: -6%;
  min-width: clamp(17px, 4.2cqh, 34px); padding: 0 clamp(2px, .6cqh, 5px);
  height: clamp(17px, 4.2cqh, 34px); border-radius: 99px;
  display: grid; place-items: center;
  font-family: var(--mono); font-weight: 800; line-height: 1;
  font-size: clamp(9px, 2.2cqh, 17px);
  color: #04261b;
  background: linear-gradient(180deg, #4cf0bd, var(--green-2));
  box-shadow: 0 0 0 2px rgba(9,6,22,.9), 0 4px 10px -4px #000;
}
/* A ton tour, la pastille passe a l'or avec l'anneau : les deux disent
   toujours la meme chose. */
.bj-dealer.is-mine .bj-status__count {
  color: #2a1c02;
  background: linear-gradient(180deg, #ffeab0, #d29a17);
}
/* la plaque du croupier */
.bj-dealer__plate {
  padding: 2px 14px; border-radius: 99px;
  background: linear-gradient(180deg, rgba(28,21,54,.95), rgba(9,6,22,.95));
  box-shadow:
    inset 0 0 0 1px rgba(160,140,240,.30),
    inset 0 1px 0 rgba(255,255,255,.06),
    0 6px 14px -8px #000;
}
.bj-dealer__plateTxt {
  font-size: clamp(8px, 1.25cqh, 10px); font-weight: 800; letter-spacing: .2em;
  text-transform: uppercase; color: #c5b6ff;
}
.bj-dealer__cards { display: flex; align-items: center; min-height: 6px; }
.bj-dealer__cards > .pcard + .pcard { margin-left: calc(var(--w) * -.46); }
.bj-total--dealer { margin-top: 2px; }

/* --------------------------------------------------------------------------
   Sabot et corbeille — du materiel, pas des rectangles
   -------------------------------------------------------------------------- */
.bj-shoe {
  position: absolute; left: 8%; top: 12%; z-index: 2;
  width: clamp(46px, 8.5%, 92px); aspect-ratio: 1.5;
  border-radius: 4px 4px 9px 9px;
  background:
    linear-gradient(105deg, rgba(255,255,255,.10) 0 22%, transparent 40%),
    linear-gradient(160deg, #3c2d6a 0%, #251b46 52%, #150e2c 100%);
  box-shadow:
    inset 0 0 0 1px rgba(160,140,240,.26),
    inset 0 -9px 16px rgba(0,0,0,.6),
    0 14px 24px -12px rgba(0,0,0,.9);
  transform: rotate(-8deg);
}
/* La tranche du paquet, apercue dans le sabot. Elle reste sombre : ce sont
   des cartes vues DE COTE, dans une boite, pas une pile de papier blanc
   sous un projecteur. */
.bj-shoe__deck {
  position: absolute; left: 13%; right: 13%; top: 13%; height: 42%;
  border-radius: 2px;
  background:
    linear-gradient(180deg, rgba(255,255,255,.18), transparent 30%),
    repeating-linear-gradient(180deg,
      rgba(226,214,255,.30) 0 1px, rgba(17,11,36,.92) 1px 3.5px);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.55),
              inset 0 -4px 6px rgba(0,0,0,.5);
}
/* la plaque de metal du sabot */
.bj-shoe__plate {
  position: absolute; left: 24%; right: 24%; top: 64%; height: 12%;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--metal), var(--metal-2));
  opacity: .75;
}
/* La levre par ou sort la carte : encastree dans le bas du sabot, pas posee
   dessous. Un liseré qui flotte sous l'objet le fait paraitre decolle. */
.bj-shoe__lip {
  position: absolute; left: 10%; right: 10%; bottom: 6%; height: 9%;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--metal), var(--metal-2));
  box-shadow: 0 0 10px -3px rgba(155,135,245,.85),
              inset 0 -1px 1px rgba(0,0,0,.4);
}
.bj-shoe.is-feeding .bj-shoe__lip { animation: shoeFeed .45s var(--ease); }
@keyframes shoeFeed {
  0%, 100% { transform: translateY(0); filter: none; }
  40%      { transform: translateY(3px); filter: brightness(1.8); }
}

.bj-tray {
  position: absolute; right: 8%; top: 13%; z-index: 2;
  width: clamp(34px, 6%, 64px); aspect-ratio: 1.35;
  border-radius: 5px;
  background: linear-gradient(180deg, #2c2350, #140d2a);
  box-shadow:
    inset 0 0 0 1px rgba(160,140,240,.22),
    inset 0 7px 13px rgba(0,0,0,.65),
    0 10px 18px -10px rgba(0,0,0,.85);
  transform: rotate(7deg);
}
/* les cartes deja jouees, empilees dans la corbeille */
.bj-tray__stack {
  position: absolute; inset: 17% 14%; border-radius: 3px;
  background:
    linear-gradient(180deg, rgba(203,188,255,.16), transparent 36%),
    repeating-linear-gradient(180deg,
      rgba(214,200,255,.20) 0 1px, rgba(14,9,30,.94) 1px 4px);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.5);
}

/* --------------------------------------------------------------------------
   Les sieges
   -------------------------------------------------------------------------- */
.bj-seat {
  position: absolute; left: var(--x); top: var(--y);
  /* ancre par le BAS : les cartes s'empilent vers le croupier */
  transform: translate(-50%, -100%);
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  /* Deux places voisines sont separees de 16% du feutre : au-dela, elles
     se marcheraient dessus. La hauteur donne la taille, la largeur pose la
     limite. */
  width: clamp(66px, min(17.5cqh, 15.5cqw), 150px); z-index: 5;
  transition: filter .3s var(--ease);
}
.bj-seat--empty { cursor: pointer; }
.bj-seat.is-won { filter: drop-shadow(0 0 20px rgba(16,212,146,.6)); }
.bj-seat.is-lost { filter: grayscale(.45) brightness(.78); }

.bj-seat__hands { display: flex; gap: 8px; align-items: flex-end;
  min-height: 4px; }
.bj-hand {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 4px; border-radius: 10px;
  transition: background .2s, outline-color .2s;
  outline: 1px solid transparent;
}
.bj-hand--active {
  background: rgba(232,201,126,.10); outline-color: rgba(232,201,126,.45);
}
.bj-hand__foot { display: flex; align-items: center; gap: 4px; }
.bj-hand__flags { display: flex; align-items: center; gap: 4px; }
.bj-seat__cards { display: flex; min-height: 4px; }
.bj-seat__cards > .pcard + .pcard { margin-left: calc(var(--w) * -.6); }
.bj-table .pcard { --w: clamp(38px, 7.4cqh, 64px); }
.bj-table .pcard--sm { --w: clamp(27px, 5cqh, 42px); }

/* Un split multiplie les mains d'une seule place — jusqu'a quatre. Les
   sieges sont poses en absolu : une main de plus ne peut donc pas pousser
   ses voisines, elle leur passe dessus. Ce sont les cartes qui cedent, d'un
   cran par main supplementaire, et les gouttieres avec elles. A quatre
   mains l'empreinte reste sous l'ecart de deux sieges voisins. */
.bj-seat__hands:has(> .bj-hand:nth-child(2)) { gap: 4px; }
.bj-seat__hands:has(> .bj-hand:nth-child(2)) .bj-hand { padding: 3px 2px; }
.bj-table .bj-seat__hands:has(> .bj-hand:nth-child(2)) .pcard--sm {
  --w: clamp(21px, 3.9cqh, 33px);
}
.bj-table .bj-seat__hands:has(> .bj-hand:nth-child(3)) .pcard--sm {
  --w: clamp(17px, 3.1cqh, 26px);
}
.bj-seat__hands:has(> .bj-hand:nth-child(3)) { gap: 3px; }
.bj-seat__hands:has(> .bj-hand:nth-child(3)) .bj-total {
  min-width: 0; padding: 1px 5px;
}
.bj-table .bj-seat__hands:has(> .bj-hand:nth-child(4)) .pcard--sm {
  --w: clamp(15px, 2.6cqh, 22px);
}

/* --- les trois cases de mise, gravees dans le drap --- */
.bj-seat__spots {
  display: flex; align-items: flex-end; gap: 6px; justify-content: center;
  min-height: clamp(30px, 5.4cqh, 46px);
  /* La reserve du bas n'est pas decorative : le montant de chaque pile est
     pose SOUS elle, hors du flux. Sans cette gouttiere il tombait sur le
     medaillon du joueur. */
  padding-bottom: clamp(8px, 2.4cqh, 20px);
}
.bj-spot {
  position: relative; border-radius: 50%;
  width: clamp(19px, 3.8cqh, 32px); aspect-ratio: 1;
  display: grid; place-items: center;
  font-size: clamp(6px, .92cqh, 8px); font-weight: 800; letter-spacing: .06em;
  color: rgba(197,182,255,.62);
  background: radial-gradient(circle at 50% 40%,
    rgba(86,64,164,.24), rgba(18,11,40,.5));
  /* Une case de mise est gravee, pas dessinee : un liseré clair en haut, une
     ombre portee vers l'interieur. Le drap est creuse, pas peint. */
  box-shadow:
    inset 0 0 0 1px rgba(160,140,240,.30),
    inset 0 2px 4px rgba(0,0,0,.55),
    0 1px 0 rgba(255,255,255,.05);
  transition: transform .16s var(--ease), box-shadow .18s;
}
.bj-spot--main {
  width: clamp(25px, 5cqh, 42px);
  font-size: clamp(6.5px, 1.05cqh, 9px); color: rgba(222,212,255,.82);
}
/* le double filet de la case principale */
.bj-spot--main::before {
  content: ""; position: absolute; inset: 12%; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(160,140,240,.18);
}
.bj-seat--empty:hover .bj-spot {
  transform: translateY(-2px);
  box-shadow:
    inset 0 0 0 1px rgba(203,188,255,.6),
    inset 0 2px 4px rgba(0,0,0,.5),
    0 0 16px -4px rgba(155,135,245,.7);
}
.bj-spot.is-filled {
  box-shadow:
    inset 0 0 0 1px rgba(203,188,255,.5),
    inset 0 2px 5px rgba(0,0,0,.55),
    0 0 20px -6px rgba(155,135,245,.8);
}
.bj-spot.is-landing { animation: chipDrop .34s cubic-bezier(.2,.9,.3,1); }
@keyframes chipDrop {
  0%   { transform: translateY(-26px) scale(.7); opacity: 0; }
  70%  { transform: translateY(2px) scale(1.06); opacity: 1; }
  100% { transform: none; }
}

/* --------------------------------------------------------------------------
   Les jetons

   La table se regarde en plongee, pas a la verticale : un jeton n'est donc
   pas un rond mais une ellipse, et une pile se lit a sa tranche. `--i` donne
   le rang de la galette, le CSS s'occupe du decalage et de l'ombre. Seule
   celle du dessus porte les encoches de bord et le creux central — c'est la
   seule dont on voit la face.
   -------------------------------------------------------------------------- */
.chipstack { position: absolute; inset: 0; }
.chip {
  position: absolute; left: 50%; bottom: calc(6% + var(--i, 0) * 13%);
  width: 84%; aspect-ratio: 1 / .62; transform: translateX(-50%);
  border-radius: 50%; z-index: calc(var(--i, 0) + 1);
  background:
    radial-gradient(120% 160% at 34% 16%, rgba(255,255,255,.45), transparent 56%),
    var(--chip-face, linear-gradient(180deg, #cbbcff, #6a4fd6));
  box-shadow:
    0 2px 0 var(--chip-wall, #48339c),
    0 4px 6px -1px rgba(0,0,0,.6),
    inset 0 0 0 1px rgba(0,0,0,.28);
}
/* les encoches de tranche, seulement sur la couronne exterieure */
.chip--top::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: repeating-conic-gradient(from 14deg,
    rgba(255,255,255,.92) 0deg 13deg, transparent 13deg 45deg);
  -webkit-mask: radial-gradient(closest-side, transparent 57%, #000 60%);
  mask: radial-gradient(closest-side, transparent 57%, #000 60%);
  opacity: .8;
}
/* le creux central, la ou un vrai jeton porte sa valeur */
.chip--top::after {
  content: ""; position: absolute; inset: 20% 18%; border-radius: 50%;
  background: var(--chip-core, #e6dfff);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.55), 0 0 0 1px rgba(0,0,0,.25);
  opacity: .92;
}
.chip--ivory {
  --chip-face: linear-gradient(180deg, #f7f3ff, #c7c0de);
  --chip-wall: #8b849f; --chip-core: #e9e5f6;
}
.chip--blue {
  --chip-face: linear-gradient(180deg, #93ccff, #2f6fc4);
  --chip-wall: #1c4a8c; --chip-core: #cfe6ff;
}
.chip--green {
  --chip-face: linear-gradient(180deg, #83f2ca, #0f9a6d);
  --chip-wall: #0a6a4a; --chip-core: #ccf8e6;
}
.chip--violet {
  --chip-face: linear-gradient(180deg, #cfc1ff, #6a4fd6);
  --chip-wall: #46329a; --chip-core: #e8e1ff;
}
.chip--gold {
  --chip-face: linear-gradient(180deg, #ffeeb8, #d29a17);
  --chip-wall: #93680a; --chip-core: #fff4d2;
}
.chipstack__amt {
  /* Sous la pile, a une distance qui suit sa taille : sur une petite table
     un decalage fixe de 13 px decrochait le montant de ses jetons. */
  position: absolute; bottom: -36%; left: 50%; transform: translateX(-50%);
  font-family: var(--mono); font-size: clamp(6px, 1.05cqh, 8px);
  font-weight: 750; color: #f4ecff; white-space: nowrap;
  text-shadow: 0 1px 3px #000, 0 0 8px rgba(0,0,0,.9);
}

/* --- le medaillon du joueur --- */
.bj-seat__avatar {
  position: relative;
  width: clamp(34px, 7.2cqh, 62px); aspect-ratio: 1;
  border-radius: 50%; padding: 2px;
  background: linear-gradient(180deg,
    rgba(203,188,255,.8), rgba(115,88,230,.45) 52%, rgba(160,140,240,.7));
  box-shadow: 0 10px 20px -10px rgba(0,0,0,.95);
  display: grid; place-items: center;
  transition: background .2s, box-shadow .2s;
}
.bj-seat__avatar::before {
  content: ""; position: absolute; inset: 2px; border-radius: 50%;
  background: var(--panel-2);
}
.bj-seat__avatar > * { position: relative; }
.bj-seat__avatar .avatar {
  width: 100%; height: 100%; border-radius: 50%;
  font-size: clamp(34px, 7.2cqh, 62px);
}
.bj-seat__plus {
  font-size: clamp(15px, 3cqh, 24px); font-weight: 800; line-height: 1;
  color: rgba(200,185,255,.45);
}
.bj-seat--empty .bj-seat__avatar {
  background: rgba(160,140,240,.26);
  box-shadow: 0 6px 14px -10px rgba(0,0,0,.9);
}
.bj-seat--empty .bj-seat__avatar::before { background: rgba(34,24,64,.55); }
.bj-seat--empty:hover .bj-seat__avatar {
  background: linear-gradient(180deg, rgba(203,188,255,.95), rgba(115,88,230,.7));
  box-shadow: 0 0 22px -6px rgba(155,135,245,.8);
}
.bj-seat--empty:hover .bj-seat__plus { color: var(--violet); }
.bj-seat--mine .bj-seat__avatar {
  background: linear-gradient(180deg, #6cf0c2, var(--green-2));
}
.bj-seat--acting .bj-seat__avatar {
  background: linear-gradient(180deg, #ffeab0, #d29a17);
  box-shadow: 0 0 0 3px rgba(232,201,126,.2), 0 0 32px -6px var(--gold);
}
/* L'anneau qui bat : un cercle qui grandit et s'efface. Transformation et
   opacite, donc rien a repeindre -- la carte graphique s'en charge seule.
   La version precedente animait le `box-shadow` du medaillon, c'est-a-dire
   un halo redessine soixante fois par seconde, en continu, pendant tout le
   tour de parole et pile au moment ou les cartes tombent. */
.bj-seat--acting .bj-seat__avatar::after {
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid rgba(232,201,126,.6); pointer-events: none;
  animation: seatPulse 1.6s ease-out infinite;
}
@keyframes seatPulse {
  0%        { transform: scale(1); opacity: .8; }
  70%, 100% { transform: scale(1.3); opacity: 0; }
}

/* --- la plaque de siege --- */
.bj-seat__plate {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 10px 3px 3px; border-radius: 99px;
  background: linear-gradient(180deg, rgba(28,21,54,.95), rgba(9,6,22,.95));
  box-shadow:
    inset 0 0 0 1px var(--line-2),
    inset 0 1px 0 rgba(255,255,255,.05),
    0 6px 14px -9px #000;
  font-size: clamp(9.5px, 1.5cqh, 11.5px); font-weight: 650; max-width: 100%;
}
.bj-seat__num {
  min-width: clamp(15px, 2.4cqh, 19px); height: clamp(15px, 2.4cqh, 19px);
  border-radius: 50%; display: grid; place-items: center;
  font-size: clamp(8.5px, 1.3cqh, 10px); font-weight: 800;
  background: linear-gradient(180deg, #3a2d70, #1d1442); color: #cabaff;
  box-shadow: inset 0 0 0 1px rgba(160,140,240,.30);
}
.bj-seat--mine .bj-seat__num {
  background: linear-gradient(180deg, #12b681, #067a52); color: #dffaef;
}
.bj-seat__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bj-seat__badges {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  justify-content: center; min-height: 2px;
}
.bj-seat__balance {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: 99px;
  background: rgba(10,7,22,.92);
  box-shadow: inset 0 0 0 1px var(--line-2);
  font-family: var(--mono); font-size: 11px; font-weight: 650;
  animation: prizePop .32s var(--ease) backwards;
}

/* --- totaux et verdicts --- */
.bj-total {
  min-width: 30px; padding: 2px 9px; border-radius: 99px;
  background: linear-gradient(180deg, rgba(20,13,42,.95), rgba(7,4,18,.95));
  box-shadow:
    inset 0 0 0 1px var(--line-2),
    inset 0 1px 0 rgba(255,255,255,.05);
  font-family: var(--mono); font-weight: 700;
  font-size: clamp(10px, 1.55cqh, 12px);
  transition: color .2s, box-shadow .2s;
}
.bj-total.is-bumped { animation: totalBump .3s var(--ease); }
@keyframes totalBump {
  0% { transform: scale(1); } 45% { transform: scale(1.22); }
  100% { transform: scale(1); }
}
.bj-total--soft { color: var(--blue); }
.bj-total--bust {
  color: var(--red);
  box-shadow: inset 0 0 0 1px rgba(255,86,128,.5);
}
.bj-total--bj {
  color: #ffe6a8;
  box-shadow: inset 0 0 0 1px rgba(242,193,78,.6), 0 0 20px -4px var(--gold);
}

.bj-outcome {
  font-size: 9px; font-weight: 850; letter-spacing: .07em;
  text-transform: uppercase; padding: 2px 6px; border-radius: 5px;
  animation: prizePop .3s var(--ease) backwards;
}
.bj-outcome--win, .bj-outcome--blackjack {
  background: var(--green-dim); color: var(--green); }
.bj-outcome--lose, .bj-outcome--bust {
  background: var(--red-dim); color: #ff90ad; }
.bj-outcome--push { background: rgba(160,140,240,.14); color: var(--text-2); }

.bj-side-chip {
  font-size: 8.5px; font-weight: 800; padding: 1px 5px; border-radius: 4px;
  background: rgba(155,135,245,.18); color: #c0b0ff;
}

/* --------------------------------------------------------------------------
   La barre d'actions — un pupitre, pas quatre boutons en vrac
   -------------------------------------------------------------------------- */
.bj-actions {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 9px; max-width: 680px; margin: 0 auto; width: 100%;
  padding: 9px; border-radius: 99px;
  background: linear-gradient(180deg, rgba(26,19,50,.92), rgba(11,7,25,.94));
  box-shadow:
    inset 0 0 0 1px var(--line-2),
    inset 0 1px 0 rgba(255,255,255,.06),
    0 20px 42px -26px #000;
}
.bj-actions:empty { display: none; }
.bj-actions .btn { padding: 13px 6px; font-size: 13px; border-radius: 99px; }
.bj-actions.is-live .btn { animation: actionsIn .26s var(--ease) backwards; }
.bj-actions.is-live .btn:nth-child(2) { animation-delay: .04s; }
.bj-actions.is-live .btn:nth-child(3) { animation-delay: .08s; }
.bj-actions.is-live .btn:nth-child(4) { animation-delay: .12s; }
@keyframes actionsIn {
  from { opacity: 0; transform: translateY(10px); }
}

.sidebet-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.sidebet {
  border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: 9px 10px;
  display: flex; flex-direction: column; gap: 5px; background: var(--bg-1);
}
.sidebet__name { font-size: 10.5px; font-weight: 750; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); }
.sidebet__in { background: transparent; border: 0; font-family: var(--mono);
  font-size: 13px; font-weight: 650; width: 100%; padding: 6px 0; }
/* C'est la boite entiere qui s'allume, pas un liseré autour du seul texte.
   `outline: none` sur :focus faisait tomber AUSSI l'anneau de :focus-visible
   (:focus est vrai des que :focus-visible l'est) : au clavier, plus rien
   n'indiquait ou l'on etait. On ne l'enleve donc qu'au pointeur. */
.sidebet:focus-within {
  border-color: rgba(155,135,245,.55);
  box-shadow: 0 0 0 3px rgba(155,135,245,.12);
}
.sidebet__in:focus:not(:focus-visible) { outline: none; }

/* --------------------------------------------------------------------------
   La page tient dans la fenetre

   Une table de blackjack ne se consulte pas en faisant defiler la page :
   miser, tirer et voir le croupier doivent etre visibles ensemble. La
   colonne de gauche prend donc toute la hauteur restante (titre, tapis,
   boutons d'action) et le rail de droite garde la mise, les manches et
   l'equite sous les yeux.

   En dessous de 1000px de large ou 620px de haut, on repasse a la pile qui
   defile : entasser tout cela dans une fenetre de telephone ne donnerait
   plus rien de jouable.
   -------------------------------------------------------------------------- */
@media (min-width: 1001px) and (min-height: 620px) {
  /* Pose par la page blackjack, retiree en la quittant. */
  .view--fit {
    padding: 12px clamp(12px, 1.6vw, 24px) 14px;
    /* La largeur qui reste depend aussi du chat, ouvert ou non : c'est elle
       qu'on mesure, pas celle de la fenetre. */
    container: bjview / inline-size;
  }
  .view--fit .bj-page {
    height: 100%; display: grid; align-items: stretch; gap: 14px;
    grid-template-columns: minmax(0, 1fr) 300px;
  }
  .view--fit .bj-page__main { min-height: 0; gap: 10px; }
  .view--fit .bj-page__head { flex: none; }
  .view--fit .bj-page__title { font-size: clamp(17px, 1.5vw, 22px); }
  .view--fit .bj-toolbar .pill { padding: 7px 13px; font-size: 12px; }

  /* Le tapis se cale sur la hauteur libre et sa largeur suit son format.
     Si la colonne devient plus etroite que ce format, c'est la largeur qui
     commande : la requete de conteneur, juste apres, s'en charge. */
  .view--fit .bj-stage {
    flex: 1; min-height: 0; container: bjstage / size;
    align-items: center;
  }
  .view--fit .bj-table {
    height: 100%; width: auto; max-width: 100%; min-height: 0;
  }

  /* La barre d'actions garde sa place meme vide : sans cela le tapis
     changerait de taille a l'instant precis ou c'est a toi de jouer. */
  .view--fit .bj-dock {
    flex: none; min-height: 56px; align-items: center;
  }
  .view--fit .bj-dock .bj-actions { margin: 0 auto; }

  /* Si le rail deborde (petite fenetre), c'est lui qui defile, pas la page. */
  .view--fit .bj-rail {
    min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  }
}
/* Le tapis remplit la place libre. Son format n'est pas sacre : un vrai
   feutre est un ovale, il s'accommode d'etre plus ou moins ramasse. On le
   laisse donc epouser la zone disponible, en bornant seulement les exces —
   plus carre que 6/5 le feutre n'est plus qu'un puits vide, plus etale que
   2,2/1 le croupier finit a l'autre bout du monde. Entre les deux, il prend
   toute la place. */
@container bjstage (max-aspect-ratio: 6 / 5) {
  .view--fit .bj-table { width: 100%; height: auto; aspect-ratio: 6 / 5; }
}
@container bjstage (min-aspect-ratio: 22 / 10) {
  .view--fit .bj-table { width: auto; height: 100%; aspect-ratio: 22 / 10; }
}
@container bjstage (min-aspect-ratio: 6 / 5) and (max-aspect-ratio: 22 / 10) {
  .view--fit .bj-table { width: 100%; height: 100%; aspect-ratio: auto; }
}

/* Chat ouvert sur un portable : le rail se resserre pour laisser le tapis
   respirer, plutot que de garder ses 300px coute que coute. */
@container bjview (max-width: 1080px) {
  .view--fit .bj-page { grid-template-columns: minmax(0, 1fr) 250px; gap: 12px; }
  .view--fit .bj-rail { padding: 12px; gap: 11px; }
}

/* En dessous, plus rien ne tient de front : on rend la page au defilement.
   Un tapis de 300px de large ne serait de toute facon plus jouable. */
@container bjview (max-width: 760px) {
  .view--fit .bj-page {
    display: flex; flex-direction: column; height: auto; gap: 14px;
    padding-bottom: 26px;
  }
  .view--fit .bj-stage { container-type: normal; display: block; }
  .view--fit .bj-table {
    width: 100%; height: auto; aspect-ratio: 4 / 3; min-height: 420px;
  }
  .view--fit .bj-dock { min-height: 0; }
}

/* Sur un ecran etroit, la contrainte n'est plus la hauteur du feutre mais
   l'ecart entre deux places : les trois du milieu sont a 20 % l'une de
   l'autre, soit une soixantaine de pixels sur un telephone. Tout ce qu'un
   siege pose de front — ses trois cases, sa plaque — doit tenir dans cette
   largeur, sinon les sieges se chevauchent et le tapis devient illisible.
   Les cases NE sont donc pas re-fixees en pixels ici : elles suivent la
   hauteur du feutre (`cqh`), et on ne borne que ce qui deborderait. */
@media (max-width: 900px) {
  .bj-table { aspect-ratio: 4 / 3; border-radius: 30% / 20%; min-height: 500px; }
  .bj-seat { width: clamp(64px, 18vw, 120px); }
  .bj-felt__type--sub { display: none; }
}
@media (max-width: 560px) {
  .bj-actions { grid-template-columns: repeat(2, 1fr); border-radius: 22px; }
  .bj-felt__type { display: none; }
  .bj-tray { display: none; }
  /* Le sabot reste : c'est de la que partent les cartes. On le range dans
     le coin pour qu'il ne mange pas la place des sieges. */
  .bj-shoe { left: 6%; top: 8%; width: 40px; }
  /* 16 + 22 + 16 + deux gouttieres de 3 = 60 px : la place exacte entre
     deux sieges voisins. */
  .bj-seat { width: clamp(56px, 15.5vw, 96px); }
  .bj-seat__spots { gap: 3px; padding-bottom: 9px; }
  .bj-spot { width: 16px; }
  .bj-spot--main { width: 22px; }
  .bj-seat__avatar { width: clamp(30px, 8.4vw, 44px); }
  .bj-seat__plate { padding: 2px 7px 2px 2px; font-size: 9.5px; }
}

/* Confort : qui demande moins d'animation en recoit moins. Les cartes
   arrivent alors sans envol, mais elles arrivent. */
@media (prefers-reduced-motion: reduce) {
  .pcard.is-dealt, .pcard.is-turning, .bj-spot.is-landing,
  .bj-total.is-bumped, .bj-actions.is-live .btn,
  .bj-seat--acting .bj-seat__avatar::after { animation: none !important;
    opacity: .55; }
  .pcard__inner { transition: none; }
}
/* --------------------------------------------------------------------------
   Crash
   -------------------------------------------------------------------------- */
.crash__stage { flex: 1; position: relative; min-height: 320px; }
#crashCanvas { position: absolute; inset: 0; width: 100%; height: 100%; }
.crash__overlay {
  position: absolute; inset: 0; display: grid; place-content: center;
  place-items: center; gap: 6px; pointer-events: none; text-align: center;
}
.crash__mult {
  font-family: var(--mono); font-size: clamp(44px, 9vw, 84px); font-weight: 750;
  letter-spacing: -.045em; line-height: 1;
  text-shadow: 0 0 44px rgba(155,135,245,.45);
  font-variant-numeric: tabular-nums;
  /* --grow suit le multiplicateur : le chiffre enfle avec la tension */
  transform: scale(var(--grow, 1));
  transition: transform .18s var(--ease);
}
.crash__mult--bust { color: var(--red); text-shadow: 0 0 44px rgba(255,79,110,.5);
  animation: bustShake .45s var(--ease); }
@keyframes bustShake {
  0%,100% { transform: translateX(0); }
  25% { transform: translateX(-8px); } 75% { transform: translateX(8px); }
}
.crash__sub { font-size: 13px; color: var(--muted); font-weight: 600; }
.crash__countdown {
  font-family: var(--mono); font-size: 40px; font-weight: 700; color: var(--violet);
}

.crash__players { border-top: 1px solid var(--line); max-height: 190px;
  overflow-y: auto; flex: none; }
.crash-row {
  display: grid; grid-template-columns: 1fr auto auto; gap: 10px;
  align-items: center; padding: 7px 14px; font-size: 12.5px;
  border-bottom: 1px solid rgba(160,140,240,.04);
}
.crash-row--won { background: rgba(155,135,245,.06); }
.crash-row--lost { opacity: .45; }
.crash-row.is-fresh { animation: cashFlash .7s var(--ease); }
@keyframes cashFlash {
  0%   { background: rgba(155,135,245,.42); transform: translateX(5px); }
  100% { background: rgba(155,135,245,.06); transform: none; }
}

/* le flash de l'explosion, sur toute la scene */
.crash__stage.is-boom::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(circle at 50% 55%,
    rgba(255,79,110,.32), transparent 62%);
  animation: crashFlash .55s ease-out forwards;
}
@keyframes crashFlash { to { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .crash__mult { transition: none; }
  .crash-row.is-fresh, .crash__stage.is-boom::after,
  .crash__mult--bust { animation: none; }
}

/* --------------------------------------------------------------------------
   Mines
   -------------------------------------------------------------------------- */
.mines__wrap { flex: 1; display: grid; place-items: center; padding: 8px; }
.mines-grid {
  display: grid; gap: 8px; width: min(100%, 470px); aspect-ratio: 1;
  perspective: 900px;
  /* Les lignes se partagent la hauteur a parts egales, quoi qu'il y ait
     dedans. Sans ca elles etaient en `auto` : la premiere gemme revelee
     imposait la taille de son SVG a toute sa ligne, qui grossissait
     pendant que les autres retrecissaient. Une grille de jeu ne bouge
     pas quand on l'ouvre. */
  grid-auto-rows: minmax(0, 1fr);
}
.mines-grid.is-boom { animation: gridShake .42s cubic-bezier(.36,.07,.19,.97); }
@keyframes gridShake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}

.mtile {
  position: relative; border-radius: 10px; cursor: pointer;
  /* la case ne prend jamais la taille de ce qu'on met dedans */
  min-width: 0; min-height: 0;
  background: linear-gradient(180deg, #2a2150, #1c1538);
  border: 1px solid var(--line-2);
  display: grid; place-items: center;
  transition: transform .13s var(--ease), background .2s, border-color .2s,
              box-shadow .2s;
  box-shadow: 0 3px 0 rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.05);
}
/* un liseré discret, pour que la grille ne soit pas un damier plat */
.mtile::before {
  content: ""; position: absolute; inset: 5px; border-radius: 6px;
  border: 1px solid rgba(170,150,255,.07); pointer-events: none;
  transition: border-color .2s;
}
.mtile:hover:not(.is-open):not(:disabled) {
  transform: translateY(-3px);
  border-color: rgba(155,135,245,.5);
  background: linear-gradient(180deg, #33285f, #221a44);
  box-shadow: 0 6px 0 rgba(0,0,0,.42), 0 10px 20px -10px rgba(155,135,245,.6);
}
.mtile:hover:not(.is-open):not(:disabled)::before {
  border-color: rgba(196,178,255,.22);
}
.mtile:active:not(.is-open):not(:disabled) { transform: translateY(0); }
.mtile:disabled { cursor: default; }

.mtile__face {
  width: 62%; height: 62%; display: grid; place-items: center;
  aspect-ratio: 1; min-width: 0; min-height: 0;
}
.mtile__face svg { width: 100%; height: 100%; display: block; }

/* l'ouverture : la case bascule sur elle-meme, avec un retard reglable */
.mtile.is-open { box-shadow: none; }
.mtile.is-fresh {
  animation: tileFlip .38s var(--ease) backwards;
  animation-delay: var(--open-delay, 0ms);
}
@keyframes tileFlip {
  0%   { transform: rotateY(88deg) scale(.86); }
  60%  { transform: rotateY(-8deg) scale(1.05); }
  100% { transform: none; }
}
.mtile--gem {
  background: linear-gradient(180deg, rgba(155,135,245,.28), rgba(90,66,180,.16));
  border-color: rgba(155,135,245,.5);
}
.mtile--gem.is-lucky {
  box-shadow: 0 0 22px -4px rgba(155,135,245,.9);
}
.mtile--mine {
  background: linear-gradient(180deg, rgba(255,79,110,.2), rgba(120,20,44,.18));
  border-color: rgba(255,79,110,.42);
}
.mtile--boom {
  border-color: var(--red);
  box-shadow: 0 0 0 2px rgba(255,79,110,.35), 0 0 34px -4px var(--red);
  z-index: 2;
}
.mtile--boom .mtile__face { animation: boomPop .4s var(--ease); }
@keyframes boomPop {
  0% { transform: scale(.4); } 55% { transform: scale(1.35); }
  100% { transform: scale(1); }
}
.mtile--ghost { opacity: .32; }
/* le temps de l'aller-retour reseau, la case montre qu'elle a compris */
.mtile.is-waiting { animation: tilePulse .7s ease-in-out infinite; }
@keyframes tilePulse { 50% { background: rgba(155,135,245,.3); } }

.mines__hud {
  display: flex; gap: 10px; justify-content: center; flex-wrap: wrap;
  padding: 10px;
}
.mines__hud .stat { min-width: 118px; text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .mtile.is-fresh, .mines-grid.is-boom, .mtile--boom .mtile__face,
  .mtile.is-waiting { animation: none !important; }
}

/* --------------------------------------------------------------------------
   Keno
   -------------------------------------------------------------------------- */
.keno { flex: 1; display: flex; flex-direction: column; gap: 14px; padding: 6px; }
.keno-grid {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 7px;
  width: 100%; margin: 0 auto; max-width: 640px;
}
.knum {
  aspect-ratio: 1; border-radius: 11px; font-family: var(--mono);
  font-weight: 700; font-size: clamp(12px, 2.4vw, 16px);
  background: linear-gradient(180deg, #2a2150, #1c1538);
  border: 1px solid var(--line-2); color: var(--text-2);
  transition: transform .13s var(--ease), background .18s, color .18s,
              border-color .18s, opacity .3s;
  /* Meme recette de relief que .mtile : 3 px pleins sous la touche et un
     filet de lumiere sur l'arete haute. Sans ce filet, le numero du keno
     paraissait plat a cote de la grille des mines. */
  box-shadow: 0 3px 0 rgba(0,0,0,.36), inset 0 1px 0 rgba(255,255,255,.05);
}
.knum:hover:not(:disabled) {
  transform: translateY(-3px); color: var(--text);
  border-color: rgba(155,135,245,.45);
}
.knum.is-picked {
  background: linear-gradient(180deg, var(--violet), var(--violet-2));
  color: #180d38; border-color: transparent;
  box-shadow: 0 3px 0 rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.05),
              0 0 18px -5px var(--violet);
}
.knum.is-drawn {
  border-color: rgba(242,193,78,.6); color: var(--gold);
  background: linear-gradient(180deg, rgba(242,193,78,.12), transparent);
}
.knum.is-hit {
  background: linear-gradient(180deg, var(--gold), #d9a63a); color: #1a1204;
  border-color: transparent;
  box-shadow: 0 3px 0 rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.05),
              0 0 26px -4px var(--gold);
}
/* les numeros ni choisis ni tires s'effacent : le tirage se lit d'un coup */
.knum.is-cold { opacity: .38; }
.knum.is-fresh { animation: hitPop .42s var(--ease); z-index: 2; }
@keyframes hitPop {
  0%   { transform: scale(.55) rotate(-8deg); }
  60%  { transform: scale(1.22) rotate(3deg); }
  100% { transform: scale(1); }
}

/* --- la rangee de boules sorties --- */
.keno-balls {
  display: flex; gap: 7px; justify-content: center; flex-wrap: wrap;
  min-height: 34px;
}
.kball {
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 12px; font-weight: 750;
  background: radial-gradient(circle at 34% 28%, #4a3c86, #201748);
  border: 1px solid var(--line-2); color: var(--text-2);
  box-shadow: inset 0 -4px 8px rgba(0,0,0,.4);
}
.kball--hit {
  background: radial-gradient(circle at 34% 28%, #ffe7a6, #d29a17);
  color: #1a1204; border-color: rgba(242,193,78,.6);
  box-shadow: 0 0 20px -4px var(--gold), inset 0 -4px 8px rgba(0,0,0,.28);
}
.kball.is-fresh { animation: ballDrop .38s cubic-bezier(.2,.9,.3,1); }
@keyframes ballDrop {
  0%   { transform: translateY(-26px) scale(.5); opacity: 0; }
  70%  { transform: translateY(3px) scale(1.12); opacity: 1; }
  100% { transform: none; }
}

.keno-result {
  text-align: center; min-height: 30px; font-weight: 700; font-size: 16px;
  color: var(--text-2); transition: color .2s;
}
.keno-result.is-drawing { color: var(--muted); font-size: 13px; }
.keno-result.is-won { color: var(--gold); animation: prizePop .34s var(--ease); }
.keno-result.is-lost { color: var(--muted); }

.keno-pays { display: grid; grid-template-columns: repeat(auto-fit, minmax(64px,1fr));
  gap: 6px; }
.kpay {
  text-align: center; padding: 7px 4px; border-radius: 8px;
  background: var(--bg-1); border: 1px solid var(--line); font-size: 11px;
  transition: border-color .18s, background .18s;
}
.kpay.is-active { border-color: var(--gold); background: var(--gold-dim); }
.kpay__h { color: var(--muted); font-size: 10px; font-weight: 700; }
.kpay__m { font-family: var(--mono); font-weight: 700; font-size: 12px; }

@media (max-width: 560px) {
  .keno-grid { grid-template-columns: repeat(5, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  .knum.is-fresh, .kball.is-fresh, .keno-result.is-won { animation: none; }
}

/* --------------------------------------------------------------------------
   Coinflip
   -------------------------------------------------------------------------- */
.flip__stage {
  flex: 1; display: grid; place-items: center; padding: 30px 20px 40px;
  perspective: 1200px; position: relative;
}
/* l'ombre portee : elle se resserre quand la piece monte */
.flip__shadow {
  position: absolute; bottom: 26px; left: 50%; transform: translateX(-50%);
  width: 120px; height: 16px; border-radius: 50%;
  background: radial-gradient(ellipse, rgba(0,0,0,.6), transparent 70%);
  transition: transform .5s var(--ease), opacity .5s var(--ease);
}
.flip__stage.is-flying .flip__shadow {
  transform: translateX(-50%) scale(.55); opacity: .45;
}

/* Pas de `filter` ici, jamais : un filtre force `transform-style: flat` sur
   l'element qui le porte. La piece etait alors aplatie, sa face pile ne
   passait plus devant, et pile ressemblait a face a chaque lancer. L'ombre
   portee vit donc sur les faces, ou elle ne casse rien. */
.coin3d {
  width: clamp(130px, 22vw, 180px); aspect-ratio: 1; position: relative;
  transform-style: preserve-3d;
  transition: transform .3s var(--ease);
}
.flip__stage.is-flying .coin3d { animation: coinHop 1.6s var(--ease); }
@keyframes coinHop {
  0%   { translate: 0 0; }
  35%  { translate: 0 -48px; }
  70%  { translate: 0 -12px; }
  100% { translate: 0 0; }
}
.coin3d__face {
  position: absolute; inset: 0; border-radius: 50%;
  backface-visibility: hidden; -webkit-backface-visibility: hidden;
  display: grid; place-items: center; overflow: hidden;
  box-shadow: inset 0 0 0 6px rgba(0,0,0,.14),
              inset 0 -10px 20px rgba(0,0,0,.28);
  filter: drop-shadow(0 18px 22px rgba(0,0,0,.55));
}
.coin3d__face svg { width: 100%; height: 100%; }
.coin3d__rim { fill: none; stroke: rgba(0,0,0,.22); stroke-width: 3.5; }
.coin3d__face--h {
  background: radial-gradient(circle at 34% 28%, #fff2c9, #f2c14e 44%, #9c6c1f);
}
.coin3d__face--h .coin3d__mark { fill: #5a3d08; }
.coin3d__face--t {
  background: radial-gradient(circle at 34% 28%, #ded4ff, #9b87f5 44%, #4b34a8);
  transform: rotateY(180deg);
}
.coin3d__face--t .coin3d__mark { fill: #22124f; }

/* le halo du resultat */
.flip__stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border-radius: inherit; opacity: 0; transition: opacity .4s;
  background: radial-gradient(circle at 50% 42%,
    rgba(155,135,245,.28), transparent 58%);
}
.flip__stage.is-won::after { opacity: 1; }

.flip__choice { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.flip-opt {
  padding: 15px 10px; border-radius: var(--r); border: 1px solid var(--line-2);
  background: var(--bg-1); font-weight: 700; font-size: 13px;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  transition: .16s;
  /* Le choix pile/face est le geste du jeu : il merite le meme relief que
     les tuiles des mines et les numeros du keno, pas une case plate. */
  box-shadow: 0 3px 0 rgba(0,0,0,.36), inset 0 1px 0 rgba(255,255,255,.05);
}
.flip-opt:hover { border-color: rgba(160,140,240,.4); }
.flip-opt__disc {
  width: 34px; height: 34px; border-radius: 50%;
  box-shadow: inset 0 0 0 3px rgba(0,0,0,.18);
}
.flip-opt--h .flip-opt__disc {
  background: radial-gradient(circle at 34% 28%, #fff2c9, #f2c14e 46%, #9c6c1f); }
.flip-opt--t .flip-opt__disc {
  background: radial-gradient(circle at 34% 28%, #ded4ff, #9b87f5 46%, #4b34a8); }
.flip-opt.is-on {
  border-color: var(--violet); background: var(--violet-dim);
  /* L'anneau de selection s'AJOUTE au relief : en le remplacant, le choix
     retenu retombait a plat pendant que l'autre gardait son epaisseur. */
  box-shadow: 0 0 0 1px var(--violet-dim),
              0 3px 0 rgba(0,0,0,.36),
              inset 0 1px 0 rgba(255,255,255,.05);
}
.flip__result {
  font-size: 20px; font-weight: 750; min-height: 28px; text-align: center;
  padding-bottom: 16px;
}

@media (prefers-reduced-motion: reduce) {
  .flip__stage.is-flying .coin3d { animation: none; }
  .coin3d { transition: none; }
}

/* --------------------------------------------------------------------------
   Jackpot
   -------------------------------------------------------------------------- */
.jp { flex: 1; display: flex; flex-direction: column; gap: 16px; padding: 6px; }
.jp__pot { text-align: center; padding: 20px 10px 6px; }
.jp__amount {
  font-family: var(--mono); font-size: clamp(34px, 7vw, 58px); font-weight: 750;
  letter-spacing: -.04em; color: var(--gold);
  text-shadow: 0 0 44px rgba(244,198,90,.4);
}
.jp__timer {
  font-family: var(--mono); font-size: 15px; color: var(--text);
  margin-top: 6px; letter-spacing: .02em;
}
/* La ligne de contexte sous le compte a rebours : heure du tirage, etat du
   pot. Elle change souvent, elle ne doit jamais pousser le reste. */
.jp__note {
  font-size: 12.5px; color: var(--muted); margin-top: 4px; min-height: 16px;
}
.jp__bar {
  height: 34px; border-radius: 99px; overflow: hidden; display: flex;
  border: 1px solid var(--line-2); background: var(--bg-1);
}
.jp__seg { height: 100%; transition: width .6s var(--ease); position: relative;
  min-width: 2px; }
.jp__seg span {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 10px; font-weight: 800; color: rgba(0,0,0,.65);
  overflow: hidden; white-space: nowrap;
}
.jp__reel {
  height: 96px; border-radius: var(--r); border: 1px solid var(--line-2);
  overflow: hidden; position: relative; background: var(--bg-1);
}
.jp__reel::after {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 2px;
  background: var(--gold); box-shadow: 0 0 16px var(--gold); z-index: 2;
  transform: translateX(-50%);
}
.jp__reel::before {
  content: ""; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(90deg, var(--bg-1), transparent 14%,
    transparent 86%, var(--bg-1));
}
.jp__track { display: flex; height: 100%; align-items: center; gap: 8px;
  padding: 0 8px; will-change: transform; }
.jp__cell {
  flex: none; width: 78px; height: 78px; border-radius: var(--r-sm);
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 5px; background: var(--panel-2);
  border: 1px solid var(--line); font-size: 10.5px; font-weight: 650;
  transition: box-shadow .3s, transform .3s var(--ease);
}
.jp__reel.is-landed .jp__cell.is-winner {
  box-shadow: 0 0 0 2px var(--gold), 0 0 30px -4px var(--gold);
  transform: scale(1.06);
}
.jp__winner {
  text-align: center; padding: 18px; border-radius: var(--r-lg);
  background: linear-gradient(135deg, var(--gold-dim), transparent);
  border: 1px solid rgba(244,198,90,.3);
}

/* --------------------------------------------------------------------------
   Lobby — l'affiche

   C'est le premier ecran : il doit donner envie de s'asseoir, pas presenter
   un produit. Trois leviers, et rien de plus : un medaillon vivant a droite
   (le jeton tourne, respire, orbite), trois promesses lisibles sous les
   boutons, et des chiffres montes en tuiles — un tableau de bord de salle,
   pas une note de bas de page.

   Les seuils se lisent sur la carte (@container), pas sur la fenetre :
   le lobby vit dans une grille dont la largeur depend du rail et du chat,
   tous deux repliables. Une largeur de fenetre ne dirait rien de la place
   reellement disponible — chat ouvert ou ferme, c'est 550 px d'ecart pour
   la meme fenetre.
   -------------------------------------------------------------------------- */
.hero {
  position: relative; overflow: clip; isolation: isolate;
  container: hero / inline-size;
  border-radius: var(--r-xl); margin-bottom: 26px;
  padding: clamp(26px, 3.6vw, 44px) clamp(22px, 3.4vw, 46px);
  border: 1px solid var(--line-2);
  background:
    radial-gradient(78% 150% at 2% -12%, rgba(155,135,245,.26), transparent 58%),
    radial-gradient(62% 120% at 92% -6%, rgba(16,212,146,.15), transparent 60%),
    radial-gradient(95% 130% at 62% 118%, rgba(115,88,230,.18), transparent 62%),
    linear-gradient(168deg, #1e1743, var(--bg-1) 64%);
  box-shadow: 0 34px 76px -44px rgba(96,62,224,.95),
              inset 0 1px 0 rgba(255,255,255,.07);
}
/* Quadrillage fin, efface vers la droite : il donne de la matiere derriere
   le titre sans jamais passer sous le medaillon. */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(rgba(160,140,240,.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(160,140,240,.06) 1px, transparent 1px);
  background-size: 34px 34px;
  mask-image: radial-gradient(115% 105% at 6% 0%, #000 8%, transparent 68%);
  -webkit-mask-image: radial-gradient(115% 105% at 6% 0%, #000 8%, transparent 68%);
}
/* Un reflet qui traverse la carte toutes les quinze secondes. Assez rare
   pour qu'on le remarque, assez pale pour qu'il ne gene pas la lecture. */
.hero::after {
  content: ""; position: absolute; inset: -70% -25%; z-index: -1;
  pointer-events: none;
  background: linear-gradient(72deg, transparent 44%,
              rgba(255,255,255,.055) 50%, transparent 56%);
  animation: heroSheen 15s var(--ease) 2s infinite;
}
@keyframes heroSheen {
  0%        { transform: translateX(-62%); opacity: 0; }
  10%       { opacity: 1; }
  42%, 100% { transform: translateX(62%); opacity: 0; }
}

/* --- haut de l'affiche : texte + medaillon --- */

.hero__top { display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(20px, 3vw, 44px); position: relative; }
.hero__in { flex: 1 1 320px; min-width: 0; }

.hero__eyebrow {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 18px;
  padding: 5px 13px 5px 10px; border-radius: 99px;
  border: 1px solid var(--line-2); background: rgba(160,140,240,.08);
  font-size: 11.5px; font-weight: 700; color: var(--text-2);
}
.hero h1 {
  font-size: clamp(30px, 7cqi, 52px); font-weight: 850; line-height: 1.02;
  letter-spacing: -.04em; margin-bottom: 14px; max-width: 15ch;
  text-wrap: balance; text-shadow: 0 0 48px rgba(155,135,245,.30);
}
/* Le dernier mot du titre est celui qu'on vient chercher : il tient sur une
   seule ligne, quoi qu'il arrive a la colonne. Le degrade le traverse du
   violet de la marque au vert des actions — l'ombre du titre, elle, doit
   sauter : sous des lettres transparentes, elle se verrait au travers. */
.hero h1 em {
  font-style: normal; white-space: nowrap; text-shadow: none;
  background: linear-gradient(100deg, #d9cfff 4%, #9b87f5 44%, var(--green) 98%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hero p { color: var(--text-2); margin-bottom: 24px; font-size: 15.5px;
  line-height: 1.6; max-width: 46ch; }

.hero__cta { display: flex; gap: 11px; flex-wrap: wrap; align-items: center; }
.hero__cta .btn--lg { padding: 15px 28px; }
/* Le bouton d'entree : halo permanent, et un eclat qui le balaie. C'est le
   seul element de la page qui bouge tout seul en continu — il n'a de sens
   que parce qu'il est unique. */
.hero__cta .btn--green {
  overflow: clip;
  box-shadow: 0 12px 32px -12px rgba(16,212,146,.95),
              0 0 0 1px rgba(26,226,160,.34),
              inset 0 1px 0 rgba(255,255,255,.38);
}
.hero__cta .btn--green::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: -60%; width: 42%;
  transform: skewX(-18deg); pointer-events: none;
  background: linear-gradient(90deg, transparent,
              rgba(255,255,255,.5), transparent);
  animation: heroShine 5.5s var(--ease) 2.4s infinite;
}
@keyframes heroShine { 0% { left: -60%; } 22%, 100% { left: 132%; } }
.hero__cta .btn--ghost { background: rgba(255,255,255,.05);
  backdrop-filter: blur(6px); }

/* Trois promesses, une par objection : c'est truque ? il faut s'inscrire ?
   je serai paye quand ? */
.hero__points {
  display: flex; flex-wrap: wrap; gap: 9px 22px; margin-top: 22px;
  font-size: 12.5px; font-weight: 600; color: var(--text-2);
}
.hero__point { display: inline-flex; align-items: center; gap: 7px; }
.hero__point > span { flex: none; }
.hero__point--green  > span { color: var(--green); }
.hero__point--violet > span { color: var(--violet); }
.hero__point--gold   > span { color: var(--gold); }

/* --- le medaillon --- */

/* Le jeton n'est plus un filigrane a 17 % : il est l'objet qu'on vient
   toucher. Deux anneaux tournant en sens contraire, trois pastilles en
   orbite, un halo qui respire. Tout est decoratif, d'ou l'aria-hidden pose
   cote markup. */
.hero__art {
  flex: 0 0 auto; width: clamp(190px, 30cqi, 280px); aspect-ratio: 1;
  position: relative; margin-inline: auto; pointer-events: none;
  animation: heroRise .8s var(--ease) .12s both;
}
.hero__halo {
  position: absolute; inset: 10%; border-radius: 50%; filter: blur(28px);
  background: radial-gradient(circle, rgba(155,135,245,.5),
              rgba(16,212,146,.16) 46%, transparent 72%);
  animation: heroBreathe 6.5s ease-in-out infinite;
}
.hero__rings { position: absolute; inset: 0; }
.hero__ring {
  fill: none; stroke-width: 1.2; transform-box: view-box;
  transform-origin: 50% 50%; animation: heroSpin 30s linear infinite;
}
.hero__ring--a { stroke: rgba(178,160,255,.42); stroke-dasharray: 2.5 11; }
.hero__ring--b { stroke: rgba(16,212,146,.34); stroke-dasharray: 46 30;
  animation-duration: 42s; animation-direction: reverse; }
.hero__coin {
  position: absolute; inset: 22%;
  filter: drop-shadow(0 18px 32px rgba(78,38,196,.6));
  animation: heroFloat 7s ease-in-out infinite;
}
.hero__coin svg { width: 100%; height: 100%; display: block; }
.hero__pip { position: absolute; inset: 5%;
  animation: heroSpin 19s linear infinite; }
.hero__pip::after {
  content: ""; position: absolute; left: 50%; top: -4px;
  width: 9px; height: 9px; margin-left: -4.5px; border-radius: 99px;
  background: var(--green); box-shadow: 0 0 14px 2px rgba(16,212,146,.75);
}
.hero__pip--2 { inset: 14%; animation-duration: 26s;
  animation-direction: reverse; }
.hero__pip--2::after { width: 7px; height: 7px; margin-left: -3.5px;
  background: var(--violet); box-shadow: 0 0 14px 2px rgba(155,135,245,.8); }
.hero__pip--3 { inset: 1%; animation-duration: 34s; animation-delay: -9s; }
.hero__pip--3::after { width: 6px; height: 6px; margin-left: -3px;
  background: var(--gold); box-shadow: 0 0 12px 2px rgba(242,193,78,.6); }

@keyframes heroSpin    { to { transform: rotate(360deg); } }
@keyframes heroFloat   { 0%, 100% { transform: translateY(-5px); }
                         50% { transform: translateY(5px); } }
@keyframes heroBreathe { 0%, 100% { opacity: .72; transform: scale(1); }
                         50% { opacity: 1; transform: scale(1.07); } }

/* --- bandeau de chiffres --- */

/* Quatre tuiles plutot que quatre colonnes separees par des filets : elles
   se replient proprement en deux rangees, et le filet colore en tete de
   chacune rattache le chiffre a sa famille — vert pour l'argent mise,
   violet pour l'equite, neutre pour l'activite. */
.hero__stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px; margin-top: clamp(24px, 3vw, 32px); position: relative;
}
.hero__stats:empty { display: none; }
.hero__stat {
  position: relative; overflow: hidden; padding: 13px 15px 12px;
  border-radius: var(--r); border: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255,255,255,.055),
              rgba(255,255,255,.014));
  animation: heroRise .55s var(--ease) both;
}
.hero__stat::before {
  content: ""; position: absolute; inset: 0 14px auto; height: 1px;
  background: linear-gradient(90deg, transparent,
              rgba(155,135,245,.8), transparent);
}
.hero__stat b {
  display: block; margin-bottom: 3px; font-family: var(--mono);
  font-size: clamp(18px, 2.6cqi, 23px); font-weight: 700;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.hero__stat span { font-size: 10px; color: var(--muted); font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; }
.hero__stat:nth-child(1) b { color: var(--green); }
.hero__stat:nth-child(1)::before { background: linear-gradient(90deg,
  transparent, rgba(16,212,146,.75), transparent); }
.hero__stat:nth-child(2) { animation-delay: .06s; }
.hero__stat:nth-child(3) { animation-delay: .12s; }
.hero__stat:nth-child(4) { animation-delay: .18s; }
.hero__stat:nth-child(4) b { color: #bcabff; }

/* --- entrees --- */

.hero__eyebrow { animation: heroRise .6s var(--ease) .02s both; }
.hero h1       { animation: heroRise .6s var(--ease) .09s both; }
.hero p        { animation: heroRise .6s var(--ease) .16s both; }
.hero__cta     { animation: heroRise .6s var(--ease) .23s both; }
.hero__points  { animation: heroRise .6s var(--ease) .30s both; }
@keyframes heroRise { from { opacity: 0; transform: translateY(12px); } }

/* Sous 640 px de colonne, le medaillon mangerait la moitie de la place du
   titre, et le passer sous le texte rallongerait la carte d'un ecran de
   defilement avant le premier bouton : il sort. Les tuiles, elles,
   passent en deux rangees plutot que de comprimer quatre chiffres. */
@container hero (max-width: 640px) {
  .hero__art { display: none; }
  .hero h1 { max-width: none; }
  .hero__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container hero (max-width: 380px) {
  .hero__stats { gap: 8px; }
  .hero__points { gap: 7px 16px; }
  .hero::after { display: none; }
}

/* --- vignettes des jeux --- */

/* Six jeux : trois colonnes tombent juste, deux rangees pleines. En
   « auto-fill », la derniere rangee se retrouvait avec une seule vignette
   des que la fenetre s'elargissait. */
.game-grid { display: grid; gap: 15px;
  grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Sur telephone on reste a deux colonnes : en une seule, six vignettes
   hautes font defiler la page sur trois ecrans avant le premier tableau. */
@media (max-width: 980px) { .game-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
@media (max-width: 400px) { .game-grid { gap: 10px; } }

.game-tile {
  position: relative; border-radius: var(--r-lg); overflow: hidden;
  aspect-ratio: 1 / 1.06; border: 1px solid var(--line);
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 16px; background: var(--bg-1);
  transition: transform .22s var(--ease), border-color .22s, box-shadow .22s;
}
.game-tile:hover {
  transform: translateY(-6px); border-color: rgba(155,135,245,.45);
  box-shadow: 0 26px 50px -24px rgba(0,0,0,.95),
              0 0 0 1px rgba(155,135,245,.16);
}
.game-tile__art {
  position: absolute; inset: 0;
  transition: transform .45s var(--ease);
}
.game-tile__art svg { width: 100%; height: 100%; display: block; }
.game-tile:hover .game-tile__art { transform: scale(1.07); }
.game-tile__shade {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 34%, rgba(6,4,14,.60) 62%,
              rgba(6,4,14,.95) 92%);
}
.game-tile__body { position: relative; }
.game-tile__name { font-size: 17.5px; font-weight: 800; letter-spacing: -.02em; }
.game-tile__desc { font-size: 11.5px; color: var(--text-2); margin-top: 2px; }
.game-tile__badge {
  position: absolute; top: 12px; left: 12px; z-index: 2;
  font-size: 9.5px; font-weight: 850; letter-spacing: .09em;
  text-transform: uppercase; padding: 3px 8px; border-radius: 6px;
  background: rgba(6,4,14,.66); backdrop-filter: blur(6px); color: #c3b2ff;
  border: 1px solid rgba(155,135,245,.34);
}
.game-tile__players {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  font-size: 10.5px; font-weight: 700; padding: 3px 8px; border-radius: 6px;
  background: rgba(6,4,14,.66); backdrop-filter: blur(6px);
  display: flex; align-items: center; gap: 5px;
}
/* « Jouer » n'apparait qu'au survol : la vignette reste lisible au repos,
   et le geste attendu devient evident des qu'on la vise. */
.game-tile__go {
  position: absolute; left: 16px; bottom: 16px; z-index: 3;
  padding: 7px 16px; border-radius: 99px; font-size: 12px; font-weight: 800;
  background: var(--green); color: #04231a;
  opacity: 0; transform: translateY(8px);
  transition: opacity .2s var(--ease), transform .2s var(--ease);
  box-shadow: 0 8px 22px -8px rgba(16,212,146,.9);
}
.game-tile:hover .game-tile__go { opacity: 1; transform: none; }
.game-tile:hover .game-tile__body { opacity: 0; transition: opacity .18s; }
@media (hover: none) {
  .game-tile__go { display: none; }
  .game-tile:hover .game-tile__body { opacity: 1; }
}

/* --------------------------------------------------------------------------
   Coffre / recompenses
   -------------------------------------------------------------------------- */
.case-box {
  width: 178px; height: 178px; margin: 0 auto; border-radius: var(--r-lg);
  background:
    radial-gradient(80% 60% at 50% 20%, rgba(242,193,78,.12), transparent 66%),
    linear-gradient(160deg, var(--panel-3), var(--panel));
  border: 1px solid var(--line-2);
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 4px;
  position: relative; transition: transform .2s var(--ease);
  box-shadow: 0 20px 50px -24px rgba(244,198,90,.5);
}
.case-box:hover { transform: translateY(-3px); }
.case-prize {
  animation: prizePop .5s var(--ease);
  font-family: var(--mono); font-size: 26px; font-weight: 750; color: var(--gold);
  text-shadow: 0 0 26px rgba(242,193,78,.6);
}
@keyframes prizePop { from { opacity: 0; transform: scale(.6); } }

.tier-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 14px;
  border-radius: var(--r-sm); border: 1px solid var(--line);
}
.tier-row.is-current { border-color: var(--violet); background: var(--violet-dim); }
.tier-row__medal {
  width: 32px; height: 32px; border-radius: 9px; display: grid;
  place-items: center; font-weight: 850; font-size: 12px; flex: none;
  background: linear-gradient(145deg, var(--panel-3), var(--panel));
  border: 1px solid var(--line-2);
}

/* --------------------------------------------------------------------------
   Equite
   -------------------------------------------------------------------------- */
.seed-box {
  display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(240px,1fr));
}
.verify-out {
  font-family: var(--mono); font-size: 12.5px; background: var(--bg);
  border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: 14px;
  white-space: pre-wrap; word-break: break-all; max-height: 260px;
  overflow-y: auto; color: var(--violet);
}

/* Selecteur manuel / auto, pleine largeur dans un panneau de jeu. */
.pill__group--block { display: flex; width: 100%; }
.pill__group--block .pill { flex: 1; justify-content: center; }

/* Selection du pari automatique : la case porte son rang de retournement. */
.mtile.is-chosen {
  border-color: rgba(155,135,245,.65);
  background: linear-gradient(180deg, rgba(155,135,245,.24), rgba(90,66,180,.14));
  box-shadow: 0 3px 0 rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.05),
              0 0 18px -6px rgba(155,135,245,.9);
}
.mtile.is-chosen::after {
  content: attr(data-rank);
  position: absolute; top: 4px; right: 6px;
  font-family: var(--mono); font-size: 10px; font-weight: 750;
  color: #ddd4ff;
}

/* --------------------------------------------------------------------------
   Finition : la main, le clavier, le doigt

   Les six jeux partagent les memes commandes (jetons de mise, pastilles
   manuel/auto, tuiles). Ce qui suit les traite ensemble, pour qu'aucun jeu
   n'ait un comportement a lui.
   -------------------------------------------------------------------------- */

/* --- l'appui s'enfonce ---------------------------------------------------
   Ces tuiles ont un relief : 3 px d'ombre pleine sous elles, comme une
   touche. Une touche qui ne descend pas quand on appuie sonne faux. On
   enfonce donc la tuile ET on retire son ombre du meme nombre de pixels :
   c'est le meme objet qui touche le fond, pas un objet qui retrecit. */
.mtile:not(:disabled):active,
.knum:not(:disabled):active,
.flip-opt:not(:disabled):active {
  transform: translateY(3px);
  box-shadow: 0 0 0 rgba(0,0,0,.42), inset 0 1px 0 rgba(255,255,255,.05);
}
.pill:active { transform: translateY(1px); }
.hchip:active { transform: translateY(0); }

/* --- le clavier voit ou il est -------------------------------------------
   L'anneau global (base.css) se pose a 2 px du bord ; sur une tuile de 58 px
   colle a ses voisines, il devient illisible. On l'ecarte et on l'arrondit
   comme la tuile. */
.mtile:focus-visible, .knum:focus-visible, .flip-opt:focus-visible {
  outline: 2px solid var(--violet); outline-offset: 3px;
  border-radius: inherit; z-index: 2;
}

/* --- au doigt -------------------------------------------------------------
   Deux choses changent sans souris : les cibles doivent grossir, et le
   survol ne doit PAS rester colle. Sur tactile, `:hover` persiste apres le
   tap : une tuile restait soulevee, un jeton restait allume, jusqu'au tap
   suivant ailleurs. On annule le deplacement, on garde la couleur. */
@media (pointer: coarse) {
  .chip-btn { min-height: 38px; padding: 8px 14px; font-size: 12px; }
  .sstat__reset { min-width: 36px; min-height: 36px; }
  .sidebet__in { padding: 9px 0; }
  .pill { min-height: 38px; }
  .hchip { padding: 7px 11px; }
}
@media (hover: none) {
  .mtile:hover:not(.is-open):not(:disabled),
  .knum:hover:not(:disabled),
  .hchip:hover,
  .bj-seat--empty:hover .bj-spot { transform: none; }
}

/* --- moins de mouvement pour qui en demande moins ------------------------
   Les cinq blocs precedents couvrent les animations de chaque jeu ; ces
   trois-la sont celles qu'on vient d'ajouter. */
@media (prefers-reduced-motion: reduce) {
  .mtile:not(:disabled):active,
  .knum:not(:disabled):active,
  .flip-opt:not(:disabled):active,
  .pill:active, .chip-btn:active { transform: none; }
}
