/* S243 — Cinematic visual lift. Motion layer for canonical-homepage.html.
   Loaded as <link rel="stylesheet" href="motion/hero-motion.css">.
   Companion: motion/hero-motion.js (GSAP timelines + Lenis).
   Designed to survive JS-off (default-visible everything except the Frame B crossfade target).
*/

/* ─────────── Hero — stacked frames + Ken Burns origin ─────────── */
.hero-cinematic {
  position: relative;
  isolation: isolate;
}
.hero-cinematic .hero-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  z-index: 0;
}
.hero-cinematic .hero-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: 52% 48%; /* slightly off-center so Ken Burns drifts toward the ridge */
  will-change: transform, opacity;
}
.hero-cinematic .hero-frame--a { z-index: 1; }
.hero-cinematic .hero-frame--b {
  z-index: 2;
  opacity: 0;        /* GSAP fades in across scroll progress */
}
.hero-cinematic .hero-scrim-layer {
  position: absolute;
  inset: 0;
  z-index: 3;
  background: linear-gradient(to bottom, rgba(0,0,0,0.65) 0%, rgba(0,0,0,0.20) 45%, rgba(0,0,0,0.85) 100%);
  pointer-events: none;
  transition: opacity 0.6s ease;
}

/* ─────────── Hero scroll cue (S260) — affordance for the static-feeling first frame ───────────
   Visible on load, bobs gently, fades out on first scroll (toggled by the inline site-behaviour
   script via .scroll-cue--hidden). Decorative (aria-hidden); the nav provides real navigation. */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: clamp(20px, 4.5vh, 44px);
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  opacity: 1;
  pointer-events: none;
  transform: translateX(-50%);
  transition: opacity 0.5s ease;
  animation: scroll-cue-bob 2s ease-in-out infinite;
}
.scroll-cue--hidden { opacity: 0; }
.scroll-cue__label {
  font-family: "Cinzel", serif;
  font-size: 10px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: rgba(201, 169, 97, 0.85);
}
.scroll-cue__chevron {
  width: 9px;
  height: 9px;
  border-right: 1px solid rgba(201, 169, 97, 0.9);
  border-bottom: 1px solid rgba(201, 169, 97, 0.9);
  transform: rotate(45deg);
}
@keyframes scroll-cue-bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(6px); }
}
/* Mobile pass #1 (Avy S303): center the scroll cue vertically on mobile; desktop keeps it
   at the bottom. Uses top + margin (not translateY) so the bob keyframes stay intact. */
@media (max-width: 767px) {
  .scroll-cue { top: 50%; bottom: auto; margin-top: -15px; }
}
@media (prefers-reduced-motion: reduce) {
  .scroll-cue { animation: none; }
}

/* ─────────── Liquid-glass surface language (Apple / 21st.dev register, restrained) ─────────── */
.glass-surface,
.glass-surface--dim {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.glass-surface {
  background: linear-gradient(135deg, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.02) 100%);
  /* Blur radius reduced 18px → 10px to lighten GPU cost — perceptually equivalent at this opacity */
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border: 1px solid rgba(255,255,255,0.06);
  box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset, 0 24px 60px -30px rgba(0,0,0,0.6);
}
.glass-surface--dim {
  background: linear-gradient(135deg, rgba(10,10,10,0.55) 0%, rgba(10,10,10,0.40) 100%);
  /* Blur radius reduced 22px → 12px — backdrop is mostly opaque so blur barely visible anyway */
  backdrop-filter: blur(12px) saturate(120%);
  -webkit-backdrop-filter: blur(12px) saturate(120%);
  border: 1px solid rgba(255,255,255,0.05);
}
/* Specular sheen — diagonal light streak sweeps across glass surface on hover/focus.
   21st.dev / Apple tier micro-interaction. Animates transform (compositor) not left (paint). */
.glass-surface::after,
.glass-surface--dim::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;
  background: linear-gradient(120deg, transparent 30%, rgba(255, 255, 255, 0.05) 50%, transparent 70%);
  transform: translate3d(-160%, 0, 0);
  transition: transform 1.6s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  z-index: 1;
  will-change: transform;
}
.glass-surface:hover::after,
.glass-surface:focus-within::after,
.glass-surface--dim:hover::after,
.glass-surface--dim:focus-within::after {
  transform: translate3d(220%, 0, 0);
}

/* (Iter 7 cleanup: ambient body::before + body > * rules removed — sections opaque-covered the ambient
   layer, so it was paying for a full-viewport composite layer with no visible payoff. Sections that
   want depth can apply radial-gradients to their own background instead.) */
header.glass-active {
  background: linear-gradient(180deg, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.35) 100%) !important;
  /* Blur radius reduced 20px → 10px — the header is small + on-scroll, where lighter blur reads same */
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
}

/* ─────────── Bespoke section reveal initial states ───────────
   IMPORTANT: only applied AFTER document.documentElement gets `.motion-ready`
   class from JS. If JS never lands (or reduced-motion is on), defaults stay visible.
*/
.motion-ready .reveal[data-reveal-pattern="rise"] > *,
.motion-ready .reveal[data-reveal-pattern="line-draw"] > *,
.motion-ready .reveal[data-reveal-pattern="card-grid"] > *,
.motion-ready .reveal[data-reveal-pattern="rule-expand"] > *,
.motion-ready .reveal[data-reveal-pattern="form-stagger"] > * {
  opacity: 0;
  transform: translateY(28px);
}

/* line-draw: the vertical gold line in Promise scales from 0 height */
.motion-ready .reveal[data-reveal-pattern="line-draw"] .reveal-line {
  transform: scaleY(0);
  transform-origin: top center;
}

/* rule-expand: the short horizontal gold rule in FAQ scales from 0 width */
.motion-ready .reveal[data-reveal-pattern="rule-expand"] .reveal-rule {
  transform: scaleX(0);
  transform-origin: center;
}

/* card-grid (S244 iter 1, replaces row-stagger): each capability card rises from below with stagger */
.motion-ready .reveal[data-reveal-pattern="card-grid"] .reveal-card {
  opacity: 0;
  transform: translateY(36px);
}

/* form-stagger: contact form fields cascade in */
.motion-ready .reveal[data-reveal-pattern="form-stagger"] .reveal-field {
  opacity: 0;
  transform: translateY(14px);
}

/* cinematic-still (S244 iter 1): atmospheric interstitial — image scales 1.05 → 1.0 on entry */
.motion-ready .reveal[data-reveal-pattern="cinematic-still"] .interstitial-frame img {
  transform: scale(1.05);
}
.motion-ready .reveal[data-reveal-pattern="cinematic-still"] > * {
  opacity: 1;
  transform: none; /* the breather doesn't translate — only the image scales */
}

/* ─────────── Vanish-on-exit + Swap-in (S243 iter 3 → iter 4 bolder variant) ───────────
   Reciprocal pair: section A vanishes on exit (left|right), the IMMEDIATELY-FOLLOWING
   section B swaps in from the opposite side during the same scroll window. Reads as one
   global-slider transition driven by vertical scroll. JS handles the GSAP timing; CSS just
   keeps transforms on the compositor for performance.
*/
.motion-ready [data-vanish-direction],
.motion-ready [data-enter-direction] {
  will-change: transform, opacity;
}

/* ─────────── Horizontal pinned slider (S243 iter 3 bolder variant) ───────────
   Used in the parallax-breaker slot (variant). Section pins for ~300vh of scroll while
   .slider-strip translates left, revealing 4 photo panels in sequence.
*/
.horizontal-slider-section {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background: #050505;
}
.slider-viewport {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.slider-strip {
  display: flex;
  height: 100%;
  width: 400vw; /* 4 panels × 100vw */
  will-change: transform;
}
.slider-panel {
  position: relative;
  flex: 0 0 100vw;
  height: 100%;
  overflow: hidden;
  isolation: isolate;
}
.slider-panel__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: 50% 55%;
}
.slider-panel__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0.20) 40%, rgba(0,0,0,0.75) 100%);
  pointer-events: none;
  z-index: 1;
}
.slider-panel__content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  padding: clamp(48px, 8vw, 120px);
}
.slider-panel__content--center {
  align-items: center;
  justify-content: center;
  text-align: center;
}
/* Progress dots (composition reference for the slider) */
.slider-progress {
  position: absolute;
  bottom: clamp(32px, 5vh, 60px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 12px;
  z-index: 3;
}
.slider-progress__dot {
  width: 6px;
  height: 1px;
  background: rgba(255, 255, 255, 0.25);
  transition: width 0.4s ease, background 0.4s ease;
}
.slider-progress__dot--active {
  width: 32px;
  background: #c9a961;
}

/* Slider panel reveal: subtle Ken Burns on the active panel (the active class is added by JS) */
.slider-panel__img {
  transform: scale(1.05);
  transition: transform 1.8s cubic-bezier(0.22, 1, 0.36, 1);
}
.slider-panel--active .slider-panel__img {
  transform: scale(1.0);
}

/* Hero stagger targets (animated by GSAP timeline against scrub) */
.motion-ready .hero-cinematic [data-motion-target] {
  opacity: 0;
  transform: translateY(16px);
}

/* ─────────── Parallax breaker — S244 iter 1: image → multi-stop gradient ───────────
   Reasoning: the image read pixelized when stretched 1920w → full-bleed at 80vh, and a chapter divider
   slot doesn't need a photograph. The gradient gives composed depth: warm gold pool top-left echoing
   the hero's golden hour, cool dark pool bottom-right for weight, diagonal editorial base.
*/
.parallax-gradient {
  background:
    radial-gradient(ellipse 90% 60% at 22% 28%, rgba(201,169,97,0.14) 0%, transparent 58%),
    radial-gradient(ellipse 70% 70% at 78% 78%, rgba(28,40,62,0.55) 0%, transparent 65%),
    linear-gradient(160deg, #050505 0%, #0b0e15 35%, #15191f 60%, #07080c 100%);
  position: relative;
}
.parallax-gradient::after {
  /* Subtle film-grain on top of the gradient so it doesn't read as flat CSS — finer than .noise. */
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.08;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.95' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* ─────────── Atmospheric interstitial (S244 iter 1) — section 2.5, pre-Capabilities breather ─────────── */
.interstitial-cinematic {
  height: clamp(50vh, 65vh, 70vh);
  isolation: isolate;
}
.interstitial-frame {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
}
.interstitial-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: center;
  will-change: transform;
}
.interstitial-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0.10) 50%, rgba(0,0,0,0.50) 100%);
  pointer-events: none;
}

/* ─────────── Capability cards (S243 iter 2 → iter 3) — 3-up grid, 4:5 portrait media + content + liquid-glass hover ─────────── */
.cap-grid {
  /* S243 iter 3: real breathing room between cards per Avy ("more spaced"). Was 1px hairline grid; now clamp-fluid gap. */
  gap: clamp(20px, 2.5vw, 36px);
  background: transparent;
  border: none;
}
.cap-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: #0a0a0a;
  overflow: hidden;
  isolation: isolate;
  transition: background 0.6s ease, transform 0.6s ease, box-shadow 0.6s ease;
  /* Subtle 1px border so each card has its own edge instead of melting into the surface */
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.cap-card:hover,
.cap-card:focus-within {
  /* Lift on hover to reinforce the new spacing — each card feels like its own object */
  transform: translateY(-4px);
  box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.8), 0 0 0 1px rgba(201, 169, 97, 0.12);
}
.cap-card__media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
}
.cap-card__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: 50% 55%;
  transition: transform 1.2s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}
.cap-card:hover .cap-card__img,
.cap-card:focus-within .cap-card__img {
  transform: scale(1.05);
}
.cap-card__media-scrim {
  /* Resting state: top half dark for content separation, gentle bottom darken for legibility */
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.05) 30%, rgba(0,0,0,0.55) 100%);
  transition: background 0.6s ease;
  pointer-events: none;
}
.cap-card:hover .cap-card__media-scrim,
.cap-card:focus-within .cap-card__media-scrim {
  /* Hover: liquid-glass-tinted overlay — gold-warm wash. Backdrop-filter dropped (it was barely
     visible at 2px blur and added a per-card GPU cost; the saturation/wash carries the effect). */
  background: linear-gradient(180deg, rgba(0,0,0,0.30) 0%, rgba(201,169,97,0.08) 50%, rgba(0,0,0,0.65) 100%);
}
.cap-card__content {
  position: relative;
  z-index: 2;
  /* S250: liquid-glass panel pulled up over the lower image so the blur frosts the photo behind it
     (was a solid #0a0a0a gradient panel). Matches the nav / contact-aside glass register. */
  margin-top: clamp(-84px, -7vw, -56px);
  padding: clamp(24px, 3vw, 36px);
  background: linear-gradient(135deg, rgba(12,12,12,0.55) 0%, rgba(12,12,12,0.40) 100%);
  backdrop-filter: blur(14px) saturate(130%);
  -webkit-backdrop-filter: blur(14px) saturate(130%);
  border-top: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.04) inset;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  overflow: hidden;
}
/* Specular sheen sweep across the glass panel on hover (same micro-interaction as .glass-surface) */
.cap-card__content::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;
  background: linear-gradient(120deg, transparent 30%, rgba(255, 255, 255, 0.05) 50%, transparent 70%);
  transform: translate3d(-160%, 0, 0);
  transition: transform 1.6s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  z-index: 1;
  will-change: transform;
}
.cap-card:hover .cap-card__content::after,
.cap-card:focus-within .cap-card__content::after {
  transform: translate3d(220%, 0, 0);
}
/* Touch (no :hover) — S253: replay the liquid-glass effect on scroll-into-view, since hover never
   fires on a phone. JS adds .cap-card--inview to each card as it reveals; the sheen sweeps once,
   the gold wash settles, and the image holds a gentle zoom. Gated to (hover: none) so desktop —
   which already gets all this on hover — is physically unaffected. */
@media (hover: none) {
  .cap-card--inview .cap-card__content::after { transform: translate3d(220%, 0, 0); }
  .cap-card--inview .cap-card__img { transform: scale(1.04); }
  .cap-card--inview .cap-card__media-scrim {
    background: linear-gradient(180deg, rgba(0,0,0,0.30) 0%, rgba(201,169,97,0.08) 50%, rgba(0,0,0,0.65) 100%);
  }
}
/* keep text/arrow above the sheen */
.cap-card__content > * {
  position: relative;
  z-index: 2;
}
.cap-card__arrow {
  margin-top: auto;
}

/* Mobile (stacked single-column): cards stay generously spaced, slightly shorter media for above-the-fold reads */
@media (max-width: 767px) {
  .cap-grid {
    gap: 28px;
  }
  .cap-card__media {
    aspect-ratio: 4 / 3;
  }
  .cap-card:hover,
  .cap-card:focus-within {
    transform: none; /* lift effect off on touch; the photo + content is enough */
    box-shadow: 0 12px 30px -16px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(201, 169, 97, 0.10);
  }
  /* Slider on mobile (S253): the SAME pinned, full-viewport, scroll-driven slider as desktop —
     scroll down moves the panels left-to-right (Avy: replicate the homepage behaviour). The base
     desktop layout (absolute viewport, 400vw flex strip, 100vw panels) already does this; we only
     need the section to cover the device. Use small-viewport height (100svh) so the iOS address bar
     can't make the pinned section overflow; browsers without svh fall back to the base 100vh.
     JS runs the GSAP pin on all widths now (no mobile branch), with ScrollTrigger.config
     ignoreMobileResize keeping the pin steady when the address bar shows/hides. */
  .horizontal-slider-section { height: 100svh; }
  .slider-panel__content { padding: clamp(24px, 7vw, 56px); }
  .slider-progress { bottom: clamp(20px, 4vh, 36px); }
}

/* ─────────── prefers-reduced-motion full fallback ─────────── */
@media (prefers-reduced-motion: reduce) {
  .hero-cinematic .hero-frame--b { opacity: 0 !important; }
  .hero-cinematic .hero-frame img { transform: none !important; }
  .motion-ready .reveal[data-reveal-pattern] > *,
  .motion-ready .reveal[data-reveal-pattern] .reveal-line,
  .motion-ready .reveal[data-reveal-pattern] .reveal-rule,
  .motion-ready .reveal[data-reveal-pattern] .reveal-card,
  .motion-ready .reveal[data-reveal-pattern] .reveal-field,
  .motion-ready .reveal[data-reveal-pattern="cinematic-still"] .interstitial-frame img,
  .motion-ready .hero-cinematic [data-motion-target] {
    opacity: 1 !important;
    transform: none !important;
  }
  /* Cap card hover scale + glass overlay are amplifications — disable */
  .cap-card:hover .cap-card__img,
  .cap-card:focus-within .cap-card__img {
    transform: none !important;
  }
  .cap-card:hover .cap-card__media-scrim,
  .cap-card:focus-within .cap-card__media-scrim {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  /* Cap-card glass panel → opaque, no blur, no sheen (ADR-008 reduced-motion downgrade) */
  .cap-card__content {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: rgba(12, 12, 12, 0.95) !important;
  }
  .cap-card__content::after { display: none !important; }
  /* Parallax gradient grain overlay — skip mix-blend on reduced motion to avoid flicker */
  .parallax-gradient::after {
    display: none !important;
  }
  /* Specular sheen on glass — disable the sweep, keep glass static */
  .glass-surface::after,
  .glass-surface--dim::after {
    display: none !important;
  }
  /* Ambient body radial — keep visible (static, no motion) */
  /* Vanish-on-exit + Swap-in (S243 iter 3 → iter 4 bolder): no sweep, no fade — sections stay put */
  .motion-ready [data-vanish-direction],
  .motion-ready [data-enter-direction] {
    transform: none !important;
    opacity: 1 !important;
  }
  /* Horizontal pinned slider (S243 iter 3 bolder): convert to vertical stack of panels, no pin, no horizontal slide */
  .horizontal-slider-section {
    height: auto !important;
  }
  .slider-strip {
    flex-direction: column !important;
    width: 100vw !important;
    height: auto !important;
    transform: none !important;
  }
  .slider-panel {
    flex: 0 0 auto !important;
    width: 100vw !important;
    height: 70vh !important;
  }
  .slider-panel__img {
    transform: none !important;
  }
  .slider-progress {
    display: none !important;
  }
  header.glass-active {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: rgba(0,0,0,0.9) !important;
  }
  .glass-surface,
  .glass-surface--dim {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background: rgba(20,20,20,0.92) !important;
  }
}

/* ── Checkbox: brand gold, not Tailwind blue (S315 fix) ───────────────────────
 * The canon markup asks for gold with accent-[#e6c479], but @tailwindcss/forms sets
 * appearance:none on checkboxes, and accent-color is a no-op on an unstyled-appearance
 * control. The plugin then paints the box from its own default colour (#2563eb), so
 * the private-catalogue opt-in has been rendering BLUE on a black-and-gold site.
 *
 * The plugin fills the checked box with `currentColor` (that is the seam it gives you:
 * you are meant to drive it with a text colour), and repeats that fill in its :hover
 * and :focus rules at the SAME specificity as anything we could write here — so a
 * specificity fight would be lost on source order. Setting `color` wins everywhere at
 * once, because every one of those rules resolves through it.
 */
input[type="checkbox"] {
  color: #e6c479;
}
/* The plugin's tick is white, which is weak on gold. Stamp a near-black one instead. */
input[type="checkbox"]:checked {
  border-color: #e6c479;
  background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='%230a0a0a' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0z'/%3e%3c/svg%3e");
}
input[type="checkbox"]:focus {
  --tw-ring-color: #e6c479;
  border-color: #e6c479;
}
