/* =============================================================
   animations.css — Webflow-grade scroll/interaction layer
   Pairs with js/animations.js. Loaded AFTER styles.css so cascade
   order is preserved.
   ============================================================= */

/* Hide-until-ready: anything GSAP will animate stays invisible
   until the timeline is built. animations.js adds .gsap-ready to
   <html> once initialization finishes. Prevents the "settle flash"
   where final-state content shows for a frame before animating in. */
html:not(.gsap-ready) [data-split],
html:not(.gsap-ready) .display {
  visibility: hidden;
}

/* SplitText helpers --------------------------------------------- */

/* Lines wrapper: each line gets its own block with overflow hidden
   so a yPercent: 100 → 0 tween masks cleanly from below. The
   padding-bottom prevents descender clipping (g, y, p, q). */
.split-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.12em;
}

/* Individual chars need to be inline-block for transforms to apply,
   and will-change to nudge them onto their own GPU layer. */
.split-char {
  display: inline-block;
  will-change: transform, opacity;
}

/* Hero display: chars rise from below — vertical-align top keeps
   the baseline consistent during the rise so adjacent chars don't
   appear to ride at different heights. */
.display .split-char,
.services-display .split-char {
  vertical-align: top;
}

/* SplitText invariant fix: when text uses background-clip: text on the
   parent (.display, .heading, .services-display, .contact-display),
   wrapping each char in its own div breaks the gradient — the inner
   div has no background to clip. Re-apply the parent's gradient on
   each char so the lit-cream fill survives the split. */
.display .split-char,
.heading .split-char,
.services-display .split-char,
.contact-display .split-char {
  background: linear-gradient(180deg, #f3f5f8 0%, #cdd1d8 55%, #9ea3aa 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Same for SplitText line wrappers — when text uses background-clip,
   the .split-line div needs its own gradient. */
.heading .split-line,
.contact-display .split-line {
  background: linear-gradient(180deg, #f3f5f8 0%, #cdd1d8 55%, #9ea3aa 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* About heading uses an inner .dim span with a different gradient —
   restore that variant inside split-line wrappers. */
.heading .split-line .dim {
  background: linear-gradient(180deg, #b9bdc4 0%, #8d929a 55%, #6a6f76 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Contact heading dim variant */
.contact-display .split-line .dim {
  background: linear-gradient(180deg, #b9bdc4 0%, #8d929a 55%, #6a6f76 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Magnetic buttons --------------------------------------------- */
/* Critical: any element with data-magnetic CANNOT use a CSS transition
   on `transform` — GSAP's quickTo writes new transforms on every
   pointermove frame, and a CSS transform transition would intercept and
   slow each one down to its own duration/easing, making the magnet feel
   broken. We restrict the transition to non-transform properties so
   GSAP owns the transform exclusively. */
[data-magnetic] {
  will-change: transform;
  /* No `transform` in the transition list — magnetic writes inline
     transforms via GSAP at pointer rate; a CSS transform transition
     would slow each frame to its own duration. Inline style wins over
     the .cta:hover rule's translateY/scale, so magnetic positioning
     stays authoritative on hover. */
  transition-property: background, background-color, border-color, color, box-shadow, opacity;
}

/* Lenis interop ------------------------------------------------ */
/* When Lenis is active it adds .lenis (and .lenis-smooth during
   smooth-scroll). These rules keep nested scroll containers safe
   and prevent overflow conflicts. */
html.lenis,
html.lenis body {
  height: auto;
}
html.lenis [data-lenis-prevent] {
  overscroll-behavior: contain;
}
/* Lenis sets html.lenis-stopped on programmatic stops — preserve
   normal scroll then. */

/* Marquee strip ------------------------------------------------ */
.marquee {
  position: relative;
  width: 100%;
  height: clamp(56px, 7vh, 76px);
  overflow: hidden;
  background: linear-gradient(
    180deg,
    rgba(5, 6, 8, 0.85) 0%,
    rgba(10, 11, 13, 0.95) 100%
  );
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  z-index: 8;
}
.marquee-track {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  font-family: "Archivo", sans-serif;
  font-weight: 700;
  font-size: clamp(11px, 1vw, 14px);
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: rgba(236, 237, 240, 0.78);
  padding-left: 100%; /* start off-screen on the right */
  will-change: transform;
}
.marquee-track > span {
  display: inline-block;
  padding: 0 clamp(20px, 2.4vw, 36px);
  flex-shrink: 0;
}
.marquee-dot {
  color: rgba(255, 255, 255, 0.30);
  padding: 0 !important;
  font-size: 1.4em;
  line-height: 0;
}

/* 3D card tilt ------------------------------------------------ */
.service-card {
  transform-style: preserve-3d;
  perspective: 1000px;
}

/* Reduced motion ------------------------------------------------ */
/* Hard reset: every animatable target snaps to its final state.
   The JS also short-circuits, this CSS is the visual safety net. */
@media (prefers-reduced-motion: reduce) {
  [data-split],
  [data-parallax],
  .display {
    visibility: visible !important;
    transform: none !important;
    opacity: 1 !important;
  }
  .marquee-track { animation: none !important; transform: none !important; }
}
