/* ============================================================
   NeuroRoute site — motion layer
   Purely additive: no colour, type, spacing or copy is changed here.
   Everything is (a) scroll-reveal, (b) idle loops on decorative figures,
   (c) hover affordances. One kill switch at the bottom for users who ask
   for reduced motion.
   ============================================================ */

/* ---------- scroll reveal ---------- */
/* Every hidden start-state below is gated behind .mo on <html>, which
   site-motion.js adds only after a real animation frame has run. In any
   context that cannot paint — background tab, offscreen iframe, print, PDF or
   html-to-image capture — the class is never added, no start-state applies,
   and the page renders complete. Transitions and animations both freeze
   without frames, so this gate, not a fill mode, is what makes it safe. */
.mo .rv:not(.rv-in){opacity:0;transform:translateY(16px)}
.rv-in{opacity:1;transform:none;transition:opacity .5s ease var(--rvd,0ms),transform .62s cubic-bezier(.2,.8,.3,1) var(--rvd,0ms)}
.mo .rv-scale:not(.rv-in){opacity:0;transform:scale(.965)}
.rv-scale.rv-in{opacity:1;transform:none;transition:opacity .45s ease var(--rvd,0ms),transform .5s cubic-bezier(.2,.8,.3,1) var(--rvd,0ms)}

/* ---------- tiles & icons ---------- */
/* Reveal decorations are transition-driven, never keyframe-driven: an
   animation that has started but cannot advance (background tab, offscreen
   iframe, print, html-to-image capture) resolves to its 0% frame and would
   hide content. A transition always resolves to its visible target. */
.tile{will-change:transform}
.tile:hover{transform:translateY(-3px);border-color:var(--accent-line);box-shadow:0 12px 34px rgba(0,0,0,.16)}
.tile-ico{transition:transform .34s cubic-bezier(.2,.9,.3,1),background .2s,color .2s,opacity .3s}
.mo .rv:not(.rv-in)>.tile-ico{opacity:0;transform:scale(.62) rotate(-10deg)}
.tile:hover .tile-ico{transform:translateY(-1px) scale(1.08);background:var(--accent);color:var(--on-accent)}
/* icons keep a slow idle float — frame 0 is the resting position, so a frozen
   animation is indistinguishable from the static icon */
.tile-ico{animation:icoIdle 5.2s ease-in-out infinite}
@keyframes icoIdle{0%,100%{transform:none}30%{transform:translateY(-2.5px) rotate(-3deg)}62%{transform:translateY(1px) rotate(2deg)}}
.tile:nth-child(2) .tile-ico{animation-delay:-.7s}
.tile:nth-child(3) .tile-ico{animation-delay:-1.4s}
.tile:nth-child(4) .tile-ico{animation-delay:-2.1s}
.tile:nth-child(5) .tile-ico{animation-delay:-2.8s}
.tile:nth-child(6) .tile-ico{animation-delay:-3.5s}
.tile:nth-child(7) .tile-ico{animation-delay:-4.2s}
.tile:nth-child(8) .tile-ico{animation-delay:-4.9s}
.tile:hover .tile-ico{animation-play-state:paused}
.tile-ico svg{transition:transform .3s cubic-bezier(.2,.9,.3,1)}
.tile:hover .tile-ico svg{transform:rotate(-8deg) scale(1.06)}
/* hero proof icons drift on the same idle loop as the tile icons */
.hproof-ic{animation:icoIdle 5.2s ease-in-out infinite}
.hproof-i:nth-child(2) .hproof-ic{animation-delay:-1.7s}
.hproof-i:nth-child(3) .hproof-ic{animation-delay:-3.4s}

/* ---------- tables ---------- */
.spec tbody tr,.cmp tbody tr{transition:background .18s}
.spec tbody tr:hover,.cmp tbody tr:not(.grp):hover{background:var(--inset)}
.spec tbody tr.win td{animation:winGlow 4.2s ease-in-out 1.2s infinite}
@keyframes winGlow{0%,100%{background:var(--pos-soft)}50%{background:color-mix(in oklab,var(--pos-soft) 60%,transparent)}}
/* meters grow from zero once their row is on screen — the inline width stays
   the source of truth, the transform only reveals it */
.meter>span{transform-origin:left;transition:transform .85s cubic-bezier(.2,.8,.3,1)}
.mo .rv:not(.rv-in) .meter>span{transform:scaleX(0)}
.pill{transition:transform .16s,opacity .3s}
.mo .rv:not(.rv-in) .pill-p{opacity:0;transform:scale(.74)}

/* ---------- numbered step flow ---------- */
.step-n{transition:transform .4s cubic-bezier(.2,.9,.3,1),background .25s,color .25s,opacity .35s}
.mo .rv:not(.rv-in) .step-n{opacity:0;transform:scale(.74)}
.step:hover .step-n{transform:scale(1.1);background:var(--accent);color:var(--on-accent)}

/* ---------- glance card ---------- */
.glance-row{transition:background .18s}
.glance-row:hover{background:var(--inset)}

/* ---------- code blocks: lines write in ---------- */
.code>div{transition:opacity .3s ease,transform .3s ease}
.mo .code.rv:not(.rv-in)>div{opacity:0;transform:translateX(-6px)}
.code>div:nth-child(1){transition-delay:.02s}.code>div:nth-child(2){transition-delay:.06s}
.code>div:nth-child(3){transition-delay:.1s}.code>div:nth-child(4){transition-delay:.14s}
.code>div:nth-child(5){transition-delay:.18s}.code>div:nth-child(6){transition-delay:.22s}
.code>div:nth-child(7){transition-delay:.26s}.code>div:nth-child(8){transition-delay:.3s}
.code>div:nth-child(9){transition-delay:.34s}.code>div:nth-child(10){transition-delay:.38s}
.code>div:nth-child(11){transition-delay:.42s}.code>div:nth-child(12){transition-delay:.46s}
.code>div:nth-child(13){transition-delay:.5s}.code>div:nth-child(14){transition-delay:.54s}
.code>div:nth-child(n+15){transition-delay:.58s}

/* ---------- calculator: bars ease instead of jumping ---------- */
.cx-fill{transition:width .5s cubic-bezier(.2,.8,.3,1)}
.cx-tierbtn,.cx-trow{will-change:transform}
.cx-tierbtn:active,.cx-trow:active{transform:scale(.985)}

/* ---------- routing-rules panel ---------- */
.rr-row{transition:background .2s}
.rr-row:hover{background:var(--inset)}
.rr-select{transition:border-color .2s,transform .2s}
.rr-row:hover .rr-select{border-color:var(--accent-line)}
.rr-count{animation:countBreathe 3.6s ease-in-out infinite}
@keyframes countBreathe{0%,100%{box-shadow:0 0 0 0 var(--accent-soft)}50%{box-shadow:0 0 0 5px transparent}}

/* ---------- ambient drift behind chapter heroes ---------- */
.hero{position:relative;overflow:hidden}
.hero>*{position:relative;z-index:1}
.hero:before{content:"";position:absolute;top:-30%;left:-10%;width:70%;height:150%;pointer-events:none;z-index:0;
  background:radial-gradient(50% 50% at 50% 50%,var(--accent-soft),transparent 70%);opacity:.75;
  animation:heroDrift 26s ease-in-out infinite alternate}
@keyframes heroDrift{0%{transform:translate3d(0,0,0) scale(1)}100%{transform:translate3d(22%,8%,0) scale(1.15)}}

/* ============================================================
   Decorative figures — text-free, theme-driven, idle loops.
   One per chapter, sitting under the At-a-glance card.
   ============================================================ */
.fig{margin-top:14px;border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);
  padding:14px 16px;overflow:hidden}
.fig svg{display:block;width:100%;height:auto;max-height:190px}
.fig-tall{padding:18px}

/* Every loop below starts AND ends on the figure's visible resting state, so a
   frozen animation (no frames available) still shows complete artwork. */

/* lanes (capabilities) */
.fg-lane-dot{animation:laneRun 3.4s linear infinite}
.fg-lane:nth-child(1) .fg-lane-dot{animation-duration:2.2s}
.fg-lane:nth-child(2) .fg-lane-dot{animation-duration:3.1s;animation-delay:-.4s}
.fg-lane:nth-child(3) .fg-lane-dot{animation-duration:2.6s;animation-delay:-1.1s}
.fg-lane:nth-child(4) .fg-lane-dot{animation-duration:4.1s;animation-delay:-.7s}
.fg-lane:nth-child(5) .fg-lane-dot{animation-duration:3.6s;animation-delay:-2s}
@keyframes laneRun{0%{transform:translateX(0);opacity:1}92%{opacity:1}100%{transform:translateX(248px);opacity:1}}

/* pipeline (how it works) */
.fg-pkt{animation:pktRun 4.4s cubic-bezier(.5,0,.5,1) infinite}
@keyframes pktRun{0%{transform:translateX(0)}22%{transform:translateX(0)}30%{transform:translateX(74px)}47%{transform:translateX(74px)}55%{transform:translateX(148px)}72%{transform:translateX(148px)}80%{transform:translateX(222px)}100%{transform:translateX(222px)}}
.fg-node{animation:nodeLit 4.4s linear infinite}
.fg-node:nth-of-type(1){animation-delay:0s}.fg-node:nth-of-type(2){animation-delay:1.1s}
.fg-node:nth-of-type(3){animation-delay:2.2s}.fg-node:nth-of-type(4){animation-delay:3.3s}
@keyframes nodeLit{0%,4%{opacity:1}26%,100%{opacity:.28}}

/* compression (enterprise) */
.fg-bar{transform-origin:left;animation:barSquash 5s cubic-bezier(.5,0,.3,1) infinite}
.fg-bar:nth-of-type(1){animation-delay:0s}.fg-bar:nth-of-type(2){animation-delay:.16s}
.fg-bar:nth-of-type(3){animation-delay:.32s}.fg-bar:nth-of-type(4){animation-delay:.48s}
.fg-bar:nth-of-type(5){animation-delay:.64s}.fg-bar:nth-of-type(6){animation-delay:.8s}
@keyframes barSquash{0%,14%{transform:scaleX(1)}44%,72%{transform:scaleX(.42)}100%{transform:scaleX(1)}}

/* shield (security) */
.fg-ring{transform-origin:center;animation:ringOut 3.6s ease-out infinite}
.fg-ring:nth-of-type(2){animation-delay:1.2s}.fg-ring:nth-of-type(3){animation-delay:2.4s}
@keyframes ringOut{0%{transform:scale(.5);opacity:.7}100%{transform:scale(1.5);opacity:0}}
.fg-scan{animation:scanSweep 3.2s ease-in-out infinite}
@keyframes scanSweep{0%,100%{transform:translateY(-24px);opacity:.9}50%{transform:translateY(24px);opacity:.9}}

/* gauge (pricing) — dash offset lives only in the keyframes, and frame 0 is
   the settled reading, so the resting artwork is a drawn gauge */
.fg-arc{stroke-dasharray:170;animation:arcFill 4.6s cubic-bezier(.3,.9,.3,1) infinite}
@keyframes arcFill{0%{stroke-dashoffset:58}9%{stroke-dashoffset:170}52%,78%{stroke-dashoffset:58}100%{stroke-dashoffset:58}}
.fg-needle{transform-origin:150px 84px;animation:needleSwing 4.6s cubic-bezier(.3,.9,.3,1) infinite}
@keyframes needleSwing{0%{transform:rotate(6deg)}9%{transform:rotate(-78deg)}52%,78%{transform:rotate(6deg)}100%{transform:rotate(6deg)}}

/* matrix (compare) */
.fg-cell{animation:cellFill 5.2s ease-in-out infinite}
@keyframes cellFill{0%,100%{opacity:1}14%{opacity:.16}40%,84%{opacity:1}}

/* ramp (start) */
.fg-ramp-line{stroke-dasharray:300;animation:rampDraw 5s ease-in-out infinite}
@keyframes rampDraw{0%{stroke-dashoffset:0}8%{stroke-dashoffset:300}52%,80%{stroke-dashoffset:0}100%{stroke-dashoffset:0}}
.fg-ramp-fill{animation:rampFade 5s ease-in-out infinite}
@keyframes rampFade{0%{opacity:.5}14%{opacity:0}55%,80%{opacity:.5}100%{opacity:.5}}
.fg-ramp-step{animation:cellFill 5s ease-in-out infinite}

/* written lines (blog) */
.fg-ln{transform-origin:left;animation:lnWrite 6s ease-in-out infinite}
@keyframes lnWrite{0%{transform:scaleX(1);opacity:1}7%{transform:scaleX(0);opacity:0}20%{opacity:1}34%,86%{transform:scaleX(1);opacity:1}100%{transform:scaleX(1);opacity:1}}

/* ---------- respect the OS setting ---------- */
@media (prefers-reduced-motion:reduce){
  .rv,.rv-scale{opacity:1;transform:none}
  .rv:not(.rv-in)>.tile-ico,.rv:not(.rv-in) .pill-p,.rv:not(.rv-in) .step-n{opacity:1;transform:none}
  .rv:not(.rv-in) .meter>span{transform:scaleX(1)}
  .code.rv:not(.rv-in)>div{opacity:1;transform:none}
  .hero:before{animation:none}
  .fig *,.spec tbody tr.win td,.rr-count{animation:none!important}
  .fg-needle{transform:rotate(6deg)}
  .fg-bar{transform:scaleX(.42)}
  .tile:hover{transform:none}
}
