/* ==========================================================================
   animations.css — keyframes, scroll-reveal states, reduced-motion
   Only transform + opacity are animated.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Keyframes
   -------------------------------------------------------------------------- */
@keyframes pulse-dot {
  0%   { box-shadow: 0 0 0 0 rgba(61,220,132,.55); }
  70%  { box-shadow: 0 0 0 9px rgba(61,220,132,0); }
  100% { box-shadow: 0 0 0 0 rgba(61,220,132,0); }
}

@keyframes spin { to { transform: rotate(360deg); } }

@keyframes marquee {
  from { transform: translate3d(0,0,0); }
  to   { transform: translate3d(-50%,0,0); }
}

@keyframes rail-drop {
  0%   { transform: scaleY(0); transform-origin: top; opacity: 0; }
  40%  { transform: scaleY(1); transform-origin: top; opacity: 1; }
  60%  { transform: scaleY(1); transform-origin: bottom; opacity: 1; }
  100% { transform: scaleY(0); transform-origin: bottom; opacity: 0; }
}

@keyframes draw { to { stroke-dashoffset: 0; } }

@keyframes drawer-in {
  to { opacity: 1; transform: translateY(0); }
}

/* Ambient float loops — decorative layers only */
@keyframes float-a {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -18px, 0); }
}
@keyframes float-b {
  0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); }
  50%      { transform: translate3d(0, 14px, 0) rotate(2.5deg); }
}
@keyframes glow-breathe {
  0%, 100% { opacity: .55; transform: scale(1); }
  50%      { opacity: .95; transform: scale(1.09); }
}

/* Hero entrance */
@keyframes rise-in {
  from { opacity: 0; transform: translate3d(0, 26px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
@keyframes line-mask {
  from { opacity: 0; transform: translate3d(0, 105%, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* Beacon sweep across the truck art */
@keyframes beacon-sweep {
  0%   { opacity: 0; transform: translateX(-40%) skewX(-18deg); }
  45%  { opacity: .5; }
  100% { opacity: 0; transform: translateX(240%) skewX(-18deg); }
}

/* --------------------------------------------------------------------------
   Ambient element hooks
   -------------------------------------------------------------------------- */
.float-a { animation: float-a 8s var(--ease-io) infinite; }
.float-b { animation: float-b 11s var(--ease-io) infinite; }
.breathe { animation: glow-breathe 9s var(--ease-io) infinite; }

/* --------------------------------------------------------------------------
   Hero entrance sequence (~120ms apart)
   -------------------------------------------------------------------------- */
.js .hero__content > * { opacity: 0; }
.hero.is-ready .hero__content > * { animation: rise-in .8s var(--ease-out) forwards; }
.hero.is-ready .hero__content > *:nth-child(1) { animation-delay: .05s; }
.hero.is-ready .hero__content > *:nth-child(2) { animation-delay: .17s; }
.hero.is-ready .hero__content > *:nth-child(3) { animation-delay: .40s; }
.hero.is-ready .hero__content > *:nth-child(4) { animation-delay: .52s; }
.hero.is-ready .hero__content > *:nth-child(5) { animation-delay: .64s; }

/* Headline lines mask up individually */
.js .hero h1 .line > span { opacity: 0; transform: translate3d(0, 105%, 0); }
.hero.is-ready h1 .line > span { animation: line-mask .9s var(--ease-out) forwards; }
.hero.is-ready h1 .line:nth-child(1) > span { animation-delay: .16s; }
.hero.is-ready h1 .line:nth-child(2) > span { animation-delay: .28s; }
.hero.is-ready h1 .line:nth-child(3) > span { animation-delay: .40s; }
/* h1 itself is index 2 in the sequence — let its own animation run without the wrapper fade */
.hero.is-ready .hero__content > h1 { animation: none; opacity: 1; }

.hero__art .sweep { animation: beacon-sweep 5.5s var(--ease-io) infinite 1.4s; }

/* --------------------------------------------------------------------------
   Scroll reveal — driven by IntersectionObserver adding .is-in
   -------------------------------------------------------------------------- */
/* The hidden start state is gated behind .js, which an inline script in <head>
   sets. Without JavaScript nothing is ever hidden, so the content is always
   readable — to a person, a crawler, or a browser where the script failed. */
[data-reveal] {
  transition:
    opacity var(--t-slow) var(--ease-out),
    transform var(--t-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 26px, 0) scale(.985);
  will-change: transform, opacity;
}
.js [data-reveal="left"]  { transform: translate3d(-30px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(30px, 0, 0); }
.js [data-reveal="zoom"]  { transform: scale(.93); }

[data-reveal].is-in {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
  will-change: auto;
}

/* Count-up numbers hold their space so nothing shifts */
.stat__num { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   Reduced motion — hard stop on movement, content stays visible
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  [data-reveal],
  .hero__content > *,
  .hero h1 .line > span,
  .drawer__link {
    opacity: 1 !important;
    transform: none !important;
  }

  .marquee__track { animation: none !important; transform: none !important; }
  .float-a, .float-b, .breathe, .live-dot, .scroll-cue__rail { animation: none !important; }
  .steps__rail path { stroke-dashoffset: 0 !important; }
  .tilt { transform: none !important; }
  .parallax { transform: none !important; }
}
