/* ============================================================
   CASE EXPERIENCE LAYER (assets/case/case.css) — immersive scroll
   for work/case pages. Every rule is gated on html.sa-case-live,
   which case.js adds ONLY when JS + motion are available. No-JS,
   reduced-motion (html.sa-case-static) and the editor all keep the
   plain skin.css layout untouched. Loaded after skin.css.
   ============================================================ */

/* ---- Environment layers: page bg morphs on .sa-case-bglayer (z -2),
   the THREE canvas floats above it (z -1), content above both.
   Body goes transparent so DOM + canvas read as ONE environment. ---- */
html.sa-case-live body { background: transparent; }
html.sa-case-live .wp-site-blocks { background: transparent; }
html.sa-case-live .sa-case-bglayer { position: fixed; inset: 0; z-index: -2; background: #f1f1f1; pointer-events: none; }
html.sa-case-live .sa-case-canvas { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }

/* ---- Intro depth polish. motion.js owns the h1 word split (.sa-w);
   we only deepen it: words settle from below with a blur+scale that
   clears as they land. Transition is a superset of skin.css's rule
   (same durations/ease/delay var) so the two layers never fight. ---- */
html.sa-case-live .sa-case-intro h1.sa-split .sa-w { transform: translateY(0.65em) scale(0.96); filter: blur(7px); transition: opacity 0.55s var(--sa-ease-out), transform 0.85s var(--sa-ease-out), filter 0.75s var(--sa-ease-out); transition-delay: var(--sa-w-delay, 0s); }
html.sa-case-live .sa-case-intro h1.sa-split.is-inview .sa-w { transform: none; filter: blur(0); }

/* Meta row: columns cascade with a rotateX settle (needs perspective
   on the row). Skin's .sa-reveal still drives opacity + timing. */
html.sa-case-live .sa-case-meta { perspective: 900px; }
html.sa-case-live .sa-case-meta > .wp-block-column.sa-reveal { transform: translateY(34px) rotateX(-16deg); transform-origin: 50% 0; }
html.sa-case-live .sa-case-meta > .wp-block-column.sa-reveal.is-inview { transform: none; }

/* ---- Hero plate (first single alignfull image): case.js scrubs the
   img scale/parallax; the figure clips so the oversize never bleeds. ---- */
html.sa-case-live .sa-case-heroplate { overflow: hidden; }
html.sa-case-live .sa-case-heroplate img { will-change: transform; }

/* ---- Pinned horizontal chapters (desktop only). case.js moves the
   stack's figures into .sa-case-h__track at runtime and pins the
   group; scroll scrubs the track sideways. 14vw side padding centres
   the first/last plate at the pin's start/end. ---- */
@media (min-width: 1024px) {
  html.sa-case-live .sa-case-h { overflow: hidden; }
  html.sa-case-live .sa-case-h__track { display: flex; align-items: center; gap: 4vw; height: 100vh; padding: 0 14vw; width: max-content; will-change: transform; }
  html.sa-case-live .sa-case-h__panel { flex: 0 0 auto; width: 72vw; max-width: none; margin: 0 !important; }
  html.sa-case-live .sa-case-h__panel img { width: 100%; height: auto; max-height: 80vh; object-fit: cover; border-radius: 12px; box-shadow: 0 40px 90px -40px rgba(4, 8, 24, 0.55); will-change: transform, filter; }
}
/* If the viewport shrinks after a desktop init, the pin reverts (gsap
   matchMedia) and the track falls back to a plain vertical stack. */
@media (max-width: 1023px) {
  html.sa-case-live .sa-case-h__track { display: block; }
  html.sa-case-live .sa-case-h__panel { margin: 0 0 16px !important; }
}

/* ---- Gallery tiles: JS drives entrance + tilt; perspective lives here. ---- */
html.sa-case-live .sa-case-grid { perspective: 1000px; }
html.sa-case-live .sa-case-grid > .wp-block-image,
html.sa-case-live .sa-case-pair > .wp-block-image { will-change: transform, opacity; }

/* ---- Carousel depth (motion.js owns behaviour, we only add the fan):
   slides get a subtle rotateY/scale/dim from case.js inline styles. ---- */
html.sa-case-live .sa-carousel .sa-carousel__track { perspective: 1200px; }
html.sa-case-live .sa-carousel .sa-carousel__track > figure,
html.sa-case-live .sa-carousel .sa-carousel__track > .wp-block-image { transform-origin: 50% 50%; will-change: transform, opacity; }

/* ---- Scroll thread: 2px brand line + dot on the right edge. ---- */
html.sa-case-live .sa-case-progress { position: fixed; top: 0; right: 16px; width: 2px; height: 100vh; z-index: 80; pointer-events: none; }
html.sa-case-live .sa-case-progress::before { content: ""; position: absolute; inset: 0; background: rgba(23, 23, 23, 0.1); }
html.sa-case-live .sa-case-progress__bar { position: absolute; inset: 0; background: var(--wp--preset--color--brand); transform: scaleY(0); transform-origin: 50% 0; }
html.sa-case-live .sa-case-progress__dot { position: absolute; top: 0; left: 50%; width: 8px; height: 8px; margin-left: -4px; border-radius: 50%; background: var(--wp--preset--color--brand); box-shadow: 0 0 0 4px rgba(0, 33, 255, 0.18); }
@media (max-width: 1023px) {
  html.sa-case-live .sa-case-progress { display: none; }
}

/* Belt-and-braces: case.js never creates these under reduced motion,
   but if the preference flips mid-session the layers disappear. */
@media (prefers-reduced-motion: reduce) {
  .sa-case-bglayer, .sa-case-canvas, .sa-case-progress { display: none !important; }
}

/* Overflow guard (v1.0.1): 100vw fixed layers exceed the layout viewport by the
   scrollbar/visual-viewport delta, and scaled plates overflow via transform —
   clip creates NO scroll container (same fix as .fx-main / v2.2 marquee). */
html.sa-case-live body { overflow-x: clip; }
.sa-case-canvas, .sa-case-bglayer { width: 100% !important; left: 0 !important; }

/* v1.0.2 mobile-viewport guard: the hero-plate scale tween made Chrome expand
   the mobile layout viewport to fit the transformed bounds (390 → 396). On
   narrow viewports images get no transforms at all, and the root clips. */
html.sa-case-live { overflow-x: clip; }
@media (max-width: 1023px) {
  html.sa-case-live .sa-case img, html.sa-case-live .wp-block-post-content .wp-block-image img { transform: none !important; }
}
