/* Effets d'animation partagés par plusieurs sections (reveal.js, pointer.js) : titres découpés, libellés décodés,
   blocs qui montent, filets tracés, libellés qui roulent au survol. Les états propres à une section sont à la fin
   de sa feuille. Rien n'est masqué sans la classe .has-motion (posée dans le <head>, jamais en mouvement réduit) ;
   si les scripts ne démarrent pas (.motion-ready absente), tout réapparaît au bout de 2,5 s. Les déplacements
   passent par translate / scale / rotate, qui s'ajoutent aux transform déjà posés par les sections. */

/* ---------- Titres découpés : chaque ligne, ou chaque lettre, monte derrière un masque ---------- */
.split-visual,
.split-line {
  display: block;
}
/* Le masque ne coupe que le haut et le bas : un titre qui déborde volontairement à droite reste entier.
   Un peu de marge pour les accents des capitales (É, À) au-dessus de l'interligne serré. */
.split-line {
  overflow-y: clip;
  padding-block: 0.16em 0.06em;
  margin-block: -0.16em -0.06em;
}
.split-inner,
.split-char {
  display: inline-block;
}
.has-motion .is-split .split-inner {
  translate: 0 118%;
  rotate: 5deg;
  transform-origin: 0 100%;
  transition:
    translate 1.3s var(--ease-expo) calc(var(--line, 0) * 0.1s + var(--delay, 0s)),
    rotate 1.3s var(--ease-expo) calc(var(--line, 0) * 0.1s + var(--delay, 0s));
}
.has-motion .is-split .split-char {
  translate: 0 112%;
  transition: translate 1.15s var(--ease-expo) calc(var(--c, 0) * 0.038s + var(--delay, 0s));
}
/* En lettres, ce sont les lettres qui bougent, pas la ligne. */
.has-motion .split-visual .split-inner {
  translate: none;
  rotate: none;
}
.has-motion .is-split.is-in .split-inner,
.has-motion .is-split.is-in .split-char,
.has-motion.is-loaded .hero-title .split-inner,
.has-motion.is-loaded .hero-name .split-char {
  translate: 0 0;
  rotate: 0deg;
}

/* ---------- Libellés décodés (glyphes aléatoires puis le texte) ---------- */
.has-motion .decode:not(.is-in) {
  opacity: 0;
}

/* ---------- Blocs : montent en entrant à l'écran, en décalé quand ils sont voisins ---------- */
.has-motion [data-reveal]:not(.is-in) {
  opacity: 0;
  translate: 0 48px;
}
.has-motion [data-reveal]:not(.is-done) {
  transition:
    opacity 0.9s var(--ease-out) calc(var(--i, 0) * 90ms),
    translate 1.3s var(--ease-expo) calc(var(--i, 0) * 90ms),
    scale 1.3s var(--ease-expo) calc(var(--i, 0) * 90ms);
}

/* ---------- Méthode et contact : les filets se tracent de gauche à droite ---------- */
.has-motion .step,
.has-motion .contact-card {
  position: relative;
  border-top-color: transparent;
}
.has-motion .step::before,
.has-motion .contact-card::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 1.4s var(--ease-expo) calc(var(--i, 0) * 90ms + 0.2s);
}
.has-motion .step.is-in::before,
.has-motion .contact-card.is-in::before {
  transform: none;
}

/* ---------- Libellés qui roulent au survol (pointer.js) ---------- */
.roll {
  position: relative;
  display: inline-flex;
  overflow: hidden;
  vertical-align: top;
}
.roll-a,
.roll-b {
  display: inline-flex;
}
.roll-b {
  position: absolute;
  top: 0;
  left: 0;
}
.roll-char {
  display: inline-block;
  transition: translate 0.6s var(--ease-expo) calc(var(--c, 0) * 14ms);
}
.roll-b .roll-char {
  translate: 0 110%;
}
:is(a, button):is(:hover, :focus-visible) .roll-a .roll-char {
  translate: 0 -110%;
}
:is(a, button):is(:hover, :focus-visible) .roll-b .roll-char {
  translate: 0 0;
}

/* Filet de sécurité si les scripts ne démarrent jamais. */
.has-motion:not(.motion-ready) [data-intro] > *,
.has-motion:not(.motion-ready) [data-reveal],
.has-motion:not(.motion-ready) :is(.nav, .bottom-bar) > *,
.has-motion:not(.motion-ready) :is(.corner, .ghost-btn, .hero-tags li, .hero-arrow, .stack-item, .round-links a) {
  animation: motion-failsafe 0.4s ease 2.5s forwards;
}
.has-motion:not(.motion-ready) .hero-figure {
  animation: motion-failsafe-clip 0.6s ease 2.5s forwards;
}
@keyframes motion-failsafe {
  to {
    opacity: 1;
    translate: 0 0;
    scale: 1;
    rotate: 0deg;
  }
}
@keyframes motion-failsafe-clip {
  to {
    clip-path: inset(0 0 0 0);
  }
}
