/* ==========================================================================
   home-motion.css — homepage final-touch animation layer
   Loaded ONLY by index.html. Pure progressive enhancement: every rule here
   activates only when JS added .motion-ready to <html> (set by boot.js before
   first paint), so no-JS users see the normal static page and reduced-motion
   users skip all of it (the media query at the bottom neutralises everything).
   ========================================================================== */

/* ---------- 2. Hero supporting elements: hidden pre-roll ----------
   Armed ONLY by boot.js (class mo-hero-armed) on the first homepage visit of
   a tab session and only when JS runs + reduced-motion is off. Return visits
   never arm it, so the hero is simply there — the cinematic plays once. */
html.mo-hero-armed .mh-hero-title {
  opacity: 0;
}

html.mo-hero-armed .mh-hero-title .mw {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

html.mo-hero-armed .mh-hero-title .mw-in {
  display: inline-block;
  transform: translateY(115%);
}

html.mo-hero-armed .mh-hero-lede,
html.mo-hero-armed .mh-hero-actions .mh-btn,
html.mo-hero-armed .mh-rack {
  opacity: 0;
}

/* anime.js writes transform/opacity every frame on these elements; a CSS
   transition on the same properties re-eases each frame and makes the motion
   swim. Transitions are cut for the duration of the timeline (JS removes the
   class on completion, which restores the button hover transitions). */
html.mo-hero-armed .mh-hero-actions .mh-btn {
  transition: none;
}

/* ---------- 3. Rack logo: idle float + pointer parallax host ---------- */
html.mo-hero-armed .mh-rack {
  will-change: transform;
}

html.motion-ready .mh-flow-logo {
  animation: mo-bob 7s ease-in-out infinite;
  transform-origin: 50% 60%;
}

@keyframes mo-bob {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-12px) rotate(1.4deg); }
}

/* Soft halo breathing behind the logo so the right column is never dead. */
html.motion-ready .mh-rack::before {
  content: "";
  position: absolute;
  inset: -18% -12%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255,255,255,0.07), rgba(255,255,255,0) 72%);
  animation: mo-halo 6s ease-in-out infinite;
  pointer-events: none;
}

@keyframes mo-halo {
  0%, 100% { transform: scale(1);    opacity: 0.55; }
  50%      { transform: scale(1.14); opacity: 1; }
}

/* ---------- 4. Card grids: deeper per-card cascade ----------
   Only the WAITING state is deepened (:not(.is-visible)); the revealed state
   falls through to base-v3's [data-reveal].is-visible { transform: none },
   which has equal specificity to the card's :hover rule and is overridden by
   it (home.css loads later) — so the hover lift keeps working untouched. */
html.motion-ready .mh-plans .mh-plan[data-reveal]:not(.is-visible),
html.motion-ready .vps-cards .vps-card[data-reveal]:not(.is-visible),
html.motion-ready .mh-game-grid .mh-game-tile[data-reveal]:not(.is-visible) {
  opacity: 0;
  transform: translateY(28px) scale(0.985);
}

/* ---------- 5. Card cursor spotlight ---------- */
/* A radial highlight follows the pointer inside plan/vps cards. The gradient
   centre is driven by --mx/--my set from home-motion.js pointermove. */
html.motion-ready .mh-plan,
html.motion-ready .vps-card {
  --mx: 50%;
  --my: 50%;
}

html.motion-ready .mh-plan::after,
html.motion-ready .vps-card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    340px circle at var(--mx) var(--my),
    rgba(255,255,255,0.09),
    rgba(255,255,255,0) 62%
  );
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
  z-index: 1;
}

html.motion-ready .mh-plan:hover::after,
html.motion-ready .vps-card:hover::after {
  opacity: 1;
}

/* Content stays above the spotlight layer. */
html.motion-ready .mh-plan > *,
html.motion-ready .vps-card > * {
  position: relative;
  z-index: 2;
}

/* ---------- 6. Primary button shimmer sweep ---------- */
/* Monochrome light sweep on hover/focus. overflow:hidden is scoped to the
   button and isolation contains the layer; the button's own outline is not
   clipped by its own overflow. */
html.motion-ready .mh-btn-primary {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

html.motion-ready .mh-btn-primary::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    105deg,
    rgba(255,255,255,0) 30%,
    rgba(255,255,255,0.28) 50%,
    rgba(255,255,255,0) 70%
  );
  transform: translateX(-120%);
  pointer-events: none;
  z-index: 0;
}

html.motion-ready .mh-btn-primary:hover::before,
html.motion-ready .mh-btn-primary:focus-visible::before {
  animation: mo-sheen 0.85s var(--ease-out);
}

@keyframes mo-sheen {
  from { transform: translateX(-120%); }
  to   { transform: translateX(120%); }
}

html.motion-ready .mh-btn-primary > * {
  position: relative;
  z-index: 1;
}

/* ---------- 7. Footer trust counters: stable digit box ---------- */
html.motion-ready .footer-trust strong {
  display: inline-block;
  min-width: 3.2ch;
}

/* ---------- 8. CTA band: travelling edge glow ---------- */
html.motion-ready .mh-cta-inner {
  position: relative;
}

/* Only where composite masks exist — without them the gradient would paint
   as a solid 1px band across the whole card instead of a thin edge. */
@supports ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
  html.motion-ready .mh-cta-inner::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    120deg,
    rgba(255,255,255,0) 20%,
    rgba(255,255,255,0.35) 50%,
    rgba(255,255,255,0) 80%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  background-size: 220% 100%;
  animation: mo-edge 5.5s linear infinite;
  pointer-events: none;
  }
}

@keyframes mo-edge {
  from { background-position: 120% 0; }
  to   { background-position: -120% 0; }
}

/* ---------- 9. Hero particles: white glow instead of legacy blue ---------- */
html.motion-ready .mh-hero .particle {
  background: rgba(255,255,255,0.5);
  box-shadow: 0 0 6px rgba(255,255,255,0.35);
}

/* ---------- 10. Parallax hosts ---------- */
html.motion-ready .particle-overlay {
  will-change: transform;
}

/* ---------- 11. Timeline-finished state (JS adds .mo-live to <html>) ----------
   Once the entrance timeline completes, idle motion may start; this keeps a
   hard floor under it. */
html.motion-ready.mo-live .mh-flow-logo {
  animation-play-state: running;
}

html.motion-ready:not(.mo-live) .mh-flow-logo,
html.motion-ready:not(.mo-live) .mh-rack::before {
  animation-play-state: paused;
}

/* ---------- 12. Reduced motion: kill the whole layer ---------- */
@media (prefers-reduced-motion: reduce) {
  html.mo-hero-armed .mh-hero-title,
  html.mo-hero-armed .mh-hero-title .mw-in,
  html.mo-hero-armed .mh-hero-lede,
  html.mo-hero-armed .mh-hero-actions .mh-btn,
  html.mo-hero-armed .mh-rack {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }

  html.motion-ready .mh-plans .mh-plan[data-reveal]:not(.is-visible),
  html.motion-ready .vps-cards .vps-card[data-reveal]:not(.is-visible),
  html.motion-ready .mh-game-grid .mh-game-tile[data-reveal]:not(.is-visible) {
    opacity: 1 !important;
    transform: none !important;
  }

  html.motion-ready .mh-btn-primary::before,
  html.motion-ready .mh-cta-inner::before,
  html.motion-ready .mh-rack::before {
    animation: none !important;
    display: none;
  }

  html.motion-ready .particle-overlay {
    transform: none !important;
  }
}
