/*! anim.css - Eureka Motion Kit (source: ops/lib/web/assets/anim.css)
 * House motion layer for framework sites. Self-hosted (CSP-safe), no build step,
 * pairs with anim.js (reveal engine). Everything animated lives behind
 * prefers-reduced-motion: no-preference; without JS or with reduced motion the
 * page renders fully visible and static. Keep this file tiny: it ships on every
 * page and the 95+ Lighthouse floor still applies.
 *
 * Vocabulary (see WEBSITE_BUILD_STANDARD.md "Motion layer"):
 *   [data-anim]                 reveal on scroll: fade-up (default), fade-down,
 *                               fade-left, fade-right, zoom, blur, mask
 *   [data-anim-stagger="90"]    parent: staggers its [data-anim] children
 *   [data-anim-count="4200"]    number counts up when revealed (+ data-prefix/suffix)
 *   [data-parallax] --parallax:6   subtle scroll parallax (native CSS, no JS)
 *   .anim-hero > *              staggered rise-in on page load (hero content)
 *   .anim-marquee > .anim-marquee-track   scrolling ribbon (duplicate content 2x)
 *   .anim-grain                 film-grain texture overlay on a section
 *   .anim-progress              page scroll progress bar (native CSS, no JS)
 */
:root{
  --anim-ease:cubic-bezier(.19,1,.22,1);
  --anim-dur:.7s;
  --anim-dist:26px;
}

@media (prefers-reduced-motion: no-preference){

  /* ---- Scroll reveals (driven by anim.js; hidden state only after the engine
     registers via html.anim-ready, so content is never lost without JS) ---- */
  .anim-ready [data-anim]{
    opacity:0;
    transition:opacity var(--anim-dur) var(--anim-ease),
               transform var(--anim-dur) var(--anim-ease),
               filter var(--anim-dur) var(--anim-ease),
               -webkit-mask-size var(--anim-dur) var(--anim-ease),
               mask-size var(--anim-dur) var(--anim-ease);
    transition-delay:var(--anim-delay,0ms);
  }
  .anim-ready [data-anim=""],
  .anim-ready [data-anim="fade-up"]{transform:translateY(var(--anim-dist))}
  .anim-ready [data-anim="fade-down"]{transform:translateY(calc(-1 * var(--anim-dist)))}
  .anim-ready [data-anim="fade-left"]{transform:translateX(calc(-1 * var(--anim-dist)))}
  .anim-ready [data-anim="fade-right"]{transform:translateX(var(--anim-dist))}
  .anim-ready [data-anim="zoom"]{transform:scale(.94)}
  .anim-ready [data-anim="blur"]{filter:blur(10px)}
  /* mask = left-to-right wipe. Painted with mask-image (NOT clip-path: a fully
     clipped element has zero visible area, so IntersectionObserver never fires). */
  .anim-ready [data-anim="mask"]{
    opacity:1;
    -webkit-mask-image:linear-gradient(#000 0 0);mask-image:linear-gradient(#000 0 0);
    -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
    -webkit-mask-size:0% 100%;mask-size:0% 100%;
  }
  .anim-ready [data-anim].anim-in{opacity:1;transform:none;filter:none;-webkit-mask-size:100% 100%;mask-size:100% 100%}

  /* ---- Hero load-in: stagger direct children, pure CSS, plays immediately ---- */
  @keyframes anim-rise{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}
  .anim-hero > *{animation:anim-rise .8s var(--anim-ease) both}
  .anim-hero > *:nth-child(2){animation-delay:.12s}
  .anim-hero > *:nth-child(3){animation-delay:.24s}
  .anim-hero > *:nth-child(4){animation-delay:.36s}
  .anim-hero > *:nth-child(5){animation-delay:.48s}
  .anim-hero > *:nth-child(n+6){animation-delay:.58s}

  /* ---- Marquee ribbon: duplicate the track content twice for a seamless loop ---- */
  .anim-marquee{overflow:hidden;white-space:nowrap}
  .anim-marquee .anim-marquee-track{display:inline-block;animation:anim-marquee var(--anim-marquee-dur,28s) linear infinite}
  .anim-marquee:hover .anim-marquee-track{animation-play-state:paused}
  @keyframes anim-marquee{to{transform:translateX(-50%)}}

  /* ---- Native scroll-driven enhancements (zero JS; Firefox degrades silently) ---- */
  @supports (animation-timeline: view()){
    [data-parallax]{
      animation:anim-parallax linear both;
      animation-timeline:view();
      animation-range:cover 0% cover 100%;
    }
    @keyframes anim-parallax{
      from{transform:translateY(calc(var(--parallax,6) * 1vh))}
      to{transform:translateY(calc(var(--parallax,6) * -1vh))}
    }
    .anim-progress{
      position:fixed;top:0;left:0;right:0;height:3px;z-index:999;
      background:var(--anim-accent,#111);transform-origin:0 50%;transform:scaleX(0);
      animation:anim-progress linear both;animation-timeline:scroll(root);
    }
    @keyframes anim-progress{to{transform:scaleX(1)}}
  }
}

/* ---- Grain texture overlay (static, so it lives outside the motion query).
   Kills the flat AI-render look. Keep opacity subtle (.05 to .09). ---- */
.anim-grain{position:relative;isolation:isolate}
.anim-grain::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.07;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:160px 160px;
}

/* ---- Cross-document page transitions (Chrome/Edge/Safari; others just navigate) ---- */
@view-transition{navigation:auto}
@media (prefers-reduced-motion: reduce){
  ::view-transition-old(root),::view-transition-new(root){animation:none}
}
