/* =====================================================================
   v4-motion: global motion layer (progressive enhancement only).
   Every effect here enhances an already-visible default:
   - no JS -> no text or trace is ever hidden (all hiding is gated on classes v4-motion.js adds)
   - reduced motion / body.is-motion-paused / data-experience=standard / data-scroll=false -> static
   Animated properties: transform, opacity, stroke-dashoffset (plus the 2px nav wire's anchored insets).
   ===================================================================== */
:root{--mo-ease:cubic-bezier(.16,1,.3,1)}

/* ---------- 5. Nav: current page is a live wire ---------- */
/* aria-current is set by v4-motion.js from location.pathname. */
.main-nav>a[aria-current=page]{color:var(--ink)}
.main-nav>a[aria-current=page]:after{background:var(--orange)}

/* Sliding wire via CSS anchor positioning; browsers without it keep the per-link underline above. */
@supports (anchor-name:--a) and (position-anchor:--a){
  .main-nav{position:relative}
  .main-nav>a:after{display:none}
  .main-nav>a[aria-current=page]{anchor-name:--mo-nav}
  .main-nav:has(>a:hover)>a[aria-current=page]{anchor-name:none}
  .main-nav>a:hover{anchor-name:--mo-nav}
  .main-nav:after{
    content:"";position:absolute;pointer-events:none;
    position-anchor:--mo-nav;left:anchor(left);right:anchor(right);top:calc(anchor(bottom) - 13px);
    height:2px;border-radius:2px;background:var(--orange);box-shadow:0 0 10px -1px #ff7a0099;
    opacity:0;transition:opacity .2s var(--mo-ease)
  }
  .main-nav:has(>a[aria-current=page]):after,.main-nav:has(>a:hover):after{opacity:1}
  @media (prefers-reduced-motion:no-preference){
    body:not(.is-motion-paused):not([data-experience=standard]) .main-nav:after{
      transition:left .4s var(--mo-ease),right .4s var(--mo-ease),opacity .2s var(--mo-ease)
    }
  }
}

/* ---------- 6. Header scroll progress: the existing --page-progress line becomes an orange "current" ---------- */
.site-header:after{background:var(--orange);height:1px;box-shadow:0 0 8px #ff7a0080}
@media (prefers-reduced-motion:no-preference){
  @supports (animation-timeline:scroll()){
    /* compositor-driven scaleX instead of a per-frame width write */
    body:not(.is-motion-paused) .site-header:after{
      width:100%;transform-origin:0 50%;transform:scaleX(0);
      animation:mo-progress linear both;animation-timeline:scroll(root block);
      animation-play-state:running!important
    }
  }
}
@keyframes mo-progress{to{transform:scaleX(1)}}

/* ---------- 1. Headline reveal ---------- */
/* v4-motion.js wraps words in .mo-w only when motion is allowed. Default state of every word: fully visible. */
.mo-w{display:inline-block}

@media (prefers-reduced-motion:no-preference){
  /* Primary: scroll-driven. .mo-sd is set by JS only when CSS.supports('animation-timeline: view()') and the page is the heading's scroller. */
  @supports (animation-timeline:view()){
    body:not(.is-motion-paused):not([data-experience=standard]):not([data-scroll=false]) .mo-head.mo-sd{
      view-timeline-name:--mo-head
    }
    body:not(.is-motion-paused):not([data-experience=standard]):not([data-scroll=false]) .mo-head.mo-sd .mo-w{
      animation:mo-word linear both;
      animation-timeline:--mo-head;
      animation-range:cover calc(2% + var(--i,0) * 2%) cover calc(27% + var(--i,0) * 2%);
      /* theme.css pauses all animations in off-screen sections; a scroll-linked reveal must never freeze half-hidden */
      animation-play-state:running!important
    }
  }
  /* Fallback (.mo-ob): IntersectionObserver adds .mo-pending (only to headings that start below the fold), then .mo-in. */
  body:not(.is-motion-paused):not([data-experience=standard]):not([data-scroll=false]) .mo-head.mo-ob.mo-pending .mo-w{
    opacity:0;transform:translateY(.38em)
  }
  body:not(.is-motion-paused):not([data-experience=standard]):not([data-scroll=false]) .mo-head.mo-ob.mo-in .mo-w{
    transition:opacity .55s var(--mo-ease),transform .9s var(--mo-ease);
    transition-delay:calc(var(--i,0) * 55ms)
  }
}
@keyframes mo-word{
  0%{opacity:0;transform:translateY(.38em);animation-timing-function:cubic-bezier(.16,1,.3,1)}
  60%{opacity:1}
  100%{opacity:1;transform:none}
}

/* ---------- 2. Circuit traces draw in ---------- */
/* .mo-trace--wait is only ever added by JS, only to SVGs that start below the fold, only when motion is allowed. */
.mo-node{transform-box:fill-box;transform-origin:50% 50%}
.mo-trace--wait .mo-draw{stroke-dasharray:1 1;stroke-dashoffset:1}
.mo-trace--wait .mo-node{opacity:0;transform:scale(.3)}
.mo-trace--wait .mo-sig{opacity:0!important}
.mo-trace--go .mo-draw{stroke-dasharray:1 1;transition:stroke-dashoffset var(--mo-dur,1.4s) cubic-bezier(.65,0,.35,1) var(--mo-delay,0s)}
.mo-trace--go .mo-node{transition:opacity .4s var(--mo-ease) calc(var(--mo-delay,0s) + var(--mo-dur,1.4s) * .6),transform .7s var(--mo-ease) calc(var(--mo-delay,0s) + var(--mo-dur,1.4s) * .6)}
.mo-trace--go .mo-sig{transition:opacity .8s ease calc(var(--mo-delay,0s) + var(--mo-dur,1.4s) * .85)}
body.is-motion-paused .mo-trace--go *{transition:none!important}

/* ---------- 3. Cross-document view transitions ---------- */
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
  .site-header{view-transition-name:mo-header}
  /* the sticky header stays put; only the page beneath it changes */
  ::view-transition-group(mo-header),
  ::view-transition-old(mo-header),
  ::view-transition-new(mo-header){animation:none}
  ::view-transition-old(root){animation:mo-vt-out .14s cubic-bezier(.4,0,1,1) both}
  ::view-transition-new(root){animation:mo-vt-in .26s var(--mo-ease) .08s both}
  html:has(>body[data-experience=standard])::view-transition-old(root),
  html:has(>body[data-experience=standard])::view-transition-new(root){animation:none}
}
@keyframes mo-vt-out{to{opacity:0}}
@keyframes mo-vt-in{from{opacity:0;transform:translateY(10px)}}

/* ---------- 4. Hero spotlight grid ---------- */
/* A 560px "lamp" rides the pointer (transform only); the blueprint inside it is counter-offset so the grid
   stays pinned to the hero. Dots and hairlines only, no fill, so text contrast is untouched. */
@media (prefers-reduced-motion:no-preference) and (hover:hover) and (pointer:fine){
  body:not(.is-motion-paused):not([data-experience=standard]):not([data-cursor=false]) .kinetic-hero.mo-spot:after{
    content:"";position:absolute;z-index:-1;left:0;top:0;width:560px;height:560px;pointer-events:none;
    background-image:radial-gradient(circle,#ffffff 1px,transparent 1.4px),
      linear-gradient(#ffffff70 1px,transparent 1px),linear-gradient(90deg,#ffffff70 1px,transparent 1px);
    background-size:22px 22px,110px 110px,110px 110px;
    background-position:calc(280px - var(--mo-x,0px) - 11px) calc(280px - var(--mo-y,0px) - 11px),
      calc(280px - var(--mo-x,0px)) calc(280px - var(--mo-y,0px)),calc(280px - var(--mo-x,0px)) calc(280px - var(--mo-y,0px));
    -webkit-mask-image:radial-gradient(closest-side,#000000 0,#00000088 42%,transparent 100%);
    mask-image:radial-gradient(closest-side,#000000 0,#00000088 42%,transparent 100%);
    transform:translate3d(calc(var(--mo-x,0px) - 280px),calc(var(--mo-y,0px) - 280px),0);
    opacity:0;transition:opacity .7s var(--mo-ease);will-change:transform,opacity
  }
  body:not(.is-motion-paused):not([data-experience=standard]):not([data-cursor=false]) .kinetic-hero.mo-spot.mo-lit:after{opacity:.24}
}
