/* Motion helpers — GSAP drives most entrances; these are CSS-only fallbacks and ambient loops */
@keyframes scrollLine{0%{transform:scaleY(0);transform-origin:top}50%{transform:scaleY(1);transform-origin:top}51%{transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}
@keyframes modalIn{from{opacity:0;transform:translateY(30px) scale(.97)}to{opacity:1;transform:none}}
@keyframes floatY{0%,100%{transform:translateY(0)}50%{transform:translateY(-16px)}}
@keyframes drift{0%{transform:translateX(-6%)}100%{transform:translateX(106vw)}}
@keyframes spinSlow{to{transform:rotate(360deg)}}
@keyframes dash{to{stroke-dashoffset:-140}}
@keyframes pulseRing{0%{transform:scale(.6);opacity:.9}100%{transform:scale(2.2);opacity:0}}
.floaty{animation:floatY 7s ease-in-out infinite}
.floaty.d2{animation-delay:-2.4s;animation-duration:9s}.floaty.d3{animation-delay:-4.6s;animation-duration:8s}
.spin-slow{animation:spinSlow 60s linear infinite}
.route path{animation:dash 6s linear infinite}
.cloud{position:absolute;left:0;opacity:.5;animation:drift 70s linear infinite}
.ping{transform-box:fill-box;transform-origin:center;animation:pulseRing 2.4s ease-out infinite}
/* reveal initial states (only when JS flagged) */
.js [data-reveal]{opacity:0;transform:translateY(34px)}
.js [data-mask]{clip-path:inset(0 0 100% 0)}
.js .hero-title .l span{transform:translateY(110%)}
.js [data-reveal].in,.js [data-mask].in{opacity:1;transform:none;clip-path:inset(0)}
.js [data-reveal],.js [data-mask]{transition:opacity .9s var(--ease),transform .9s var(--ease),clip-path 1.2s var(--ease)}
.no-gsap .hero-title .l span{transform:none!important}
.no-gsap [data-reveal]{transition-delay:calc(var(--i,0)*90ms)}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}
  .js [data-reveal],.js [data-mask],.js .hero-title .l span{opacity:1!important;transform:none!important;clip-path:none!important}
}
