/* RummiCard — © 2026 Richard Boulais & Claude */
/* ===================================================================
   RummiCard — feuille de style
   =================================================================== */
:root {
  --cw: 62px;              /* largeur de carte */
  --ch: 88px;              /* hauteur de carte */
  --radius: 8px;
  --felt: #15564a;
  --felt1: #186354;        /* haut du tapis */
  --felt2: #0e3e34;        /* bas du tapis */
  --gold: #f0b429;
  --ink: #e8edf5;
  --dim: #8b9ab0;
  --panel: rgba(255, 255, 255, .055);
  --stroke: rgba(255, 255, 255, .11);
  --s0: #242a36;
  --s1: #d42b3d;
  --s2: #1769cf;
  --s3: #138a5c;
  font-synthesis: none;
}

* {
  box-sizing: border-box; margin: 0; padding: 0;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;          /* pas de menu au doigt long */
  -webkit-tap-highlight-color: transparent;
  /* « manipulation » et non « none », et c'est un choix mesuré sur l'iPhone,
     le 14 octobre 2026 : « none » a bien supprimé le zoom à deux doigts, mais
     le double-tap sur une carte zoomait toujours — on se retrouvait agrandi
     sans aucun moyen de revenir. Le pincement est le seul recours qui
     fonctionne, il doit donc rester.
     Sur chaque élément, car « touch-action » ne s'hérite pas : posée sur
     « html, body » seulement, la règle laissait tout l'intérieur à « auto ».
     Safari ignore cette propriété pour le double-tap sur une carte — essayé
     en « none » comme en « manipulation », avec et sans garde-fou en
     JavaScript, et avec « maximum-scale », qui l'aggravait. La page ne peut
     pas l'empêcher. */
  touch-action: manipulation;
}

html, body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;            /* pas de rebond élastique */
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif;
  color: var(--ink);
  background:
    radial-gradient(1200px 700px at 50% -10%, #1b2740 0%, transparent 60%),
    linear-gradient(170deg, #0f1726 0%, #080c14 100%);
}

button { font: inherit; color: inherit; cursor: pointer; border: 0; background: none; }
button:disabled { cursor: default; }

.hidden { display: none !important; }

/* ---------- Écran d'accueil ---------------------------------------- */
#menu {
  position: absolute; inset: 0;
  padding-bottom: env(safe-area-inset-bottom);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 26px; text-align: center; padding: 30px;
}
#menu .logo {
  display: flex; align-items: center; gap: 14px;
  font-size: 46px; font-weight: 800; letter-spacing: -1.5px;
}
#menu .logo .mini { display: flex; gap: 4px; }
#menu .logo .mini .card { --cw: 34px; --ch: 48px; }
#menu .tag { color: var(--dim); font-size: 15px; max-width: 460px; line-height: 1.55; }
#menu h2 { font-size: 13px; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); font-weight: 600; }

.choices { display: flex; gap: 10px; }
/* Le chiffre seul : le titre de la rubrique dit deja ce qu'on compte. Les
   pastilles redeviennent carrees, et le chiffre occupe la place rendue. */
.choice {
  width: 58px; height: 58px; border-radius: 14px;
  background: var(--panel); border: 1px solid var(--stroke);
  display: grid; place-items: center;
  font-size: 26px; font-weight: 700; transition: .16s;
}
.choice:hover { background: rgba(255, 255, 255, .11); transform: translateY(-2px); }
.choice.on {
  background: linear-gradient(180deg, #2f7f68, #1d6252);
  border-color: #46a789; box-shadow: 0 6px 20px rgba(32, 120, 98, .45);
}

.cta {
  padding: 14px 42px; border-radius: 13px; font-size: 16px; font-weight: 700;
  background: linear-gradient(180deg, var(--gold), #d9971a); color: #2b1e04;
  box-shadow: 0 8px 24px rgba(240, 180, 41, .3); transition: .16s;
}
.cta:hover { transform: translateY(-2px); box-shadow: 0 12px 30px rgba(240, 180, 41, .42); }
.linkbtn { color: var(--dim); font-size: 13px; text-decoration: underline; text-underline-offset: 3px; }
.foot {
  position: absolute; bottom: 18px; left: 0; right: 0;
  text-align: center; font-size: 11.5px; color: rgba(255, 255, 255, .34);
}
.linkbtn:hover { color: var(--ink); }

/* ---------- Cadre de jeu ------------------------------------------- */
#game {
  position: absolute; inset: 0; display: flex; flex-direction: column; gap: 9px;
  padding: calc(10px + env(safe-area-inset-top)) calc(14px + env(safe-area-inset-right))
           calc(12px + env(safe-area-inset-bottom)) calc(14px + env(safe-area-inset-left));
}

header { display: flex; align-items: center; gap: 14px; flex: 0 0 auto; }
header .brand { font-size: 17px; font-weight: 800; letter-spacing: -.4px; }
header .brand span { color: var(--gold); }
.pill {
  display: flex; align-items: center; gap: 7px; padding: 5px 11px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--stroke); font-size: 12.5px; color: var(--dim);
}
.pill b { color: var(--ink); font-weight: 650; }
/* Largeur figée pour les pastilles dont le texte change en cours de partie :
   sans cela l'en-tête passait d'une rangée à deux selon le tour, et tout le
   plateau — donc toutes les cartes — se décalait. */
#turnpill { width: 118px; }
#meldpill { width: 152px; }
#turnpill, #meldpill { overflow: hidden; white-space: nowrap; }
.spacer { flex: 1; }
/* Les boutons d'icones ne cedent jamais un pixel : quand la ligne est trop
   courte, c'est le bandeau des joueurs qui se resserre — lui sait passer aux
   initiales. Sans cela, sur un telephone etroit, les boutons retrecissaient
   jusqu'a devenir impossibles a viser du doigt. */
.iconbtn {
  width: 32px; height: 32px; border-radius: 9px; background: var(--panel);
  border: 1px solid var(--stroke); font-size: 14px; display: grid; place-items: center;
  flex: 0 0 auto;
}
.iconbtn:hover { background: rgba(255, 255, 255, .12); }
/* Au doigt, la cible deborde le dessin : les boutons gardent leur petite
   taille — chaque pixel de l'entete est rendu aux cartes — mais s'atteignent
   sur toute la hauteur de la ligne. L'ecart entre deux voisins est preserve,
   pour qu'aucun ne vole le pouce destine a l'autre. */
@media (hover: none) and (pointer: coarse) {
  .iconbtn { position: relative; }
  .iconbtn::after { content: ''; position: absolute; inset: -8px -2px; }
}

/* ---------- Adversaires ------------------------------------------- */
#opponents { display: flex; gap: 9px; flex: 0 0 auto; flex-wrap: wrap; }

/* Bandeau compact des joueurs, logé dans la première ligne. Sur tablette et
   téléphone il remplace à lui seul la rangée des joueurs et les pastilles :
   une ligne de moins avant la table, et autant de hauteur rendue aux cartes. */
#oppmini { display: none; align-items: center; gap: 6px; min-width: 0; overflow: hidden; }
#oppmini .mini {
  display: flex; align-items: center; gap: 5px; padding: 4px 9px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--stroke);
  font-size: 12px; color: var(--dim); flex: 0 0 auto;
}
/* Réduites aux initiales, les pastilles acceptent de se serrer : à six
   joueurs sur un téléphone, mieux vaut quelques pixels de rembourrage en
   moins que la dernière coupée au bord. */
#oppmini.initiales .mini { flex: 0 1 auto; min-width: 0; padding: 4px 5px; gap: 3px; }
#oppmini .mini b { color: var(--ink); font-weight: 700; font-size: 11px; }
#oppmini .mini .nm { white-space: nowrap; }
#oppmini .mini .n { color: var(--ink); font-weight: 650; }
#oppmini .mini.actif {
  background: linear-gradient(180deg, rgba(240, 180, 41, .2), rgba(240, 180, 41, .07));
  border-color: rgba(240, 180, 41, .55); color: var(--ink);
}
#oppmini .mini.actif b { color: var(--gold); }
#oppmini .mini.pense .nm::after { content: ' \2026'; color: var(--gold); }
#oppmini .mini.pioche { color: var(--dim); }
#oppmini .mini .lbl { color: var(--dim); }
.opp {
  display: flex; align-items: center; gap: 8px; padding: 6px 11px 6px 8px; border-radius: 12px;
  background: var(--panel); border: 1px solid var(--stroke); transition: .22s;
  flex: 1 1 140px; min-width: 0; max-width: 195px; overflow: hidden;
}
.opp .av {
  width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center;
  font-weight: 700; font-size: 13px; background: #2b3448; color: #c6d2e6;
}
.opp .who { min-width: 0; overflow: hidden; }
.opp .nm { font-size: 13px; font-weight: 650; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.opp .sub { font-size: 10.5px; color: var(--dim); white-space: nowrap; }
.opp.active {
  background: linear-gradient(180deg, rgba(240, 180, 41, .18), rgba(240, 180, 41, .07));
  border-color: rgba(240, 180, 41, .5);
}
.opp.active .av { background: var(--gold); color: #2b1e04; }
.opp .fan { display: flex; margin-left: auto; padding-left: 6px; flex: 0 0 auto; }
.opp .fan i {
  width: 10px; height: 16px; border-radius: 2px; margin-left: -5px;
  background: linear-gradient(140deg, #3d4a63, #263046); border: 1px solid rgba(255, 255, 255, .14);
}
.opp.thinking .nm::after { content: ' …'; color: var(--gold); }

/* ---------- Plateau ----------------------------------------------- */
#boardwrap {
  flex: 1 1 auto; min-height: 0; border-radius: 16px; position: relative;
  background:
    radial-gradient(900px 420px at 50% 0%, rgba(255, 255, 255, .07), transparent 70%),
    linear-gradient(175deg, var(--felt1) 0%, var(--felt2) 100%);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .09), inset 0 -24px 60px rgba(0, 0, 0, .34), 0 10px 34px rgba(0, 0, 0, .38);
  border: 1px solid rgba(255, 255, 255, .08);
  overflow: hidden;
}
#boardwrap::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .5;
  background-image: radial-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 4px 4px;
}
#board { position: absolute; inset: 0; display: flex; overflow: hidden; }

/* Zones de la table : à gauche les suites, à droite les brelans et carrés. */
.zone {
  flex: 1 1 50%; min-width: 0; padding: 8px; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-wrap: wrap; align-content: flex-start; align-items: flex-start;
  gap: 11px;
}
.zone.full { flex: 1 1 100%; }

/* Table rangée : la hauteur d'une carte vaut sa valeur. */
.zone.grid { display: block; position: relative; overflow-x: auto; }
/* Décalé de l'angle : le tapis a un rayon de 16 px qui mangeait le « S »
   de « Suites ». */
.zone.grid .zonehead { position: absolute; top: 2px; left: 15px; margin: 0; width: auto; }
.zone.grid .set {
  position: absolute; padding: 0; background: none; border: 0; border-radius: 0;
}
.zone.grid .set.bad > .card {
  box-shadow: 0 0 0 2px #e24a4a, 0 0 10px rgba(226, 74, 74, .45), 0 2px 5px rgba(0, 0, 0, .34);
}
/* Table rangée : les combinaisons n'ont pas de cadre — chacune n'est qu'une
   colonne ou une ligne de cartes. Celle que « Magique » désigne se marque
   donc sur ses cartes, comme le fait l'anneau rouge d'une combinaison
   invalide. */
.zone.grid .set.montree > .card {
  box-shadow: 0 0 0 2px #8676ff, 0 0 10px rgba(134, 118, 255, .45), 0 2px 5px rgba(0, 0, 0, .34);
}
.zone.grid .set.target > .card, .zone.grid .set.target > .slot { z-index: 2; }
.zone.grid .newzone.tall {
  position: absolute; writing-mode: vertical-rl; text-orientation: mixed;
  padding: 10px 0; min-width: 0; line-height: 1.2;
}
.zone .ruler { position: absolute; inset: 0; pointer-events: none; }
.zone .ruler i {
  position: absolute; left: 0; width: 16px; text-align: right; font-style: normal;
  font-size: 9.5px; font-weight: 600; color: rgba(255, 255, 255, .34); line-height: 1;
}
.zone .ruler i.acehigh { color: rgba(240, 180, 41, .45); }
.zone .gridline {
  position: absolute; left: 20px; right: 6px; height: 1px;
  background: rgba(255, 255, 255, .055);
}
.zone .spacer { width: 1px; }

#board.split .zone + .zone { border-left: 1px dashed rgba(255, 255, 255, .16); }
.zonehead {
  width: 100%; margin-bottom: -4px; font-size: 10px; font-weight: 600;
  letter-spacing: .13em; text-transform: uppercase; color: rgba(255, 255, 255, .38);
}
#board.moyen { --cw: 54px; --ch: 77px; }
#board.dense { --cw: 48px; --ch: 68px; }
#board.denser { --cw: 40px; --ch: 57px; }
/* La consigne d'ouverture, inscrite au milieu du tapis. Elle est posée
   par-dessus la table plutôt que dans son flux : la table rangée n'a pas
   d'emplacement vide où l'écrire, et la consigne ne s'affichait donc que sur
   la table libre. Elle ne prend pas les clics, pour qu'on puisse glisser une
   carte au travers. */
.consigne {
  position: absolute; inset: 0; display: grid; place-items: center;
  pointer-events: none; padding: 16px; z-index: 1;
}
/* Table rangée : la phrase se range dans la moitié droite, à droite de la
   bande « nouveau groupe », sur trois lignes. Elle n'empiète alors sur aucune
   des deux zones de dépôt. La largeur est donnée en caractères : c'est elle
   qui fait les trois lignes, quelle que soit la taille des cartes. */
.consigne.droite { justify-items: start; }
.consigne.droite span { max-width: 22ch; text-align: left; }
.consigne span {
  text-align: center; color: rgba(255, 255, 255, .42); font-size: 14px;
  line-height: 1.6; max-width: 36ch;
}
/* Le gras est au fil de la phrase — « ouvrez la partie par une suite » —
   et non plus un titre en tête : c'est un message, pas un panneau. */
.consigne b { color: var(--gold); font-weight: 650; }

.set {
  display: flex; gap: 3px; padding: 6px; border-radius: 12px;
  background: rgba(0, 0, 0, .17); border: 1px solid rgba(255, 255, 255, .07);
  transition: box-shadow .18s, border-color .18s, background .18s;
}
.set.bad { border-color: rgba(226, 74, 74, .6); background: rgba(226, 74, 74, .12); }
.set.target { border-color: rgba(255, 255, 255, .6); box-shadow: 0 0 0 2px rgba(255, 255, 255, .22), 0 6px 20px rgba(0, 0, 0, .3); }
/* Combinaison que « Magique » désigne : son contenu change dans la solution
   montrée. Le violet est celui de son bouton — on reconnaît d'où vient la
   lumière. La couleur reste à l'intérieur du cadre de la combinaison, elle ne
   déborde donc sur aucune voisine. */
.set.montree {
  border-color: rgba(149, 134, 255, .75);
  background: rgba(101, 89, 214, .17);
  box-shadow: 0 0 0 2px rgba(101, 89, 214, .3);
}
.set.fresh { animation: pop .34s cubic-bezier(.2, .9, .3, 1.2); }
@keyframes pop { from { transform: scale(.9); opacity: .4; } }

.newzone {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  min-width: calc(var(--cw) + 12px); height: calc(var(--ch) + 12px); padding: 0 12px;
  border-radius: 12px; border: 1.5px dashed rgba(255, 255, 255, .22);
  color: rgba(255, 255, 255, .4); font-size: 11.5px; text-align: center; line-height: 1.3;
}
.newzone.target { border-color: rgba(255, 255, 255, .72); color: #fff; background: rgba(255, 255, 255, .09); }
/* Hors de votre tour : la zone garde sa place — sinon toute la table
   bougerait à chaque tour — mais s'efface. */
.newzone.off { opacity: .42; }

/* ---------- Carte -------------------------------------------------- */
.card {
  position: relative; width: var(--cw); height: var(--ch); flex: 0 0 auto;
  border-radius: var(--radius); background: linear-gradient(170deg, #fffdf7 0%, #f2ece0 100%);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .7) inset, 0 2px 5px rgba(0, 0, 0, .34);
  color: var(--s0); overflow: hidden; transition: transform .14s, box-shadow .14s;
}
.card .corner {
  position: absolute; top: 3px; left: 5px; right: 4px;
  display: flex; align-items: center; gap: 2px; line-height: 1;
}
.card .rank {
  font-size: calc(var(--ch) * .23); font-weight: 750; line-height: 1; letter-spacing: -.5px;
}
.card .cs { font-size: calc(var(--ch) * .185); line-height: 1; opacity: .9; }
.card .suit { position: absolute; right: 4px; bottom: 1px; font-size: calc(var(--ch) * .34); line-height: 1; opacity: .95; }
.card .mid {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: calc(var(--ch) * .30); font-weight: 700; opacity: .13;
}
.card.s0 { color: var(--s0); }
.card.s1 { color: var(--s1); }
.card.s2 { color: var(--s2); }
.card.s3 { color: var(--s3); }
.card.pickable:hover { transform: translateY(-5px); box-shadow: 0 8px 18px rgba(0, 0, 0, .4); }
.card.staged::after {
  content: ''; position: absolute; inset: 0; border-radius: var(--radius);
  box-shadow: inset 0 0 0 2px var(--gold);
}
/* Cartes que les joueurs virtuels viennent de poser, le temps d'un tour. */
.card.fromai::after {
  content: ''; position: absolute; inset: 0; border-radius: var(--radius);
  box-shadow: inset 0 0 0 2px #5bc8ff;
}
.zone.grid .card.fromai { box-shadow: 0 0 10px rgba(91, 200, 255, .55), 0 2px 5px rgba(0, 0, 0, .34); }
/* Vos cartes du tour en cours : même traitement que celles des joueurs
   virtuels, mais en doré — tant que « Au suivant ! » n'est pas cliqué, on
   voit d'un coup d'œil ce qu'on a posé et ce qu'on peut encore reprendre. */
.zone.grid .card.staged { box-shadow: 0 0 10px rgba(240, 180, 41, .5), 0 2px 5px rgba(0, 0, 0, .34); }
.card.staged.fromai::after { box-shadow: inset 0 0 0 2px var(--gold); }

.card.lifted { opacity: .25; }
.card.ghost {
  position: fixed; z-index: 90; pointer-events: none; margin: 0;
  box-shadow: 0 18px 34px rgba(0, 0, 0, .5);
  transform: rotate(-3deg) scale(1.08);
}
.card.landed { animation: land .4s cubic-bezier(.2, .9, .3, 1.3); }
@keyframes land {
  0% { transform: scale(1.14); box-shadow: 0 0 0 4px rgba(255, 255, 255, .5), 0 10px 22px rgba(0, 0, 0, .45); }
  100% { transform: none; }
}

/* Une suite se lit de haut en bas, cartes décalées : seul le coin
   (valeur + couleur) de chaque carte dépasse, la dernière est entière. */
.set.run { flex-direction: column; gap: 0; }
.set.run > * + * { margin-top: calc(var(--step, calc(var(--ch) * 0.28)) - var(--ch)); }
.set.run .card.pickable:hover { transform: translateX(7px); }
.set.run .card { box-shadow: 0 1px 0 rgba(255, 255, 255, .7) inset, 0 -1px 4px rgba(0, 0, 0, .3); }

/* Brelans et carrés : même principe, mais en largeur. Seule la tranche
   gauche de chaque carte reste visible — c'est elle qui porte la valeur et
   la couleur, comme sur un éventail tenu en main. */
.set.group { gap: 0; }
.set.group > * + * { margin-left: calc(var(--gstep, calc(var(--cw) * 0.45)) - var(--cw)); }
.set.group .card.pickable:hover { transform: translateY(-7px); }
.set.group .card { box-shadow: 1px 0 0 rgba(255, 255, 255, .55) inset, -1px 0 4px rgba(0, 0, 0, .3); }
/* Cette tranche est étroite : côte à côte, la valeur et le symbole de
   couleur n'y tiennent pas, et c'est le symbole qui se fait rogner — on ne
   sait plus de quelle couleur est la carte. L'un sous l'autre, les deux
   restent entiers. Même chose dans une main resserrée en éventail. */
.set.group .card .corner,
#rack.serre .card .corner {
  flex-direction: column; align-items: flex-start; gap: 1px;
}

.hole {
  width: var(--cw); height: var(--ch); flex: 0 0 auto; border-radius: var(--radius);
  border: 1.5px dashed rgba(255, 255, 255, .16); background: rgba(0, 0, 0, .14);
}

.slot {
  width: var(--cw); height: var(--ch); flex: 0 0 auto; border-radius: var(--radius);
  border: 2px dashed rgba(255, 255, 255, .65); background: rgba(255, 255, 255, .1);
  animation: breathe 1.1s ease-in-out infinite;
}
@keyframes breathe { 50% { background: rgba(255, 255, 255, .19); } }

/* ---------- Barre d'actions --------------------------------------- */
#bar { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.btn {
  padding: 9px 15px; border-radius: 11px; font-size: 13px; font-weight: 620;
  background: var(--panel); border: 1px solid var(--stroke); transition: .15s;
  display: flex; align-items: center; gap: 6px; white-space: nowrap;
}
.btn:hover:not(:disabled) { background: rgba(255, 255, 255, .13); transform: translateY(-1px); }
.btn:disabled { opacity: .34; }
/* Deux pictogrammes trop discrets pour ce qu'ils font. « Refaire » change de
   caractère : ⟲ était dessiné en trait fin dans une boîte large et vide —
   l'agrandir n'épaississait pas le trait. ↺ ferme son cercle et porte un trait
   plus épais à taille égale. Il reste monochrome, donc il prend la couleur du
   bouton et pâlit avec lui quand l'action n'est pas disponible, ce qu'un emoji
   en couleur ne ferait pas. « Quitter » gagne la moitié de sa taille.
   Le libellé garde la sienne, et l'interligne est bridé pour que la rangée ne
   grandisse pas — ce serait de la hauteur prise au tapis. */
#rewind { font-size: 26px; line-height: 17px; }
#rewind .lbl { font-size: 13px; line-height: normal; }
#restart { font-size: 21px; }
/* Quand la table ne tient plus et doit défiler, les boutons se réduisent à
   leur pictogramme : une rangée de moins, autant de tapis gagné. */
#game.compact .btn .lbl { display: none; }
#game.compact .btn { padding: 9px 12px; }
/* Les boutons devenus étroits, le message retrouve leur rangée : c'est de là
   que vient la hauteur rendue au plateau. */
#game.compact #msg { flex: 1 1 auto; order: 0; white-space: nowrap; height: 1.4em; }
/* Et quand les sept boutons ne tiennent pas sur une rangée, les trois
   principaux se réduisent eux aussi à leur pictogramme plutôt que de
   déborder sur une seconde — le cas du téléphone. */
#game.icones .btn .lbl { display: none; }
#game.icones .btn { padding: 9px 12px; }
.btn.go { background: linear-gradient(180deg, #2f9c76, #1d7a5c); border-color: #3fb68c; color: #fff; }
.btn.go:hover:not(:disabled) { box-shadow: 0 6px 18px rgba(45, 150, 115, .4); }
/* « Magique » porte la couleur de ce qu'il montre, comme « Indices » porte
   la sienne : éteint il se fond dans la barre avec les autres boutons ;
   allumé, il prend exactement le violet des cartes qu'il désigne. Le bouton
   et la lumière sur la table sont alors la même chose, et l'on voit d'un coup
   d'œil si la solution est affichée. */
.btn.magic.on {
  background: linear-gradient(180deg, #7a68f0, #5546c6);
  border-color: #9586ff; color: #fff;
}
.btn.magic.on:hover:not(:disabled) { box-shadow: 0 6px 18px rgba(134, 118, 255, .45); }

.btn.hint.on {
  background: linear-gradient(180deg, #caa02a, #a67d16); border-color: #e3bb49; color: #fff;
}

/* Cartes de la main que l'on peut poser. L'anneau reste dans le plan de sa
   carte : dans une main resserree, s'il passait au-dessus, on verrait des
   contours verts flotter par-dessus les cartes voisines. Seule la tranche
   visible se borde de vert, et cela suffit a la reconnaitre. */
#rack .card.playable::before {
  content: ''; position: absolute; inset: 0; border-radius: var(--radius);
  box-shadow: inset 0 0 0 2px #52d39a, 0 0 12px rgba(82, 211, 154, .5);
}
/* Cartes injouables : un voile uniforme, posé sur chaque carte. L'ancienne
   transparence laissait voir deux épaisseurs là où les cartes se
   chevauchent, et la tranche découverte de chaque carte paraissait plus
   claire que le reste — une bande verticale sur toute la main. */
.card .voile {
  position: absolute; inset: 0; border-radius: var(--radius);
  background: rgba(8, 12, 20, .55); pointer-events: none;
}
#rack .card:hover .voile.terne { background: rgba(8, 12, 20, .18); }
/* Projecteur : ce qui n'a pas bougé s'efface deux secondes, le temps qu'on
   voie ce qui vient d'arriver. */
/* Pas d'animation d'apparition : la table se redessine entierement a chaque
   coup des joueurs virtuels, et le voile, recree avec elle, rejouait son
   fondu a chaque fois — c'est ce qui faisait clignoter l'assombrissement. */
.card .voile.eteinte { background: rgba(8, 12, 20, .66); }

/* La dernière carte piochée : même bleu que les cartes fraîchement posées
   par les joueurs virtuels, puisque c'est le même propos — voici ce qui
   vient d'arriver. Si la carte est aussi jouable, l'anneau vert garde le
   bord et le bleu se glisse en dedans : les deux restent lisibles. */
/* Comme l'anneau vert, celui-ci reste dans le plan de sa carte : sa tranche
   visible se borde de bleu, et rien ne flotte au-dessus des voisines. */
#rack .card.piochee { box-shadow: 0 0 12px rgba(91, 200, 255, .6), 0 2px 5px rgba(0, 0, 0, .34); }
#rack .card.piochee::after {
  content: ''; position: absolute; inset: 0; border-radius: var(--radius);
  box-shadow: inset 0 0 0 2px #5bc8ff;
}
#rack .card.playable.piochee::after { inset: 3px; border-radius: calc(var(--radius) - 2px); }

/* Cartes que « Magique » désigne. Même violet que son bouton, et même
   précaution que pour les anneaux vert et bleu : l'anneau reste dans le plan
   de sa carte, pour qu'aucun contour ne flotte au-dessus des voisines dans
   une main resserrée. Il se glisse en dedans quand un autre anneau occupe
   déjà le bord. */
#rack .card.montree { box-shadow: 0 0 12px rgba(134, 118, 255, .65), 0 2px 5px rgba(0, 0, 0, .34); }
#rack .card.montree::after {
  content: ''; position: absolute; inset: 0; border-radius: var(--radius);
  box-shadow: inset 0 0 0 2px #8676ff;
}
#rack .card.playable.montree::after { inset: 3px; border-radius: calc(var(--radius) - 2px); }
/* Carte à la fois piochée et désignée : le violet prend le bord et le bleu
   cède la place. Les deux anneaux se disputent le même pseudo-élément, et
   entre « vous venez de la prendre » et « jouez-la », le second l'emporte. */

#msg {
  font-size: 12.5px; color: var(--dim); flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* Hauteur figée : un message avec émoji fait une ligne plus haute qu'un
     message sans, et la barre entière — donc le plateau, donc les cartes —
     se décalait d'un tour à l'autre. */
  line-height: 1.4; height: 1.4em;
}
#msg b { color: var(--gold); font-weight: 650; }
#msg.warn { color: #ffcf6b; }
#msg.good { color: #6fdcae; }

/* ---------- Main du joueur ---------------------------------------- */
#rackwrap {
  flex: 0 0 auto; border-radius: 14px; padding: 9px 10px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .07), rgba(255, 255, 255, .03));
  border: 1px solid var(--stroke); position: relative;
}
#rackwrap.target { border-color: rgba(255, 255, 255, .55); background: rgba(255, 255, 255, .11); }
/* Hauteur réservée constante : si elle suivait la taille des cartes, le
   plateau changerait de hauteur, donc de taille de cartes, donc la main —
   et l'affichage oscillerait entre deux états. */
#rack { display: flex; flex-wrap: wrap; gap: 4px; min-height: 88px; align-items: flex-end; }
#rack .card { cursor: grab; }
#rack .card:active { cursor: grabbing; }
.racklabel {
  position: absolute; top: -8px; left: 12px; font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--dim); background: #10182a; padding: 0 6px; border-radius: 4px;
}

/* ---------- Bulle d'aide au survol -------------------------------- */
#hint {
  position: fixed; z-index: 95; pointer-events: none; padding: 5px 10px; border-radius: 9px;
  background: rgba(10, 16, 28, .93); border: 1px solid var(--stroke); font-size: 11.5px;
  color: #fff; white-space: nowrap; box-shadow: 0 8px 20px rgba(0, 0, 0, .5);
}
#hint b { color: var(--gold); }

/* ---------- Superpositions ---------------------------------------- */
#overlay {
  position: absolute; inset: 0; z-index: 100; display: grid; place-items: center;
  background: rgba(6, 10, 18, .72); backdrop-filter: blur(7px); padding: 24px;
}
.panel {
  width: min(560px, 100%); max-height: 100%; overflow-y: auto; border-radius: 18px; padding: 26px 28px;
  background: linear-gradient(180deg, #19233a, #121a2c); border: 1px solid var(--stroke);
  box-shadow: 0 26px 70px rgba(0, 0, 0, .6);
}
.panel h2 { font-size: 22px; margin-bottom: 4px; letter-spacing: -.4px; }
.panel h3 { font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: var(--gold); margin: 14px 0 6px; }
.panel p, .panel li { font-size: 13.5px; line-height: 1.65; color: #c3cde0; }
.panel ul { padding-left: 18px; }
.panel .row { display: flex; gap: 10px; margin-top: 18px; }
/* La rangée de fin de partie : l'action principale prend la place que les
   boutons secondaires lui laissent. */
.panel .row.fin .cta { flex: 1; }
.optrow {
  display: flex; align-items: flex-start; gap: 11px; width: 100%; text-align: left;
  padding: 9px 12px; border-radius: 11px; border: 1px solid var(--stroke);
  background: var(--panel); margin-bottom: 6px; transition: .15s;
}
.optrow:hover { background: rgba(255, 255, 255, .11); }
.optrow .dot {
  width: 16px; height: 16px; border-radius: 50%; flex: 0 0 auto; margin-top: 2px;
  border: 1.5px solid rgba(255, 255, 255, .34);
}
.optrow.on { border-color: #46a789; background: rgba(47, 127, 104, .22); }
.optrow.on .dot { border-color: #6fdcae; background: #6fdcae; box-shadow: inset 0 0 0 3px #16304a; }
.optrow .lbl { display: flex; flex-direction: column; gap: 2px; }
.optrow .lbl b { font-size: 13.5px; font-weight: 650; }
.optrow .lbl em { font-style: normal; font-size: 12px; color: var(--dim); }

.scores { width: 100%; border-collapse: collapse; margin-top: 12px; }
.scores td { padding: 8px 6px; border-bottom: 1px solid rgba(255, 255, 255, .08); font-size: 13.5px; }
.scores tr.win td { color: var(--gold); font-weight: 700; }
.scores td.n { text-align: right; color: var(--dim); }
.trophy { font-size: 40px; text-align: center; margin-bottom: 6px; }

#toast {
  position: fixed; left: 50%; top: 14px; transform: translateX(-50%); z-index: 96;
  padding: 9px 16px; border-radius: 11px; font-size: 13px; font-weight: 600;
  background: rgba(10, 16, 28, .94); border: 1px solid var(--stroke);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .5); opacity: 0; transition: opacity .2s, transform .2s;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(4px); }
#toast .who { color: var(--gold); }

/* ===================================================================
   Adaptation aux écrans étroits
   -------------------------------------------------------------------
   La table décide elle-même de sa disposition (voir pickLayout) : tant
   que la largeur suffit, les suites et les groupes restent côte à côte ;
   sinon les deux grilles s'empilent, chacune sur toute la largeur. Le
   reste de l'habillage se replie par paliers.
   =================================================================== */

#board.stack { flex-direction: column; }
#board.stack .zone { min-height: 0; }
#board.split.stack .zone + .zone {
  border-left: 0; border-top: 1px dashed rgba(255, 255, 255, .16);
}

/* Hors ordinateur, la barre du bas perd son message : il passe en bulle
   temporaire, et sur une table vide il s'inscrit sur le tapis. Ces deux ou
   trois lignes rendues au plateau, ce sont des cartes plus grandes. */
@media (max-width: 1040px) {
  #bar { flex-wrap: wrap; }
  #msg { display: none; }
}
/* Le message du moment, inscrit sur une table vide : il garde les couleurs
   de la barre — doré pour un avertissement, vert quand le tour est bon. */


/* Tablette et téléphone : une seule ligne avant la table. Les pastilles et
   la rangée des joueurs laissent la place au bandeau compact, qui dit la
   même chose dans la ligne déjà occupée par les boutons d'icônes.
   Le doigt vaut la largeur : un iPad en paysage est plus large que bien des
   fenêtres d'ordinateur, et c'est pourtant lui qui a besoin de la place. */
@media (max-width: 1040px), (hover: none) and (pointer: coarse) {
  #game header .brand, #game header .pill, #game #opponents { display: none; }
  #game #oppmini { display: flex; }
  #game header { flex-wrap: nowrap; }
}

/* Tablette en portrait. */
@media (max-width: 820px) {
  #game {
    gap: 7px;
    padding-left: calc(9px + env(safe-area-inset-left));
    padding-right: calc(9px + env(safe-area-inset-right));
  }
  header { flex-wrap: wrap; gap: 9px; }
  .btn { padding: 9px 12px; }
  .opp { flex: 1 1 112px; }
}

/* Téléphone : seules les trois actions courantes gardent leur libellé,
   les autres se réduisent à leur pictogramme. */
@media (max-width: 620px) {
  header .brand, #meldpill { display: none; }
  .pill { padding: 4px 9px; font-size: 11.5px; }
  .iconbtn { width: 28px; height: 28px; font-size: 13px; }
  #hints .lbl, #auto .lbl, #sort .lbl, #rewind .lbl { display: none; }
  .btn { padding: 8px 11px; font-size: 14px; }
  #bar { gap: 6px; }
  /* Table pleine : chaque combinaison paie son rembourrage et l'écart qui la
     sépare de la suivante. Sur un téléphone, ces quelques pixels par rangée
     sont ce qui sépare une table entière d'une table qui défile. */
  .zone { gap: 6px; }
  .set { padding: 3px; gap: 2px; }
  /* Des pastilles plus étroites : quatre joueurs tiennent sur une rangée,
     et au-delà le retour à la ligne reste possible. */
  /* Le bandeau des joueurs se resserre encore : le nom cède la place au
     compte de cartes dès que la ligne devient étroite. */
  /* Chaque pixel compte : les trois noms ne tiennent sur la ligne qu'au
     prix de ces quelques unites d'ecart et de rembourrage. */
  #game header { gap: 5px; }
  #oppmini { gap: 4px; }
  #oppmini .mini { padding: 4px 5px; font-size: 11.5px; gap: 3px; }
  .iconbtn { width: 26px; height: 26px; font-size: 12.5px; }
  /* Le compte de la pioche cède sa place aux noms : sur une ligne de 357
     pixels, les deux ne tiennent pas, et savoir qui joue passe avant. */
  #oppmini .mini.pioche { display: none; }
  /* Les boutons au ras du bas : seule la zone réservée au trait tactile de
     l'iPhone est préservée, le rembourrage décoratif est rendu au tapis. */
  #game { padding-bottom: calc(2px + env(safe-area-inset-bottom)); gap: 5px; }
  #opponents { gap: 5px; }
  .opp { flex: 1 1 74px; min-width: 0; max-width: none; padding: 5px 7px; gap: 6px; }
  .opp .av { width: 26px; height: 26px; font-size: 12px; }
  .opp .nm { font-size: 11.5px; }
  .opp .sub, .opp .fan { display: none; }
  #rackwrap { padding: 8px; }
  /* La main tient sur une rangée grâce au chevauchement : on peut resserrer
     la hauteur réservée. Elle reste constante, pour ne pas faire osciller
     la taille des cartes. */
  #rack { min-height: 62px; }
  /* Trois boutons côte à côte ne tiennent pas dans un panneau large de
     284 pixels : « Nouvelle partie » se brisait en deux lignes et « Menu »
     sortait du cadre, derrière une barre de défilement. L'action principale
     prend donc la ligne entière, les deux autres se partagent la suivante.
     Le retour à la ligne vaut mieux qu'un libellé raccourci : « Gleiche
     Austeilung » et « Stessa distribuzione » sont plus longs encore que
     « Même donne ». */
  .panel .row.fin { flex-wrap: wrap; }
  .panel .row.fin .cta { flex-basis: 100%; }
  .panel .row.fin .btn { flex: 1; justify-content: center; }
}



/* La version, au pied du panneau des options : discrete, mais lisible sans
   quitter la partie. */
.versiontxt {
  margin: 10px 0 0; text-align: center;
  font-size: 11.5px; color: rgba(255, 255, 255, .34);
}

/* ---------- Le magicien, en deux saynètes ---------------------------
   Animées en CSS et non par element.animate() : c'est la seule façon que
   « prefers-reduced-motion » les arrête. Leur dernière image est l'image
   utile — table assombrie, doigt arrivé, carte posée — de sorte qu'arrêtées
   net par ce réglage, elles montrent encore ce qu'il faut voir. */
.demo {
  position: relative; display: flex; align-items: center; gap: 4px;
  margin: 10px 0 2px; padding: 10px 12px 18px; border-radius: 12px;
  background: linear-gradient(160deg, var(--felt1), var(--felt2));
  border: 1px solid var(--stroke); overflow: hidden;
}
.demo .dc {
  flex: 0 0 auto; width: 26px; height: 36px; border-radius: 5px;
  background: #f6f3ea; color: #1b2430; font-size: 11.5px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .45);
}
.demo .dc.rouge { color: #b4303a; }
.demo .dc.casse { box-shadow: 0 0 0 2px #c0564f, 0 1px 3px rgba(0, 0, 0, .45); }
.demo .dc.visee { box-shadow: 0 0 0 2px var(--gold), 0 1px 3px rgba(0, 0, 0, .45); }
.demo .ecart { flex: 0 0 auto; width: 10px; }
.demo .doigt {
  position: absolute; left: 14px; bottom: 5px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--gold);
  box-shadow: 0 0 0 4px rgba(240, 180, 41, .28);
  animation: demoDoigt 5s ease-in-out infinite;
}
/* La course du doigt est une classe, pas un attribut : sur un téléphone les
   cartes rétrécissent, et sa cible doit suivre. */
.demo .doigt.versMain { --vers: 148px; }
.demo .doigt.versTapis { --vers: 14px; }
/* Le voile du magicien, en plus sobre : on éteint par la luminosité. */
.demo .dc.sombre { animation: demoVoile 5s ease-in-out infinite; }
.demo .dc.arrive { animation: demoArrive 5s ease-in-out infinite; }

/* Sur un téléphone, neuf cartes et deux écarts ne tiennent pas à 26 px : la
   saynète rétrécit, et la course du doigt avec elle. Ce bloc vient après les
   règles de base — à spécificité égale, c'est le dernier qui l'emporte, et
   placé plus haut il était tout simplement écrasé. */
@media (max-width: 620px) {
  .demo { gap: 3px; padding-left: 8px; padding-right: 8px; }
  .demo .dc { width: 22px; height: 31px; font-size: 10px; }
  .demo .ecart { width: 7px; }
  .demo .doigt.versMain { --vers: 124px; }
  .demo .doigt.versTapis { --vers: 10px; }
}

@keyframes demoDoigt {
  0%, 8%    { transform: translateX(0); opacity: 0; }
  18%       { transform: translateX(0); opacity: 1; }
  34%, 100% { transform: translateX(var(--vers)); opacity: 1; }
}
@keyframes demoVoile {
  0%, 30%   { filter: none; }
  44%, 100% { filter: brightness(.4) saturate(.45); }
}
@keyframes demoArrive {
  0%, 58%   { opacity: 0; transform: scale(.55); }
  74%, 100% { opacity: 1; transform: none; }
}

/* ---------- Soutien -------------------------------------------------
   Des liens, pas des widgets : aucun script tiers n'est chargé, la
   politique de sécurité du contenu reste donc stricte et personne n'est
   pisté. Les boutons empilés gardent la même cible du doigt que les
   pastilles de tapis. */
.dons { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 2px; }
.donlien {
  display: block; padding: 12px 14px; border-radius: 11px; text-align: center;
  border: 1px solid var(--stroke); background: var(--panel);
  font-size: 14px; font-weight: 600; color: var(--ink);
  text-decoration: none; transition: .15s;
}
.donlien:hover { border-color: var(--gold); background: rgba(240, 180, 41, .12); }
.donjamais { margin-top: 12px; text-align: center; }
/* La ligne de fin de partie : une invitation, pas une réclame. */
.soutien {
  margin-top: 16px; text-align: center;
  font-size: 12.5px; color: rgba(255, 255, 255, .42);
}
.soutien .linkbtn { font-size: 12.5px; }

/* ---------- Couleur du tapis, dans les options ----------------------
   Chaque pastille porte la couleur qu'elle propose ; elles sont assez
   grandes pour être visées du doigt. */
.felts { display: flex; flex-wrap: wrap; gap: 10px; margin: 2px 0 6px; }
.feltdot {
  width: 44px; height: 44px; border-radius: 12px;
  border: 2px solid var(--stroke); transition: .15s;
}
.feltdot:hover { border-color: rgba(255, 255, 255, .45); }
.feltdot.on { border-color: var(--gold); box-shadow: 0 0 0 3px rgba(240, 180, 41, .25); }

/* ---------- Mouvement réduit ----------------------------------------
   Qui a demandé moins d'animation au niveau du système ne doit pas voir les
   cartes glisser d'un bout à l'autre de la table. Les durées tombent à
   presque rien plutôt qu'à zéro : les transitions continuent de se terminer,
   et le code qui les attend n'est pas pris en défaut. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Choix de la langue sur l'écran d'accueil ---------------- */
.langs { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 4px; }
.langbtn {
  padding: 5px 11px; border-radius: 999px; font-size: 12px; color: var(--dim);
  background: var(--panel); border: 1px solid var(--stroke); transition: .15s;
}
.langbtn:hover { background: rgba(255, 255, 255, .12); color: var(--ink); }
.langbtn.on { border-color: var(--gold); color: var(--gold); font-weight: 650; }

/* ---------- Téléphone couché : on demande de le redresser -----------
   La table se joue à la verticale ; en paysage un téléphone n'a plus la
   hauteur nécessaire. Le manifeste demande déjà le portrait à l'app
   installée, ce voile couvre les autres cas. */
#rotate { display: none; }
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  #rotate {
    display: grid; place-items: center; position: fixed; inset: 0; z-index: 200;
    padding: 24px; text-align: center;
    background: linear-gradient(170deg, #0f1726 0%, #080c14 100%);
  }
  #rotate b { display: block; font-size: 19px; margin-bottom: 8px; }
  #rotate b::before { content: '⟲'; display: block; font-size: 38px; color: var(--gold); margin-bottom: 10px; }
  #rotate span { font-size: 13.5px; color: var(--dim); }
}


/* ---------- Journal de mise au point -------------------------------- */
.jrn {
  width: 100%; height: 160px; margin-top: 10px; padding: 8px 10px;
  border-radius: 10px; border: 1px solid var(--stroke); background: rgba(0, 0, 0, .3);
  color: var(--dim); font-family: ui-monospace, Menlo, monospace; font-size: 10.5px;
  line-height: 1.45; resize: vertical; -webkit-user-select: text; user-select: text;
}
