/* ==========================================================================
   Motion and interaction. Everything here animates transform and opacity,
   with two documented exceptions: grid-template-rows on the stage panels and
   FAQ answers (opens a panel of unknown height without measuring it in JS),
   and short colour changes on hover. Colours, spacing and type come from
   styles.css and typography.css.

   Motion budget:
     1. The cinematic moment is the descent (counter, rail, stage line, stage dot).
     2. Ambient motion is the hero cell, which turns, breathes and wanders.
     3. Everything else is feedback to the reader's own input.
   ========================================================================== */

:root{
  /* Critically damped spring (mass 1, stiffness 170, damping 26): no overshoot,
     which suits a medical brand better than a bouncy one. */
  --spring:linear(0,.0345,.1146,.2154,.3214,.4237,.5175,.6006,.6725,.7335,.7846,.8269,.8615,.8898,.9126,.9309,.9455,.9572,.9664,.9738,.9795,.9841,.9876,.9904,1);
  --spring-dur:530ms;
}

/* ----- Reveal on scroll: four blocks on home, opacity and 12px only ----- */
[data-reveal]{opacity:1;transform:none}
.motion-ready [data-reveal]{transition:opacity 600ms var(--ease-out),transform 600ms var(--ease-out)}
.motion-ready [data-reveal]:not(.seen){opacity:0;transform:translateY(12px)}

/* ----- Load-in: one short staggered fade, 3 steps, 600ms in total ----- */
.hero .heroinner>*,.page-hero .heroinner>*{animation:hero-enter 400ms var(--ease-out) both}
.hero .heroinner>:nth-child(2),.page-hero .heroinner>:nth-child(2){animation-delay:100ms}
.hero .heroinner>:nth-child(n+3),.page-hero .heroinner>:nth-child(n+3){animation-delay:200ms}
@keyframes hero-enter{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}

/* ----- Hero cell (protected). The living cell is at 37.0C, the warm top of the
   Preservation Line, so it moves: three slow motions on separate properties
   (rotate, scale, translate) so they stack instead of overriding each other.
   Periods of 180s, 5s and 26s share no common rhythm, so the combined motion
   never visibly loops. The lens is a separate wrapper that does not move, so
   the edge stays still while the image animates inside it. ----- */
.cell-image{animation:cell-turn 180s linear infinite,cell-breathe 5s cubic-bezier(.45,0,.55,1) infinite alternate,cell-wander 26s cubic-bezier(.45,0,.55,1) infinite alternate}
@keyframes cell-turn{from{rotate:0deg}to{rotate:360deg}}
@keyframes cell-breathe{from{scale:1}to{scale:1.045}}
@keyframes cell-wander{0%{translate:-10px 6px}35%{translate:8px -12px}70%{translate:12px 8px}100%{translate:-6px -8px}}

/* ----- Feedback: one press, no hover lift ----- */
.btnfill,.btnghost,.tiercta,.book,.section-nav a,.navtoggle,.stagehead{transition:transform 120ms ease-out,background-color .2s ease,color .2s ease,border-color .2s ease}
.btnfill:active,.btnghost:active,.tiercta:active,.book:active,.section-nav a:active{transform:scale(.98)}
.stagehead:active{transform:scale(.995)}
.navlinks a,.faqq,.speccite,.usesdoi,.reflist a,.footcol a,.postback,.editorial-link,.faqmore a,.reading-nav a,.motion-toggle{transition:color .2s ease,background-color .2s ease,border-color .2s ease}
.posttitle,.next-note a{transition:text-decoration-color .2s ease}
.postcard-frame img{transition:transform 400ms var(--ease-out)}
.postcard:hover .postcard-frame img{transform:scale(1.02)}
.navtoggle span{transition:transform .3s var(--ease-out),opacity .3s}
.counter{transition:border-color .4s,opacity .2s}
.counter .cval{transition:color .4s}

/* ----- Mobile nav drawer ----- */
@media(max-width:900px){
  .navlinks{transition:opacity .2s ease}
}

/* ----- The descent (the page's one cinematic moment). Counter and rail are
   driven by main.js on scroll. The stage line fills with scaleY from the same
   scroll progress (no extra scroll listener), the active stage's dot grows,
   and a stage's figure settles in when its panel opens. ----- */
.stages::after{transition:none}
.stagetemp::after{transition:transform 300ms var(--ease-out)}
.stage.active .stagetemp::after{transform:scale(1.6)}
.stage{transition:background-color .6s ease}
.stagechev{transition:transform var(--spring-dur) var(--spring),border-color .3s}
.stagepanel{visibility:hidden;transition:grid-template-rows var(--spring-dur) var(--spring),visibility 0s linear var(--spring-dur)}
.stagehead[aria-expanded="true"]+.stagepanel{visibility:visible;transition:grid-template-rows var(--spring-dur) var(--spring),visibility 0s}
.stagefig{opacity:0;transform:translateY(16px);transition:opacity 450ms var(--ease-out),transform 450ms var(--ease-out)}
.stagehead[aria-expanded="true"]+.stagepanel .stagefig{opacity:1;transform:none;transition-delay:120ms}
html:not(.enhanced) .stagepanel{visibility:visible}
html:not(.enhanced) .stagefig{opacity:1;transform:none}

/* ----- FAQ accordion ----- */
.faqa{transition:grid-template-rows .4s var(--ease-out),visibility .4s}
.faqa>p{transition:padding .4s var(--ease-out)}
.faqx{transition:transform .3s var(--ease-out)}
.faq.open .faqx{transform:rotate(45deg)}

/* ----- Vault image: pointer parallax (feedback to the pointer, off for touch).
   Two layers move at different rates, so depth reads as parallax rather than a
   tilt gimmick. The transform is written by main.js on every pointer move; the
   transition only smooths the settle when the pointer leaves. ----- */
.vaultphoto img{will-change:transform;transform:translate3d(var(--px,0),var(--py,0),0) scale(var(--pz,1));transition:transform var(--spring-dur) var(--spring)}
.vaultphoto.tracking img{transition:none}
.vaultsheen{position:absolute;inset:0;pointer-events:none;opacity:0;background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),var(--hair),transparent 62%);transition:opacity .45s ease}
.vaultphoto:hover .vaultsheen{opacity:1}

/* ----- Package picked: a 600ms Bronze outline pulse on the field it filled in ----- */
.selwrap::after{content:"";position:absolute;inset:-4px;border:2px solid var(--bronze);border-radius:var(--r-1);opacity:0;pointer-events:none}
.selwrap.picked::after{animation:pick-pulse 600ms ease-out}
@keyframes pick-pulse{0%{opacity:0}25%{opacity:1}100%{opacity:0}}

/* ----- Pause: the Pause button, off-screen, and hidden tabs pause ambient motion.
   Kept after the animation rules above so the equal-specificity cascade wins. ----- */
.motion-paused,.motion-paused *,.motion-paused *::before,.motion-paused *::after{animation-play-state:paused}

/* ----- Reduced motion: everything above is off. Panels open instantly, content
   is visible immediately, and the counter still updates its number (a text
   change, not an animation). ----- */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}
  [data-reveal],.motion-ready [data-reveal]:not(.seen){opacity:1!important;transform:none!important}
  .vaultphoto img{transform:none}
  .vaultsheen{display:none}
  .motion-toggle{display:none}
  .btnfill:active,.btnghost:active,.tiercta:active,.book:active,.section-nav a:active,.stagehead:active{transform:none}
  .stage.active .stagetemp::after{transform:none}
  .selwrap.picked::after{opacity:1}
}
