/* ==========================================================================
   ANIMATIONS — scroll reveals, entrances, ambient motion, keyframes.
   Everything here is compositor-only (transform / opacity / filter / clip-path)
   and every single effect is switched off under prefers-reduced-motion.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Scroll reveal — driven by one shared IntersectionObserver in reveal.js.
   Elements carry data-reveal="<variant>"; the observer adds .is-revealed.
   -------------------------------------------------------------------------- */

[data-reveal] {
  --reveal-delay: 0ms;
  transition:
    opacity var(--t-enter) var(--ease-out) var(--reveal-delay),
    transform var(--t-enter) var(--ease-out) var(--reveal-delay),
    clip-path var(--t-enter) var(--ease-out) var(--reveal-delay),
    filter var(--t-enter) var(--ease-out) var(--reveal-delay);
  will-change: opacity, transform;
}

[data-reveal='fade-up']   { opacity: 0; transform: translate3d(0, 34px, 0); }
[data-reveal='fade-in']   { opacity: 0; }
[data-reveal='fade-left'] { opacity: 0; transform: translate3d(-36px, 0, 0); }
[data-reveal='fade-right']{ opacity: 0; transform: translate3d(36px, 0, 0); }
[data-reveal='scale-in']  { opacity: 0; transform: scale(0.94); }
[data-reveal='clip-reveal'] { clip-path: inset(0 0 100% 0); opacity: 0; }
[data-reveal='mask-wipe']   { clip-path: inset(0 100% 0 0); }
[data-reveal='blur-in']   { opacity: 0; filter: blur(14px); transform: scale(1.04); }

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

/* Per-line headline wipe. split.js wraps each visual line in .line > .line__i
   so the inner span can slide up behind an overflow-clipped mask. */
.line { display: block; overflow: hidden; }
.line__i {
  display: block;
  transform: translate3d(0, 108%, 0);
  transition: transform 780ms var(--ease-out) var(--line-delay, 0ms);
  will-change: transform;
}
.is-revealed .line__i,
.hero.is-entered .line__i { transform: none; }

/* --------------------------------------------------------------------------
   Hero entrance — runs once on load, orchestrated by class not by observer.
   -------------------------------------------------------------------------- */

.hero__eyebrow,
.hero__lead,
.hero__actions,
.hero__scroll { opacity: 0; transform: translate3d(0, 20px, 0); }

.hero.is-entered .hero__eyebrow,
.hero.is-entered .hero__lead,
.hero.is-entered .hero__actions,
.hero.is-entered .hero__scroll {
  opacity: 1;
  transform: none;
  transition: opacity var(--t-enter) var(--ease-out) var(--d, 0ms),
              transform var(--t-enter) var(--ease-out) var(--d, 0ms);
}

.hero__media img { transform: scale(1.09); filter: blur(8px); opacity: 0; }
.hero.is-entered .hero__media img {
  transform: scale(1);
  filter: none;
  opacity: 1;
  transition: transform 1500ms var(--ease-out),
              filter 900ms var(--ease-out),
              opacity 700ms var(--ease-out);
}

/* Gold hairline that draws across before the headline lands. */
.hero__rule { transform: scaleX(0); transform-origin: left; }
.hero.is-entered .hero__rule {
  transform: scaleX(1);
  transition: transform 900ms var(--ease-out) 120ms;
}

/* --------------------------------------------------------------------------
   Ambient motion
   -------------------------------------------------------------------------- */

/* Slow-drifting blurred light behind heroes and CTA blocks. */
.orb {
  position: absolute;
  border-radius: 50%;
  pointer-events: none;
  filter: blur(70px);
  opacity: 0.34;
  will-change: transform;
}
.orb--gold   { background: radial-gradient(circle, var(--gold-500), transparent 68%); }
.orb--violet { background: radial-gradient(circle, var(--violet-500), transparent 68%); }
.orb--crimson{ background: radial-gradient(circle, var(--crimson-500), transparent 68%); }
.orb--a { animation: drift-a 21s var(--ease-in-out) infinite; }
.orb--b { animation: drift-b 17s var(--ease-in-out) infinite; }
.orb--c { animation: drift-c 25s var(--ease-in-out) infinite; }

@keyframes drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(6%, -8%, 0) scale(1.14); }
}
@keyframes drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.06); }
  50%      { transform: translate3d(-7%, 6%, 0) scale(0.94); }
}
@keyframes drift-c {
  0%, 100% { transform: translate3d(0, 0, 0) scale(0.96); }
  50%      { transform: translate3d(4%, 9%, 0) scale(1.1); }
}

/* Client-name marquee. Speed is nudged by scroll velocity in main.js via
   --marquee-boost, so it feels tied to the page rather than looping blindly. */
.marquee {
  display: flex;
  overflow: hidden;
  user-select: none;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  flex: none;
  gap: var(--s-7);
  padding-right: var(--s-7);
  min-width: 100%;
  animation: marquee 46s linear infinite;
  animation-duration: calc(46s / var(--marquee-boost, 1));
  will-change: transform;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: var(--s-4);
  font-family: var(--ff-display);
  font-size: clamp(1.1rem, 2vw, 1.6rem);
  font-weight: 600;
  color: var(--mist-500);
  white-space: nowrap;
  transition: color var(--t-base) var(--ease-out);
}
.marquee__item:hover { color: var(--gold-400); }
.marquee__item::after { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--gold-700); flex: none; }

@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Neon tube flicker — only used on the neon service page hero. */
.neon-text {
  color: var(--bone-50);
  text-shadow:
    0 0 6px rgb(237 27 51 / 0.9),
    0 0 18px rgb(237 27 51 / 0.7),
    0 0 42px rgb(237 27 51 / 0.5);
  animation: neon-breathe 4.5s var(--ease-in-out) infinite;
}
@keyframes neon-breathe {
  0%, 100% { opacity: 1; }
  46%      { opacity: 0.86; }
  48%      { opacity: 1; }
  52%      { opacity: 0.9; }
}

@keyframes wa-pulse {
  0%, 84%, 100% { transform: scale(1); }
  88%           { transform: scale(1.22); }
  92%           { transform: scale(0.96); }
  96%           { transform: scale(1.08); }
}

@keyframes draw-check {
  to { stroke-dashoffset: 0; }
}

/* Scroll cue */
.scroll-cue {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--mist-500);
}
.scroll-cue svg { width: 16px; height: 16px; color: var(--gold-500); animation: cue-bob 2.4s var(--ease-in-out) infinite; }
@keyframes cue-bob {
  0%, 100% { transform: translateY(0); opacity: 0.75; }
  50%      { transform: translateY(6px); opacity: 1; }
}

/* Scroll progress bar */
.progress {
  position: fixed;
  top: 0; left: 0;
  z-index: calc(var(--z-sticky) + 2);
  height: 2px;
  width: 100%;
  transform-origin: left;
  transform: scaleX(0);
  background: var(--grad-gold);
  pointer-events: none;
}

/* Gold curtain used for the page transition fallback. */
.curtain {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  pointer-events: none;
  background: var(--grad-gold);
  transform: scaleY(0);
  transform-origin: bottom;
}
.curtain.is-in { animation: curtain-in 520ms var(--ease-in-out) forwards; }
@keyframes curtain-in {
  0%   { transform: scaleY(0); transform-origin: bottom; }
  100% { transform: scaleY(1); transform-origin: bottom; }
}

/* Counter digits sit on tabular figures so the width doesn't jitter while
   the value animates. */
.counter { font-variant-numeric: tabular-nums; }

/* Custom cursor disc — desktop, fine pointer only. */
.cursor {
  position: fixed;
  top: 0; left: 0;
  z-index: var(--z-modal);
  display: none;
  place-items: center;
  width: 76px; height: 76px;
  margin: -38px 0 0 -38px;
  border-radius: 50%;
  background: var(--grad-gold);
  color: var(--ink-950);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  pointer-events: none;
  opacity: 0;
  /* Parked off-canvas until JS takes over. At 0,0 the negative margins would
     push it 38px past the left edge and widen the document on narrow screens.
     JS overwrites this transform wholesale on first pointermove. */
  transform: translate3d(-300px, -300px, 0) scale(0.3);
  transition: opacity 220ms var(--ease-out), transform 320ms var(--ease-spring);
}
.cursor.is-active { opacity: 1; transform: scale(1); }
@media (hover: hover) and (pointer: fine) {
  .cursor { display: grid; }
}

/* --------------------------------------------------------------------------
   Reduced motion — a hard off switch.
   Content must land in its final, fully readable state with no movement.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  html { scroll-behavior: auto; }

  [data-reveal],
  [data-reveal].is-revealed {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    clip-path: none !important;
  }

  .line__i { transform: none !important; }

  .hero__eyebrow, .hero__lead, .hero__actions, .hero__scroll,
  .hero__media img, .hero__rule,
  .megamenu__item, .mobile-menu__link {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }

  /* Ambient motion is decoration only — remove it entirely. */
  .orb { animation: none !important; opacity: 0.2; }
  .marquee__track { animation: none !important; }
  .marquee {
    overflow-x: auto;
    mask-image: none;
    -webkit-mask-image: none;
  }
  .scroll-cue svg, .mobile-bar__wa svg, .neon-text { animation: none !important; }
  .progress, .curtain, .cursor { display: none !important; }

  /* Parallax and pinning are disabled in JS; neutralise any inline transform
     that was already written to the element. */
  [data-parallax] { transform: none !important; }
}
