/* ==========================================================================
   The Fintech Navigator — motion
   One rule governs everything here: motion carries meaning or it doesn't ship.
   Entrances explain hierarchy, transitions explain continuity, and the whole
   file collapses to nothing under prefers-reduced-motion.
   ========================================================================== */

/* ----------------------------------------------------------- the keyframes */
@keyframes rise      { from{ opacity:0; transform:translateY(18px); } to{ opacity:1; transform:none; } }
@keyframes riseFar   { from{ opacity:0; transform:translateY(34px); } to{ opacity:1; transform:none; } }
@keyframes fade      { from{ opacity:0; } to{ opacity:1; } }
@keyframes wipe      { from{ opacity:0; transform:translateY(26px) scale(.995); } to{ opacity:1; transform:none; } }
@keyframes slideIn   { from{ opacity:0; transform:translateX(28px); } to{ opacity:1; transform:none; } }
@keyframes barGrow   { from{ transform:scaleY(.06); opacity:.35; } to{ transform:none; opacity:1; } }
@keyframes pulseDot  { 0%,100%{ opacity:1; transform:scale(1); } 50%{ opacity:.35; transform:scale(1.55); } }
@keyframes spinSlow  { to{ transform:rotate(360deg); } }
@keyframes drift     { 0%,100%{ transform:translate(0,0) scale(1); } 50%{ transform:translate(4%,3%) scale(1.08); } }
@keyframes marquee   { from{ transform:translateX(0); } to{ transform:translateX(-50%); } }
@keyframes marqueeR  { from{ transform:translateX(0); } to{ transform:translateX(50%); } }
@keyframes shimmer   { from{ background-position:-180% 0; } to{ background-position:180% 0; } }
@keyframes blink     { 0%,45%{ opacity:1; } 55%,100%{ opacity:.15; } }
@keyframes drawRing  { from{ transform:translate(-50%,-50%) scale(.6); opacity:0; } to{ transform:translate(-50%,-50%) scale(1); opacity:1; } }
@keyframes popIn     { from{ opacity:0; transform:translate(-50%,-50%) scale(.2); } to{ opacity:var(--sat-o,1); transform:translate(-50%,-50%) scale(1); } }
@keyframes ripple    { from{ transform:scale(1); opacity:.45; } to{ transform:scale(2.5); opacity:0; } }

/* --------------------------------------------------------- view transition */
/* Every route change replays this, so the app never "jumps" between pages. */
.view{ animation:wipe .5s var(--ease) both; }

/* ------------------------------------------------------ hero entrance stack */
/* Staggered so the eye lands on the headline, then the promise, then the ask. */
.hero h1        { animation:rise .75s var(--ease) .05s both; }
.hero__lede     { animation:rise .75s var(--ease) .16s both; }
.hero__cta      { animation:rise .75s var(--ease) .28s both; }
.heromap        { animation:riseFar .85s var(--ease) .38s both; }
.hero .statgrid { animation:riseFar .85s var(--ease) .48s both; }

.hero__aurora--a{ animation:drift 24s ease-in-out infinite; }
.hero__aurora--b{ animation:drift 31s ease-in-out infinite reverse; }

/* ------------------------------------------------------------ scroll reveal */
/* Applied by motion.js via IntersectionObserver. Nothing here fires until an
   element is actually about to be seen, so the page stays cheap on scroll. */
[data-reveal]{
  opacity:0;
  transform:translateY(var(--reveal-y, 24px));
  transition:
    opacity .75s var(--ease-out) var(--reveal-delay, 0ms),
    transform .75s var(--ease-out) var(--reveal-delay, 0ms);
  will-change:opacity, transform;
}
[data-reveal="left"] { transform:translateX(-26px); }
[data-reveal="right"]{ transform:translateX(26px); }
[data-reveal="scale"]{ transform:scale(.96); }
[data-reveal].is-in{ opacity:1; transform:none; will-change:auto; }

/* ------------------------------------------------------------ live elements */
.livedot{ animation:pulseDot 2.1s ease-in-out infinite; }
.tl__bar{ animation:barGrow .6s var(--ease) both; }
.barcol__bar{ animation:barGrow .8s var(--ease) both; }
.blinker{ animation:blink 1.15s steps(1) infinite; }

/* orbit: slow counter-rotating rings, and satellites that pop in on load */
.orbit__spin--a{ animation:spinSlow 190s linear infinite; }
.orbit__spin--b{ animation:spinSlow 260s linear infinite reverse; }
.orbit__ring{ animation:drawRing .9s var(--ease-out) both; }
.orbit__sat{ animation:popIn .55s var(--ease-out) both; }
.orbit__core::after{
  content:''; position:absolute; inset:0; border-radius:50%;
  border:1px solid var(--lime); animation:ripple 3.6s ease-out infinite;
  pointer-events:none;
}

/* marquee */
.marquee__track{ animation:marquee 46s linear infinite; }
[dir="rtl"] .marquee__track{ animation-name:marqueeR; }

/* skeleton shimmer for gated content */
.shimmer{
  background:linear-gradient(90deg, var(--card) 8%, var(--card-hi) 22%, var(--card) 36%);
  background-size:180% 100%;
  animation:shimmer 2.4s linear infinite;
}

/* counters land on a tick rather than fading in — reads as "instrument" */
.stat__n{ transition:color .3s var(--ease); }

/* ------------------------------------------------ magnetic / tilt affordance */
.magnetic{ transition:transform .35s var(--ease-out); will-change:transform; }

/* ==========================================================================
   THE OPT-OUT
   Everything above degrades to a plain, still page. Content never depends on
   motion to be reachable — reveals resolve to visible, loops simply stop.
   ========================================================================== */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  [data-reveal]{ opacity:1 !important; transform:none !important; }
  .hero__aurora{ opacity:.10; }
  .orbit__core::after{ display:none; }
  .marquee__track{ animation:none; }
  .magnetic{ transform:none !important; }
}
