/*
 * motion.css — motion tokens + no-FOUC pre-hide for the GSAP motion layer.
 *
 * Personality is "calm over loud" (brand-essence §3): settled durations, gentle
 * eases, short travel. Values mirror the static pipeline's --hv-motion-* tokens
 * (code/brands/hirevolution/tokens.css) so both build systems share one motion
 * feel. hv-motion.js reads these via getComputedStyle. Contract: ../../MOTION.md.
 *
 * Token rule (as everywhere): no off-token values in shipped markup — elements
 * declare a named effect via hv-anim-* / data-hv-anim; timing comes from here.
 */

:root {
  /* Durations — JS parses ms to seconds for GSAP. */
  --hv-motion-duration-fast: 200ms;
  --hv-motion-duration-base: 600ms;
  --hv-motion-duration-slow: 900ms;

  /* Entrance travel. */
  --hv-motion-distance-sm: 8px;
  --hv-motion-distance-md: 16px;
  --hv-motion-distance-lg: 28px;

  /* Stagger between sibling reveals (ms). */
  --hv-motion-stagger: 90ms;

  /* Unified-stagger entrance tokens (1.9.1).
     Separate from the general-purpose tokens above so per-widget effects
     (fade-up, reveal) can keep power3.out/600ms while the composed section
     entrances are crisper: shorter duration, softer ease, smaller lift.
     "Calm over loud": element lands and is still quickly; fade is dominant. */
  --hv-motion-duration-enter: 500ms;
  --hv-motion-ease-enter: power2.out;

  /* GSAP ease names — strings GSAP accepts directly (no CustomEase needed).
     power3.out ≈ the static pipeline's settled cubic-bezier(0.22,1,0.36,1). */
  --hv-motion-ease-default: power3.out;
  --hv-motion-ease-snap: back.out(1.4);

  /* Colour tint tokens for heading-accent animation (ink→green).
     Mirror hv-tokens.css values so the tween is token-driven.
     JS reads these via getComputedStyle — no raw hex in hv-motion.js. */
  --hv-motion-color-ink:    #1F2937;
  --hv-motion-color-accent: #3F7A2A;

  /* Lenis smooth-scroll feel. Controls the lerp interpolation factor:
     lower = slower/smoother, higher = snappier. Tuned to "calm over loud" —
     settled and premium, not floaty. hv-motion.js reads this via
     getComputedStyle (unitless float stored as a plain number). */
  --hv-motion-lenis-lerp: 0.1;

  /* Nav colour-flip tokens — used by initNavFlip() in hv-motion.js and the
     .hv-flip-dark CSS rules in hv-elementor.css. Mirror the brand tokens in
     hv-tokens.css so the flip feels native to the palette. */
  --hv-motion-nav-bar-bg:        rgba(253, 250, 245, 0.55); /* frosted light tint over light bands (cream @55%) */
  --hv-motion-nav-bar-bg-dark:   rgba(27, 25, 23, 0.45);    /* frosted dark tint over dark bands (ink @45%) */
  --hv-motion-nav-bar-blur:      10px;   /* backdrop blur for the frosted bar */
  --hv-motion-nav-flip-text:     #FDFAF5; /* = --hv-background (approved cream) — flipped link/CTA colour */
  --hv-motion-nav-flip-duration: 500ms;   /* bg + text fade — calm, not instant */
  --hv-motion-nav-flip-logo-dur: 300ms;   /* logo crossfade — slightly quicker */
  --hv-motion-nav-dark-band:     0.6;     /* luminance threshold: < this = dark band */
}

/*
 * Elementor 4.x transform-transition neutraliser (1.9.2).
 *
 * Elementor's frontend.min.css applies this to animated targets:
 *   transition: background .3s, border .3s, border-radius .3s, box-shadow .3s,
 *               transform var(--e-transform-transition-duration, .4s)
 * on .elementor-element:not(.e-con) wrappers AND their .elementor-widget-container
 * children. When GSAP drives transform on these elements frame-by-frame, the browser
 * re-interpolates each rAF-set value over 0.4s — the rendered transform lags ~0.4s
 * behind GSAP while opacity (not in that transition list) tracks correctly.
 * This produces the "heading fully opaque, still sliding up" desync Jon measured.
 *
 * Fix: set --e-transform-transition-duration: 0s on every element that carries a
 * GSAP hook class. Elementor's rule then resolves to transform 0s (instant) on
 * those elements only. Hover-lift card transitions in hv-elementor.css use the
 * explicit transition shorthand (not this variable), so they are unaffected.
 *
 * Container stagger targets (.e-con) lack hook classes; those are covered in
 * hv-motion.js (JS sets/restores the variable around each stagger tween).
 * Only under no-preference — reduce users never see the transform transition issue
 * because the entrance tweens never fire for them.
 */
@media (prefers-reduced-motion: no-preference) {
  [class*="hv-anim-"],
  [data-hv-anim],
  [class*="hv-anim-"] .elementor-widget-container,
  [data-hv-anim] .elementor-widget-container {
    --e-transform-transition-duration: 0s;
  }
}

/*
 * No-FOUC pre-hide. Only under no-preference, and only once the inline head
 * snippet has added .hv-motion-active (removed by the failsafe if motion never
 * initialises, so content can never be stuck hidden). Reduced-motion users
 * never get this rule — their content is visible from first paint.
 * Markup-agnostic: hooks live on whatever element carries them (Elementor
 * wrapper divs included). Never applied in the editor — the no-FOUC snippet
 * is skipped there, so .hv-motion-active is never present.
 *
 * Fixed contract: self-animating effects hide the element; stagger-up hides its
 * DIRECT children (the things that stagger in). hv-motion.js uses fromTo() with
 * explicit end states so this pre-hide can't poison the destination value.
 */
@media (prefers-reduced-motion: no-preference) {
  /* Self-animating effects (both hook forms) hide the element itself.
     count-up is excluded: it drives textContent not opacity, so hiding it
     would show a blank numeral flash on scroll-in. The numeral stays visible
     (showing 0 for a frame is fine; gsap.fromTo overrides before paint). */
  .hv-motion-active [data-hv-anim]:not([data-hv-anim="stagger-up"]):not([data-hv-anim="count-up"]),
  .hv-motion-active [class*="hv-anim-"]:not(.hv-anim-stagger-up):not(.hv-anim-count-up) {
    opacity: 0;
  }
  /* stagger-up hides its DIRECT children (the things that stagger in). */
  .hv-motion-active [data-hv-anim="stagger-up"] > *,
  .hv-motion-active .hv-anim-stagger-up > * {
    opacity: 0;
  }
}
