/* Precursor Signal — scroll effects
   Built on native scroll-driven timelines (animation-timeline: view()/scroll()),
   so the motion is tied to scroll position rather than to a JS scroll handler —
   it tracks the finger exactly and runs off the compositor.

   IMPORTANT: these are scoped to container and decorative elements only. The
   fade-and-rise reveals in cinematic.css animate opacity/transform on cards and
   headings; applying a second timeline to those same properties would fight it.
   Containers are never tagged by that system, so the two layers compose. */

/* ---------- anchored jumps glide instead of teleporting ---------- */
html { scroll-behavior: smooth; scroll-padding-top: clamp(5rem, 10vw, 6.5rem); }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

@supports (animation-timeline: view()) {

  /* ---------- 1. bands recede as they leave ----------
     A section dims and settles back a touch on its way out of the top of the
     viewport, so what you are reading is always the nearest thing. */
  @keyframes bandRecede {
    from { opacity: 1; transform: scale(1) translateY(0); }
    to   { opacity: 0.55; transform: scale(0.985) translateY(-14px); }
  }
  #page-landing > .wrap,
  #page-landing > .light-section,
  #page-landing > .dark-section,
  #page-analytics > .light-section,
  #page-newsletter > .light-section,
  #page-issue > .light-section {
    animation: bandRecede linear both;
    animation-timeline: view();
    animation-range: exit 10% exit 90%;
    transform-origin: 50% 0%;
    will-change: opacity, transform;
  }

  /* ---------- 2. the mesh wash drifts inside its section ----------
     Parallax against the content above it, which reads as depth rather than
     as a background image scrolling in lockstep. */
  @keyframes meshDrift {
    from { transform: translate3d(0, -5%, 0) scale(1.04); }
    to   { transform: translate3d(0,  5%, 0) scale(1.04); }
  }
  .mesh-bg {
    animation: meshDrift linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }

  /* the dot ground creeps at a different rate again — three speeds in
     total (content, mesh, dots) is what sells the depth */
  @keyframes groundCreep {
    from { background-position: -1px -1px; }
    to   { background-position: -1px 40px; }
  }
  #page-landing > .wrap,
  #page-landing > .light-section {
    animation: bandRecede linear both, groundCreep linear both;
    animation-timeline: view(), view();
    animation-range: exit 10% exit 90%, cover 0% cover 100%;
  }

  /* ---------- 3. the hero settles as you leave it ---------- */
  @keyframes heroSettle {
    from { opacity: 1; }
    to   { opacity: 0.35; }
  }
  .atmosphere > .wrap {
    animation: heroSettle linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 70%;
  }

  /* ---------- 4. the orbit rings scale with scroll through Coverage ----------
     The map opens up as you move through the section. */
  @keyframes orbitOpen {
    from { transform: scale(0.94); opacity: 0.5; }
    to   { transform: scale(1);    opacity: 1; }
  }
  .sm-orbit-path {
    animation: orbitOpen linear both;
    animation-timeline: view();
    animation-range: entry 20% cover 45%;
  }

  /* ---------- 5. the footer ghost word rises into place ---------- */
  @keyframes ghostRise {
    from { opacity: 0; transform: translateY(30px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .ghost-word {
    animation: ghostRise linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 90%;
  }
}

@media (prefers-reduced-motion: reduce) {
  #page-landing > .wrap,
  #page-landing > .light-section,
  #page-landing > .dark-section,
  #page-analytics > .light-section,
  #page-newsletter > .light-section,
  #page-issue > .light-section,
  .mesh-bg, .atmosphere > .wrap, .sm-orbit-path, .ghost-word {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}
