/* AFDP scroll-story engine — structural layer only.
   Worlds own every color, face, and visual; this file owns the mechanics:
   film driver, sticky stage, scene layering, beats, reveals, resolved states.

   Law: the NO-JS / reduced-motion default is the complete, readable page.
   The .js class (set by the engine) is what earns hidden initial states. */

/* ---------- film structure ---------- */

.film {
  /* tall scroll driver: N scenes x --scene-len each */
  --scene-len: 130vh;
  height: calc(var(--scenes, 5) * var(--scene-len));
  position: relative;
}

.film-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
}

.scene {
  position: absolute;
  inset: 0;
  /* worlds read --p (eased) and --pl (linear) for every scrubbed visual */
}

/* no-JS: the film collapses into stacked full-height chapters, all visible */
html:not(.js) .film { height: auto; }
html:not(.js) .film-stage { position: static; height: auto; overflow: visible; }
html:not(.js) .scene { position: relative; min-height: 100vh; }

/* reduced motion: same stacked, resolved presentation (film clips horizontal spill — rm horizontal clip) */
html.rm .film, html:not(.js) .film { overflow: hidden; }
html.rm .film { height: auto; }
html.rm .film-stage { position: static; height: auto; overflow: visible; }
html.rm .scene { position: relative; min-height: 100vh; }

/* scenes hide until active only when the engine is running full-motion;
   transition arms only after first settled render (no boot flash) */
html.js:not(.rm) .scene { opacity: 0; pointer-events: none; }
html.js.booted:not(.rm) .scene { transition: opacity 0.35s linear; }
html.js:not(.rm) .scene.active { opacity: 1; pointer-events: auto; }

/* ---------- parallax hooks ---------- */

[data-depth] { transform: translateY(var(--shift, 0px)); will-change: transform; }
html.rm [data-depth], html:not(.js) [data-depth] { transform: none; }

/* ---------- beats (copy over the film) ---------- */

.beat {
  position: absolute;
  z-index: 4;
  max-width: 30rem;
  transform: translateY(var(--rise, 0px));
  will-change: opacity, transform;
}
html:not(.js) .beat, html.rm .beat { position: relative; inset: auto; opacity: 1 !important; visibility: visible !important; transform: none; max-width: 34rem; margin: 1.6rem clamp(1.25rem, 6vw, 6rem); text-align: left; }

/* ---------- char-split display reveal ---------- */

.charsplit .chw { display: inline-block; white-space: nowrap; }
.charsplit .ch { display: inline-block; }
html.js:not(.rm) .charsplit .ch {
  transform: translateY(115%);
  opacity: 0;
  transition: transform 0.7s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.45s linear;
}
html.js:not(.rm) .charsplit { overflow: hidden; }
html.js:not(.rm) .charsplit.in .ch, html.js:not(.rm) .charsplit.is-visible .ch { transform: none; opacity: 1; }

/* ---------- sections below the film ---------- */

.section { position: relative; }
html.js:not(.rm) .section > .wrap > * {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
html.js:not(.rm) .section.in > .wrap > *, html.js:not(.rm) .section.is-visible > .wrap > * { opacity: 1; transform: none; }
html.js:not(.rm) .section.in > .wrap > *:nth-child(2) { transition-delay: 0.09s; }
html.js:not(.rm) .section.in > .wrap > *:nth-child(3) { transition-delay: 0.18s; }
html.js:not(.rm) .section.in > .wrap > *:nth-child(4) { transition-delay: 0.27s; }
html.js:not(.rm) .section.in > .wrap > *:nth-child(5) { transition-delay: 0.36s; }

/* ---------- marquee ---------- */

.marquee { overflow: hidden; }
.marquee-track {
  display: flex;
  gap: 3rem;
  width: max-content;
  transform: skewX(var(--vskew, 0deg));
  animation: marquee-drift var(--marquee-t, 26s) linear infinite;
}
@keyframes marquee-drift { to { transform: translateX(-50%) skewX(var(--vskew, 0deg)); } }
html.rm .marquee-track, html:not(.js) .marquee-track { animation: none; transform: none; }

/* ---------- shared boundary dialog shell (worlds style it) ---------- */

dialog.boundary { border: 0; padding: 0; max-width: 32rem; width: calc(100% - 2.5rem); }
dialog.boundary::backdrop { background: rgba(10, 12, 10, 0.55); }

/* ---------- capture hygiene ---------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001s !important; transition-duration: 0.001s !important; }
}
