/* ==========================================================================
   motion.css — reveal staging, kinetic type, ambient loops
   Every rule animates transform / opacity / clip-path only. No layout props.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Scroll reveal staging
   Elements are staged here and released by IntersectionObserver (motion.js).
   If JS never runs, the .no-js fallback below keeps everything visible.
   -------------------------------------------------------------------------- */

[data-reveal] {
  opacity: 0;
  will-change: opacity, transform;
  transition:
    opacity 720ms var(--ease-out),
    translate 720ms var(--ease-out),
    scale 720ms var(--ease-out),
    clip-path 860ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

[data-reveal="up"]     { translate: 0 28px; }
[data-reveal="down"]   { translate: 0 -20px; }
[data-reveal="left"]   { translate: 28px 0; }
[data-reveal="right"]  { translate: -28px 0; }
[data-reveal="fade"]   { translate: none; }
[data-reveal="scale"]  { scale: 0.965; }
[data-reveal="wipe"]   { clip-path: inset(0 100% 0 0); opacity: 1; }

[data-reveal].is-revealed {
  opacity: 1;
  translate: 0 0;
  scale: 1;
  clip-path: inset(0 0 0 0);
  will-change: auto;
}

html.no-js [data-reveal] {
  opacity: 1;
  translate: none;
  scale: none;
  clip-path: none;
}

/* --------------------------------------------------------------------------
   2. Kinetic type — per-word mask reveal for serif headings
   Built by motion.js: each word is wrapped in .kt__word > .kt__inner.
   -------------------------------------------------------------------------- */

.kt { display: block; }

.kt__word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  /* Space for descenders so the mask never clips a 'g' or 'y'. */
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.kt__inner {
  display: inline-block;
  translate: 0 110%;
  transition: translate 900ms var(--ease-out);
  transition-delay: var(--kt-delay, 0ms);
}

.kt.is-revealed .kt__inner { translate: 0 0; }

html.no-js .kt__inner { translate: 0 0; }

@media (prefers-reduced-motion: reduce) {
  .kt__inner { translate: 0 0 !important; }
}

/* The hairline gold rule that draws beneath a revealed heading. */
.kt-rule {
  display: block;
  height: 1px;
  margin-top: 1.5rem;
  background: var(--gilded);
  scale: 0 1;
  transform-origin: left center;
  transition: scale 1100ms var(--ease-out) 260ms;
}

.kt-rule.is-revealed { scale: 1 1; }

/* --------------------------------------------------------------------------
   2b. Hero entrance staging
   Staged only when scripting is available and motion is welcome, so the hero
   is never left invisible if the timeline cannot run.
   -------------------------------------------------------------------------- */

html:not(.no-js) [data-hero-step] { opacity: 0; }

@media (prefers-reduced-motion: reduce) {
  [data-hero-step] { opacity: 1 !important; }
}

/* --------------------------------------------------------------------------
   3. Count-up numerals
   -------------------------------------------------------------------------- */

.counter { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   4. Magnetic pull (JS sets --pull-x / --pull-y)
   -------------------------------------------------------------------------- */

.magnetic {
  translate: var(--pull-x, 0) var(--pull-y, 0);
  transition: translate 420ms var(--ease-spring);
}

/* --------------------------------------------------------------------------
   5. Tilt (JS sets --rx / --ry)
   -------------------------------------------------------------------------- */

.tilt {
  transform-style: preserve-3d;
  transform: perspective(1100px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 480ms var(--ease-out);
}

/* --------------------------------------------------------------------------
   6. Ambient loops
   -------------------------------------------------------------------------- */

@keyframes gild-drift {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}

.gilded--drift {
  animation: gild-drift 9s linear infinite;
}

@keyframes breathe {
  0%, 100% { opacity: 0.42; }
  50%      { opacity: 0.85; }
}

@keyframes float-slow {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -10px; }
}

@keyframes trace-dash {
  to { stroke-dashoffset: -1000; }
}

@keyframes draw-in {
  from { stroke-dashoffset: var(--dash, 1000); }
  to   { stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .gilded--drift { animation: none; }
}

/* --------------------------------------------------------------------------
   7. Page enter — a single, quiet curtain lift on first paint
   -------------------------------------------------------------------------- */

.page-veil {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--bg);
  pointer-events: none;
  opacity: 1;
  transition: opacity 620ms var(--ease-out);
}

.page-veil.is-lifted { opacity: 0; }

html.no-js .page-veil { display: none; }

/* --------------------------------------------------------------------------
   8. Canvas scenes — shared frame styling
   -------------------------------------------------------------------------- */

.scene {
  position: relative;
  width: 100%;
  border-radius: var(--radius-cards);
  overflow: hidden;
  background: var(--bg-card);
  border: 1px solid var(--line);
}

.scene canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.scene__caption {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  right: 1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  font-size: 0.6875rem;
  font-weight: var(--font-weight-medium);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-faint);
  pointer-events: none;
}

.scene__hint {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--gold);
  opacity: 0.85;
}

/* A "reduced motion" static stand-in shown in place of a live scene. */
.scene__fallback { display: none; }

@media (prefers-reduced-motion: reduce) {
  .scene__fallback { display: block; }
}
