/* ==========================================================================
   Reach Global Digital — Animations & Keyframes
   Every motion token is documented in docs/animations.md
   All animations honour prefers-reduced-motion (see styles.css reset)
   ========================================================================== */

/* --------------------------------------------------------------------------
   A. Keyframes
   -------------------------------------------------------------------------- */

/* A1 — Infinite ping used on live status dots */
@keyframes ping {
  0% {
    transform: scale(1);
    opacity: 0.7;
  }
  80%,
  100% {
    transform: scale(2.4);
    opacity: 0;
  }
}

/* A2 — Seamless infinite marquee (logos + skill pills) */
@keyframes marquee {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

/* A2b — 3D service marquee track. Keyframe name and motion taken verbatim from
   the Google Stitch source so the two builds stay in sync. */
@keyframes evosionInfiniteTrack {
  0% {
    transform: translate3d(0, 0, 0);
  }
  100% {
    transform: translate3d(-50%, 0, 0);
  }
}

/* A3 — Counter-free float for ambient hero glows */
@keyframes float-slow {
  0%,
  100% {
    transform: translate3d(0, 0, 0) scale(1);
  }
  50% {
    transform: translate3d(0, -24px, 0) scale(1.05);
  }
}

/* A4 — Elemental entrance (used by .is-in reveal and AJAX states) */
@keyframes slide-up {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* A5 — Fade only (backdrops, overlays) */
@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* A6 — Scale-in for badges / dots on completion */
@keyframes pop-in {
  0% {
    opacity: 0;
    transform: scale(0.85);
  }
  60% {
    transform: scale(1.04);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* A7 — Skeleton shimmer for the form submit state */
@keyframes shimmer {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}

/* A8 — Vertical ambient scroll for the hero mesh (set in JS via custom props) */
@keyframes mesh-drift {
  0% {
    background-position: 0 0, 0 0;
  }
  100% {
    background-position: 0 48px, 48px 0;
  }
}

/* A9 — Subtle attention pulse on the primary CTA (max 3 cycles, then stops) */
@keyframes cta-pulse {
  0%,
  100% {
    box-shadow: 0 1px 2px rgba(17, 24, 39, 0.06);
  }
  50% {
    box-shadow: 0 4px 18px rgba(235, 108, 1, 0.45);
  }
}

/* A10 — Star twinkle used on the 5.0 rating block */
@keyframes twinkle {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.55;
    transform: scale(0.88);
  }
}

/* --------------------------------------------------------------------------
   B. Ambient (decorative, and paused while off-screen)
   -------------------------------------------------------------------------- */
.hero-glow-a {
  animation: float-slow 14s ease-in-out infinite;
  animation-play-state: paused;
}
.hero-glow-b {
  animation: float-slow 18s ease-in-out infinite reverse;
  animation-play-state: paused;
}

/* --------------------------------------------------------------------------
   B1. In-view gating
   --------------------------------------------------------------------------
   Continuous motion is expensive and pointless while it is off-screen, and it
   keeps the compositor busy for the whole session. Every continuous animation
   therefore starts paused and is only released by an IntersectionObserver,
   which toggles `is-inview` on the owning section (see initInViewMotion in
   main.js).

   The selectors are wrapped in :where(), which contributes ZERO specificity, so
   these land at 0,1,0. That matters: animations.css is loaded AFTER styles.css,
   so a plain `.svc-marquee.is-inview .svc-marquee__track` (0,3,0) would come
   last at equal specificity with the hover/focus pause rules in styles.css and
   would silently win — breaking "pause on hover". At 0,1,0 the existing
   `.marquee-viewport:hover .marquee-track` (0,3,0) and
   `.svc-marquee:hover .svc-marquee__track` (0,3,0) still take precedence.

   Do not unwrap these. :where() needs Chrome 88 / Firefox 78 / Safari 14.
   -------------------------------------------------------------------------- */
:where(.hero.is-inview) .hero-glow-a,
:where(.hero.is-inview) .hero-glow-b,
:where(.marquee-band.is-inview) .marquee-track,
:where(.svc-marquee.is-inview) .svc-marquee__track {
  animation-play-state: running;
}

/* --------------------------------------------------------------------------
   C. Interaction-driven micro-animations
   -------------------------------------------------------------------------- */

/* Underline sweep for text links in the CTA + footer */
.link-underline {
  position: relative;
}
.link-underline::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}
.link-underline:hover::after,
.link-underline:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Gradient border sweep on primary buttons */
.btn-primary {
  position: relative;
  overflow: hidden;
}
.btn-primary::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg, transparent 20%, rgba(255, 255, 255, 0.28) 50%, transparent 80%);
  transform: translateX(-120%);
  transition: transform 0.6s var(--ease);
}
.btn-primary:hover::before {
  transform: translateX(120%);
}

/* Card tilt-ready wrapper (JS adds the transform) */
.tilt {
  transform-style: preserve-3d;
  transition: transform 0.4s var(--ease);
}

/* Rating stars */
.stars.is-animating .icon {
  animation: twinkle 0.5s var(--ease) both;
}
.stars.is-animating .icon:nth-child(2) { animation-delay: 0.06s; }
.stars.is-animating .icon:nth-child(3) { animation-delay: 0.12s; }
.stars.is-animating .icon:nth-child(4) { animation-delay: 0.18s; }
.stars.is-animating .icon:nth-child(5) { animation-delay: 0.24s; }

/* Number roll on the metric strip (JS sets the final text) */
.metric-value {
  display: inline-block;
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   D. State animations
   -------------------------------------------------------------------------- */

/* Button loading */
.btn.is-loading {
  pointer-events: none;
  color: transparent !important;
  position: relative;
}
.btn.is-loading::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  animation: spin 0.7s linear infinite;
}
.btn-outline.is-loading::after,
.btn-ghost.is-loading::after {
  border-color: rgba(17, 24, 39, 0.2);
  border-top-color: var(--ink);
}
.btn-ghost.is-loading::after {
  border-color: rgba(255, 255, 255, 0.3);
  border-top-color: #fff;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* Card skeleton while the audit form is submitting */
.is-submitting .form-grid {
  opacity: 0.45;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/* Success banner pop */
.form-success.is-visible .icon {
  animation: pop-in 0.5s var(--ease) both;
}

/* Mobile drawer staggered link entrance */
.mobile-drawer.is-open .drawer-link {
  animation: slide-up 0.4s var(--ease) both;
}
.mobile-drawer.is-open .drawer-link:nth-child(1) { animation-delay: 0.04s; }
.mobile-drawer.is-open .drawer-link:nth-child(2) { animation-delay: 0.08s; }
.mobile-drawer.is-open .drawer-link:nth-child(3) { animation-delay: 0.12s; }
.mobile-drawer.is-open .drawer-link:nth-child(4) { animation-delay: 0.16s; }
.mobile-drawer.is-open .drawer-link:nth-child(5) { animation-delay: 0.2s; }

/* Phase cards: sequential connect line */
.phase-card::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brand), transparent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.55s var(--ease);
}
.phase-card:hover::after {
  transform: scaleX(1);
}
