/* motion.css — every animation on the site, in one file so the
 * prefers-reduced-motion override at the bottom can switch all of it off with
 * certainty.
 *
 * Rules kept throughout:
 *  - transform and opacity only, so the compositor does the work and nothing
 *    triggers layout during scroll;
 *  - nothing on the critical path — the page is fully readable before app.js
 *    runs, and <noscript> forces every .reveal visible;
 *  - anything with a negative inset is clipped by its host (see components.css).
 */

/* ── scroll reveal ────────────────────────────────────────────────────── */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.reveal.in { opacity: 1; transform: none; }

/* ── headline word stagger ────────────────────────────────────────────── */

/* app.js wraps each word of .split in a <span class="w"><span>…</span></span>.
 * The outer span clips, the inner one slides up out of it. If JS never runs,
 * .split keeps its plain text and simply doesn't animate. */
.split .w { display: inline-block; overflow: hidden; vertical-align: bottom; }
.split .w > span {
  display: inline-block;
  transform: translateY(105%);
  opacity: 0;
  animation: wordUp .85s var(--ease-out) forwards;
  animation-delay: calc(var(--w) * 55ms);
}
@keyframes wordUp {
  to { transform: translateY(0); opacity: 1; }
}

/* ── aurora drift ─────────────────────────────────────────────────────── */

.hero-aurora {
  animation: auroraDrift 26s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes auroraDrift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(2.5%, -2%, 0) scale(1.06); }
  100% { transform: translate3d(-2%, 1.5%, 0) scale(1.02); }
}

.deck-glow, .cta-glow {
  animation: glowPulse 9s ease-in-out infinite alternate;
}
@keyframes glowPulse {
  from { opacity: .78; transform: scale(1); }
  to   { opacity: 1;   transform: scale(1.06); }
}

/* ── the deck ─────────────────────────────────────────────────────────── */

/* Each card breathes on its own offset, so the stack never pulses as one slab.
 * The float is applied to .deck-card, which sits INSIDE the slot that owns the
 * 3D placement — layering the two transforms instead of fighting over one. */
.deck-card { animation: cardFloat 7.5s ease-in-out infinite; }
.deck-slot.s1 .deck-card { animation-delay: 0s; }
.deck-slot.s2 .deck-card { animation-delay: .5s; }
.deck-slot.s3 .deck-card { animation-delay: 1s; }
.deck-slot.s4 .deck-card { animation-delay: 1.5s; }
.deck-slot.s5 .deck-card { animation-delay: 2s; }
@keyframes cardFloat {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-11px); }
}

/* Entrance: the deck assembles from a flat stack into depth on first paint. */
.deck-slot { animation: slotIn 1.1s var(--ease-out) both; }
.deck-slot.s1 { animation-delay: .28s; }
.deck-slot.s2 { animation-delay: .18s; }
.deck-slot.s3 { animation-delay: .05s; }
.deck-slot.s4 { animation-delay: .18s; }
.deck-slot.s5 { animation-delay: .28s; }
@keyframes slotIn {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) translateX(0) translateY(30px) translateZ(-40px) rotateY(0) rotateZ(0);
  }
}

/* Scroll-driven parallax where supported. The deck rotates a few degrees as it
 * travels through the viewport — a progressive enhancement that simply does not
 * apply in browsers without scroll-driven animations. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 981px) {
    .deck-stage {
      animation: deckTilt linear both;
      animation-timeline: view();
      animation-range: entry 10% exit 90%;
    }
    @keyframes deckTilt {
      from { transform: rotateX(9deg) rotateY(-7deg); }
      to   { transform: rotateX(-6deg) rotateY(6deg); }
    }
  }
}

/* ── pointer tilt ─────────────────────────────────────────────────────── */

/* app.js sets --tx/--ty from the pointer position over a .tilt card. Values
 * default to 0, so the rule is inert until a pointer actually moves. */
@media (hover: hover) and (pointer: fine) {
  .tilt {
    transform: perspective(700px) rotateX(var(--ty, 0deg)) rotateY(var(--tx, 0deg)) translateZ(0);
    transition: transform .35s var(--ease-out), border-color .3s, box-shadow .3s;
  }
  .tilt:hover { transition-duration: .08s; }
}

/* ── magnetic CTA ─────────────────────────────────────────────────────── */

@media (hover: hover) and (pointer: fine) {
  .btn-magnetic {
    transform: translate(var(--mx, 0px), var(--my, 0px)) translateY(var(--lift, 0px));
    transition: transform .3s var(--ease-spring), box-shadow .3s var(--ease-out);
  }
  .btn-magnetic:hover { --lift: -2px; transition-duration: .12s; }
}

/* ── marquee-ish shimmer on the primary button ────────────────────────── */

.btn-primary::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(110deg, transparent 30%, rgba(255,255,255,.42) 50%, transparent 70%);
  background-size: 220% 100%;
  background-position: 220% 0;
  pointer-events: none;
  animation: sheen 5.5s ease-in-out infinite;
}
@keyframes sheen {
  0%, 62%  { background-position: 220% 0; }
  86%, 100% { background-position: -120% 0; }
}

/* ── below-the-fold rendering ─────────────────────────────────────────── */

/* Skips layout and paint for offscreen sections. contain-intrinsic-size keeps
 * the scrollbar honest so skipping never causes a jump. */
.related, .cta-band, .foot {
  content-visibility: auto;
  contain-intrinsic-size: auto 400px;
}

/* ── the global off switch ────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto; }
  .reveal { opacity: 1 !important; transform: none !important; }
  .split .w > span { transform: none !important; opacity: 1 !important; }
  .tilt { transform: none !important; }
  .btn-magnetic { transform: none !important; }
}
