/* ============================================================
   Studio Practice — Design System v2
   Shared across all pages. Loaded via:
     <link rel="stylesheet" href="/assets/sp-design-v2.css">

   Apple-DNA premium direction. Off-white system, borderless,
   generous whitespace, real work as rest beats, modern motion.
   Techniques: OKLCH + color-mix, View Transitions, container
   queries, backdrop-filter (-webkit- prefixed), dvh, magnetic
   interactions, accessible reduced-motion paths, font-variation
   axes (Fraunces opsz + SOFT).

   Cascade layers (low → high specificity):
     reset       — normalizations
     tokens      — :root custom properties
     base        — typography, body defaults
     components  — nav, footer, carousel, cards, form, etc.
     utilities   — single-purpose helpers (.inner, .eyebrow, .reveal)
     overrides   — page-specific escape hatches
   ============================================================ */

@layer reset, tokens, base, components, utilities, overrides;

/* ONE source of truth for the light body background (+ ink/muted/line/accent).
   Change /assets/sp-tokens.css once and the whole site + the tools move together.
   No per-page background edits. */
@import "/assets/sp-tokens.css";

@view-transition { navigation: auto; }

/* Navigation crossfade — keep SHORT. At 600ms every internal nav felt
   sluggish ("takes a while to load back and forth", 2026-06-09). */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 260ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
::view-transition-old(wordmark),
::view-transition-new(wordmark) {
  animation-duration: 260ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

:root {
  color-scheme: light;
  /* Surface — Apple-near-white system */
  --bg:           var(--sp-bg, oklch(99% 0.002 80));   /* one source: /assets/sp-tokens.css (#fcfcfa) */
  --bg-raised:   #ffffff;
  --bg-warm:      oklch(96% 0.008 80);          /* warm sand for one section */
  --bg-deep:      oklch(15% 0.008 80);          /* deep ink for contrast moment */

  /* Ink */
  --ink:          oklch(20% 0.005 80);          /* #1d1d1f Apple-ink */
  --ink-2:        oklch(38% 0.005 80);
  --muted:        oklch(52% 0.006 80);          /* #6e6e73 */
  --subtle:       oklch(78% 0.005 80);

  /* Lines */
  --line:         oklch(88% 0.004 80);          /* #d2d2d7 hairline */
  --line-soft:    oklch(94% 0.003 80);

  /* Accent — quieter, less saturated than the original navy */
  --accent:       oklch(46% 0.11 248);
  --accent-soft:  oklch(72% 0.07 248);
  --accent-tint:  oklch(96% 0.018 248);

  /* Layout */
  --inner:        1320px;
  --pad-x:        clamp(24px, 5vw, 72px);
  --pad-y:        clamp(96px, 12vw, 168px);
  --pad-y-tight:  clamp(64px, 8vw, 112px);

  /* Grid — 12-col (Simple Grid API on modern CSS Grid). Container stays wide; --inner is the width. */
  --gutter:       clamp(24px, 2.2vw, 32px);   /* one uniform column gutter — 8-pt endpoints (24→32) */
  --bp-grid:      768px;                       /* stack → grid breakpoint (also hardcoded in @media below) */
  /* 8-pt spacing scale — snap gaps/padding to these */
  --space-3xs: 4px;  --space-2xs: 8px;  --space-xs: 12px; --space-sm: 16px;
  --space-md: 24px;  --space-lg: 32px;  --space-xl: 48px; --space-2xl: 64px;
  --space-3xl: 96px; --space-4xl: 128px;

  /* Motion */
  --ease:         cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-out:     cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast:       180ms;
  --t-base:       360ms;
  --t-slow:       900ms;

  /* Type */
  --serif:        "Fraunces", "Times New Roman", serif;
  --sans:         "DM Sans", -apple-system, system-ui, sans-serif;
  --mono:         "JetBrains Mono", ui-monospace, monospace;

  --eyebrow-size: 11px;
  --eyebrow-track: 0.18em;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  overflow-x: clip;
  overscroll-behavior-x: none;
}
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.55;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  overscroll-behavior-x: none;
}
::selection { background: var(--accent); color: #fff; }

img, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; border: 0; background: transparent; color: inherit; }

/* Web Component FOUC prevention — reserve layout space, hide content until
   sp-shell.js defines the elements. No visible flash, no shift on define. */
sp-nav:not(:defined) {
  display: flex;
  height: 64px;
  visibility: hidden;
}
sp-footer:not(:defined) {
  display: block;
  min-height: 380px;
  visibility: hidden;
}

.inner { max-width: var(--inner); margin: 0 auto; padding-inline: var(--pad-x); }

/* ==== 12-COLUMN GRID — Simple Grid API (.container / .row / .col-N) on modern CSS Grid ====
   Mobile-first: columns are full width and stack; at >=768px .col-N take their span.
   .col-N-sm holds its span even on mobile. Gutter + width are tokens (stays wide, 1320). */
.container { width: 100%; max-width: var(--inner); margin-inline: auto; padding-inline: var(--pad-x); }
.container.narrow { max-width: 960px; }   /* long-form / manuscript pages */
.row { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter); }
[class^="col-"], [class*=" col-"] { grid-column: span 12; }   /* base: full width (stacked) */
.col-1-sm{grid-column:span 1}.col-2-sm{grid-column:span 2}.col-3-sm{grid-column:span 3}.col-4-sm{grid-column:span 4}
.col-5-sm{grid-column:span 5}.col-6-sm{grid-column:span 6}.col-7-sm{grid-column:span 7}.col-8-sm{grid-column:span 8}
.col-9-sm{grid-column:span 9}.col-10-sm{grid-column:span 10}.col-11-sm{grid-column:span 11}.col-12-sm{grid-column:span 12}
@media (min-width: 768px) {
  .col-1{grid-column:span 1}.col-2{grid-column:span 2}.col-3{grid-column:span 3}.col-4{grid-column:span 4}
  .col-5{grid-column:span 5}.col-6{grid-column:span 6}.col-7{grid-column:span 7}.col-8{grid-column:span 8}
  .col-9{grid-column:span 9}.col-10{grid-column:span 10}.col-11{grid-column:span 11}.col-12{grid-column:span 12}
}
.eyebrow {
  font-family: var(--mono);
  font-size: var(--eyebrow-size);
  font-weight: 500;
  letter-spacing: var(--eyebrow-track);
  text-transform: uppercase;
  color: var(--muted);
}

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 350;
  margin: 0;
  text-wrap: balance;
  letter-spacing: -0.018em;
  line-height: 1.04;
  font-variation-settings: "opsz" 144, "SOFT" 30;
  hanging-punctuation: first allow-end; /* Safari — quotes hang into the margin */
}
h1 em, h2 em, h3 em { font-style: italic; color: var(--muted); font-weight: 400; }
p { text-wrap: pretty; }

/* ============================================================
   Scroll progress hairline (top of viewport)
   ============================================================ */
.scroll-progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  transform-origin: 0 50%;
  transform: scaleX(0);
  background: var(--accent);
  z-index: 200;
  pointer-events: none;
  opacity: 0.6;
}
@supports (animation-timeline: scroll()) {
  .scroll-progress {
    animation: progress linear;
    animation-timeline: scroll(root);
  }
  @keyframes progress { to { transform: scaleX(1); } }
}

/* ============================================================
   Nav — Apple-style transparent → backdrop blur
   ============================================================ */
/* ============================================================
   NAV — defaults to inverted (black ink bg, white text) for
   light-background pages. On pages with a dark hero behind the
   nav, add `class="has-hero"` to <body> for the transparent-over-
   hero treatment that returns to black on scroll.
   ============================================================ */
.nav {
  position: sticky;
  top: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 64px;
  padding-inline: var(--pad-x);
  background: rgba(20, 21, 24, 0.72); /* fallback for any color-mix issues */
  background: color-mix(in oklch, var(--ink) 72%, transparent);
  backdrop-filter: saturate(180%) blur(28px);
  -webkit-backdrop-filter: saturate(180%) blur(28px);
  border-bottom: 1px solid rgba(255,255,255,0.1);
  transition: background 420ms var(--ease),
              backdrop-filter 420ms var(--ease),
              border-color 420ms var(--ease);
}
.nav-wordmark {
  display: flex; align-items: center; gap: 10px;
  color: #fff;
  transition: color 360ms var(--ease);
}
.nav-wordmark img {
  width: 28px; height: 28px;
  filter: invert(1) brightness(2);
  transition: filter 360ms var(--ease);
}
.nav-sp-wordmark {
  font-family: var(--serif);
  font-size: 18px;
  font-weight: 500;
  letter-spacing: -0.01em;
}
.nav-links {
  display: flex; align-items: center; gap: 32px;
}
.nav-links a {
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  color: rgba(255,255,255,0.78);
  position: relative;
  padding-block: 6px;
  letter-spacing: 0;
  transition: color 360ms var(--ease-out), letter-spacing 420ms var(--ease-out);
}
.nav-links a:not(.nav-client-login)::after {
  content: "";
  position: absolute;
  left: 50%;
  right: 50%;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transition: left 460ms var(--ease-out), right 460ms var(--ease-out);
}
.nav-links a:not(.nav-client-login):hover {
  color: #fff;
  letter-spacing: -0.012em;
}
.nav-links a.active { color: #fff; }
.nav-links a:hover::after,
.nav-links a.active::after { left: 0; right: 0; }

.nav-links a.nav-client-login {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.85);
  padding: 9px 16px;
  border: 1px solid rgba(255,255,255,0.45);
  border-radius: 100px;
  background: transparent;
  transition: color 280ms var(--ease-out),
              background 360ms var(--ease-out),
              border-color 280ms var(--ease-out),
              transform 360ms var(--ease-out),
              box-shadow 360ms var(--ease-out),
              letter-spacing 360ms var(--ease-out);
}
.nav-links a.nav-client-login:hover {
  color: var(--ink);
  background: #fff;
  border-color: #fff;
  transform: translateY(-1px);
  letter-spacing: 0.18em;
  box-shadow: 0 10px 24px -10px rgba(0,0,0,0.35);
}
.nav-links a.nav-client-login:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px -2px rgba(0,0,0,0.35);
}
/* Book a Time — the single primary CTA. Ink-filled on the solid nav; white over the hero. */
.nav-links a.nav-book {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #fff;
  background: var(--ink);
  border: 1px solid var(--ink);
  padding: 9px 16px;
  border-radius: 100px;
  transition: background 360ms var(--ease-out),
              color 280ms var(--ease-out),
              transform 360ms var(--ease-out),
              box-shadow 360ms var(--ease-out),
              letter-spacing 360ms var(--ease-out);
}
.nav-links a.nav-book::after { display: none; }
.nav-links a.nav-book:hover {
  color: #fff;
  transform: translateY(-1px);
  letter-spacing: 0.18em;
  box-shadow: 0 12px 26px -12px rgba(0,0,0,0.4);
}
.nav-links a.nav-book:active { transform: translateY(0); box-shadow: 0 2px 6px -2px rgba(0,0,0,0.35); }
.nav-hamburger {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  /* 44px tap-target floor; icon stays 20px, padding is invisible hit area */
  min-width: 44px;
  min-height: 44px;
  padding: 8px;
  margin-right: -12px; /* keep the icon optically on the pad-x edge */
}
.nav-hamburger span {
  width: 20px;
  height: 1.5px;
  background: #fff;
  transition: background 360ms var(--ease);
}

/* ============================================================
   HAS-HERO MODE — when body has class="has-hero", the nav goes
   transparent + white over the hero image until user scrolls.
   ============================================================ */
body.has-hero .nav:not(.is-scrolled) {
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
body.has-hero .nav:not(.is-scrolled) .nav-wordmark { color: #fff; }
body.has-hero .nav:not(.is-scrolled) .nav-wordmark img { filter: invert(1) brightness(2); }
body.has-hero .nav:not(.is-scrolled) .nav-links a { color: rgba(255,255,255,0.78); }
body.has-hero .nav:not(.is-scrolled) .nav-links a:not(.nav-client-login):hover { color: #fff; }
body.has-hero .nav:not(.is-scrolled) .nav-links a.active { color: #fff; }
body.has-hero .nav:not(.is-scrolled) .nav-links a.nav-client-login {
  color: rgba(255,255,255,0.85);
  border-color: rgba(255,255,255,0.45);
}
body.has-hero .nav:not(.is-scrolled) .nav-links a.nav-client-login:hover {
  color: var(--ink);
  background: #fff;
  border-color: #fff;
  box-shadow: 0 10px 24px -10px rgba(0,0,0,0.35);
}
body.has-hero .nav:not(.is-scrolled) .nav-hamburger span { background: #fff; }
body.has-hero .nav:not(.is-scrolled) .nav-links a.nav-book {
  color: var(--ink); background: #fff; border-color: #fff;
}
body.has-hero .nav:not(.is-scrolled) .nav-links a.nav-book:hover {
  color: var(--ink); background: #fff; box-shadow: 0 12px 26px -12px rgba(0,0,0,0.45);
}

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-hamburger { display: flex; }
}

/* Mobile menu */
.mobile-menu {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 100dvh;
  background: var(--bg);
  z-index: 100;
  display: flex;
  flex-direction: column;
  /* Flush left, stacked from the top under the nav line — reads like a
     table of contents (Wilfredo, 2026-06-09: not a fan of centered) */
  align-items: flex-start;
  justify-content: flex-start;
  padding: 96px var(--pad-x) 48px;
  gap: 32px;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease);
}
.mobile-menu.is-open { opacity: 1; pointer-events: auto; }
.mobile-menu a {
  font-family: var(--serif);
  font-size: clamp(36px, 8vw, 56px);
  font-weight: 300;
  color: var(--ink);
}
.mobile-menu-close {
  position: absolute; top: 18px; right: 24px;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
}

/* ============================================================
   HERO — full-bleed carousel
   ============================================================ */
.hero {
  position: relative;
  width: 100%;
  /* Definite height (56.25vw = 16:9 of the width, floored 480, capped 820) instead of
     aspect-ratio + max-height: Safari resolves the slides' height:100% against the
     un-clamped aspect-ratio height and overflows the caption out of the clip; a definite
     height resolves identically in Safari and Chromium. */
  height: clamp(480px, 56.25vw, 820px);
  overflow: hidden;
  background: var(--ink);
  view-transition-name: hero;
  /* Slide under the transparent nav so the hero image shows through it */
  margin-top: -64px;
}
.hero::before {
  /* Subtle film grain for premium tactility */
  content: "";
  position: absolute; inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.6'/></svg>");
}
.carousel-track {
  display: flex;
  height: 100%;
  width: 100%;
  transition: transform 900ms var(--ease-out);
  will-change: transform;
}
.carousel-slide {
  flex: 0 0 100%;
  position: relative;
  overflow: hidden;
}
.carousel-slide img,
.carousel-slide video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center center;
  transform: scale(1.04);
  transition: transform 6s var(--ease-out), filter var(--t-slow) var(--ease);
  filter: brightness(0.92);
}
.carousel-slide.is-active img,
.carousel-slide.is-active video {
  transform: scale(1.0);
  filter: brightness(1);
}
.carousel-slide::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(0,0,0,0.42) 0%,
    rgba(0,0,0,0.12) 18%,
    rgba(0,0,0,0) 38%,
    rgba(0,0,0,0) 55%,
    rgba(0,0,0,0.58) 100%);
  pointer-events: none;
}

.carousel-caption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: clamp(28px, 5vw, 56px) var(--pad-x) clamp(32px, 4vw, 56px);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  color: #fff;
}
.caption-cat {
  display: block;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: rgba(255,255,255,0.7);
  margin-bottom: 14px;
}
.caption-title {
  display: block;
  font-family: var(--serif);
  font-size: clamp(40px, 6vw, 84px);
  font-weight: 300;
  letter-spacing: -0.015em;
  line-height: 1;
  margin-bottom: 14px;
}
.caption-desc {
  display: block;
  font-size: 16px;
  max-width: 520px;
  color: rgba(255,255,255,0.82);
  line-height: 1.5;
}
.caption-right {
  display: flex; flex-direction: column; align-items: flex-end; gap: 18px;
}
.caption-url {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgba(255,255,255,0.6);
}

.carousel-nav {
  position: absolute;
  left: 50%; bottom: 24px;
  transform: translateX(-50%);
  display: flex; gap: 8px;
  z-index: 3;
}
.carousel-dot {
  width: 18px;
  height: 2px;
  border-radius: 1px;
  background: rgba(255,255,255,0.32);
  transition: width 520ms var(--ease-out), background 280ms var(--ease-out);
  cursor: pointer;
  padding: 0;
}
.carousel-dot.is-active {
  width: 36px;
  background-color: #fff;
}
.carousel-dot:hover { background-color: rgba(255,255,255,0.6); }

/* Pause/play toggle — WCAG 2.2.2 stop mechanism for the auto-advance.
   Created by sp-main.js only when auto-advance is running. Sits just right
   of the centered dots row; --dots-w is set by JS (the +18px allows for the
   active dot growing 18px wider after init). */
.carousel-pause {
  position: absolute;
  z-index: 3;
  bottom: 4px;
  left: calc(50% + var(--dots-w, 200px) / 2 + 18px);
  display: flex;
  align-items: center;
  justify-content: center;
  /* 44px hit area around a small quiet glyph */
  width: 44px; height: 44px;
  color: rgba(255,255,255,0.55);
  transition: color 280ms var(--ease-out);
}
.carousel-pause:hover,
.carousel-pause:focus-visible { color: #fff; }
.carousel-pause svg { width: 12px; height: 12px; display: block; }

.carousel-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 48px; height: 48px;
  border-radius: 50%;
  background: rgba(0,0,0,0.3);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: rgba(255,255,255,0.85);
  font-size: 22px;
  display: flex; align-items: center; justify-content: center;
  z-index: 3;
  opacity: 0;
  transition: opacity var(--t-base) var(--ease), background var(--t-fast);
}
.hero:hover .carousel-btn { opacity: 1; }
.carousel-btn:hover { background: rgba(0,0,0,0.55); color: #fff; }
.carousel-btn-prev { left: 24px; }
.carousel-btn-next { right: 24px; }

@media (max-width: 760px) {
  /* On narrow screens 16:9 would be too short — size to viewport height instead */
  .hero { height: clamp(480px, 70dvh, 640px); }
  .carousel-caption {
    flex-direction: column;
    align-items: flex-start;
    gap: 18px;
    padding-bottom: 56px;  /* room for dots */
  }
  .caption-right { align-items: flex-start; }
  .caption-title { font-size: 38px; }
  .carousel-btn { display: none; }
  .caption-desc { font-size: 14px; }
}

/* ============================================================
   Voice band — quiet positioning statement
   ============================================================ */
.voice {
  padding-block: var(--pad-y);
  background: var(--bg);
}
.voice-inner { display: grid; grid-template-columns: 6fr 6fr; gap: var(--gutter); align-items: end; }
.voice-headline {
  font-size: clamp(48px, 8vw, 112px);
  letter-spacing: -0.025em;
  line-height: 0.96;
}
.voice-sub {
  font-size: 18px;
  line-height: 1.65;
  color: var(--muted);
  max-width: 480px;
  margin-bottom: 12px;
}
.voice-makers {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 24px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  position: relative;
  padding-block: 4px;
  /* letter-spacing intentionally NOT animated on hover. Combined with the
     gap change, it widened the link's bounding box enough that the cursor
     fell outside the new hit area, fired mouseleave, snapped back, and
     oscillated. The underline draw-in below carries the breathing intent
     without any layout shift. (Confirmed shake bug 2026-05-27.) */
  transition: gap 280ms var(--ease-out),
              color 280ms var(--ease-out);
}
.voice-makers::after {
  content: "";
  position: absolute;
  left: 50%;
  right: 50%;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transition: left 460ms var(--ease-out), right 460ms var(--ease-out);
}
.voice-makers:hover {
  gap: 14px;
}
.voice-makers:hover::after { left: 0; right: 0; }
@media (max-width: 860px) {
  .voice-inner { grid-template-columns: 1fr; }
}

/* ============================================================
   Section heading pattern
   ============================================================ */
.section-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 32px;
  padding-bottom: 48px;
  margin-bottom: clamp(48px, 6vw, 80px);
  border-bottom: 1px solid var(--line);
}
.section-head h2 {
  font-size: clamp(40px, 5vw, 72px);
}
.section-num {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted);
}

/* ============================================================
   Services — borderless, generous, visual-led
   ============================================================ */
.services {
  padding-block: var(--pad-y);
  container-type: inline-size;
}
.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);   /* 4 / 4 / 4 on the 12-col grid */
  gap: var(--gutter);
}
@container (max-width: 880px) {
  .services-grid { grid-template-columns: 1fr; }
}
.service-card {
  position: relative;
  background: var(--bg-raised);
  border-radius: 18px;
  overflow: hidden;
  transition: transform var(--t-base) var(--ease),
              box-shadow var(--t-base) var(--ease);
  will-change: transform;
}
.service-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 24px 60px -28px rgba(29,29,31,0.18);
}
.service-visual {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--bg-warm);
  overflow: hidden;
}
.service-visual img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.2s var(--ease-out);
}
.service-card:hover .service-visual img { transform: scale(1.04); }
.service-info {
  padding: 28px 28px 32px;
  display: flex; flex-direction: column; gap: 14px;
}
.service-num {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--accent);
}
.service-name {
  font-size: clamp(26px, 2.5vw, 34px);
  line-height: 1.05;
}
.service-desc {
  font-size: 15px;
  color: var(--muted);
  margin: 0;
}
.service-tags {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-top: 8px;
}
.service-tag {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink-2);
  padding: 6px 10px;
  background: var(--bg-warm);
  border-radius: 100px;
}
@media (max-width: 860px) {
  .services-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Featured rest beat — half-page work moment
   ============================================================ */
.feature {
  padding-block: var(--pad-y);
  background: var(--bg-deep);
  color: #fff;
  position: relative;
  overflow: hidden;
}
.feature::before {
  /* Subtle radial wash for depth */
  content: "";
  position: absolute;
  inset: -10% -5%;
  background:
    radial-gradient(60% 70% at 70% 20%,
      color-mix(in oklch, var(--accent) 22%, transparent) 0%,
      transparent 65%),
    radial-gradient(50% 60% at 10% 90%,
      color-mix(in oklch, var(--accent-soft) 14%, transparent) 0%,
      transparent 70%);
  pointer-events: none;
  z-index: 0;
}
.feature .inner { position: relative; z-index: 1; }
.feature .feature-eyebrow { color: rgba(255,255,255,0.6); }
.feature .feature-desc    { color: rgba(255,255,255,0.78); }
.feature .feature-meta    { color: rgba(255,255,255,0.55); border-color: rgba(255,255,255,0.14); }
.feature .feature-title em { color: rgba(255,255,255,0.55); }

.feature-inner {
  display: grid;
  grid-template-columns: 5fr 7fr;   /* snapped to 12-col: col-5 / col-7 */
  gap: var(--gutter);
  align-items: center;
}
.feature.reverse .feature-inner { grid-template-columns: 7fr 5fr; }   /* col-7 / col-5 */
.feature.reverse .feature-text { order: 2; }
.feature.reverse .feature-visual { order: 1; }
.feature-eyebrow {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 20px;
}
.feature-title {
  font-size: clamp(40px, 5vw, 76px);
  line-height: 1.0;
  letter-spacing: -0.02em;
}
.feature-desc {
  margin-top: 24px;
  font-size: 17px;
  line-height: 1.65;
  color: var(--muted);
  max-width: 460px;
}
.feature-meta {
  margin-top: 28px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  display: flex; gap: 32px;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted);
}
.feature-visual {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 40px 80px -32px rgba(29,29,31,0.25);
  aspect-ratio: 16 / 10;
  background: #000;
}
.feature-visual img,
.feature-visual video {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.5s var(--ease-out);
}
.feature:hover .feature-visual img,
.feature:hover .feature-visual video { transform: scale(1.025); }
@media (max-width: 860px) {
  .feature-inner,
  .feature.reverse .feature-inner { grid-template-columns: 1fr; gap: 40px; }
  .feature.reverse .feature-text { order: 1; }
  .feature.reverse .feature-visual { order: 2; }
}

/* ============================================================
   Lab + Mission — paired borderless cards
   ============================================================ */
.lab {
  padding-block: var(--pad-y);
}
.lab-grid {
  display: grid;
  grid-template-columns: 6fr 6fr;
  gap: var(--gutter);
}
.lab-card {
  position: relative;
  display: grid;
  grid-template-rows: 1fr auto;
  background: var(--bg-raised);
  border-radius: 20px;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  isolation: isolate;
  transition: transform var(--t-base) var(--ease);
}
.lab-card:hover { transform: translateY(-4px); }
.lab-card-visual {
  position: absolute; inset: 0;
  z-index: 0;
}
.lab-card-visual img,
.lab-card-visual video {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.5s var(--ease-out);
}
.lab-card:hover .lab-card-visual img,
.lab-card:hover .lab-card-visual video { transform: scale(1.04); }
.lab-card-text {
  position: relative;
  z-index: 1;
  align-self: end;
  padding: 32px 36px 36px;
  color: #fff;
  background: linear-gradient(180deg,
    rgba(0,0,0,0) 0%,
    rgba(0,0,0,0.65) 70%,
    rgba(0,0,0,0.85) 100%);
}
.lab-eyebrow {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: rgba(255,255,255,0.7);
  margin-bottom: 16px;
}
.lab-headline {
  font-size: clamp(32px, 3.6vw, 52px);
  color: #fff;
  line-height: 1.02;
  margin-bottom: 16px;
}
.lab-headline em { color: rgba(255,255,255,0.7); }
.lab-desc {
  margin: 0 0 20px;
  font-size: 15px;
  line-height: 1.55;
  color: rgba(255,255,255,0.78);
  max-width: 440px;
}
.lab-cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: #fff;
  transition: gap var(--t-fast);
}
.lab-card:hover .lab-cta { gap: 14px; }
@media (max-width: 860px) {
  .lab-grid { grid-template-columns: 1fr; }
  .lab-card { aspect-ratio: 4 / 4; }
}

/* ============================================================
   Process
   ============================================================ */
.process {
  padding-block: var(--pad-y);
  background: var(--bg);
}
.process-grid {
  display: grid;
  grid-template-columns: 6fr 6fr;
  gap: var(--gutter);
  align-items: start;
}
.process-headline {
  font-size: clamp(40px, 5vw, 76px);
  letter-spacing: -0.02em;
  line-height: 1.02;
}
.process-body p {
  margin: 0 0 16px;
  color: var(--ink-2);
  font-size: 17px;
  line-height: 1.65;
  max-width: 460px;
}
.process-more { margin-top: 30px; }
.process-more a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  padding-bottom: 5px;
  transition: color 0.25s, border-color 0.25s, gap 0.25s;
}
.process-more a:hover {
  color: var(--accent);
  border-color: var(--accent);
  gap: 12px;
}
.process-stats {
  margin-top: 40px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px 32px;
  padding-top: 32px;
  border-top: 1px solid var(--line);
}
.process-stat-label {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.process-stat-value {
  font-family: var(--serif);
  font-size: 26px;
  font-weight: 400;
}
@media (max-width: 860px) {
  .process-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Contact — light editorial section (drop deep navy)
   ============================================================ */
.contact {
  padding-block: var(--pad-y);
  background: var(--accent-tint);
}
.contact-eyebrow {
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 48px;
}
.contact-layout {
  display: grid;
  grid-template-columns: 6fr 6fr;
  gap: var(--gutter);
  align-items: start;
}
.contact-left-headline {
  font-size: clamp(48px, 6vw, 92px);
  letter-spacing: -0.02em;
  line-height: 0.98;
  margin-bottom: 20px;
}
.contact-left-desc {
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink-2);
  margin: 0 0 32px;
  max-width: 420px;
}
.contact-socials { display: flex; gap: 14px; margin-top: 32px; }
.social-link {
  width: 40px; height: 40px;
  border-radius: 50%;
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-2);
  transition: all var(--t-fast);
}
.social-link svg { width: 16px; height: 16px; }
.social-link:hover {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

.contact-form { display: flex; flex-direction: column; gap: 32px; }
.contact-field { display: flex; flex-direction: column; gap: 10px; }
.contact-field label {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted);
}
.contact-field input,
.contact-field textarea {
  font: inherit;
  font-size: 17px;
  padding: 10px 0;
  border: 0;
  border-bottom: 1px solid color-mix(in oklch, var(--ink) 18%, transparent);
  background: transparent;
  border-radius: 0;
  color: var(--ink);
  transition: border-bottom-color 280ms var(--ease-out);
}
.contact-field input::placeholder,
.contact-field textarea::placeholder {
  color: var(--muted);
  opacity: 0.7;
}
.contact-field input:focus,
.contact-field textarea:focus {
  outline: none;
  border-bottom-color: var(--ink);
}
.contact-field textarea {
  resize: vertical;
  min-height: 80px;
  font-family: inherit;
  line-height: 1.5;
}

.contact-submit {
  align-self: flex-start;
  padding: 14px 26px;
  background: var(--ink);
  color: var(--bg);
  border: 1px solid var(--ink);
  border-radius: 100px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  transition: color 280ms var(--ease-out),
              background 360ms var(--ease-out),
              border-color 280ms var(--ease-out),
              transform 360ms var(--ease-out),
              box-shadow 360ms var(--ease-out),
              letter-spacing 360ms var(--ease-out);
}
.contact-submit:hover {
  color: var(--ink);
  background: transparent;
  border-color: var(--ink);
  transform: translateY(-1px);
  letter-spacing: 0.22em;
  box-shadow: 0 14px 28px -14px color-mix(in oklch, var(--ink) 45%, transparent);
}
.contact-submit:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px -2px color-mix(in oklch, var(--ink) 40%, transparent);
}
.contact-submit:disabled { opacity: 0.55; cursor: wait; }

.contact-form-status {
  margin: 0;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.contact-form-status[data-state="ok"]  { color: var(--accent); }
.contact-form-status[data-state="err"] { color: oklch(50% 0.15 25); }

@media (max-width: 860px) {
  .contact-layout { grid-template-columns: 1fr; }
}

/* ============================================================
   Footer — denser, multi-column

   FOOTER CSS MAP — these styles live in 3 places; keep in sync:
     • main site pages  → assets/sp-design-v2.css   (this file: .footer-col, --ink-* tokens)
     • embedded footers → assets/sp-shell-embed.css + assets/sp-footer-embed.css
                          (sp-footer.site-footer, self-contained --spf-* tokens)
   Standalone subdir projects bundle their own copies (e.g. special-projects/tesla-charging-audit).
   DARK footers are not a variant here — they're per-page overrides
   (clients/index.html, payment-system/styles.css). Most footers render light.
   Full reference: BRAND_ASSETS.md § Footer CSS map.
   ============================================================ */
.site-footer {
  display: block; /* custom elements default to inline; needed for vertical padding */
  background: var(--bg);
  border-top: 1px solid var(--line);
  padding: 96px 0 64px;
}
.site-footer .inner {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
}
.footer-brand { grid-column: span 4; }   /* brand block — 4 of 12 */
.footer-col   { grid-column: span 2; }    /* each link group — 2 of 12 (4+2+2+2+2 = 12) */
.footer-col h3 {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 18px;
}
.footer-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.footer-col a {
  font-size: 14px;
  color: var(--ink-2);
  position: relative;
  display: inline-block;
  padding-block: 2px;
  letter-spacing: 0;
  transition: color 280ms var(--ease-out), letter-spacing 420ms var(--ease-out);
}
.footer-col a::after {
  content: "";
  position: absolute;
  left: 50%; right: 50%; bottom: 0;
  height: 1px;
  background: currentColor;
  transition: left 460ms var(--ease-out), right 460ms var(--ease-out);
}
.footer-col a:hover { color: var(--ink); letter-spacing: -0.01em; }
.footer-col a:hover::after { left: 0; right: 0; }

/* Social row (Connect) — monoline icons. NOTE: footer styles are duplicated in
   sp-shell-embed.css and sp-footer-embed.css; keep these three in sync. */
.footer-social { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; margin-top: 2px; }
.footer-social a { display: inline-flex; padding: 0; color: var(--ink-2); transition: color 280ms var(--ease-out), transform 280ms var(--ease-out); }
.footer-social a::after { display: none; }
.footer-social a:hover { color: var(--ink); transform: translateX(2px); letter-spacing: 0; }
.footer-social svg { width: 20px; height: 20px; display: block; }

.footer-brand {
  display: flex; flex-direction: column; gap: 14px;
  max-width: 340px;
}
.footer-brand .footer-wordmark {
  display: flex; align-items: center; gap: 10px;
}
.footer-brand .footer-wordmark img { width: 32px; height: 32px; }
.footer-brand .footer-wordmark span {
  font-family: var(--serif); font-size: 20px; font-weight: 500;
}
.footer-brand p {
  margin: 0;
  font-size: 14px;
  color: var(--muted);
  line-height: 1.6;
}
/* Inline metadata strip under the brand tagline */
.footer-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.footer-meta a {
  color: var(--muted);
  position: relative;
  display: inline-block;
  padding-block: 2px;
  transition: color 280ms var(--ease-out);
}
.footer-meta a::after {
  content: "";
  position: absolute;
  left: 50%; right: 50%; bottom: 0;
  height: 1px;
  background: currentColor;
  transition: left 460ms var(--ease-out), right 460ms var(--ease-out);
}
.footer-meta a:hover { color: var(--ink); }
.footer-meta a:hover::after { left: 0; right: 0; }

@media (max-width: 860px) {
  .footer-brand { grid-column: span 12; }   /* full width */
  .footer-col   { grid-column: span 6; }     /* 2-up on the 12-col grid */
  .footer-bottom { flex-direction: column; align-items: flex-start; gap: 14px; }
}

/* Reveal — elegant scroll-triggered entrance for content below the fold.
   Above-fold elements stay visible. Soft Y rise + subtle scale + blur fade. */
.reveal { /* visible by default */ }
.reveal.is-entering {
  animation: revealIn 1100ms var(--ease-out) both;
  will-change: transform, opacity, filter;
}
.reveal.rd-1.is-entering { animation-delay: 90ms; }
.reveal.rd-2.is-entering { animation-delay: 230ms; }
.reveal.rd-3.is-entering { animation-delay: 370ms; }
@keyframes revealIn {
  from {
    opacity: 0;
    transform: translateY(44px) scale(0.985);
    filter: blur(6px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

/* Note: reveals are handled by IntersectionObserver in app.js — the
   scroll-driven CSS override was hiding above-the-fold content. */

/* Hero text mask reveal — runs when the headline scrolls into view (the
   reveal IO adds .is-entering), not on page load: the voice band sits below
   the fold, so a load-time animation would always play unseen. Spans rest
   visible (no-JS safe); the keyframes carry their own hidden from-state. */
.hero-line-stage {
  display: block;
  overflow: hidden;
  /* Room for italic descenders (g, y, p) within the mask */
  padding-bottom: 0.18em;
  margin-bottom: -0.18em;
}
.hero-line-stage > span { display: block; }
/* The line masks carry the entrance — suppress the h1's generic revealIn
   so the headline doesn't double-animate */
.voice-headline.reveal.is-entering { animation: none; }
.voice-headline.is-entering .hero-line-stage > span {
  /* Mask-rise only. Do NOT animate font-variation-settings (opsz) here:
     morphing the axis re-rasterizes and reflows the glyphs every frame,
     which Safari renders as visible banding/shimmer on light backgrounds.
     Confirmed on the services hero 2026-06-09. */
  animation: lineUp 1100ms var(--ease-out) both;
}
.voice-headline.is-entering .hero-line-stage.delay-1 > span { animation-delay: 90ms; }
.voice-headline.is-entering .hero-line-stage.delay-2 > span { animation-delay: 260ms; }
@keyframes lineUp {
  from { transform: translateY(110%); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}

/* @starting-style for entrance on Hero — modern browsers */
@supports (selector(:has(*))) and (animation-timeline: view()) {
  .voice-headline { will-change: transform; }
}

/* Reduce motion */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
  .reveal { opacity: 1; transform: none; }
  .carousel-slide img,
  .carousel-slide video { transform: none !important; }
  /* Hero lines start hidden and rely on their entrance animation to appear —
     skip the animation entirely and render the final state */
  .hero-line-stage > span {
    animation: none !important;
    transform: none;
    opacity: 1;
  }
}

/* ============================================================
   Scroll-driven parallax on rest beats (modern only)
   ============================================================ */
@supports (animation-timeline: view()) {
  .feature-visual img,
  .feature-visual video {
    animation: featureParallax linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  @keyframes featureParallax {
    from { transform: translateY(-3%) scale(1.06); }
    to   { transform: translateY(3%) scale(1.06); }
  }
}

/* ============================================================
   Magnetic interaction — applied via JS-set CSS variables
   ============================================================ */
.magnetic {
  transition: transform var(--t-base) var(--ease-out);
  will-change: transform;
}
.magnetic[data-magnet] {
  transform: translate(var(--mx, 0px), var(--my, 0px));
}

/* ============================================================
   Accessible focus — Apple-style subtle ring
   ============================================================ */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}
.contact-submit:focus-visible { outline-offset: 4px; }
/* Form fields suppress the ring for pointer focus (underline darkens
   instead) — restore it for keyboard focus, where the underline alone
   is too quiet an indicator. */
.contact-field input:focus-visible,
.contact-field textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
  border-radius: 4px;
}

/* ============================================================
   Skip link — visually hidden until keyboard-focused.
   Injected by sp-shell.js as the first element in <body>.
   ============================================================ */
.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 300;
  padding: 12px 18px;
  background: var(--ink);
  color: #fff;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: 6px;
  transform: translateY(calc(-100% - 16px));
}
.skip-link:focus-visible {
  transform: none;
  outline-color: #fff;
}

/* Light-only design. Dark-mode token flip removed until each
   component is reviewed in dark theme. The color-scheme: light
   declaration at :root tells the UA to render form controls,
   scrollbars, etc. in light theme regardless of system pref. */

/* ============================================================
   Safe-area insets — iOS notch / dynamic island
   ============================================================ */
@supports (padding: env(safe-area-inset-left)) {
  .nav {
    padding-left: max(var(--pad-x), env(safe-area-inset-left));
    padding-right: max(var(--pad-x), env(safe-area-inset-right));
  }
  .carousel-caption {
    padding-left: max(var(--pad-x), env(safe-area-inset-left));
    padding-right: max(var(--pad-x), env(safe-area-inset-right));
  }
}

/* ============================================================
   Tap target floor — mobile a11y
   ============================================================ */
@media (max-width: 760px) {
  .nav-links a,
  .footer-col a,
  .social-link {
    min-height: 44px;
  }
  /* Carousel dots: 44px tap target via padding (NOT min-height) so the
     visible 2px bar isn't stretched into a tall white block on mobile.
     content-box + background-clip: content-box keeps the rendered bg
     scoped to the 2px content, padding is just invisible hit area. */
  .carousel-dot {
    padding: 21px 0;
    box-sizing: content-box;
    background-clip: content-box;
  }
  /* Dots row is 44px tall here (padding above) — re-center the pause toggle
     on the visible 2px dots line */
  .carousel-pause { bottom: 24px; }
}
