/* ─────────────────────────────────────────────────────────────────────────────
   Mise en scène : annonces géantes, volets, tremblement, podium final,
   et la version atténuée pour « prefers-reduced-motion ».

   Les animations ne touchent qu'à transform, opacity et clip-path : le
   navigateur peut les confier à la carte graphique, elles restent fluides.
   ───────────────────────────────────────────────────────────────────────────── */

.fx-canvas,
.announcer,
.wipe {
  position: fixed;
  inset: 0;
  pointer-events: none; /* décoratif : ne bloque jamais un clic */
}

.fx-canvas {
  z-index: 65;
  width: 100%;
  height: 100%;
}

.announcer {
  z-index: 60;
  overflow: hidden;
}

.wipe {
  z-index: 80;
  overflow: hidden;
}

/* ── Annonces géantes ────────────────────────────────────────────────────── */

.announce {
  --field: clamp(170px, 40vh, 340px); /* hauteur du bandeau principal */
  --stripe: clamp(14px, 3.6vh, 34px); /* hauteur des deux bandes fines */
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: clamp(8px, 2vh, 18px);
  rotate: -4deg;
  /* Sortie : l'ensemble file vers le haut juste avant la fin (--d = durée totale). */
  animation: announce-out 300ms cubic-bezier(0.7, 0, 0.84, 0) forwards;
  animation-delay: calc(var(--d) - 310ms);
}

@keyframes announce-out {
  to {
    opacity: 0;
    transform: translateY(-14vh) scale(1.08);
  }
}

/* Le bandeau de couleur qui traverse l'écran derrière le texte. */
.announce__field {
  position: absolute;
  inset: 50% -20vw auto;
  height: var(--field);
  translate: 0 -50%;
  background: var(--c);
  box-shadow: 0 30px 60px -20px rgb(5 2 16 / 0.8);
  animation: band-in 460ms var(--ease-out) both;
}

@keyframes band-in {
  from {
    transform: scaleX(0);
    transform-origin: left;
  }
  to {
    transform-origin: left;
  }
}

/* Deux bandes fines encadrent le bandeau et arrivent en sens inverse :
   l'une sombre par la droite, l'autre claire par la gauche. */
.announce__stripe {
  position: absolute;
  inset: 0 -20vw auto;
  height: var(--stripe);
}

.announce__stripe--back {
  top: calc(50% - var(--field) / 2 - var(--stripe) - 12px);
  background: var(--ink-0);
  animation: stripe-from-right 520ms var(--ease-out) 60ms both;
}

.announce__stripe--front {
  top: calc(50% + var(--field) / 2 + 12px);
  background: var(--paper);
  animation: stripe-from-left 520ms var(--ease-out) 130ms both;
}

@keyframes stripe-from-right {
  from {
    transform: translateX(110%);
  }
}

@keyframes stripe-from-left {
  from {
    transform: translateX(-110%);
  }
}

.announce__text {
  position: relative;
  display: flex;
  /* Une fois les lettres posées, le mot entier « cogne ». */
  animation: text-punch 520ms var(--ease-spring) calc(var(--n) * 32ms + 430ms) both;
  color: var(--ink-0);
  font-weight: 900;
  font-stretch: 62%; /* très étroit : de très grandes lettres tiennent en largeur */
  /* La taille s'adapte au nombre de lettres (--n) pour remplir la largeur. */
  font-size: min(calc(190vw / var(--n)), 26vh, 12rem);
  line-height: 0.9;
  text-transform: uppercase;
  white-space: nowrap;
}

@keyframes text-punch {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.1) rotate(-1.5deg);
  }
  100% {
    transform: scale(1);
  }
}

/* Chaque lettre entre à son tour, en rebondissant. */
.announce__char {
  display: inline-block;
  animation: char-in 520ms var(--ease-spring) both;
  animation-delay: calc(var(--i) * 32ms + 90ms);
}

@keyframes char-in {
  from {
    opacity: 0;
    transform: translateY(70%) rotate(12deg) scale(0.5);
  }
}

.announce__sub {
  position: relative;
  padding: 0.5em 1.2em;
  border-radius: 999px;
  background: var(--ink-0);
  color: var(--paper);
  font-weight: 700;
  font-size: clamp(0.95rem, 2.4vw, 1.3rem);
  text-align: center;
  animation: sub-in 480ms var(--ease-spring) 380ms both;
}

@keyframes sub-in {
  from {
    opacity: 0;
    transform: translateY(20px) scale(0.8);
  }
}

/* Version « small » (Brelan) : pas de bandeau, une étiquette qui traverse. */
.announce--small .announce__field {
  display: none;
}

.announce--small .announce__text {
  padding: 0.1em 0.45em 0.04em;
  border-radius: 0.16em;
  background: var(--c);
  box-shadow: 0 24px 48px -18px rgb(5 2 16 / 0.85);
  font-size: min(calc(120vw / var(--n)), 18vh, 7rem);
  animation: tag-in 420ms var(--ease-spring) both;
}

@keyframes tag-in {
  from {
    opacity: 0;
    transform: translateX(-60vw) skewX(-18deg);
  }
}

.announce--small .announce__char {
  animation: none;
}

.announce--small .announce__sub {
  animation-delay: 220ms;
}

/* Version « mega » (Yahtzee) : la couleur envahit tout l'écran. */
.announce--mega .announce__field {
  inset: -30vh -30vw;
  height: auto;
  translate: none;
  box-shadow: none;
  animation: flood 560ms var(--ease-out) both;
}

@keyframes flood {
  from {
    clip-path: circle(0% at 50% 55%);
  }
  to {
    clip-path: circle(100% at 50% 55%);
  }
}

.announce--mega .announce__text {
  font-size: min(calc(190vw / var(--n)), 40vh, 18rem);
}

.announce--mega .announce__char {
  animation:
    char-in 560ms var(--ease-spring) both,
    char-bounce 620ms ease-in-out 3;
  animation-delay:
    calc(var(--i) * 45ms + 420ms),
    calc(var(--i) * 45ms + 1000ms);
}

@keyframes char-bounce {
  50% {
    transform: translateY(-9%) scaleY(1.08);
  }
}

.announce--mega .announce__sub {
  animation-delay: 900ms;
}

/* ── Éclair ──────────────────────────────────────────────────────────────── */
/* Un seul éclair bref par annonce (jamais de clignotement répété). */

.flash {
  position: absolute;
  inset: 0;
  background: var(--c);
  animation: flash 420ms ease-out both;
}

@keyframes flash {
  from {
    opacity: 0.8;
  }
  to {
    opacity: 0;
  }
}

/* ── Volets ──────────────────────────────────────────────────────────────── */

/* Changement d'écran : un pan de couleur traverse et masque tout un instant. */
.wipe__panel {
  position: absolute;
  inset: 0 -12vw;
  background: var(--c);
  animation: wipe 820ms cubic-bezier(0.7, 0, 0.25, 1) both;
}

@keyframes wipe {
  0% {
    transform: translateX(-100%) skewX(-8deg);
  }
  40%,
  48% {
    transform: translateX(0) skewX(0deg);
  }
  100% {
    transform: translateX(100%) skewX(-8deg);
  }
}

/* « À toi de jouer » : un bandeau file en travers, sans masquer le jeu. */
.banner {
  position: absolute;
  inset: 42% -10vw auto;
  display: grid;
  place-items: center;
  padding: clamp(10px, 2vh, 20px) 0;
  rotate: -3deg;
  background: var(--c);
  box-shadow: 0 24px 48px -18px rgb(5 2 16 / 0.85);
  animation: banner 1400ms cubic-bezier(0.2, 0.9, 0.2, 1) both;
}

.banner__label {
  color: var(--ink-0);
  font-weight: 900;
  font-stretch: 70%;
  /* --n = nombre de lettres : un long pseudo rétrécit le texte au lieu de déborder. */
  font-size: min(calc(170vw / var(--n, 14)), 11vw, 7rem);
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
  animation: banner-label 1400ms cubic-bezier(0.2, 0.9, 0.2, 1) both;
}

@keyframes banner {
  0% {
    transform: translateX(-110%);
  }
  22%,
  70% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(110%);
  }
}

/* Le texte glisse un peu à contresens du bandeau : effet de parallaxe. */
@keyframes banner-label {
  0% {
    transform: translateX(30%);
  }
  22% {
    transform: translateX(2%);
  }
  70% {
    transform: translateX(-2%);
  }
  100% {
    transform: translateX(-30%);
  }
}

/* ── Tremblement d'écran ─────────────────────────────────────────────────── */

#app.is-shaking {
  animation: shake-soft 420ms linear;
}

#app.is-shaking[data-shake='hard'] {
  animation: shake-hard 620ms linear;
}

@keyframes shake-soft {
  15% { transform: translate(-4px, 2px); }
  30% { transform: translate(4px, -3px); }
  45% { transform: translate(-3px, -1px); }
  60% { transform: translate(2px, 2px); }
  80% { transform: translate(-1px, 0); }
}

@keyframes shake-hard {
  8% { transform: translate(-11px, 6px) rotate(-0.5deg); }
  16% { transform: translate(10px, -8px) rotate(0.5deg); }
  24% { transform: translate(-9px, -5px) rotate(-0.4deg); }
  32% { transform: translate(8px, 7px) rotate(0.4deg); }
  42% { transform: translate(-6px, 4px); }
  54% { transform: translate(5px, -4px); }
  68% { transform: translate(-3px, 2px); }
  84% { transform: translate(2px, -1px); }
}

/* ── Classement final ────────────────────────────────────────────────────── */

.results {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  overflow-y: auto;
  background-color: var(--ink-0);
  background-image: radial-gradient(var(--ink-2) 2.5px, transparent 3px);
  background-size: 30px 30px;
  animation: results-in 700ms var(--ease-out) both;
}

@keyframes results-in {
  from {
    clip-path: circle(0% at 50% 100%);
  }
  to {
    clip-path: circle(150% at 50% 100%);
  }
}

.results {
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

.results__inner {
  display: grid;
  gap: clamp(12px, 2.4vh, 24px);
  justify-items: center;
  align-content: center;
  width: min(100%, 860px);
  margin: auto;
  padding: clamp(20px, 5vh, 56px) var(--pad);
  text-align: center;
}

/* Le nom du vainqueur n'apparaît qu'une fois le podium monté (classe is-revealed). */
.results__title {
  padding: 0.12em 0.4em 0.06em;
  border-radius: 0.14em;
  background: var(--c);
  color: var(--ink-0);
  font-weight: 900;
  font-stretch: 100%;
  font-size: clamp(2.4rem, 11vw, 6.6rem);
  line-height: 0.95;
  text-transform: uppercase;
  text-wrap: balance;
  rotate: -3deg;
  opacity: 0;
}

.results__sub,
.titles,
.results__record,
.results__series,
.results__rest,
.results__actions {
  opacity: 0;
}

/* Record personnel battu : une étiquette à la couleur du vainqueur. */
.results__record {
  padding: 0.45em 1em;
  border-radius: 999px;
  background: var(--c);
  color: var(--ink-0);
  font-weight: 800;
}

/* Le palmarès : une étiquette par titre, cerclée de la couleur du joueur. */
.titles {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  max-width: 640px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.titles__item {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 0.4em 0.9em;
  border-radius: 999px;
  background: var(--ink-2);
  box-shadow: inset 0 0 0 2px var(--c);
  font-weight: 700;
}

.titles__title {
  color: var(--c);
  font-weight: 800;
  font-stretch: 112%;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Le score de la série de revanches. */
.results__series {
  font-weight: 800;
  font-stretch: 105%;
  font-size: clamp(1rem, 2.6vw, 1.25rem);
}

.results.is-revealed .results__title {
  opacity: 1;
  animation: title-slam 720ms var(--ease-spring) both;
}

@keyframes title-slam {
  0% {
    opacity: 0;
    transform: scale(3.4) rotate(9deg);
  }
  55% {
    opacity: 1;
    transform: scale(0.92) rotate(-1deg);
  }
}

.results.is-revealed :is(.results__sub, .titles, .results__record, .results__series, .results__rest, .results__actions) {
  opacity: 1;
  animation: rise-in 600ms var(--ease-out) both;
}

.results.is-revealed .results__sub {
  animation-delay: 250ms;
}
.results.is-revealed .results__rest {
  animation-delay: 400ms;
}
.results.is-revealed .results__actions {
  animation-delay: 700ms;
}

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

.results__sub {
  font-weight: 700;
  font-size: clamp(1.1rem, 3vw, 1.5rem);
}

/* Le podium : trois colonnes qui montent du sol. overflow: hidden les cache
   tant qu'elles sont « sous terre ». */
.podium {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(8px, 2vw, 18px);
  width: 100%;
  margin-top: clamp(4px, 2vh, 20px);
  overflow: hidden;
  --step: clamp(96px, 22vh, 200px); /* hauteur de la plus haute marche */
}

.podium__step {
  display: grid;
  justify-items: center;
  gap: 2px;
  flex: 1 1 0;
  min-width: 0;
  max-width: 220px;
  transform: translateY(101%);
  transition: transform 800ms var(--ease-out);
}

.podium__step.is-up {
  transform: translateY(0);
}

/* Ordre visuel classique : 2ᵉ à gauche, 1ᵉʳ au centre, 3ᵉ à droite. */
.podium__step[data-place='1'] {
  order: 2;
}
.podium__step[data-place='2'] {
  order: 1;
}
.podium__step[data-place='3'] {
  order: 3;
}

/* Un robot au classement : son icône précède son pseudo. */
:is(.podium__name, .results__name, .titles__who) .icon {
  width: 1.1em;
  height: 1.1em;
  margin-right: 0.3em;
  vertical-align: -0.2em;
}

.podium__name {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 800;
  font-size: clamp(0.95rem, 2.6vw, 1.3rem);
}

.podium__score {
  color: var(--c);
  font-weight: 900;
  font-stretch: 125%;
  font-size: clamp(1.6rem, 5.4vw, 3rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.podium__block {
  display: grid;
  justify-items: center;
  align-content: start;
  width: 100%;
  height: var(--step);
  margin-top: 8px;
  padding-top: 10px;
  border-radius: 18px 18px 0 0;
  background: var(--c);
}

.podium__step[data-place='2'] .podium__block {
  height: calc(var(--step) * 0.7);
}

.podium__step[data-place='3'] .podium__block {
  height: calc(var(--step) * 0.46);
}

.podium__rank {
  color: var(--ink-0);
  font-weight: 900;
  font-stretch: 125%;
  font-size: clamp(1.8rem, 6vw, 3.4rem);
  line-height: 1;
}

.results__rest {
  display: grid;
  gap: 6px;
  width: min(100%, 420px);
}

.results__rest:empty {
  display: none;
}

.results__rest li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-radius: var(--radius-s);
  background: var(--ink-2);
  font-weight: 700;
}

.results__rank {
  color: var(--paper-dim);
}

.results__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

.results__points {
  color: var(--c);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}

.results__actions {
  display: grid;
  gap: 10px;
  justify-items: center;
  margin-top: 6px;
  /* Tous les boutons s'alignent sur cette largeur : celle de « Revanche ». */
  --actions-width: min(100%, 380px);
}

/* « Revanche » : le plus gros bouton, sur toute la largeur du groupe. Il la
   garde, que la revanche soit demandée ou non. */
#replay-btn {
  width: var(--actions-width);
}

/* Juste en dessous : « Partager » et « Quitter », plus petits, de même
   taille, côte à côte. S'il n'y en a qu'un (pas de résultat à partager), il
   prend toute la largeur. */
.results__more {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 10px;
  width: var(--actions-width);
}

.results__more .btn {
  min-height: 48px;
  padding-inline: 0.8em;
  font-size: 0.92rem;
}

/* Où en est la revanche. Deux lignes sont toujours réservées : le texte change
   à chaque accord, et ce qui suit ne doit pas bouger. */
.results__wait {
  display: grid;
  align-content: center;
  min-height: 2.9em;
  max-width: 36ch;
  font-weight: 700;
  text-align: center;
  text-wrap: balance;
}

/* ── La chance, chiffrée ─────────────────────────────────────────────────── */
/* Un tableau sous les boutons : une ligne par joueur, avec son petit graphique
   (la part de chaque face parmi ses dés) et ses points de chance. Les lignes
   et le pied partagent les mêmes colonnes : les graphiques s'alignent, et se
   comparent d'un coup d'œil (voir js/ui/luck.js). */

.luck {
  --plot: 108px; /* largeur d'un graphique : six colonnes de 18 px */
  --points: 3.2em; /* largeur de la colonne des points */
  display: grid;
  gap: 10px;
  width: min(100%, 520px);
  margin-top: 6px;
  padding: clamp(14px, 3vw, 20px);
  border-radius: var(--radius-s);
  background: var(--ink-2);
  text-align: left;
}

.luck__title {
  margin: 0;
  color: var(--paper);
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.05rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.luck__lead {
  color: var(--paper-dim);
  font-weight: 500;
  font-size: 0.88rem;
  line-height: 1.4;
  text-wrap: pretty;
}

.luck__list {
  display: grid;
}

.luck__row,
.luck__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--plot) var(--points);
  align-items: center;
  gap: 12px;
  border-top: 1px solid var(--ink-3);
}

.luck__row {
  padding: 9px 0 8px;
}

/* Le joueur : son pseudo, précédé d'une pastille de sa couleur, et dessous la
   formule (« de la veine »), qui laisse place au détail d'une face au survol. */
.luck__who {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.luck__name {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-weight: 800;
}

.luck__pseudo {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.luck__dot {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 4px;
  background: var(--c);
}

.luck__name .icon {
  flex: none;
  width: 1.1em;
  height: 1.1em;
  margin-right: -2px;
}

/* (Sur un écran très étroit, la formule passe sur deux lignes plutôt que d'être coupée.) */
.luck__word {
  color: var(--paper-dim);
  font-weight: 600;
  font-size: 0.8rem;
  line-height: 1.25;
}

/* Le graphique : six colonnes posées sur une ligne de base. Derrière elles,
   un trait fin marque la part attendue (une face sur six) : une colonne qui le
   dépasse est une face sortie plus souvent que la moyenne. --fair est sa
   hauteur, fixée en JS d'après l'échelle commune à tous les graphiques. */
.luck__plot {
  position: relative;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  height: 40px;
  border-bottom: 1px solid var(--ink-4);
}

.luck__plot::before {
  content: '';
  position: absolute;
  inset: auto 0 var(--fair);
  height: 1px;
  background: var(--paper-mute);
}

/* Une colonne : sa zone sensible prend toute la hauteur, la barre part du bas. */
.luck__slot {
  position: relative; /* au-dessus du trait */
  display: grid;
  align-items: end;
  justify-items: center;
}

.luck__bar {
  width: 12px;
  border-radius: 3px 3px 0 0;
  background: var(--c);
  transition: filter 150ms;
}

.luck__slot:hover .luck__bar {
  filter: brightness(1.3) saturate(1.2);
}

.luck__points {
  justify-self: end;
  font-weight: 900;
  font-stretch: 125%;
  font-size: 1.25rem;
  line-height: 1;
  font-variant-numeric: tabular-nums; /* une colonne de nombres : ils s'alignent */
  white-space: nowrap;
}

/* Le pied : ce que veut dire le trait, l'axe des six faces, et l'unité. */
.luck__foot {
  align-items: start;
  padding-top: 6px;
  color: var(--paper-mute);
  font-weight: 700;
  font-size: 0.72rem;
  line-height: 1.3;
}

.luck__key {
  display: flex;
  align-items: baseline;
  gap: 7px;
  min-width: 0;
}

.luck__key-line {
  flex: none;
  width: 16px;
  height: 1px;
  background: var(--paper-mute);
  translate: 0 -0.3em;
}

.luck__axis {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.luck__unit {
  justify-self: end;
}

/* Revanche demandée : le bouton s'efface, on attend les autres. */
#replay-btn[aria-pressed='true'] {
  --btn-bg: var(--ink-3);
  --btn-fg: var(--paper);
}

/* ── L'affichette de fin de partie ───────────────────────────────────────── */
/* Une réclame pour notre autre jeu, Dada : une fenêtre au milieu de l'écran,
   par-dessus le classement assombri (voir js/ui/poster.js). Elle porte les
   couleurs de Dada et non celles d'ici : la mer, l'écume, le jaune du soleil.
   On voit d'emblée qu'elle parle d'ailleurs. */

.poster {
  --sea: #0e5158;
  --sea-light: #17717a;
  --foam: #eaf4ee;
  --sun: #f7b81f;
  --pitch: #0b2228;
  --mascot: clamp(104px, 30vw, 128px); /* la largeur du homard */
  width: min(calc(100vw - 32px), 420px);
  max-height: none;
  padding: 0 26px 24px;
  border: 0;
  border-radius: var(--radius);
  background: var(--sea);
  color: var(--foam);
  /* Un liseré plus clair la détache du fond, puis l'ombre la soulève. */
  box-shadow:
    inset 0 0 0 2px var(--sea-light),
    0 24px 48px -12px rgb(5 2 16 / 0.9);
  text-align: center;
  overflow: visible; /* pour le homard */
}

.poster[open] {
  display: grid;
  justify-items: center;
  gap: 10px;
  animation: poster-in 520ms var(--ease-spring) both;
}

.poster::backdrop {
  background: rgb(13 6 34 / 0.8);
  animation: fade-in 260ms ease-out both;
}

/* La fenêtre reçoit le clavier à l'ouverture (voir index.html) : pas d'anneau
   autour d'elle, il ne désignerait aucun bouton. */
.poster:focus-visible {
  outline: none;
}

@keyframes poster-in {
  from {
    opacity: 0;
    transform: translateY(48px) scale(0.86) rotate(3deg);
  }
}

/* Le homard dépasse du haut de la fenêtre, comme s'il s'y accrochait. */
.poster__mascot {
  width: var(--mascot);
  margin-top: calc(var(--mascot) * -0.66);
  overflow: visible;
  rotate: -7deg;
  filter: drop-shadow(0 8px 8px rgb(5 2 16 / 0.45));
}

/* Il salue en arrivant : deux coups de pince, une fois la fenêtre posée.
   (transform-box : la pince tourne autour de son attache, donnée dans les
   coordonnées du dessin.) */
.poster__claw {
  transform-box: view-box;
  animation: poster-wave 900ms 460ms var(--ease-out) both;
}

.poster__claw--left {
  transform-origin: 11px 18px;
  --wave: -22deg;
}

.poster__claw--right {
  transform-origin: 37px 17px;
  --wave: 22deg;
}

@keyframes poster-wave {
  25%,
  75% {
    transform: rotate(var(--wave));
  }
  50% {
    transform: rotate(0deg);
  }
}

.poster__title {
  font-weight: 900;
  font-stretch: 110%;
  font-size: clamp(1.35rem, 6vw, 1.6rem);
  line-height: 1.1;
  text-wrap: balance;
}

.poster__text {
  max-width: 32ch;
  color: #c4e0da; /* l'écume, un ton plus sourd */
  line-height: 1.4;
  text-wrap: pretty;
}

/* Les deux réponses, l'une sous l'autre : y aller, ou remettre à plus tard. */
.poster__actions {
  display: grid;
  gap: 8px;
  width: min(100%, 280px);
  margin-top: 10px;
}

.poster__actions .btn {
  text-decoration: none;
  white-space: nowrap;
}

.poster__actions .btn--primary {
  --btn-bg: var(--sun);
  --btn-fg: var(--pitch);
  min-height: 56px;
  font-weight: 900;
  font-size: 1.05rem;
}

.poster__later {
  --btn-fg: var(--foam);
  min-height: 46px;
  box-shadow: inset 0 0 0 2px var(--sea-light);
  font-size: 0.9rem;
}

.poster__later:active:not(:disabled) {
  box-shadow: inset 0 0 0 2px var(--foam);
}

.poster__close {
  position: absolute;
  top: 6px;
  right: 6px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--foam);
  transition: background-color 160ms;
}

.poster__close:hover {
  background: var(--sea-light);
}

.poster__close .icon {
  width: 22px;
  height: 22px;
}

/* Un écran bas (un téléphone couché) : un homard plus petit, une fenêtre plus
   large, les deux réponses côte à côte. Tout doit tenir sans défiler. */
@media (max-height: 560px) {
  .poster {
    --mascot: 72px;
    width: min(calc(100vw - 32px), 520px);
    padding-bottom: 18px;
  }

  .poster[open] {
    gap: 6px;
  }

  .poster__text {
    max-width: none;
  }

  .poster__actions {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: min(100%, 440px);
    margin-top: 6px;
  }

  .poster__actions .btn {
    min-height: 48px;
    padding-inline: 0.6em;
  }
}

/* ── Fenêtre de confirmation ─────────────────────────────────────────────── */

.confirm {
  width: min(calc(100vw - 32px), 420px);
  padding: 24px;
  border: 0;
  border-radius: var(--radius);
  background: var(--ink-2);
  color: var(--paper);
  box-shadow: var(--shadow);
}

.confirm[open] {
  animation: toast-in 320ms var(--ease-spring) both;
}

.confirm::backdrop {
  background: rgb(13 6 34 / 0.78);
}

.confirm__title {
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.4rem;
  text-transform: uppercase;
}

.confirm__text {
  margin-top: 8px;
  color: var(--paper-dim);
}

.confirm__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

/* La fenêtre du pseudo d'un spectateur : la même, avec un champ. */
.nickname__field {
  margin-top: 16px;
}

.nickname__error {
  margin-top: 12px;
}

/* Pseudo refusé : la fenêtre fait « non » de la tête (comme l'accueil). */
.nickname.is-refused {
  animation: refuse 380ms ease-in-out;
}

/* ── Fenêtre des statistiques ────────────────────────────────────────────── */

.stats {
  width: min(calc(100vw - 24px), 560px);
  max-height: min(calc(100dvh - 32px), 760px);
  padding: 20px;
  border: 0;
  border-radius: var(--radius);
  background: var(--ink-2);
  color: var(--paper);
  box-shadow: var(--shadow);
}

.stats[open] {
  animation: toast-in 320ms var(--ease-spring) both;
}

.stats::backdrop {
  background: rgb(13 6 34 / 0.78);
}

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

.stats__head .icon-btn {
  background: var(--ink-3);
}

.stats__note,
.stats__empty {
  margin-top: 4px;
  color: var(--paper-dim);
  font-weight: 500;
}

.stats__empty {
  margin-top: 16px;
}

/* Un bloc par pseudo, séparés par un filet. */
.stats__profile {
  display: grid;
  gap: 10px;
  justify-items: start;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 2px solid var(--ink-3);
}

.stats__name {
  margin: 0;
  color: var(--p0);
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.25rem;
}

/* Deux colonnes de lignes « libellé … valeur ». */
.stats__lines {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 4px 24px;
  width: 100%;
  margin: 0;
}

.stats__line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 5px 0;
  border-bottom: 1px solid var(--ink-3);
}

.stats__line dt {
  color: var(--paper-dim);
  font-weight: 600;
}

.stats__line dd {
  margin: 0;
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.stats__line small {
  margin-left: 8px;
  color: var(--paper-dim);
  font-weight: 600;
  font-stretch: 100%;
  font-size: 0.8rem;
}

.stats__bots {
  color: var(--paper-dim);
  font-weight: 600;
}

/* ── Fenêtre du classement général ───────────────────────────────────────── */
/* Elle reprend le cadre de la fenêtre des statistiques (.stats). */

.ranking__tabs {
  margin-top: 16px;
}

/* « Cette semaine » doit tenir dans son onglet, même sur un petit téléphone. */
.ranking__tabs .tabs__tab {
  padding: 0 4px;
  font-size: clamp(0.78rem, 3.6vw, 0.9rem);
}

.ranking {
  margin-top: 10px;
}

.ranking__row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--ink-3);
  font-weight: 700;
}

.ranking__rank {
  flex: none;
  width: 1.3em;
  color: var(--paper-dim);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.ranking__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ranking__when {
  flex: none;
  color: var(--paper-dim);
  font-weight: 600;
  font-size: 0.8rem;
  white-space: nowrap;
}

.ranking__score {
  flex: none;
  min-width: 2.6em;
  font-weight: 900;
  font-stretch: 112%;
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* Le premier : son rang et son score prennent la couleur de la liste. */
.ranking__row:first-child :is(.ranking__rank, .ranking__score) {
  color: var(--c);
}

.ranking__last {
  margin-top: 16px;
  color: var(--paper-dim);
  font-weight: 600;
  text-wrap: pretty;
}

/* Le lien vers « Le jeu en chiffres », au pied de la fenêtre : un bouton de
   toute la largeur. (C'est un lien : on lui retire son soulignement.) */
.ranking__figures {
  width: 100%;
  margin-top: 16px;
  text-align: center;
  text-decoration: none;
}

/* ── Fenêtre des règles du jeu ───────────────────────────────────────────── */
/* Elle reprend, elle aussi, le cadre de la fenêtre des statistiques (.stats). */

.rules {
  line-height: 1.5;
}

.rules p {
  color: var(--paper-dim);
}

.rules__heading {
  margin: 18px 0 6px;
  color: var(--p0);
  font-weight: 800;
  font-stretch: 112%;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Les étapes d'un tour sont numérotées ; les bonus, de simples puces. */
.rules__steps {
  display: grid;
  gap: 6px;
  padding-left: 1.4em;
  color: var(--paper-dim);
  list-style: decimal;
}

.rules__steps--plain {
  list-style: disc;
}

.rules__steps strong {
  color: var(--paper);
}

/* Une liste dans une puce (les trois cas du Yahtzee supplémentaire), et son exemple chiffré. */
.rules__steps .rules__steps {
  margin: 6px 0;
}

.rules__example {
  padding: 8px 12px;
  border-radius: 12px;
  background: var(--ink-0);
  color: var(--paper);
  font-size: 0.9rem;
}

/* Les treize lignes : le dessin et le nom à gauche, ce que ça rapporte à droite. */
.rules__lines {
  display: grid;
  margin: 0;
}

.rules__line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 0;
  border-bottom: 1px solid var(--ink-3);
}

.rules__line dt {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  font-weight: 800;
}

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

.rules__line dd {
  margin: 0;
  color: var(--paper-dim);
  font-size: 0.9rem;
  text-align: right;
  text-wrap: balance;
}

/* ── Fenêtre de partage d'un résultat ────────────────────────────────────── */
/* Elle reprend aussi le cadre de la fenêtre des statistiques (.stats). */

/* L'image du classement : sa place est réservée avant qu'elle n'arrive. */
.share__card {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  margin-top: 14px;
  border-radius: var(--radius-s);
  background: var(--ink-1);
}

/* Même ordonnance que sur l'écran de fin : le bouton principal sur toute la
   largeur, puis les autres, plus petits et de même taille, côte à côte. */
.share__actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 16px;
}

.share__actions .btn {
  min-height: 48px;
  padding-inline: 0.6em;
  /* Des lettres un peu moins larges : « Copier le lien » tient sur une ligne, même sur un téléphone. */
  font-stretch: 100%;
  font-size: 0.85rem;
  text-decoration: none; /* le bouton de l'image est un lien */
}

.share__actions .btn--primary {
  grid-column: 1 / -1;
  min-height: 56px;
  font-stretch: 112%;
  font-size: 1rem;
}

/* Un seul bouton sous le principal : il prend toute la largeur lui aussi. */
.share__actions.is-short .btn {
  grid-column: 1 / -1;
}

/* Le compte rendu d'un partage. Sa ligne est toujours là, même vide : la
   fenêtre ne change pas de taille quand un message y apparaît. */
.share__status {
  min-height: 2.9em;
  margin-top: 12px;
  color: var(--paper);
  font-weight: 700;
  font-size: 0.95rem;
  text-align: center;
  text-wrap: balance;
}

.share__status.is-new {
  animation: fade-in 260ms ease-out both;
}

/* ── Moins d'animations, à la demande du système ─────────────────────────── */
/* Les mouvements sont supprimés ; il reste de brefs fondus pour que les
   changements ne soient pas brutaux. (Le JavaScript, lui, n'envoie plus les
   dés en vol, ne fait plus trembler l'écran et limite les confettis.) */

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

  /* Dé en attente : immobile, vu de trois quarts. */
  .die.is-idle .die__cube {
    animation: none !important;
    transform: rotateX(-24deg) rotateY(34deg);
  }

  .die.is-idle .die__mover {
    animation: none !important;
    transform: scale(0.88);
    opacity: 0.75;
  }

  /* Les annonces apparaissent en fondu et restent lisibles, sans rebond. */
  .announce,
  .announce__field,
  .announce__stripe,
  .announce__text,
  .announce__char,
  .announce__sub {
    animation: none !important;
  }

  .announce {
    animation: fade-in 200ms ease-out both !important;
  }

  .banner,
  .banner__label {
    animation: fade-through 1400ms linear both !important;
  }

  .results,
  .results.is-revealed .results__title,
  .results.is-revealed :is(.results__sub, .titles, .results__record, .results__series, .results__rest, .results__actions) {
    animation: fade-in 250ms ease-out both !important;
  }

  .podium__step,
  .pcard,
  .row,
  .btn {
    transition-duration: 1ms !important;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
}

@keyframes fade-through {
  0%,
  100% {
    opacity: 0;
  }
  15%,
  80% {
    opacity: 1;
  }
}

/* En équipes : les joueurs de l'équipe, en petit sous son nom. */
.podium__members {
  max-width: 100%;
  overflow: hidden;
  color: var(--paper-dim);
  font-weight: 600;
  font-size: clamp(0.75rem, 2vw, 0.9rem);
  text-overflow: ellipsis;
  white-space: nowrap;
}
