:root {
  --noir: #000000;
  --os: #d9d3c5;
  --cendre: #8b8f92;
  --neon: #ff3a2c;
  --texte: 'Cormorant Garamond', 'Times New Roman', serif;
}

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

html,
body {
  margin: 0;
  height: 100%;
  background: var(--noir);
  color: var(--os);
  font-family: var(--texte);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

[hidden] {
  display: none !important;
}

.visuellement-cache {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Ordre d'empilement des étapes */
.scene {
  z-index: 1;
}

.arrivee {
  z-index: 2;
}

.accueil {
  z-index: 3;
}

.chambre {
  z-index: 10;
}

.site {
  z-index: 11;
}

.chambre-avant {
  z-index: 12;
}

.carton,
.fin {
  z-index: 20;
}

.grain {
  z-index: 25;
}

.flash {
  z-index: 26;
}

.suite {
  z-index: 30;
}

.intro {
  z-index: 35;
}

.entree {
  z-index: 40;
}

.scene {
  position: fixed;
  inset: 0;
  overflow: hidden;
}

.scene canvas,
.gros-plan,
.gros-plan img,
.noir {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.sans-webgl .scene {
  background: url('../assets/images/manoir.jpg') center 43% / cover no-repeat;
}

.sans-webgl #gl {
  display: none;
}

/* Gros plans de la porte pendant l'entrée */
.gros-plan {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.7s ease;
}

.gros-plan.visible {
  opacity: 1;
}

.gros-plan img {
  object-fit: cover;
  filter: saturate(0.85) contrast(1.05) brightness(0.92);
  transform-origin: 50% 55%;
}

#porte-ouverte {
  opacity: 0;
  transition: opacity 1.1s ease;
}

#porte-ouverte.visible {
  opacity: 1;
}

/* Zone cliquable posée sur la porte du manoir */
.porte {
  position: absolute;
  top: 0;
  left: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  pointer-events: none;
  border-radius: 40% 40% 4px 4px / 22% 22% 4px 4px;
}

body[data-etape='manoir'] .porte {
  pointer-events: auto;
}

/* Tant qu'on n'a pas vu la fille à la fenêtre, la porte ne réagit pas */
.porte.verrouillee {
  cursor: default;
}

.en-transition .porte {
  pointer-events: none;
  visibility: hidden;
}

/* La statuette de la quête bonus, posée sur le décor, et sa zone cliquable */
.scene .statuette {
  inset: auto;
  top: 0;
  left: 0;
  pointer-events: none;
}

.statuette-cible {
  position: absolute;
  top: 0;
  left: 0;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.en-transition .statuette-cible {
  visibility: hidden;
}

.statuette-cible:focus-visible {
  outline: 1px solid rgba(217, 211, 197, 0.45);
  outline-offset: 4px;
}

/* Le compteur de la quête bonus, en bas à droite : une figurine par statuette, fendue quand elle est cassée, et
   au-dessus un message de temps en temps */
.quete {
  position: fixed;
  z-index: 24;
  right: max(3vw, 16px);
  bottom: max(3vh, 16px);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
  max-width: min(36rem, calc(100% - 32px));
  pointer-events: none;
  opacity: 0;
  transition: opacity 2s ease;
}

/* À l'écran de fin, la quête s'en va. */
body[data-etape='fin'] .quete.active {
  opacity: 0;
}

/* Quand la lampe meurt avant que la fille surgisse, elle s'en va plus vite. */
body.quete-cachee .quete.active {
  opacity: 0;
  transition-duration: 0.6s;
}

.quete.active {
  opacity: 1;
}

.quete-message {
  text-align: right;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 1.2s ease, transform 1.2s ease;
}

.quete.parle .quete-message {
  opacity: 1;
  transform: none;
  transition-duration: 0.5s;
}

.quete-titre {
  margin: 0 0 0.15rem;
  font-size: clamp(1.05rem, 1.5vw, 1.6rem);
  letter-spacing: 0.04em;
  color: #e0866a;
  text-shadow: 0 0 14px #000, 0 0 3px #000;
}

.quete-icones {
  display: flex;
  gap: 10px;
  opacity: 0.8;
}

/* La quête principale, juste au-dessus des figurines : chaque cours s'écrit de gauche à droite quand on repose la
   fiche d'accueil, puis se barre une fois validé. */
.quete-cours {
  margin: 0;
  padding: 0;
  list-style: none;
}

.quete-cours[hidden] {
  display: none;
}

.quete-cours li {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  font-size: clamp(1.1rem, 1.6vw, 1.75rem);
  line-height: 1.7;
  color: rgba(217, 211, 197, 0.9);
  text-shadow: 0 0 14px #000, 0 0 3px #000;
  animation: quete-ecrit 1.2s ease-out both;
}

.quete-cours li + li {
  animation-delay: 0.9s;
}

.quete-cours li::after {
  content: '';
  flex: none;
  width: 0.72em;
  height: 0.72em;
  border: 1px solid rgba(217, 211, 197, 0.75);
  box-shadow: 0 0 6px #000;
}

.quete-cours li.faite {
  color: rgba(217, 211, 197, 0.5);
  text-decoration: line-through #d97757;
}

.quete-cours li.faite::after {
  border-color: #d97757;
  background: #d97757;
}

@keyframes quete-ecrit {
  from {
    clip-path: inset(-20px 100% -20px -20px);
  }
  to {
    clip-path: inset(-20px -20px -20px -20px);
  }
}

.quete-icone {
  width: clamp(36px, 2.6vw, 56px);
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 0 6px #000);
}

.quete-corps {
  fill: #2a1714;
  transition: fill 0.3s ease;
}

.quete-pupilles {
  fill: #ff3a1a;
}

.quete-moitie {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transition: transform 0.45s cubic-bezier(0.3, 1.6, 0.5, 1);
}

.cassee .quete-corps {
  fill: #d97757;
}

.cassee .quete-pupilles {
  fill: #140605;
}

.cassee .quete-moitie--g {
  transform: translate(-1.4px, 0.8px) rotate(-14deg);
}

.cassee .quete-moitie--d {
  transform: translate(1.4px, 1px) rotate(11deg);
}

.quete-texte {
  margin: 0;
  font-style: italic;
  font-size: clamp(1.1rem, 1.7vw, 1.85rem);
  color: rgba(217, 211, 197, 0.85);
  text-shadow: 0 0 14px #000, 0 0 3px #000;
}

/* Une quête qui arrive : en grand et en blanc au milieu de l'écran, sur une ombre qui la détache du décor. Les lettres
   sortent du flou une à une ; js/quete.js la fait ensuite filer vers le coin en rapetissant. */
.quete-annonce {
  position: fixed;
  inset: 0;
  z-index: 25;
  display: grid;
  place-items: center;
  padding: 24px 16px;
  pointer-events: none;
}

.quete-annonce-boite {
  position: relative;
  isolation: isolate;
  max-width: 100%;
  text-align: center;
  opacity: 0;
  filter: blur(8px);
  transition: opacity 0.6s ease, filter 0.6s ease;
}

.quete-annonce-boite::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: -45% -30%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.6), transparent);
}

.quete-annonce.visible .quete-annonce-boite {
  opacity: 1;
  filter: none;
}

.quete-annonce-titre {
  margin: 0 0 0.4em;
  font-size: clamp(1.15rem, 1.9vw, 2.4rem);
  letter-spacing: 0.06em;
  color: #e0866a;
  text-shadow: 0 0 18px #000, 0 0 4px #000;
}

.quete-annonce-texte {
  max-width: 22ch;
  margin: 0;
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.9rem, 3.8vw, 4.8rem);
  line-height: 1.2;
  color: #f6f3ec;
  text-shadow: 0 0 24px #000, 0 0 6px #000;
  text-wrap: balance;
}

.quete-mot {
  white-space: nowrap;
}

.quete-lettre {
  display: inline-block;
  opacity: 0;
  animation: quete-lettre 0.7s var(--a) ease-out forwards;
}

@keyframes quete-lettre {
  from {
    opacity: 0;
    filter: blur(6px);
    transform: translateY(0.15em);
  }
  to {
    opacity: 1;
    filter: none;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .quete-lettre {
    animation-name: quete-lettre-calme;
  }

  @keyframes quete-lettre-calme {
    to {
      opacity: 1;
    }
  }
}

/* Sur un écran étroit, il se pose au-dessus des sous-titres et de la consigne. */
@media (max-width: 700px) {
  .quete {
    bottom: calc(max(9vh, 40px) + 4.5rem);
  }
}

.porte:focus-visible {
  outline: 1px solid rgba(217, 211, 197, 0.45);
  outline-offset: 8px;
}

.indice {
  position: absolute;
  left: 50%;
  bottom: max(6vh, 28px);
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 32px);
  margin: 0;
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  letter-spacing: 0.02em;
  text-align: center;
  color: rgba(217, 211, 197, 0.8);
  text-shadow: 0 0 18px #000, 0 0 4px #000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 2.5s ease;
}

.indice.visible {
  opacity: 1;
  animation: respire 5s ease-in-out 2.5s infinite;
}

@keyframes respire {
  50% {
    opacity: 0.45;
  }
}

.noir {
  background: var(--noir);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.9s ease;
}

.noir.visible {
  opacity: 1;
}

/* Écran d'entrée */
.entree,
.suite {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(1.4rem, 4vh, 2.4rem);
  padding: 24px 16px;
  text-align: center;
}

.entree {
  background: rgba(0, 0, 0, 0.9);
  transition: opacity 1.8s ease;
}

.entree.cachee {
  opacity: 0;
  pointer-events: none;
}

/* Le titre : une ligne pâle, puis « apprendre » énorme, rouge sang, qui coule. Les coulures partent du pied des
   lettres et descendent lentement à l'ouverture ; la plus longue lâche une goutte de temps en temps. Le filtre #filtre-sang
   fond lettres et coulures en une seule matière et leur donne un reflet mouillé. */
.entree-titre {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 0;
  font-weight: 300;
  line-height: 1;
}

.entree-titre-haut {
  font-size: clamp(1.5rem, 4.6vw, 3.3rem);
  letter-spacing: 0.01em;
}

.entree-sang {
  /* Le bas réservé aux coulures fait partie de la boîte (le filtre ne déborde pas d'elle), sans pousser la suite. */
  padding: 0 0.1em 0.62em;
  margin-bottom: -0.38em;
  font-size: clamp(4rem, 17vw, 10.5rem);
  font-weight: 700;
  line-height: 0.95;
  letter-spacing: -0.01em;
  color: #8e0c06;
  filter: url(#filtre-sang);
}

.coule {
  position: relative;
  display: inline-block;
  width: 0;
  height: 0;
  vertical-align: baseline;
}

.coule::before,
.coule::after,
.coule b {
  content: '';
  position: absolute;
  left: var(--x);
  background: currentColor;
}

.coule::before {
  top: var(--y);
  width: calc(var(--e) * 1.8);
  height: 0;
  margin-left: calc(var(--e) * -0.9);
  clip-path: polygon(0 0, 100% 0, 78% 0.07em, 74% 100%, 26% 100%, 22% 0.07em);
  animation: coule var(--t) var(--r) cubic-bezier(0.25, 0.6, 0.35, 1) forwards;
}

/* La perle au bout de la coulure, qui descend avec elle. */
.coule::after {
  top: calc(var(--y) - 0.03em);
  width: calc(var(--e) * 1.75);
  height: calc(var(--e) * 2);
  margin-left: calc(var(--e) * -0.875);
  border-radius: 50% 50% 50% 50% / 42% 42% 58% 58%;
  animation: perle var(--t) var(--r) cubic-bezier(0.25, 0.6, 0.35, 1) forwards;
}

@keyframes coule {
  to {
    height: var(--l);
  }
}

@keyframes perle {
  to {
    transform: translateY(var(--l));
  }
}

/* La goutte qui gonfle au bout de la plus longue coulure, se détache, tombe et s'amenuise. */
.coule b {
  top: calc(var(--y) + var(--l) - 0.02em);
  width: calc(var(--e) * 1.6);
  height: calc(var(--e) * 1.9);
  margin-left: calc(var(--e) * -0.8);
  border-radius: 50% 50% 50% 50% / 40% 40% 60% 60%;
  opacity: 0;
  animation: chute 6.5s calc(var(--r) + var(--t)) ease-in infinite;
}

@keyframes chute {
  0% {
    opacity: 1;
    transform: scale(0.5);
  }
  70% {
    transform: scale(1.1);
  }
  80% {
    transform: translateY(0.05em) scale(1);
  }
  92% {
    opacity: 1;
    transform: translateY(0.34em) scale(0.75);
  }
  97%,
  100% {
    opacity: 0;
    transform: translateY(0.42em) scale(0.3);
  }
}

.entree-filtres {
  position: absolute;
  width: 0;
  height: 0;
}

.entree-avertissement {
  max-width: 34ch;
  margin: 0;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--cendre);
}

.bouton {
  padding: 0.35em 0.15em;
  border: 0;
  border-bottom: 1px solid currentColor;
  background: none;
  color: var(--os);
  font: 500 clamp(1.2rem, 2.2vw, 1.45rem) / 1 var(--texte);
  letter-spacing: 0.12em;
  cursor: pointer;
  transition: color 0.4s ease, text-shadow 0.4s ease;
}

.bouton:hover:not(:disabled),
.bouton:focus-visible {
  color: var(--neon);
  text-shadow: 0 0 12px rgba(255, 58, 44, 0.7);
  outline: none;
}

.bouton:disabled {
  opacity: 0.45;
  cursor: progress;
}

/* L'introduction : une voix dans le noir. Au début, une lueur à peine grise, comme une pièce encore éclairée ; elle
   s'éteint d'un coup quand la voix le demande. Une phrase à la fois au centre, ou le titre, dans une brume qui dérive. */
.intro {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 24px 16px;
  overflow: hidden;
  background: radial-gradient(ellipse at 50% 45%, #1c1916 0%, #0c0b0a 55%, #050505 100%);
}

.intro.eteinte {
  background: var(--noir);
}

/* Deux nappes de brume pâle, très lentes, qui ne passent jamais au même endroit en même temps. Quand la lumière
   s'éteint, il en reste un peu. */
.intro::before,
.intro::after {
  content: '';
  position: absolute;
  inset: -30%;
  background:
    radial-gradient(ellipse 34% 20% at 32% 56%, rgba(205, 199, 186, 0.075), transparent 70%),
    radial-gradient(ellipse 26% 15% at 68% 42%, rgba(205, 199, 186, 0.055), transparent 70%);
  filter: blur(18px);
  pointer-events: none;
  animation: intro-brume 30s ease-in-out infinite alternate;
  transition: opacity 1.6s ease;
}

.intro::after {
  background:
    radial-gradient(ellipse 40% 22% at 62% 64%, rgba(205, 199, 186, 0.06), transparent 70%),
    radial-gradient(ellipse 24% 14% at 26% 36%, rgba(205, 199, 186, 0.045), transparent 70%);
  animation-duration: 37s;
  animation-direction: alternate-reverse;
}

.intro.eteinte::before,
.intro.eteinte::after {
  opacity: 0.55;
}

@keyframes intro-brume {
  from {
    transform: translate3d(-7%, 2%, 0) scale(1);
  }
  to {
    transform: translate3d(7%, -3%, 0) scale(1.18);
  }
}

.intro > * {
  grid-area: 1 / 1;
}

.intro-texte,
.intro-titre {
  position: relative;
  z-index: 1;
}

.intro-texte {
  max-width: 22ch;
  margin: 0;
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.8rem, 4.4vw, 3rem);
  line-height: 1.3;
  text-align: center;
}

/* Tant qu'elle est là (--duree, fixée par le script), la phrase avance lentement vers nous. Quand elle part, elle
   s'efface en un souffle, un peu plus grande et floue, sans que l'avancée ne reparte de zéro. */
.intro-texte.ecrit,
.intro-titre.ecrit {
  animation: intro-avance var(--duree, 4s) cubic-bezier(0.25, 0, 0.6, 1) both;
}

.intro-texte.ecrit.dissout,
.intro-titre.ecrit.dissout {
  animation:
    intro-avance var(--duree, 4s) cubic-bezier(0.25, 0, 0.6, 1) both,
    intro-traverse 0.22s ease-in forwards;
}

@keyframes intro-avance {
  from {
    scale: 0.95;
  }
  to {
    scale: 1.05;
  }
}

@keyframes intro-traverse {
  to {
    transform: scale(1.12);
    filter: blur(6px);
    opacity: 0;
  }
}

.intro-mot {
  white-space: nowrap;
}

/* Chaque lettre sort d'une brume légère : une tache un peu floue et un peu grande, qui devient nette en moins d'un
   quart de seconde et garde un léger halo. Elles ne sont pas tout à fait sur la même ligne. */
.intro-lettre {
  display: inline-block;
  position: relative;
  top: var(--y);
  color: transparent;
  animation: intro-encre 0.45s var(--a) ease-out forwards;
}

@keyframes intro-encre {
  0% {
    color: transparent;
    transform: scale(1.3);
    filter: blur(6px);
    text-shadow: 0 0 0.5em rgba(217, 211, 197, 0);
  }
  35% {
    color: rgba(217, 211, 197, 0.9);
    filter: blur(1px);
    text-shadow: 0 0 0.4em rgba(217, 211, 197, 0.45);
  }
  100% {
    color: var(--os);
    transform: none;
    filter: none;
    text-shadow: 0 0 0.3em rgba(217, 211, 197, 0.16);
  }
}

/* « apprendre » monte en sang au moment où il le dit, un peu trop grand puis à sa place. */
.intro-titre .entree-sang {
  animation: intro-apparait 0.45s ease-out both;
}

@keyframes intro-apparait {
  from {
    opacity: 0;
    scale: 1.18;
  }
}

@media (prefers-reduced-motion: reduce) {
  .intro::before,
  .intro::after {
    animation: none;
  }

  .intro-texte.ecrit,
  .intro-titre.ecrit {
    animation: none;
  }

  .intro-texte.ecrit.dissout,
  .intro-titre.ecrit.dissout {
    animation: intro-efface 0.22s ease-in forwards;
  }

  @keyframes intro-efface {
    to {
      opacity: 0;
    }
  }

  .intro-lettre {
    animation-name: intro-encre-calme;
  }

  @keyframes intro-encre-calme {
    from {
      color: transparent;
    }
    to {
      color: var(--os);
    }
  }

  .intro-titre .entree-sang {
    animation-name: intro-efface;
    animation-direction: reverse;
  }
}

/* Écran de fin provisoire */
.suite {
  background: var(--noir);
}

.suite[hidden] {
  display: none;
}

.suite-texte {
  margin: 0;
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1.6rem, 3.6vw, 2.4rem);
}

.suite-note {
  margin: 0;
  color: var(--cendre);
  font-size: 1.1rem;
}

/* La chambre du début */
.chambre {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--noir);
}

.chambre--cliquable {
  cursor: pointer;
}

/* Le témoin qui suit la souris sur un objet cliquable */
.chambre-temoin {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  font-style: italic;
  color: var(--os);
  text-shadow: 0 0 10px #000, 0 0 3px #000;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.chambre-temoin::before {
  content: '';
  width: 22px;
  height: 22px;
  flex: none;
  border: 1.5px solid rgba(244, 236, 222, 0.9);
  border-radius: 50%;
  box-shadow: 0 0 12px rgba(255, 214, 160, 0.55), inset 0 0 6px rgba(255, 214, 160, 0.35);
  animation: temoin 1.4s ease-in-out infinite;
}

.chambre-temoin.visible {
  opacity: 1;
}

@keyframes temoin {
  50% {
    transform: scale(1.3);
    opacity: 0.55;
  }
}

.chambre-avant {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.chambre-plan--avant {
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
}

.chambre-relief {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Les petits cœurs qui montent au-dessus du chat quand on le caresse. Le calque a la taille de l'image
   (positions en pixels de l'image) et suit la caméra. */
.chambre-coeurs {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  pointer-events: none;
}

.coeur {
  position: absolute;
  width: var(--taille);
  height: var(--taille);
  margin: calc(var(--taille) / -2) 0 0 calc(var(--taille) / -2);
  opacity: 0;
  filter: drop-shadow(0 0 3px rgba(255, 150, 170, 0.6));
  animation: coeur var(--duree) ease-out forwards;
}

.coeur svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Chaque cœur porte une tête de mort, montrée à sa place dans l'envers de la pièce. */
.coeur svg + svg,
.chambre-coeurs--envers .coeur svg:first-child {
  display: none;
}

.chambre-coeurs--envers .coeur svg + svg {
  display: block;
}

.chambre-coeurs--envers .coeur {
  filter: drop-shadow(0 0 4px rgba(255, 40, 20, 0.7));
}

/* Il gonfle comme une bulle, monte en se balançant, puis s'efface. */
@keyframes coeur {
  0% {
    transform: translate(0, 0) scale(0.2);
    opacity: 0;
  }
  12% {
    transform: translate(0, -6px) scale(1.15);
    opacity: 1;
  }
  45% {
    transform: translate(var(--balance), -38px) scale(1);
    opacity: 1;
  }
  100% {
    transform: translate(calc(var(--balance) * -0.6), -95px) scale(0.85);
    opacity: 0;
  }
}

@keyframes coeur-doux {
  20%,
  60% {
    opacity: 1;
  }
}

.chambre-camera {
  position: absolute;
  inset: 0;
  will-change: transform;
}

.chambre-plan {
  position: absolute;
  top: 0;
  left: 0;
}

.chambre-plan img {
  display: block;
  width: 100%;
  height: 100%;
}

.chambre-ouverture-image {
  opacity: 0;
}

.chambre-ouverture-image.allumee {
  animation: allume 0.75s linear forwards;
}

/* Son visage éclairé en gros plan, posé sur la photo (position et taille en ligne, voir chambre.js). Ses bords se
   fondent dans la photo, qui a le même visage en moins net dessous. */
.chambre-plan img.chambre-visage {
  position: absolute;
  -webkit-mask-image: radial-gradient(closest-side, #000 70%, transparent);
  mask-image: radial-gradient(closest-side, #000 70%, transparent);
}

@keyframes allume {
  0% {
    opacity: 0;
  }
  10% {
    opacity: 0.9;
  }
  20% {
    opacity: 0.1;
  }
  32% {
    opacity: 1;
  }
  44% {
    opacity: 0.45;
  }
  100% {
    opacity: 1;
  }
}

/* Dans le noir, on ne voit que ses yeux et le haut de son visage, dessinés aux mesures de l'image. */
.chambre-yeux {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  opacity: 0;
  pointer-events: none;
}

.chambre-yeux.visibles {
  opacity: 1;
}

/* Quand il allume, son regard du noir revient à chaque creux de la lumière qui vacille (l'inverse de « allume »),
   puis se fond dans ses vrais yeux. */
.chambre-yeux.eteints {
  animation: regard-eteint 0.75s linear forwards;
}

@keyframes regard-doux {
  to {
    opacity: 0;
  }
}

@keyframes regard-eteint {
  0% {
    opacity: 1;
  }
  10% {
    opacity: 0.3;
  }
  20% {
    opacity: 0.95;
  }
  32% {
    opacity: 0.15;
  }
  44% {
    opacity: 0.6;
  }
  100% {
    opacity: 0;
  }
}

.chambre-fumee {
  position: absolute;
  pointer-events: none;
}

.chambre-lueur {
  position: absolute;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(170, 200, 255, 0.3), rgba(150, 185, 255, 0.08) 55%, transparent);
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease;
}

.chambre-lueur.allumee {
  opacity: 1;
  animation: lueur-ecran 5s ease-in-out infinite;
}

@keyframes lueur-ecran {
  50% {
    opacity: 0.85;
  }
}

.chambre .noir {
  transition-duration: 1.6s;
}

/* Cartons noirs */
.carton {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 24px 16px;
  background: var(--noir);
}

.carton-texte {
  margin: 0;
  font-weight: 300;
  font-style: italic;
  font-size: clamp(1.8rem, 4.5vw, 3rem);
  letter-spacing: 0.01em;
  text-align: center;
  opacity: 0;
  transition: opacity 1.2s ease;
}

.carton-texte.visible {
  opacity: 1;
}

/* L'écran de fin : le merci au milieu du noir, et le lien pour recommencer. Chacun apparaît lentement, l'un après
   l'autre (js/fin.js). */
.fin {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(1.6rem, 5vh, 3rem);
  padding: 24px 16px;
  background: var(--noir);
  text-align: center;
}

.fin-merci {
  max-width: 20ch;
  margin: 0;
  font-weight: 300;
  font-style: italic;
  font-size: clamp(2.1rem, 4.6vw, 6.5rem);
  line-height: 1.2;
  text-wrap: balance;
}

.fin-recommencer {
  margin-top: 1rem;
  padding: 8px 4px;
  border: 0;
  background: none;
  color: rgba(217, 211, 197, 0.7);
  font: inherit;
  font-size: clamp(1rem, 1.3vw, 1.6rem);
  letter-spacing: 0.04em;
  text-decoration: underline;
  text-underline-offset: 5px;
  cursor: pointer;
}

.fin-recommencer:hover,
.fin-recommencer:focus-visible {
  color: var(--os);
}

.fin-recommencer:focus-visible {
  outline: 1px dashed rgba(217, 211, 197, 0.6);
  outline-offset: 6px;
}

.fin-merci,
.fin-recommencer {
  opacity: 0;
  transition: opacity 2.2s ease;
}

.fin-merci.visible,
.fin-recommencer.visible {
  opacity: 1;
}

.fin-recommencer:not(.visible) {
  visibility: hidden;
}

/* Le mur de la lampe et le logo Instagram se partagent la même place : l'un s'éteint, l'autre se trace. */
.fin-centre {
  display: grid;
  place-items: center;
}

.fin-centre > * {
  grid-area: 1 / 1;
}

/* Le logo Instagram peint au doigt dans le sang : le cadre, puis le rond, puis le point d'un coup de doigt, et les
   coulures qui descendent ; le lien vers le compte apparaît dessous. */
.fin-insta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 4px 8px;
  color: var(--os);
  text-decoration: none;
}

.fin-insta:not(.dessine) {
  visibility: hidden;
}

.fin-insta-logo {
  display: block;
  width: clamp(120px, 23vmin, 280px);
  height: auto;
}

.fin-insta-texte {
  font-size: clamp(1.15rem, 1.8vw, 2.1rem);
  letter-spacing: 0.02em;
  text-wrap: balance;
  text-underline-offset: 5px;
  opacity: 0;
  transition: opacity 2.2s ease;
}

.fin-insta.visible .fin-insta-texte {
  opacity: 1;
}

.fin-insta:hover .fin-insta-texte,
.fin-insta:focus-visible .fin-insta-texte {
  text-decoration: underline;
}

.fin-insta:focus-visible {
  outline: 1px dashed rgba(217, 211, 197, 0.6);
  outline-offset: 6px;
}

.fin-insta-trait,
.fin-insta-point {
  opacity: 0;
}

.fin-insta-trait {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.fin-insta.dessine .fin-insta-cadre {
  animation: fin-insta-trait 1.1s cubic-bezier(0.35, 0.1, 0.6, 1) forwards;
}

.fin-insta.dessine .fin-insta-rond {
  animation: fin-insta-trait 0.65s 1.2s cubic-bezier(0.35, 0.1, 0.6, 1) forwards;
}

.fin-insta.dessine .fin-insta-point {
  animation: fin-insta-point 0.12s 1.95s forwards;
}

/* Les coulures : lentes au départ, puis de plus en plus vite, comme celles du cœur. */
.fin-insta.dessine .fin-insta-coulure {
  animation: fin-insta-trait var(--t) calc(2.1s + var(--r)) cubic-bezier(0.5, 0, 0.9, 0.6) forwards;
}

@keyframes fin-insta-trait {
  from {
    opacity: 1;
  }
  to {
    opacity: 1;
    stroke-dashoffset: 0;
  }
}

@keyframes fin-insta-point {
  to {
    opacity: 1;
  }
}

/* Sous le merci, la lampe torche s'allume sur un pan de mur du manoir, tremble un peu dans la main, et un doigt invisible
   y trace un cœur dans le sang : la moitié gauche, puis la droite, puis les coulures descendent. Il se brouille et
   devient le petit Claude méchant, peint au doigt comme ceux des murs. Le brouillage (décalage, tranche coupée,
   couleurs qui se séparent, lumière qui saute) est tiré au hasard par js/fin.js. */
.fin-figure {
  position: relative;
  width: clamp(220px, 44vmin, 560px);
  aspect-ratio: 1;
  opacity: 0;
}

.fin-mur {
  display: block;
  width: 100%;
  height: 100%;
  /* Le bord du faisceau se perd dans le noir. */
  mask-image: radial-gradient(circle closest-side, #000 72%, transparent 100%);
}

.fin-figure.allume {
  opacity: 1;
  animation: fin-allume 0.7s steps(1, end);
}

.fin-figure.allume .fin-mur {
  animation: fin-main 5.2s ease-in-out infinite alternate;
}

/* La lampe qui hésite avant de tenir. */
@keyframes fin-allume {
  0% {
    opacity: 0.35;
  }
  12% {
    opacity: 0;
  }
  24% {
    opacity: 0.8;
  }
  34% {
    opacity: 0.1;
  }
  48% {
    opacity: 1;
  }
}

/* La main qui tient la lampe n'est jamais tout à fait immobile. */
@keyframes fin-main {
  0% {
    transform: translate(-0.6%, 0.3%) rotate(-0.4deg);
  }
  50% {
    transform: translate(0.4%, -0.5%) rotate(0.2deg);
  }
  100% {
    transform: translate(0.7%, 0.4%) rotate(0.5deg);
  }
}

.fin-trait {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.fin-figure.dessine .fin-trait--gauche {
  animation: fin-trait 1s cubic-bezier(0.35, 0.1, 0.6, 1) forwards;
}

.fin-figure.dessine .fin-trait--droite {
  animation: fin-trait 1s 1.05s cubic-bezier(0.35, 0.1, 0.6, 1) forwards;
}

@keyframes fin-trait {
  to {
    stroke-dashoffset: 0;
  }
}

/* Les coulures : le sang descend lentement, puis de plus en plus vite. */
.fin-coulures {
  transform-box: fill-box;
  transform-origin: top;
  transform: scaleY(0);
}

.fin-figure.dessine .fin-coulures {
  animation: fin-coule 1.3s 1.7s cubic-bezier(0.5, 0, 0.9, 0.6) forwards;
}

@keyframes fin-coule {
  to {
    transform: none;
  }
}

.fin-claude,
.fin-clin,
.fin-figure[data-forme='claude'] .fin-coeur {
  visibility: hidden;
}

.fin-figure[data-forme='claude'] .fin-claude,
.fin-figure[data-forme='claude'].clin .fin-clin {
  visibility: visible;
}

.fin-figure.brouille {
  transform: translate(var(--gx, 0), var(--gy, 0)) skewX(var(--gk, 0deg));
  clip-path: inset(var(--haut, 0%) 0 var(--bas, 0%) 0);
}

.fin-figure.brouille .fin-mur {
  filter: url(#fin-rgb) brightness(var(--lum, 1));
}

/* Il s'éteint comme un vieil écran : écrasé en un trait qui brille, puis en un point, puis plus rien. */
.fin-figure.eteint .fin-mur {
  animation: fin-eteint 0.5s cubic-bezier(0.6, 0, 0.9, 0.4) forwards;
}

@keyframes fin-eteint {
  0% {
    transform: none;
    filter: brightness(1);
  }
  45% {
    transform: scale(1.15, 0.03);
    filter: brightness(3);
  }
  80% {
    transform: scale(0.02, 0.03);
    filter: brightness(4);
    opacity: 1;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fin-figure.allume,
  .fin-figure.allume .fin-mur {
    animation: none;
  }

  .fin-figure .fin-trait,
  .fin-figure .fin-coulures {
    animation: none !important;
    stroke-dashoffset: 0;
    transform: none;
  }

  .fin-figure.brouille {
    transform: none;
    clip-path: none;
  }

  .fin-figure.eteint .fin-mur {
    animation: fin-efface 0.5s ease forwards;
  }

  .fin-insta.dessine .fin-insta-trait,
  .fin-insta.dessine .fin-insta-point {
    animation: none;
    opacity: 1;
    stroke-dashoffset: 0;
  }

  @keyframes fin-efface {
    to {
      opacity: 0;
    }
  }
}

/* L'heure du second carton : une horloge à palettes. Chaque chiffre est coupé en deux moitiés sur une charnière ;
   quand il change, le haut de l'ancien bascule vers le bas, puis le bas du nouveau se rabat et claque. Le chiffre
   qui vient de tomber reste un instant rouge sombre. */
.palette {
  position: relative;
  display: inline-block;
  width: 0.68em;
  height: 1.14em;
  margin: 0 0.035em;
  vertical-align: -0.26em;
  font-style: normal;
  font-weight: 500;
  font-variant-numeric: lining-nums tabular-nums;
  perspective: 4em;
}

.palette > span {
  position: absolute;
  left: 0;
  right: 0;
  height: 50%;
  overflow: hidden;
  background: linear-gradient(#211c17, #15120f);
  color: #e9e2d4;
  backface-visibility: hidden;
}

.palette i {
  display: block;
  height: 1.14em;
  line-height: 1.14em;
  font-style: normal;
  text-align: center;
}

.palette-haut,
.palette-rabat-haut {
  top: 0;
  border-radius: 0.08em 0.08em 0 0;
  transform-origin: 50% 100%;
}

.palette-bas,
.palette-rabat-bas {
  bottom: 0;
  border-radius: 0 0 0.08em 0.08em;
  transform-origin: 50% 0;
}

.palette-bas i,
.palette-rabat-bas i {
  margin-top: -0.57em;
}

/* La charnière. */
.palette::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: calc(50% - 0.5px);
  z-index: 3;
  height: 1px;
  background: rgba(0, 0, 0, 0.85);
}

.palette-rabat-haut,
.palette-rabat-bas {
  z-index: 2;
  visibility: hidden;
}

.palette--tombe .palette-rabat-haut {
  visibility: visible;
  animation: rabat-haut 0.13s ease-in forwards;
}

.palette--tombe .palette-rabat-bas {
  visibility: visible;
  animation: rabat-bas 0.13s 0.13s ease-out both;
}

@keyframes rabat-haut {
  to {
    transform: rotateX(-90deg);
  }
}

@keyframes rabat-bas {
  from {
    transform: rotateX(90deg);
  }
  to {
    transform: none;
  }
}

.palette--rouge > span {
  animation: palette-rouge 2.2s ease-out;
}

@keyframes palette-rouge {
  0% {
    color: #d02c1e;
  }
  100% {
    color: #e9e2d4;
  }
}

.carton-texte--choc {
  animation: choc-carton 0.28s steps(4, end);
}

@keyframes choc-carton {
  0% {
    transform: translate(0, 2px);
  }
  25% {
    transform: translate(-2px, -1px);
  }
  50% {
    transform: translate(1px, 1px);
  }
  75% {
    transform: translate(-1px, 0);
  }
  100% {
    transform: none;
  }
}

/* Le taxi et la forêt */
.arrivee {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--noir);
  cursor: none;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.arrivee canvas,
.arrivee .noir {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.arrivee .noir {
  transition-duration: 1.1s;
}

.sous-titre,
.consigne-marche {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 32px);
  margin: 0;
  text-align: center;
  text-shadow: 0 0 14px #000, 0 0 3px #000;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.sous-titre {
  bottom: max(9vh, 40px);
  font-size: clamp(1.25rem, 2.4vw, 1.7rem);
  color: #ece6d8;
}

.consigne-marche {
  bottom: max(6vh, 28px);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(1.05rem, 1.9vw, 1.35rem);
  color: rgba(217, 211, 197, 0.75);
  transition-duration: 1.4s;
}

/* Au-dessus de la consigne quand les deux sont à l'écran. */
.sous-titre--haut {
  bottom: calc(max(6vh, 28px) + 2.6rem);
}

.sous-titre.visible,
.consigne-marche.visible {
  opacity: 1;
}

/* En sortant du taxi, une seule fois : comment avancer, avec la souris dont le bouton gauche s'allume comme quand on
   appuie dessus. */
.aide-marche {
  position: absolute;
  left: 50%;
  bottom: max(6vh, 28px);
  display: flex;
  align-items: center;
  gap: 16px;
  width: max-content;
  max-width: calc(100% - 32px);
  transform: translateX(-50%);
  font-size: clamp(1.1rem, 1.45vw, 2.3rem);
  color: rgba(217, 211, 197, 0.85);
  text-shadow: 0 0 14px #000, 0 0 3px #000;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.2s ease;
}

.aide-marche.visible {
  opacity: 1;
}

.aide-marche p {
  margin: 0;
  font-style: italic;
  font-weight: 300;
}

.aide-souris {
  flex: none;
  width: 1.1em;
  height: 1.65em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  filter: drop-shadow(0 0 6px #000);
}

.aide-bouton {
  fill: currentColor;
  stroke: none;
  animation: aide-appui 1.8s ease-in-out infinite;
}

@keyframes aide-appui {
  0%,
  100% {
    opacity: 0.1;
  }
  30%,
  75% {
    opacity: 0.9;
  }
}

@media (pointer: coarse) {
  .aide-souris {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .aide-bouton {
    animation: none;
    opacity: 0.7;
  }
}

/* Il panique : la phrase tremble. */
.sous-titre--panique {
  animation: panique 0.12s steps(2) infinite;
}

@keyframes panique {
  0% {
    transform: translate(calc(-50% - 1.5px), 0);
  }
  100% {
    transform: translate(calc(-50% + 1.5px), -1px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .entree,
  .noir,
  .gros-plan,
  .indice,
  .carton-texte {
    transition-duration: 0.3s;
  }

  .indice.visible,
  .chambre-lueur.allumee,
  .chambre-temoin::before,
  .carton-texte--choc,
  .palette--tombe .palette-rabat-haut,
  .palette--tombe .palette-rabat-bas {
    animation: none;
  }

  /* Le sang est déjà coulé, rien ne bouge. */
  .coule::before {
    animation: none;
    height: var(--l);
  }

  .coule::after {
    animation: none;
    transform: translateY(var(--l));
  }

  .coule b {
    display: none;
  }

  .coeur {
    animation-name: coeur-doux;
  }

  .chambre-yeux.eteints {
    animation-name: regard-doux;
  }

  .sous-titre--panique {
    animation: none;
  }
}

/* Grain de film sur la forêt et le manoir : il bouge par à-coups, comme une pellicule. */
.grain {
  position: fixed;
  inset: -40px;
  pointer-events: none;
  background: url('../assets/images/grain.png');
  mix-blend-mode: overlay;
  opacity: 0;
  transition: opacity 1s ease;
  animation: grain 0.6s steps(6) infinite;
}

body[data-etape='arrivee'] .grain,
body[data-etape='manoir'] .grain {
  opacity: 0.09;
}

body[data-etape='accueil'] .grain,
body[data-etape='openspace'] .grain,
body[data-etape='fin'] .grain {
  opacity: 0.07;
}

/* L'accueil du manoir : la pièce, la feuille à cliquer sur le comptoir, et la feuille lue de près. */
.accueil {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--noir);
  cursor: none;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.accueil canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* La statuette de la quête bonus sur la cheminée : son canvas est placé et dimensionné par statuette.js. */
.accueil .statuette {
  inset: auto;
  top: 0;
  left: 0;
  pointer-events: none;
}

.accueil-feuille {
  position: absolute;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  cursor: pointer;
}

/* La porte noire de gauche et le néon au-dessus : les deux mènent à l'Open Space, une fois la quête prise. */
.accueil-sortie {
  position: absolute;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.accueil-sortie:focus-visible,
.accueil-feuille:focus-visible {
  outline: 1px dashed rgba(217, 211, 197, 0.6);
  outline-offset: 6px;
}

.accueil-fiche {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.74);
  cursor: auto;
  animation: fiche-fond 0.4s ease;
}

.accueil-fiche[hidden] {
  display: none;
}

/* Une vieille feuille tapée à la machine, jaunie, avec une auréole d'humidité et une tache de sang dans un coin. */
.fiche {
  width: min(460px, 100%);
  max-height: calc(100% - 32px);
  overflow: auto;
  padding: 44px 40px 30px;
  color: #2b2117;
  font: 17px / 1.55 'Special Elite', 'Courier New', monospace;
  background:
    radial-gradient(ellipse 26% 16% at 84% 10%, rgba(110, 18, 10, 0.6), rgba(110, 18, 10, 0) 70%),
    radial-gradient(ellipse 60% 40% at 18% 88%, rgba(120, 84, 40, 0.3), rgba(120, 84, 40, 0) 70%),
    radial-gradient(ellipse at 50% 40%, #e2d2a4, #c8b07a 75%, #a68b55);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.8), inset 0 0 60px rgba(70, 45, 15, 0.45);
  transform: rotate(-1.2deg);
  animation: fiche-arrive 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.fiche-titre {
  margin: 0 0 18px;
  font-size: 22px;
  letter-spacing: 0.04em;
}

.fiche-texte {
  margin: 0 0 16px;
}

.fiche-cours {
  margin: 0 0 20px;
  padding: 0;
  list-style: none;
}

.fiche-cours li {
  position: relative;
  margin: 0 0 10px;
  padding-left: 34px;
}

.fiche-cours li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 3px;
  width: 18px;
  height: 18px;
  border: 2px solid #2b2117;
}

.fiche-cours li.faite::after {
  content: '';
  position: absolute;
  left: 6px;
  top: 1px;
  width: 8px;
  height: 16px;
  border: solid #7a1208;
  border-width: 0 3px 3px 0;
  transform: rotate(40deg);
}

.fiche-reposer {
  display: block;
  margin: 8px 0 0 auto;
  padding: 6px 0;
  border: 0;
  background: none;
  color: #5a1a0e;
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 4px;
  cursor: pointer;
}

.fiche-reposer:focus-visible {
  outline: 1px dashed #5a1a0e;
  outline-offset: 4px;
}

@keyframes fiche-arrive {
  from {
    opacity: 0;
    transform: rotate(-4deg) scale(0.92) translateY(30px);
  }
}

@keyframes fiche-fond {
  from {
    opacity: 0;
  }
}

/* L'Open Space : la pièce dans le noir, et l'ordinateur à cliquer. */
.openspace {
  position: fixed;
  inset: 0;
  overflow: hidden;
  background: var(--noir);
  cursor: none;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.openspace canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.openspace-ordinateur {
  position: absolute;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  cursor: pointer;
}

/* Tant que le ballon n'est pas arrêté, l'ordinateur ne répond pas : rien n'indique qu'on peut le cliquer. */
.openspace-ordinateur:disabled {
  cursor: inherit;
}

.openspace-ordinateur:focus-visible {
  outline: 1px dashed rgba(217, 211, 197, 0.6);
  outline-offset: 6px;
}

/* La troisième statuette, sur le bureau de gauche : son canvas est placé et dimensionné par statuette.js. */
.openspace .statuette {
  inset: auto;
  top: 0;
  left: 0;
  pointer-events: none;
}

/* La fin de l'Open Space. Le noir qui tombe quand la lampe meurt (son opacité est réglée image par image), la fille
   qui surgit en plein écran, ses sous-titres, puis le certificat qu'elle nous tend. */
.openspace-noir {
  position: absolute;
  inset: 0;
  z-index: 6;
  background: var(--noir);
  opacity: 0;
  pointer-events: none;
}

.openspace-fille {
  position: absolute;
  inset: 0;
  z-index: 7;
  overflow: hidden;
  background: var(--noir);
  pointer-events: none;
}

.openspace-fille video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: 50% 36%;
  filter: brightness(0.86) contrast(1.08) saturate(0.82);
}

/* Les bords mangés par le noir (le film a déjà le grain de la nuit). */
.openspace-fille::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 72% 78% at 50% 44%, rgba(0, 0, 0, 0) 52%, rgba(0, 0, 0, 0.82) 100%);
}

/* Le sursaut quand elle surgit : d'abord ses yeux en très gros, l'image brûlée, une image en négatif, deux coupures
   noires, puis elle recule par saccades jusqu'à sa place en faisant trembler l'image. Pas de dernière image dans
   l'animation : après, ce sont les règles de la vidéo (et ses décrochages) qui comptent. Ensuite (approche), elle
   avance lentement vers nous pendant qu'elle nous fixe, et reste là. */
.openspace-fille.surgit video {
  animation: surgit 0.75s steps(15) both;
}

.openspace-fille.approche video {
  scale: 1.07;
  transition: scale 2.25s cubic-bezier(0.3, 0, 0.6, 1) 0.75s;
}

@keyframes surgit {
  0% {
    transform: scale(2.4) translate(0.8%, 0.4%);
    filter: brightness(2.1) contrast(1.7) saturate(0.2);
  }
  7% {
    transform: scale(2.2) translate(-1.2%, 0.6%);
    filter: invert(1) contrast(1.4);
  }
  13% {
    filter: brightness(0);
  }
  20% {
    transform: scale(1.7) translate(1.4%, -0.8%);
    filter: brightness(1.6) contrast(1.6) saturate(0) hue-rotate(-20deg);
  }
  27% {
    filter: brightness(0);
  }
  34% {
    transform: scale(1.3) translate(-1%, 0.5%);
    filter: brightness(1.35) contrast(1.4) saturate(0.5);
  }
  47% {
    transform: scale(1.14) translate(0.8%, -0.4%);
  }
  60% {
    transform: scale(1.07) translate(-0.5%, 0.3%);
  }
  80% {
    transform: scale(1.025) translate(0.2%, -0.1%);
  }
}

/* Pendant qu'elle parle, l'image décroche par moments : elle glisse d'un coup et ses couleurs bavent. */
.openspace-fille.bug video {
  transform: translate(0.6%, -0.25%) scale(1.012);
  filter: brightness(1.25) contrast(1.35) saturate(0.4) hue-rotate(-14deg);
}

.openspace-fille.bug::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: var(--bande, 40%);
  z-index: 1;
  height: 7%;
  background: rgba(200, 220, 230, 0.12);
  backdrop-filter: blur(1px) brightness(1.6);
  transform: translateX(-2.5%);
}

.openspace-sous-titre {
  z-index: 8;
}

.openspace-certificat {
  position: absolute;
  inset: 0;
  z-index: 9;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.66);
  cursor: auto;
  animation: fiche-fond 0.6s ease;
}

.openspace-certificat.range {
  opacity: 0;
  transition: opacity 0.8s ease;
}

/* Le certificat qu'elle nous tend : une vraie feuille imprimée, jaunie, pliée en quatre, avec ses auréoles de café
   et les empreintes de ses petits doigts en sang (le papier : assets/images/certificat-papier.webp, détouré par
   tools/certificat.mjs). Le texte est imprimé en caractères anciens, le nom rempli à la plume, les deux formateurs
   signent à l'encre bleu-noir, le tampon rouge et le sceau sec par-dessus, et une observation a été tapée après
   coup au ruban rouge de la machine à écrire. Tout se mesure en largeur de feuille (cqw), pour que la page garde sa
   mise en place à toutes les tailles. Elle monte vers nous depuis le bas. Sur un téléphone tenu droit, la feuille
   est tournée d'un quart de tour pour être lue en grand. */
.certificat {
  --l: min(1240px, 100vw - 32px, (100dvh - 84px) * 1.506);
  position: relative;
  display: grid;
  justify-items: end;
  gap: 10px;
  width: var(--l);
  animation: certificat-tendu 0.75s cubic-bezier(0.16, 0.84, 0.24, 1);
}

.certificat-place {
  position: relative;
  width: 100%;
  aspect-ratio: 2000 / 1328;
}

.certificat-feuille {
  --encre: #2a2119;
  --plume: #1c2236;
  --rouge: #8e1a12;
  position: absolute;
  inset: 0;
  container-type: inline-size;
  background: url('../assets/images/certificat-papier.webp') center / 100% 100% no-repeat;
  filter: drop-shadow(0 24px 44px rgba(0, 0, 0, 0.78)) saturate(0.84) brightness(0.9);
  rotate: 0.6deg;
}

/* La page imprimée, dans le cadre guilloché (les unités cqw y valent un centième de la largeur de la feuille). */
.certificat-contenu {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 11.4cqw 13.5cqw 10.9cqw;
  color: var(--encre);
  font: 1.65cqw / 1.38 'IM Fell English', 'Cormorant Garamond', serif;
  text-align: center;
}

/* L'encre boit le papier : on voit ses fibres et ses taches à travers. */
.certificat-contenu > * {
  margin: 0;
  mix-blend-mode: multiply;
}

/* Une lampe faible, un peu à gauche : les bords de la feuille restent dans l'ombre. */
.certificat-feuille::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 72% 70% at 44% 40%, rgba(0, 0, 0, 0) 42%, rgba(30, 20, 10, 0.4) 100%);
  mix-blend-mode: multiply;
  pointer-events: none;
}

.certificat-serie {
  position: absolute;
  top: 12.1cqw;
  right: 14.4cqw;
  color: var(--rouge);
  font: 1.5cqw / 1 'Special Elite', 'Courier New', monospace;
  letter-spacing: 0.12em;
  opacity: 0.85;
}

.certificat-logo {
  display: block;
  width: auto;
  height: 3.9cqw;
  margin-top: 1.1cqw;
  opacity: 0.88;
}

.certificat-ecole {
  margin-top: 0.4cqw;
  font-size: 1.35cqw;
  font-style: italic;
  letter-spacing: 0.02em;
}

.certificat-titre {
  margin: 1.3cqw 0 1.2cqw;
  font: 400 3.7cqw / 1.1 'IM Fell English SC', 'Cormorant Garamond', serif;
  letter-spacing: 0.035em;
}

.certificat-texte {
  max-width: 50cqw;
  text-wrap: balance;
}

.certificat-certifie {
  font-style: italic;
}

/* Le nom, à la plume, sur la ligne imprimée pour lui. */
.certificat-nom {
  min-width: 38cqw;
  margin: 0.1cqw 0 1cqw;
  padding: 0 2cqw 0.15cqw;
  border-bottom: 0.1cqw solid rgba(42, 33, 25, 0.7);
  color: #1d150e;
  font: 5.2cqw / 1.2 'Pinyon Script', 'Cormorant Garamond', cursive;
  overflow-wrap: anywhere;
  rotate: -0.8deg;
}

.certificat-lieu {
  margin-top: 0.7cqw;
  font-size: 1.45cqw;
  font-style: italic;
}

.certificat-signatures {
  display: flex;
  justify-content: space-between;
  width: 100%;
  margin-top: auto;
  padding: 0 3cqw;
}

.certificat-signature {
  position: relative;
  width: 17cqw;
  margin: 0;
  padding-top: 0.45cqw;
  border-top: 0.1cqw solid rgba(42, 33, 25, 0.7);
  font: 1.3cqw / 1.2 'IM Fell English SC', 'Cormorant Garamond', serif;
  letter-spacing: 0.03em;
}

.certificat-paraphe {
  position: absolute;
  bottom: 78%;
  left: 50%;
  color: var(--plume);
  font: 4.6cqw / 1 'Herr Von Muellerhoff', cursive;
  letter-spacing: 0;
  white-space: nowrap;
  translate: -46% 0;
  rotate: -7deg;
  opacity: 0.9;
}

.certificat-paraphe--jeff {
  font: 5cqw / 1 'Mrs Saint Delafield', cursive;
  translate: -62% -6%;
  rotate: -3deg;
}

/* Tapée après coup, à la machine, au ruban rouge, pas tout à fait droite. */
.certificat-observation {
  align-self: flex-start;
  margin: 1.5cqw 0 0 1cqw;
  color: var(--rouge);
  font: 1.2cqw / 1.2 'Special Elite', 'Courier New', monospace;
  letter-spacing: 0.02em;
  rotate: -0.5deg;
  opacity: 0.9;
}

/* Le sceau sec : frappé dans le papier, il n'a pas d'encre, seulement un relief qui prend la lumière en haut à
   gauche et fait une ombre en bas à droite. */
.certificat-sceau {
  position: absolute;
  left: 16.5cqw;
  bottom: 15.2cqw;
  width: 10cqw;
  fill: rgba(120, 92, 52, 0.12);
  stroke: rgba(120, 92, 52, 0.12);
  filter: drop-shadow(-0.07cqw -0.07cqw 0 rgba(255, 249, 232, 0.8)) drop-shadow(0.08cqw 0.1cqw 0.04cqw rgba(70, 46, 20, 0.45));
  rotate: -12deg;
}

.certificat-sceau text {
  stroke: none;
}

/* Le tampon rouge, posé de travers entre les deux signatures. */
.certificat-contenu .certificat-tampon {
  position: absolute;
  left: 50%;
  bottom: 13.6cqw;
  width: 15.5cqw;
  margin: 0;
  opacity: 0.86;
  translate: -50% 0;
  rotate: -9deg;
}

.certificat .fiche-reposer {
  margin: 0;
  color: #d8ccb4;
  font: 16px / 1.4 'Special Elite', 'Courier New', monospace;
}

.certificat .fiche-reposer:focus-visible {
  outline-color: #d8ccb4;
}

@media (orientation: portrait) and (max-width: 760px) {
  .certificat {
    --l: min(100dvh - 96px, (100vw - 24px) * 1.506);
    width: calc(var(--l) / 1.506);
  }

  .certificat-place {
    height: var(--l);
    aspect-ratio: auto;
  }

  .certificat-feuille {
    inset: auto;
    top: 50%;
    left: 50%;
    width: var(--l);
    aspect-ratio: 2000 / 1328;
    translate: -50% -50%;
    rotate: 90.6deg;
  }
}

@keyframes certificat-tendu {
  from {
    transform: translateY(70vh) rotate(7deg) scale(1.08);
  }
}

@media (prefers-reduced-motion: reduce) {
  .openspace-fille.surgit video,
  .certificat,
  .openspace-certificat {
    animation: none;
  }

  .openspace-fille.bug video {
    transform: none;
  }

  .openspace-fille.approche video {
    scale: none;
  }
}

/* Dans l'ordinateur : un vieil écran cathodique où s'ouvre Claude Code. Lignes de balayage, verre bombé qui
   assombrit les bords, lueur autour des lettres, et un léger frémissement de l'image. */
.terminal {
  --cc-orange: #d77757;
  --cc-texte: #e6e3dc;
  --cc-gris: #8c8c86;
  --cc-bleu: #b1b9f9;
  --cc-vert: #6fcf86;
  --cc-rouge: #ff6b6b;
  position: absolute;
  inset: 0;
  z-index: 5;
  background: #030404;
  cursor: auto;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.terminal.visible {
  opacity: 1;
}

.terminal-ecran {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 5vh, 56px) clamp(16px, 6vw, 96px);
  overflow: hidden;
  background: radial-gradient(ellipse at 50% 45%, #141917 0%, #0b0e0d 65%, #040505 100%);
  color: var(--cc-texte);
  font-family: 'JetBrains Mono', ui-monospace, Consolas, monospace;
  font-size: clamp(13px, 0.6rem + 0.7vw, 23px);
  line-height: 1.5;
  text-shadow: 0 0 6px rgba(200, 235, 220, 0.28);
  animation: terminal-fremit 0.12s steps(2) infinite;
}

/* Au-dessus de tout, même du lecteur vidéo agrandi : c'est le verre de l'écran. */
.terminal-ecran::before,
.terminal-ecran::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

.terminal-ecran::before {
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, 0.28) 0 1px, transparent 1px 3px);
}

.terminal-ecran::after {
  box-shadow: inset 0 0 18vmin rgba(0, 0, 0, 0.92);
  background: radial-gradient(ellipse at 30% 20%, rgba(255, 255, 255, 0.04), transparent 45%);
}

@keyframes terminal-fremit {
  50% {
    opacity: 0.975;
  }
}

/* Une mauvaise réponse : l'image décroche un instant. */
.terminal.decroche .terminal-ecran {
  animation: terminal-decroche 0.45s steps(6);
}

@keyframes terminal-decroche {
  0% { transform: translate(0, 0); filter: none; }
  20% { transform: translate(-6px, 2px); filter: hue-rotate(-30deg) saturate(2); }
  40% { transform: translate(5px, -3px); filter: none; }
  60% { transform: translate(-3px, 0); filter: hue-rotate(20deg) saturate(1.6); }
  100% { transform: translate(0, 0); filter: none; }
}

.terminal-defile {
  flex: 1;
  width: 100%;
  max-width: 100ch;
  margin: 0 auto;
  padding-top: 0.9em;
  overflow-y: auto;
  scrollbar-width: none;
}

.terminal-defile > * + * {
  margin-top: 0.9em;
}

.terminal-saisie,
.terminal-pied {
  width: 100%;
  max-width: 100ch;
  margin: 0 auto;
}

.terminal-saisie {
  padding: 0.35em 0.8em;
  margin-top: 1em;
  border-top: 1px solid #3b3b38;
  border-bottom: 1px solid #3b3b38;
}

.t-invite {
  margin-right: 0.6ch;
  color: var(--cc-gris);
}

.t-curseur {
  display: inline-block;
  width: 0.6em;
  height: 1.1em;
  vertical-align: -0.2em;
  background: var(--cc-texte);
  animation: t-clignote 1.06s steps(1) infinite;
}

@keyframes t-clignote {
  50% {
    opacity: 0;
  }
}

.terminal-pied {
  margin-top: 0.4em;
  margin-bottom: 0;
  padding-left: 0.8em;
}

.t-lien {
  padding: 0;
  border: 0;
  background: none;
  color: var(--cc-gris);
  font: inherit;
  cursor: pointer;
}

.t-lien:hover,
.t-lien:focus-visible {
  color: var(--cc-texte);
  outline: none;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* La boîte d'accueil de Claude Code : bord orange arrondi, son nom dans le bord, le petit personnage. */
.t-accueil {
  position: relative;
  padding: 1.4em 1.5em 1.1em;
  border: 1px solid var(--cc-orange);
  border-radius: 8px;
  text-align: center;
}

.t-accueil-titre {
  position: absolute;
  top: -0.8em;
  left: 1.2em;
  padding: 0 0.6ch;
  background: #121614;
  color: var(--cc-orange);
}

.t-accueil p {
  margin: 0.2em 0;
}

.t-bienvenue {
  font-weight: 700;
}

.t-claude {
  display: block;
  width: 5.5em;
  margin: 0.9em auto 0.8em;
  fill: var(--cc-orange);
  filter: drop-shadow(0 0 6px rgba(215, 119, 87, 0.45));
}

.t-claude .t-claude-yeux {
  fill: #0b0e0d;
}

.t-discret {
  margin: 0;
  color: var(--cc-gris);
}

.t-ligne {
  margin: 0;
  white-space: pre-wrap;
}

.t-commande {
  padding: 0.1em 0.6ch;
  background: rgba(255, 255, 255, 0.06);
  color: var(--cc-gris);
}

.t-reflexion {
  color: var(--cc-orange);
}

.t-etoile {
  display: inline-block;
  width: 1ch;
}

.t-reussite {
  color: var(--cc-vert);
}

.t-erreur {
  color: var(--cc-rouge);
}

/* Les questions à choix, comme dans Claude Code : la ligne visée en bleu pâle avec sa flèche. */
.t-menu {
  padding: 0.8em 1em;
  border: 1px solid #4a4a46;
  border-radius: 8px;
}

.t-menu.fait {
  opacity: 0.55;
}

.t-menu-titre {
  margin: 0 0 0.6em;
  font-weight: 700;
}

.t-options {
  margin: 0 0 0.7em;
  padding: 0;
  list-style: none;
}

.t-option {
  display: block;
  width: 100%;
  padding: 0.1em 0;
  border: 0;
  background: none;
  color: var(--cc-texte);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.t-option:focus-visible {
  outline: none;
}

.t-pointeur {
  visibility: hidden;
}

.t-option.actif {
  color: var(--cc-bleu);
}

.t-option.actif .t-pointeur {
  visibility: visible;
}

.t-note {
  color: var(--cc-vert);
}

/* Le lecteur de la vidéo du cours, à la manière de YouTube mais sans aucun logo : le titre en haut, le gros bouton
   de lecture au milieu, puis en bas la barre rouge et les commandes, qui s'effacent pendant la lecture quand la
   souris ne bouge plus. Agrandi, il remplit tout l'écran cathodique. */
.t-video {
  position: relative;
  container-type: inline-size;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 6px;
  background: #000;
  color: #fff;
  font-family: Roboto, 'DM Sans', Arial, sans-serif;
  font-size: clamp(12px, 0.5rem + 0.45vw, 16px);
  line-height: 1.2;
  text-shadow: none;
  overflow: hidden;
  user-select: none;
}

.t-video.agrandi {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: auto;
  aspect-ratio: auto;
  border-radius: 0;
}

.t-video video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  cursor: pointer;
}

.t-video[data-etat='lecture']:not(.reveille),
.t-video[data-etat='lecture']:not(.reveille) video {
  cursor: none;
}

.t-video-titre {
  position: absolute;
  inset: 0 0 auto;
  padding: 0.9em 1.1em 2.6em;
  background: linear-gradient(rgba(0, 0, 0, 0.6), transparent);
  font-size: 1.2em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
  transition: opacity 0.25s;
}

.t-lecture-grande {
  position: absolute;
  top: 50%;
  left: 50%;
  width: clamp(56px, 10cqi, 92px);
  padding: 0;
  border: 0;
  background: none;
  translate: -50% -50%;
  cursor: pointer;
}

.t-lecture-grande svg {
  display: block;
  width: 100%;
}

.t-lecture-fond {
  fill: rgba(18, 18, 18, 0.78);
  transition: fill 0.15s;
}

.t-lecture-grande:hover .t-lecture-fond,
.t-lecture-grande:focus-visible .t-lecture-fond {
  fill: rgba(0, 0, 0, 0.92);
}

.t-lecture-grande:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.8);
  outline-offset: 3px;
  border-radius: 12px;
}

.t-lecture-signe {
  fill: #fff;
}

.t-video:not([data-etat='debut']) .t-lecture-grande {
  display: none;
}

.t-video-bas {
  position: absolute;
  inset: auto 0 0;
  padding: 3em 0.8em 0;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
  transition: opacity 0.25s;
}

.t-video[data-etat='debut'] .t-video-bas {
  display: none;
}

.t-video[data-etat='lecture']:not(.reveille) .t-video-bas,
.t-video[data-etat='lecture']:not(.reveille) .t-video-titre {
  opacity: 0;
}

/* La barre de progression : le fond pâle, le chargé un peu moins pâle, le lu en rouge avec sa tête ronde, qui
   n'apparaît qu'au survol (la barre s'épaissit alors). */
.t-barre {
  position: relative;
  height: 15px;
  cursor: pointer;
}

.t-barre::before,
.t-barre-charge,
.t-barre-lu {
  position: absolute;
  top: 50%;
  left: 0;
  height: 3px;
  translate: 0 -50%;
  transition: height 0.1s;
}

.t-barre::before {
  content: '';
  right: 0;
  background: rgba(255, 255, 255, 0.22);
}

.t-barre-charge {
  width: var(--charge, 0%);
  background: rgba(255, 255, 255, 0.4);
}

.t-barre-lu {
  width: var(--lu, 0%);
  background: #f00;
}

.t-barre-tete {
  position: absolute;
  top: 50%;
  right: 0;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #f00;
  translate: 50% -50%;
  scale: 0;
  transition: scale 0.1s;
}

.t-barre:hover::before,
.t-barre:hover .t-barre-charge,
.t-barre:hover .t-barre-lu {
  height: 5px;
}

.t-barre:hover .t-barre-tete {
  scale: 1;
}

.t-commandes {
  display: flex;
  align-items: center;
  height: 3em;
}

.t-bouton {
  flex: none;
  width: 3em;
  height: 3em;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  opacity: 0.9;
  cursor: pointer;
}

.t-bouton:hover,
.t-bouton:focus-visible {
  opacity: 1;
}

.t-bouton:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.7);
  outline-offset: -4px;
  border-radius: 4px;
}

.t-bouton svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: currentColor;
}

.t-temps {
  margin-left: 0.5em;
  color: #eee;
  font-size: 0.95em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.t-agrandir {
  margin-left: auto;
}

/* Les icônes qui changent selon l'état : lire, pause ou revoir ; le son ou le son coupé ; agrandir ou réduire. */
.t-icone-pause,
.t-icone-revoir,
.t-icone-muet,
.t-icone-petit,
.t-video[data-etat='lecture'] .t-icone-lire,
.t-video[data-etat='fin'] .t-icone-lire,
.t-video.muet .t-icone-ondes,
.t-video.agrandi .t-icone-grand {
  display: none;
}

.t-video[data-etat='lecture'] .t-icone-pause,
.t-video[data-etat='fin'] .t-icone-revoir,
.t-video.muet .t-icone-muet,
.t-video.agrandi .t-icone-petit {
  display: inline;
}

@media (prefers-reduced-motion: reduce) {
  .terminal-ecran,
  .terminal.decroche .terminal-ecran,
  .t-curseur {
    animation: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fiche,
  .accueil-fiche,
  .quete-cours li {
    animation: none;
  }
}

/* L'éclair qui aveugle : la page devient presque blanche un instant. Son opacité est réglée image par image. */
.flash {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: #e4eaff;
  opacity: 0;
}

@keyframes grain {
  0% { transform: translate(0, 0); }
  17% { transform: translate(-23px, 11px); }
  33% { transform: translate(14px, -29px); }
  50% { transform: translate(-31px, -7px); }
  67% { transform: translate(27px, 19px); }
  83% { transform: translate(-9px, 33px); }
  100% { transform: translate(0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .grain {
    animation: none;
  }
}
