/* Dance Escape — sage shabby chic, calibré pour lecture à 1-2 m :
   typographies surdimensionnées, contraste poussé, décor adouci pour
   ne pas concurrencer le contenu lisible à distance. */
:root {
  /* Nuancier vert sauge feutré (muted / désaturé / chaleureux).
     Échelle 50-800 cohérente : 50-200 = fonds, 300-500 = accents,
     600-800 = textes et profondeurs. Tons légèrement gris-verts plutôt
     que verts vifs — c'est le "feutré" du shabby chic. */
  --sage-50:  #EEF1E8;
  --sage-100: #DDE4D2;
  --sage-200: #C2D0B1;
  --sage-300: #A7B894;
  --sage-400: #8DA078;  /* accent clair, hover bouton */
  --sage-500: #7B8D69;  /* sauge "vrai" — boutons, bordures */
  --sage-600: #5F6F4F;  /* sauge profond — labels secondaires */
  --sage-700: #475437;  /* sauge très profond — titres, accents marqués */
  --sage-800: #34402A;  /* sauge encre — réserve haut-contraste */
  --cream:    #FBF8F1;
  --cream-2:  #F5EFE3;
  --rose:     #E6C9C0;
  --rose-2:   #A86A5C;  /* terre-cuite feutrée — alertes/échec */
  --gold:     #8A6A1F;  /* doré encre — accents victoire */
  /* Texte : vert sauge feutré profond (pas du noir), contraste > 9:1 sur cream */
  --ink:      #3A4730;
  --shadow:   0 12px 30px rgba(58, 71, 48, .22), 0 2px 6px rgba(58, 71, 48, .14);

  /* Deux polices, direction Art Nouveau moderne :
     --font-display : titres décoratifs, appels à l'action. Marcellus
       = serif elegant inspire Art Nouveau, mais reste lisible a 2m
       (vs Italianno script qui etait illisible de loin).
     --font-body : tout le reste, lecture à distance et UI utilitaire.
       Cormorant Garamond couvre du gros corps lisible aux petits labels. */
  --font-display: "Marcellus", "Cormorant Garamond", serif;
  --font-body:    "Cormorant Garamond", "Times New Roman", serif;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }

body {
  font-family: var(--font-body);
  color: var(--ink);
  font-weight: 500;
  background:
    radial-gradient(900px 500px at 15% -5%, rgba(230, 201, 192, .18), transparent 60%),
    radial-gradient(700px 400px at 115% 105%, rgba(141, 160, 120, .22), transparent 60%),
    linear-gradient(180deg, var(--cream) 0%, var(--cream-2) 100%);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/* Decor Art Nouveau : whiplash + rose stylisee. SVG colore en dur
   (sage + rose), utilise en background-image. Deux groupes :
   - 4 coins : grand format, ancres tournees vers le centre
   - 4 bordures milieu : plus petits, miroirs, formant un cadre floral
     supplementaire entre les coins. */
.corner-ornament {
  position: fixed;
  pointer-events: none;
  background: url('/img/ornament-corner.svg') no-repeat center / contain;
  /* Pas de z-index : auto + ordre DOM (ornements AVANT les .screen
     dans index.html) → les .screen et leur contenu (bouton, dancer)
     peignent par-dessus les ornements, sans avoir à se rajouter un
     z-index. Le body gradient reste en arrière-plan natif. */
}

/* Grands ornements d'angle (x4).
   ============================================================
   Structure : un wrapper .corner-* (positionné, sway) + un
   pseudo-élément ::before qui porte la SVG, la rotation de base
   (orientation tournée vers le centre) et le reveal mask.
   Pourquoi cette séparation : le sway doit pivoter depuis la
   BASE de l'ornement (le coin de page), pas depuis le centre
   du div. Or `transform-origin` s'applique à TOUTES les
   transformations d'un élément, donc on ne peut pas avoir une
   rotation de base center-pivot ET un sway base-pivot sur le
   même élément. Le pseudo gère la base (center origin par
   défaut), le wrapper gère le sway avec transform-origin posé
   sur le coin correspondant.
   ============================================================ */
.corner-tl, .corner-tr, .corner-bl, .corner-br {
  width: clamp(320px, 48vmin, 560px);
  height: clamp(320px, 48vmin, 560px);
  /* Le wrapper devient transparent : la SVG est sur ::before. */
  background: none;
  animation: corner-sway 8s ease-in-out infinite alternate;
}
.corner-tl::before, .corner-tr::before, .corner-bl::before, .corner-br::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url('/img/ornament-corner.svg') no-repeat center / contain;
  opacity: .75;
  /* Gradient 135deg : transparent en haut-gauche du mask, opaque en bas-droite.
     Mask size 220% (plus grand que le pseudo) → on glisse le mask de 0%/0%
     (visible-area = haut-gauche du mask = TRANSPARENT → caché) jusqu'à
     100%/100% (visible-area = bas-droite du mask = OPAQUE → montré).
     Initial : caché. Animation : reveal vers visible. */
  -webkit-mask-image: linear-gradient(135deg, transparent 0%, transparent 25%, #000 75%, #000 100%);
          mask-image: linear-gradient(135deg, transparent 0%, transparent 25%, #000 75%, #000 100%);
  -webkit-mask-size: 220% 220%;
          mask-size: 220% 220%;
  -webkit-mask-position: 0% 0%;
          mask-position: 0% 0%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  animation: corner-reveal 1.6s cubic-bezier(.4, 0, .2, 1) forwards;
}
.corner-tl::before { rotate:   0deg; animation-delay: 300ms; }
.corner-tr::before { rotate:  90deg; animation-delay: 500ms; }
.corner-br::before { rotate: 180deg; animation-delay: 700ms; }
.corner-bl::before { rotate: 270deg; animation-delay: 900ms; }

/* Offset négatif : la base de chaque ornement (SVG coord 0,0, où sortent
   les whiplash) part hors-page → le motif "entre" dans l'écran plutôt
   que de finir en pointe sèche. body a overflow:hidden → débordement
   clippé. transform-origin pose le pivot du sway sur le coin de page
   correspondant (= où la SVG (0,0) apparaît après la rotation du
   pseudo) → l'ornement balance comme une plante accrochée au bord. */
.corner-tl { top: -2vmin;    left: -2vmin;    transform-origin:   0%   0%;  animation-delay: 1900ms; }
.corner-tr { top: -2vmin;    right: -2vmin;   transform-origin: 100%   0%;  animation-delay: 2400ms; }
.corner-br { bottom: -2vmin; right: -2vmin;   transform-origin: 100% 100%;  animation-delay: 2900ms; }
.corner-bl { bottom: -2vmin; left: -2vmin;    transform-origin:   0% 100%;  animation-delay: 3400ms; }

@keyframes corner-reveal {
  from { -webkit-mask-position: 0% 0%;     mask-position: 0% 0%; }
  to   { -webkit-mask-position: 100% 100%; mask-position: 100% 100%; }
}
@keyframes corner-sway {
  from { transform: rotate(-0.8deg); }
  to   { transform: rotate( 0.8deg); }
}

/* Ornements de milieu de bord : plus petits, plus discrets,
   inverses horizontalement pour creer des paires miroirs face-a-face
   sur chaque bord (haut & bas). Sway désynchronisé des coins :
   période 7.3s (vs 8s des coins) → drift constant, ils ne se
   ré-alignent jamais pendant une session.
   Même refactor que les coins : la rotation et le scale de base
   vivent sur ::before (origine center), le wrapper gère le sway
   avec transform-origin sur le côté où l'ornement "s'accroche"
   au bord de la page (pendule). */
.edge-top-left, .edge-top-right, .edge-bot-left, .edge-bot-right {
  width: clamp(220px, 32vmin, 360px);
  height: clamp(220px, 32vmin, 360px);
  background: none; /* SVG est sur ::before maintenant */
  animation: corner-sway 7.3s ease-in-out infinite alternate;
}
.edge-top-left::before, .edge-top-right::before,
.edge-bot-left::before, .edge-bot-right::before {
  content: "";
  position: absolute;
  inset: 0;
  background: url('/img/ornament-corner.svg') no-repeat center / contain;
  opacity: .65;
}
/* Bord haut : deux ornements symetriques sortant vers le centre */
.edge-top-left::before  { rotate:  45deg; scale:  0.85; }
.edge-top-right::before { rotate:  45deg; scale: -0.85; }
/* Bord bas */
.edge-bot-left::before  { rotate: 225deg; scale: -0.85; }
.edge-bot-right::before { rotate: 225deg; scale:  0.85; }

/* Pivot pendule : top edges pendent du bord bas du div (côté intérieur
   de la page), bottom edges pendent du bord haut. Désynchro par delay.
   z-index : 3 edges sur 4 passent devant le bouton (z 2) pour l'effet
   décoratif des whiplash qui se déploient au-dessus du contenu. Seule
   edge-bot-left reste à z 1 pour ne pas mordre sur le bouton — mais
   reste au-dessus du .hint (auto) sous le bouton pour cohérence. */
.edge-top-left  { top: -2vmin;    left:  35%;  transform-origin: 50% 100%; animation-delay:  600ms; z-index: 3; }
.edge-top-right { top: -2vmin;    right: 35%;  transform-origin: 50% 100%; animation-delay: 1300ms; z-index: 3; }
.edge-bot-left  { bottom: -2vmin; left:  35%;  transform-origin: 50%   0%; animation-delay: 2000ms; z-index: 1; }
.edge-bot-right { bottom: -2vmin; right: 35%;  transform-origin: 50%   0%; animation-delay: 2700ms; z-index: 3; }

.screen {
  position: fixed; inset: 0;
  display: none;
  align-items: center; justify-content: center;
  padding: 4vmin;
  /* z-index 10 : position: fixed crée un stacking context isolé.
     Sans z-index explicite, le contexte de .screen est à z auto au
     niveau body, donc même un z-index énorme sur le bouton à
     l'intérieur reste piégé sous les ornements qui ont un z 1+ au
     niveau body. On lève la .screen entière au-dessus des 8
     ornements (max z 3), tout en restant sous les modales (z 50+). */
  z-index: 10;
}
.screen.visible { display: flex; }

.frame {
  text-align: center;
  /* Glassmorphism : fond translucide cream + backdrop-filter qui floute
     ce qui passe derrière (notamment les ornaments edges qui mordent sur
     la frame). saturate(135%) revigore les couleurs floutées pour éviter
     le rendu lavé. Bordure blanchâtre fine + inset highlight = effet
     "plaque de verre" qui colle au feel Art Nouveau délicat. */
  background: rgba(251, 248, 241, .15);
  -webkit-backdrop-filter: blur(8px) saturate(145%);
          backdrop-filter: blur(8px) saturate(145%);
  border: 1px solid rgba(255, 255, 255, .45);
  border-radius: 32px;
  padding: 7vmin 9vmin;
  box-shadow:
    var(--shadow),
    inset 0 1px 0 rgba(255, 255, 255, .65),
    inset 0 -1px 0 rgba(71, 84, 55, .08);
  max-width: 1100px;
}

.overline {
  font-family: var(--font-body);
  letter-spacing: .42em;
  text-transform: uppercase;
  font-size: clamp(1rem, 1.8vmin, 1.4rem);
  font-weight: 600;
  color: var(--sage-600);
  margin: 0 0 1.4rem;
}

.title-script {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(5.5rem, 14vmin, 13rem);
  line-height: 1.05;
  letter-spacing: .015em;
  margin: 0 0 .4rem;
  color: var(--sage-700);
  text-shadow: 0 1px 0 #fff;
}

.subtitle {
  font-family: var(--font-body);
  font-size: clamp(1.8rem, 3.2vmin, 2.6rem);
  font-weight: 500;
  color: var(--sage-600);
  margin: 0 0 3rem;
}

.start-btn {
  appearance: none;
  border: 0;
  cursor: pointer;
  /* Position relative + z-index 49 : le bouton est au top de la pile
     UI (au-dessus des 8 ornements quels qu'ils soient) tout en restant
     en-dessous des modales (z 50+) qui doivent pouvoir le recouvrir
     pendant une session. */
  position: relative;
  z-index: 49;
  /* Gradient sauge seul ; le grain canson est posé en ::after avec
     mix-blend-mode pour blender SUR le texte aussi, pas juste sous. */
  background: linear-gradient(180deg, var(--sage-500), var(--sage-600));
  color: var(--cream);
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-size: clamp(1.8rem, 3.2vmin, 2.6rem);
  padding: 1em 2em;
  border-radius: 999px;
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255,255,255,.35);
  transition: transform .5s ease, box-shadow .2s ease, filter .2s ease;
}
/* Grain canson superposé : pseudo-élément absolu qui couvre tout le
   bouton (gradient + texte). mix-blend-mode: overlay fait que les zones
   claires du bruit éclaircissent ce qu'il y a dessous et les zones
   foncées l'assombrissent → texture papier "imprimée" qui touche aussi
   le texte cream (subtilement, vu qu'il est déjà clair). pointer-events
   none pour ne pas voler le clic au bouton. */
.start-btn::after {
  content: "";
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.45' numOctaves='3' seed='7' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='1'/%3E%3C/svg%3E") repeat;
  pointer-events: none;
  mix-blend-mode: overlay;
  border-radius: inherit;
  opacity: 0.28;
}

.start-btn:hover { transform: scale(1.01); filter: brightness(1.06); }
.start-btn:active { transform: scale(0.985); transition-duration: .08s; }
.start-btn:disabled,
.start-btn.is-disabled {
  cursor: wait;
  filter: grayscale(.6) brightness(.85);
  opacity: .55;
  pointer-events: none;
  transform: none;
  box-shadow: var(--shadow);
}
.start-btn-inner { position: relative; }
.start-btn-inner::before, .start-btn-inner::after {
  content: "✿"; color: var(--cream); opacity: .85;
  margin: 0 .55em; font-size: .85em;
}

.hint {
  margin-top: 2rem;
  font-family: var(--font-body);
  font-size: clamp(1.1rem, 1.6vmin, 1.35rem);
  font-weight: 500;
  color: var(--sage-600);
  transition: opacity .25s ease;
}
.hint.hidden { display: none; }

/* Dance screen */
.dance-stage {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  gap: 1.4rem;
}

.pulse-ring {
  position: absolute;
  width: 42vmin; height: 42vmin;
  border-radius: 50%;
  border: 3px solid transparent;
  animation: pulse 1.6s ease-out infinite;
}
.pulse-ring.pulse-sage { border-color: rgba(71, 84, 55, .55); }
.pulse-ring.pulse-rose { border-color: rgba(168, 106, 92, .55); }
.pulse-ring.pulse-d1   { animation-delay: .4s; }
.pulse-ring.pulse-d2   { animation-delay: .8s; }
.pulse-ring.pulse-d3   { animation-delay: 1.2s; }
@keyframes pulse {
  0%   { transform: scale(.4);  opacity: .95; }
  100% { transform: scale(1.85); opacity: 0; }
}

.dancer {
  font-size: clamp(11rem, 26vmin, 22rem);
  /* --shimmy-duration est posé par kiosk.js à partir du BPM du morceau
     en cours (30/BPM secondes par croche, 2 oscillations par battement).
     Fallback à 0.275 s ≈ 109 BPM doublé si le morceau n'a pas de BPM. */
  animation: shimmy var(--shimmy-duration, 0.275s) ease-in-out infinite alternate;
  filter: drop-shadow(0 8px 20px rgba(58, 71, 48, .32));
}
.dancer .emoji {
  display: inline-block;
  /* --dancer-flip est posé par kiosk.js : valeur initiale aléatoire à
     chaque session, puis re-toggle 2-4 fois pendant la phase de danse
     (cadence en fonction du BPM). La transition lisse le changement
     d'orientation en 220 ms pour éviter le snap brut. */
  transform: scaleX(var(--dancer-flip, 1));
  transition: transform 220ms ease-in-out;
}
@keyframes shimmy {
  from { transform: translateY(0) rotate(-6deg) scale(1); }
  to   { transform: translateY(-14px) rotate(8deg) scale(1.06); }
}

.dance-call {
  font-family: var(--font-display);
  font-size: clamp(5rem, 12vmin, 10rem);
  color: var(--sage-700);
  margin: 0;
  line-height: 1.05;
  letter-spacing: .02em;
  text-shadow: 0 1px 0 #fff;
}
.dance-sub {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: clamp(1.6rem, 2.8vmin, 2.4rem);
  color: var(--sage-600);
  margin: 0;
}
/* À partir du moment où le code secret apparaît, "Dansez !" + sous-texte
   sont retirés (display:none) — c'est l'invité doit noter le code, pas
   danser. On garde la danseuse + les anneaux pour l'ambiance. La classe
   .victory-shown est posée par kiosk.js à T2 et retirée au prochain
   démarrage de session. */
.dance-stage.victory-shown .dance-call,
.dance-stage.victory-shown .dance-sub {
  display: none;
}

.track-tag {
  margin-top: 1.2rem;
  font-family: var(--font-body);
  font-size: clamp(1.2rem, 1.8vmin, 1.6rem);
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--sage-600);
  min-height: 1.4em;
}

.timer-track {
  position: absolute;
  left: 6vmin; right: 6vmin; bottom: 5vmin;
  height: 18px;
  border-radius: 999px;
  background: rgba(71, 84, 55, .16);
  border: 1px solid rgba(71, 84, 55, .2);
  overflow: hidden;
}
.timer-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--sage-500), var(--gold));
  transition: width .2s linear;
}

/* Modals — pleins, contrastés, gros caractères pour lecture à distance */
.modal {
  position: fixed; inset: 0;
  display: none;
  align-items: center; justify-content: center;
  padding: 4vmin;
  background: rgba(58, 71, 48, .58);
  z-index: 50;
}
.modal.visible { display: flex; animation: fade .25s ease; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.modal-card {
  background: var(--cream);
  border: 3px solid var(--sage-700);
  border-radius: 28px;
  padding: 4vmin 6vmin;
  text-align: center;
  box-shadow: var(--shadow);
  width: 80vw;
  height: 80vh;
  max-width: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1vmin;
}
.modal-card h2 {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(6rem, 13.5vmin, 11.25rem);
  line-height: 1;
  color: var(--sage-700);
  margin: 0;
}
.modal-card p {
  font-size: clamp(5.4rem, 10.2vmin, 9rem);
  margin: 0;
  line-height: 1.3;
  color: var(--ink);
  max-width: 80%;
}
.modal-card .sub {
  color: var(--sage-600);
  font-weight: 500;
}
.modal-card em {
  font-style: normal;
  font-weight: 700;
  color: var(--rose-2);
  border-bottom: 3px solid currentColor;
}
.countdown {
  font-family: var(--font-display);
  font-size: clamp(10rem, 26vmin, 22rem);
  color: var(--rose-2);
  line-height: 1;
  margin: 0;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 2px 0 #fff;
}
.modal-card.warn {
  border-color: var(--rose-2);
  background: linear-gradient(180deg, #FFF4F0, var(--cream));
}
.modal-card.victory {
  border-color: var(--gold);
  background: linear-gradient(180deg, #FFF7E2, var(--cream));
}
/* Modales annexes : fond sage profond, texte cream pour contraste. */
.modal-card.info {
  background: linear-gradient(180deg, var(--sage-700), var(--sage-800));
  border-color: var(--sage-500);
  color: var(--cream);
}
.modal-card.info h2 {
  color: var(--cream);
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(4.5rem, 10.5vmin, 9rem);
}
.modal-card.info p {
  color: var(--cream);
  max-width: 80%;
}
.modal-card.info .countdown {
  color: var(--cream);
  text-shadow: 0 2px 0 rgba(0,0,0,.18);
}
.secret-code {
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: .14em;
  font-size: clamp(3.5rem, 9vmin, 9rem);
  line-height: 1.05;
  color: var(--cream);
  background: var(--sage-700);
  border: 3px solid var(--gold);
  border-radius: 22px;
  padding: .3em .7em;
  margin: 0;
  display: inline-block;
  white-space: nowrap;
  max-width: 92%;
}

.confetti {
  position: fixed; inset: 0;
  pointer-events: none;
  /* Au-dessus du modal (50) et du toast (100) pour que les confettis
     soient visibles par dessus la modale victoire et son fond. Sous
     le debug chrono (200) qui doit rester toujours lisible. */
  z-index: 150;
  display: none;
}
.confetti.active { display: block; }

.cam-hidden { position: fixed; width: 1px; height: 1px; opacity: 0; left: -10px; top: -10px; }
.yt-host { position: fixed; width: 1px; height: 1px; opacity: 0; left: -10px; top: -10px; overflow: hidden; }

/* Debug chrono : visible en bas à droite, discret mais lisible */
.debug-chrono {
  position: fixed;
  right: 14px;
  bottom: 14px;
  z-index: 200;
  font-family: var(--font-body);
  font-size: 1.1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
  color: var(--cream);
  background: rgba(58, 71, 48, .7);
  padding: .25em .7em;
  border-radius: 8px;
  border: 1px solid rgba(251, 248, 241, .18);
  pointer-events: none;
  opacity: .85;
}
.debug-chrono.running { opacity: 1; }

/* Error toast — lisible à distance aussi */
.toast {
  position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%);
  background: var(--sage-700); color: var(--cream);
  padding: 1em 1.8em; border-radius: 999px;
  font-family: var(--font-body);
  font-size: clamp(1.1rem, 1.6vmin, 1.4rem);
  font-weight: 500;
  box-shadow: var(--shadow);
  z-index: 100;
}
