/* ===========================================================================
   ANIMATIC — the motion layer.

   The discipline: CUT between scenes, EASE within them, and always HOLD a beat
   at the key pose. That single deliberate deviation from smoothness — a two-
   or three-frame freeze — is the entire difference between "animatic" and
   "corporate web with a scroll library bolted on".

   Everything here degrades to a 120ms cross-fade under prefers-reduced-motion,
   and the identity survives: the chapter card still appears, it simply does
   not perform.
   ========================================================================= */

/* --- Reveal primitives --------------------------------------------------- */
[data-reveal] { will-change: transform, opacity; }
[data-stagger] > * { will-change: transform, opacity; }

/* --- The chapter-card transition ----------------------------------------
   Timeline, ~1200ms:
     0–160    outbound content lifts 8px and fades          ease-settle
     160–420  colour plane wipes across on the diagonal     ease-paper
     420–480  STUTTER HOLD — nothing moves at all
     480–620  chapter number stamps in from below           ease-gate
     620–900  gerund sets letter by letter, 40ms stagger    ease-gate
     900–960  STUTTER HOLD
     960–1100 beast letterforms resolve out of the silhouette
     1100–1200 plane lifts, inbound content assembles behind it
   The two holds are non-negotiable. Remove them and it is an ordinary page
   transition.                                                              */
.chapter-card[data-animatic] .chapter-card__rule  { animation: cc-rule  240ms var(--ease-paper) 160ms both; }
.chapter-card[data-animatic] .chapter-card__num   { animation: cc-stamp 140ms var(--ease-gate) 480ms both; }
.chapter-card[data-animatic] .chapter-card__name  { animation: cc-name  280ms var(--ease-gate) 620ms both; }
.chapter-card[data-animatic] .chapter-card__beast { animation: cc-beast 140ms var(--ease-paper) 960ms both; }

@keyframes cc-rule  { from { transform: scaleX(0); opacity: 0; } to { transform: scaleX(1); opacity: .45; } }
@keyframes cc-stamp { from { transform: translateY(18px) scale(.94); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes cc-name  { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes cc-beast { from { transform: scale(.9); opacity: 0; } to { transform: none; opacity: .3; } }

/* Per-letter set for the gerund, driven by --i from JS. */
.split-char { display: inline-block; will-change: transform, opacity; }
[data-animatic] .split-char {
  animation: char-set 260ms var(--ease-gate) both;
  animation-delay: calc(620ms + var(--i, 0) * 40ms);
}
@keyframes char-set { from { transform: translateY(.5em) rotate(2deg); opacity: 0; } to { transform: none; opacity: 1; } }

/* --- Page-level transition plane ---------------------------------------- */
.wipe {
  position: fixed; inset: 0; z-index: var(--z-modal);
  background: var(--accent);
  transform: translate3d(0, 100%, 0) skewY(-2deg);
  pointer-events: none;
}
.wipe.is-in  { animation: wipe-in  var(--t-slow) var(--ease-paper) forwards; }
.wipe.is-out { animation: wipe-out var(--t-slow) var(--ease-paper) forwards; }
@keyframes wipe-in  { to { transform: translate3d(0, 0, 0) skewY(0deg); } }
@keyframes wipe-out { from { transform: translate3d(0, 0, 0) skewY(0deg); } to { transform: translate3d(0, -100%, 0) skewY(2deg); } }

/* --- Stamp: elements arrive with weight, like a printing press ----------- */
.stamp-in { animation: stamp 380ms var(--ease-gate) both; }
@keyframes stamp {
  0%   { transform: scale(1.14) translateY(-6px); opacity: 0; }
  62%  { transform: scale(.985) translateY(0); opacity: 1; }
  /* the hold: two frames of nothing at all */
  74%  { transform: scale(.985); }
  100% { transform: scale(1); }
}

/* --- Beast state machine ------------------------------------------------
   idle → reveal (letters resolve out, staggered D→S→F) → hover → exit.
   Authored here in CSS so it works without a runtime; a Rive runtime can take
   over the same class names later without markup changes.                   */
.dse-beast { transition: transform var(--t-base) var(--ease-paper); }
.dse-beast [data-letter] {
  transform-box: fill-box; transform-origin: center;
  animation: beast-letter 420ms var(--ease-paper) both;
}
.dse-beast [data-letter="d"] { animation-delay: 0ms; }
.dse-beast [data-letter="s"] { animation-delay: 80ms; }
.dse-beast [data-letter="f"] { animation-delay: 160ms; }
@keyframes beast-letter { from { opacity: 0; transform: scale(.72); } to { opacity: 1; transform: scale(1); } }
a:hover > .dse-beast, .card:hover .dse-beast, .poster:hover .dse-beast { transform: scale(1.03) rotate(-.6deg); }

/* --- Marquee / drift ----------------------------------------------------- */
.drift { animation: drift 9s var(--ease-settle) infinite alternate; }
@keyframes drift { from { transform: translateY(-6px) rotate(-1deg); } to { transform: translateY(6px) rotate(1deg); } }

/* --- Hover lift on media ------------------------------------------------- */
.lift { transition: transform var(--t-base) var(--ease-paper), box-shadow var(--t-base); }
.lift:hover { transform: translateY(-4px); box-shadow: var(--sh-lg); }

/* --- Parallax layers ----------------------------------------------------- */
[data-parallax] { will-change: transform; }

/* --- Counter / odometer -------------------------------------------------- */
.odo { font-variant-numeric: tabular-nums; }

/* --- Sticky pinned sequence --------------------------------------------- */
.pinned { position: relative; }
.pinned__stage { position: sticky; top: var(--nav-h); height: calc(100vh - var(--nav-h)); display: grid; place-items: center; overflow: hidden; }

/* --- Scroll-scrubbed frame sequence (stop-motion) ------------------------ */
.scrub { position: relative; }
.scrub__frames { position: relative; aspect-ratio: 16/10; }
.scrub__frames img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; }
.scrub__frames img.is-on { opacity: 1; }

/* ===========================================================================
   REDUCED MOTION — ship this on day one, never as a retrofit.
   No parallax, no pinning, no letter stagger, no scrub. The chapter card still
   appears; it simply cross-fades in 120ms. The identity survives, the motion
   does not.
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .chapter-card[data-animatic] .chapter-card__rule,
  .chapter-card[data-animatic] .chapter-card__num,
  .chapter-card[data-animatic] .chapter-card__name,
  .chapter-card[data-animatic] .chapter-card__beast,
  [data-animatic] .split-char {
    animation: cc-fade 120ms linear both !important;
  }
  @keyframes cc-fade { from { opacity: 0; } to { opacity: 1; } }
  .gsap-hide { opacity: 1 !important; transform: none !important; }
  .hero__scroll i, .drift, .ticker__track { animation: none !important; }
  .pinned__stage { position: static; height: auto; }
  .wipe { display: none; }
}

/* Print: never leave content hidden by a failed animation. */
@media print {
  .gsap-hide, [data-reveal], [data-stagger] > * { opacity: 1 !important; transform: none !important; }
}
