/**
 * motion.css — Nick Ho motion system
 *
 * The masks are not decoration: an overflow-clipped wrapper is what turns a
 * slide-in into a *reveal*. Without it the effect looks generic.
 */

/* --- Masked text reveal ------------------------------------------- */

/* SplitText's mask:'lines' option injects its own wrappers; these rules cover
   both that and the built-in fallback splitter. */
.motion-mask,
[data-reveal="text"] .split-mask {
  display: block;
  overflow: clip;      /* clip beats hidden: never creates a scroll container */
  overflow-clip-margin: 0.1em; /* room for descenders and accents */
}

.motion-line,
.motion-word,
.motion-char {
  display: inline-block;
  will-change: transform;
}

.motion-line { display: block; }

/* Reveal targets start hidden so there is no flash before GSAP initialises.
   Scoped to .js-motion (set on <html> by your boot script) so content stays
   visible if JavaScript never runs. */
.js-motion [data-reveal="fade"],
.js-motion [data-reveal="fade-up"],
.js-motion [data-reveal="slide"] {
  opacity: 0;
}

/* --- Parallax ------------------------------------------------------ */

[data-parallax="trigger"] {
  overflow: clip; /* hide the oversized target's edges */
}

/* Give the target room to travel without exposing an edge. */
[data-parallax="target"] {
  width: 100%;
  height: 120%;
  object-fit: cover;
  will-change: transform;
}

/* --- Scrub-lag lines ----------------------------------------------- */

[data-line-scroll] {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}

.bg-line {
  width: 1px;
  height: 0;
  background: currentColor;
  opacity: 0.12;
  transform-origin: top center;
}

/* --- Character-stagger button -------------------------------------- */

[data-char-button] {
  --char-stagger: 0.018s;
  position: relative;
  display: inline-flex;
  overflow: clip;
  cursor: pointer;
}

.btn__content {
  display: inline-flex;
}

/* The hover copy sits exactly on top, pre-shifted below the mask. */
.btn__content--hover {
  position: absolute;
  inset: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.btn__char {
  display: inline-block;
  /* Same shape as expo.out, expressed as a bezier for CSS. */
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--char) * var(--char-stagger));
  will-change: transform;
}

.btn__content--hover .btn__char { transform: translateY(100%); }

[data-char-button]:hover .btn__content:not(.btn__content--hover) .btn__char,
[data-char-button]:focus-visible .btn__content:not(.btn__content--hover) .btn__char {
  transform: translateY(-100%);
}

[data-char-button]:hover .btn__content--hover .btn__char,
[data-char-button]:focus-visible .btn__content--hover .btn__char {
  transform: translateY(0);
}

/* --- Odometer ------------------------------------------------------ */

[data-odometer] {
  font-variant-numeric: tabular-nums; /* stops width jitter as digits change */
}

/* --- Section overlap ------------------------------------------------ */

[data-overlap] {
  position: relative;
  background: var(--section-bg, #000); /* must be opaque to occlude the section below */
}

/* --- Reduced motion -------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .js-motion [data-reveal] { opacity: 1 !important; transform: none !important; }
  .bg-line { height: 100%; }
  .btn__char { transition: none; }
  * { scroll-behavior: auto !important; }
}
