/* ==========================================================================
   animations.css — Scroll-driven reveal & stagger animations
   --------------------------------------------------------------------------
   The shared fade-up reveal used by every scroll-revealed section, plus the
   sequential "stagger" cascade for a revealed container's children. Driven by
   js/animations.js (task 7.1), which:
     - adds `.visible` to a `.reveal` element when it enters the viewport
       (fire-once via IntersectionObserver, threshold 0.1)         (Req 3.1)
     - writes an ordinal `--i` custom property on each `.stagger` descendant of
       a revealed container so the cascade delay can be computed in CSS
       as `calc(var(--i) * var(--stagger-delay))` (default 80ms)   (Req 3.2)
   This file only styles the two states; it never toggles classes.

   Tokens consumed from css/variables.css: --stagger-delay (80ms), --ease-out.

   PROGRESSIVE ENHANCEMENT (Req 9.6)
   --------------------------------------------------------------------------
   Every rule that HIDES content is gated on `html.js-loaded` (added early by
   js/main.js, task 13.1). Without JS — or before main.js runs, or if a script
   fails — none of the hide rules apply, so all `.reveal`/`.stagger` content
   renders in its final, visible state and is never withheld.

   SCOPING NOTES (avoiding conflicts with the hero and the news timeline)
   --------------------------------------------------------------------------
   * Hero: `section.hero` is itself a `.reveal` and its children carry
     `.stagger`, but the hero runs its OWN entrance sequence in css/hero.css
     (`.hero-enter`). The generic reveal is therefore neutralized on the hero
     (see §3) and the generic stagger explicitly excludes `.hero` descendants
     (`:not(.hero)`), so the two systems never double-hide or fight.
   * News: news items reveal with a horizontal slide defined in css/news.css
     under `.news-timeline .reveal-news` (specificity 0,3,1). The generic
     `.reveal` rules here are kept intentionally low-specificity (0,2,1 / 0,3,1)
     and transition-based so news.css cleanly overrides both the hidden and
     visible states for those items regardless of stylesheet load order.

   Requirements: 3.1 (fade-up), 3.2 (stagger), 3.4 (reduced motion), 9.6 (PE).
   ========================================================================== */

/* ==========================================================================
   1. Shared keyframes
   --------------------------------------------------------------------------
   `reveal-rise` is the fade-up motion (opacity 0 -> 1, translateY -> 0) used by
   the stagger cascade (§4). The top-level reveal (§2) uses a transition rather
   than this animation so that news.css can override it by specificity, but the
   keyframe is shared here so stagger children animate identically. Transform +
   opacity only — both are compositor-friendly and never trigger layout.
   ========================================================================== */

@keyframes reveal-rise {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ==========================================================================
   2. Reveal fade-up (Req 3.1)
   --------------------------------------------------------------------------
   Any `.reveal` element starts hidden (opacity 0, nudged down 30px) and eases
   to its final state once js/animations.js adds `.visible`. Implemented as a
   transition (not an animation) so news.css's higher-specificity slide rules
   win for `.reveal-news` items. Kept at low specificity on purpose — do NOT add
   `:not(...)` here, or it would tie/beat news.css and break the news slide.
   ========================================================================== */

html.js-loaded .reveal {
  opacity: 0;
  transform: translateY(30px);
  transition:
    opacity 0.7s var(--ease-out),
    transform 0.7s var(--ease-out);
  will-change: opacity, transform;
}

html.js-loaded .reveal.visible {
  opacity: 1;
  transform: none;
}

/* ==========================================================================
   3. Hero opt-out
   --------------------------------------------------------------------------
   `section.hero` is a `.reveal`, but css/hero.css owns its entrance. Force the
   hero container to its visible state (never fade it via the generic reveal)
   and drop the transition so nothing competes with the hero's own keyframes.
   Higher specificity (0,3,1 / 0,4,1) than §2 guarantees this wins. Hero
   `.stagger` children are handled separately by the `:not(.hero)` scope in §4.
   ========================================================================== */

html.js-loaded .hero.reveal,
html.js-loaded .hero.reveal.visible {
  opacity: 1;
  transform: none;
  transition: none;
  will-change: auto;
}

/* ==========================================================================
   4. Stagger cascade (Req 3.2)
   --------------------------------------------------------------------------
   `.stagger` descendants of a revealed container start hidden and, once the
   container gains `.visible`, rise sequentially. js/animations.js sets `--i`
   (0-based ordinal) on each child; the per-child delay is
   `calc(var(--i) * var(--stagger-delay))` so consecutive items are offset by
   the default 80ms. `--i` falls back to 0 (no delay) for above-the-fold
   content, which animations.js reveals without indexing (Req 3.5).

   Scoped with `:not(.hero)` so the hero's own `.stagger` children (animated by
   css/hero.css) are never touched here. News items are not `.stagger`, so this
   never interferes with the news timeline.
   ========================================================================== */

html.js-loaded .reveal:not(.hero) .stagger {
  opacity: 0;
  transform: translateY(18px);
  will-change: opacity, transform;
}

html.js-loaded .reveal:not(.hero).visible .stagger {
  animation: reveal-rise 0.55s var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger-delay));
}

/* ==========================================================================
   5. Reduced motion (Req 3.4)
   --------------------------------------------------------------------------
   When the visitor prefers reduced motion, disable every transform/opacity
   transition and keyframe animation and render the final visible state
   immediately, with no delay. js/animations.js also reveals all content up
   front in this mode; these rules guarantee nothing animates or stays hidden
   even if `.visible` has not yet been applied. `!important` overrides the
   per-child `animation-delay` and the transitions defined above.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html.js-loaded .reveal,
  html.js-loaded .reveal.visible,
  html.js-loaded .reveal:not(.hero) .stagger,
  html.js-loaded .reveal:not(.hero).visible .stagger {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
}
