/* ============================================================
   MOTION, scroll reveals and ambient animation
   ============================================================ */

/* ---------- Scroll reveal ---------- */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  will-change: opacity, transform;
}

.reveal--left  { transform: translateX(-32px); }
.reveal--right { transform: translateX(32px); }
.reveal--scale { transform: scale(0.94); }

/* Single column: the side offsets have nothing to slide from, and the one heading
   right would push the document wider than the window. Vertical only. */
@media (max-width: 859.98px) {
  .reveal--left,
  .reveal--right { transform: translateY(28px); }
}

.reveal.is-in {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* No JS: everything stays visible */
.no-js .reveal { opacity: 1; transform: none; }

/* ---------- Hero animated background ---------- */
@keyframes drift-a {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(6vw, 4vh, 0) scale(1.15); }
  100% { transform: translate3d(0, 0, 0) scale(1); }
}

@keyframes drift-b {
  0%   { transform: translate3d(0, 0, 0) scale(1.1); }
  50%  { transform: translate3d(-7vw, -3vh, 0) scale(0.95); }
  100% { transform: translate3d(0, 0, 0) scale(1.1); }
}

@keyframes scan {
  0%   { transform: translateY(-100%); opacity: 0; }
  8%   { opacity: 0.5; }
  92%  { opacity: 0.5; }
  100% { transform: translateY(1200%); opacity: 0; }
}

/* ---------- Chromatic glitch (brand signature) ---------- */
@keyframes glitch-a {
  0%, 82%, 100% { clip-path: inset(0 0 100% 0); transform: translate(0, 0); }
  84%  { clip-path: inset(12% 0 62% 0); transform: translate(calc(var(--glitch-offset) * -1.5), -1px); }
  87%  { clip-path: inset(48% 0 28% 0); transform: translate(var(--glitch-offset), 1px); }
  90%  { clip-path: inset(70% 0 8% 0);  transform: translate(calc(var(--glitch-offset) * -1), 0); }
  93%  { clip-path: inset(24% 0 54% 0); transform: translate(var(--glitch-offset), -1px); }
}

@keyframes glitch-b {
  0%, 82%, 100% { clip-path: inset(100% 0 0 0); transform: translate(0, 0); }
  85%  { clip-path: inset(58% 0 22% 0); transform: translate(var(--glitch-offset), 1px); }
  88%  { clip-path: inset(18% 0 66% 0); transform: translate(calc(var(--glitch-offset) * -1), -1px); }
  91%  { clip-path: inset(38% 0 44% 0); transform: translate(calc(var(--glitch-offset) * 1.5), 0); }
  94%  { clip-path: inset(76% 0 6% 0);  transform: translate(calc(var(--glitch-offset) * -1), 1px); }
}

/* ---------- Scroll cue ---------- */
@keyframes scroll-cue {
  0%   { transform: translateY(0); opacity: 0; }
  30%  { opacity: 1; }
  100% { transform: translateY(14px); opacity: 0; }
}

/* ---------- Axis visuals ---------- */
/* transform rather than the r attribute: needs transform-box: fill-box */
@keyframes node-pulse {
  0%, 100% { transform: scale(1);   opacity: 0.55; }
  50%      { transform: scale(1.6); opacity: 1; }
}

@keyframes link-flow {
  from { stroke-dashoffset: 60; }
  to   { stroke-dashoffset: 0; }
}

@keyframes ring-out {
  0%   { transform: scale(0.2); opacity: 0; }
  15%  { opacity: 0.9; }
  100% { transform: scale(1); opacity: 0; }
}

@keyframes spin-slow {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ---------- Active section cursor ---------- */
@keyframes blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.25; }
}

/* Reduced motion: no ambient loop */
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  .hero__glow, .hero__scan,
  .glitch__layer, .scroll-cue__dot { animation: none !important; }
}
