/* ==========================================================================
   ANIMATIONS — scroll reveals, text effects, ambient motion
   ========================================================================== */

/* --------------------------------------------------------------------------
   SCROLL REVEAL
   Elements start hidden only when JS is available (html.js), so the page
   stays fully readable without scripts.
   -------------------------------------------------------------------------- */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity 900ms var(--ease-out),
    transform 900ms var(--ease-out),
    filter 900ms var(--ease-out);
  transition-delay: var(--delay, 0ms);
  will-change: opacity, transform;
}

.js [data-reveal="blur"] { filter: blur(8px); transform: translateY(18px); }
.js [data-reveal="left"] { transform: translateX(-34px); }
.js [data-reveal="right"] { transform: translateX(34px); }
.js [data-reveal="scale"] { transform: scale(0.965) translateY(18px); }
.js [data-reveal="clip"] {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1100ms var(--ease-out);
}

.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  filter: none;
  clip-path: inset(0 0 0 0);
}

/* Stagger helper — children animate in sequence */
.js [data-stagger] > * {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 780ms var(--ease-out), transform 780ms var(--ease-out);
}

.js [data-stagger].is-revealed > * { opacity: 1; transform: none; }
.js [data-stagger].is-revealed > *:nth-child(1)  { transition-delay: 0ms; }
.js [data-stagger].is-revealed > *:nth-child(2)  { transition-delay: 70ms; }
.js [data-stagger].is-revealed > *:nth-child(3)  { transition-delay: 140ms; }
.js [data-stagger].is-revealed > *:nth-child(4)  { transition-delay: 210ms; }
.js [data-stagger].is-revealed > *:nth-child(5)  { transition-delay: 280ms; }
.js [data-stagger].is-revealed > *:nth-child(6)  { transition-delay: 350ms; }
.js [data-stagger].is-revealed > *:nth-child(7)  { transition-delay: 420ms; }
.js [data-stagger].is-revealed > *:nth-child(8)  { transition-delay: 490ms; }
.js [data-stagger].is-revealed > *:nth-child(9)  { transition-delay: 560ms; }
.js [data-stagger].is-revealed > *:nth-child(n+10) { transition-delay: 620ms; }

/* --------------------------------------------------------------------------
   SPLIT TEXT — per-word mask reveal (used on display headings)
   -------------------------------------------------------------------------- */
.split-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.08em;
  margin-bottom: -0.08em;
}

.split-word > i {
  display: inline-block;
  font-style: inherit;
  transform: translateY(105%);
  opacity: 0;
  transition:
    transform 980ms var(--ease-out),
    opacity 700ms var(--ease-out);
  transition-delay: var(--wd, 0ms);
}

.is-revealed .split-word > i,
.split-word.is-revealed > i { transform: translateY(0); opacity: 1; }

/* --------------------------------------------------------------------------
   SCRAMBLE / DECODE — the terminal-flavoured text effect
   -------------------------------------------------------------------------- */
[data-scramble] { font-variant-ligatures: none; }

.scramble-char { transition: opacity 90ms linear; }
.scramble-char.is-noise { opacity: 0.42; }

/* --------------------------------------------------------------------------
   AMBIENT MOTION
   -------------------------------------------------------------------------- */

/* Slow float for decorative panels */
.float { animation: float 8.5s var(--ease-in-out) infinite; }

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

/* Scan line sweeping down a surface — cyber/security flavour */
.scanline { position: relative; overflow: hidden; }

.scanline::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: -30%;
  height: 30%;
  pointer-events: none;
  background: linear-gradient(180deg, transparent, var(--surface-active), transparent);
  animation: scan 6.5s var(--ease-in-out) infinite;
}

@keyframes scan {
  0%   { top: -35%; opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { top: 105%; opacity: 0; }
}

/* Border draw-in on reveal */
.draw-border { position: relative; }

.draw-border::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background:
    linear-gradient(90deg, var(--text), var(--text)) top left / var(--dl, 0%) 1px no-repeat,
    linear-gradient(90deg, var(--text), var(--text)) bottom right / var(--dl, 0%) 1px no-repeat,
    linear-gradient(180deg, var(--text), var(--text)) top right / 1px var(--dl, 0%) no-repeat,
    linear-gradient(180deg, var(--text), var(--text)) bottom left / 1px var(--dl, 0%) no-repeat;
  opacity: 0.35;
  transition: --dl 900ms var(--ease-out);
}

.draw-border.is-revealed::after { --dl: 100%; }

/* Magnetic buttons — JS sets --tx/--ty */
.magnetic {
  transition: transform 380ms var(--ease-spring);
  transform: translate(var(--tx, 0px), var(--ty, 0px));
}

/* Parallax layer — JS sets --py */
.parallax { transform: translate3d(0, var(--py, 0px), 0); will-change: transform; }

/* Tilt card — JS sets --rx/--ry */
.tilt {
  transform: perspective(1100px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 520ms var(--ease-out);
}

/* Counting number lock-in flash */
.stat__num.is-counting { color: var(--text-2); }

/* Typewriter caret for scramble headings */
.type-caret::after {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 1em;
  margin-left: 0.12em;
  background: currentColor;
  vertical-align: -0.12em;
  animation: blink 1.05s steps(2, start) infinite;
}

/* Vertical rotating word list */
.rotator {
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
  height: 1.16em;
}

.rotator > span {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(102%);
  transition: transform 720ms var(--ease-out), opacity 480ms var(--ease-out);
}

.rotator > span.is-in { opacity: 1; transform: translateY(0); }
.rotator > span.is-out { opacity: 0; transform: translateY(-102%); }

/* --------------------------------------------------------------------------
   REDUCED MOTION — strip everything non-essential
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-reveal],
  .js [data-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    clip-path: none !important;
  }

  .split-word > i { transform: none !important; opacity: 1 !important; }
  .marquee__track { animation: none; }
  .scanline::after, .cta__bg { animation: none; }
  .cursor, .cursor-dot { display: none; }
  .hero__scroll-line::after { animation: none; }
}
