/* ─────────────────────────────────────────────────────────────────────
 * Flowella — motion overlay (CSS Scroll-Driven Animations)
 *
 * Pure CSS, no JS libraries. Everything here is progressive enhancement
 * sitting on top of design-system.css + main.css.
 *
 * Design contract:
 *   1. FINAL-STATE-FIRST. Every animated element renders in its final
 *      visual state by default. Animations only override that state in
 *      browsers that support `animation-timeline: view()` / `scroll()`.
 *      Browsers without support — and any device with
 *      `prefers-reduced-motion: reduce` — see the page exactly as before.
 *   2. COMPOSITE-ONLY. Animations only touch `opacity` and `transform`,
 *      so they run on the compositor and never trigger layout/paint on
 *      scroll.
 *   3. RESTRAINED. Vertical entry distance capped at 12px. Easing is
 *      `cubic-bezier(0.22, 1, 0.36, 1)` (soft ease-out, no bounce).
 *      Time-based loops in the hero are slow and low-amplitude.
 *   4. NO HEX COLOURS. Everything reuses the design-system tokens
 *      (`--green`, `--secondary`, etc.) so colour drift is impossible.
 *
 * Browser support note:
 *   `animation-timeline: view()` ships in Chromium 115+ and Safari 26.
 *   Firefox is behind a flag at time of writing. The `@supports` gate
 *   means non-supporting browsers keep the existing static layout.
 *
 *   Scroll-driven rules also set `animation-duration: 1ms`. Firefox
 *   (and the spec) requires a non-zero duration even when the timeline
 *   is in charge of progress; without it, progress stays at 0%.
 * ───────────────────────────────────────────────────────────────────── */

/* Registered custom property used by the count-up counter() approach.
   Even when we fall back to the JS counter for the editor-driven stats
   band, having `--fr-num` registered is harmless and lets future modules
   adopt the pure-CSS pattern. */
@property --fr-num {
  syntax: "<integer>";
  inherits: false;
  initial-value: 0;
}

/* ────────────────────────────────────────────────────────────────────
 * Time-based, looping motion.
 *
 * Lives outside the @supports gate because plain @keyframes animations
 * are safe in every modern browser. Still gated by reduced-motion.
 * ──────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {

  /* Hero glow — slow breathe behind the mascot. */
  @keyframes fr-hero-glow {
    from { opacity: .85; transform: scale(.97); }
    to   { opacity: 1;   transform: scale(1.03); }
  }
  .hero .hero-art-glow {
    animation: fr-hero-glow 7s ease-in-out infinite alternate;
    will-change: opacity, transform;
  }

  /* Hero eyebrow status dot — soft pulse so the "live" feel is
     present without demanding attention. Uses the existing --green
     token for the box-shadow tint. */
  @keyframes fr-hero-dot {
    from {
      transform: scale(1);
      box-shadow: 0 0 8px var(--green);
    }
    to {
      transform: scale(1.25);
      box-shadow: 0 0 16px var(--green);
    }
  }
  .hero .hero-eyebrow .dot {
    animation: fr-hero-dot 1.6s ease-in-out infinite alternate;
    will-change: transform, box-shadow;
  }
}

/* ────────────────────────────────────────────────────────────────────
 * Use case card — icon hover affordance.
 *
 * Hover-only, no scroll dependency, so it lives outside the @supports
 * block. The glow uses `currentColor` because each card sets its own
 * accent via a `color:` rule on `.uc-icon` (rotated by :nth-child),
 * so the halo automatically picks up the right tint per card.
 *
 * `color-mix` is used to dial the tint to ~30% alpha while keeping the
 * design-system token as the source of truth. Supported in every
 * browser that already runs the rest of this stylesheet.
 * ──────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  .uc-card .uc-icon {
    transition:
      transform 200ms cubic-bezier(0.22, 1, 0.36, 1),
      box-shadow 200ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  .uc-card:hover .uc-icon,
  .uc-card:focus-visible .uc-icon {
    transform: rotate(3deg);
    box-shadow:
      0 0 0 6px color-mix(in srgb, currentColor 12%, transparent),
      0 8px 22px -6px color-mix(in srgb, currentColor 30%, transparent);
  }
}

/* ────────────────────────────────────────────────────────────────────
 * Scroll-driven motion.
 *
 * Everything below depends on `animation-timeline: view()` (or
 * `scroll()` for the hero parallax). Wrapped twice:
 *   - prefers-reduced-motion: no-preference  (motion is OK)
 *   - @supports (animation-timeline: view()) (browser can do it)
 *
 * If either fails, the rules don't apply and elements keep their
 * default static state.
 * ──────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {

    /* ── 1. Section entry reveal (.fr-reveal hook) ─────────────────
     *
     * Apply via a generic `.fr-reveal` class for new markup, or via
     * the existing module-level child selectors below for sections
     * already in the codebase (so the hook is ambient, no markup
     * edits required).
     *
     * `from` state hides the element 12px below its final position;
     * the timeline interpolates to the natural state across the first
     * 40% of the element's entry into the viewport.
     */
    @keyframes fr-rise {
      from { opacity: 0; transform: translateY(12px); }
      to   { opacity: 1; transform: none; }
    }

    .fr-reveal,
    /* Body of each home-page section — comparison cards, three-step,
       use cases, video feature, blog grid, two-up cards, case studies,
       and the closing CTA strip. */
    section.s .vs-grid,
    section.s .steps,
    section.s .uc-grid,
    section.s .story-grid,
    section.s .blog-bento,
    section.s .blog-grid,
    section.s .twoup,
    section.s .cs-shell,
    section.s .cta-strip,
    /* Section heads (eyebrow + h-display + lede) reveal independently
       so they cascade naturally with the body as the section enters. */
    section.s .problem-head,
    section.s .solution-head,
    section.s .uc-head,
    section.s .blog-head,
    section.s .cs-head,
    section.s .stats-head,
    section.s .howdygo-head,
    /* Walk-grid (product mock module) and walk-side intro — same
       feel as the other body sections. */
    section.s .walk-grid {
      animation: fr-rise both cubic-bezier(0.22, 1, 0.36, 1);
      animation-timeline: view();
      animation-range: entry 0% entry 40%;
      animation-duration: 1ms;
    }

    /* Story-side intro inside the video feature gets its own reveal
       so the copy column doesn't wait on the heavy video tile column.
       Both columns animate in their own viewport-relative range. */
    section.s .story-side {
      animation: fr-rise both cubic-bezier(0.22, 1, 0.36, 1);
      animation-timeline: view();
      animation-range: entry 0% entry 40%;
      animation-duration: 1ms;
    }

    /* ── 4. Comparison-card chat / form row stagger ────────────────
     *
     * Inside each .vs-card the chat bubbles (bad card) and the form
     * rows (good card) fade up with a small cascade. Stagger is done
     * by shifting `animation-range` per nth-child, because that's the
     * idiomatic way to cascade scroll-driven animations — `animation-
     * delay` in time units doesn't translate cleanly when duration is
     * 1ms and the timeline is view-progress-based.
     *
     * Cap: 4 children per card. Anything past nth-child(4) inherits
     * the 4th-child range so it doesn't disappear or animate out of
     * order on overlong content.
     */
    @keyframes fr-rise-mini {
      from { opacity: 0; transform: translateY(8px); }
      to   { opacity: 1; transform: none; }
    }

    .vs-card .vs-illus > .vs-msg,
    .vs-card .vs-illus > .vs-jumble,
    .vs-card .vs-illus .vs-form > .vs-form-row {
      animation: fr-rise-mini both cubic-bezier(0.22, 1, 0.36, 1);
      animation-timeline: view();
      animation-range: entry 10% entry 60%;
      animation-duration: 1ms;
    }

    /* Per-position stagger — each step shifts the entry range by ~6%,
       which on a typical viewport reads as roughly an 80ms cascade. */
    .vs-card .vs-illus > .vs-msg:nth-child(1),
    .vs-card .vs-illus .vs-form > .vs-form-row:nth-child(1) {
      animation-range: entry 10% entry 50%;
    }
    .vs-card .vs-illus > .vs-msg:nth-child(2),
    .vs-card .vs-illus .vs-form > .vs-form-row:nth-child(2) {
      animation-range: entry 16% entry 56%;
    }
    .vs-card .vs-illus > .vs-msg:nth-child(3),
    .vs-card .vs-illus .vs-form > .vs-form-row:nth-child(3) {
      animation-range: entry 22% entry 62%;
    }
    .vs-card .vs-illus > .vs-msg:nth-child(4),
    .vs-card .vs-illus .vs-form > .vs-form-row:nth-child(4),
    .vs-card .vs-illus .vs-form > .vs-form-row:nth-child(n+5) {
      animation-range: entry 28% entry 68%;
    }
    /* Chip cluster trails the chat / form rows. */
    .vs-card .vs-illus > .vs-jumble {
      animation-range: entry 34% entry 74%;
    }

    /* ── 3. Hero background-word parallax ──────────────────────────
     *
     * Subtle, document-scroll-tied translateY so the giant italic
     * "flow" word drifts up as the user scrolls past the hero. Range
     * is the full document scroll — the word only drifts a maximum
     * of 60px across the entire scroll length, which is barely
     * perceptible on a long page but adds depth on short ones.
     *
     * `scroll()` (no arg) defaults to the nearest scrollable
     * ancestor, which on every page here is the document.
     */
    @keyframes fr-hero-parallax {
      from { transform: translateY(0); }
      to   { transform: translateY(-60px); }
    }
    .hero .hero-bg-word {
      animation: fr-hero-parallax linear;
      animation-timeline: scroll();
      animation-duration: 1ms;
      will-change: transform;
    }

    /* ── 2. Stat count-up ──────────────────────────────────────────
     *
     * Pure-CSS path for the 5★ / 100K+ / 90%+ band. The numbers
     * themselves are owned by JS (see flowella-video-feature.module/
     * module.hubl.js) because the values are editor-driven free text
     * with mixed suffixes that don't fit the @property/counter()
     * pattern cleanly.
     *
     * What we DO add here is the entrance reveal for the stats band
     * itself, so the numbers fade up alongside the count-up. The
     * count-up triggers from the same scroll position via Intersection-
     * Observer in the JS file.
     */
    section.s .story-stats {
      animation: fr-rise both cubic-bezier(0.22, 1, 0.36, 1);
      animation-timeline: view();
      animation-range: entry 0% entry 40%;
      animation-duration: 1ms;
    }
  }
}
