:root {
  --texte: #15202b;
  --texte-doux: #66717c;
  --trait: #dde2e7;
  --carte: rgb(255 255 255 / 0.93);
  --urgent: #d9480f;
  /* Écrits par jeu.js selon l'altitude : couleurs du ciel et du texte posé dessus. */
  --ciel-haut: #4c93da;
  --ciel-bas: #c4e4f6;
  --sur-ciel: #15202b;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  min-height: 100dvh;
  display: grid;
  place-items: start center;
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--texte);
  background: var(--ciel-bas);
  -webkit-font-smoothing: antialiased;
}

/* Lumière du Soleil, venue de très haut au-dessus de l'écran : discrète au premier cran franchi par la réponse,
   plus forte et plus chaude à chaque cran. Trois couches de rayons (r1 dès le 1er cran, r2 à partir du 3e, r3, plus
   vifs, à partir du 5e) qui pulsent et oscillent chacune à son rythme ; chaleur orangée sur les derniers crans.
   Chaque couche a son opacité selon le cran (variables ci-dessous), l'élément intérieur <i> porte l'animation. */
#soleil { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden;
  --halo: 0; --r1: 0; --r2: 0; --r3: 0; --chaud: 0; }
#soleil[data-niveau="1"] { --halo: 0.12; --r1: 0.3; }
#soleil[data-niveau="2"] { --halo: 0.2; --r1: 0.45; }
#soleil[data-niveau="3"] { --halo: 0.3; --r1: 0.6; --r2: 0.3; }
#soleil[data-niveau="4"] { --halo: 0.4; --r1: 0.75; --r2: 0.55; }
#soleil[data-niveau="5"] { --halo: 0.52; --r1: 0.9; --r2: 0.75; --r3: 0.35; --chaud: 0.15; }
#soleil[data-niveau="6"] { --halo: 0.66; --r1: 1; --r2: 0.9; --r3: 0.7; --chaud: 0.45; }
#soleil[data-niveau="7"] { --halo: 0.85; --r1: 1; --r2: 1; --r3: 1; --chaud: 0.85; }
#soleil > div { position: absolute; inset: 0; mix-blend-mode: screen; transition: opacity 0.9s ease; }
#soleil .lumiere {
  opacity: var(--halo);
  background: radial-gradient(ellipse 110% 75% at 50% -35%, rgb(255 250 228 / 0.9), rgb(255 236 180 / 0.45) 40%,
    rgb(255 220 150 / 0) 85%);
}
#soleil .chaleur {
  opacity: var(--chaud);
  background: radial-gradient(ellipse 120% 85% at 50% -40%, rgb(255 165 60 / 0.55), rgb(255 120 40 / 0.22) 50%,
    rgb(255 100 30 / 0) 90%);
}
/* Rayons : le centre est 80vh au-dessus de l'écran, les rayons arrivent donc larges et presque parallèles ; ils
   s'effacent vers le bas de l'écran. */
#soleil .rayons {
  -webkit-mask-image: linear-gradient(#000, rgb(0 0 0 / 0.55) 35%, transparent 82%);
  mask-image: linear-gradient(#000, rgb(0 0 0 / 0.55) 35%, transparent 82%);
}
#soleil .r1 { opacity: var(--r1); }
#soleil .r2 { opacity: var(--r2); }
#soleil .r3 { opacity: var(--r3); }
/* L'élément déborde largement (en haut et sur les côtés) pour qu'aucun bord n'apparaisse quand il oscille ; le
   centre des rayons est à 50vh au-dessus de son bord haut, soit 80vh au-dessus de l'écran. */
#soleil .rayons i { position: absolute; inset: -30vh -60% 0; transform-origin: 50% -50vh; }
#soleil .r1 i {
  background: repeating-conic-gradient(from 0deg at 50% -50vh, rgb(255 246 220 / 0) 0deg 3deg,
    rgb(255 246 220 / 0.13) 6.5deg, rgb(255 246 220 / 0) 10deg 13deg);
  animation: pulse 5.3s ease-in-out infinite, balance 23s ease-in-out infinite alternate;
}
#soleil .r2 i {
  background: repeating-conic-gradient(from 2deg at 50% -50vh, rgb(255 240 205 / 0) 0deg 2deg,
    rgb(255 240 205 / 0.13) 4.5deg, rgb(255 240 205 / 0) 7deg 9deg);
  animation: pulse 3.7s ease-in-out -1.2s infinite, balance 17s ease-in-out -6s infinite alternate-reverse;
}
#soleil .r3 i {
  background: repeating-conic-gradient(from 5deg at 50% -50vh, rgb(255 250 232 / 0) 0deg 5.5deg,
    rgb(255 250 232 / 0.24) 7.5deg, rgb(255 250 232 / 0) 9.5deg 15deg);
  animation: pulse 2.9s ease-in-out -0.7s infinite, balance 13s ease-in-out -3s infinite alternate;
}
@keyframes pulse { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
@keyframes balance { from { rotate: -1.5deg; } to { rotate: 1.5deg; } }

/* Effet de vieux moniteur, discret, par-dessus tout : lignes de balayage, coins assombris, et une bande claire
   qui descend lentement. */
#crt {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
  overflow: hidden;
  background:
    repeating-linear-gradient(rgb(0 0 0 / 0) 0 2px, rgb(0 0 0 / 0.055) 2px 3px),
    radial-gradient(ellipse 125% 110% at 50% 50%, rgb(0 0 0 / 0) 62%, rgb(0 0 0 / 0.22) 100%);
}
#crt::after {
  content: "";
  position: absolute;
  inset: -30vh 0 auto;
  height: 30vh;
  background: linear-gradient(rgb(255 255 255 / 0), rgb(255 255 255 / 0.035), rgb(255 255 255 / 0));
  animation: balayage 9s linear infinite;
}
@keyframes balayage { to { transform: translateY(160vh); } }
@media (prefers-reduced-motion: reduce) { #crt::after { display: none; } }

/* Décor du départ (0 m), dessiné par jeu.js en pixels : la plaine en bas, des nuages qui traversent le ciel. Il
   descend hors de l'écran quand on monte. */
#decor { position: fixed; inset: 0; z-index: -1; pointer-events: none; overflow: hidden; }
#decor canvas { position: absolute; left: 0; image-rendering: pixelated; }
#plaine { bottom: 0; width: 100%; height: 21vh; image-rendering: auto; } /* tracé lisse, pas en pixels */
/* Nuages en pixels qui traversent lentement le ciel (chacun à sa vitesse), derrière la forêt. */
#nuages { position: absolute; inset: 0; }
#nuages canvas {
  top: var(--y);
  bottom: auto;
  width: auto;
  height: auto;
  opacity: var(--opacite);
  animation: derive var(--duree) linear var(--retard) infinite;
}
@keyframes derive { from { transform: translateX(-100%); } to { transform: translateX(100vw); } }
@media (prefers-reduced-motion: reduce) { #nuages canvas { animation-play-state: paused; } }

#ciel {
  position: fixed;
  inset: 0;
  z-index: -1;
  background: linear-gradient(var(--ciel-haut), var(--ciel-bas));
}

/* Contenu calé en haut (pas centré) : quand la carte s'agrandit, elle s'allonge vers le bas. */
main { width: min(540px, 100% - 32px); margin: clamp(32px, 18vh, 180px) 0 32px; }

.carte {
  background: var(--carte);
  border-radius: 24px;
  padding: 36px 32px;
  box-shadow: 0 20px 50px rgb(0 0 0 / 0.18);
  text-align: center;
}
body.en-jeu { overflow: hidden; } /* la carte qui descend hors de l'écran ne crée pas de barre de défilement */

h1 { font-size: clamp(3rem, 12vw, 4.5rem); font-weight: 800; letter-spacing: -0.04em; margin: 4px 0 16px; }
/* Titre de l'accueil, posé sur le ciel : lettres blanches, doublées d'une copie dorée décalée à gauche et d'une
   copie rouge-orangé décalée à droite, avec une lueur chaude. */
.titre {
  font: 400 clamp(5rem, 22vw, 10.5rem) / 0.85 "Jersey 10", Inter, sans-serif;
  letter-spacing: 0.08em;
  text-align: center;
  margin: 0 0 20px;
  color: #fff;
  /* Copies dorée et rouge-orangé, lueur chaude, et une ombre bleu nuit qui garde le titre lisible devant les nuages. */
  text-shadow: -0.02em 0 0 rgb(255 210 80 / 0.85), 0.02em 0 0 rgb(255 90 50 / 0.85), 0 0.035em 0 rgb(24 52 92 / 0.55),
    0 0 0.12em rgb(255 170 80 / 0.6), 0 0 0.3em rgb(24 52 92 / 0.25);
}
/* « dle » à la suite du titre : petit, blanc uni, ombre bleu nuit (pas l'effet du titre). */
.titre .dle {
  font: 800 0.22em / 1 Inter, sans-serif;
  letter-spacing: 0;
  margin-left: 0.04em;
  text-shadow: 0 2px 0 rgb(24 52 92 / 0.5), 0 0 8px rgb(24 52 92 / 0.3);
}
h2 { font-size: 1.6rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1.25; margin: 12px 0 8px; }
p { margin: 0; }

.sur-titre { font-size: 0.85rem; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--texte-doux); }
.regle { line-height: 1.6; color: var(--texte-doux); margin-bottom: 28px; }

/* Accueil sans carte, à la manière de krillion.io : titre et devise en haut, règle en une ligne et départ plus bas,
   tout posé sur le ciel. */
#accueil { text-align: center; }
#accueil .titre { margin-bottom: 6px; }
.devise, .consigne-jeu, .infos, .envoler { font-family: "Jersey 10", Inter, sans-serif; font-weight: 400; }
.devise { font-size: 1.6rem; letter-spacing: 0.3em; text-transform: uppercase; color: var(--sur-ciel); opacity: 0.8; }
.depart { margin-top: clamp(48px, 36vh, 360px); /* règle juste au-dessus de l'horizon, bouton posé sur la plaine */ display: flex; flex-direction: column; align-items: center; gap: 18px; }
.consigne-jeu { font-size: 1.4rem; line-height: 1.25; letter-spacing: 0.05em; color: var(--sur-ciel); opacity: 0.9; max-width: 30em; }
.envoler {
  font-size: 2.4rem;
  line-height: 1;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #fff;
  background: rgb(18 40 72 / 0.32); /* verre sombre : le blanc reste lisible même sur l'horizon clair */
  border: 1px solid rgb(255 255 255 / 0.5);
  border-radius: 12px;
  padding: 10px 28px 12px;
  text-shadow: -0.03em 0 0 rgb(255 210 80 / 0.8), 0.03em 0 0 rgb(255 90 50 / 0.8), 0 0 0.3em rgb(255 170 80 / 0.5);
  transition: background-color 0.2s, transform 0.2s;
}
.envoler::before, .envoler::after { content: "▲"; font-size: 0.45em; vertical-align: 0.35em; }
.envoler::before { margin-right: 0.8em; }
.envoler::after { margin-left: 0.8em; }
.envoler:hover { background: rgb(18 40 72 / 0.45); transform: translateY(-2px); }
.infos { font-size: 1.15rem; letter-spacing: 0.08em; color: var(--sur-ciel); opacity: 0.65; }
#joueurs:not(:empty)::before { content: " · "; }
.discret { font-size: 0.85rem; color: var(--texte-doux); }

button { font: inherit; cursor: pointer; }
.lien { border: 0; background: none; padding: 0; color: inherit; text-decoration: underline; }
a { color: inherit; }

/* Partie */
.entete { display: flex; align-items: center; gap: 14px; padding-bottom: 24px; }
.chrono { flex: 1; height: 4px; border-radius: 2px; background: var(--trait); overflow: hidden; }
#chrono-barre { height: 100%; background: var(--texte); transform-origin: left; }
#chrono-barre.urgent { background: var(--urgent); }
#secondes { min-width: 2ch; text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
#secondes.urgent { color: var(--urgent); }

/* Partie : le champ (puis la réponse) flotte sur le ciel au milieu de l'écran ; la carte de la question est plus
   bas. Quand la réponse monte, la carte descend et sort de l'écran ; elle remonte avec la question suivante. */
#zone-reponse { min-height: 170px; display: flex; flex-direction: column; justify-content: flex-end; text-align: center; }
#jeu.lecture #zone-reponse { opacity: 0; pointer-events: none; }
#jeu:not(.lecture) #zone-reponse { transition: opacity 0.35s; }
#carte-question { margin-top: clamp(24px, 14vh, 160px); transition: transform 0.6s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.5s; }
#carte-question.partie { transform: translateY(75vh); opacity: 0; transition: transform 0.8s ease-in, opacity 0.8s ease-in; }

#question { margin: 0; }

/* Temps de lecture : la carte ne montre que la question ; ensuite l'entête (compteur, chrono) se déplie au-dessus,
   ce qui fait glisser la question vers le bas, et le champ apparaît. Le repli est immédiat, le dépli animé. */
.repli { display: grid; grid-template-rows: 1fr; }
.repli > div { min-height: 0; overflow: hidden; }
#jeu:not(.lecture) .repli { transition: grid-template-rows 0.45s ease, opacity 0.45s ease; }
#jeu.lecture .repli { grid-template-rows: 0fr; opacity: 0; }
/* Ligne du temps de lecture sous la question : l'inverse des replis (visible seulement pendant la lecture). */
.annonce { display: grid; grid-template-rows: 0fr; opacity: 0; }
.annonce > div { min-height: 0; overflow: hidden; }
#jeu.lecture .annonce { grid-template-rows: 1fr; opacity: 1; }
#jeu:not(.lecture) .annonce { transition: grid-template-rows 0.45s ease, opacity 0.3s ease; }
#prelude { padding-top: 10px; font-size: 0.78rem; letter-spacing: 0.02em; color: var(--texte-doux); font-variant-numeric: tabular-nums; }
#question { transition: opacity 0.35s; }
#question.entree { animation: entree 0.6s ease-out backwards; }
@keyframes entree { from { opacity: 0; transform: translateY(12px); } }
#saisie { transition: opacity 0.35s, transform 0.35s; }

/* La réponse est posée sur le ciel : couleur du texte sur ciel, halo clair pour la lisibilité. */
#reponse { filter: drop-shadow(0 0 10px rgb(255 255 255 / 0.55)); }
/* Réponse en capitales, dans la police du titre : la saisie du joueur (minuscules, majuscules mêlées) reste nette. */
#reponse {
  font: 400 2.8rem / 1 "Jersey 10", Inter, sans-serif;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  min-height: 0;
  overflow-wrap: anywhere;
  color: var(--sur-ciel);
}
#reponse:not(:empty) { margin: 4px 0 6px; }
#reponse span { display: inline-block; white-space: pre; transition: color 0.25s, text-shadow 0.25s; }
#reponse.saut { animation: saut 0.3s ease-out; }
@keyframes saut { 40% { transform: scale(1.08); } }

/* Crans de rareté d'une réponse (charte § 3) : 30 m, 100 m, 200 m, 330 m, 500 m, 800 m, 1 km. La réponse se
   réchauffe à chaque cran, comme en approchant du Soleil, et prend feu au dernier. */
:root { --c1: #7d6b5d; --c2: #9a6a3a; --c3: #c27a1a; --c4: #d97a00; --c5: #e8590c; --c6: #d9381e; }
#reponse[data-niveau="1"] { color: var(--c1); }
#reponse[data-niveau="2"] { color: var(--c2); }
#reponse[data-niveau="3"] { color: var(--c3); }
#reponse[data-niveau="4"] { color: var(--c4); }
#reponse[data-niveau="5"] { color: var(--c5); }
#reponse[data-niveau="6"] { color: var(--c6); }
#reponse[data-niveau="7"] { color: #ffb81c; filter: none; } /* les flammes suffisent à détacher le texte */
#reponse[data-niveau="4"] span { text-shadow: 0 0 10px rgb(217 122 0 / 0.25); }
#reponse[data-niveau="5"] span { text-shadow: 0 0 14px rgb(232 89 12 / 0.4); }
#reponse[data-niveau="6"] span { text-shadow: 0 0 16px rgb(217 56 30 / 0.5), 0 -3px 10px rgb(255 140 0 / 0.35); }
#reponse[data-niveau="7"] span {
  animation: flamme 0.5s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * -0.13s);
}
/* Flammes : ombres jaunes, orange puis rouges qui montent au-dessus des lettres et vacillent. */
@keyframes flamme {
  from { text-shadow: 0 0 1px #b02a00, 0 0 2px #d84300, 0 -3px 4px #ffd23f, 1px -7px 6px #ff9a00,
    -1px -12px 9px #ff5a00, 0 -18px 14px rgb(220 40 0 / 0.55); }
  to { text-shadow: 0 0 1px #b02a00, 0 0 2px #d84300, 1px -4px 5px #ffe066, -1px -9px 7px #ffa200,
    2px -15px 11px #ff6a00, -1px -22px 16px rgb(220 40 0 / 0.45); }
}

/* Gain de la réponse : visible dès le départ de la montée, compte les mètres ; couleur unie (texte sur ciel). */
#gain { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--sur-ciel); min-height: 1.4em; margin-bottom: 20px; opacity: 0; transition: opacity 0.3s; }
#gain.visible { opacity: 1; }

.champ {
  display: block;
  width: 100%;
  font: inherit;
  font-size: 1.3rem;
  text-align: center;
  padding: 14px 16px;
  border: 2px solid var(--trait);
  border-radius: 14px;
  background: #fff;
  color: var(--texte);
  outline: none;
}
.champ:focus { border-color: var(--texte); }
.champ::placeholder { color: #9aa3ab; font-size: 1rem; text-overflow: ellipsis; }
/* Saisie alignée à gauche : le curseur se place devant l'exemple au lieu de le couper au milieu. */
#saisie { text-align: left; padding-left: 20px; }
.champ.suite { font-weight: 600; background: var(--texte); border-color: var(--texte); color: #fff; }
.secoue { animation: secoue 0.35s; }
@keyframes secoue { 20%, 60% { transform: translateX(-7px); } 40%, 80% { transform: translateX(7px); } }
.chute { animation: chute 0.7s ease-in forwards; }
@keyframes chute {
  25% { transform: translateY(-5px) rotate(1deg); }
  100% { transform: translateY(26px) rotate(-4deg); opacity: 0.25; }
}

/* Fin */
.altitude { font-size: clamp(3rem, 13vw, 4.2rem); font-weight: 800; letter-spacing: -0.04em; margin-top: 8px; }
#f-rang { font-weight: 500; min-height: 1.5em; margin: 6px 0 28px; opacity: 0; transition: opacity 0.5s; }
#f-rang.visible { opacity: 1; }
/* Courbe de fin : la montée du joueur, suivie de près, puis la vue s'élargit sur tous les joueurs du jour. */
.courbe { margin: 14px 0 12px; border: 1px solid var(--trait); border-radius: 14px; background: rgb(21 32 43 / 0.03); overflow: hidden; }
.courbe canvas { display: block; width: 100%; height: 170px; }
#f-detail { list-style: none; padding: 0; margin: 0 0 24px; text-align: left; }
#f-detail li { padding: 14px 0; border-top: 1px solid var(--trait); }
#f-detail .q { font-size: 0.85rem; color: var(--texte-doux); }
#f-detail .ligne { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; margin: 2px 0 4px; }
#f-detail .toi { font-weight: 700; font-size: 1.1rem; }
#f-detail .m { font-weight: 600; white-space: nowrap; }
#f-detail .discret + .discret { margin-top: 2px; }
#f-test { margin-top: 12px; }

/* Altimètre : une règle graduée qu'on découvre en montant. Le point du joueur part du bas (au niveau de la carte
   de la question), monte jusqu'au milieu de l'écran puis y reste : c'est la règle qui défile ; tout en haut, la
   règle s'arrête et le point repart vers le haut. Positions calculées par jeu.js (placerRegle). */
#altimetre {
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  width: 220px; /* une largeur réelle, sinon le masque (fondu en haut et en bas) cache tout */
  --x: 12px; /* position de la ligne, tout près du bord : la règle reste discrète */
  color: var(--sur-ciel);
  pointer-events: none;
  transition: color 0.4s;
  -webkit-mask-image: linear-gradient(transparent, #000 14%, #000 86%, transparent);
  mask-image: linear-gradient(transparent, #000 14%, #000 86%, transparent);
}
#regle { position: absolute; left: var(--x); top: 0; height: 0; opacity: 0.8; } /* son bord bas est l'altitude 0 */
/* Petits traits tous les 10 m (6 px), pour le décor ; plus marqués sur la partie parcourue. */
#regle .micro {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 3px;
  background: repeating-linear-gradient(to top, currentColor 0 1px, transparent 1px 6px);
  opacity: 0.12;
}
#regle #micro-trace { opacity: 0.3; }
#regle .ligne, #trace { position: absolute; bottom: 0; left: -1px; width: 2px; border-radius: 1px; background: currentColor; }
#regle .ligne { opacity: 0.3; }
#trace { opacity: 0.85; } /* le chemin déjà parcouru */
.grad { position: absolute; left: 0; width: 5px; height: 1px; background: currentColor; opacity: 0.4; }
.grad.fin { width: 3px; opacity: 0.25; }
.grad.demi { width: 8px; opacity: 0.55; }
.grad.km { width: 12px; height: 2px; margin-bottom: -0.5px; opacity: 0.7; }
.grad.avant { opacity: 0.2; }
.grad span { position: absolute; left: 18px; top: -7px; font-size: 0.68rem; font-weight: 500; white-space: nowrap; transition: opacity 0.2s; }
#paliers > div {
  position: absolute;
  left: -4px;
  width: 10px;
  height: 2px;
  background: currentColor;
  opacity: 0.45;
}
#paliers > div span {
  transition: opacity 0.2s;
  position: absolute;
  left: 16px;
  top: -8px;
  font-size: 0.7rem;
  white-space: nowrap;
}
#paliers > div.prochain { opacity: 1; }
#paliers > div.prochain span { font-weight: 700; }
#curseur {
  position: absolute;
  top: 0;
  left: calc(var(--x) - 4.5px);
  width: 9px;
  height: 9px;
  margin-top: -4.5px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 3px rgb(255 255 255 / 0.25);
}
#alt-valeur { position: absolute; left: 18px; top: -6px; font-size: 0.75rem; font-weight: 600; white-space: nowrap; }
#etage { position: absolute; left: 18px; top: 10px; font-size: 0.6rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap; opacity: 0.8; }

@media (max-width: 760px) {
  main { width: min(540px, 100% - 72px); margin-left: 56px; margin-right: 16px; }
  #altimetre { --x: 9px; width: 60px; }
  #alt-valeur, #etage, #paliers > div span, .grad span { display: none; }
  .carte { padding: 28px 20px; }
  .devise { font-size: 1.15rem; letter-spacing: 0.2em; }
  .depart { margin-top: 43vh; } /* titre plus petit : on redescend pour que le bouton reste sur la plaine */
  .consigne-jeu { font-size: 1.1rem; }
  .envoler { font-size: 2rem; }
  /* Sur téléphone, le clavier couvre le bas de l'écran : la carte reste juste sous le champ. */
  #zone-reponse { min-height: 140px; }
  #carte-question { margin-top: 20px; }
}
