/* ── Primitives de mise en page — portées d'Oryzo ───────────────────────────
   Relevées dans sa CSS et dans l'inspecteur sur le site en ligne. Le relevé
   complet est dans reference/oryzo/ANALYSE.md.

   Convention à retenir : les classes typographiques portent EXACTEMENT le nom
   de leur variable. Un élément en `--body1` s'écrit `class="body1"`. Pas de nom
   sémantique intermédiaire — c'est ce qui permet de lire une maquette et
   d'écrire le HTML sans table de correspondance.
   ───────────────────────────────────────────────────────────────────────── */

/* ── Conteneur et grille ─────────────────────────────────────────────────── */

.o-container {
  width: 100%;
  padding: 0 var(--site-padding-x);
}

/* La grille 16 colonnes. La gouttière vaut 24/90 de la colonne : c'est
   `--grid-gap-scale` qui tient ce rapport, tout le reste en découle. */
.o-grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: 0 var(--grid-gap-width);
}

/* Placement : `.o-col-4-8` = commence colonne 4, occupe 8 colonnes. On écrit le
   placement dans le HTML plutôt qu'une règle CSS par bloc — la grille est
   assez régulière pour que ça reste lisible. */
[class*='o-col-'] { grid-column: span var(--grid-columns); }
.o-col-1 { grid-column: span 1; }
.o-col-2 { grid-column: span 2; }
.o-col-3 { grid-column: span 3; }
.o-col-4 { grid-column: span 4; }
.o-col-5 { grid-column: span 5; }
.o-col-6 { grid-column: span 6; }
.o-col-7 { grid-column: span 7; }
.o-col-8 { grid-column: span 8; }
.o-col-9 { grid-column: span 9; }
.o-col-10 { grid-column: span 10; }
.o-col-11 { grid-column: span 11; }
.o-col-12 { grid-column: span 12; }
.o-col-14 { grid-column: span 14; }
.o-col-16 { grid-column: span 16; }

.o-start-2 { grid-column-start: 2; }
.o-start-3 { grid-column-start: 3; }
.o-start-4 { grid-column-start: 4; }
.o-start-5 { grid-column-start: 5; }
.o-start-6 { grid-column-start: 6; }
.o-start-9 { grid-column-start: 9; }
.o-start-10 { grid-column-start: 10; }
.o-start-11 { grid-column-start: 11; }

/* Filet horizontal — le séparateur d'Oryzo.
   Ce n'est pas un trait plein : c'est un pointillé fabriqué au dégradé, deux
   pixels pleins puis deux vides. Relevé tel quel dans leur CSS. Le filet vit
   partout sur le site — sous les titres de features, dans la carte du hero,
   sous la navigation — et c'est lui qui donne l'air « fiche technique ». */
.o-dashline {
  --dashline-color: var(--color-white);
  height: 1px;
  width: 100%;
  background: repeating-linear-gradient(
    90deg,
    var(--dashline-color) 0 2px,
    var(--color-white-transparent) 0 4px
  );
}

/* Il se dessine de gauche à droite quand la section prend la main. */
.o-dashline[data-draw] {
  transform-origin: 0 50%;
  transform: scaleX(var(--active-ratio, 1));
}

/* ── Sections ────────────────────────────────────────────────────────────
   Une `.section` est une étape du parcours. Elle porte `--active-ratio`,
   écrite par le JS entre 0 et 1 selon sa position — lisible depuis la CSS,
   donc animable sans une ligne de JS par élément.

   `[data-pin]` épingle le contenu plein écran : la section ne défile plus, sa
   hauteur ne sert qu'à fabriquer de la longueur de scroll. C'est le motif
   central d'Oryzo, et il est opt-in section par section, comme chez eux.
   ───────────────────────────────────────────────────────────────────────── */

.o-section {
  position: relative;
  width: 100%;
  z-index: var(--z-content);
  --active-ratio: 0;
}

.o-section__inner {
  position: relative;
  width: 100%;
}

/* Le cœur du dispositif. Le contenu est **fixe et plein écran**, donc la
   section ne prend aucune hauteur dans le flux : les douze sections sont
   empilées au même endroit et c'est la hauteur du `body`, posée en pixels par
   le JS, qui fabrique toute la longueur de scroll.

   Le scroll ne déplace donc rien — il fait avancer un curseur. `visibility`
   (et non `display`) décide laquelle des piles se voit ; la mise en page des
   autres reste calculée, donc revenir en arrière ne coûte pas un relayout. */
.o-section[data-pin] .o-section__inner {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: calc(var(--vh) * 100);
  padding-top: var(--site-padding-y);
  padding-bottom: var(--site-padding-y);
}

/* ── Typographie ─────────────────────────────────────────────────────────── */

.h1, .h2, .h3, .h4, .h5 {
  font-family: var(--display-font);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.02em;
  margin: 0;
}
.h1 { font-size: var(--h1); letter-spacing: -0.035em; }
.h2 { font-size: var(--h2); letter-spacing: -0.025em; }
.h3 { font-size: var(--h3); }
.h4 { font-size: var(--h4); line-height: 1.12; }
.h5 { font-size: var(--h5); line-height: 1.2; }

.body1 { font-size: var(--body1); line-height: 1.24; letter-spacing: -0.015em; }
.body2 { font-size: var(--body2); line-height: 1.34; }
.body3 { font-size: var(--body3); line-height: 1.5; }

/* Les `sub` sont les surtitres en petites capitales espacées — c'est la voix
   « étiquette » du site, jamais du texte courant. */
.sub1, .sub2 {
  font-family: var(--mono-font);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1.3;
}
.sub1 { font-size: var(--sub1); }
.sub2 { font-size: var(--sub2); }

.quote {
  font-size: var(--quote);
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.link-header {
  font-family: var(--mono-font);
  font-size: var(--link-header);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.o-btn {
  font-family: var(--mono-font);
  font-size: var(--btn);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ── Découpe de texte ────────────────────────────────────────────────────
   Deux niveaux imbriqués par fragment : l'extérieur porte `overflow: clip`
   et fait masque, l'intérieur coulisse dedans. Le JS pose les masques une
   fois (src/core/split.js) ; ensuite **plus rien ne tourne par frame**.

   La position se calcule en CSS à partir de `--active-ratio`, écrit sur la
   section par le moteur de scène. Chaque ligne connaît son rang (`--i`) et
   part donc un peu après la précédente. C'est ce qui permet à Oryzo d'animer
   des centaines de lignes au scroll sans une seule boucle JS par élément.

   Les amplitudes sont en `em`, jamais en pixels : elles suivent la taille du
   texte, et la même animation reste juste du portable au 4K.
   ───────────────────────────────────────────────────────────────────────── */

.o-split { display: block; }

.o-split__mask {
  position: relative;
  display: block;
  text-align: start;
  overflow: clip;

  /* Avancement de CETTE ligne : la progression de la section, décalée du rang
     de la ligne, puis étalée sur une fenêtre. Tout est sans unité, donc
     `clamp()` borne proprement entre 0 et 1. */
  --reveal: clamp(
    0,
    (var(--active-ratio, 1) - var(--i, 0) * var(--split-stagger, 0.055)) /
      var(--split-window, 0.34),
    1
  );
  opacity: var(--reveal);
}

.o-split__inner {
  position: relative;
  display: block;
  text-align: start;
  /* 1.05em : un poil plus que la hauteur de ligne, pour que le texte parte
     franchement hors du masque et non collé à son bord. */
  transform: translate3d(0, calc(1.05em * (1 - var(--reveal))), 0);
  will-change: transform;
}

/* Sans JS de scène (fallback, `noscript`), la découpe reste posée mais rien
   ne l'anime : on la neutralise plutôt que de laisser le texte hors champ. */
html:not([data-stage='on']) .o-split__mask { opacity: 1; }
html:not([data-stage='on']) .o-split__inner { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .o-split__mask { opacity: 1; }
  .o-split__inner { transform: none; }
}

/* ── Une seule rupture, comme Oryzo ──────────────────────────────────────── */

.desktop-only { display: revert; }
.mobile-only { display: none; }

@media (max-width: 767.98px) {
  .desktop-only { display: none; }
  .mobile-only { display: revert; }

  /* En dessous de 768, la grille 16 colonnes n'a plus de sens : les colonnes
     tomberaient sous 15 px. Oryzo repasse en pile. */
  .o-grid { grid-template-columns: repeat(4, 1fr); }
  [class*='o-col-'] { grid-column: span 4; }
  [class*='o-start-'] { grid-column-start: auto; }
}
