/* =========================================================================
   LGD — animations.css
   Keyframes + reveal states. Everything here degrades to "already visible"
   under prefers-reduced-motion (see the block at the bottom of the file).
   ========================================================================= */

/* ------------------------- 1. REVEAL PRIMITIVES ----------------------- */
/* Elements start hidden and are switched on by IntersectionObserver in
   scroll.js, which adds .is-revealed. If JS never runs, the no-js safety
   net at the bottom of this file makes everything visible anyway. */

[data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity 0.85s var(--ease-out),
    transform 0.85s var(--ease-out);
  transition-delay: var(--reveal-delay, 0s);
}
[data-reveal="left"]  { transform: translateX(-32px); }
[data-reveal="right"] { transform: translateX(32px); }
[data-reveal="scale"] { transform: scale(0.94); }
[data-reveal="blur"]  { filter: blur(10px); transition-property: opacity, transform, filter; }

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Word-by-word headline reveal (spans injected by main.js). */
/* overflow:hidden is what makes the words rise out of nothing — the padding
   trick keeps descenders (g, y, p) from being clipped by that same rule. */
.split-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.split-word {
  display: inline-block;
  transform: translateY(105%);
  transition: transform 0.95s var(--ease-out);
  transition-delay: var(--word-delay, 0s);
  will-change: transform;
}
.is-revealed .split-word,
.split-ready .split-word { transform: translateY(0); }

/* ---------------------------- 2. LOADER ------------------------------- */

/* Gold particles converging into the circular icon mark: the mark's strokes
   draw themselves on, then the whole thing pulses once and lifts. */
.loader__mark [data-draw] {
  stroke-dasharray: var(--len, 300);
  stroke-dashoffset: var(--len, 300);
  animation: mark-draw 1.05s var(--ease-out) forwards;
  animation-delay: var(--draw-delay, 0s);
}
@keyframes mark-draw { to { stroke-dashoffset: 0; } }

.loader__mark { animation: mark-breathe 2.4s var(--ease-soft) 1s infinite; }
@keyframes mark-breathe {
  0%, 100% { filter: drop-shadow(0 0 6px rgba(254, 213, 4, 0.35)); }
  50%      { filter: drop-shadow(0 0 22px rgba(254, 213, 4, 0.75)); }
}

.loader__bar i { animation: load-fill 1.6s var(--ease-out) forwards; }
@keyframes load-fill { to { width: 100%; } }

/* ----------------------------- 3. HERO -------------------------------- */

.hero__ring-fallback { animation: ring-drift 26s linear infinite; }
@keyframes ring-drift {
  0%   { transform: translate(-50%, -50%) rotate(0deg)   scale(1); }
  50%  { transform: translate(-50%, -50%) rotate(180deg) scale(1.045); }
  100% { transform: translate(-50%, -50%) rotate(360deg) scale(1); }
}

.hero__scroll i { animation: scroll-hint 2.1s var(--ease-soft) infinite; transform-origin: top; }
@keyframes scroll-hint {
  0%        { transform: scaleY(0);   opacity: 0; }
  35%       { transform: scaleY(1);   opacity: 1; }
  100%      { transform: scaleY(1);   opacity: 0; transform-origin: bottom; }
}

/* Hero proof number gets a slow gold breath so the eye lands on it. */
.hero__proof-value { animation: proof-pulse 4.5s var(--ease-soft) infinite; }
@keyframes proof-pulse {
  0%, 100% { text-shadow: 0 0 18px rgba(254, 213, 4, 0.25); }
  50%      { text-shadow: 0 0 38px rgba(254, 213, 4, 0.55); }
}

/* -------------------------- 4. IMAGE RAY SWEEP ------------------------ */

.shot.is-revealed .shot__ray { animation: ray-sweep 1.5s var(--ease-out) 0.15s forwards; }
@keyframes ray-sweep {
  0%   { transform: translateX(-120%); opacity: 0; }
  22%  { opacity: 0.9; }
  100% { transform: translateX(120%);  opacity: 0; }
}

/* ------------------------- 5. 3-IN-1 DIAGRAM -------------------------- */

.system__ring     { animation: spin 44s linear infinite;         transform-origin: 50% 50%; }
.system__ring--in { animation: spin-rev 30s linear infinite;     transform-origin: 50% 50%; }
@keyframes spin     { to { transform: rotate(360deg); } }
@keyframes spin-rev { to { transform: rotate(-360deg); } }

.system__node { transform-box: fill-box; transform-origin: center; }
.system__node circle { transition: r 0.35s var(--ease-out), fill 0.35s var(--ease-out); }
.system__node.is-active circle { fill: var(--color-gold); }

/* Energy pulses travelling the connector lines between the three nodes. */
.system__pulse {
  stroke-dasharray: 4 172;
  animation: pulse-travel 3.4s linear infinite;
  animation-delay: var(--pulse-delay, 0s);
}
.system__pulse--2 { --pulse-delay: 1.1s; }
.system__pulse--3 { --pulse-delay: 2.2s; }
@keyframes pulse-travel { to { stroke-dashoffset: -176; } }

.system__core { animation: core-glow 3.6s var(--ease-soft) infinite; transform-box: fill-box; transform-origin: center; }
@keyframes core-glow {
  0%, 100% { opacity: 0.55; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.07); }
}

/* --------------------------- 6. FOOTER SWEEP -------------------------- */

.footer__sweep i { animation: sweep 7s var(--ease-soft) infinite; }
@keyframes sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(394%); }
}

/* ------------------------ 7. AMBIENT BACKGROUND ----------------------- */

.ambient { animation: ambient-shift 30s var(--ease-soft) infinite alternate; }
@keyframes ambient-shift {
  0%   { opacity: 0.75; }
  100% { opacity: 1; }
}

/* Floating gold motes — injected by main.js, paused when off-screen. */
.mote {
  position: absolute;
  width: 2px; height: 2px;
  border-radius: 50%;
  background: var(--color-gold);
  opacity: 0;
  animation: mote-rise var(--mote-dur, 14s) linear infinite;
  animation-delay: var(--mote-delay, 0s);
}
@keyframes mote-rise {
  0%   { opacity: 0;    transform: translateY(0)      scale(0.6); }
  12%  { opacity: 0.65; }
  85%  { opacity: 0.3; }
  100% { opacity: 0;    transform: translateY(-190px) scale(1.25); }
}
/* IntersectionObserver adds .is-paused to off-screen sections. */
.is-paused .mote,
.is-paused .system__pulse,
.is-paused .system__ring { animation-play-state: paused; }

/* ------------------------ 8. MARQUEE (proof strip) -------------------- */

.stat { transition: transform var(--dur-mid) var(--ease-out); }
.stat:hover { transform: translateY(-4px); }

/* --------------------- 9. NO-JS / REDUCED-MOTION ---------------------- */

/* If JS is disabled the reveal classes never arrive — show everything. */
.no-js [data-reveal],
.no-js .split-word {
  opacity: 1 !important;
  transform: none !important;
  filter: none !important;
}
.no-js .loader { display: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal],
  .split-word {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
  .hero__ring-fallback,
  .system__ring,
  .system__ring--in,
  .footer__sweep i,
  .mote,
  .hero__scroll i { animation: none !important; }
  .mote { opacity: 0.35; }
  .cursor, .cursor-dot { display: none !important; }
}

/* ---- FAQ answer reveal (interior pages) --------------------------------
   Height cannot be transitioned out of display:none, so the answer fades and
   lifts instead. Disabled wholesale by the reduced-motion block above. */
.faq__item[open] .faq__a { animation: faq-open 0.42s var(--ease-out) both; }
@keyframes faq-open {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}
