/* ==========================================================================
   ANIMATIONS — scroll entrances, keyframes, floating elements
   Everything here is opt-in via prefers-reduced-motion: no-preference.
   ========================================================================== */

/* ---- Scroll-triggered entrances ----------------------------------------
   FAIL-SAFE BY DESIGN. Content is visible by default; it is only hidden once
   JS has confirmed it can reveal it again (the `.js` class is set by an inline
   script in <head>). So if JS fails, is blocked, or the observer misses an
   element, the page still reads perfectly — a decorative animation can never
   permanently swallow content.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion:no-preference){
  .js .reveal{
    opacity:0;
    transform:translateY(28px) scale(.985);
    filter:blur(6px);
    transition:opacity var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms),
               transform var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms),
               filter var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms);
  }
  .js .reveal.is-in{opacity:1;transform:none;filter:none}

  .js .reveal-l{opacity:0;transform:translateX(-34px);
    transition:opacity var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms),
               transform var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms)}
  .js .reveal-r{opacity:0;transform:translateX(34px);
    transition:opacity var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms),
               transform var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms)}
  .js .reveal-l.is-in,.js .reveal-r.is-in{opacity:1;transform:none}

  .js .reveal-s{opacity:0;transform:scale(.94);
    transition:opacity var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms),
               transform var(--t-enter) var(--ease-out) calc(var(--i,0) * 70ms)}
  .js .reveal-s.is-in{opacity:1;transform:none}
}

/* Hero headline: lines rise from behind an overflow mask. */
@media (prefers-reduced-motion:no-preference){
  .js .hero__line > span{transform:translateY(105%);opacity:0}
  .js .hero.is-ready .hero__line > span{
    transform:none;opacity:1;
    transition:transform 880ms var(--ease-out) calc(var(--i,0) * 110ms),
               opacity 880ms var(--ease-out) calc(var(--i,0) * 110ms);
  }
  .js .hero__fade{opacity:0;transform:translateY(20px)}
  .js .hero.is-ready .hero__fade{
    opacity:1;transform:none;
    transition:opacity 760ms var(--ease-out) calc(420ms + var(--i,0) * 110ms),
               transform 760ms var(--ease-out) calc(420ms + var(--i,0) * 110ms);
  }
}

/* ---- Keyframes --------------------------------------------------------- */
@keyframes drift{
  0%  {transform:translate3d(0,0,0) scale(1)}
  50% {transform:translate3d(2.5%,-2%,0) scale(1.06)}
  100%{transform:translate3d(-2%,2.5%,0) scale(1.02)}
}
@keyframes cue{
  0%,100%{transform:scaleY(.3);transform-origin:top;opacity:.35}
  50%    {transform:scaleY(1);transform-origin:top;opacity:1}
}
@keyframes pulseGlow{
  0%,100%{box-shadow:var(--sh-2),0 0 0 0 rgba(224,27,34,.45)}
  55%    {box-shadow:var(--sh-red),0 0 0 14px rgba(224,27,34,0)}
}
@keyframes ringWobble{
  0%,88%,100%{transform:rotate(0)}
  90%{transform:rotate(-13deg)} 92%{transform:rotate(11deg)}
  94%{transform:rotate(-8deg)}  96%{transform:rotate(5deg)}  98%{transform:rotate(-2deg)}
}
@keyframes floatY{
  0%,100%{transform:translateY(0) rotate(0)}
  50%    {transform:translateY(-16px) rotate(4deg)}
}
@keyframes dashRun{ to{stroke-dashoffset:0} }
@keyframes markerPulse{
  0%,100%{r:4;opacity:1}
  50%    {r:7;opacity:.45}
}
@keyframes chromeSweep{
  0%  {background-position:-180% 0}
  100%{background-position:280% 0}
}

/* ---- Floating background glyphs ---------------------------------------- */
.floaty{position:absolute;pointer-events:none;color:var(--chrome-500);opacity:.07;z-index:-1}
@media (prefers-reduced-motion:no-preference){
  .floaty{animation:floatY var(--dur,8s) var(--ease-mech) infinite;animation-delay:var(--delay,0s)}
}
.floaty svg{width:100%;height:100%}
@media (max-width:640px){ .floaty{display:none} }

/* ---- Route map (the "we come to you" SVG) ------------------------------ */
.routemap{width:100%;height:auto;overflow:visible}
.routemap .road{
  fill:none;stroke:var(--slate);stroke-width:2;stroke-linecap:round;
}
.routemap .trace{
  fill:none;stroke:url(#routeGrad);stroke-width:3;stroke-linecap:round;
  stroke-dasharray:var(--len,1200);stroke-dashoffset:var(--len,1200);
}
.routemap.is-in .trace{animation:dashRun 2.6s var(--ease-out) forwards}
@media (prefers-reduced-motion:reduce){
  .routemap .trace{stroke-dashoffset:0}
}
.routemap .marker{fill:var(--blue-400)}
@media (prefers-reduced-motion:no-preference){
  .routemap.is-in .marker{animation:markerPulse 2.4s var(--ease-mech) infinite}
  .routemap.is-in .marker:nth-of-type(2){animation-delay:.5s}
  .routemap.is-in .marker:nth-of-type(3){animation-delay:1s}
}
.routemap .outline{fill:rgba(10,132,232,.05);stroke:rgba(10,132,232,.28);stroke-width:1.5}
.route-label{
  position:absolute;padding:.45rem .8rem;border-radius:var(--r-pill);
  font-size:var(--fs-xs);font-weight:600;color:var(--ink-2);white-space:nowrap;
  background:var(--glass);border:1px solid var(--glass-line);box-shadow:var(--sh-1);
}
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .route-label{-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur)}
}

/* ---- Ring wobble on the top-bar phone icon ----------------------------- */
@media (prefers-reduced-motion:no-preference){
  .ring-ico{animation:ringWobble 2s var(--ease-mech) infinite;transform-origin:50% 20%}
}

/* ---- Chrome sweep across a headline ------------------------------------ */
@media (prefers-reduced-motion:no-preference){
  .sweep{background-size:220% 100%;animation:chromeSweep 7s linear infinite}
}

/* ---- FLIP reflow for filtered review grids ----------------------------- */
.flip-move{transition:transform 460ms var(--ease-out)}
.review-grid > .is-hidden{display:none}

/* ==========================================================================
   REDUCED MOTION — hard stop. Content stays fully visible and functional.
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
  .reveal,.reveal-l,.reveal-r,.reveal-s,
  .hero__line > span,.hero__fade{
    opacity:1!important;transform:none!important;filter:none!important;
  }
  .floaty,.hero__aurora,.hero__cue{display:none!important}
  .tilt{transform:none!important}
  .tilt__inner{transform:none!important}
  .tilt__spec{display:none}
  .steps::before{transform:scaleX(1)!important}
}
