/* ==========================================================================
   ANIMATIONS — Hale Custom Signs
   Rules:
   1. transform + opacity only. Never animate layout properties.
   2. Custom easing tokens only. No ease-in-out defaults.
   3. will-change applied surgically, stripped by JS after settle.
   4. Everything degrades to "visible, static" under prefers-reduced-motion.
   ========================================================================== */

/* ==========================================================================
   1. SCROLL-TRIGGERED REVEALS
   JS (animations.js) adds .is-in via IntersectionObserver, then unobserves —
   so reveals never re-trigger on scroll-back.
   ========================================================================== */
[data-reveal] {
  opacity: 0;
  transition:
    opacity var(--d-reveal) var(--e-out),
    transform var(--d-reveal) var(--e-out);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: transform, opacity;
}
[data-reveal="up"] {
  transform: translateY(38px);
}
[data-reveal="down"] {
  transform: translateY(-38px);
}
[data-reveal="left"] {
  transform: translateX(-46px);
}
[data-reveal="right"] {
  transform: translateX(46px);
}
[data-reveal="scale"] {
  transform: scale(0.9);
}
[data-reveal="blur"] {
  filter: blur(14px);
  transform: translateY(24px);
  transition:
    opacity var(--d-reveal) var(--e-out),
    transform var(--d-reveal) var(--e-out),
    filter var(--d-reveal) var(--e-out);
}
/* Dimensional letters rising off the wall */
[data-reveal="letter"] {
  transform: translateY(30px) translateZ(-60px) rotateX(-22deg);
  transform-origin: bottom center;
}
[data-reveal].is-in {
  opacity: 1;
  transform: none;
  filter: none;
}
/* JS strips will-change here after the transition ends */
[data-reveal].is-settled {
  will-change: auto;
}

/* ==========================================================================
   2. HERO ENTRANCE — choreographed, not simultaneous
   eyebrow -> headline words -> lede -> CTAs -> ornament
   ========================================================================== */
@keyframes riseIn {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes riseInLetter {
  from {
    opacity: 0;
    transform: translateY(0.5em) rotateX(-45deg);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* WARNING: .enter owns the `animation` shorthand on its element. Never put
   .enter on the same element as another animating class (.gold-leaf--live,
   .float, .neon-strike, .tube-breathe) — the later rule in the cascade wins
   the shorthand outright and the loser silently never runs, leaving the
   element stuck at opacity:0. Nest them on separate elements instead. */
.enter {
  opacity: 0;
  animation: riseIn var(--d-slower) var(--e-out) forwards;
  animation-delay: var(--enter-delay, 0ms);
}

/* Word-level headline reveal. JS wraps each word in .word > span. */
.word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  /* padding stops descenders/glow being clipped by overflow */
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.word > span {
  display: inline-block;
  opacity: 0;
  animation: riseInLetter 900ms var(--e-out) forwards;
  animation-delay: var(--word-delay, 0ms);
  transform-origin: bottom center;
}

/* ==========================================================================
   3. FLOATING — decorative layers only. Offset delays so nothing syncs.
   ========================================================================== */
@keyframes floatY {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-18px);
  }
}
@keyframes floatDrift {
  0%,
  100% {
    transform: translate(0, 0) rotate(0deg);
  }
  33% {
    transform: translate(10px, -14px) rotate(1.6deg);
  }
  66% {
    transform: translate(-8px, -6px) rotate(-1.2deg);
  }
}
@keyframes floatSlow {
  0%,
  100% {
    transform: translateY(0) scale(1);
  }
  50% {
    transform: translateY(-26px) scale(1.03);
  }
}

.float {
  animation: floatY 6s var(--e-in-out) infinite;
  animation-delay: var(--float-delay, 0s);
}
.float--drift {
  animation: floatDrift 14s var(--e-in-out) infinite;
  animation-delay: var(--float-delay, 0s);
}
.float--slow {
  animation: floatSlow 9s var(--e-in-out) infinite;
  animation-delay: var(--float-delay, 0s);
}

/* ==========================================================================
   4. NEON — the signature effect
   Authentic tube behaviour: a burst of struggle, then steady burn.
   Runs once on entrance, NOT infinitely (an infinitely flickering sign is a
   broken sign, and it is an accessibility problem).
   ========================================================================== */
@keyframes neonStrike {
  0% {
    opacity: 0.15;
    text-shadow: none;
  }
  6% {
    opacity: 0.9;
    text-shadow:
      0 0 4px rgba(255, 246, 221, 0.9),
      0 0 12px rgba(248, 192, 8, 0.7);
  }
  9% {
    opacity: 0.2;
    text-shadow: none;
  }
  14% {
    opacity: 1;
    text-shadow:
      0 0 4px rgba(255, 246, 221, 0.9),
      0 0 12px rgba(248, 192, 8, 0.8),
      0 0 26px rgba(248, 192, 8, 0.5);
  }
  18% {
    opacity: 0.3;
    text-shadow: none;
  }
  22% {
    opacity: 0.85;
  }
  26% {
    opacity: 0.4;
  }
  32%,
  100% {
    opacity: 1;
    text-shadow:
      0 0 4px rgba(255, 246, 221, 0.9),
      0 0 11px rgba(248, 192, 8, 0.8),
      0 0 24px rgba(248, 192, 8, 0.6),
      0 0 52px rgba(248, 192, 8, 0.36),
      0 0 90px rgba(248, 192, 8, 0.2);
  }
}
.neon-strike {
  animation: neonStrike 1.9s var(--e-snap) forwards;
  animation-delay: var(--strike-delay, 0ms);
}

/* Gentle breathing glow for a tube that's warmed up */
@keyframes tubeBreathe {
  0%,
  100% {
    filter: brightness(1);
  }
  50% {
    filter: brightness(1.14);
  }
}
.tube-breathe {
  animation: tubeBreathe 4.5s var(--e-in-out) infinite;
}

/* Gold-leaf shimmer — a slow specular travelling across the fill */
@keyframes goldShimmer {
  0% {
    background-position: 50% 0%;
  }
  50% {
    background-position: 50% 100%;
  }
  100% {
    background-position: 50% 0%;
  }
}
.gold-leaf--live {
  animation: goldShimmer 7s var(--e-in-out) infinite;
}

/* ==========================================================================
   5. PARALLAX
   JS writes --py (px). Depth planes move at different rates via data-speed.
   ========================================================================== */
[data-parallax] {
  will-change: transform;
  transform: translate3d(0, var(--py, 0px), 0);
}
[data-parallax="scale"] {
  transform: translate3d(0, var(--py, 0px), 0) scale(var(--pscale, 1));
}

/* ==========================================================================
   6. 3D TILT
   JS writes --rx/--ry from pointer position.
   ========================================================================== */
.tilt-scene {
  perspective: 1100px;
}
.tilt {
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))
    translateZ(var(--tz, 0px));
  transition: transform var(--d-slow) var(--e-out);
  will-change: transform;
}
.tilt.is-tilting {
  /* while actively tracking the pointer, drop the easing for 1:1 response */
  transition: none;
}

/* ==========================================================================
   7. MARQUEE — the moving message board
   ========================================================================== */
@keyframes marquee {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}
.marquee {
  position: relative;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    #000 8%,
    #000 92%,
    transparent
  );
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee var(--marquee-dur, 42s) linear infinite;
}
.marquee:hover .marquee__track {
  animation-play-state: paused;
}
.marquee__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  padding-inline: var(--sp-5);
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 0.9rem + 0.7vw, 1.6rem);
  letter-spacing: var(--tr-label);
  text-transform: uppercase;
  color: var(--text-low);
  white-space: nowrap;
  transition: color var(--d-base) var(--e-out);
}
.marquee__item:hover {
  color: var(--gold-400);
}
.marquee__item i {
  width: 5px;
  height: 5px;
  background: var(--crimson-500);
  transform: rotate(45deg);
  flex: none;
  box-shadow: var(--glow-crimson);
}

/* ==========================================================================
   8. SCAN LINE — the CNC cutting head crossing a surface
   ========================================================================== */
@keyframes scanLine {
  0% {
    transform: translateY(-100%);
    opacity: 0;
  }
  10%,
  90% {
    opacity: 1;
  }
  100% {
    transform: translateY(100%);
    opacity: 0;
  }
}
.scan::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    transparent,
    rgba(248, 192, 8, 0.5),
    transparent
  );
  height: 40%;
  animation: scanLine 5s var(--e-in-out) infinite;
  animation-delay: var(--scan-delay, 0s);
}

/* ==========================================================================
   9. CUSTOM CURSOR — desktop + fine pointer only
   ========================================================================== */
.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-cursor);
  width: 28px;
  height: 28px;
  margin: -14px 0 0 -14px;
  border: 1px solid var(--gold-500);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(var(--cx, 0px), var(--cy, 0px), 0) scale(var(--cs, 1));
  transition:
    opacity var(--d-base) var(--e-out),
    width var(--d-base) var(--e-out),
    height var(--d-base) var(--e-out),
    background var(--d-base) var(--e-out);
  will-change: transform;
  mix-blend-mode: difference;
}
.cursor.is-active {
  opacity: 1;
}
.cursor.is-hovering {
  background: rgba(248, 192, 8, 0.22);
  width: 52px;
  height: 52px;
  margin: -26px 0 0 -26px;
}
.cursor__dot {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-cursor);
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  background: var(--gold-500);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0);
  transition: opacity var(--d-base) var(--e-out);
  will-change: transform;
}
.cursor__dot.is-active {
  opacity: 1;
}
/* Only ever engage on a real mouse */
@media (hover: none), (pointer: coarse) {
  .cursor,
  .cursor__dot {
    display: none !important;
  }
}

/* ==========================================================================
   10. MAGNETIC — JS writes --mx/--my on pointer proximity
   ========================================================================== */
.magnetic {
  transform: translate3d(var(--mx, 0px), var(--my, 0px), 0);
  transition: transform var(--d-slow) var(--e-spring);
  will-change: transform;
}
.magnetic.is-pulling {
  transition: transform 90ms linear;
}

/* ==========================================================================
   11. LIGHTBOX
   ========================================================================== */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: var(--sp-5);
  background: rgba(4, 3, 9, 0.94);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--d-slow) var(--e-out),
    visibility var(--d-slow);
}
.lightbox.is-open {
  opacity: 1;
  visibility: visible;
}
.lightbox__figure {
  position: relative;
  max-width: min(1200px, 92vw);
  max-height: 84vh;
  transform: scale(0.94) translateY(16px);
  transition: transform var(--d-slow) var(--e-spring);
}
.lightbox.is-open .lightbox__figure {
  transform: none;
}
.lightbox__img {
  max-width: 100%;
  max-height: 76vh;
  width: auto;
  object-fit: contain;
  border-radius: var(--r-md);
  box-shadow: var(--sh-4);
  border: 1px solid var(--border-strong);
  background: var(--ink-850);
}
.lightbox__cap {
  margin-top: var(--sp-4);
  text-align: center;
  font-size: var(--fs-body-sm);
  color: var(--text-mid);
}
.lightbox__cap span {
  display: block;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--text-low);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.lightbox__close,
.lightbox__nav {
  position: absolute;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: rgba(6, 4, 13, 0.8);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: var(--text-hi);
  transition:
    background var(--d-fast) var(--e-out),
    border-color var(--d-fast) var(--e-out),
    color var(--d-fast) var(--e-out),
    transform var(--d-base) var(--e-out);
}
.lightbox__close svg,
.lightbox__nav svg {
  width: 18px;
  height: 18px;
}
.lightbox__close:hover,
.lightbox__nav:hover {
  background: var(--gold-500);
  border-color: var(--gold-500);
  color: var(--ink-950);
}
.lightbox__close {
  top: calc(var(--sp-5) * -1 - 8px);
  right: 0;
}
.lightbox__nav--prev {
  left: calc(var(--sp-7) * -1);
  top: 38%;
}
.lightbox__nav--next {
  right: calc(var(--sp-7) * -1);
  top: 38%;
}
.lightbox__nav--prev:hover {
  transform: translateX(-3px);
}
.lightbox__nav--next:hover {
  transform: translateX(3px);
}
@media (max-width: 860px) {
  .lightbox__nav--prev {
    left: 0;
    top: auto;
    bottom: -66px;
  }
  .lightbox__nav--next {
    right: 0;
    top: auto;
    bottom: -66px;
  }
  .lightbox__close {
    top: -60px;
  }
}

/* ==========================================================================
   12. FLIP — review/gallery filter transitions
   JS sets --flip-x/--flip-y/--flip-s, then removes .is-flipping to play.
   ========================================================================== */
.flip-item {
  transition:
    transform var(--d-slow) var(--e-out),
    opacity var(--d-base) var(--e-out);
}
.flip-item.is-flipping {
  transition: none;
  transform: translate(var(--flip-x, 0px), var(--flip-y, 0px))
    scale(var(--flip-s, 1));
}
.flip-item.is-entering {
  opacity: 0;
  transform: scale(0.9) translateY(14px);
}
.flip-item.is-exiting {
  opacity: 0;
  transform: scale(0.9);
  pointer-events: none;
}

/* ==========================================================================
   13. COUNTER — no layout shift while digits tick
   ========================================================================== */
.counter {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* ==========================================================================
   14. REDUCED MOTION — the hard stop
   Everything above resolves to its final, visible, static state.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-reveal],
  [data-reveal].is-in {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
    will-change: auto !important;
  }
  .enter,
  .word > span {
    opacity: 1 !important;
    animation: none !important;
    transform: none !important;
  }
  .float,
  .float--drift,
  .float--slow,
  .tube-breathe,
  .gold-leaf--live,
  .neon-strike,
  .scan::after {
    animation: none !important;
  }
  /* A struck neon tube should still READ as lit when motion is off */
  .neon-strike {
    opacity: 1 !important;
    text-shadow:
      0 0 4px rgba(255, 246, 221, 0.9),
      0 0 11px rgba(248, 192, 8, 0.8),
      0 0 24px rgba(248, 192, 8, 0.6),
      0 0 52px rgba(248, 192, 8, 0.36) !important;
  }
  .marquee__track {
    animation: none !important;
    transform: none !important;
  }
  .marquee {
    overflow-x: auto;
  }
  [data-parallax] {
    transform: none !important;
    will-change: auto !important;
  }
  .tilt {
    transform: none !important;
    will-change: auto !important;
  }
  .magnetic {
    transform: none !important;
    will-change: auto !important;
  }
  .cursor,
  .cursor__dot {
    display: none !important;
  }
  .card:hover,
  .review-card:hover,
  .btn:hover {
    transform: none !important;
  }
  .lightbox__figure {
    transform: none !important;
  }
  .spinner {
    animation: none !important;
    border-top-color: rgba(255, 255, 255, 0.3);
  }
}
