/* ==========================================================================
   Le récit : les chapitres qui défilent par-dessus le décor de l'enveloppe.

   Chaque chapitre occupe un écran entier et s'accroche au défilement. Les
   éléments animés (mots calligraphiés, filets) démarrent invisibles ICI, et
   non depuis JS : c'est ce qui évite qu'ils apparaissent une fraction de
   seconde avant que GSAP ne prenne la main. GSAP est ensuite seul à écrire
   dans leur opacité et leur transform — voir assets/invitation/js/story.js.
   ========================================================================== */

/* Tant que l'enveloppe est fermée, le récit n'existe pas du tout : ni dans la
   mise en page, ni sous le pointeur, ni dans l'ordre de tabulation.

   C'est volontairement plus radical que de le neutraliser calque par calque.
   Le conteneur couvre toute la hauteur du document, donc aussi le premier
   écran — celui du sceau, qui est DESSOUS. Il a suffi qu'un chapitre ne fasse
   pas exactement la hauteur de l'écran pour que son voile clair déborde sur le
   bas de la scène et avale le clic d'ouverture. Un `display: none` ne laisse
   pas cette marge d'erreur. */
.recit { display: none; }

html.recit-ouvert .recit {
  display: block;
  position: relative;
  z-index: 5;          /* au-dessus de .scene, qui reste en fond fixe */

  /* Les zones vides du conteneur ne captent rien ; chaque chapitre qui a
     besoin du pointeur le reprend pour lui. */
  pointer-events: none;
}

/* Un chapitre n'est pas ce qu'on voit : c'est la COURSE qu'on parcourt
   pendant qu'on le voit. Un bloc vide, qui n'a rien à montrer et ne sert
   qu'à donner de la distance à parcourir.

   C'est ce qui rend le récit lent sans jamais toucher au geste du lecteur :
   la molette répond exactement comme d'habitude, mais il faut deux à trois
   écrans de défilement pour passer une étape, au lieu d'un seul coup.

   La traversée de cette course EST l'écriture du chapitre : le texte s'écrit
   sur la première partie, se tient, puis s'efface avant la fin — voir
   assets/invitation/js/story.js. D'où la hauteur, qui n'est pas un choix de
   mise en page : le JS la pose ici même, en style en ligne, à la mesure de la
   timeline du chapitre. `--chapitre-course` n'est que le repli.

   Rien n'y est cliquable — ces blocs couvrent tout le document, leur laisser
   le pointeur reviendrait à masquer la scène qui est dessous. */
.chapitre {
  position: relative;
  min-height: var(--chapitre-course);
  pointer-events: none;
}

/* Ce qui est réellement à l'écran, et qui n'en bouge JAMAIS.

   `fixed`, et non `sticky` : le texte est posé au centre de l'écran et y
   reste. Le défilement ne le fait pas glisser, il décide seulement quel
   chapitre est montré — les vues se relaient par un fondu piloté depuis
   assets/invitation/js/story.js. Avec `sticky`, le texte restait certes
   épinglé pendant sa course, mais glissait à chaque changement de chapitre :
   c'est exactement ce mouvement dont on ne veut pas.

   Conséquence : toutes les vues sont superposées en permanence. D'où l'état
   de départ ci-dessous — invisible et hors du pointeur — que seul le chapitre
   actif lève. `visibility` plutôt que `display`, pour que la mise en page
   subsiste et que le canevas du grattage garde ses dimensions. */
.chapitre-vue {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;

  /* Deux déclarations, pas une : `svh` est là pour que le texte tienne à
     l'écran barre d'URL déployée, et `vh` est le repli si l'unité n'est pas
     comprise — sans lui, la déclaration entière tombe et la vue s'effondre à
     la hauteur de son contenu. */
  height: 100vh;
  height: 100svh;

  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3vh;

  padding: 10vh 8vw;
  text-align: center;

  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* La couverture est vide : elle réserve le premier écran au décor de
   l'enveloppe, pour qu'on la voie ouverte avant que le texte ne monte. Pas de
   course à parcourir, donc, et pas de vue épinglée.

   Elle seule est en `lvh` — la PLUS GRANDE hauteur d'écran possible. En `svh`
   (la plus petite), le premier texte s'allumerait dès que la barre d'URL se
   rétracte, avant qu'on ait vu l'enveloppe ouverte. */
.chapitre--couverture {
  min-height: 100vh;
  min-height: 100lvh;
  pointer-events: none;
}

/* Le dernier chapitre n'a pas de course : c'est la fin du document, il n'y a
   rien après quoi défiler. Un écran suffit à faire croiser la bande centrale
   à sa course quand on arrive en bas. Le lecteur y arrive, gratte, et reste. */
.chapitre--final {
  min-height: 100vh;
  min-height: 100svh;
}

/* Voile de papier derrière le texte : la dentelle et le pli de l'enveloppe
   restent visibles en fond, mais assez estompés pour ne pas gêner la
   lecture. Il se fond sur les bords plutôt que de dessiner une boîte. */
.chapitre-vue::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(70% 55% at 50% 50%,
    var(--chapitre-voile) 0%,
    var(--chapitre-voile) 55%,
    transparent 100%);
  pointer-events: none;
}

/* ---- Texte calligraphié ------------------------------------------------ */
.calligraphie {
  max-width: var(--chapitre-largeur);
  color: var(--encre);
  font-family: var(--calligraphie);
  font-size: var(--calligraphie-taille);
  font-weight: 400;
  line-height: var(--calligraphie-interligne);
  text-wrap: balance;
}

/* Un mot = deux span imbriqués, découpés par
   assets/invitation/js/story.js. `inline-block` est indispensable sur les
   deux : GSAP anime `transform`, qui n'a aucun effet sur une boîte inline.

   `.mot` tient la place et reste immobile ; `.mot-encre` est ce que GSAP
   anime. Cette séparation n'est pas décorative : GSAP retire et réinsère sa
   cible pour la mesurer, et le mot revenait alors de l'autre côté du blanc
   qui le suivait — les deux derniers mots finissaient collés. Le blanc entre
   deux `.mot` est un vrai nœud texte, et doit le rester pour que la ligne se
   coupe normalement.

   Pas de `will-change` ici : un chapitre compte une trentaine de mots, et
   autant de calques promus en permanence coûterait plus qu'ils ne
   rapportent. GSAP le pose lui-même le temps du tween. */
.calligraphie .mot {
  display: inline-block;
}

.calligraphie .mot-encre {
  display: inline-block;
  opacity: 0;
}

/* ---- Filets d'encadrement ---------------------------------------------- */
.filet {
  width: min(46vw, 220px);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--or), transparent);
  opacity: 0;
  transform: scaleX(0);   /* GSAP le déroule depuis le centre */
}

/* ---- Invitation à faire défiler ----------------------------------------
   Fixe en bas d'écran : elle accompagne le lecteur sur les premiers
   chapitres et s'efface une fois le dernier atteint. */
/* Centré par `left/right: 0` et non par un `translateX(-50%)` : GSAP écrit
   dans l'opacité de cet élément, et lui laisser aussi le transform évite
   d'avoir deux autorités sur la même propriété. */
.defilement {
  position: fixed;
  bottom: 62px;
  left: 0;
  right: 0;
  z-index: 15;

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;

  color: var(--encre);
  pointer-events: none;
  opacity: 0;          /* GSAP l'amène quand l'enveloppe finit de s'ouvrir */
}

/* Le même voile que derrière les chapitres, en plus petit.

   Il n'existe que depuis qu'il y a un FOND PHOTOGRAPHIQUE : au repos, la
   photo est encore nette, et l'accroche tombait sur ce qu'elle voulait — une
   robe blanche, un smoking, un banc sombre. L'encre bordeaux disparaissait
   sur la moitié des photos.

   Un voile d'ivoire résout les deux cas d'un coup, et c'est pour cela qu'il
   est préféré à un halo porté par le texte : sur une photo sombre il donne au
   texte un fond clair, et quand le fond s'éclaircit il devient de l'ivoire sur
   de l'ivoire, donc invisible. Il n'y a rien à basculer. */
.defilement::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 320px;
  height: 210px;
  transform: translate(-50%, -50%);
  z-index: -1;   /* derrière le texte, mais dans le contexte de .defilement */

  background: radial-gradient(50% 50% at 50% 50%,
    var(--chapitre-voile) 0%,
    transparent 70%);
  pointer-events: none;
}

.defilement-mot {
  font-size: 10px;
  letter-spacing: .34em;
  text-transform: uppercase;
}

.defilement-trait {
  display: block;
  width: 1px;
  height: 42px;
  background: linear-gradient(180deg, var(--or), transparent);
  transform-origin: top center;
}
