/* ===========================================================================
   animations.css — keyframes, scroll-reveal system, reduced-motion master.
   Loaded LAST so the reduced-motion overrides win.
   =========================================================================== */

/* ---------------------------- 1. SCROLL REVEAL --------------------------- */
/* Scoped to .js so content is only hidden when JS can reveal it (see the gate
   script in <head>). Without JS, no .js class → elements keep opacity:1.

   We animate `opacity` + the individual `translate` property (NOT `transform`),
   so reveal never fights the 3D `transform` used by .tilt cards. The transition
   is declared in longhand so the stagger delay applies to opacity/translate
   only, while `transform` (tilt) keeps a 0s delay and its own short duration. */
.js [data-reveal] {
  opacity: 0;
  translate: 0 24px;
  /* box-shadow + border-color are listed too: this longhand fully replaces the
     `transition` shorthand on .tilt cards (which also carry data-reveal), so we
     must re-declare every property .tilt eases or its hover shadow/border snaps. */
  transition-property: opacity, translate, transform, box-shadow, border-color;
  transition-duration: 0.8s, 0.8s, 0.18s, 0.4s, 0.3s;
  transition-timing-function: var(--ease), var(--ease), var(--ease), var(--ease), var(--ease);
  transition-delay: calc(var(--i, 0) * 60ms), calc(var(--i, 0) * 60ms), 0s, 0s, 0s;
  will-change: opacity, translate;
}
.js [data-reveal].in { opacity: 1; translate: 0 0; }

/* ------------------------------ 2. KEYFRAMES ----------------------------- */
@keyframes menuIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

/* Hero wireframe cube — slow rotation with a slight fixed tilt */
@keyframes spin3d {
  from { transform: rotateX(-22deg) rotateY(0deg); }
  to   { transform: rotateX(-22deg) rotateY(360deg); }
}

/* Orbit rings */
@keyframes spinZ {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Approach layered planes — gentle float that PRESERVES the isometric tilt */
@keyframes floatY {
  0%, 100% { transform: rotateX(56deg) rotateZ(44deg) translateY(0); }
  50%      { transform: rotateX(56deg) rotateZ(44deg) translateY(-14px); }
}

/* Data dot travelling along a connector path */
@keyframes flowAlong {
  from { offset-distance: 0%;   opacity: 0; }
  10%  { opacity: 1; }
  90%  { opacity: 1; }
  to   { offset-distance: 100%; opacity: 0; }
}

/* Connector accent sweep — ONE-SHOT on scroll-in (not a perpetual marquee).
   A single accent band travels across once, then settles to a plain hairline. */
@keyframes flowDrawH {
  from { background-position: -60% 0, 0 0; }
  to   { background-position:  160% 0, 0 0; }
}
@keyframes flowDrawV {
  from { background-position: 0 -60%, 0 0; }
  to   { background-position: 0  160%, 0 0; }
}

/* Subtle scroll cue bob */
@keyframes cueBob {
  0%, 100% { transform: translateY(0); opacity: 0.7; }
  50%      { transform: translateY(4px); opacity: 1; }
}
.scroll-cue svg { animation: cueBob 2.4s ease-in-out infinite; }

/* ----------------------- 3. REDUCED-MOTION MASTER ------------------------ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  /* Reveal: show everything, no movement */
  .js [data-reveal] {
    opacity: 1 !important;
    translate: 0 0 !important;
    transition: none !important;
  }

  /* Kill 3D tilt + interior depth offsets */
  .tilt { transform: none !important; }
  .tilt .tile-icon,
  .tilt .tile-figure,
  .tilt .tile-title { transform: none !important; }

  /* Freeze decorative motion */
  .cube3d, .orbit--a, .orbit--b, .planes3d, .scroll-cue svg { animation: none !important; }
  .flow-dot { display: none !important; }
  .flow-step + .flow-step::before { animation: none !important; }

  /* Global belt-and-suspenders */
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
