/* Hyperlane Club — shared motion layer
   Re-implements four 21st.dev animation concepts in vanilla CSS/JS:
   1) Aurora hero background   2) Word-by-word headline reveal
   3) Marquee marque strip     4) Spotlight glow-follow cards
   Guardrails: transform/opacity only, no transition-all, reduced-motion safe. */

/* ---------------------------------------------------------------
   1) AURORA HERO BACKGROUND  (21st.dev "Aurora Background")
   Two slow, oversized gold light fields drift and breathe behind the
   hero atmosphere. Sits above .atmosphere::before, below the content. */
.aurora {
  position: absolute;
  inset: -20%;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}
.aurora::before,
.aurora::after {
  content: "";
  position: absolute;
  width: 65%;
  height: 65%;
  border-radius: 50%;
  filter: blur(70px);
  opacity: .5;
  will-change: transform, opacity;
}
.aurora::before {
  top: -10%; right: 4%;
  background: radial-gradient(circle, rgba(212,175,55,.22), transparent 65%);
  animation: aurora-a 26s ease-in-out infinite alternate;
}
.aurora::after {
  bottom: -12%; left: 0%;
  background: radial-gradient(circle, rgba(212,175,55,.12), transparent 65%);
  animation: aurora-b 34s ease-in-out infinite alternate;
}
@keyframes aurora-a {
  0%   { transform: translate3d(0,0,0) scale(1);      opacity: .42; }
  100% { transform: translate3d(-8%,6%,0) scale(1.18); opacity: .6; }
}
@keyframes aurora-b {
  0%   { transform: translate3d(0,0,0) scale(1.05);   opacity: .3; }
  100% { transform: translate3d(7%,-5%,0) scale(1.25); opacity: .5; }
}

/* ---------------------------------------------------------------
   2) WORD-BY-WORD HEADLINE REVEAL  (21st.dev "Text Reveal" / blur-in)
   JS splits the headline into word spans; each rises + unblurs in
   sequence. Falls back to fully visible if JS never runs. */
.word-reveal .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.4em);
  filter: blur(6px);
  animation: word-in .85s cubic-bezier(.2,.8,.2,1) forwards;
  animation-delay: var(--word-delay, 0s);
}
@keyframes word-in {
  to { opacity: 1; transform: none; filter: blur(0); }
}

/* ---------------------------------------------------------------
   3) MARQUEE MARQUE STRIP  (21st.dev "Marquee")
   A track duplicated twice scrolls left forever; mask fades the ends.
   Pauses on hover so a name can be read. */
.marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee 38s linear infinite;
  will-change: transform;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item {
  flex: 0 0 auto;
  padding: 0 2.75rem;
}
@keyframes marquee {
  from { transform: translate3d(0,0,0); }
  to   { transform: translate3d(-50%,0,0); }
}

/* ---------------------------------------------------------------
   4) SPOTLIGHT GLOW-FOLLOW CARDS  (21st.dev "Spotlight Card")
   A soft gold radial follows the cursor. --mx/--my set by JS; --spot
   toggles visibility. Pointer-events none so it never blocks the image. */
.spotlight { position: relative; }
.spotlight__glow {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border-radius: inherit;
  opacity: 0;
  transition: opacity .4s ease;
  background: radial-gradient(
    220px circle at var(--mx, 50%) var(--my, 0%),
    rgba(212,175,55,.18), transparent 60%);
}
.spotlight:hover .spotlight__glow { opacity: var(--spot, 1); }

/* ---------------------------------------------------------------
   5) PARALLAX ON IMAGES  (scroll-driven depth)
   A wrapper [data-parallax] clips; its image is scaled up and over-
   sized so a small vertical drift never exposes an edge. JS sets
   --py (px) on scroll via rAF. Transform only; no layout shift. */
.parallax { position: relative; overflow: hidden; }
.parallax > img,
.parallax > .parallax__media {
  /* Oversize + lift so drift stays within the frame at all positions.
     The element is taller than its frame; we slide it between bounds. */
  position: absolute;
  inset: -12% 0;            /* 12% bleed top & bottom = 124% height */
  width: 100%;
  height: 124%;
  object-fit: cover;
  transform: translate3d(0, var(--py, 0px), 0);
  will-change: transform;
}
/* When the frame relies on natural image height (e.g. about 900x1100),
   the wrapper sets an explicit aspect via the markup; absolute fill works
   because the wrapper is position:relative with its own sizing. */

/* ---------------------------------------------------------------
   6) RICHER SCROLL-REVEAL  (directional + staggered)
   Extends the base .reveal. Direction set via [data-reveal]; stagger
   delay set by JS on children of [data-stagger] via --rv-d.
   Premium easing, opacity/transform only. */
.reveal { transition-delay: var(--rv-d, 0s); }
.reveal[data-reveal="fade"]       { transform: none; }
.reveal[data-reveal="rise"]       { transform: translateY(28px); }
.reveal[data-reveal="slide-left"] { transform: translateX(-32px); }
.reveal[data-reveal="slide-right"]{ transform: translateX(32px); }
.reveal[data-reveal="scale"]      { transform: scale(.965); }
.reveal[data-reveal].in           { transform: none; opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .aurora::before, .aurora::after { animation: none; }
  .word-reveal .word { animation: none; opacity: 1; transform: none; filter: none; }
  .marquee__track { animation: none; }
  .spotlight__glow { display: none; }
  .parallax > img,
  .parallax > .parallax__media { transform: none !important; }
  .reveal[data-reveal] { transform: none !important; opacity: 1 !important; }
}
