/* ══════════════════════════════════════════════════════════════
   LEM GLOBAL — animations.css
   Motion vocabulary shared with the HubPal product landing:
   shimmer, float, pulse, orbit, ring-wave, flow-dash, reveal.

   Everything degrades to a static, fully visible state under
   prefers-reduced-motion (bottom of file).
   ══════════════════════════════════════════════════════════════ */

/* ── KEYFRAMES ─────────────────────────────────────────────── */

/* Brand-word gradient sweep. */
@keyframes shimmer { to { background-position: 220% center; } }

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

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

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

/* Expanding waves emanating from a hub node. */
@keyframes ring-wave {
  0%   { transform: scale(1);   opacity: 0.55; }
  100% { transform: scale(2.1); opacity: 0; }
}

/* Travelling dashes along a connector line. */
@keyframes flow-dash { to { stroke-dashoffset: -13; } }

/* Halo around the founder portrait. Deliberately smaller than ring-wave so it
   never grows past its grid column. */
@keyframes founder-halo {
  0%   { transform: scale(1);    opacity: 0.5; }
  70%  { opacity: 0; }
  100% { transform: scale(1.35); opacity: 0; }
}

@keyframes chip-drift {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

@keyframes rise-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@keyframes ping {
  0%   { transform: scale(1);   opacity: 0.55; }
  70%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}


/* ── SCROLL REVEAL ─────────────────────────────────────────── */
/* Hidden until ui.js adds .is-visible via IntersectionObserver.
   Scoped to .js — set by an inline script in <head> — so that if the
   script never runs the content simply renders, rather than staying
   invisible at opacity 0. */

.js .reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}

.js .reveal.from-left  { transform: translateX(-26px); }
.js .reveal.from-right { transform: translateX(26px); }
.js .reveal.from-scale { transform: scale(0.97); }

.js .reveal.is-visible { opacity: 1; transform: none; }

/* Below the split breakpoint the layout is already stacked, so a sideways
   slide reads oddly — and a 26px horizontal offset on a 375px screen pushes
   content past the viewport, flashing a horizontal scrollbar mid-animation.
   Slide vertically instead. */
@media (max-width: 980px) {
  .js .reveal.from-left,
  .js .reveal.from-right { transform: translateY(18px); }
}

/* Fixed delays, matching HubPal's .delay-N convention. */
.delay-1 { transition-delay: 0.10s; }
.delay-2 { transition-delay: 0.20s; }
.delay-3 { transition-delay: 0.30s; }
.delay-4 { transition-delay: 0.40s; }

/* Index-driven stagger — ui.js writes --i on each child. */
.js [data-stagger] > * {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.55s var(--ease), transform 0.55s var(--ease);
  transition-delay: calc(var(--i, 0) * 70ms);
}

.js [data-stagger].is-visible > * { opacity: 1; transform: none; }


/* ── PAGE ENTRANCE ─────────────────────────────────────────── */
.enter   { animation: rise-in 0.7s var(--ease) both; }
.enter-1 { animation-delay: 0.06s; }
.enter-2 { animation-delay: 0.16s; }
.enter-3 { animation-delay: 0.26s; }
.enter-4 { animation-delay: 0.36s; }
.enter-5 { animation-delay: 0.46s; }


/* ── UTILITIES ─────────────────────────────────────────────── */
.anim-float { animation: float 5s ease-in-out infinite; }
.anim-pulse { animation: pulse 3.5s ease-in-out infinite; }


/* ── HUB DIAGRAM ───────────────────────────────────────────── */
/* Drives the connector diagram; transform-origin matches its centre. */

.hub-svg { width: 100%; height: auto; }

.hub-svg .orbit {
  transform-origin: 240px 220px;
  animation: orbit-spin 40s linear infinite;
}

.hub-svg .ring {
  transform-origin: 240px 220px;
  animation: ring-wave 3.6s ease-out infinite;
  opacity: 0;
}

.hub-svg .r2 { animation-delay: 1.2s; }
.hub-svg .r3 { animation-delay: 2.4s; }

.hub-svg .core { transform-origin: 240px 220px; animation: pulse 3.5s ease-in-out infinite; }

.hub-svg .flow { animation: flow-dash 1.4s linear infinite; }

.hub-svg .nchip {
  animation: chip-drift 5.5s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}

.hub-svg .nchip:nth-of-type(2) { animation-delay: 0.9s; }
.hub-svg .nchip:nth-of-type(3) { animation-delay: 1.8s; }
.hub-svg .nchip:nth-of-type(4) { animation-delay: 2.7s; }
.hub-svg .nchip:nth-of-type(5) { animation-delay: 3.6s; }
.hub-svg .nchip:nth-of-type(6) { animation-delay: 4.5s; }


/* ── REDUCED MOTION ────────────────────────────────────────── */
@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;
  }

  /* Content must never stay stuck at opacity 0. */
  .js .reveal,
  .js [data-stagger] > * {
    opacity: 1 !important;
    transform: none !important;
  }

  /* The brand gradient relies on an animation for its fill position;
     pin it to a readable frame rather than letting it sit at 0%. */
  .brand-gradient { background-position: 60% center; }
}
