/* ============================================================
   ADDITIVE ALIVENESS LAYER — motion-only presentation.
   Loaded after sections.css. All motion CSS is scoped under .motion-ready;
   static fallbacks under .motion-static / .is-solo / .is-reduced-motion.
   STRUCTURAL — content-free; copy as-is.
   ============================================================ */

/* Native cursor by default — no custom trailing cursor (it reads as laggy). */

/* Statement-media frame-scrub: swap the <canvas> in over the poster <video>
   once motion is live. The width-grow + canvas sizing live in sections.css /
   motion.js (initStatementMediaExpand). */
.motion-ready #statement-media .tilestone__canvas { display: block; }
.motion-ready #statement-media .tilestone__video { opacity: 0; }

/* Cinematic statement 3D card-swap primitives. */
.motion-ready .design-planning__stage {
  perspective: 1600px;
  transform-style: preserve-3d;
}

.motion-ready .design-planning__photo,
.motion-ready .design-planning__sketch {
  backface-visibility: hidden;
  transform-style: preserve-3d;
}

/* GPU hint scoped to the active swap: only promote the two layers while the loop
   is actually running. `is-live` is toggled by the ScrollTrigger in initCardSwap
   (onEnter -> add, onLeave -> remove), so the layers drop their compositor
   promotion the moment the swap is paused off-screen -- trims VRAM without
   touching the animation while it plays. */
.motion-ready .design-planning__stage.is-live .design-planning__photo,
.motion-ready .design-planning__stage.is-live .design-planning__sketch {
  will-change: transform, filter;
}

.motion-ready .design-planning__photo {
  z-index: 2;
  transform:
    translate3d(var(--dp-photo-x, 0), var(--dp-photo-y, 0), var(--dp-photo-z, 0))
    rotate(var(--dp-photo-r, 0deg))
    scale(var(--dp-photo-s, 1));
}

.motion-ready .design-planning__sketch {
  z-index: 3;
  transform:
    translate3d(var(--dp-sketch-x, 0), var(--dp-sketch-y, 0), var(--dp-sketch-z, 0))
    rotate(var(--dp-sketch-r, -4deg))
    scale(var(--dp-sketch-s, 1));
}

.motion-ready .design-planning__stage.is-swapped .design-planning__photo {
  z-index: 3;
}

.motion-ready .design-planning__stage.is-swapped .design-planning__sketch {
  z-index: 2;
}

/* Before/after tease (terracotta handle tint while teasing/dragging). */
.motion-ready .ba__handle,
.motion-ready .ba__grip {
  transition:
    background 220ms var(--ease-out),
    color 220ms var(--ease-out),
    box-shadow 220ms var(--ease-out);
}

.motion-ready .ba__slider.is-teasing .ba__handle,
.motion-ready .ba__slider.is-dragging .ba__handle {
  background: var(--terracotta);
}

.motion-ready .ba__slider.is-teasing .ba__grip,
.motion-ready .ba__slider.is-dragging .ba__grip {
  background: var(--terracotta);
  color: #fffaf3;
  box-shadow: 0 10px 30px rgba(192, 97, 61, 0.42);
}

.motion-ready .ba__slider.has-user-touched .ba__grip {
  background: rgba(245, 242, 236, 0.96);
  color: #121419;
}

.motion-ready .ba__slider.has-user-touched.is-dragging .ba__handle {
  background: var(--terracotta);
}

.motion-ready .ba__slider.has-user-touched.is-dragging .ba__grip {
  background: var(--terracotta);
  color: #fffaf3;
}

/* Hover micro-interactions — the scale-not-shift rule. */
.motion-ready .svc-tile,
.motion-ready .work-card,
.motion-ready .review-card,
.motion-ready .team-card,
.motion-ready .process__step,
.motion-ready .btn {
  transition:
    transform 360ms var(--ease-out),
    box-shadow 360ms var(--ease-out),
    border-color 360ms var(--ease-out),
    background 360ms var(--ease-out);
}

/* Every hover pop RISES a little AND scales up a touch (never a pure translate
   -- a pure translateY "felt weird"). Scale kept modest so a grown card's border
   never collides with its neighbour. */
.motion-ready .svc-tile:hover,
.motion-ready .work-card:hover,
.motion-ready .team-card:hover,
.motion-ready .process__step:hover {
  transform: translate3d(0, -0.28rem, 0) scale(1.025);
}

/* Reviews pop: scale grow + a soft drop-shadow bleeding toward neighbours.
   PAINT FIX: never animate box-shadow blur on hover (a per-frame paint op).
   The shadow lives on an always-painted ::after at opacity 0; the hover only
   transitions OPACITY (compositor-cheap) -- identical look, no repaint per
   frame. The card needs a stacking context for the layer to sit behind content. */
.motion-ready .review-card { position: relative; }
.motion-ready .review-card::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  box-shadow:
    0 30px 60px -34px rgba(0, 0, 0, 0.62),
    0 10px 26px -18px rgba(0, 0, 0, 0.45);
  transition: opacity 360ms var(--ease-out);
}
.motion-ready .review-card:hover {
  transform: translate3d(0, -0.16rem, 0) scale(1.04);
  z-index: 4;
  border-color: rgba(236, 233, 227, 0.42);
}
.motion-ready .review-card:hover::after { opacity: 1; }

.motion-ready [data-motion-depth] {
  will-change: transform;
}

/* Drop the reveal GPU hint once revealed. base.css sets will-change on every
   .js [data-reveal] so the reveal composites smoothly, but never cleared it --
   leaving dozens of retained compositor layers (real VRAM) at rest on long
   pages. Once a reveal finishes it carries .is-in; clear the hint there.
   (Loaded after base.css, so this wins on source order.) */
.js [data-reveal].is-in {
  will-change: auto;
}

/* Scope rail — ZERO hover fx: sections.css pauses .scope-rail__track on
   :hover/:focus-within; override it so the word rail keeps scrolling under the
   cursor, untouched. (Remove this rule if you DO want hover-to-pause on a rail.) */
.scope-rail:hover .scope-rail__track,
.scope-rail:focus-within .scope-rail__track {
  animation-play-state: running;
}

/* Statement-media side labels stay visible without motion (gsap never hides them). */
.motion-static #statement-media .tilestone__side,
.is-solo #statement-media .tilestone__side,
.is-reduced-motion #statement-media .tilestone__side {
  opacity: 1;
  transform: none;
}
