/* ═══════════════════════════════════════════════════════════════════════════
   animations.css — keyframes et classes de révélation.

   Une seule règle, tenue partout dans le projet : on n'anime que `transform`,
   `translate`, `opacity` et `clip-path`. Les cas qui semblent y échapper — le
   filet de titre, la barre de progression de lecture, le filet d'une carte,
   la bande d'un panneau — se font en `scaleX()` avec un `transform-origin`,
   jamais en `width`.

   **Pourquoi `translate` et non `transform` pour la révélation.** Une carte
   doit pouvoir se soulever au survol *alors qu'elle vient d'apparaître*. Si
   les deux gestes écrivaient dans `transform`, le dernier déclaré gagnerait,
   et comme cette feuille est chargée après components.css, c'est la
   révélation qui annulerait le survol. `translate` et `transform` sont deux
   propriétés distinctes qui se composent : la révélation prend l'une, le
   survol garde l'autre, et aucune des deux ne connaît l'existence de l'autre.
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes line-up {
  from { transform: translateY(105%); }
  to   { transform: translateY(0); }
}

@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@keyframes pulse-soft {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.35); opacity: .55; }
}

/* L'indice de défilement du hero : un segment qui descend le long d'un filet. */
@keyframes scroll-hint {
  0%        { transform: translateY(-120%); opacity: 0; }
  30%, 70%  { opacity: 1; }
  100%      { transform: translateY(340%);  opacity: 0; }
}

/* La découpe : un bloc se dévoile de bord à bord, comme une lame qui passe.
   `inset()` est bien interpolable ; `clip-path: none` ne l'est pas — d'où
   l'état final écrit `inset(0)` et non `none`. */
@keyframes cut-in-x {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0); }
}
@keyframes cut-in-y {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0); }
}
@keyframes plate-in {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* ── Ouverture du hero ──────────────────────────────────────────────────────
   Tout est en `animation-delay`, aucun `setTimeout` : la chronologie tient
   dans la feuille de style, et elle se lit d'un bloc. Total : 1,7 s. */

.hero__kicker {
  clip-path: inset(0 100% 0 0);
  animation: cut-in-x 520ms var(--ease) 0ms forwards;
}
[dir="rtl"] .hero__kicker { clip-path: inset(0 0 0 100%); }

.hero__title .cut {
  animation: plate-in 460ms var(--ease) 560ms both;
  transform-origin: left;
}

.hero__figure {
  clip-path: inset(100% 0 0 0);
  animation: cut-in-y 700ms var(--ease) 680ms forwards;
}

.hero__proof > div {
  clip-path: inset(0 0 100% 0);
  animation: cut-in-y 560ms var(--ease) both;
}
.hero__proof > div:nth-child(1) { animation-delay: 900ms; }
.hero__proof > div:nth-child(2) { animation-delay: 980ms; }
.hero__proof > div:nth-child(3) { animation-delay: 1060ms; }
.hero__proof > div:nth-child(4) { animation-delay: 1140ms; }

.hero__scroll { opacity: 0; animation: fade-in 400ms var(--ease) 1300ms forwards; }
@keyframes fade-in { to { opacity: 1; } }

/* ── Révélation au défilement ───────────────────────────────────────────────
   Posée par reveal.js à 15 % de visibilité, puis `unobserve` : une révélation
   ne se rejoue jamais. Le décalage est plafonné à six rangs — au-delà, on
   n'attend plus une animation, on attend tout court. */
[data-reveal] {
  opacity: 0;
  translate: 0 24px;
  transition: opacity var(--dur) var(--ease), translate var(--dur) var(--ease);
  transition-delay: calc(min(var(--i, 0), 6) * 60ms);
}
[data-reveal].is-visible { opacity: 1; translate: none; }

/* ── Moins de mouvement ────────────────────────────────────────────────────
   Obligatoire, pas optionnel. Tout tombe à 0,01 ms, rien ne boucle, et tout
   ce qui est découpé est rendu à son état final. Le contenu, lui, n'est
   jamais retiré : une vidéo reste jouable, un aperçu ne démarre simplement
   plus tout seul. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  html { scroll-behavior: auto; }

  [data-reveal] { opacity: 1; translate: none; }

  .hero__title .line > span { transform: none; animation: none; }
  .hero__kicker,
  .hero__figure,
  .hero__proof > div { clip-path: inset(0); animation: none; }
  .hero__title .cut { transform: rotate(calc(-1.2deg * var(--dir))); animation: none; }
  .hero__scroll { opacity: 1; animation: none; }
  .hero__scroll i::after { animation: none; transform: translateY(100%); }
  .hero__kicker .dot,
  .tag--wip::before { animation: none; }

  .rule { transform: scaleX(1); }
  .card__edge,
  .panel__edge { transform: scaleX(1); }
  .marquee__track { animation: none; }

  /* Le soulèvement disparaît : seule la bordure change. Un survol qui déplace
     un bloc sous le curseur est exactement ce que cette préférence demande
     d'éviter. */
  .card:hover,
  .deliv:hover,
  .media-tile:hover,
  .reel:hover .reel__open { transform: none; }
  .card:hover .card__thumb,
  .reel:hover .reel__poster { transform: none; }
  .btn:hover { transform: none; }
}
