/* AMALAB - motion-beats.css (V20)
   Second motion layer on top of css/motion.css: section-specific
   choreography ("beats") + small site-wide signatures. Same grammar:
   one easing (var(--ease-out)), opacity/transform only, one-shot,
   html.js gating everywhere, reduced motion resolves instantly
   (block at end). Driven by the same .reveal / data-reveal-* observers
   in js/site.js; js/motion-beats.js adds FAQ, header, progress only. */

/* ---------- 1 - Title-dot punch: the terminal dot lands after its title ----------
   site.js injects .title-dot into h1/h2 ending with ".". Scoped to normal
   section heads + heroes; the pinned systems (benefits, scaled, problème)
   author their own dots outside .section-head and are never matched. */
html.js main .section-head.reveal h2 .title-dot {
  display: inline-block;
  opacity: 0;
  transform: scale(0.5);
  transform-origin: bottom left;
  transition: opacity 240ms var(--ease-out), transform 240ms var(--ease-out);
  transition-delay: 300ms;
}
html.js main .section-head.reveal.is-visible h2 .title-dot {
  opacity: 1;
  transform: none;
}
html.js .page-hero h1 .title-dot,
html.js .hero-copy h1 .title-dot {
  display: inline-block;
  transform-origin: bottom left;
  animation: amal-dot-in 240ms var(--ease-out) 500ms both;
}
@keyframes amal-dot-in {
  from { opacity: 0; transform: scale(0.5); }
  to { opacity: 1; transform: none; }
}

/* ---------- 2 - Header hairline once the page scrolls ----------
   .is-scrolled is toggled by js/motion-beats.js via a sentinel observer.
   Pure affordance: harmless without JS (class never appears). */
.site-header::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 1px;
  background: var(--border);
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
  pointer-events: none;
}
.site-header.is-scrolled::after { opacity: 1; }

/* ---------- 3 - Reading progress (insights articles) ----------
   2px teal bar above the sticky header (z-index 100). scaleX is set
   directly by js/motion-beats.js, no transition (it tracks the scroll). */
.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--teal);
  transform: scaleX(0);
  transform-origin: left center;
  z-index: 120;
  pointer-events: none;
}

/* ---------- 4 - Optional cascade for sibling .reveal blocks ----------
   js/motion-beats.js sets --ri on the .reveal children of a few wrappers
   (.scaled-loop-wrap) so they arrive as a sequence. Everything without
   --ri resolves to 0ms: strictly no change for existing reveals. */
html.js .reveal { transition-delay: calc(var(--ri, 0) * 90ms); }

/* ---------- 5 - Partner panel: the handoff beat ----------
   « Une équipe en renfort … vous passe les clés. » The 07-step list is
   the message: each line draws its own hairline as it lands, and each
   index number turns orange only once its step has arrived - the keys
   being handed over, one by one. The arrival itself now belongs to the
   pinned journey engine (js/panel-steps.js): li.is-in marks an arrived
   step, so the hairline draw + idx ignition key to that class — same
   beat, engine-owned cadence, fully reversible on a backward scrub.
   Scoped to this navy panel only. */
[aria-labelledby="partner-panel-title"] .rule-list > li {
  position: relative;
  border-bottom-color: transparent;
}
[aria-labelledby="partner-panel-title"] .rule-list > li::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--inv-border);
}
html.js [aria-labelledby="partner-panel-title"] .steps-list > li::after {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 520ms var(--ease-out) 90ms;
}
html.js [aria-labelledby="partner-panel-title"] .steps-list > li.is-in::after {
  transform: scaleX(1);
}
[aria-labelledby="partner-panel-title"] .steps-list .idx {
  transition: color 420ms var(--ease-out) 200ms;
}
html.js [aria-labelledby="partner-panel-title"] .steps-list > li:not(.is-in) .idx {
  color: var(--inv-fg-muted);
}

/* ---------- 6 - Split converge: « avancent ensemble » ----------
   The two columns of a .split arrive at the same moment from opposite
   sides and settle together (index, diagnostic, formation, gouvernance). */
html.js .split[data-reveal-stagger] > * {
  transform: translateX(-14px);
  transition-duration: 640ms;
  transition-delay: 0ms;
}
html.js .split[data-reveal-stagger] > :last-child {
  transform: translateX(14px);
}
html.js .split[data-reveal-stagger].is-visible > * { transform: none; }

/* ---------- 7 - num-item: the number arrives first ----------
   Two tiers inside each staggered num-item: the index number rises
   slightly ahead of its own heading and copy. Site-wide num grids.
   The item itself is neutralized here (opacity/transform only - its
   transition-delay is left alone, so motion.css's num-item::before
   hairline draw still inherits it) so only the two tiers below show
   motion, instead of a third, larger container-level fade underneath. */
html.js [data-reveal-stagger] > .num-item {
  opacity: 1;
  transform: none;
}
html.js [data-reveal-stagger] > .num-item > .num {
  display: inline-block;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 480ms var(--ease-out), transform 480ms var(--ease-out);
  transition-delay: min(calc(var(--ri, 0) * 70ms), 560ms);
}
html.js [data-reveal-stagger] > .num-item > :not(.num) {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 480ms var(--ease-out), transform 480ms var(--ease-out);
  transition-delay: calc(min(calc(var(--ri, 0) * 70ms), 560ms) + 120ms);
}
html.js [data-reveal-stagger].is-visible > .num-item > .num,
html.js [data-reveal-stagger].is-visible > .num-item > :not(.num) {
  opacity: 1;
  transform: none;
}

/* ---------- 8 - Résultats: moved out ----------
   « Si ça marche, ça doit se voir dans vos chiffres. » The home #resultats
   section was reskinned from static .metric rows into six animated KPI
   bento tiles (Sierra pattern). Its reveal choreography now lives in
   css/results-tiles.css (reveal-driven SVG draw, gated on the same
   [data-reveal-stagger] .is-visible + --ri contract). Nothing here. */

/* ---------- 9 - Cas d'usage: alternate arrivals ----------
   The nine .phase blocks slide in from alternating sides (subtle,
   ±12px). .phase only exists on cas-usage.html. */
html.js .phase.reveal { transform: translate(-12px, 8px); }
html.js .phase.reveal:nth-of-type(even) { transform: translate(12px, 8px); }
html.js .phase.reveal.is-visible { transform: none; }

/* ---------- 10 - Fondateurs: two profiles converge ----------
   « Deux fondateurs, deux métiers qui se complètent. » Same converge
   figure as the split (a-propos only, via .founders-grid). */
html.js .founders-grid[data-reveal-stagger] > * {
  transform: translateX(-14px);
  transition-duration: 640ms;
  transition-delay: 0ms;
}
html.js .founders-grid[data-reveal-stagger] > :last-child {
  transform: translateX(14px);
}
html.js .founders-grid[data-reveal-stagger].is-visible > * { transform: none; }

/* ---------- Mobile: stacked layouts move vertically ----------
   Below the stacking breakpoint (.split/.phase collapse at 767px),
   side-to-side converge/alternate reads as noise on a one-column
   layout and horizontal offsets have no room; the beats fall back
   to the house rise. Delays/durations from the desktop rules keep
   applying (split children still arrive together). */
@media (max-width: 767px) {
  html.js .split[data-reveal-stagger] > *,
  html.js .split[data-reveal-stagger] > :last-child,
  html.js .founders-grid[data-reveal-stagger] > *,
  html.js .founders-grid[data-reveal-stagger] > :last-child {
    transform: translateY(12px);
  }
  html.js .split[data-reveal-stagger].is-visible > *,
  html.js .founders-grid[data-reveal-stagger].is-visible > * {
    transform: none;
  }
  html.js .phase.reveal,
  html.js .phase.reveal:nth-of-type(even) {
    transform: translateY(10px);
  }
  html.js .phase.reveal.is-visible { transform: none; }
}

/* ---------- Reduced motion: every state above resolves instantly ---------- */
@media (prefers-reduced-motion: reduce) {
  html.js main .section-head.reveal h2 .title-dot,
  html.js .page-hero h1 .title-dot,
  html.js .hero-copy h1 .title-dot,
  html.js .split[data-reveal-stagger] > *,
  html.js .founders-grid[data-reveal-stagger] > *,
  html.js .phase.reveal,
  html.js [data-reveal-stagger] > .num-item > .num,
  html.js [data-reveal-stagger] > .num-item > :not(.num) {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
  html.js [aria-labelledby="partner-panel-title"] .steps-list > li::after {
    transform: none !important;
    transition: none !important;
  }
  html.js [aria-labelledby="partner-panel-title"] .steps-list > li:not(.is-in) .idx {
    color: var(--orange) !important;
  }
  [aria-labelledby="partner-panel-title"] .steps-list .idx { transition: none !important; }
  html.js .scaled-loop-wrap > .reveal { transition-delay: 0ms !important; }
  .reading-progress { display: none; }
}
