/* Scroll-triggered entrance animations for editorial widgets.
   reveal.js flips <html>.no-js → .js and adds .is-revealed to any
   [data-reveal] element that intersects the viewport. Animations are then
   time-based (real durations), fire once, and don't reverse on scroll-up.

   Fallback contract:
   - No JS → .js never applied → the `.js` gates below don't match →
     `color: transparent` / start-state / paused animations never fire →
     content renders at its natural rest state (visible textContent, bars
     at full width, waffle cells visible).
   - prefers-reduced-motion: reduce → entire @media block is skipped →
     same static rest state as no-JS. */

/* @property must be at top level, not inside @layer. */
@property --n {
  syntax: '<integer>';
  initial-value: 0;
  inherits: false;
}
@property --n-final {
  syntax: '<integer>';
  initial-value: 0;
  inherits: false;
}

@media (prefers-reduced-motion: no-preference) {
  @layer components {
    /* -------- Metric cards: number counts up when Impacto enters view -------- */
    @keyframes count-up {
      from { --n: 0; }
      to   { --n: var(--n-final); }
    }

    /* Only hide the underlying text + install the counter overlay when JS is
       loaded. Without .js, cards show textContent (final number) directly. */
    .js .metrics .metric-card__value {
      position: relative;
      color: transparent;
      counter-reset: num var(--n);
      animation: count-up 1400ms ease-out both;
      animation-play-state: paused;
    }
    .js .metrics .metric-card__value::after {
      content: counter(num);
      position: absolute;
      inset: 0;
      color: var(--green-bright);
    }
    /* Per-card stagger: card 1 first, card 5 last. */
    .js .metrics .metric-card:nth-child(1) .metric-card__value { animation-delay: 0ms; }
    .js .metrics .metric-card:nth-child(2) .metric-card__value { animation-delay: 150ms; }
    .js .metrics .metric-card:nth-child(3) .metric-card__value { animation-delay: 300ms; }
    .js .metrics .metric-card:nth-child(4) .metric-card__value { animation-delay: 450ms; }
    .js .metrics .metric-card:nth-child(5) .metric-card__value { animation-delay: 600ms; }
    .js .metrics.is-revealed .metric-card__value {
      animation-play-state: running;
    }

    /* -------- Workload bars: scaleX from left; number fades in near the end -- */
    @keyframes bar-grow {
      from { transform: scaleX(0); }
      to   { transform: scaleX(1); }
    }
    @keyframes bar-value-appear {
      from, 60% { opacity: 0; }
      to        { opacity: 1; }
    }

    .workload__bar { transform-origin: left; }

    .js .workload .workload__bar {
      animation: bar-grow 900ms ease-out both;
      animation-play-state: paused;
      animation-delay: calc(var(--i, 0) * 200ms);
    }
    .js .workload .workload__row:nth-child(2) .workload__bar {
      animation-delay: calc(500ms + var(--i, 0) * 200ms);
    }
    .js .workload .workload__bar-value {
      animation: bar-value-appear 900ms ease-out both;
      animation-play-state: paused;
      animation-delay: calc(var(--i, 0) * 200ms);
    }
    .js .workload .workload__row:nth-child(2) .workload__bar-value {
      animation-delay: calc(500ms + var(--i, 0) * 200ms);
    }
    .js .workload.is-revealed .workload__bar,
    .js .workload.is-revealed .workload__bar-value {
      animation-play-state: running;
    }

    /* -------- Sleeping giants: waffle cells cascade card-by-card ------------- */
    @keyframes cell-pop {
      from { opacity: 0; scale: 0.6; }
      to   { opacity: 1; scale: 1; }
    }

    .js .giants .giants__cell[data-filled] {
      animation: cell-pop 350ms ease-out both;
      animation-play-state: paused;
      /* --ci = card index (0-3); --i = cell index (0-39). Cards stagger 400ms
         apart; cells inside a card stagger 15ms each. */
      animation-delay: calc(var(--ci, 0) * 400ms + var(--i, 0) * 15ms);
    }
    .js .giants.is-revealed .giants__cell[data-filled] {
      animation-play-state: running;
    }
  }
}

/* Hero pitch draws itself in on first paint.
   Separate block: this is a time-based animation, not scroll-driven — no
   dependency on animation-timeline: view(). `pathLength="1"` on each stroked
   shape lets `stroke-dasharray: 1` mean "one full path" universally.
   `stroke-dashoffset: 0` at rest = solid line, so browsers ignoring the
   media query (reduced-motion) see the pitch normally. */
.hero__pitch svg [pathLength] {
  stroke-dasharray: 1;
}

@media (prefers-reduced-motion: no-preference) {
  @layer components {
    @keyframes hero-pitch-draw {
      from { stroke-dashoffset: 1; }
      to   { stroke-dashoffset: 0; }
    }
    @keyframes hero-pitch-spot {
      from { opacity: 0; scale: 0; }
      to   { opacity: 1; scale: 1; }
    }

    .hero__pitch svg [pathLength] {
      animation: hero-pitch-draw 900ms ease-out both;
    }
    .hero__pitch svg .pitch-spot {
      transform-box: fill-box;
      transform-origin: center;
      animation: hero-pitch-spot 400ms ease-out both;
    }

    /* Sequence: boundary → midline → circle → left-then-right pairs → dots.
       `svg` in each selector matches the base rule's specificity (0,2,1) so
       cascade order wins — without it, the base `animation` shorthand's
       implicit animation-delay: 0s would beat these lower-specificity rules. */
    .hero__pitch svg .pitch-boundary            { animation-delay: 200ms; }
    .hero__pitch svg .pitch-midline             { animation-delay: 800ms; }
    .hero__pitch svg .pitch-circle              { animation-delay: 1200ms; }
    .hero__pitch svg .pitch-goalbox--left       { animation-delay: 1500ms; }
    .hero__pitch svg .pitch-goalbox--right      { animation-delay: 1700ms; }
    .hero__pitch svg .pitch-goalarea--left      { animation-delay: 1900ms; }
    .hero__pitch svg .pitch-goalarea--right     { animation-delay: 2100ms; }
    .hero__pitch svg .pitch-spot--center        { animation-delay: 2400ms; }
    .hero__pitch svg .pitch-spot--penalty-left  { animation-delay: 2600ms; }
    .hero__pitch svg .pitch-spot--penalty-right { animation-delay: 2800ms; }
  }
}
