/* =============================================================================
 * motion.css — ALL animation. Nothing here changes static appearance. (D2)
 *
 * Every duration/easing below references a token from reset.css. No animation
 * may hardcode a value — that is the motion equivalent of the data schema.
 *
 * Hard rules:
 *   · Never animate backdrop-filter: blur(). Ever.
 *   · transform and opacity only. No layout properties.
 *   · Seed pulse stays under 1Hz (WCAG 2.3.1).
 * ============================================================================= */

/* Everything in this block is opt-IN motion: it applies only when the reader
 * has not asked for less, and only when the in-page pause control is off. */
@media (prefers-reduced-motion: no-preference) {
  html:not(.force-reduce) .zone-layer {
    transition: opacity var(--dur-zonefade) var(--ease-standard);
  }

  html:not(.force-reduce) .seed {
    transition: opacity var(--dur-bloom-out) var(--ease-bloom);
  }

  html:not(.force-reduce) .seed::after {
    /* attack-fast, decay-slow: bioluminescence flashes on disturbance,
     * then fades. The audio envelope shares this asymmetry. */
    transition: opacity var(--dur-bloom-out) var(--ease-bloom),
                transform var(--dur-bloom-out) var(--ease-bloom);
  }
  html:not(.force-reduce) .seed.is-bloomed::after {
    transition-duration: var(--dur-bloom-in);
    transform: scale(1.9);
  }

  html:not(.force-reduce) .seed-glyph {
    transition: transform var(--dur-bloom-out) var(--ease-bloom);
  }
  html:not(.force-reduce) .seed.is-bloomed .seed-glyph {
    transition-duration: var(--dur-bloom-in);
    transform: scale(1.25);
  }

  /* the slow tidal pulse — 0.14Hz, far under the 3-flash threshold */
  html:not(.force-reduce) .seed.is-marquee::before {
    animation: seed-pulse var(--dur-pulse) var(--ease-standard) infinite;
  }
  @keyframes seed-pulse {
    0%, 100% { transform: scale(1);    opacity: 0.35; }
    50%      { transform: scale(1.22); opacity: 0.08; }
  }

  html:not(.force-reduce) .bloom-card {
    animation: card-in var(--dur-bloom-in) var(--ease-bloom) both;
  }
  @keyframes card-in {
    from { opacity: 0; transform: translate3d(var(--cx, 0), calc(var(--cy, 0px) + 6px), 0); }
  }

  /* the unfold: scrim opacity + a whisper of column scale. No blur animation. */
  html:not(.force-reduce) .scrim {
    animation: scrim-in var(--dur-drawer) var(--ease-unfold) both;
  }
  @keyframes scrim-in { from { opacity: 0; } to { opacity: 0.55; } }

  html:not(.force-reduce) .drawer {
    animation: drawer-in var(--dur-drawer) var(--ease-unfold) both;
  }
  @keyframes drawer-in {
    from { opacity: 0; transform: translate3d(2.5%, 0, 0); }
  }

  html:not(.force-reduce).drawer-open #main {
    transform: scale(0.985);
    transition: transform var(--dur-drawer) var(--ease-unfold);
  }
  html:not(.force-reduce) #main { transition: transform var(--dur-drawer) var(--ease-unfold); }

  /* drawer content stagger */
  html:not(.force-reduce) .drawer-inner > * {
    animation: content-rise var(--dur-reveal) var(--ease-standard) both;
  }
  html:not(.force-reduce) .drawer-inner > *:nth-child(1) { animation-delay: calc(var(--stagger-content) * 0); }
  html:not(.force-reduce) .drawer-inner > *:nth-child(2) { animation-delay: calc(var(--stagger-content) * 1); }
  html:not(.force-reduce) .drawer-inner > *:nth-child(3) { animation-delay: calc(var(--stagger-content) * 2); }
  html:not(.force-reduce) .drawer-inner > *:nth-child(4) { animation-delay: calc(var(--stagger-content) * 3); }
  html:not(.force-reduce) .drawer-inner > *:nth-child(5) { animation-delay: calc(var(--stagger-content) * 4); }
  html:not(.force-reduce) .drawer-inner > *:nth-child(n+6) { animation-delay: calc(var(--stagger-content) * 5); }
  @keyframes content-rise { from { opacity: 0; transform: translate3d(0, 8px, 0); } }

  /* the lens wash: a depth-staggered transition within the viewport.
   * We do not pretend a light travels across twenty unrendered screens. */
  html:not(.force-reduce).lens-active .seed {
    transition: opacity var(--dur-lens) var(--ease-standard);
  }

  html:not(.force-reduce) .overture-cue {
    animation: cue-drift var(--dur-cue) var(--ease-standard) infinite;
  }
  @keyframes cue-drift {
    0%   { opacity: 0; transform: translateY(-8px); }
    40%  { opacity: 1; }
    100% { opacity: 0; transform: translateY(12px); }
  }

  html:not(.force-reduce) .toc-item { transition: background var(--dur-reveal) var(--ease-standard); }
  html:not(.force-reduce) .fig-img  { transition: opacity var(--dur-reveal) var(--ease-standard); }
  html:not(.force-reduce) .hud-btn  { transition: color var(--dur-hover-tint) var(--ease-standard), border-color var(--dur-hover-tint) var(--ease-standard); }
}

/* ---------------------------------------------------------------------------
 * The reduced path. Reached by the OS flag OR the in-page control (WCAG 2.2.2)
 * — one shared code path, so testing one tests both. Not an afterthought:
 * the piece is designed to be complete without a single moving pixel.
 * ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

html.force-reduce *, html.force-reduce *::before, html.force-reduce *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

/* In either reduced path the marine snow becomes a faint static texture and
 * the parallax layer freezes. The zone gradient steps per era rather than
 * interpolating continuously — a full-screen hue morph can bother
 * vestibular-sensitive readers even with parallax off. */
@media (prefers-reduced-motion: reduce) {
  .snow { opacity: 0.35; }
  .silhouettes { transform: none !important; }
}
html.force-reduce .snow { opacity: 0.35; }
html.force-reduce .silhouettes { transform: none !important; }
