/* =============================================================================
   16. MOTION & ACCESSIBILITY
   Shared keyframes referenced by name throughout the file, plus a global
   reduced-motion override so animation always respects user preference.
   ============================================================================= */
/* Shared @keyframes referenced by name throughout every section file above, plus the global prefers-reduced-motion override. Load this AFTER the sections that reference these keyframes is fine — @keyframes are hoisted — but it stays here to match the original numbering. */
@keyframes glow-pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 0.85; }
}

@keyframes reveal-up {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes float-a {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-12px); }
}

@keyframes float-b {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(10px); }
}

@keyframes dot-travel {
  0%, 100% { left: 4%; opacity: 0; }
  15% { opacity: 1; }
  50% { left: 92%; opacity: 1; }
  65% { opacity: 0; }
}

@keyframes core-ring {
  0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.5; }
  50% { transform: translate(-50%, -50%) scale(1.18); opacity: 0.15; }
}

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

/* Hero image: subtle idle float, independent of the trust-marquee scroll. */
@keyframes hero-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

/* Services network connector pulse: a single short dash (24px) travels
   outward from the hub, then a long gap (500px) before it repeats — one
   visible "pulse of energy" per cycle, not continuous marching ants. The
   offset target matches the dasharray cycle length (24 + 500 = 524) so
   each loop lines up seamlessly regardless of the path's actual length. */
@keyframes services-dash-flow {
  to { stroke-dashoffset: -524; }
}

/* Hero trust strip: right-to-left marquee. The track holds two identical
   item sets, so translating exactly -50% loops without a visible seam. */
@keyframes trust-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Featured Capability carousel auto-rotation. Each slide gets a staggered
   animation-delay (see section 11) so only one is visible at a time
   across the shared 20s / 5-slide cycle. */
@keyframes carousel-autoplay {
  0% { opacity: 0; transform: translateX(16px); }
  3% { opacity: 1; transform: translateX(0); }
  20% { opacity: 1; transform: translateX(0); }
  23% { opacity: 0; transform: translateX(-16px); }
  100% { opacity: 0; }
}

/* Glitch heading effect: one short, one-shot RGB-channel-split jitter,
   triggered on hover/focus only (see effects.css) — not a looping animation. */
@keyframes glitch-shift-1 {
  0% { transform: translate(0, 0); }
  50% { transform: translate(-3px, 1px); }
  100% { transform: translate(0, 0); }
}

@keyframes glitch-shift-2 {
  0% { transform: translate(0, 0); }
  50% { transform: translate(3px, -1px); }
  100% { transform: translate(0, 0); }
}

/* Scanline texture drift, used on .hero__visual::after / .platform__panel::after. */
@keyframes scanline-drift {
  from { background-position: 0 0; }
  to { background-position: 0 40px; }
}

/* Holographic border sweep, used on .platform__panel:hover / .services__node:hover. */
@keyframes holographic-sweep {
  0% { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}

/* Boot sequence: logo halo pulse, staggered line fade-in, progress fill,
   and the final overlay wipe that reveals the hero underneath. See
   css/components/boot-sequence.css for the element structure. */
@keyframes boot-halo-pulse {
  0%, 100% { opacity: 0.35; transform: scale(1); }
  50% { opacity: 0.6; transform: scale(1.08); }
}

@keyframes boot-line-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes boot-progress-fill {
  from { width: 0%; }
  to { width: 100%; }
}

@keyframes boot-wipe {
  0%, 80% { opacity: 1; }
  100% { opacity: 0; visibility: hidden; }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  /* Without this, the forced 1-iteration/0.01ms animation above would
     settle on the keyframe's final (opacity: 0) frame, hiding every
     slide. Freeze on slide 1 instead; manual selection still overrides
     it via the higher-specificity #id rules in section 11. */
  .carousel__image,
  .carousel__slide {
    animation: none !important;
    opacity: 0 !important;
  }

  #capability-image-1,
  #capability-panel-1 {
    opacity: 1 !important;
  }

  /* Glitch text: freeze to a static, unglitched frame rather than a
     mid-jitter one. */
  .glitch-text::before,
  .glitch-text::after {
    animation: none !important;
    opacity: 0 !important;
  }

  /* Boot sequence: skip entirely rather than collapsing to a 0.01ms flash —
     animation-delay isn't touched by the rule above, so without this the
     overlay would still sit on screen, fully opaque, for its whole delay
     before vanishing in a flash. */
  .boot {
    animation: none !important;
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none !important;
  }
}
