/* ==========================================================
   Lettre aux invités — mise en forme
   Mobile d'abord, aucune ressource externe.
   ========================================================== */

/* ---------- Polices libres (licence OFL, dans polices/) ---------- */
@font-face {
  font-family: "Cinzel";
  src: url("polices/cinzel-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Cinzel";
  src: url("polices/cinzel-latin-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Great Vibes";
  src: url("polices/great-vibes-latin-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---------- Couleurs et mesures ---------- */
:root {
  --vert-foret: #22392E;
  --vert-nuit: #0f1d17;
  --or: #B0894C;
  --or-clair: #d9b779;
  --creme: #f6ebcf;
  --petale: #f4c6d2;
  --titre: "Cinzel", Georgia, "Times New Roman", serif;
  --plume: "Great Vibes", "Segoe Script", "Brush Script MT", cursive;
  --texte: Georgia, "Times New Roman", serif;
  --toucher: 48px;
  --marge: clamp(.75rem, 4vw, 1.5rem);
  --haut-securite: env(safe-area-inset-top, 0px);
  --bas-securite: env(safe-area-inset-bottom, 0px);
  /* Marges de côté : jamais sous l'encoche de l'iPhone couché (la page occupe tout l'écran, viewport-fit=cover) */
  --marge-gauche: max(var(--marge), env(safe-area-inset-left, 0px));
  --marge-droite: max(var(--marge), env(safe-area-inset-right, 0px));
  /* Hauteur de la barre du haut (bouton de 48 px et ses marges) : chaque écran lui réserve cette place */
  --haut-barre: calc(4rem + var(--haut-securite));
  /* Nuit étoilée : petits points lumineux, en trois couches de tailles différentes pour éviter un motif visible
     (fond de la page et de l'invitation à tourner le téléphone) */
  --etoiles:
    radial-gradient(1.5px 1.5px at 23px 41px, rgba(255, 248, 225, .9), transparent),
    radial-gradient(1px 1px at 87px 12px, rgba(255, 248, 225, .7), transparent),
    radial-gradient(1px 1px at 150px 95px, rgba(255, 248, 225, .6), transparent),
    radial-gradient(1.5px 1.5px at 61px 160px, rgba(217, 183, 121, .8), transparent),
    radial-gradient(1px 1px at 190px 140px, rgba(255, 248, 225, .5), transparent),
    radial-gradient(1px 1px at 120px 210px, rgba(255, 248, 225, .7), transparent),
    radial-gradient(2px 2px at 260px 60px, rgba(255, 248, 225, .8), transparent),
    radial-gradient(1px 1px at 300px 250px, rgba(217, 183, 121, .6), transparent);
  --etoiles-tailles: 220px 230px, 220px 230px, 220px 230px, 220px 230px, 330px 310px, 330px 310px, 410px 370px, 410px 370px;
  --fond-nuit: radial-gradient(ellipse at 50% 35%, var(--vert-foret) 0%, #182b22 45%, var(--vert-nuit) 100%);
}

/* ---------- Base ---------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  background: var(--vert-nuit);
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  color: var(--creme);
  font: 1rem/1.6 var(--texte);
  overflow-x: hidden;
  background: var(--fond-nuit) fixed;
}

/* Nuit étoilée (voir --etoiles) */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: var(--etoiles);
  background-size: var(--etoiles-tailles);
}

img { display: block; max-width: 100%; height: auto; }

[hidden] { display: none !important; }

button {
  font: inherit;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
}

:focus-visible {
  outline: 2px solid var(--or-clair);
  outline-offset: 3px;
}

/* ---------- Texte de secours (sans JavaScript ou réglages illisibles) ---------- */
.secours {
  position: relative;
  z-index: 2;
  max-width: 34rem;
  margin: 0 auto;
  padding: calc(2rem + var(--haut-securite)) var(--marge-droite) calc(2rem + var(--bas-securite)) var(--marge-gauche);
  text-align: center;
}
.secours-titre {
  margin: 0 0 1.5rem;
  font: 400 clamp(2.4rem, 11vw, 3.4rem)/1.1 var(--plume);
  color: var(--or-clair);
}
.secours section { margin-bottom: 2rem; }

.bouton-formulaire {
  display: inline-block;
  min-height: var(--toucher);
  padding: .8rem 1.4rem;
  border: 2px solid var(--or);
  border-radius: 999px;
  background: var(--or);
  color: var(--vert-nuit);
  font: 700 .95rem/1.3 var(--titre);
  text-decoration: none;
}

/* Avec JavaScript, le secours disparaît et la carte prend sa place */
.js .secours { display: none; }
html:not(.js) .barre,
html:not(.js) .scene,
html:not(.js) .petales { display: none; }

/* ---------- Barre du haut : son à gauche, langue à droite ---------- */
/* Posée en haut de la page et non fixée à l'écran : elle défile avec la page, pour ne jamais passer
   par-dessus un bouton ou un texte (chaque écran lui réserve sa place en haut, --haut-barre) */
.barre {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: calc(.5rem + var(--haut-securite)) var(--marge-droite) .5rem var(--marge-gauche);
  pointer-events: none;
}
.barre > * { pointer-events: auto; }

.bouton-son {
  width: var(--toucher);
  height: var(--toucher);
  display: grid;
  place-items: center;
  padding: 0;
  border: 2px solid var(--or);
  border-radius: 50%;
  background: rgba(15, 29, 23, .75);
  cursor: pointer;
}
.bouton-son svg {
  width: 26px;
  height: 26px;
  fill: none;
  stroke: var(--creme);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.bouton-son .haut-parleur { fill: var(--creme); }
.bouton-son[aria-pressed="true"] .croix,
.bouton-son[aria-pressed="false"] .ondes { display: none; }

.langues {
  display: flex;
  border: 2px solid var(--or);
  border-radius: 999px;
  overflow: hidden;
  background: rgba(15, 29, 23, .75);
}
.langues button {
  min-width: var(--toucher);
  min-height: calc(var(--toucher) - 4px);
  padding: 0 .9rem;
  border: 0;
  background: none;
  font: 700 .9rem/1 var(--titre);
  letter-spacing: .08em;
  cursor: pointer;
}
.langues button + button { border-left: 1px solid var(--or); }
.langues button[aria-pressed="true"] {
  background: var(--or);
  color: var(--vert-nuit);
}

/* ---------- La scène ---------- */
.scene {
  position: relative;
  z-index: 2;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: calc(var(--haut-barre) + .5rem) var(--marge-droite) calc(1.5rem + var(--bas-securite)) var(--marge-gauche);
  transition: opacity .6s ease;
  /* Rien ne dépasse de la scène : les morceaux du cachet et le rabat, déplacés par les animations,
     élargissaient la page (408 px au lieu de 360) et faisaient sortir le bouton DE de l'écran sur Android */
  overflow: hidden;
  overflow: clip;
}
/* Rien ne s'affiche tant que les réglages et les textes ne sont pas chargés */
[data-etat="chargement"] .scene { opacity: 0; }

/* L'enveloppe : la photo est carrée, son fond flou se fond dans la nuit grâce au masque */
.enveloppe {
  display: block;
  width: min(88vw, 26rem, 62vh);
  width: min(88vw, 26rem, 62svh);
  padding: 0;
  border: 0;
  border-radius: 1rem;
  background: none;
  cursor: pointer;
}
.enveloppe-carte {
  position: relative;
  display: block;
}

/* Bord adouci : un fondu horizontal croisé avec un fondu vertical (plus large en haut et en bas,
   où la photo montre le fond flou). Posé sur chaque couche d'image, jamais sur un parent :
   un masque sur un parent aplatirait les rotations et effacerait la lettre qui sort.
   Préfixe -webkit- pour Safari iOS 15. */
.face-recto img,
.face-verso > img,
.copie-verso {
  -webkit-mask-image:
    linear-gradient(to right, transparent 2%, #000 10%, #000 90%, transparent 98%),
    linear-gradient(to bottom, transparent 8%, #000 19%, #000 81%, transparent 93%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 2%, #000 10%, #000 90%, transparent 98%),
    linear-gradient(to bottom, transparent 8%, #000 19%, #000 81%, transparent 93%);
  mask-composite: intersect;
}
.face-recto img,
.face-verso > img { width: 100%; }

/* Le verso et ses couches, toutes à la taille de l'image ; les découpes (clip-path) sont en %,
   posées par le script, pour rester alignées quand l'écran tourne ou change de taille */
.face-verso {
  position: absolute;
  inset: 0;
  visibility: hidden;
}
.enveloppe-carte.cote-verso .face-recto { visibility: hidden; }
.enveloppe-carte.cote-verso .face-verso { visibility: visible; }

.couche {
  position: absolute;
  inset: 0;
  display: block;
}
.copie-verso {
  background-image: var(--image-verso);
  background-size: 100% 100%;
}
.interieur {
  z-index: 1;
  background: linear-gradient(to bottom, rgba(60, 40, 20, .45), rgba(60, 40, 20, .15)), var(--papier);
}
.rabat {
  z-index: 2;
  transform-origin: 50% var(--rabat-haut);
}
.rabat-envers {
  visibility: hidden;
  background: linear-gradient(to top, rgba(60, 40, 20, .25), rgba(255, 255, 255, .15)), var(--papier);
}
.lettre-glissante {
  z-index: 3;
  inset: auto;
  left: 19%;
  width: 62%;
  top: 40%;
  height: 40%;   /* s'arrête au-dessus du bord bas adouci, pour ne jamais dépasser sous l'enveloppe */
  overflow: hidden;
  visibility: hidden;
  box-shadow: 0 -4px 14px rgba(0, 0, 0, .25);
}
.lettre-glissante img { width: 100%; }
.corps { z-index: 4; }
.cachet-moitie {
  z-index: 5;
  transform-origin: var(--cachet-x) var(--cachet-y);
}

/* Pastille couleur papier qui cache le cachet d'origine une fois ses morceaux tombés ; bord en dégradé
   pour qu'elle se fonde dans le papier. Sa place et sa taille viennent du script (réglage « cachet »). */
.pastille {
  position: absolute;
  background: radial-gradient(closest-side, var(--papier) 90%, transparent 100%);
}

.consigne {
  margin: 0;
  min-height: 1.3em;
  font: 400 clamp(2rem, 8vw, 2.7rem)/1.2 var(--plume);
  color: var(--creme);
  text-align: center;
  text-shadow: 0 0 12px rgba(217, 183, 121, .55);
  animation: pulsation 2.4s ease-in-out infinite;
  transition: opacity .3s ease;
}
/* Paysage bas : l'enveloppe et « Touchez l'enveloppe » tiennent dans l'écran sans défiler. La taille de l'enveloppe
   (carrée) est plafonnée à la hauteur de l'écran, moins la barre et sa marge (4,5rem), l'écart (.5rem),
   la consigne (2,6rem) et la marge du bas (.75rem), arrondis à 8,5rem */
@media (orientation: landscape) and (max-height: 500px) {
  .scene {
    gap: .5rem;
    padding-bottom: calc(.75rem + var(--bas-securite));
  }
  .enveloppe {
    width: min(88vw, 26rem, calc(100vh - 8.5rem - var(--haut-securite) - var(--bas-securite)));
    width: min(88vw, 26rem, calc(100svh - 8.5rem - var(--haut-securite) - var(--bas-securite)));
  }
  .consigne { font-size: 2rem; min-height: 2.6rem; }
}
[data-etat="retournement"] .consigne,
[data-etat="ouverture"] .consigne { opacity: 0; animation: none; }
[data-etat="lettre"] .scene,
[data-etat="personnages"] .scene,
[data-etat="carte"] .scene { visibility: hidden; }

/* ---------- L'ouverture : animations ---------- */
/* Retournement en deux temps : 0 → 90°, échange des faces (par le script), puis -90° → 0.
   Chaque élément porte sa propre perspective : pas de 3D imbriquée, pas de backface-visibility. */
.enveloppe-carte.retourne-1 { animation: retourne-1 .42s ease-in forwards; }
.enveloppe-carte.retourne-2 { animation: retourne-2 .42s ease-out forwards; }
@keyframes retourne-1 {
  from { transform: perspective(1200px) rotateY(0deg); }
  to   { transform: perspective(1200px) rotateY(90deg) scale(1.04); }
}
@keyframes retourne-2 {
  from { transform: perspective(1200px) rotateY(-90deg) scale(1.04); }
  to   { transform: perspective(1200px) rotateY(0deg); }
}

/* Le cachet se fend, puis ses deux moitiés tombent en tournant */
.enveloppe.cachet-brise .cachet-gauche { animation: cachet-gauche 1.1s ease-in forwards; }
.enveloppe.cachet-brise .cachet-droite { animation: cachet-droite 1.1s ease-in forwards; }
@keyframes cachet-gauche {
  0%   { transform: none; opacity: 1; }
  18%  { transform: translate(-2%, -.5%) rotate(-6deg); opacity: 1; }
  100% { transform: translate(-16%, 95%) rotate(-60deg); opacity: 0; }
}
@keyframes cachet-droite {
  0%   { transform: none; opacity: 1; }
  18%  { transform: translate(2%, -.5%) rotate(6deg); opacity: 1; }
  100% { transform: translate(14%, 100%) rotate(70deg); opacity: 0; }
}

/* Le rabat se lève en deux temps : l'image jusqu'à 90°, puis l'envers (couleur papier) jusqu'à 180° */
.enveloppe.rabat-1 .rabat { animation: rabat-1 .35s ease-in forwards; }
.enveloppe.rabat-2 .rabat { animation: rabat-2 .45s ease-out forwards; }
.enveloppe.rabat-2 .rabat-image { visibility: hidden; }
.enveloppe.rabat-2 .rabat-envers { visibility: visible; }
@keyframes rabat-1 {
  from { transform: perspective(900px) rotateX(0deg); }
  to   { transform: perspective(900px) rotateX(90deg); }
}
@keyframes rabat-2 {
  from { transform: perspective(900px) rotateX(90deg); }
  to   { transform: perspective(900px) rotateX(180deg); }
}

/* La lettre glisse hors de l'enveloppe, puis l'enveloppe s'efface */
.enveloppe.lettre-sort .lettre-glissante {
  visibility: visible;
  animation: lettre-sort 1s cubic-bezier(.25, .7, .35, 1) forwards;
}
@keyframes lettre-sort {
  from { transform: translateY(0); }
  to   { transform: translateY(-150%); }
}
.enveloppe.efface { animation: efface .6s ease forwards; }
@keyframes efface {
  to { opacity: 0; transform: translateY(6%) scale(.92); }
}

/* ---------- La lettre ouverte ---------- */
/* Posée en haut de la page, à sa hauteur naturelle : c'est la page entière qui défile au doigt,
   jamais une boîte à l'intérieur de la page (le défilement imbriqué marche mal sur Chrome Android) */
.lettre-ouverte {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  min-height: 100vh;     /* repli pour les navigateurs qui ne connaissent pas svh */
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .75rem;
  padding: calc(var(--haut-barre) + .5rem) var(--marge-droite) calc(.75rem + var(--bas-securite)) var(--marge-gauche);
}
.lettre-cadre {
  flex: 0 0 auto;
  width: min(92vw, 30rem);
  overflow: hidden;
  border: 2px solid var(--or);
  border-radius: .75rem;
  background: var(--vert-nuit);
  box-shadow: 0 18px 45px rgba(0, 0, 0, .6);
}
.lettre-cadre img { width: 100%; }
.lettre-ouverte.apparait .lettre-cadre { animation: lettre-agrandit .7s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes lettre-agrandit {
  from { opacity: .3; transform: translateY(-6rem) scale(.45); }
  to   { opacity: 1; transform: none; }
}

/* « Continuer » sous la lettre, mais collant : il flotte au bas de l'écran pendant la lecture,
   centré (loin du coin bas droit), et se pose sous les rouleaux en bas de page, sans les recouvrir */
.bouton-continuer {
  position: -webkit-sticky;
  position: sticky;
  bottom: calc(.75rem + var(--bas-securite));
  z-index: 3;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .55);
  flex: 0 0 auto;
  min-height: var(--toucher);
  min-width: 12rem;
  padding: .7rem 1.6rem;
  border: 2px solid var(--or);
  border-radius: 999px;
  background: var(--or);
  color: var(--vert-nuit);
  font: 700 1rem/1.2 var(--titre);
  letter-spacing: .05em;
  cursor: pointer;
  animation: continuer-apparait .45s ease-out both;
}
@keyframes continuer-apparait {
  from { opacity: 0; transform: translateY(.75rem); }
  to   { opacity: 1; transform: none; }
}
/* Paysage bas (téléphone couché) : le bouton qui flotte cacherait trop de texte ; il reste simplement sous la lettre */
@media (orientation: landscape) and (max-height: 500px) {
  .bouton-continuer { position: static; }
}

/* Rouleaux de la lettre : liens transparents centrés sur chaque rouleau dessiné, 48 px au moins ;
   rien au survol, contour doré au clavier, léger halo doré au toucher */
.lettre-image { position: relative; }
.rouleau {
  position: absolute;
  left: calc(var(--x) + var(--largeur) / 2);
  top: calc(var(--y) + var(--hauteur) / 2);
  width: var(--largeur);
  height: var(--hauteur);
  min-width: var(--toucher);
  min-height: var(--toucher);
  transform: translate(-50%, -50%);
  border-radius: .75rem;
  -webkit-tap-highlight-color: rgba(217, 183, 121, .35);
}
.rouleau:focus-visible { outline: 3px solid var(--or-clair); outline-offset: 2px; }
.rouleau:active { box-shadow: inset 0 0 0 999px rgba(217, 183, 121, .3); }

/* La lettre passe en retrait quand les personnages arrivent : simple décor fixe et coupé,
   qui n'allonge pas la page */
.lettre-ouverte.en-retrait {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.lettre-ouverte.en-retrait .lettre-cadre { animation: retrait .6s ease forwards; }
@keyframes retrait {
  from { opacity: 1; transform: none; }
  to   { opacity: .3; transform: scale(.92); }
}

/* ---------- Les personnages et la bulle ---------- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Posée en haut de la page, haute d'au moins un écran ; s'il faut plus de place, la page défile */
.dialogue {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  min-height: 100vh;     /* repli pour les navigateurs qui ne connaissent pas svh */
  min-height: 100svh;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: .5rem;
  padding: calc(var(--haut-barre) + .5rem) var(--marge-droite) calc(.75rem + var(--bas-securite)) var(--marge-gauche);
}

/* Le bouton transparent couvre la scène, sous tout le reste : bulle et personnages laissent passer le toucher,
   les commandes et la barre du haut restent au-dessus */
.zone-suite {
  position: absolute;
  inset: 0;
  z-index: 1;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.zone-suite:focus-visible { outline-offset: -6px; }
.bulle,
.personnages { position: relative; z-index: 2; pointer-events: none; }

.bulle {
  width: min(100%, 34rem);
  padding: .8rem 1.1rem .5rem;
  border: 2px solid var(--or);
  border-radius: 1.25rem;
  background: var(--creme);
  color: #2b2117;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
  visibility: hidden;
}
.bulle.apparait {
  visibility: visible;
  animation: bulle-apparait .35s ease-out both;
}
@keyframes bulle-apparait {
  from { opacity: 0; transform: translateY(.5rem) scale(.94); }
  to   { opacity: 1; transform: none; }
}
/* Pointe de la bulle, tournée vers celui qui parle (au centre pour les deux) */
.bulle::after {
  content: "";
  position: absolute;
  bottom: -11px;
  left: var(--pointe, 22%);
  width: 20px;
  height: 20px;
  border-right: 2px solid var(--or);
  border-bottom: 2px solid var(--or);
  background: var(--creme);
  transform: translateX(-50%) rotate(45deg);
}
.bulle[data-qui="droite"] { --pointe: 78%; }
.bulle[data-qui="deux"] { --pointe: 50%; }

.bulle-texte {
  display: grid;
  margin: 0;
  font: 1.05rem/1.45 var(--texte);
}
.bulle-fantome,
.bulle-ecrit { grid-area: 1 / 1; }
.bulle-fantome { visibility: hidden; }
.bulle-suite {
  margin: .35rem 0 0;
  font: 400 1.25rem/1.2 var(--plume);
  color: #7a5a2c;
  text-align: right;
}

.personnages {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  width: min(100%, 34rem);
}
.personnage {
  width: min(47vw, 15rem, 36vh);
  width: min(47vw, 15rem, 36svh);
  margin: 0;
}
.personnage .cadre-image {
  position: relative;
  transform-origin: 50% 100%;
}
.personnage img { width: 100%; }
.personnage img.parle {
  position: absolute;
  inset: 0;
  visibility: hidden;
}
.personnage.bouche-ouverte img.parle { visibility: visible; }

/* Sortie de la lettre : du centre de la lettre vers leur place, avec un petit rebond */
.dialogue.entree .personnage-gauche { animation: sortie-gauche .9s cubic-bezier(.3, .7, .4, 1) both; }
.dialogue.entree .personnage-droite { animation: sortie-droite .9s cubic-bezier(.3, .7, .4, 1) .25s both; }
@keyframes sortie-gauche {
  0%   { opacity: 0; transform: translate(45%, -70%) scale(.3); }
  65%  { opacity: 1; transform: translate(0, -8%) scale(1.04); }
  82%  { transform: translate(0, 2%) scale(.98); }
  100% { opacity: 1; transform: none; }
}
@keyframes sortie-droite {
  0%   { opacity: 0; transform: translate(-45%, -70%) scale(.3); }
  65%  { opacity: 1; transform: translate(0, -8%) scale(1.04); }
  82%  { transform: translate(0, 2%) scale(.98); }
  100% { opacity: 1; transform: none; }
}

/* Celui qui parle se dandine ; il s'arrête dès que sa réplique est finie */
.personnage.parle .cadre-image { animation: dandine .45s ease-in-out infinite alternate; }
@keyframes dandine {
  from { transform: rotate(-3deg); }
  to   { transform: rotate(3deg); }
}

.commandes {
  position: relative;
  z-index: 3;
  display: flex;
  gap: .75rem;
  justify-content: center;
}
.bouton-secondaire {
  min-height: var(--toucher);
  min-width: 8.5rem;
  padding: .6rem 1.2rem;
  border: 2px solid var(--or);
  border-radius: 999px;
  background: rgba(15, 29, 23, .85);
  color: var(--creme);
  font: 700 .9rem/1.2 var(--titre);
  letter-spacing: .04em;
  cursor: pointer;
}

/* Paysage bas (téléphone couché) : personnages sur les côtés, bulle au centre, commandes en bas */
@media (orientation: landscape) and (max-height: 500px) {
  .dialogue {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas: "g b d" "c c c";
    align-items: end;
    column-gap: .75rem;
  }
  .personnages { display: contents; }
  .personnage { width: min(24vw, 56vh); width: min(24vw, 56svh); }
  .personnage-gauche { grid-area: g; }
  .personnage-droite { grid-area: d; }
  .bulle { grid-area: b; align-self: center; width: auto; }
  .bulle[data-qui="gauche"] { --pointe: 12%; }
  .bulle[data-qui="droite"] { --pointe: 88%; }
  .commandes { grid-area: c; }
}

/* ---------- La carte de rappel ---------- */
/* Posée en haut de la page, sans défilement intérieur : la page défile jusqu'à « Revoir la lettre » */
.carte-rappel {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  min-height: 100vh;     /* repli pour les navigateurs qui ne connaissent pas svh */
  min-height: 100svh;
  z-index: 2;
  display: flex;
  --taille-mini: clamp(4.5rem, 22vw, 6.5rem);
  /* en haut, la place de la barre, une marge, et celle des personnages qui dépassent de la carte */
  padding: calc(var(--haut-barre) + .5rem + var(--taille-mini) * .55) var(--marge-droite) calc(1rem + var(--bas-securite)) var(--marge-gauche);
}
.carte {
  position: relative;
  width: min(100%, 30rem);
  /* marge automatique : centrée s'il y a la place, et le haut reste accessible si elle défile */
  margin: auto;
  padding: calc(var(--taille-mini) * .45 + .5rem) 1.15rem 1.15rem;
  border: 2px solid var(--or);
  border-radius: 1.25rem;
  background: var(--creme);
  color: #2b2117;
  text-align: center;
  box-shadow: 0 18px 45px rgba(0, 0, 0, .55);
}
.carte-rappel.apparait .carte { animation: carte-apparait .6s cubic-bezier(.2, .8, .3, 1) both; }
@keyframes carte-apparait {
  from { opacity: 0; transform: translateY(1.5rem); }
  to   { opacity: 1; transform: none; }
}

/* L'ours et le panda, en petit, dépassent du haut de la carte */
.carte-personnages {
  position: absolute;
  top: calc(var(--taille-mini) * -.55);
  left: -.25rem;
  right: -.25rem;
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}
.carte-personnages img { width: var(--taille-mini); }

.carte-titre {
  margin: 0 0 .5rem;
  font: 700 clamp(1.2rem, 5.5vw, 1.6rem)/1.2 var(--titre);
  color: #5a3e1b;
}
.carte-titre:focus { outline: none; }
.carte-titre:focus-visible { outline: 2px solid var(--or); }

.compte-intro {
  margin: 0;
  font: 400 1.6rem/1.1 var(--plume);
  color: #7a5a2c;
}
.compte-cases {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: .4rem;
  margin: .4rem 0;
}
.case {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: .45rem .15rem;
  border-radius: .6rem;
  background: var(--vert-foret);
  color: var(--creme);
}
.nombre {
  font: 700 clamp(1.35rem, 7vw, 1.9rem)/1.1 var(--titre);
  font-variant-numeric: tabular-nums;
}
.unite { font-size: .75rem; }
.compte-date,
.carte-rappel-texte,
.carte-pourquoi,
.apres-limite { margin: .5rem 0; }
.apres-limite { font-weight: 700; color: #8e1b1b; font-size: 1.1rem; }
.carte-rappel-texte { font-weight: 700; }
.carte-pourquoi { margin-bottom: .3rem; color: #5a4632; }

/* Deux colonnes quand elles ont la place, une seule sinon : « Fahrgemeinschaften » ne tient pas
   dans une demi-carte de téléphone et débordait sur « Unterkunft » */
.raisons {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10.5rem), 1fr));
  gap: .25rem .75rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
  text-align: left;
}
/* Coupure des mots longs selon la langue de la page (<html lang>, réglé par le script) ; en dernier recours,
   un mot trop long passe à la ligne plutôt que de dépasser */
.raisons li {
  display: flex;
  align-items: baseline;
  gap: .45rem;
  min-width: 0;
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: anywhere;
}
.raisons li::before {
  content: "";
  flex: 0 0 auto;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--or);
  transform: translateY(-.1rem);
}

.boutons-formulaire {
  display: flex;
  flex-direction: column;
  gap: .6rem;
}
.bouton-formulaire.grand {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  font-size: 1rem;
}
.adresse-site {
  margin: .6rem 0 0;
  font-size: .88rem;
  color: #5a4632;
}
.adresse-site strong {
  -webkit-user-select: all;
  user-select: all;
}
.bouton-revoir { margin-top: .9rem; }
/* Mention des voix : petite et discrète, mais lisible (contraste de 5,6:1 sur le crème) */
.credit-voix {
  margin: .8rem 0 0;
  font-size: .75rem;
  color: #6b5a45;
}

/* Paysage bas : deux colonnes, compte à rebours et raisons à gauche, boutons à droite */
@media (orientation: landscape) and (max-height: 500px) {
  .carte-rappel { --taille-mini: 4.5rem; }
  .carte {
    width: min(100%, 46rem);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 1.25rem;
    align-items: center;
  }
  .carte-titre { grid-column: 1 / -1; }
}

/* Fondus des animations réduites */
@keyframes disparait { to { opacity: 0; } }
@keyframes apparait { from { opacity: 0; } to { opacity: 1; } }
@keyframes pulsation {
  0%, 100% { opacity: .75; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.06); }
}

/* ---------- Image absente : cadre de remplacement, jamais de vide ---------- */
.cadre-image { display: block; }
.cadre-image.image-absente {
  display: grid;
  place-items: center;
  aspect-ratio: 1 / 1;
  padding: 1.5rem;
  border: 2px dashed var(--or);
  border-radius: 1rem;
  background: rgba(34, 57, 46, .6);
}
.cadre-image.image-absente img { display: none; }
.cadre-image.image-absente::after {
  content: attr(data-message);
  color: var(--creme);
  font: 400 1rem/1.4 var(--titre);
  text-align: center;
}

/* ---------- Pétales de cerisier, derrière la carte ---------- */
.petales {
  position: fixed;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
}
.petale {
  position: absolute;
  top: -6vh;
  left: var(--x);
  width: var(--taille);
  height: calc(var(--taille) * .72);
  border-radius: 150% 0 150% 0;
  background: radial-gradient(ellipse at 30% 30%, #fff1f4 0%, var(--petale) 55%, #e79ab0 100%);
  opacity: .8;
  animation: chute var(--duree) linear var(--delai) infinite;
}
@keyframes chute {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  25%  { transform: translate3d(calc(var(--derive) * .5), 28vh, 0) rotate(130deg); }
  50%  { transform: translate3d(calc(var(--derive) * -.3), 56vh, 0) rotate(260deg); }
  75%  { transform: translate3d(var(--derive), 84vh, 0) rotate(400deg); }
  100% { transform: translate3d(calc(var(--derive) * .2), 112vh, 0) rotate(540deg); }
}

/* ---------- Téléphone couché : invitation à le redresser ---------- */
/* Affichée par le CSS seul, dans la même condition que les règles de paysage bas (ordinateurs et tablettes,
   plus hauts que 500 px, ne la voient jamais). La page reste en place sous elle, invisible : rien ne repart de zéro
   (un display: none relancerait les animations), et rien n'est atteignable au clavier ni par un lecteur d'écran.
   Seulement avec le JavaScript : sans lui, le texte de secours se lit très bien en paysage. */
.tourner { display: none; }
@media (orientation: landscape) and (max-height: 500px) {
  html.js { overflow: hidden; }
  html.js .tourner {
    position: fixed;
    inset: 0;
    z-index: 10;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: var(--haut-securite) var(--marge-droite) var(--bas-securite) var(--marge-gauche);
    background-image: var(--etoiles), var(--fond-nuit);
    background-size: var(--etoiles-tailles), 100% 100%;
    background-color: var(--vert-nuit);
  }
  /* !important : certaines couches de l'enveloppe se déclarent elles-mêmes visibles */
  html.js body > :not(.tourner),
  html.js body > :not(.tourner) * { visibility: hidden !important; }
}
.tourner-icone {
  width: 4.5rem;
  height: 4.5rem;
  fill: none;
  stroke: var(--or-clair);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 8px rgba(217, 183, 121, .45));
  animation: tourner-telephone 2.6s ease-in-out infinite;
}
/* Le téléphone couché se redresse, marque une pause, puis recommence */
@keyframes tourner-telephone {
  0%, 15%   { transform: rotate(-90deg); }
  50%, 85%  { transform: rotate(0deg); }
  100%      { transform: rotate(-90deg); }
}
.tourner-texte {
  max-width: 34rem;
  margin: 0;
  font: 400 2.1rem/1.25 var(--plume);
  color: var(--creme);
  text-align: center;
  text-shadow: 0 0 12px rgba(217, 183, 121, .55);
}

/* ---------- Ordinateur ---------- */
@media (min-width: 768px) {
  .barre {
    padding-left: max(1.5rem, env(safe-area-inset-left, 0px));
    padding-right: max(1.5rem, env(safe-area-inset-right, 0px));
  }
}

/* ---------- Accessibilité : mouvement réduit ---------- */
/* Même parcours, mêmes touchers : chaque mouvement devient un fondu court */
@media (prefers-reduced-motion: reduce) {
  .petales { display: none; }
  .tourner-icone { animation: none; }
  .consigne { animation: none; opacity: 1; }
  .scene { transition-duration: .2s; }
  .enveloppe-carte.retourne-1 { animation: disparait .1s linear forwards; }
  .enveloppe-carte.retourne-2 { animation: apparait .1s linear forwards; }
  .enveloppe.cachet-brise .cachet-moitie { animation: disparait .2s linear forwards; }
  .enveloppe.rabat-1 .rabat { animation: disparait .1s linear forwards; }
  .enveloppe.rabat-2 .rabat { transform: perspective(900px) rotateX(180deg); animation: apparait .1s linear forwards; }
  .enveloppe.lettre-sort .lettre-glissante { transform: translateY(-150%); animation: apparait .2s linear forwards; }
  .enveloppe.efface { animation: disparait .2s linear forwards; }
  .lettre-ouverte.apparait .lettre-cadre { animation: apparait .2s linear both; }
  .bouton-continuer { animation: apparait .2s linear both; }
  .lettre-ouverte.en-retrait .lettre-cadre { animation: none; opacity: .3; }
  .dialogue.entree .personnage-gauche,
  .dialogue.entree .personnage-droite { animation: apparait .2s linear both; }
  .personnage.parle .cadre-image { animation: none; }
  .bulle.apparait { animation: apparait .15s linear both; }
  .carte-rappel.apparait .carte { animation: apparait .2s linear both; }
}
