/* ─────────────────────────────────────────────────────────────────────────────
   L'écran de jeu : cartes des joueurs, scène (dés 3D) et feuille de score.

   Trois dispositions selon la largeur :
     - étroit (téléphone)     : joueurs, scène, feuille, empilés ;
     - moyen (tablette, téléphone couché) : scène à gauche, feuille à droite ;
     - large (ordinateur)     : joueurs | scène | feuille.
   ───────────────────────────────────────────────────────────────────────────── */

.game {
  display: grid;
  gap: var(--gap);
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    'players'
    'stage'
    'sheet';
  align-content: start;
}

/* La colonne (ou la rangée) des joueurs, avec les réactions dessous.
   Elle passe au-dessus de la scène : une carte agrandie ou sa couronne ne
   doivent jamais être recouvertes par elle. */
.side {
  position: relative;
  z-index: 3;
  grid-area: players;
  display: grid;
  gap: 8px;
  align-content: start;
  min-width: 0;
}

.stage {
  grid-area: stage;
}

.sheet {
  grid-area: sheet;
}

@media (min-width: 720px) {
  .game {
    grid-template-columns: minmax(0, 1.1fr) minmax(330px, 0.9fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      'players sheet'
      'stage sheet';
    min-height: calc(100dvh - 64px - var(--pad));
  }
}

@media (min-width: 1180px) {
  .game {
    grid-template-columns: 240px minmax(0, 1fr) minmax(380px, 460px);
    grid-template-rows: 1fr;
    grid-template-areas: 'players stage sheet';
  }
}

/* ── Score des équipes (parties en équipes) ──────────────────────────────── */
/* Deux moitiés côte à côte ; l'équipe en tête prend sa couleur. */

.teamscore {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.teamscore[hidden] {
  display: none;
}

.teamscore__side {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  padding: 6px 12px;
  border-radius: var(--radius-s);
  background: var(--ink-2);
  box-shadow: inset 4px 0 0 var(--team);
  transition:
    background-color 300ms,
    color 300ms;
}

.teamscore__name {
  overflow: hidden;
  color: var(--team);
  font-weight: 800;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 300ms;
}

.teamscore__total {
  font-weight: 900;
  font-stretch: 125%;
  font-size: 1.3rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.teamscore__side.is-leading {
  background: var(--team);
  color: var(--ink-0);
}

.teamscore__side.is-leading .teamscore__name {
  color: var(--ink-0);
}

/* Sur grand écran, la colonne des joueurs est étroite : le nom de l'équipe
   passe au-dessus de son score, pour ne pas être coupé. */
@media (min-width: 1180px) {
  .teamscore__side {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }
}

/* ── Cartes des joueurs ──────────────────────────────────────────────────── */

/* En équipes : un liseré à la couleur de son équipe, en haut de la carte
   (épinglé, comme la couronne : la carte garde sa taille). */
.pcard__team {
  display: none;
  position: absolute;
  top: 0;
  left: 12px;
  right: 12px;
  height: 4px;
  border-radius: 0 0 4px 4px;
  background: var(--team);
}

.pcard.has-team .pcard__team {
  display: block;
}

.tag--team {
  color: var(--team);
  text-transform: uppercase;
}

.pcard.is-active .tag--team {
  color: inherit;
}

.players {
  display: flex;
  gap: 8px;
  min-width: 0;
}

.pcard {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas:
    'initial body'
    'score score';
  align-items: center;
  gap: 2px 8px;
  flex: 1 1 0;
  min-width: 0;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-s);
  background: var(--ink-2);
  color: var(--paper);
  text-align: left;
  transition:
    flex-grow 420ms var(--ease-out),
    transform 420ms var(--ease-spring),
    background-color 300ms,
    color 300ms,
    opacity 300ms;
}

.pcard:hover {
  background: var(--ink-3);
}

.pcard:active {
  transform: scale(0.96);
}

.pcard__initial .icon {
  width: 72%;
  height: 72%;
}

.pcard__initial {
  grid-area: initial;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: var(--c);
  color: var(--ink-0);
  font-weight: 900;
  font-size: 0.8rem;
  transition:
    background-color 300ms,
    color 300ms;
}

.pcard__body {
  grid-area: body;
  display: grid;
  min-width: 0;
  overflow: hidden; /* un nom ou une mention trop longs ne débordent pas sur le score */
}

.pcard__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 800;
  font-size: 0.92rem;
}

.pcard__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 8px;
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--paper-dim);
  transition: color 300ms;
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

/* Sur une carte, l'étiquette « robot » se fait plus petite, et sans icône :
   celle du robot est déjà juste à côté, à la place de l'initiale. */
.pcard__tags .bot-badge {
  padding-inline: 6px;
  font-size: 0.62rem;
}

.pcard__tags .bot-badge .icon {
  display: none;
}

/* Le compteur de tours (« 7/13 ») : combien de ses 13 tours ce joueur a joués.
   Il est épinglé sur la carte (comme la couronne), sans y prendre de place :
   la carte garde donc exactement sa taille, et rien ne bouge à l'écran. En
   bandeau, il est à cheval sur son bord inférieur ; sur grand écran, où la
   carte est plus haute, il tient dedans (voir plus bas). */
.pcard__turns {
  position: absolute;
  right: 10px;
  bottom: -9px;
  z-index: 1;
  padding: 1px 7px;
  border-radius: 7px;
  background: var(--ink-0);
  box-shadow: inset 0 0 0 1.5px var(--ink-4);
  color: var(--paper-dim);
  font-weight: 800;
  font-size: 0.7rem;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transition:
    background-color 300ms,
    color 300ms,
    box-shadow 300ms;
}

/* Sur la carte active, son liseré prend la couleur du joueur. */
.pcard.is-active .pcard__turns {
  box-shadow: inset 0 0 0 1.5px var(--c);
  color: var(--paper);
}

/* Il a déjà joué cette manche : un tour d'avance sur ceux qui attendent. Son compteur s'allume. */
.pcard .pcard__turns.is-ahead {
  background: var(--paper);
  box-shadow: none;
  color: var(--ink-0);
}

.tag .icon {
  width: 1em;
  height: 1em;
}

.pcard__score {
  grid-area: score;
  font-weight: 900;
  font-stretch: 125%;
  font-size: 1.5rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* Le joueur vient de marquer : son score bondit. */
.pcard.is-gaining .pcard__score,
#sheet-total.is-gaining {
  animation: score-pop 650ms var(--ease-spring);
}

#sheet-total {
  display: inline-block; /* pour pouvoir l'animer */
}

@keyframes score-pop {
  30% {
    transform: scale(1.5) rotate(-6deg);
  }
  60% {
    transform: scale(0.94);
  }
}

/* Le joueur dont c'est le tour : sa carte prend sa couleur et s'agrandit. */
.pcard.is-active {
  flex-grow: 1.9;
  background: var(--c);
  color: var(--ink-0);
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

.pcard.is-active .pcard__initial {
  background: var(--ink-0);
  color: var(--c);
}

.pcard.is-active .pcard__tags {
  color: var(--ink-1);
}

/* On regarde la feuille d'un autre joueur que celui qui joue : sa carte est cerclée. */
.pcard.is-viewed:not(.is-active) {
  box-shadow: inset 0 0 0 2px var(--c);
}

.pcard.is-offline {
  opacity: 0.6;
}

/* La couronne du meneur. */
.pcard__crown {
  position: absolute;
  top: -11px;
  right: 6px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--paper);
  color: var(--ink-0);
  rotate: 12deg;
  animation: crown-in 520ms var(--ease-spring) both;
}

.pcard__crown .icon {
  width: 16px;
  height: 16px;
}

@keyframes crown-in {
  from {
    transform: translateY(-16px) scale(0) rotate(-40deg);
  }
}

/* Tant que les cartes sont en bandeau (téléphone, tablette), chacune tient
   sur une ligne : initiale, nom, score. */
@media (max-width: 1179px) {
  .pcard {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: 'initial body score';
    min-height: 52px;
  }

  .pcard__score {
    font-size: 1.25rem;
  }

  /* À partir de 3 joueurs, les cartes inactives se réduisent à l'initiale et
     au score, empilés, pour laisser la place à la carte active. */
  .players:has(.pcard:nth-child(3)) {
    gap: 6px;
  }

  .players:has(.pcard:nth-child(3)) .pcard:not(.is-active) {
    grid-template-columns: 1fr;
    grid-template-areas:
      'initial'
      'score';
    justify-items: center;
    gap: 3px;
    padding: 6px 2px;
  }

  /* Carte réduite : le compteur se centre sous elle, un peu plus petit. */
  .players:has(.pcard:nth-child(3)) .pcard:not(.is-active) .pcard__turns {
    right: auto;
    bottom: -8px;
    left: 50%;
    translate: -50% 0;
    padding-inline: 5px;
    font-size: 0.62rem;
    line-height: 1.3;
  }

  .players:has(.pcard:nth-child(3)) .pcard:not(.is-active) .pcard__body {
    display: none;
  }

  .players:has(.pcard:nth-child(3)) .pcard:not(.is-active) .pcard__score {
    font-size: 1rem;
    font-stretch: 100%;
  }

  .players:has(.pcard:nth-child(3)) .pcard__tags {
    display: none;
  }

  .players:has(.pcard:nth-child(3)) .pcard.is-active {
    flex-grow: 2.6;
  }

  .players:has(.pcard:nth-child(3)) .pcard__crown {
    top: -9px;
    right: -4px;
    width: 22px;
    height: 22px;
  }
}

@media (min-width: 1180px) {
  .players {
    flex-direction: column;
    align-self: start;
    gap: 10px;
  }

  .pcard {
    flex: none;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: 'initial body score';
    gap: 12px;
    min-height: 72px;
    padding: 12px 16px 12px 12px;
    transform-origin: left center;
  }

  .pcard__initial {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    font-size: 1.3rem;
    font-stretch: 125%;
  }

  .pcard__name {
    font-size: 1.05rem;
  }

  /* La carte est assez haute pour loger le compteur sous le score : le score
     remonte d'autant (un simple décalage, la carte ne change pas de taille). */
  .pcard__score {
    font-size: 1.7rem;
    translate: 0 -9px;
  }

  .pcard__turns {
    right: 16px;
    bottom: 8px;
  }

  /* La carte active grossit vers la droite (son origine est à gauche). On
     reste en deçà de l'espace qui la sépare de la scène, pour ne pas la toucher. */
  .pcard.is-active {
    transform: scale(1.045);
  }

  .pcard__crown {
    top: -10px;
    right: -8px;
  }
}

/* ── Réactions ───────────────────────────────────────────────────────────── */

/* Les émojis et, à leur droite, le bouton « Dire » du chat (sur téléphone et
   tablette : il occupe la hauteur des deux rangées, sans en ajouter une). */
.banter {
  position: relative; /* le panneau des phrases se déplie par-dessus la table de jeu */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 6px;
}

/* Un spectateur n'a pas de bouton « Dire » : les émojis prennent toute la largeur. */
.banter:has(> .say[hidden]) {
  grid-template-columns: minmax(0, 1fr);
}

.say {
  display: grid;
}

.say__toggle {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 2px;
  width: 62px;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: var(--ink-3);
  color: var(--paper);
  font-weight: 800;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  transition:
    transform 200ms var(--ease-spring),
    background-color 200ms;
}

.say__toggle .icon {
  width: 24px;
  height: 24px;
  color: var(--p0);
}

.say__toggle:hover {
  transform: translateY(-3px);
  background: var(--ink-4);
}

.say__toggle:active {
  transform: scale(0.92);
}

.say__toggle[aria-expanded='true'] {
  background: var(--ink-4);
}

/* Le panneau des phrases : posé sous le bouton, au-dessus de la table. */
.say__panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  left: 0;
  z-index: 5;
  padding: 10px;
  border-radius: var(--radius-s);
  background: var(--ink-2);
  box-shadow:
    0 0 0 2px var(--ink-4),
    var(--shadow);
  animation: toast-in 240ms var(--ease-out) both;
}

@media (min-width: 1180px) {
  /* Sur ordinateur, la colonne des joueurs est étroite : le bouton passe sous les émojis. */
  .banter {
    grid-template-columns: minmax(0, 1fr);
  }

  .say__toggle {
    grid-auto-flow: column;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 44px;
    font-size: 0.85rem;
  }

  .say__panel {
    right: auto;
    width: 340px;
  }
}

/* Douze émojis, sur deux rangées de six. */
.reactions {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 6px;
}

.reaction {
  min-width: 0;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: var(--ink-2);
  font-size: 1.25rem;
  line-height: 1;
  transition:
    transform 200ms var(--ease-spring),
    background-color 200ms;
}

.reaction:hover {
  transform: translateY(-3px) scale(1.12);
  background: var(--ink-3);
}

.reaction:active {
  transform: scale(0.85);
}

/* « 2 spectateurs » et, dessous, les pseudos de ceux qui en ont un (ou, pour
   un spectateur : « Tu regardes la partie », avec qui). */
.watchers {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 12px;
  background: var(--ink-2);
  color: var(--paper-dim);
  font-size: 0.82rem;
  font-weight: 700;
}

.watchers[hidden] {
  display: none;
}

.watchers .icon {
  flex: none;
  color: var(--p0);
}

.watchers__text {
  display: grid;
  min-width: 0;
}

/* Les pseudos : plus lumineux que le nombre, c'est ce qu'on vient y lire. */
.watchers__names {
  color: var(--paper);
  overflow-wrap: anywhere;
}

/* ── Derniers coups ──────────────────────────────────────────────────────── */
/* Une ligne par coup : qui (à sa couleur), quelle case, combien. Sur
   téléphone et tablette, tout tient sur une ligne et seuls les deux derniers
   coups restent ; sur ordinateur, la colonne est étroite mais haute : chaque
   coup prend deux lignes, et on en montre six. */
.moves {
  display: grid;
  gap: 6px;
}

.moves__title {
  font-weight: 800;
  font-stretch: 112%;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--paper-dim);
}

.moves__list {
  display: grid;
  gap: 4px;
}

.move {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: 'who what points';
  align-items: center;
  column-gap: 10px;
  padding: 6px 10px 6px 8px;
  border-left: 4px solid var(--c);
  border-radius: 10px;
  background: var(--ink-2);
  font-size: 0.85rem;
  font-weight: 700;
}

/* Le plus récent : un peu plus en avant que les autres. */
.move:first-child {
  background: var(--ink-3);
}

.move__who {
  grid-area: who;
  max-width: 11ch;
  overflow: hidden;
  color: var(--c);
  font-weight: 800;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.move__who .icon {
  width: 1.05em;
  height: 1.05em;
  margin-right: 0.25em;
  vertical-align: -0.15em;
}

.move__what {
  grid-area: what;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--paper);
}

.move__what .row__icon {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--paper-dim);
}

.move__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* « d'office » : le tour d'un absent, joué par le serveur. */
.move__tag {
  flex: none;
  padding: 1px 6px;
  border-radius: 99px;
  background: var(--ink-4);
  color: var(--paper-dim);
  font-size: 0.72rem;
}

.move__points {
  grid-area: points;
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.move__bonus {
  margin-left: 4px;
  color: var(--p0);
  font-size: 0.8rem;
}

/* Une case sacrifiée (zéro) : en retrait. */
.move.is-zero .move__points {
  color: var(--paper-mute);
}

/* Un Yahtzee : la ligne s'allume à la couleur du joueur. */
.move.is-big {
  background: color-mix(in srgb, var(--c) 22%, var(--ink-2));
}

/* Un coup qui arrive glisse en tête du fil. */
.move.is-new {
  animation: move-in 520ms var(--ease-spring) both;
}

@keyframes move-in {
  from {
    transform: translateY(-10px) scale(0.96);
    opacity: 0;
    background: color-mix(in srgb, var(--c) 45%, var(--ink-3));
  }
}

/* Avant le premier coup. */
.moves__empty {
  padding: 8px 10px;
  border: 2px dashed var(--ink-3);
  border-radius: 10px;
  color: var(--paper-mute);
  font-size: 0.82rem;
  font-weight: 600;
}

@media (max-width: 1179px) {
  .move:nth-child(n + 3) {
    display: none;
  }

  /* La place des deux lignes est gardée d'avance : rien ne bouge quand les coups arrivent. */
  .move {
    min-height: 34px;
  }

  .moves__list {
    min-height: calc(2 * 34px + 4px);
    align-content: start;
  }
}

@media (min-width: 1180px) {
  /* La colonne des joueurs s'empile en flex, pour que le fil prenne la place
     qui reste, et pas plus : `contain: size` l'empêche d'allonger la colonne
     (et toute la page avec) quand six joueurs l'occupent déjà. Ce qui ne
     tient pas s'efface en fondu, en bas. */
  .side {
    display: flex;
    flex-direction: column;
  }

  .side > * {
    flex: none;
  }

  .side > .moves {
    flex: 1 1 auto;
    contain: size;
    align-content: start;
    margin-top: 6px;
    overflow: hidden;
    mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent);
  }

  .move {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      'who points'
      'what points';
    row-gap: 1px;
  }

  .move__who {
    max-width: none;
    font-size: 0.78rem;
  }
}

/* La réaction qui jaillit de la carte du joueur et se pose au-dessus de la
   table (animée en JS) : un gros autocollant rond, cerclé de la couleur du
   joueur, avec son nom en étiquette. */
.reaction-fly {
  position: fixed;
  z-index: 62;
  display: grid;
  justify-items: center;
  font-size: clamp(2.6rem, 11vw, 4.4rem);
  pointer-events: none;
  will-change: transform, opacity;
}

.reaction-fly__emoji {
  display: grid;
  place-items: center;
  width: 1.7em;
  height: 1.7em;
  border-radius: 50%;
  background: var(--ink-0);
  box-shadow:
    0 0 0 0.09em var(--c),
    0 0 0 0.13em var(--ink-0),
    0 0.16em 0 0.13em rgb(13 6 34 / 0.45);
  line-height: 1;
}

/* Une phrase du chat : même autocollant, mais c'est une bulle de texte. */
.reaction-fly__bubble {
  max-width: min(76vw, 15em);
  padding: 0.5em 0.9em 0.8em;
  border-radius: 1.1em;
  background: var(--paper);
  box-shadow:
    0 0 0 0.16em var(--c),
    0 0 0 0.24em var(--ink-0),
    0 0.32em 0 0.24em rgb(13 6 34 / 0.45);
  color: var(--ink-0);
  font-size: clamp(1.05rem, 4.4vw, 1.45rem);
  font-weight: 800;
  line-height: 1.2;
  text-align: center;
  text-wrap: balance;
}

.reaction-fly__name .icon {
  width: 1.1em;
  height: 1.1em;
  margin-right: 0.3em;
  vertical-align: -0.2em;
}

.reaction-fly__name {
  max-width: 12ch;
  margin-top: -0.5em;
  padding: 0.25em 0.8em;
  overflow: hidden;
  border-radius: 99px;
  background: var(--c);
  /* Un liseré sombre : l'étiquette reste lisible sur une table de la même couleur. */
  box-shadow: 0 0 0 2px var(--ink-0);
  color: var(--ink-0);
  font-size: clamp(0.78rem, 2.6vw, 0.95rem);
  font-weight: 800;
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* La carte de celui qui réagit fait un petit bond (la pastille, pour un spectateur). */
:is(.pcard, .watchers).is-reacting {
  animation: react-bump 420ms var(--ease-spring);
}

@keyframes react-bump {
  35% {
    transform: scale(1.12) rotate(-3deg);
  }
}

/* Le joueur courant tarde : le message d'aide palpite. */
.stage.is-hurrying .stage__hint {
  animation: hurry 700ms ease-in-out infinite alternate;
}

@keyframes hurry {
  to {
    transform: scale(1.06);
  }
}

/* ── La scène ────────────────────────────────────────────────────────────── */

.stage {
  --accent: var(--p0);
  --stage-gap: clamp(14px, 3vh, 34px);
  --roll-height: 66px; /* hauteur du bouton « Lancer » */
  --actions-gap: 12px;
  --hint-height: 2.9rem; /* deux lignes de texte d'aide */
  position: relative;
  z-index: 2; /* les dés qui volent passent au-dessus de la feuille de score */
  display: grid;
  /* Une colonne qui ne dépasse JAMAIS la largeur de la scène, même si un titre est long. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  gap: var(--stage-gap);
  min-height: clamp(300px, 44vh, 460px);
  padding: clamp(16px, 2.6vw, 30px);
  border-radius: var(--radius);
  color: var(--ink-0);
  /* Les dés se dimensionnent d'après la largeur de la scène (unités cqi). */
  container-type: inline-size;
}

/* Le fond coloré est dans un calque à part : lui seul est rogné aux coins
   arrondis, pour que les dés puissent arriver de l'extérieur de la scène. */
.stage__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  border-radius: inherit;
  box-shadow: var(--shadow);
}

.stage__fill {
  position: absolute;
  inset: 0;
  background-color: var(--p0);
  /* De gros points, ton sur ton : la face d'un dé géant. */
  background-image: radial-gradient(rgb(13 6 34 / 0.09) 30%, transparent 31%);
  background-size: 72px 72px;
}

/* Changement de tour : la couleur du joueur suivant s'ouvre en cercle depuis le bas. */
.stage__fill--next {
  clip-path: circle(0% at 50% 100%);
}

.stage__fill--next.is-wiping {
  animation: stage-wipe 600ms var(--ease-out) forwards;
}

@keyframes stage-wipe {
  to {
    clip-path: circle(150% at 50% 100%);
  }
}

/* Un score vient de tomber : la scène accuse le coup. */
.stage.is-thumping {
  animation: stage-thump 420ms var(--ease-out);
}

@keyframes stage-thump {
  25% {
    transform: scale(0.975);
  }
  60% {
    transform: scale(1.012);
  }
}

.stage__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

/* Le bloc du titre prend toute la place laissée par les compteurs de droite. */
.stage__head > :first-child {
  flex: 1 1 auto;
  min-width: 0;
}

/* Le titre tient sur une ligne, de hauteur constante. S'il est trop long, le
   JavaScript réduit ses lettres (--fit, voir fitTitle dans game.js) : la
   scène garde ainsi la même taille quel que soit le pseudo. */
.stage__title {
  --size: clamp(1.7rem, 7.4cqi, 4rem);
  font-weight: 900;
  font-stretch: 75%;
  font-size: calc(var(--size) * var(--fit, 1));
  line-height: calc(var(--size) * 0.92);
  letter-spacing: -0.01em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* Un robot joue : son icône précède le titre, à sa taille. */
.stage__title .icon {
  width: 0.82em;
  height: 0.82em;
  margin-right: 0.22em;
  vertical-align: -0.08em;
  stroke-width: 2.4;
}

.stage__title.is-entering {
  animation: title-in 620ms var(--ease-out) both;
}

@keyframes title-in {
  from {
    opacity: 0;
    transform: translateX(-28px) skewX(-12deg);
    clip-path: inset(0 100% 0 0);
  }
  to {
    clip-path: inset(-10% -10% -10% -10%);
  }
}

.stage__round {
  margin-top: 6px;
  font-weight: 700;
  font-size: 0.95rem;
}

/* À droite du titre : les lancers restants et la somme des dés. */
.stage__meters {
  display: grid;
  justify-items: end;
  gap: 6px;
  flex: none;
}

/* Invisibles, mais toujours à leur place : rien ne bouge quand ils apparaissent. */
.stage__sum.is-off,
.stage__keys.is-off {
  visibility: hidden;
}

.stage__sum {
  /* Largeur et hauteur fixes : « Somme 7 » ou « Somme 30 », la pastille ne change pas. */
  min-width: 7em;
  min-height: calc(1.45em + 8px);
  padding: 4px 10px;
  border-radius: 999px;
  background: rgb(13 6 34 / 0.14);
  font-weight: 800;
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  text-align: center;
  white-space: nowrap;
}

/* Lancers restants : trois pastilles pleines, qui se vident une à une. */
.rolls {
  display: flex;
  gap: 6px;
  padding: 8px 10px;
  border-radius: 999px;
  background: var(--ink-0);
}

.rolls__pip {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent);
  transition:
    transform 320ms var(--ease-spring),
    background-color 320ms;
}

.rolls__pip.is-spent {
  background: var(--ink-3);
  transform: scale(0.6);
}

/* Le bouton et le message d'aide occupent une zone de hauteur CONSTANTE. Quand
   ce n'est pas mon tour, le bouton disparaît et le message se centre dans la
   zone : la scène ne change pas de taille, la feuille de score ne bouge pas. */
.stage__actions {
  display: grid;
  justify-items: center;
  align-content: center;
  gap: var(--actions-gap);
  min-height: calc(var(--roll-height) + var(--actions-gap) + var(--hint-height));
}

.btn--roll {
  --btn-bg: var(--ink-0);
  --btn-fg: var(--paper);
  width: min(100%, 380px);
  min-height: var(--roll-height);
  border-radius: 20px;
  font-weight: 900;
  font-stretch: 125%;
  font-size: clamp(1.15rem, 4.4cqi, 1.5rem);
}

#skip-btn {
  font-stretch: 100%;
  font-size: 1.1rem;
}

.btn--roll:disabled {
  --btn-bg: rgb(13 6 34 / 0.22);
  --btn-fg: var(--ink-0);
}

/* Deux lignes sont toujours réservées au message ; un message court s'y centre. */
.stage__hint {
  display: grid;
  align-content: center;
  min-height: var(--hint-height);
  font-weight: 700;
  text-align: center;
  text-wrap: balance;
}

/* Rappel des raccourcis clavier. Absent par défaut : il n'a de sens que sur un
   appareil qui a une souris — donc, presque toujours, un clavier. Là, sa place
   est toujours réservée (il est seulement invisible hors de son tour). */
.stage__keys {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .stage__keys {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px 14px;
    /* Il suit de près le message d'aide, sans l'écart habituel entre les blocs de la scène. */
    margin-top: calc(var(--actions-gap) - var(--stage-gap));
    font-size: 0.78rem;
    font-weight: 700;
    opacity: 0.8;
  }
}

.stage__keys span {
  white-space: nowrap;
}

/* Une touche du clavier. */
.stage__keys kbd {
  display: inline-block;
  min-width: 1.7em;
  margin-inline: 1px;
  padding: 0.1em 0.45em;
  border-radius: 6px;
  background: var(--ink-0);
  color: var(--paper);
  font: inherit;
  font-size: 0.72rem;
  text-align: center;
}

/* ── Les dés ─────────────────────────────────────────────────────────────── */

.tray {
  --die: clamp(44px, 15cqi, 112px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--die) * 0.2);
  padding-block: calc(var(--die) * 0.3) calc(var(--die) * 0.22);
}

.die {
  position: relative;
  flex: none;
  width: var(--die);
  height: var(--die);
  padding: 0;
  border: 0;
  background: none;
  cursor: default;
  transition: transform 360ms var(--ease-spring);
}

.die:disabled {
  opacity: 1;
}

.tray.is-interactive .die {
  cursor: pointer;
}

.tray.is-interactive .die:hover {
  transform: translateY(-8%);
}

.tray.is-interactive .die:active {
  transform: scale(0.92);
}

.die:focus-visible {
  outline-offset: 8px;
  border-radius: 20%;
}

/* L'ombre au sol : décalée vers le bas, aux bords flous. */
.die__shadow {
  position: absolute;
  inset: 22% 4% -20%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(13 6 34 / 0.5), rgb(13 6 34 / 0));
  transition:
    transform 360ms var(--ease-out),
    opacity 360ms;
}

/* L'onde de choc quand le dé touche la table (animée en JS). */
.die__ring {
  position: absolute;
  inset: 0;
  border: 3px solid var(--ink-0);
  border-radius: 24%;
  opacity: 0;
  pointer-events: none;
}

/* Chaque dé a sa propre perspective : c'est elle qui donne la profondeur. */
.die__mover {
  position: absolute;
  inset: 0;
  perspective: calc(var(--die) * 5);
  /* On prévient le navigateur que ce bloc va bouger : il le prépare à
     l'avance, et le lancer démarre sans à-coup. */
  will-change: transform, opacity;
  /* Le dé qui vole ne prend jamais un clic : au départ d'un lancer, il est
     invisible mais deux fois plus grand, et posé sur le bouton « Relancer ».
     Le clic sur un dé, lui, arrive toujours au bouton .die, qui ne bouge pas. */
  pointer-events: none;
}

.die__cube {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  /* La face avant est plus proche de nous que le centre du cube : la
     perspective la grossit. On réduit donc un peu le cube (sur ses trois
     axes) pour que le dé posé tienne dans sa case sans toucher ses voisins. */
  scale: 0.88 0.88 0.88;
}

/* Les six faces : des carrés poussés d'un demi-dé vers l'extérieur, chacun
   dans sa direction. Elles sont volontairement carrées, sans coins arrondis :
   six carrés se rejoignent exactement sur les arêtes et forment un cube fermé.
   (Avec des faces arrondies, on voyait à travers les coins du dé.)
   L'arrondi est dessiné À L'INTÉRIEUR de chaque face : un fond clair (l'arête
   du dé) et, par-dessus, une plaque sombre aux coins ronds. */
.die__face {
  --half: calc(var(--die) / 2);
  --plate: var(--ink-0);
  position: absolute;
  inset: 0;
  display: grid;
  grid-template: repeat(3, 1fr) / repeat(3, 1fr);
  padding: 17%;
  background: var(--ink-3);
  backface-visibility: hidden; /* une face vue de dos n'est pas dessinée */
}

.die__face::before {
  content: '';
  position: absolute;
  inset: 4.5%;
  border-radius: 20%;
  background: var(--plate);
}

.die__face--1 {
  transform: translateZ(var(--half));
}
.die__face--6 {
  transform: rotateY(180deg) translateZ(var(--half));
}
/* Les côtés et le dessus sont un peu plus clairs : la lumière semble venir d'en haut. */
.die__face--3 {
  --plate: var(--ink-1);
  transform: rotateY(90deg) translateZ(var(--half));
}
.die__face--4 {
  --plate: var(--ink-1);
  transform: rotateY(-90deg) translateZ(var(--half));
}
.die__face--2 {
  --plate: var(--ink-2);
  transform: rotateX(90deg) translateZ(var(--half));
}
.die__face--5 {
  --plate: var(--ink-2);
  transform: rotateX(-90deg) translateZ(var(--half));
}

/* Les points. Leur case dans la grille 3 × 3 est fixée en JS (voir dice.js). */
.die__pip {
  position: relative; /* au-dessus de la plaque */
  place-self: center;
  width: 78%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--paper);
}

/* Le « 1 » : un seul gros point, à la couleur du joueur (comme le point rouge des vrais dés). */
.die__face--1 .die__pip {
  width: 120%;
  background: var(--accent, var(--p0));
  transition: background-color 400ms;
}

/* Dé pas encore lancé : il tourne lentement sur lui-même, en attente. */
.die.is-idle .die__cube {
  animation: die-idle 7s linear infinite;
  animation-delay: var(--idle-delay, 0s);
}

.die.is-idle .die__mover {
  animation: die-float 2.6s ease-in-out infinite alternate;
  animation-delay: var(--idle-delay, 0s);
}

@keyframes die-idle {
  from {
    transform: rotateX(var(--tilt-x)) rotateY(var(--tilt-y)) rotateX(0deg) rotateY(0deg);
  }
  to {
    transform: rotateX(var(--tilt-x)) rotateY(var(--tilt-y)) rotateX(360deg) rotateY(720deg);
  }
}

@keyframes die-float {
  from {
    transform: translateY(4%) scale(0.86);
  }
  to {
    transform: translateY(-8%) scale(0.92);
  }
}

/* Dé gardé : il se soulève, son ombre s'éloigne, un cadre et un cadenas apparaissent. */
.die.is-held,
.tray.is-interactive .die.is-held:hover {
  transform: translateY(-26%);
}

.die.is-held .die__shadow {
  transform: translateY(30%) scale(0.82);
  opacity: 0.55;
}

.die.is-held::before {
  content: '';
  position: absolute;
  inset: -6%;
  border: calc(var(--die) * 0.045) solid var(--ink-0);
  border-radius: 26%;
  animation: held-frame 320ms var(--ease-spring) both;
}

@keyframes held-frame {
  from {
    opacity: 0;
    transform: scale(1.35);
  }
}

.die__lock {
  position: absolute;
  top: -19%;
  right: -17%;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 46%;
  height: 46%;
  border-radius: 50%;
  background: var(--paper);
  color: var(--ink-0);
  transform: scale(0) rotate(-60deg);
  transition: transform 320ms var(--ease-spring);
  pointer-events: none;
}

.die__lock .icon {
  width: 62%;
  height: 62%;
}

.die.is-held .die__lock {
  transform: scale(1) rotate(0deg);
}

/* ── La feuille de score ─────────────────────────────────────────────────── */

.sheet {
  display: grid;
  /* Une colonne qui ne dépasse JAMAIS la largeur de la feuille. Sans cela, un
     long prénom dans le titre, plus l'aperçu du total (« → 144 »), élargissait
     toute la feuille au-delà de son cadre. Le titre, lui, se raccourcit (« … »). */
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  align-content: start;
  padding: clamp(12px, 2vw, 22px);
  border-radius: var(--radius);
  background: var(--ink-2);
  box-shadow: var(--shadow);
}

.sheet__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  padding: 2px 4px 0;
}

/* Le nom du joueur et, pour l'hôte, de quoi l'exclure : sur la même ligne,
   pour que l'en-tête garde la même hauteur que le bouton soit là ou non. */
.sheet__who {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  min-height: 34px;
}

.sheet__kick {
  flex: none;
  height: 30px;
  padding: 0 10px;
  border: 0;
  border-radius: 9px;
  background: var(--ink-3);
  color: var(--paper);
  font-weight: 700;
  font-size: 0.78rem;
  white-space: nowrap;
  transition:
    transform 180ms var(--ease-spring),
    background-color 180ms,
    color 180ms;
}

.sheet__kick:hover {
  background: var(--danger);
  color: var(--ink-0);
}

.sheet__kick:active {
  transform: scale(0.94);
}

/* Le « ? » qui ouvre les règles du jeu. */
.sheet__help {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ink-3);
  color: var(--paper);
  transition:
    transform 180ms var(--ease-spring),
    background-color 180ms;
}

.sheet__help .icon {
  width: 20px;
  height: 20px;
}

.sheet__help:hover {
  transform: scale(1.12) rotate(-8deg);
  background: var(--ink-4);
}

.sheet__help:active {
  transform: scale(0.9);
}

/* Feuille d'un robot : son icône précède le titre. */
.sheet__title .icon {
  margin-right: 0.35em;
  vertical-align: -0.24em;
}

.sheet__title {
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 800;
  font-stretch: 112%;
  font-size: 1.05rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--c);
  transition: color 300ms;
}

.sheet__total {
  flex: none; /* le total ne se comprime pas : c'est le titre qui cède la place */
  font-weight: 900;
  font-stretch: 125%;
  font-size: clamp(2.2rem, 6vw, 3.2rem);
  line-height: 0.9;
  font-variant-numeric: tabular-nums;
}

.sheet__cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.sheet__col {
  display: grid;
  /* Comme la feuille : une colonne qui ne dépasse jamais sa place. Sans cela,
     une ligne au contenu trop large (un long libellé, plus une note sous ses
     points) élargissait toutes les lignes de la colonne, hors de la feuille. */
  grid-template-columns: minmax(0, 1fr);
  gap: 6px;
  align-content: start;
}

.row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  width: 100%;
  min-height: 46px;
  padding: 0 12px;
  border: 0;
  border-radius: 12px;
  background: var(--ink-1);
  color: var(--paper-dim);
  text-align: left;
  transition:
    transform 200ms var(--ease-spring),
    background-color 220ms,
    color 220ms,
    box-shadow 220ms;
}

.row:disabled {
  cursor: default;
}

/* Le petit dessin de la combinaison (voir categoryIcons.js). */
.row__icon {
  flex: none;
  width: 22px;
  height: 22px;
}

.row__label {
  flex: 1; /* occupe la place entre le dessin et les points */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 700;
  font-stretch: 88%; /* un peu resserré : « Grande suite » tient sur un téléphone */
  font-size: 0.98rem;
}

.row__value {
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;
}

/* Case remplie. */
.row[data-state='filled'] {
  background: var(--ink-3);
  color: var(--paper);
}

/* Points possibles avec les dés actuels (vus par tous les joueurs). */
.row[data-state='option'] {
  color: var(--paper);
  box-shadow: inset 0 0 0 2px var(--c);
}

.row[data-state='option'] .row__value {
  color: var(--c);
}

.row[data-state='zero'] .row__value {
  color: var(--paper-mute);
}

/* Case libre mais interdite par la règle du joker. */
.row[data-state='blocked'] {
  opacity: 0.45;
}

/* C'est à moi de choisir : les lignes jouables deviennent de vrais boutons. */
.sheet.is-picking .row[data-state='option'] {
  background: var(--c);
  color: var(--ink-0);
  box-shadow: 0 8px 16px -10px rgb(5 2 16 / 0.9);
  animation: option-in 420ms var(--ease-spring) both;
}

.sheet.is-picking .row[data-state='option'] .row__value {
  color: var(--ink-0);
}

.sheet.is-picking .row[data-state='zero'] {
  box-shadow: inset 0 0 0 2px var(--ink-4);
}

.sheet.is-picking .row:not(:disabled):hover {
  transform: translateY(-2px) scale(1.025);
}

.sheet.is-picking .row[data-state='zero']:not(:disabled):hover {
  background: var(--ink-3);
  color: var(--paper);
}

.sheet.is-picking .row:not(:disabled):active {
  transform: scale(0.95);
  transition-duration: 60ms;
}

@keyframes option-in {
  from {
    transform: scale(0.92);
  }
}

/* Le coup de tampon : la valeur tombe de haut, de travers, et la ligne flashe. */
.row > * {
  position: relative; /* le texte reste au-dessus de l'aplat du tampon */
  z-index: 1;
}

.row.is-stamped {
  animation: row-flash 700ms var(--ease-out);
}

/* L'aplat de couleur du joueur couvre la ligne, puis se retire vers la droite. */
.row.is-stamped::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--c);
  transform-origin: right;
  animation: stamp-sweep 620ms cubic-bezier(0.7, 0, 0.2, 1) both;
}

.row.is-stamped > * {
  animation: stamp-ink 620ms steps(1) both;
}

@keyframes stamp-sweep {
  0%,
  30% {
    transform: scaleX(1);
  }
  100% {
    transform: scaleX(0);
  }
}

/* Tant que l'aplat est là, le texte passe en sombre pour rester lisible. */
@keyframes stamp-ink {
  0% {
    color: var(--ink-0);
  }
  55% {
    color: inherit;
  }
}

.row.is-stamped .row__value {
  animation:
    stamp 560ms var(--ease-spring) both,
    stamp-ink 620ms steps(1) both;
}

@keyframes stamp {
  0% {
    opacity: 0;
    transform: scale(3.2) rotate(-16deg);
  }
  45% {
    opacity: 1;
    transform: scale(0.86) rotate(4deg);
  }
  100% {
    transform: scale(1) rotate(0deg);
  }
}

@keyframes row-flash {
  0% {
    transform: scale(1.05);
  }
  30% {
    transform: scale(0.98);
  }
}

/* Les points d'une ligne et, dessous, l'aperçu « → 57/63 ». */
.row__points {
  display: grid;
  justify-items: end;
  flex: none;
  line-height: 1;
}

.row__after {
  font-weight: 800;
  font-stretch: 90%;
  font-size: 0.68rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
  opacity: 0.85;
}

.row__after:empty {
  display: none;
}

.row__after.is-bonus {
  opacity: 1;
  text-transform: uppercase;
}

/* ── Les bonus : sous les lignes, à plat, sans cadre de bouton ───────────── */

.sheet__bonus {
  display: grid;
  gap: 10px;
  padding: 10px 6px 2px;
  border-top: 2px solid var(--ink-3);
}

.bonus {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 2px 8px;
  padding-bottom: 9px; /* la place de la jauge */
  color: var(--paper-dim);
}

.bonus .row__icon {
  width: 20px;
  height: 20px;
  color: var(--c);
}

.bonus__text {
  display: grid;
  min-width: 0;
}

.bonus__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 800;
  font-stretch: 88%;
  font-size: 0.86rem;
  color: var(--paper);
}

/* « 2 d'avance pour le bonus » : la partie du détail qui compte. */
.bonus__pace {
  font-weight: 800;
  color: var(--paper);
}

.bonus__head {
  display: flex;
  align-items: center;
  min-width: 0;
}

/* Le « ? » à côté du titre : il déplie l'explication du bonus. */
.bonus__info {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: none;
  margin-left: 6px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ink-4);
  color: var(--paper);
  font-size: 0.72rem;
  font-weight: 900;
  line-height: 1;
  vertical-align: 1px;
  transition:
    transform 180ms var(--ease-spring),
    background-color 180ms;
}

/* Un petit rond, mais une vraie cible pour le doigt. */
.bonus__info::after {
  content: '';
  position: absolute;
  inset: -12px;
}

.bonus__info:hover {
  transform: scale(1.15);
}

.bonus__info[aria-expanded='true'] {
  background: var(--c);
  color: var(--ink-0);
}

.bonus[data-state='missed'] + .bonus__tip {
  opacity: 0.8;
}

/* L'explication dépliée, entre les deux bonus. */
.bonus__tip {
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--ink-0);
  color: var(--paper);
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.45;
  text-wrap: pretty;
  animation: tip-in 240ms var(--ease-out);
}

@keyframes tip-in {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
}

.bonus__detail {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  font-stretch: 88%;
  font-size: 0.74rem;
}

.bonus__value {
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
  color: var(--paper);
}

/* Bonus gagné : la valeur prend la couleur du joueur. */
.bonus[data-state='earned'] .bonus__value {
  color: var(--c);
}

.bonus[data-state='missed'] {
  opacity: 0.55;
}

/* Bonus Yahtzee sur le point de tomber (un Yahtzee de plus attend sa ligne) :
   la valeur à venir clignote doucement dans la couleur du joueur. */
.bonus[data-state='coming'] .bonus__value {
  color: var(--c);
  animation: bonus-coming 700ms ease-in-out infinite alternate;
}

.bonus[data-state='coming'] .bonus__detail {
  color: var(--paper);
}

@keyframes bonus-coming {
  to {
    opacity: 0.45;
  }
}

/* La jauge du bonus de 35. */
.bonus__bar {
  position: absolute;
  inset: auto 0 0;
  height: 5px;
  overflow: hidden;
  border-radius: 3px;
  background: var(--ink-0);
}

.bonus__fill,
.bonus__ghost {
  position: absolute;
  inset: 0;
  background: var(--c);
  transform: scaleX(var(--progress, 0));
  transform-origin: left;
  transition: transform 500ms var(--ease-out);
}

/* L'aperçu : plus clair, il dépasse la partie acquise jusqu'où mènerait le choix. */
.bonus__ghost {
  opacity: 0.4;
}

/* Le bonus est à portée avec les dés actuels : la jauge palpite. */
.bonus.is-reachable .bonus__ghost {
  animation: ghost-pulse 900ms ease-in-out infinite alternate;
}

@keyframes ghost-pulse {
  to {
    opacity: 0.85;
  }
}

/* Bonus qui vient d'être gagné : la valeur claque. */
.bonus.is-stamped .bonus__value {
  animation: stamp 700ms var(--ease-spring) both;
}

.bonus.is-stamped {
  animation: bonus-win 900ms var(--ease-out);
}

@keyframes bonus-win {
  0% {
    transform: scale(1.12);
  }
  40% {
    transform: scale(0.98);
  }
}

/* L'aperçu du total, à côté du total. */
.sheet__total {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.sheet__total-after {
  order: -1;
  color: var(--c);
  font-size: 0.45em;
  font-stretch: 100%;
  white-space: nowrap;
}

@media (min-width: 1180px) and (min-height: 760px) {
  .row {
    min-height: 60px;
    padding: 0 16px;
  }

  .sheet__col {
    gap: 8px;
  }

  .row__icon {
    width: 26px;
    height: 26px;
  }

  .row__label {
    font-stretch: 100%;
    font-size: 1.02rem;
  }

  .row__value {
    font-size: 1.3rem;
  }
}

/* Téléphone couché : peu de hauteur, on resserre la scène. */
@media (max-height: 520px) and (min-width: 720px) {
  .stage {
    --stage-gap: 8px;
    min-height: 0;
  }

  .row {
    min-height: 40px;
  }
}

/* Téléphone en mode portrait : la scène ne garde que l'essentiel, pour que la
   feuille de score reste à portée de pouce. (Placé en fin de fichier pour
   passer après les réglages généraux ci-dessus.) */
@media (max-width: 719px) {
  .stage {
    --stage-gap: 10px;
    --roll-height: 56px;
    --actions-gap: 8px;
    --hint-height: 2.56rem; /* deux lignes, dans la taille de texte du téléphone */
    min-height: 0;
    padding: 14px 14px 12px;
  }

  .stage__round {
    margin-top: 2px;
    font-size: 0.85rem;
  }

  .stage__hint {
    font-size: 0.88rem;
  }

  .sheet {
    gap: 8px;
  }

  .sheet__total {
    font-size: 2rem;
  }

  .row {
    min-height: 42px;
    padding: 0 8px;
    gap: 5px;
  }

  /* Le dessin prend de la place : on resserre encore un peu le libellé. */
  .row__icon {
    width: 20px;
    height: 20px;
  }

  .row__label {
    font-stretch: 80%;
    font-size: 0.94rem;
  }

  .row__value {
    font-size: 1.08rem;
  }
}
