/* ============================================================
   AJW PRESENTS — V6
   Reference: landonorris.com (statement hero, big serif display,
   dated photo rail, FIX/CREATE typographic split, fanned cards,
   signature device).
   Standard vertical scroll. No staircase. Brand: cream + terracotta + teal.
   ============================================================ */

/* ---------- LOCAL FONT — AURELLIS (elegant high-contrast serif) ----------
   Hosted locally from assets/FONTS/aurellis/. swap so other fonts
   render first while Aurellis loads. Used as the new default
   display font (Font 1). */
@font-face {
  font-family: "Aurellis";
  src: url("FONTS/aurellis/aurellis.woff2") format("woff2"),
       url("FONTS/aurellis/aurellis.woff") format("woff");
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}

/* ---------- LOCAL FONT — BLUEMUN (timeless serif) ----------
   Hosted locally from assets/FONTS/bluemun/. Four weights:
   400 (regular), 500 (medium), 600 (semibold), 700 (bold).
   Used in font slot 10. */
@font-face {
  font-family: "Bluemun";
  src: url("FONTS/bluemun/bluemun-regular.woff2") format("woff2"),
       url("FONTS/bluemun/bluemun-regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bluemun";
  src: url("FONTS/bluemun/bluemun-medium.woff2") format("woff2"),
       url("FONTS/bluemun/bluemun-medium.woff") format("woff");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bluemun";
  src: url("FONTS/bluemun/bluemun-semibold.woff2") format("woff2"),
       url("FONTS/bluemun/bluemun-semibold.woff") format("woff");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Bluemun";
  src: url("FONTS/bluemun/bluemun-bold.woff2") format("woff2"),
       url("FONTS/bluemun/bluemun-bold.woff") format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---------- 1. TOKENS ---------- */
:root {
  --cream: #F2EDE4;
  --cream-soft: #EAE3D6;
  --terracotta: #CE7B5E;
  --terracotta-hover: #BF6F54;
  --terracotta-text: #B35F41;
  --teal: #1F5B82;
  --teal-deep: #174866;
  --black: #111111;
  --black-soft: #2A2A2A;

  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;

  --pad-x: clamp(1.25rem, 5vw, 5rem);
  --pad-y: clamp(4rem, 9vw, 9rem);

  --space-1: 0.5rem;
  --space-2: 1rem;
  --space-3: 1.5rem;
  --space-4: 2rem;
  --space-5: 3rem;
  --space-6: 4.5rem;
  --space-7: 6.5rem;
  --space-8: 9rem;

  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-quart: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-entry: 1000ms;
  --dur-hover: 200ms;

  --nav-h: 76px;
  --container: 1440px;
}

/* ROOT-LEVEL --font-display override — sets AURELLIS as default.
   The earlier :root rule above sets Fraunces; this rule wins because
   it's later in source order. (Easier than rewriting the original
   :root to keep the diff small and reversible.) */
:root {
  --font-display: "Aurellis", "Fraunces", Georgia, "Times New Roman", serif;
}

/* ============================================================
   PREVIEW TOGGLES (temporary — inline in main nav)
   Compact font + palette switchers for design comparison.
   ============================================================ */
.nav-preview {
  display: flex;
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  pointer-events: auto;
}
.nav-preview__group {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  pointer-events: auto;
}
.nav-preview__label {
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-weight: 500;
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.45);
  margin-right: 0.35rem;
}
.nav-preview__btn {
  width: 28px;
  height: 28px;
  border-radius: 999px;
  border: 1px solid rgba(17, 17, 17, 0.16);
  background: transparent;
  color: rgba(17, 17, 17, 0.65);
  font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  font-weight: 500;
  font-size: 0.72rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
  pointer-events: auto;
}
.nav-preview__btn:hover {
  border-color: var(--terracotta);
  color: var(--terracotta-text);
}
.nav-preview__btn[aria-pressed="true"] {
  background: var(--terracotta);
  color: var(--cream);
  border-color: var(--terracotta);
}
@media (max-width: 1100px) {
  .nav-preview__label { display: none; }
}
@media (max-width: 900px) {
  .nav-preview { display: none; }
}
/* Dark palette: lighten button borders and labels for visibility */
html.palette-3 .nav-preview__label { color: rgba(242, 237, 228, 0.5); }
html.palette-3 .nav-preview__btn { border-color: rgba(242, 237, 228, 0.2); color: rgba(242, 237, 228, 0.75); }
html.palette-3 .nav-preview__btn:hover { color: var(--cream); border-color: var(--terracotta); }

/* ============================================================
   FONT VARIATIONS — applied via html.font-N (10 slots)

   Slot 1  — AURELLIS              (local; elegant high-contrast serif; default)
   Slot 2  — INSTRUMENT SERIF      (modern editorial high-contrast)
   Slot 3  — CORMORANT GARAMOND    (refined Garamond revival)
   Slot 4  — DM SERIF DISPLAY      (bold sharp serifs, slightly playful)
   Slot 5  — FRAUNCES              (the previous site default)
   Slot 6  — PLAYFAIR DISPLAY      (classic editorial high-contrast)
   Slot 7  — BRICOLAGE GROTESQUE   (modern variable sans display)
   Slot 8  — ITALIANA              (very refined Didone)
   Slot 9  — ECZAR                 (display serif with character)
   Slot 10 — BLUEMUN               (local; timeless serif)
   ============================================================ */
html.font-1 {
  --font-display: "Aurellis", "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-2 {
  --font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-3 {
  --font-display: "Cormorant Garamond", Georgia, "Times New Roman", serif;
  --font-body: "Manrope", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-4 {
  --font-display: "DM Serif Display", Georgia, "Times New Roman", serif;
  --font-body: "Manrope", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-5 {
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-6 {
  --font-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-7 {
  --font-display: "Bricolage Grotesque", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-8 {
  --font-display: "Italiana", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-9 {
  --font-display: "Eczar", Georgia, "Times New Roman", serif;
  --font-body: "Manrope", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html.font-10 {
  --font-display: "Bluemun", Georgia, "Times New Roman", serif;
  --font-body: "Instrument Sans", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}

/* ============================================================
   PALETTE VARIATIONS — applied via html.palette-N
   Token swaps re-skin the whole site without rewriting sections.
   ============================================================ */

/* Palette 1 — Editorial Cream (current default, no overrides) */
html.palette-1 { /* uses :root values */ }

/* Palette 2 — Saturated: more terracotta + cream-soft colour blocking */
html.palette-2 {
  --cream-soft: #F1D6C5; /* warmer terracotta-tinted soft */
}
html.palette-2 .section--dark,
html.palette-2 .thesis,
html.palette-2 .concepts,
html.palette-2 .approach-quote {
  background: var(--terracotta);
  color: var(--cream);
}
html.palette-2 .section--dark .display em,
html.palette-2 .thesis__statement em { color: var(--teal); }
html.palette-2 .partners,
html.palette-2 .approach-step:nth-of-type(even),
html.palette-2 .about-close { background: var(--cream-soft); }
html.palette-2 .modes { background: var(--cream-soft); }
html.palette-2 .home-cta { background: var(--terracotta); color: var(--cream); }
html.palette-2 .home-cta h2 { color: var(--cream); }
html.palette-2 .home-cta .cta { background: var(--teal); color: var(--cream); }

/* Palette 2 — Thesis section: keep the palette-1 look (teal background,
   terracotta italic emphasis). Higher specificity + !important to win
   against the .section--dark rule above which also matches this element. */
html.palette-2 .thesis.section--dark,
html.palette-2 section.thesis {
  background: var(--teal) !important;
  color: var(--cream) !important;
}
html.palette-2 .thesis .thesis__statement em {
  color: var(--terracotta) !important;
}
/* Palette 2 — Concepts in Development section: keep the palette-1 look
   (teal background, cream text). Same override pattern as .thesis above. */
html.palette-2 section.concepts {
  background: var(--teal) !important;
  color: var(--cream) !important;
}

/* Palette 3 — Dark Editorial: invert surface to deep teal/black, cream as text */
html.palette-3 {
  --cream: #181D22;
  --cream-soft: #20262C;
  --black: #F2EDE4;
  --black-soft: #E5DCC9;
  --teal: #F2EDE4;
  --teal-deep: #E5DCC9;
  --terracotta: #DA8567;
  --terracotta-hover: #C77452;
  --terracotta-text: #E69478;
}
html.palette-3 body { background: #181D22; color: #F2EDE4; }
html.palette-3 .site-nav.is-scrolled { background: rgba(24, 29, 34, 0.86); border-bottom-color: rgba(242, 237, 228, 0.08); }
html.palette-3 .menu-overlay { background: #181D22; }
html.palette-3 .footer-statement,
html.palette-3 .site-footer { background: #181D22; color: #F2EDE4; }
html.palette-3 .home-hero__caption,
html.palette-3 .career-rail__caption,
html.palette-3 .footer-bottom { color: rgba(242, 237, 228, 0.55); }
html.palette-3 .career-rail,
html.palette-3 .home-cta,
html.palette-3 .modes,
html.palette-3 .highlights,
html.palette-3 .work-preview,
html.palette-3 .about-close,
html.palette-3 .about-body,
html.palette-3 .case-study,
html.palette-3 .approach-step { background: #181D22; color: #F2EDE4; }
html.palette-3 .approach-step:nth-of-type(even) { background: #20262C; }
html.palette-3 .menu-toggle { background: #20262C; color: #F2EDE4; border-color: rgba(242, 237, 228, 0.12); }
html.palette-3 .focus-pill { background: #20262C; color: #F2EDE4; border-color: rgba(242, 237, 228, 0.12); }
html.palette-3 .work-preview__card { background: #20262C; }
html.palette-3 .partners { background: #1F242A; color: #F2EDE4; }

/* Palette 4 — High Quiet: display in black, accents only on CTAs */
html.palette-4 {
  --teal: #111111;
  --teal-deep: #1c1c1c;
  --terracotta-text: #111111;
}
html.palette-4 .accent,
html.palette-4 .thesis__statement em,
html.palette-4 .home-hero__title em { color: var(--terracotta); }
html.palette-4 .career-rail__action,
html.palette-4 .highlights__num,
html.palette-4 .case-study__eyebrow,
html.palette-4 .approach-step__meta { color: rgba(17, 17, 17, 0.55); }
html.palette-4 .partners__overlay { color: rgba(17, 17, 17, 0.32); }

/* ---------- 2. RESET + BASE ---------- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  /* Near-imperceptible vertical falloff — the cream warms slightly toward
     the viewport bottom, lending soft depth to areas where body shows
     through. Most sections paint over this with their own background. */
  background: linear-gradient(180deg, #F2EDE4 0%, #EFE9DD 100%) fixed;
  color: var(--black);
  font-family: var(--font-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

html { scroll-behavior: auto; overflow-x: hidden; }
body { min-height: 100vh; min-height: 100dvh; overflow-x: hidden; overscroll-behavior-y: none; }

html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, ul, ol, dl { margin: 0; padding: 0; }
ul, ol { list-style: none; }

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

input, textarea, select { font: inherit; color: inherit; }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 2px;
  border-radius: 2px;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--teal); color: var(--cream);
  padding: 0.75rem 1rem;
  font-family: var(--font-body); font-weight: 500; font-size: 0.85rem;
}
.skip-link:focus { left: 1rem; top: 1rem; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ---------- 3. TYPOGRAPHY ---------- */
.display {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 0.92;
  color: var(--teal);
}
.display--xxl { font-size: clamp(4rem, 16vw, 18rem); }
.display--xl  { font-size: clamp(2.75rem, 9vw, 9rem); line-height: 0.95; }
.display--lg  { font-size: clamp(2.25rem, 6.5vw, 6rem); line-height: 0.95; }
.display--md  { font-size: clamp(1.75rem, 4.5vw, 3.75rem); line-height: 1; }
.display--sm  { font-size: clamp(1.4rem, 3vw, 2.25rem); line-height: 1.05; }

.display-italic {
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  letter-spacing: -0.01em;
  line-height: 1.15;
  color: var(--teal);
}

/* Accent inline highlight inside big display text — terracotta key words */
.accent {
  color: var(--terracotta);
  font-style: italic;
  font-weight: 700;
}

.lede {
  font-family: var(--font-body);
  font-size: clamp(1.05rem, 1.4vw, 1.3rem);
  line-height: 1.55;
  max-width: 56ch;
  color: var(--black);
}

.body {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.6;
  max-width: 64ch;
  color: var(--black);
}

.label, .eyebrow {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--black);
}
.eyebrow--accent { color: var(--terracotta-text); }
.eyebrow--mute { color: rgba(17, 17, 17, 0.55); }
.section--dark .eyebrow { color: rgba(242, 237, 228, 0.7); }
.section--dark .eyebrow--accent { color: var(--terracotta); }

.mono {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.65);
}
.section--dark .mono { color: rgba(242, 237, 228, 0.65); }

.numero {
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--terracotta);
  margin-right: 0.25em;
}

.pullquote {
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.4rem, 3vw, 2.4rem);
  line-height: 1.25;
  color: var(--teal);
  max-width: 30ch;
}
.section--dark .pullquote { color: var(--cream); }

/* Caption — used under photo rail entries */
.caption {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.7);
}

/* ---------- 4. BUTTONS / LINKS ---------- */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 1em 1.6em;
  background: var(--terracotta);
  color: var(--cream);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-radius: 999px;
  transition: background var(--dur-hover) ease, transform var(--dur-hover) ease;
  white-space: nowrap;
}
.cta:hover { background: var(--terracotta-hover); }
.cta .arrow { display: inline-block; transition: transform var(--dur-hover) ease; }
.cta:hover .arrow { transform: translateX(3px); }

/* ---------- FLOW CTA — orchestrated hover treatment ----------
   Used ONLY on the primary "Work With AJW" button in the top nav
   (.cta + .cta--flow modifier). On hover, five things synchronise:
     1. Circle expands from centre, filling the button with teal-deep.
     2. Right arrow slides off the right edge.
     3. A second arrow drops in from the left.
     4. Label shifts right to balance the new layout.
     5. Cream text/arrows stay cream throughout.
   Pill shape preserved (no border-radius morph). Used deliberately
   on this single hero-tier CTA — not as a global button style. */
.cta--flow {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* Padding tuned so the hover state lands BALANCED — equal space
     between the arrow and the button's left edge (20 px) and the
     label's right edge and the button's right edge (~19 px).
     Math:
       arrow position from button left = 1.6em ≈ 20 px (L_left)
       label hover shift = 16 px (sits ~17 px right of the arrow)
       L_right = right_padding − translate = 35 − 16 ≈ 19 px ✓
     Was 1em 2em, which produced L_right of only 9 px (about half
     of L_left). 1em 2.8em corrects the imbalance. */
  padding: 1em 2.8em;
}
/* Hold the base background as terracotta on hover (the circle takes
   over the visual fill) — so the bg doesn't shift to terracotta-hover
   first and clash with the expanding circle. */
.cta--flow:hover {
  background: var(--terracotta);
}
/* Expanding circle — at rest a tiny dot at centre; on hover grows
   to ~240px and fades in. teal-deep against the terracotta base
   gives a clear cool/warm flip on hover. */
.cta--flow::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  background: var(--teal-deep);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  z-index: 0;
  pointer-events: none;
  transition:
    width 800ms cubic-bezier(0.19, 1, 0.22, 1),
    height 800ms cubic-bezier(0.19, 1, 0.22, 1),
    opacity 800ms ease;
}
.cta--flow:hover::before,
.cta--flow:focus-visible::before {
  width: 240px;
  height: 240px;
  opacity: 1;
}
/* All inner content stacks above the circle. */
.cta--flow > * {
  position: relative;
  z-index: 1;
}
/* Label sits centred at rest (no offset). On hover it shifts
   +16px right to clear the incoming left-side arrow with a small
   gap (the arrow sits at left: 1.6em ≈ 20px and is ~14px wide,
   so a +16px label shift puts the label about 8px to the right of
   the arrow — comfortable gap, label remains close to the arrow
   rather than drifting right of centre). Was +24px which pushed
   the label too far right; reduced after rebalancing the button
   padding. */
.cta--flow .cta__label {
  display: inline-block;
  transform: translateX(0);
  transition: transform 800ms cubic-bezier(0.23, 1, 0.32, 1);
}
.cta--flow:hover .cta__label,
.cta--flow:focus-visible .cta__label {
  transform: translateX(16px);
}
/* Arrow that slides IN from the left on hover. Absolutely positioned
   so it doesn't take layout space at rest (sits off the left edge).
   Bouncy ease (cubic-bezier overshoots slightly) for a deliberate
   "dropping into place" feel. */
.cta--flow .cta__arrow-in {
  position: absolute;
  left: -25%;
  top: 50%;
  transform: translateY(-50%);
  display: inline-block;
  z-index: 2;
  transition: left 800ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.cta--flow:hover .cta__arrow-in,
.cta--flow:focus-visible .cta__arrow-in {
  left: 1.6em;
}
/* (Right-side arrow at rest was removed — used to read as a pointer
   toward the hamburger menu next to it. Markup deleted, rules below
   collapsed. Hover-only left-side arrow choreography is preserved.) */
/* Press-down feedback. */
.cta--flow:active {
  transform: scale(0.96);
  transition: transform 100ms ease;
}
/* Reduced motion — strip the choreography, fall back to a simple
   background-shift hover. */
@media (prefers-reduced-motion: reduce) {
  .cta--flow::before { display: none; }
  .cta--flow .cta__arrow-in { display: none; }
  .cta--flow .cta__label { transform: none; transition: none; }
  .cta--flow:hover { background: var(--terracotta-hover); }
}
/* Mobile — hide the "Work With AJW" pill in the persistent top nav.
   At ≤600px viewport the brand + pill + hamburger together overflow
   the available width by ~13px (388px content vs 375px viewport),
   pushing the hamburger one pixel from the edge. The hamburger menu
   already contains a Contact link, and the home/case-studies CTA
   sections plus footer surface the same call-to-action, so removing
   the pill on phones loses no functionality and recovers ~210px of
   breathing room in the nav. */
@media (max-width: 600px) {
  .site-nav .cta--flow { display: none; }
}

.cta--inverse { background: var(--cream); color: var(--teal); }
.cta--inverse:hover { background: var(--terracotta); color: var(--cream); }

.cta--ghost {
  background: transparent;
  color: var(--terracotta-text);
  border: 1px solid var(--terracotta);
  padding: 1em 1.6em;
}
.cta--ghost:hover { background: var(--terracotta); color: var(--cream); border-color: var(--terracotta); }

.cta--icon {
  width: 56px;
  height: 56px;
  padding: 0;
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
}

.link {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: var(--terracotta-text);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.92rem;
  padding-bottom: 1px;
  border-bottom: 1px solid var(--terracotta);
  transition: border-bottom-width var(--dur-hover) ease;
}
.link:hover { border-bottom-width: 2px; padding-bottom: 0; }
.link .arrow { transition: transform var(--dur-hover) ease; }
.link:hover .arrow { transform: translateX(2px); }

.link--inverse { color: var(--cream); border-bottom-color: var(--cream); }

.mailto {
  color: var(--black);
  font-family: var(--font-body);
  font-size: 0.95rem;
  border-bottom: 1px solid var(--terracotta);
  padding-bottom: 1px;
}
.mailto:hover { border-bottom-width: 2px; padding-bottom: 0; }

/* ---------- 5. NAVIGATION (persistent across pages) ---------- */
.site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  /* Above the menu overlay (z-index 105) so the nav stays visible
     and on top when the menu is open — important on devices where
     the nav's safe-area padding makes its rendered height exceed
     var(--nav-h). */
  z-index: 120;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.25rem clamp(1rem, 3vw, 2.25rem);
  padding-top: max(1.25rem, env(safe-area-inset-top));
  padding-left: max(clamp(1rem, 3vw, 2.25rem), env(safe-area-inset-left));
  padding-right: max(clamp(1rem, 3vw, 2.25rem), env(safe-area-inset-right));
  background: rgba(242, 237, 228, 0.0);
  transition: background 300ms ease, backdrop-filter 300ms ease;
}
.site-nav.is-scrolled {
  background: rgba(242, 237, 228, 0.86);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
}

/* Brand lockup — primary "AJW" mark + secondary "AJW Presents" imprint label.
   Used in the site nav and the menu overlay. AJW = the operator;
   AJW Presents = the signature applied to venues. */
.brand {
  display: inline-flex;
  flex-direction: column;
  gap: 0.2rem;
  line-height: 1;
  flex-shrink: 0;
  text-decoration: none;
}
/* Brand mark is now a PNG (transparent BG, teal AJW). Sized by height so its
   2:1 aspect scales the width naturally. */
.brand__mark {
  display: block;
  height: clamp(44px, 5.5vh, 64px);
  width: auto;
  user-select: none;
  -webkit-user-drag: none;
}
.brand__imprint {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.6rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.55);
}

.site-nav__right {
  display: flex;
  align-items: center;
  /* Bumped from 0.75rem → 1.5rem so the (now-larger) menu icon has
     comfortable breathing room from the "Work With AJW" CTA next to
     it. */
  gap: 1.5rem;
}

/* Menu toggle — bare icon (no circle background). Three deep-teal
   bars at rest that morph into an X on open via stroke-dasharray
   + rotation. The bare icon reads as a clear "this is the menu"
   without competing visually with the surrounding elements. */
.menu-toggle {
  /* Click-target sized to match the visible icon (56 × 56 svg), so
     the user clicks anywhere inside the icon's bounds. Background
     is transparent — no circle frame. */
  width: 56px;
  height: 56px;
  background: transparent;
  color: var(--teal-deep);
  display: inline-grid;
  place-items: center;
  border: none;
  /* Color transition handles hover state (stroke uses currentColor). */
  transition: color var(--dur-hover) ease;
  cursor: pointer;
}
.menu-toggle:hover { color: var(--terracotta); }

.menu-toggle svg {
  /* Bumped from 42 → 56 px. The menu icon now reads as visibly
     larger than the "Work With AJW" CTA's filled pill, balancing
     the visual weight (a bare icon needs to be physically larger
     than a filled pill of equivalent height to feel like a peer). */
  width: 56px;
  height: 56px;
  stroke: currentColor;
  fill: none;
  /* Reduced to 2.5 (Option C — ~23% thinner than the original 3.25).
     Distinctly lighter — the icon shifts from "bold" toward
     "elegant," matching the editorial register of the rest of
     the site. */
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 500ms ease-in-out;
}
/* The morphing path traces a hidden hamburger-with-loops shape.
   At rest, dasharray 12 63 reveals only the top bar; combined with
   the static middle bar (path 2) below it reads as a two-line
   hamburger. On open, dasharray 20 300 + dashoffset shifts the
   visible portion to a different segment, AND the SVG rotates -45°
   — together they morph hamburger → X smoothly. */
.menu-toggle__path-morph {
  stroke-dasharray: 12 63;
  stroke-dashoffset: 0;
  transition:
    stroke-dasharray 500ms ease-in-out,
    stroke-dashoffset 500ms ease-in-out;
}
.menu-toggle[aria-expanded="true"] svg {
  transform: rotate(-45deg);
}
.menu-toggle[aria-expanded="true"] .menu-toggle__path-morph {
  stroke-dasharray: 20 300;
  stroke-dashoffset: -32.42px;
}
@media (prefers-reduced-motion: reduce) {
  .menu-toggle svg,
  .menu-toggle__path-morph {
    transition: none;
  }
}

/* Full-screen menu overlay */
.menu-overlay {
  position: fixed;
  /* Starts BELOW the header (was inset: 0). The site-nav stays
     visible at the top of the viewport throughout the menu's open
     state — the menu toggle button stays in place and morphs in-situ
     instead of being covered by an overlay-internal close button. */
  top: var(--nav-h);
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 105;
  background: var(--cream);
  display: flex;
  flex-direction: column;
  padding: 1.25rem clamp(1rem, 3vw, 2.25rem);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-20px);
  /* Lengthened from 350/450ms — gives the open a smoother, more
     deliberate glide instead of a snap. */
  transition: opacity 700ms var(--ease-quart), transform 800ms var(--ease-quart);
}
.menu-overlay[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
/* The duplicate header inside the overlay (logo + close button) is
   redundant now that the page header stays visible. Both the
   container and the close button are hidden — the real menu toggle
   in the header serves as the close. */
.menu-overlay__top,
.menu-overlay__close { display: none; }

.menu-overlay__body {
  flex: 1;
  display: grid;
  /* Layout flipped from the previous (links 1.2fr | previews 1fr) —
     image previews now sit on the LEFT (1fr), the link list on the
     RIGHT (1.2fr). HTML order is unchanged for accessibility (links
     still come first in source); CSS `order` below handles the
     visual flip. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  gap: clamp(2rem, 5vw, 5rem);
  padding: clamp(2rem, 5vw, 4rem) 0;
  align-items: stretch;
}

.menu-overlay__links {
  display: flex;
  flex-direction: column;
  gap: clamp(0.5rem, 1.5vw, 1rem);
  justify-content: center;
  /* Visually placed in the right-hand grid cell. */
  order: 2;
  /* Right-align each link inside its column — every link's right
     edge lines up against the column's right edge, left edges are
     jagged according to text length. Editorial right-aligned list. */
  align-items: flex-end;
  text-align: right;
}
.menu-overlay__link {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 7vw, 5.5rem);
  line-height: 0.95;
  letter-spacing: -0.02em;
  color: var(--teal);
  display: flex;
  align-items: baseline;
  /* Page name first in HTML, number second in visual order — number
     sits on the RIGHT of the link, against the column edge. The
     1.1rem gap absorbs what was previously 0.6rem gap + 0.5rem
     margin on .num combined. */
  flex-direction: row-reverse;
  gap: 1.1rem;
  /* Each link starts hidden + offset above its final position.
     When .menu-overlay gains [data-open="true"], the rules below
     reveal the links one after the other (cascading drop-down)
     via per-item transition-delay. Color is INSTANT (0ms) so the
     hover highlight registers the moment the cursor crosses the
     link — no perceptible delay. */
  opacity: 0;
  transform: translateY(-14px);
  transition:
    opacity 480ms var(--ease-quart),
    transform 540ms var(--ease-quart);
}
.menu-overlay[data-open="true"] .menu-overlay__link {
  opacity: 1;
  transform: translateY(0);
}
/* Cascading reveal — 200ms initial delay (lets the overlay's main
   fade/slide settle) + 90ms between successive items. Five items
   total finishes ~560ms after the overlay starts opening, with the
   final link's reveal completing around 1.05s. */
.menu-overlay[data-open="true"] .menu-overlay__link:nth-child(1) { transition-delay: 200ms; }
.menu-overlay[data-open="true"] .menu-overlay__link:nth-child(2) { transition-delay: 290ms; }
.menu-overlay[data-open="true"] .menu-overlay__link:nth-child(3) { transition-delay: 380ms; }
.menu-overlay[data-open="true"] .menu-overlay__link:nth-child(4) { transition-delay: 470ms; }
.menu-overlay[data-open="true"] .menu-overlay__link:nth-child(5) { transition-delay: 560ms; }
.menu-overlay__link .num {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  color: var(--terracotta-text);
  /* margin-right was previously used to space the number from the
     text when number sat on the LEFT. Now that the number sits on
     the RIGHT (via flex-direction: row-reverse on the link), that
     spacing is handled by the link's gap (1.1rem). */
}
.menu-overlay__link:hover { color: var(--terracotta); }
.menu-overlay__link[aria-current="page"] { color: var(--terracotta); }

.menu-overlay__previews {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  align-content: center;
  /* Visually placed in the left-hand grid cell (HTML order is
     links-then-previews; this flips them visually). */
  order: 1;
}

/* Each preview is an <a> element wrapping figure + caption.
   tabindex="-1" + the parent's aria-hidden="true" keep it out of
   screen-reader/keyboard nav; pointer users still get the visual
   interaction. */
.menu-overlay__preview {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 4px;
  background: var(--cream-soft);
  text-decoration: none;
  color: inherit;
}
.menu-overlay__preview .image-slot {
  position: absolute;
  inset: 0;
  height: 100%;
}
.menu-overlay__preview img,
.menu-overlay__preview video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Image is scaled inside the (overflow:hidden) frame on hover —
     creates a subtle zoom-in that reads as "this tile is alive."
     400ms is long enough to feel intentional but short enough to
     respond crisply when the cursor enters. */
  transition: transform 400ms var(--ease-quart);
}
.menu-overlay__preview:hover img,
.menu-overlay__preview:focus-visible img,
.menu-overlay__preview:hover video,
.menu-overlay__preview:focus-visible video {
  transform: scale(1.06);
}

/* Blur stack markup is still in the DOM but rendered invisible —
   keeping the harmless empty spans avoids touching every page's
   HTML. Hover blur effect was removed at user's request; only the
   caption-emphasis treatment is kept. */
.menu-overlay__blur-stack { display: none; }

/* Caption — at rest: small dark pill (legible against any image).
   On hover/focus: pill background fades, text scales up, and an
   arrow slides in to indicate navigation. Transitions tightened
   from 400ms → 200ms for a more responsive hover feel. */
.menu-overlay__preview .caption {
  position: absolute;
  bottom: 0.75rem;
  left: 0.75rem;
  z-index: 2;
  display: inline-flex;
  align-items: baseline;
  color: var(--cream);
  background: rgba(17, 17, 17, 0.4);
  padding: 0.3rem 0.6rem;
  border-radius: 2px;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  transform-origin: bottom left;
  transition:
    background 200ms var(--ease-quart),
    backdrop-filter 200ms var(--ease-quart),
    -webkit-backdrop-filter 200ms var(--ease-quart),
    padding 200ms var(--ease-quart),
    transform 200ms var(--ease-quart);
}
.menu-overlay__preview:hover .caption,
.menu-overlay__preview:focus-visible .caption {
  background: transparent;
  -webkit-backdrop-filter: blur(0);
  backdrop-filter: blur(0);
  padding: 0.3rem 0;
  transform: scale(1.35);
}
.caption__arrow {
  display: inline-block;
  margin-left: 0;
  opacity: 0;
  transform: translateX(-8px);
  transition:
    opacity 200ms var(--ease-quart),
    transform 200ms var(--ease-quart),
    margin-left 200ms var(--ease-quart);
}
.menu-overlay__preview:hover .caption__arrow,
.menu-overlay__preview:focus-visible .caption__arrow {
  opacity: 1;
  transform: translateX(0);
  margin-left: 0.4rem;
}

/* Mobile + reduced-motion bypass — caption stays in its rest state. */
@media (max-width: 820px), (prefers-reduced-motion: reduce) {
  .menu-overlay__preview:hover .caption,
  .menu-overlay__preview:focus-visible .caption {
    transform: none;
    padding: 0.3rem 0.6rem;
    background: rgba(17, 17, 17, 0.4);
    -webkit-backdrop-filter: blur(4px);
    backdrop-filter: blur(4px);
  }
  .menu-overlay__preview:hover .caption__arrow,
  .menu-overlay__preview:focus-visible .caption__arrow {
    opacity: 0;
    margin-left: 0;
  }
}

@media (max-width: 820px) {
  .menu-overlay__body { grid-template-columns: 1fr; }
  .menu-overlay__previews { display: none; }
}

/* Menu open — keep the site-nav visible at the top so the menu
   toggle button stays in place and the hamburger→X morph animation
   plays in-situ. Force the nav's cream-frosted background regardless
   of scroll position so it reads as a defined header band over the
   menu surface. */
body[data-menu-open="true"] .site-nav {
  background: rgba(242, 237, 228, 0.86);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  backdrop-filter: saturate(160%) blur(14px);
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
}

/* Body offset for fixed nav (excluding home where hero sits beneath) */
.has-site-nav { padding-top: var(--nav-h); }

/* ---------- 6. SECTIONS / LAYOUT ---------- */
.section {
  position: relative;
  padding: var(--pad-y) var(--pad-x);
}
.section--dark {
  background: var(--teal);
  color: var(--cream);
}
.section--dark .display,
.section--dark .display-italic { color: var(--cream); }
.section--dark .body { color: rgba(242, 237, 228, 0.85); }
.section--dark .lede { color: rgba(242, 237, 228, 0.92); }

.section__inner {
  max-width: var(--container);
  margin: 0 auto;
  position: relative;
}

.section__head {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  max-width: 64rem;
  margin-bottom: clamp(2.5rem, 5vw, 4.5rem);
}

/* ---------- 7. IMAGE SLOT (real or placeholder) ---------- */
.image-slot {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: transparent;
}
.image-slot > img,
.image-slot > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.image-slot__cross {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  display: none;
}
.image-slot__cross line {
  stroke: rgba(206, 123, 94, 0.2);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* Placeholder state — applied via JS when img errors or is missing */
.image-slot--placeholder {
  border: 1px solid rgba(206, 123, 94, 0.3);
}
.image-slot--placeholder > img,
.image-slot--placeholder > video { display: none; }
.image-slot--placeholder .image-slot__cross { display: block; }

.image-slot--video-pending {
  border: 1px solid rgba(206, 123, 94, 0.3);
  position: relative;
}
.image-slot--video-pending::after {
  content: "Video coming soon";
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-text);
}

/* ---------- 8. SIGNATURE MARK ---------- */
.signature-mark {
  display: inline-block;
  width: clamp(80px, 12vw, 140px);
  height: auto;
  color: var(--terracotta);
}
.signature-mark--lg { width: clamp(120px, 18vw, 220px); }
.signature-mark--xl { width: clamp(180px, 28vw, 360px); }
.signature-mark img,
.signature-mark svg { width: 100%; height: auto; display: block; }
/* Fallback: if signature.png fails to load, render an italic AW glyph */
.signature-mark[data-fallback="true"]::before {
  content: "AW";
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  font-size: clamp(2.5rem, 6vw, 5rem);
  color: var(--terracotta);
  line-height: 1;
  letter-spacing: -0.02em;
}
.signature-mark[data-fallback="true"] img { display: none; }

/* ---------- 9. FOOTER ---------- */
.site-footer {
  background: var(--cream);
  border-top: 1px solid rgba(17, 17, 17, 0.08);
}
.footer-statement {
  padding: clamp(4rem, 10vw, 9rem) var(--pad-x);
  text-align: right;
  background: var(--cream);
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
}
.footer-statement h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 9vw, 8rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--teal);
  max-width: 16ch;
  /* margin-left: auto pushes the constrained-width <h2> block to the
     right edge of its container — text-align: right alone only aligns
     inline content, it doesn't move a block with max-width. */
  margin-left: auto;
}
.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: clamp(1.5rem, 3vw, 3rem);
  padding: clamp(3rem, 6vw, 5rem) var(--pad-x);
  max-width: var(--container);
  margin: 0 auto;
}
/* Footer brand mark — replaces the text "AJW" h3 in column 1 with the
   institutional logo, sized at ~70% of the header brand mark for a
   subtle but anchored presence on the cream footer. The negative
   left margin compensates for the transparent padding inside the
   PNG so the visible "ajw" glyph sits flush with the text below. */
.footer-brand__mark {
  display: block;
  height: clamp(31px, 3.85vh, 45px);
  width: auto;
  margin-left: -0.75rem;
  margin-bottom: 1rem;
}
.footer-grid h3 {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.65);
  margin-bottom: 1rem;
}
.footer-grid ul li,
.footer-grid p {
  font-family: var(--font-body);
  font-size: 0.95rem;
  line-height: 1.8;
  color: var(--black);
}
.footer-grid a:hover { color: var(--terracotta-text); }
.footer-newsletter {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
.footer-newsletter input {
  flex: 1;
  background: transparent;
  border: 1px solid rgba(17, 17, 17, 0.2);
  border-radius: 999px;
  padding: 0.7rem 1rem;
  font-size: 0.9rem;
}
.footer-newsletter button {
  border-radius: 999px;
  background: var(--terracotta);
  color: var(--cream);
  padding: 0.7rem 1.2rem;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.footer-newsletter button:hover { background: var(--terracotta-hover); }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 1.5rem clamp(1.25rem, 5vw, 5rem) 2rem;
  border-top: 1px solid rgba(17, 17, 17, 0.06);
  font-family: var(--font-body);
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  color: rgba(17, 17, 17, 0.6);
}
.footer-bottom .footer-legal { display: flex; gap: 1.5rem; flex-wrap: wrap; }
@media (max-width: 820px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 520px) {
  .footer-grid { grid-template-columns: 1fr; }
}

/* ---------- 10. MOTION PRIMITIVES (GSAP-driven) ---------- */
/* CSS-driven reveal pipeline. JS toggles .is-revealed once the element
   crosses the IntersectionObserver threshold; the transition handles the
   actual animation. Bypasses GSAP/ScrollTrigger entirely so Lenis's
   intermediate scroll updates can't cause flicker. */
[data-reveal], [data-reveal-stagger] > * {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 900ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
}
[data-reveal-image] {
  opacity: 0;
  transform: scale(1.03);
  transition: opacity 1000ms cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 1000ms cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
}
[data-reveal].is-revealed,
[data-reveal-stagger] > .is-revealed,
[data-reveal-image].is-revealed {
  opacity: 1;
  transform: none;
}
[data-parallax] { will-change: transform; }
/* Scroll-scrubbed titles — GSAP applies inline transform on scroll.
   will-change promotes the element to its own GPU layer so the scrub
   doesn't hit layout each frame. transform-origin centered so the
   scale animation breathes around the visual centre of the title. */
[data-scrub-title] {
  will-change: transform;
  transform-origin: 50% 50%;
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-reveal-image] { opacity: 1; transform: none; }
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}

/* ---------- WORD-BY-WORD HEADLINE REVEAL ----------
   Replaces the block-fade [data-reveal] entry on selected display headlines
   with a per-word stagger. JS splits text into <span class="reveal-word">
   wrappers and animates them via GSAP+ScrollTrigger when the headline
   enters the viewport. The parent stays opacity:0 until the JS has
   inserted the spans (preventing a flash of un-split text), then
   becomes opacity:1 — the words themselves drive visibility from there. */
[data-word-reveal] {
  opacity: 0;
}
[data-word-reveal][data-word-revealed-init="true"] {
  opacity: 1;
}
[data-word-reveal] .reveal-word {
  display: inline-block;
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 700ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--word-index, 0) * 70ms);
  will-change: transform, opacity;
}
[data-word-reveal].is-words-revealed .reveal-word {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  [data-word-reveal],
  [data-word-reveal][data-word-revealed-init="true"] { opacity: 1; }
  [data-word-reveal] .reveal-word {
    opacity: 1;
    transform: none;
    will-change: auto;
  }
}

/* ---------- THESIS PIN REVEAL — scroll-driven word lighting ----------
   The thesis section pins as it scrolls into the viewport. While pinned,
   each word lights up from low opacity to full as the user scrolls.

   Words start at 0.22 opacity (readable but visibly muted) and animate
   to 1 driven by GSAP scrub on desktop. Highlighted words sit inside
   <em> which already has color: var(--terracotta), so a span inside an
   <em> inherits terracotta — opacity is the only thing animated, the
   highlight colour applies for free.

   The base opacity is set in CSS (not via gsap.set) so the muted state
   is visible the moment the section paints, before any JS has run. JS
   then either drives scrub on desktop or runs a staggered viewport-entry
   fade on mobile (inline transition + delay). Reduced-motion users get
   words at full opacity, no pin, no animation. */
[data-thesis-pin-reveal] .thesis-word {
  /* `inline` (not `inline-block`) so the browser only line-breaks at
     real whitespace between words. inline-block would make each
     character a separate breakable unit, allowing words to split
     mid-letter across lines. */
  display: inline;
  opacity: 0.05;
  will-change: opacity;
}
@media (prefers-reduced-motion: reduce) {
  [data-thesis-pin-reveal] .thesis-word {
    opacity: 1;
    will-change: auto;
  }
}

/* ---------- MARQUEE TEXT RAIL ----------
   Continuous-scroll horizontal text band placed between major sections.
   Track holds the same content repeated 4× so the loop seams at -50%
   translate without a visible jump. Cream background blends into
   surrounding sections — this is editorial punctuation, not a banner. */
.marquee {
  width: 100%;
  height: 140px;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: var(--cream);
  position: relative;
  user-select: none;
}
.marquee-track {
  display: flex;
  white-space: nowrap;
  animation: marquee-scroll 40s linear infinite;
  will-change: transform;
}
.marquee-content {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 6rem;
  letter-spacing: -0.01em;
  line-height: 1;
  color: var(--terracotta);
  padding-right: 2rem;
  flex-shrink: 0;
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (max-width: 768px) {
  .marquee { height: 80px; }
  .marquee-content { font-size: 3.5rem; padding-right: 1.25rem; }
}
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation-play-state: paused; }
}

/* ============================================================
   PAGE-SPECIFIC SECTIONS
   ============================================================ */

/* ---------- HOME — HERO ---------- */
/* Hero is a fixed-viewport stage. HOSPITALITY + video form a centred
   stage; the five phrases overlay the video; descriptor + Current
   Focus stay pinned to the bottom. As the user scrolls, JS animates
   a single continuous expansion (see initHeroExpand). The base
   colour is the same cream as the rest of the cream sections —
   the bg image fades back to this cream rather than fading to teal,
   so the next section (teal thesis) reads as a deliberate colour
   break, not a smooth gradient. */
.home-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 0;
  background: var(--cream);
  color: var(--cream);
  text-align: center;
}

/* No background image — hero is plain cream. The video sits over
   the cream base with its own black frame; the video element itself
   is set to opacity 0.7 so the black backing tints it darker, which
   makes the white phrases (under mix-blend-mode: difference) read as
   bright over the darker video pixels. */

/* ---------- HERO AMBIENT AURORA ----------
   Sunlight-on-surface effect. A near-white highlight passes slowly
   across the hero, with a much softer warm tone underneath for
   depth. The previous version used full brand terracotta which read
   as discoloration rather than atmosphere. Now the gradient colours
   carry their own opacity (rgba in the gradient stops) so the
   container itself is at full opacity — cleaner control, no
   double-attenuation. Heavily blurred (80px) so bands are
   imperceptible as bands; just a soft moving wash of light. */
.home-hero__aurora {
  position: absolute;
  inset: -10%;
  z-index: -1;
  pointer-events: none;
  opacity: 1;
  filter: blur(70px);             /* slightly less blur so wash is more legible */
  /* Extended mask falloff — visible across most of the hero with a gentle
     gradient toward the bottom-left rather than confined tight in the corner. */
  -webkit-mask-image: radial-gradient(ellipse at top right, #000 0%, transparent 105%);
  mask-image: radial-gradient(ellipse at top right, #000 0%, transparent 105%);
}
.home-hero__aurora::before,
.home-hero__aurora::after {
  content: "";
  position: absolute;
  inset: -50%;
}
.home-hero__aurora::before {
  /* Highlight layer — near-white at ~70% peak. Smooth transitions
     from transparent → highlight → transparent (rather than sharp
     band edges) give the gradient a flowing feel, like sunlight
     sweeping across the surface. The white now dominates the wash. */
  background: repeating-linear-gradient(
    115deg,
    transparent 0%,
    rgba(255, 252, 245, 0.70) 14%,
    rgba(255, 252, 245, 0.70) 22%,
    transparent 36%
  );
  animation: aurora-drift-a 70s linear infinite;
}
.home-hero__aurora::after {
  /* Warm depth layer — pulled WAY back to ~8% so the warmth is
     barely-there atmospheric tilt rather than visible discoloration. */
  background: repeating-linear-gradient(
    -65deg,
    transparent 0%,
    rgba(213, 180, 158, 0.08) 10%,
    rgba(213, 180, 158, 0.08) 16%,
    transparent 26%
  );
  animation: aurora-drift-b 90s linear infinite reverse;
}
@keyframes aurora-drift-a {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-30%, -10%, 0); }
}
@keyframes aurora-drift-b {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(20%, 15%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .home-hero__aurora::before,
  .home-hero__aurora::after { animation: none; }
}
@media (max-width: 768px) {
  .home-hero__aurora { filter: blur(50px); }
}
.home-hero__top {
  position: absolute;
  top: 1.5rem; left: 50%;
  transform: translateX(-50%);
}
.home-hero__top-icon {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--terracotta);
  display: grid; place-items: center;
  color: var(--cream);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.95rem;
}
.home-hero__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3.5rem, 17vw, 19rem);
  line-height: 0.85;
  letter-spacing: -0.04em;
  color: var(--teal);
  text-align: center;
  margin: 0;
}
/* HOSPITALITY anchor — pinned at the top of the page, large, in
   teal. Z-index 5 so it overlaps the video below it. Top offset is
   tuned so HOSPITALITY's bottom edge extends meaningfully INTO the
   video's top portion from the start (rather than just sitting above
   it). No fade animation — stays put throughout the expansion as the
   brand register. */
/* Title block — HOSPITALITY + the 5-line list as one typographic
   composition. The block is absolutely centred in the section.
   z-index: 1 so the .home-hero__media (z-index 2) renders ON TOP
   of the centre portion of the block, hiding it where the video
   sits. A duplicate of this block lives INSIDE .home-hero__media
   (.home-hero__title-block--overlay) and shows only inside the
   video frame, with mix-blend-mode applied — so the user sees the
   plain text outside the video and the blended text inside it. */
.home-hero__title-block {
  --hosp-size: clamp(2.5rem, 10.4vw, 11rem);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* min-width ensures the block is wide enough for the longest
     phrase ("Cultural Programming" / "Training & Standards") even
     when HOSPITALITY's content is narrower. Without this, the
     block sized to HOSPITALITY would clip the longer phrases on
     the right. */
  width: max-content;
  min-width: 82vw;
  max-width: 96vw;
  z-index: 1;
  pointer-events: none;
}

/* HOSPITALITY anchor — plain text on cream. No blend mode at this
   layer (the blend happens only on the inside copy that lives within
   the video frame). */
.home-hero__title--anchor {
  font-family: var(--font-display);
  /* Fraunces 900 — the heaviest cut of the family. Reads as a more
     architectural mark than the 700 it was set in previously. */
  font-weight: 900;
  /* Push the optical-size axis to its display end so the strokes
     are tuned for very large display use rather than text. */
  font-variation-settings: "opsz" 144;
  font-size: var(--hosp-size);
  letter-spacing: -0.045em;
  line-height: 0.9;
  text-transform: uppercase;
  /* Swapped from teal → terracotta. The cycler beneath is now teal,
     so the two layers swap their previous treatment. */
  color: var(--terracotta);
  margin: 0;
  text-align: center;
  display: block;
}

/* ---------- HERO WHEEL — 3D cycling phrase wheel ----------
   Sits directly below HOSPITALITY. Five phrases in DOM, but only the
   centre is fully readable at any moment.

   3D treatment: the wheel container has CSS perspective; each item
   uses rotateX combined with translateY so items above the centre
   tilt backward (top edge goes away from viewer) and items below
   tilt forward (top edge comes toward viewer). The combination
   imitates a horizontal-axis cylinder — a casino wheel curving into
   and out of view. Items further from centre tilt more steeply
   (rotateX 110deg places them past perpendicular, fully invisible).

   Architecture: each phrase has a data-pos attribute (-2, -1, 0, 1, 2)
   that the JS rewrites every cycle. CSS attribute selectors map each
   position to a transform + opacity. Transitions carry items between
   positions, so the wheel appears to physically rotate.

   The "wrap" item (rotating from -2 to 2 around the back of the
   cylinder) gets an `is-snap` class for one frame so its transition
   is suppressed — otherwise it would visibly fly across the wheel
   instead of teleporting around the back.

   Vibration buildup: BEFORE each rotation, the centre item gets an
   `is-vibrating` class for 400ms. The animation wobbles the item
   along Y with progressively larger amplitude — mechanical
   anticipation, like a wheel about to tick over. Once the vibration
   ends, the rotation transition starts and physically advances the
   wheel.

   Reduced motion: hide all non-centre items, freeze the centre.
   No transitions, no animation, no JS cycling. */
.hero-wheel {
  position: relative;
  width: 100%;
  height: 3.4em;
  margin-top: -0.25em;             /* light overlap into HOSPITALITY's bottom */
  font-family: var(--font-body);
  font-weight: 800;
  font-size: clamp(1.7rem, 4vw, 3.5rem);
  line-height: 1;
  color: var(--terracotta);
  pointer-events: none;
  user-select: none;
  /* perspective creates the depth that rotateX needs to feel like
     a real cylinder — items tilting toward/away from the viewer.
     500px is a moderate depth; smaller = more dramatic curve. */
  perspective: 500px;
  perspective-origin: center center;
}

.hero-wheel__item {
  position: absolute;
  left: 50%;
  top: 50%;
  white-space: nowrap;
  transform: translate(-50%, -50%);
  transform-origin: center center;
  transform-style: preserve-3d;
  transition:
    transform 600ms cubic-bezier(0.32, 0.72, 0, 1),
    opacity 500ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* Centre — focal, full opacity, no rotation. */
.hero-wheel__item[data-pos="0"] {
  transform: translate(-50%, -50%) rotateX(0deg);
  opacity: 1;
}

/* Top — previous phrase, tilted backward as if curving over the top
   of the cylinder. translateY positions it visually above centre;
   rotateX 60deg pushes its top edge away from the viewer. */
.hero-wheel__item[data-pos="-1"] {
  transform: translate(-50%, calc(-50% - 1em)) rotateX(60deg);
  opacity: 0.32;
}

/* Bottom — next phrase, tilted forward as if curving up from below.
   translateY downward; rotateX -60deg brings its top edge forward. */
.hero-wheel__item[data-pos="1"] {
  transform: translate(-50%, calc(-50% + 1em)) rotateX(-60deg);
  opacity: 0.32;
}

/* Hidden above — rotated past 90deg so the item is past edge-on,
   effectively behind the cylinder. opacity 0 so it doesn't
   intercept events or render glitches at the seam. */
.hero-wheel__item[data-pos="-2"] {
  transform: translate(-50%, calc(-50% - 1.5em)) rotateX(115deg);
  opacity: 0;
}

/* Hidden below — same, mirrored. */
.hero-wheel__item[data-pos="2"] {
  transform: translate(-50%, calc(-50% + 1.5em)) rotateX(-115deg);
  opacity: 0;
}

/* Snap class — applied for one frame to the wrap item so it
   teleports from hidden-above to hidden-below without animating
   across the cylinder. JS removes after a 2-RAF gap. */
.hero-wheel__item.is-snap {
  transition: none !important;
}

/* Vibration buildup — fires on the centre BEFORE each rotation.
   Y-translation wobble with progressively increasing amplitude to
   imitate mechanical anticipation. The animation ends back at
   centre so the rotation transition starts cleanly. */
.hero-wheel__item.is-vibrating {
  animation: hero-wheel-vibrate 400ms cubic-bezier(0.45, 0, 0.55, 1);
}

@keyframes hero-wheel-vibrate {
  0%   { transform: translate(-50%, -50%) rotateX(0deg); }
  12%  { transform: translate(-50%, calc(-50% - 0.8px)) rotateX(0deg); }
  24%  { transform: translate(-50%, calc(-50% + 0.8px)) rotateX(0deg); }
  36%  { transform: translate(-50%, calc(-50% - 1.5px)) rotateX(0deg); }
  48%  { transform: translate(-50%, calc(-50% + 1.5px)) rotateX(0deg); }
  60%  { transform: translate(-50%, calc(-50% - 2.5px)) rotateX(0deg); }
  72%  { transform: translate(-50%, calc(-50% + 2.5px)) rotateX(0deg); }
  84%  { transform: translate(-50%, calc(-50% - 4px)) rotateX(0deg); }
  100% { transform: translate(-50%, -50%) rotateX(0deg); }
}

@media (prefers-reduced-motion: reduce) {
  .hero-wheel__item {
    transition: none !important;
    animation: none !important;
  }
  /* Show only the centre word, statically. */
  .hero-wheel__item:not([data-pos="0"]) {
    display: none;
  }
}
.home-hero__sub {
  margin-top: clamp(1rem, 2vw, 1.5rem);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.84rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.7);
}
.home-hero__focus {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: clamp(2rem, 4vw, 3rem);
  flex-wrap: wrap;
  justify-content: center;
}
.home-hero__focus .label {
  color: rgba(17, 17, 17, 0.55);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
}
.home-hero__focus .focus-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--cream-soft);
  border: 1px solid rgba(17, 17, 17, 0.08);
  padding: 0.65rem 1.1rem;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--teal);
  transition: background var(--dur-hover) ease, color var(--dur-hover) ease;
}
.home-hero__focus .focus-pill:hover { background: var(--terracotta); color: var(--cream); border-color: var(--terracotta); }

/* Hero media — absolutely centred in the viewport. ONE smooth
   motion: the frame opens sideways with a slight height growth.
   Width animates 25vw → 65vw (2.6×); height animates 35vw → 42vw
   (1.2×) at a much lower rate, so the box mostly opens horizontally.
   Initial state is a narrow portrait crop of the 2:1 landscape video;
   final state is a wide near-landscape frame with most of the video
   visible. Border-radius animates 8px → 0. */
.home-hero__media {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* Initial 4:5 portrait ratio (20vw × 25vw — taller than wide).
     Reduced 15% from the previous 24×30 start. JS animates height
     up to ~34vw early in the scroll, then continues width expansion
     to 80vw across the full hero passage — the video sits inset
     from the viewport edges at end state, so the bottom shadow
     doesn't bleed into the byline below. */
  width: 20vw;
  height: 25vw;
  max-width: 100vw;
  max-height: 80vh;
  border-radius: 10px;
  overflow: hidden;
  z-index: 2;
  /* Softened shadow — reduced offset / blur / opacity from
     0 30px 80px rgba(0,0,0,0.5) so the darkening doesn't reach the
     byline copy positioned beneath the hero. */
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
  /* Black backdrop — video is now fully opaque so the backdrop
     is fully covered; #000 is the safe choice in case the video
     fails to load. */
  background: #000;
}
/* Scroll hint — small "Scroll ↓" badge anchored to the bottom-centre
   of the video frame. Sits above the video (z-index 4) but below the
   title-block overlay (z-index 3 within the same parent — the hint's
   higher index keeps it visible if their bounding boxes ever overlap).
   Subtle: muted cream, low opacity, gentle vertical bob to draw the
   eye without screaming. JS fades opacity to 0 as scroll begins so it
   only exists on first paint. */
.home-hero__scroll-hint {
  position: absolute;
  /* Pinned to the bottom-centre of the hero SECTION (not the video
     frame). Sits in the empty cream space where the "Current Focus"
     pill used to be. */
  bottom: clamp(2rem, 4vh, 3.5rem);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  z-index: 4;
  pointer-events: none;
  font-family: var(--font-body);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  /* Teal at 65% opacity — legible on the cream backdrop and matches
     the byline colour above. Was cream when the hint sat over the
     dark video, but cream on cream is invisible. */
  color: rgba(31, 91, 130, 0.65);
  animation: scroll-hint-bob 2.4s ease-in-out infinite;
  will-change: transform, opacity;
}
.home-hero__scroll-hint-arrow {
  display: block;
  opacity: 0.85;
}
@keyframes scroll-hint-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 4px); }
}
@media (prefers-reduced-motion: reduce) {
  .home-hero__scroll-hint {
    animation: none;
  }
}

.home-hero__media-video {
  /* Full opacity — video plays at its natural brightness. */
  opacity: 1;
  /* Sized 150% of the frame and offset upward by 25% so the visible
     middle 100% fills the frame. The extra 25% above and 25% below
     are clipped by .home-hero__media's overflow:hidden. JS animates
     translateY on this element during the section's exit — the FRAME
     stays locked in place; the video CONTENT drifts within the frame.
     The 25% headroom comfortably absorbs the JS's 22%-of-frame drift
     (now bumped from 10% so the parallax is actually perceptible
     against the video's own motion). */
  position: absolute;
  top: -25%;
  left: 0;
  width: 100%;
  height: 150%;
  object-fit: cover;
  object-position: center;
  display: block;
  pointer-events: none;
}

/* Phrases — now a typographic CONTINUATION of HOSPITALITY rather
   than an overlay on the video. Same Fraunces family, lighter
   weight (400 vs HOSPITALITY's 700), smaller but still substantial
   font-size, terracotta colour from the brand palette. Tightly
   stacked (gap: 0, line-height: 1) so the five lines read as one
   block. Negative margin-top pulls the first line up into the
   bottom 13% of HOSPITALITY's letterforms — the overlap effect that
   makes the title and the list feel composed rather than separate.
   The negative margin is calc'd against --hosp-size so it tracks
   HOSPITALITY's actual rendered font-size at any viewport. */
.home-hero__phrases {
  /* Negative margin-top tightens the gap between HOSPITALITY and the
     first phrase line. Doubled from -0.32em → -0.65em (≈ another
     50% reduction of the remaining gap). Em is relative to this
     list's own font-size, so the offset scales with the viewport. */
  margin: -0.65em 0 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  /* ~60% of HOSPITALITY's font-size — each entry reads as substantial
     typography in its own right rather than a service menu. The two
     elements compose as a single typographic block. */
  font-size: clamp(1.5rem, 6.4vw, 6.8rem);
  line-height: 1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--terracotta);
  pointer-events: none;
}
.home-hero__phrase {
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

/* Phrase cycler — single-line window beneath HOSPITALITY that
   cycles through the five service names. Driven by scroll progress
   through the hero pin range. Each phrase change uses the same
   per-character roll mechanic as the original text-roll: chars
   in the current phrase slide UP out of the frame while chars in
   the incoming phrase slide UP from below. Per-character delay is
   centre-radiating (letters near the middle of each word fire first,
   edges fire last) so the roll reads as a wave from the centre.

   Two layers (top + bottom) overlap perfectly via absolute
   positioning. JS populates each layer's <span class="char"> spans
   on demand, computing centre-radiating transition-delays per
   character based on the phrase length. */
.home-hero__phrase-cycler {
  position: relative;
  /* Pulls the cycler into HOSPITALITY's bottom third — "level 2"
     overlap (moderate). Visibly stamped against HOSPITALITY without
     crossing into its main body. Em is relative to the cycler's
     own font-size, so the offset scales with the viewport. */
  margin-top: -0.60em;
  height: 1em;
  width: 100%;
  line-height: 1;
  overflow: hidden;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 6.4vw, 6.8rem);
  letter-spacing: -0.01em;
  /* Trying lowercase in place of the uppercase treatment — gives the
     phrase a softer, more editorial counterpoint to HOSPITALITY's
     heavy uppercase mark above. */
  text-transform: lowercase;
  /* Solid teal everywhere — both the outer copy on cream and the
     overlay copy over the video read the same. Pairs with the solid
     terracotta on HOSPITALITY above. */
  color: var(--teal);
  pointer-events: none;
  text-align: center;
}
.cycler-roll__top,
.cycler-roll__bottom {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  display: block;
  white-space: nowrap;
  text-align: center;
}
.cycler-roll__top .char,
.cycler-roll__bottom .char {
  display: inline-block;
  /* 0.4s transition — subtle slowdown from the original 0.25s.
     Reads as more considered without losing responsiveness when
     the user scrolls quickly between phrases. */
  transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1);
  /* transition-delay set inline by JS per character for the
     centre-radiating stagger pattern */
}
.cycler-roll__top .char {
  transform: translateY(0);
}
.cycler-roll__bottom .char {
  transform: translateY(100%);
}
.home-hero__phrase-cycler.is-rolled .cycler-roll__top .char {
  transform: translateY(-100%);
}
.home-hero__phrase-cycler.is-rolled .cycler-roll__bottom .char {
  transform: translateY(0);
}
/* `no-transition` is added briefly when the JS snaps the layers
   back to their initial positions after the animation completes —
   so the snap is invisible. */
.home-hero__phrase-cycler.no-transition .cycler-roll__top .char,
.home-hero__phrase-cycler.no-transition .cycler-roll__bottom .char {
  transition: none !important;
}

/* Overlay copy of the title block — lives INSIDE .home-hero__media
   (which has overflow: hidden), so it's clipped to the video frame.
   Positioned identically to the outer title-block (centred at media's
   centre, which equals the viewport centre because both are centred
   absolutely). The overlay's text uses mix-blend-mode: difference to
   composite against the video pixels behind it. The blend therefore
   ONLY applies where text overlaps the video — outside the video,
   the outer title-block's plain text shows instead. As the video
   expands sideways/downward, more of the text falls inside the media
   frame, so more becomes "blended" naturally. */
.home-hero__title-block--overlay {
  --hosp-size: clamp(2.5rem, 10.4vw, 11rem);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: max-content;
  z-index: 3;   /* above the video element inside media */
  pointer-events: none;
}
/* CYCLER ONLY — over-video copy switches to cream so it stays
   legible against the video imagery (teal-on-video can compete
   with whatever colours the footage is throwing at it). Off-video,
   the cycler stays teal per its base rule above. HOSPITALITY is
   NOT affected — its terracotta reads cleanly on both surfaces.

   Effect: as the video edge grows past the cycler text, each letter
   transitions teal → cream in lockstep with the edge. */
.home-hero__title-block--overlay .home-hero__phrase-cycler {
  color: var(--cream);
}

/* ---------- TEXT-ROLL — letter-by-letter slot-reel reveal ----------
   Applied to each line of the typographic block (HOSPITALITY + 5
   service names) by initTextRoll(). Two stacked copies of the same
   text: top visible at translateY(0), bottom hidden at
   translateY(100%). On `.is-rolled` (added to ancestor on viewport
   entry), top → translateY(-100%) and bottom → translateY(0). Each
   character has its own transition-delay set inline by JS, computed
   from a centre-radiating stagger pattern.

   The .text-roll class is added by JS to existing line elements
   (.home-hero__title--anchor and .home-hero__phrase), so this rule
   needs to override their default display for the overflow:hidden
   trick to work correctly. */
.text-roll {
  display: inline-block;
  position: relative;
  overflow: hidden;
  vertical-align: top;
  line-height: 0.85;
  /* Re-enable pointer events so hover registers — the parent
     .home-hero__title-block has pointer-events: none so clicks pass
     through to the video. The text-roll lines re-capture hover for
     the per-line roll trigger. */
  pointer-events: auto;
  cursor: default;
}
.text-roll__top,
.text-roll__bottom {
  display: block;
  white-space: nowrap;
}
.text-roll__bottom {
  position: absolute;
  inset: 0;
}
.text-roll__top .char,
.text-roll__bottom .char {
  display: inline-block;
  /* Slowed to 1.2s (was 0.6s) so the roll is clearly visible —
     letters take a beat each to slide rather than flashing past. */
  transition: transform 1.2s cubic-bezier(0.65, 0, 0.35, 1);
  /* transition-delay set inline by JS per character */
}
.text-roll__top .char {
  transform: translateY(0);
}
.text-roll__bottom .char {
  transform: translateY(100%);
}
.is-rolled .text-roll__top .char {
  transform: translateY(-100%);
}
.is-rolled .text-roll__bottom .char {
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  /* No transition; show top copy as if rolled into place from the
     start (transform: 0). Bottom copy hidden. Static text. */
  .text-roll__top .char,
  .text-roll__bottom .char {
    transition: none !important;
    transform: none !important;
  }
  .text-roll__bottom {
    display: none;
  }
}

/* Bottom-anchored variants of the existing sub + focus elements.
   They stay pinned to the bottom of the viewport throughout the
   expansion — they don't animate. The original .home-hero__sub
   and .home-hero__focus rules earlier in the file styled the
   previous flex-centred layout; these modifiers override position
   and adjust colour for the new dark-on-image context. */
.home-hero__sub--bottom {
  position: absolute;
  /* Positioned at the visual midpoint between the bottom edge of
     the video at full stretch and the TOP edge of the focus pill
     beneath. Earlier version used pill BOTTOM for the calc, but
     that ignored the pill's own height (~43px / ~4vh) — putting the
     byline visibly closer to the pill than to the video.
     Math:
       video bottom from viewport bottom = 50vh − 17vw
         (video is 34vw tall and centred → bottom edge sits 17vw
          below viewport centre)
       pill TOP from viewport bottom ≈ 7vh + 4vh ≈ 11vh
         (pill bottom-offset clamp(4rem, 6.75vh, 5.25rem) ≈ 7vh on
          most desktops, plus ~4vh of pill height)
       midpoint = ((50vh − 17vw) + 11vh) / 2 = 30.5vh − 8.5vw
     Subtract half the byline's own height (~1.3vh) for true visual
     centring → ~31vh − 8.5vw. The clamp guards the result on
     extreme viewport ratios where the video hits its max-height:
     80vh cap (tall narrow screens). */
  bottom: clamp(7rem, calc(29.5vh - 8.5vw), 12.5rem);
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  padding: 0 1.5rem;
  width: max-content;
  max-width: min(56ch, 92vw);
  text-align: center;
  font-family: var(--font-body);
  font-weight: 500;
  /* Reduced 20% from clamp(1.15rem, 1.7vw, 1.55rem) — tones the
     line down so it reads as a quieter byline beneath the typographic
     block rather than competing with it. */
  font-size: clamp(0.92rem, 1.36vw, 1.24rem);
  letter-spacing: 0;
  text-transform: none;
  line-height: 1.45;
  color: var(--teal);
  z-index: 5;
}
.home-hero__focus--bottom {
  position: absolute;
  /* Roughly half of the descriptor's bottom offset so the focus pill
     sits vertically centred between the descriptor above and the
     section's bottom edge below. */
  bottom: clamp(4rem, 6.75vh, 5.25rem);
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  z-index: 5;
}
/* Bottom-anchored variants of the focus elements — sit on the cream
   backdrop (or the bg image at 50% in the initial state). The
   default focus-pill style (cream-soft on cream) would disappear,
   so override to the terracotta brand accent: visible on both the
   image-overlay initial state and the cream final state. */
.home-hero__focus--bottom .label {
  color: rgba(17, 17, 17, 0.6);
  text-shadow: none;
}
.home-hero__focus--bottom .focus-pill {
  background: var(--terracotta);
  border-color: var(--terracotta);
  color: var(--cream);
  backdrop-filter: none;
}
.home-hero__focus--bottom .focus-pill:hover {
  background: var(--teal);
  border-color: var(--teal);
  color: var(--cream);
}

/* ---------- HOME — THESIS STATEMENT ---------- */
.thesis {
  background: var(--teal);
  color: var(--cream);
  padding: clamp(5rem, 12vw, 11rem) var(--pad-x);
}
/* Editorial thesis treatment — restrained typography over visual
   shouting. Three short paragraphs in one consistent voice
   (lowercase, weight 500, ~2rem max), generous line-height, narrow
   measure, subtle vertical rhythm between sentences. Trusts
   restraint to carry weight rather than scale.
   Key words emphasised in terracotta only (no italic, no weight
   shift) so the rhythm of the type stays uniform. */
.thesis__block {
  /* Tight measure (~46ch) — focused editorial column instead of a
     full-width billboard. */
  max-width: 46ch;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  text-align: center;
  gap: 0;
}
.thesis__statement {
  font-family: var(--font-display);
  /* Weight 500 — confident but not bold-shouty. Fraunces / Aurellis
     carries presence at this weight without the marketing-collateral
     feel that 700 + huge-size produces. */
  font-weight: 500;
  /* Significantly smaller — was clamp(2rem, 6.2vw, 6.5rem). At
     ~2.2rem max the type reads as editorial pull-quote rather than
     a billboard. */
  font-size: clamp(1.4rem, 2.4vw, 2.2rem);
  /* Generous leading — lets each sentence settle on its own. */
  line-height: 1.5;
  letter-spacing: -0.005em;
  color: var(--cream);
  /* Subtle vertical rhythm between sentences (was 0). Each sentence
     has its own beat instead of running together. */
  margin: 0 0 0.65em;
}
.thesis__statement:last-child {
  margin-bottom: 0;
}
.thesis__statement em {
  color: var(--terracotta);
  font-style: normal;
  /* Match the surrounding weight — the colour shift is the only
     emphasis (no bold pop). */
  font-weight: inherit;
}

/* Eyebrow — small uppercase tracked label above the thesis block,
   anchoring it as a designed editorial passage (matching the eyebrow
   pattern used elsewhere on the site). */
.thesis__eyebrow {
  display: block;
  margin: 0 auto clamp(1.75rem, 3.5vw, 3rem);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(242, 237, 228, 0.55);
  text-align: center;
}

@media (max-width: 600px) {
  .thesis__statement { font-size: clamp(1.2rem, 4.4vw, 1.6rem); }
}
.thesis__caption {
  margin-top: clamp(2rem, 4vw, 3rem);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(242, 237, 228, 0.6);
  text-align: center;
}

/* ---------- HOME — MESSAGE FROM ALEX ---------- */
.message {
  position: relative;
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  overflow: hidden;
}
.message__label {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-text);
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
  text-align: center;
}
.message__inner {
  position: relative;
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr;
  align-items: center;
  text-align: center;
}
.message__bg-text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 9vw, 9rem);
  line-height: 0.92;
  letter-spacing: -0.025em;
  color: var(--teal);
  opacity: 0.9;
  max-width: 14ch;
  margin: 0 auto;
  position: relative;
  z-index: 1;
}
.message__portrait {
  position: relative;
  z-index: 2;
  margin: clamp(-3rem, -5vw, -4rem) auto clamp(-2rem, -4vw, -3rem);
  width: clamp(220px, 32vw, 460px);
}
.message__portrait .image-slot {
  aspect-ratio: 4 / 5;
  border-radius: 4px;
}
.message__signature {
  position: relative;
  z-index: 3;
  margin: 0 auto;
  width: clamp(180px, 28vw, 340px);
  transform: translateY(-30%) rotate(-4deg);
}

/* ---------- HOME — SELECTED HIGHLIGHTS ---------- */
.highlights {
  background: var(--cream);
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  border-top: 1px solid rgba(17, 17, 17, 0.06);
}
.highlights__inner {
  max-width: var(--container);
  margin: 0 auto;
}
.highlights__head {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-bottom: clamp(2.5rem, 5vw, 4rem);
}
.highlights__head h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.25rem, 5.5vw, 4.5rem);
  line-height: 0.98;
  letter-spacing: -0.02em;
  color: var(--teal);
  max-width: 18ch;
}
.highlights__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(2rem, 5vw, 5rem);
  row-gap: 0;
  max-width: 1200px;
}
.highlights__item {
  display: grid;
  grid-template-columns: 3rem 1fr;
  align-items: baseline;
  gap: 0.75rem;
  padding: 1.1rem 0;
  border-top: 1px solid rgba(17, 17, 17, 0.1);
  font-family: var(--font-body);
  font-size: clamp(0.95rem, 1.15vw, 1.05rem);
  line-height: 1.5;
  color: var(--black);
}
.highlights__item:last-child { border-bottom: 1px solid rgba(17, 17, 17, 0.1); }
.highlights__num {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  color: var(--terracotta-text);
}
@media (max-width: 820px) {
  .highlights__grid { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .highlights__item { grid-template-columns: 2.25rem 1fr; gap: 0.5rem; }
}

/* ============================================================
   THESIS CLOSE — tight, visible-by-default thesis statement
   that closes the track record. Static (no motion); content
   has to read on first paint, no matter what.
   ============================================================ */
.thesis-close {
  /* Strongly asymmetric padding — top is much larger than bottom to
     balance the visual weight of the signature image at the bottom.
     Top approx matches home-cta's top padding (~173px @ 1440), so the
     gap above the heading mirrors the gap below the signature when
     viewed as a section moment. */
  padding: clamp(7rem, 12vw, 11rem) var(--pad-x) clamp(3.5rem, 7vw, 5.5rem);
  background: var(--cream-soft);
  border-top: 1px solid rgba(17, 17, 17, 0.06);
  text-align: center;
}
.thesis-close__inner {
  max-width: 44rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* Lead — display italic, smaller than before. */
.thesis-close__lead {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.5rem, 3.4vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: -0.005em;
  color: var(--teal);
  margin: 0 0 clamp(1rem, 2vw, 1.5rem);
  max-width: 22ch;
  text-wrap: balance;
}
/* Body — quiet, narrow column, smaller. */
.thesis-close__body {
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 1.1vw, 1.05rem);
  line-height: 1.55;
  color: rgba(17, 17, 17, 0.72);
  margin: 0 0 clamp(1.5rem, 3vw, 2.25rem);
  max-width: 38ch;
  text-wrap: balance;
}
/* Verdict — display roman, smaller, with terracotta rule above. */
.thesis-close__final {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 3.6vw, 2.6rem);
  line-height: 1.1;
  letter-spacing: -0.008em;
  color: var(--ink);
  margin: 0;
  position: relative;
  padding-top: clamp(1.25rem, 2.5vw, 1.75rem);
  text-wrap: balance;
}
.thesis-close__final::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  height: 2px;
  width: clamp(72px, 10vw, 140px);
  background: var(--terracotta);
}
.thesis-close__emphasis {
  color: var(--terracotta);
}
.thesis-close__signature {
  display: block;
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  width: clamp(110px, 14vw, 160px);
  height: auto;
  opacity: 0.78;
}
.thesis-close__signature img {
  width: 100%;
  height: auto;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

/* ---------- HOME — CAREER RAIL (the film strip) ---------- */
.career-rail {
  background: var(--cream);
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  position: relative;
  overflow: hidden;
}
.career-rail__head {
  text-align: center;
  margin-bottom: clamp(3rem, 7vw, 6rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-items: center;
}
.career-rail__head .display-italic {
  font-size: clamp(1.4rem, 3vw, 2.4rem);
  color: var(--teal);
  max-width: 36ch;
}
.career-rail__grid {
  position: relative;
  max-width: 1700px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem) clamp(1rem, 2vw, 2rem);
}
.career-rail__item {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  position: relative;
}
.career-rail__item .image-slot { width: 100%; position: relative; }
.career-rail__item .image-slot img {
  width: 100%;
  height: auto;
  display: block;
}
/* Caption is now a single block with three stacked lines:
   venue (display, prominent) → role (body, secondary) → location/year (mono caps). */
.career-rail__caption {
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  margin-top: 0.7rem;
}
.career-rail__venue {
  font-family: var(--font-display);
  font-weight: 700;
  /* Bumped 30% from 1rem → 1.3rem so the venue name reads as a
     more confident editorial mark within each card. */
  font-size: 1.3rem;
  line-height: 1.15;
  letter-spacing: -0.005em;
  color: var(--ink);
}
.career-rail__what {
  font-family: var(--font-body);
  font-weight: 500;
  /* Bumped 20% from 0.78rem → 0.936rem to keep proportional
     hierarchy with the larger venue name above. */
  font-size: 0.936rem;
  line-height: 1.3;
  color: rgba(17, 17, 17, 0.72);
}
.career-rail__where {
  font-family: var(--font-body);
  font-weight: 500;
  /* Bumped 20% from 0.66rem → 0.792rem to match the body line's
     proportional increase. Still smaller than the role line so
     the three-tier hierarchy is preserved. */
  font-size: 0.792rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.5);
  margin-top: 0.15rem;
}
/* Venue row — venue name on the left, optional Case Study link on the
   right. Currently used by the INDSTRY card. The link uses the same
   uppercase tracked treatment as .career-rail__where so it reads as
   meta, not as a primary CTA — terracotta colour signals "click me"
   without shouting. Arrow nudges right on hover for affordance. */
.career-rail__venue-row {
  display: flex;
  justify-content: space-between;  /* venue on left, Case Study link on right */
  align-items: baseline;
  gap: 0.75rem;
}
.career-rail__cs-link {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.66rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta);
  text-decoration: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  transition: color 220ms ease;
}
.career-rail__cs-link .arrow {
  display: inline-block;
  transition: transform 220ms cubic-bezier(0.32, 0.72, 0, 1);
}
.career-rail__cs-link:hover { color: var(--terracotta-hover, var(--terracotta)); }
.career-rail__cs-link:hover .arrow { transform: translateX(4px); }
/* Varied placement & sizes — the moodboard look (vertical fallback) */
.career-rail__item--01 { grid-column: 1 / 5;  margin-top: 0; }
.career-rail__item--02 { grid-column: 6 / 11; margin-top: 6vw; }
.career-rail__item--03 { grid-column: 2 / 5;  margin-top: 4vw; }
.career-rail__item--04 { grid-column: 7 / 12; margin-top: -2vw; }
.career-rail__item--05 { grid-column: 1 / 4;  margin-top: 5vw; }
.career-rail__item--06 { grid-column: 5 / 10; margin-top: 8vw; }
.career-rail__item--07 { grid-column: 9 / 13; margin-top: -3vw; }
.career-rail__item--08 { grid-column: 2 / 6;  margin-top: 4vw; }
.career-rail__item--01 .image-slot { aspect-ratio: 3 / 4; }
.career-rail__item--02 .image-slot { aspect-ratio: 16 / 9; }
.career-rail__item--03 .image-slot { aspect-ratio: 4 / 5; }
.career-rail__item--04 .image-slot { aspect-ratio: 3 / 2; }
.career-rail__item--05 .image-slot { aspect-ratio: 4 / 5; }
.career-rail__item--06 .image-slot { aspect-ratio: 16 / 10; }
.career-rail__item--07 .image-slot { aspect-ratio: 3 / 4; }
.career-rail__item--08 .image-slot { aspect-ratio: 5 / 4; }

/* ============================================================
   HORIZONTAL SCROLL-JACK MODE — applied via .career-rail--horizontal
   class. All cards uniform size, single horizontal line, scroll-jack
   pins the section and translates the rail right→left.
   ============================================================ */
.career-rail--horizontal {
  height: 100vh !important;
  min-height: 100vh;
  padding: 0 !important;
  overflow: hidden !important;
  display: flex !important;
  flex-direction: column !important;
}
.career-rail--horizontal .career-rail__head {
  padding: clamp(100px, 13vh, 150px) var(--pad-x) clamp(1.5rem, 3vh, 2.5rem) !important;
  margin: 0 !important;
  flex: 0 0 auto !important;
}
.career-rail--horizontal .career-rail__grid {
  display: flex !important;
  flex-direction: row !important;
  flex-wrap: nowrap !important;
  gap: clamp(0.75rem, 1.5vw, 2.25rem) !important;   /* breathing-room gap, ~12-36px */
  width: max-content !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 6vw !important;
  flex: 1 1 auto !important;
  align-items: center !important;
  grid-template-columns: none !important;
  will-change: transform;
}
/* Editorial-scale cards. Sized to feel substantial without dominating
   the entire viewport — leaves room for the rhythm of the gap. */
.career-rail--horizontal .career-rail__item {
  flex: 0 0 auto !important;
  width: clamp(512px, 52vw, 880px) !important;
  height: auto !important;
  margin: 0 !important;
  grid-column: auto !important;
  align-self: center !important;
  display: flex !important;
  flex-direction: column !important;
  gap: 0.7rem !important;
}
/* Force a uniform 16:9 aspect for ALL image slots in horizontal mode.
   Override the per-item aspect-ratio rules from the vertical layout. */
.career-rail--horizontal .career-rail__item .image-slot {
  width: 100% !important;
  aspect-ratio: 16 / 9 !important;
  height: auto !important;
  position: relative;
  overflow: hidden;
}
/* Image and video both fill their frame edge-to-edge. Per-image parallax
   was tested and rejected — even with the reference's exact mechanics
   (left:-12.5%, 125% width, 10% counter-shift), the visible content
   alignment between adjacent cards reads as gap variation, and the
   hover-rotate alts caused layering issues since they're created
   dynamically. Cleaner, more readable without the effect. */
.career-rail--horizontal .career-rail__item .image-slot img,
.career-rail--horizontal .career-rail__item .image-slot video {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
}
/* Career-rail videos are pure visual content — no native controls, no
   click-to-fullscreen, no right-click menu. Clicks pass through to the
   parent figure (which itself has no handler), so the card behaves
   identically to a static image card. */
.career-rail__item .image-slot video {
  pointer-events: none;
}

/* Hover-rotation rotor layers — absolutely positioned crossfade overlays
   that sit on top of the base <img>. The base image is never touched, so
   if every rotor is at opacity 0, the base remains visible. No blank
   gaps possible. Rotors are pre-rendered on init so there's no fetch
   delay when hover starts. */
.career-rail__item .image-slot img.career-rail__rotor {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  opacity: 0;
  transition: opacity 700ms cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
}
.career-rail__item .image-slot img.career-rail__rotor.is-active {
  opacity: 1;
}

@media (max-width: 900px) {
  /* Mobile keeps the existing vertical grid layout — JS doesn't activate
     horizontal mode below this breakpoint. */
  .career-rail__grid { grid-template-columns: repeat(6, 1fr); gap: 1.5rem 1rem; }
  .career-rail__item { margin-top: 0 !important; }
  .career-rail__item--01, .career-rail__item--03, .career-rail__item--05, .career-rail__item--07 { grid-column: 1 / 4; }
  .career-rail__item--02, .career-rail__item--04, .career-rail__item--06, .career-rail__item--08 { grid-column: 4 / 7; }
}
@media (max-width: 540px) {
  .career-rail__grid { grid-template-columns: 1fr; }
  .career-rail__item { grid-column: 1 / -1 !important; }
}

.career-rail__quote {
  margin: clamp(4rem, 8vw, 7rem) auto 0;
  max-width: 60ch;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: center;
}
.career-rail__quote .pullquote {
  font-size: clamp(1.5rem, 3.4vw, 2.6rem);
  max-width: 30ch;
}

/* ---------- HOME — ENGAGEMENT MODES (3 columns) ---------- */
.modes {
  background: var(--cream);
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  border-top: 1px solid rgba(17, 17, 17, 0.06);
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
}
.modes__head {
  max-width: var(--container);
  margin: 0 auto clamp(2.5rem, 5vw, 4rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-items: flex-start;
}
.modes__head h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 7vw, 6rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--teal);
  max-width: 18ch;
}
.modes__grid {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 3.5rem);
}
.mode {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--terracotta);
}
.mode h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.75rem, 3.2vw, 2.5rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--teal);
}
.mode p {
  font-family: var(--font-body);
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--black);
  max-width: 38ch;
}
.mode .link { align-self: flex-start; margin-top: 0.5rem; }
@media (max-width: 900px) {
  .modes__grid { grid-template-columns: 1fr; }
}

/* ---------- HOME — FIX / CREATE SPLIT (legacy, unused but kept for safety) ---------- */
.split {
  background: var(--cream);
  padding: clamp(4rem, 9vw, 8rem) var(--pad-x);
  border-top: 1px solid rgba(17, 17, 17, 0.06);
  border-bottom: 1px solid rgba(17, 17, 17, 0.06);
}
.split__inner {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.split__col {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.split__col h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(4rem, 14vw, 14rem);
  line-height: 0.85;
  letter-spacing: -0.04em;
  color: var(--teal);
}
.split__col--right { text-align: right; align-items: flex-end; }
.split__col--right h2 { color: var(--terracotta); }
.split__col p { max-width: 38ch; font-size: 0.98rem; line-height: 1.55; }
.split__col--right p { margin-left: auto; }
.split__cta {
  width: 56px; height: 56px;
  display: inline-grid; place-items: center;
  border-radius: 50%;
  background: var(--terracotta);
  color: var(--cream);
  margin-top: 1rem;
}
.split__cta:hover { background: var(--terracotta-hover); }
.split__cta--right { align-self: flex-end; }

.split__center {
  width: clamp(220px, 24vw, 360px);
}
.split__center .image-slot { aspect-ratio: 3 / 4; }

.split__below {
  max-width: var(--container);
  margin: clamp(3rem, 6vw, 5rem) auto 0;
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid rgba(17, 17, 17, 0.08);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1rem 2.5rem;
  align-items: baseline;
}
.split__below h3 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.4rem, 2.6vw, 2rem);
  color: var(--teal);
  line-height: 1.1;
}
.split__below p { max-width: 56ch; font-size: 0.95rem; }

@media (max-width: 900px) {
  .split__inner { grid-template-columns: 1fr; gap: 2rem; }
  .split__col, .split__col--right { text-align: left; align-items: flex-start; }
  .split__col--right p { margin-left: 0; }
  .split__col--right { order: 3; }
  .split__center { order: 2; width: 60%; }
  .split__below { grid-template-columns: 1fr; gap: 0.75rem; }
}

/* ---------- HOME — THE WORK PREVIEW ---------- */
.work-preview {
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
}
.work-preview__inner {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  /* Text column = natural content width (heading sets it); cards
     column takes everything remaining. Was 1fr / 1.2fr — that
     stretched the text column wider than necessary and left empty
     space below the CTA. Now the text stays exactly where it is and
     the accordion expands leftward into the previously vacant area. */
  grid-template-columns: auto minmax(0, 1fr);
  /* Wider gap (was clamp(2rem, 5vw, 5rem)) so the accordion's left
     edge nudges right without moving the heading. Composition feels
     more balanced — the heading no longer hugs the inner block's
     left edge with the accordion crowded close. */
  gap: clamp(3rem, 8vw, 8rem);
  align-items: center;
}
.work-preview__text {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  align-items: flex-start;   /* prevent CTA from stretching to full column width */
}
/* ACCORDION LAYOUT. Five cards in a horizontal row. The active card
   flex-grows to fill remaining space; the four inactive cards collapse
   to narrow strips with rotated vertical labels. Hover (or tap on
   touch) changes the active card. Mobile collapses to a vertical stack
   with all labels horizontal — no rotation, no accordion behaviour. */
.work-preview__cards {
  display: flex;
  gap: 8px;
  height: clamp(420px, 56vw, 600px);
  width: 100%;
  align-items: stretch;
}
.work-preview__card {
  /* IMPORTANT: flex-grow stays 0 in BOTH states. We animate flex-basis
     only — the active card has a calc()-derived fixed basis, inactive
     cards have the strip basis. If the active state used flex: 1 1 0
     (grow: 1), the new active would instantly absorb all free space
     the moment .is-active is added (grow changes are not transitioned),
     and you'd see a jump-to-fully-open then settle. Keeping grow: 0
     means width is purely flex-basis, which animates smoothly. The
     basis values are designed so all 5 cards always sum to 100%, so
     the transition is symmetric: shrinking card and growing card move
     in lockstep with no overshoot. */
  flex: 0 0 clamp(64px, 7vw, 92px);    /* narrow strip default */
  position: relative;
  background: var(--cream-soft);
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 8px 30px rgba(17, 17, 17, 0.10);
  text-decoration: none;
  color: inherit;
  display: block;
  cursor: pointer;
  transition: flex-basis 1100ms cubic-bezier(0.65, 0, 0.35, 1),
              box-shadow 1100ms cubic-bezier(0.65, 0, 0.35, 1);
  will-change: flex-basis;
}
.work-preview__card.is-active {
  /* Take all the space the four inactive strips and four 8px gaps
     don't claim. Keeps flex-grow at 0 so the only animated dimension
     is flex-basis itself — guarantees a smooth shrink/grow handoff. */
  flex: 0 0 calc(100% - 32px - 4 * clamp(64px, 7vw, 92px));
  box-shadow: 0 18px 55px rgba(17, 17, 17, 0.18);
}

.work-preview__card .image-slot {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
}
.work-preview__card .image-slot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  filter: contrast(1.03) saturate(0.97);
  transition: filter 480ms ease;
}
.work-preview__card.is-active .image-slot img {
  filter: contrast(1.05) saturate(1);
}

/* Inactive cards get a stronger full-card overlay — image recedes,
   sideways label pops. Active card uses a softer bottom-only overlay
   so the photo breathes and the horizontal meta stays legible.
   Inactive overlay averages ~0.75 alpha for a clearly muted look. */
.work-preview__card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(17, 17, 17, 0.88) 0%,
    rgba(17, 17, 17, 0.78) 30%,
    rgba(17, 17, 17, 0.7) 65%,
    rgba(17, 17, 17, 0.62) 100%
  );
  pointer-events: none;
  transition: background 900ms cubic-bezier(0.65, 0, 0.35, 1);
}
.work-preview__card.is-active::after {
  background: linear-gradient(
    to top,
    rgba(17, 17, 17, 0.55) 0%,
    rgba(17, 17, 17, 0.22) 28%,
    transparent 58%
  );
}

/* Vertical label — visible when card is collapsed (narrow strip).
   Uses writing-mode: sideways-lr so the browser handles vertical text
   natively. Text reads bottom-to-top with characters upright.

   Two-column stacked layout: flex-direction: column in sideways-lr
   lays children along the BLOCK axis (horizontal in screen coords),
   producing two parallel vertical text columns. Source order [name,
   descriptor] places name on the LEFT and descriptor on the RIGHT
   (sideways-lr stacks lines left-to-right). This is "title + subtitle"
   stacked typography rotated on its side — gives each line its own
   reading column and frees up vertical room.

   Cross-fade timing (matched to the 1100ms width transition):
   - Becoming inactive: card compresses + horizontal meta fades out
     (over 500ms, no delay), then vertical label fades back IN late
     (500ms with a 600ms delay). Reads as a smooth handoff.
   - Becoming active: vertical label fades OUT fast (280ms), then
     horizontal meta fades in late (500ms with a 600ms delay). */
.work-preview__card-label-vertical {
  position: absolute;
  bottom: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  writing-mode: sideways-lr;
  display: flex;
  flex-direction: column;          /* parallel columns: name | desc */
  align-items: flex-start;         /* bottom-anchor both columns */
  gap: 0.45em;
  white-space: nowrap;
  pointer-events: none;
  z-index: 2;
  opacity: 1;
  /* DEFAULT-STATE transition (applies when card is going BACK to
     inactive). Fade in late, after the card has compressed back to
     its strip width. */
  transition: opacity 500ms ease 600ms;
}
.work-preview__card.is-active .work-preview__card-label-vertical {
  opacity: 0;
  /* ACTIVE-STATE transition (applies when card is becoming active).
     Fade the sideways label out quickly so it doesn't compete with
     the expanding card's horizontal meta. */
  transition: opacity 280ms ease;
}
.work-preview__card-label-vertical__name {
  font-family: var(--font-display);
  font-weight: 700;
  /* Bumped 30% from 1.05rem → 1.365rem so the venue name reads with
     more presence on the now-wider collapsed card. */
  font-size: 1.365rem;
  line-height: 1;
  letter-spacing: 0.005em;
  color: var(--cream);
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55);
}
.work-preview__card-label-vertical__desc {
  font-family: var(--font-body);
  font-weight: 500;
  /* Bumped 15% from 0.65rem → 0.7475rem to keep proportional
     hierarchy with the larger venue name above. */
  font-size: 0.7475rem;
  line-height: 1;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(242, 237, 228, 0.85);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}

/* Horizontal meta block — visible when card is active (expanded).

   Symmetric cross-fade with the vertical label:
   - Becoming inactive (DEFAULT-STATE transition): gradual 500ms
     fade-out as the card begins to compress — no delay so it starts
     immediately and is gone by the time the card hits strip width.
   - Becoming active (ACTIVE-STATE transition): late fade-in (500ms
     with a 600ms delay) so it appears once the card has expanded
     enough to host it. */
.work-preview__card-meta {
  /* Span the FULL width of the card and centre with text-align.
     Previously this used left:50% + translateX(-50%) which shrinks
     the box to content width and centres that box — when the title
     and descriptor have different lengths, each line gets text-align
     centred within the content-shrunk box, which can read as visually
     off-axis on cards where one line is much longer than the other.
     Spanning 0 → 0 with text-align:center centres each line against
     the actual card centreline, independent of line length. */
  position: absolute;
  left: 0;
  right: 0;
  bottom: 1.5rem;
  padding: 0 1.5rem;
  text-align: center;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 500ms ease,
              transform 500ms ease;
  pointer-events: none;
  z-index: 2;
}
.work-preview__card.is-active .work-preview__card-meta {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 500ms ease 600ms,
              transform 500ms cubic-bezier(0.22, 1, 0.36, 1) 600ms;
}
.work-preview__card-name {
  font-family: var(--font-display);
  font-weight: 700;
  /* Matched to the collapsed sideways label name (1.365rem) so the
     name stays at the same scale across both states — no cross-state
     size jump as the user clicks between cards. */
  font-size: 1.365rem;
  color: var(--cream);
  margin-bottom: 0.25rem;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55);
  line-height: 1.15;
}
.work-preview__card-desc {
  font-family: var(--font-body);
  font-weight: 500;
  /* Matched to the collapsed sideways label descriptor (0.7475rem)
     for the same reason — consistent scale across both states. */
  font-size: 0.7475rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(242, 237, 228, 0.92);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}

@media (max-width: 900px) {
  /* Mobile — vertical stack, full-width cards, all labels horizontal.
     The accordion mechanic doesn't apply (no hover, narrow strips
     would be unreadable). Each card is a full preview card. */
  .work-preview__inner { grid-template-columns: 1fr; }
  .work-preview__cards {
    flex-direction: column;
    height: auto;
    gap: 1rem;
  }
  .work-preview__card,
  .work-preview__card.is-active {
    flex: 0 0 auto;
    width: 100%;
    height: clamp(280px, 60vw, 420px);
  }
  .work-preview__card-label-vertical { display: none; }
  .work-preview__card-meta { opacity: 1; transition: none; }
}

/* ---------- HOME — PARTNERS ---------- */
.partners {
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  background: var(--cream-soft);
}
.partners__inner {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: center;
}
.partners__head {
  position: relative;
}
.partners__head h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 9vw, 8rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--teal);
}
.partners__overlay {
  position: absolute;
  top: 28%; left: 8%;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(2rem, 6vw, 5rem);
  color: var(--terracotta);
  transform: rotate(-6deg);
  pointer-events: none;
}
.partners__body { display: flex; flex-direction: column; gap: 1.5rem; }
.partners__logos {
  grid-column: 1 / -1;
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid rgba(17, 17, 17, 0.1);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: center;
}
.partners__logo {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.25rem, 2.5vw, 1.75rem);
  color: rgba(17, 17, 17, 0.55);
  letter-spacing: 0.04em;
  text-align: center;
}
@media (max-width: 900px) {
  .partners__inner { grid-template-columns: 1fr; }
  .partners__logos { grid-template-columns: repeat(2, 1fr); }
}

/* ---------- HOME — FINAL CTA ---------- */
.home-cta {
  position: relative;
  padding: clamp(5rem, 12vw, 11rem) var(--pad-x);
  background: var(--terracotta);
  color: var(--cream);
  overflow: hidden;
}
.home-cta__inner {
  max-width: var(--container);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 2rem;
  align-items: flex-start;
}
.home-cta h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 7vw, 6.5rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--cream);
  max-width: 18ch;
}
.home-cta .cta {
  background: var(--teal);
  color: var(--cream);
}
.home-cta .cta:hover {
  background: var(--cream);
  color: var(--teal);
}
/* Brand sign-off — cream logo stamped in the bottom-right corner of
   the terracotta CTA. Reads as "signed by AJW" without competing with
   the personal signature used elsewhere on the site. */
.home-cta__mark {
  position: absolute;
  right: var(--pad-x);
  bottom: clamp(1.75rem, 5vw, 4rem);
  height: clamp(60px, 7.5vw, 90px);
  width: auto;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}
/* On mobile the CTA section is too compact to fit a corner sign-off
   without colliding with the REQUEST A CONVERSATION button (the
   button and the logo end up at the same vertical band). The footer
   logo already provides brand reinforcement on mobile, so the CTA
   sign-off is hidden below 600px. */
@media (max-width: 600px) {
  .home-cta__mark { display: none; }
}

/* ---------- CASE STUDIES PAGE ---------- */
.cs-hero {
  /* Bottom padding matched to both the TOC's padding-top AND its
     margin-top — every vertical gap in the hero footer (lede →
     rule → links → next-section border) is now the same step. */
  padding: clamp(7rem, 12vw, 10rem) var(--pad-x) clamp(1.5rem, 3vw, 2.25rem);
  text-align: center;
}
.cs-hero h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 13vw, 14rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--teal);
}
.cs-hero p {
  margin: 1.5rem auto 0;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.2rem, 2.4vw, 1.75rem);
  color: rgba(17, 17, 17, 0.7);
  max-width: 38ch;
}

.case-study {
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  border-top: 1px solid rgba(17, 17, 17, 0.08);
  /* Anchor scrolling — when a quick-jump link targets this article,
     the scroll position lands with the article's top edge offset
     below the fixed site-nav so the heading isn't hidden behind it. */
  scroll-margin-top: var(--nav-h);
}
.concepts {
  /* Same anchor-scroll offset for the Concepts section. */
  scroll-margin-top: var(--nav-h);
}

/* ---------- CASE STUDIES — QUICK-JUMP TOC ----------
   Uppercase tracked editorial label style — same typographic
   treatment as the home page's "On Operations" eyebrow above the
   thesis section. Six links separated by ·, body sans, small scale,
   uppercase, terracotta-text default → terracotta on hover. */
.case-studies-jump {
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  /* Matched to the margin-top above (the gap between "Proven thinking."
     and the hairline rule). With the cs-hero padding-bottom also set
     to the same value, all three vertical gaps in the hero footer
     (lede → rule → links → next section) read as one consistent
     rhythm — same step between every horizontal line. */
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid rgba(206, 123, 94, 0.25);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  /* Wider gap (was 0.7em) so each case-study label has clear
     breathing room from its neighbours and reads as a discrete
     item rather than as part of a continuous string. */
  gap: 1.15em;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  /* Bumped from 56rem (896px) → 72rem (1152px) so the wider gap
     between items doesn't force "Concepts in Development" — the
     longest label — to wrap onto a second line on desktop. On
     narrower viewports the flex-wrap rule still kicks in naturally
     when the content genuinely doesn't fit. */
  max-width: 72rem;
  margin-left: auto;
  margin-right: auto;
}
.case-studies-jump__link {
  color: var(--terracotta-text);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-hover) ease;
}
.case-studies-jump__link:hover,
.case-studies-jump__link:focus-visible {
  color: var(--terracotta);
}
.case-studies-jump__sep {
  color: rgba(206, 123, 94, 0.9);
  user-select: none;
}

/* ---------- BACK-TO-TOP — floating bottom-left button ----------
   Appears after the user scrolls past the first case study
   (Third Street). Clicking smooth-scrolls back to the top.
   Default state is hidden (opacity 0, pointer-events none) — JS
   adds .is-visible based on an IntersectionObserver tracking the
   first case study's exit. */
.back-to-top {
  position: fixed;
  bottom: clamp(1.5rem, 3vw, 2.5rem);
  left: clamp(1.5rem, 3vw, 2.5rem);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--teal);
  color: var(--cream);
  border: none;
  display: inline-grid;
  place-items: center;
  cursor: pointer;
  z-index: 90;
  /* Hidden by default — fades in/out on scroll past Third Street. */
  opacity: 0;
  pointer-events: none;
  transform: translateY(12px);
  transition:
    opacity 350ms var(--ease-quart),
    transform 350ms var(--ease-quart),
    background 200ms ease;
  box-shadow: 0 4px 16px rgba(17, 17, 17, 0.18);
}
.back-to-top.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.back-to-top:hover {
  background: var(--terracotta);
}
.back-to-top svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
@media (prefers-reduced-motion: reduce) {
  .back-to-top { transition: opacity 200ms ease, background 200ms ease; transform: none; }
}

/* Smooth in-page scrolling for anchor jumps. Doesn't affect the
   regular Lenis-driven scrolling — only fires when the URL hash
   changes (i.e., a TOC link is clicked). */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
/* All case studies sit on the same main cream surface — the dark
   case-study__body-wrap below each gallery handles chapter separation. */
.case-study__inner { max-width: var(--container); margin: 0 auto; }
.case-study__head {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-bottom: clamp(2.5rem, 5vw, 4.5rem);
  max-width: 80rem;
}
/* 2-column variant — used when the case-study head pairs text with a small
   featured media block (e.g. Third Street's Fox 11 clip beside the title). */
.case-study__head--with-media {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(260px, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: end;
  max-width: none;
}
.case-study__head--with-media .case-study__head-text {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 50rem;
}
.case-study__head-media {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-self: end;
}
.case-study__head-video {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #0e1216;
  overflow: hidden;
  border-radius: 4px;
  box-shadow: 0 6px 24px rgba(17, 17, 17, 0.18);
  position: relative;  /* anchors the .video-block__unmute button */
}
.case-study__head-video video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.case-study__head-media__caption {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.55);
}
@media (max-width: 820px) {
  .case-study__head--with-media {
    grid-template-columns: 1fr;
    gap: 1.5rem;
    align-items: stretch;
  }
}
.case-study__eyebrow {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-text);
}
.case-study__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 8vw, 7rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--teal);
}
.case-study__meta {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(17, 17, 17, 0.6);
}
.case-study__lede {
  margin-top: 0.5rem;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.3rem, 2.6vw, 1.9rem);
  color: var(--teal);
  max-width: 36ch;
}
.case-study__media {
  margin: clamp(2rem, 5vw, 4rem) 0;
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: clamp(1rem, 2vw, 2rem);
}
.case-study__media .image-slot:first-child { aspect-ratio: 3 / 2; }
.case-study__media .image-slot:nth-child(2) { aspect-ratio: 4 / 5; align-self: end; }
.case-study__media .image-slot--video { aspect-ratio: 16 / 9; align-self: center; position: relative; }
.image-slot__tag {
  position: absolute;
  top: 0.75rem; left: 0.75rem;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--cream);
  background: rgba(17, 17, 17, 0.55);
  padding: 0.35rem 0.6rem;
  border-radius: 2px;
  backdrop-filter: blur(4px);
  z-index: 2;
}

/* Single-video variant — drops the 2-col grid, headline + video stack full-width */
.case-study__media--single {
  display: flex;
  flex-direction: column;
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
}
.case-study__media--single .case-study__video-head {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.case-study__media--single .image-slot {
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: 4px;
  overflow: hidden;
}
.case-study__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}
.case-study__block { display: flex; flex-direction: column; gap: 1.25rem; }
.case-study__block h3 {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-text);
  padding-bottom: 0.5rem;
  border-bottom: 1px solid rgba(206, 123, 94, 0.3);
  margin-bottom: 0.5rem;
}
.case-study__block p {
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  max-width: 60ch;
}
.case-study__cta {
  margin-top: clamp(2rem, 4vw, 3rem);
}
@media (max-width: 900px) {
  .case-study__media, .case-study__body { grid-template-columns: 1fr; }
}

/* ---------- GALLERY — two-row continuous marquee, natural-aspect tiles ----------
   Two horizontal rows scrolling in opposite directions at different speeds.
   Each tile uses fixed height + auto width so each image's natural aspect
   ratio drives its size — no cropping. Track contents are duplicated by JS
   for a seamless infinite loop. */
.gallery {
  position: relative;
  padding: clamp(2.5rem, 4.8vw, 4rem) 0;
  background: var(--cream-soft);
  width: 100%;
  overflow: hidden;
}
.gallery__viewport {
  width: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Vertical gap between the two marquee rows — tightened from
     clamp(1rem, 2vw, 2rem) (Level 2 reduction). */
  gap: clamp(0.5rem, 1vw, 1rem);
}
.gallery__marquee {
  width: 100%;
  overflow: hidden;
  position: relative;
}
.gallery__marquee-track {
  display: flex;
  align-items: center;
  /* Horizontal gap between images in each scrolling row — tightened
     from clamp(1rem, 2vw, 2rem) (Level 2 reduction). */
  gap: clamp(0.5rem, 1vw, 1rem);
  width: max-content;
  will-change: transform;
  animation: marquee-scroll 90s linear infinite;
}
.gallery__marquee--rtl .gallery__marquee-track {
  /* Reverse direction = right-to-left becomes left-to-right visually.
     Slightly different speed creates the "different paces" feel. */
  animation-direction: reverse;
  animation-duration: 110s;
}
/* Marquee runs continuously regardless of cursor — only the FLIP zoom
   pauses it so the close-animation can return to the source tile cleanly. */
body.gallery-zoom-active .gallery__marquee-track {
  animation-play-state: paused;
}
@keyframes marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .gallery__marquee-track { animation: none; }
}

/* Tile uses height for sizing — each image's natural aspect ratio determines
   its width via width: auto on the inner img/video. */
.gallery__tile {
  position: relative;
  flex: 0 0 auto;
  height: clamp(224px, 30vh, 368px);
  overflow: hidden;
  border-radius: 3px;
  background: var(--cream-soft);
  transition: box-shadow 220ms var(--ease-out);
}
.gallery__marquee--row-2 .gallery__tile {
  height: clamp(192px, 26vh, 320px);
}
.gallery__tile:hover { box-shadow: 0 8px 30px rgba(17, 17, 17, 0.18); }

.gallery__tile .image-slot {
  height: 100%;
  width: auto;
  display: block;
}
.gallery__tile .image-slot > img,
.gallery__tile .image-slot > video {
  height: 100%;
  width: auto;
  display: block;
  transition: transform 480ms ease, filter 320ms ease;
  /* Subtle tone-unification filter — pulls slight contrast and pulls
     saturation back ~3%. Imperceptible per image, but creates a more
     consistent feel across mixed sources (AI/screenshot/photo). */
  filter: contrast(1.03) saturate(0.97);
  /* No object-fit: image's natural aspect drives the width via height-based
     scaling. */
}
.gallery__tile:hover .image-slot > img,
.gallery__tile:hover .image-slot > video {
  transform: scale(1.05);
  filter: contrast(1.04) saturate(1);
}

/* Floating quote tile — pure text + AW signature underneath. No box. */
.gallery__tile--quote {
  width: clamp(240px, 26vw, 380px);
  aspect-ratio: auto;
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow: visible;
  padding: 0 clamp(0.4rem, 0.8vw, 1rem);
  display: flex;
  flex-direction: column;
  gap: clamp(0.75rem, 1.2vw, 1.25rem);
  cursor: default;
  align-self: center;
  justify-content: center;
  height: auto;
}
.gallery__tile--quote:hover { box-shadow: none; }
.gallery__tile--quote blockquote {
  font-family: var(--font-display);
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.1rem, 1.7vw, 1.55rem);
  line-height: 1.2;
  color: var(--teal);
  letter-spacing: -0.005em;
  text-wrap: balance;
}
.gallery__tile--quote .signature-mark {
  width: clamp(72px, 8vw, 110px);
  height: auto;
  display: block;
  color: var(--terracotta);
}
.gallery__tile--quote .signature-mark img {
  width: 100%;
  height: auto;
  display: block;
}

.gallery__tile--video { background: var(--black); }

/* Mobile / touch: native horizontal scroll per row, no scroll-jack pin */
@media (max-width: 900px), (hover: none) {
  .gallery__viewport { overflow: visible; }
  .gallery__row {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    transform: none !important;
    width: 100%;
    padding-bottom: 0.5rem;
  }
  .gallery__row::-webkit-scrollbar { display: none; }
  .gallery__tile { scroll-snap-align: start; }
  .gallery__tile--sm { height: clamp(100px, 14vh, 140px); }
  .gallery__tile--md { height: clamp(140px, 20vh, 200px); }
  .gallery__tile--lg { height: clamp(180px, 26vh, 260px); }
}

/* ---------- DARK BODY WRAPPER — case-study body in dark mode ---------- */
.case-study__body-wrap {
  background: #181D22;
  color: var(--cream);
  padding: clamp(3.5rem, 7vw, 6rem) var(--pad-x);
}
.case-study__body-wrap .case-study__inner {
  max-width: var(--container);
  margin: 0 auto;
}
.case-study__body-wrap .case-study__block h3 { color: var(--terracotta); border-bottom-color: rgba(206, 123, 94, 0.4); }
.case-study__body-wrap .case-study__block p { color: rgba(242, 237, 228, 0.86); }
.case-study__body-wrap .case-study__cta {
  background: var(--cream);
  color: var(--teal);
}
.case-study__body-wrap .case-study__cta:hover {
  background: var(--terracotta);
  color: var(--cream);
}

/* ---------- ZOOM OVERLAY — FLIP animation, media grows from tile ---------- */
.gallery-zoom {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: rgba(17, 17, 17, 0.92);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 360ms cubic-bezier(0.32, 0.72, 0, 1);
}
.gallery-zoom.is-open {
  opacity: 1;
  pointer-events: auto;
}
.gallery-zoom__media {
  display: block;
  border-radius: 3px;
  box-shadow: 0 30px 100px rgba(0, 0, 0, 0.5);
  /* position + transform driven by JS */
}
.gallery-zoom__close {
  position: fixed;
  top: clamp(1rem, 2vw, 2rem);
  right: clamp(1rem, 2vw, 2rem);
  z-index: 302;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(242, 237, 228, 0.12);
  color: var(--cream);
  display: grid;
  place-items: center;
  border: 0;
  cursor: pointer;
  transition: background 200ms ease, opacity 240ms ease;
  opacity: 0;
  pointer-events: none;
}
.gallery-zoom.is-open .gallery-zoom__close {
  opacity: 1;
  pointer-events: auto;
  transition-delay: 220ms; /* fades in after the FLIP settles */
}
.gallery-zoom__close:hover { background: var(--terracotta); }
.gallery-zoom__close svg { width: 18px; height: 18px; }

/* Concepts in development — fanned card layout */
.concepts {
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  background: var(--teal);
  color: var(--cream);
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
/* Two stacked atmospheric image layers behind the card grid.
   JS swaps background-image on the inactive layer and cross-fades. */
.concepts__bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0;
  transition: opacity 600ms ease;
  z-index: 0;
  pointer-events: none;
}
.concepts__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(31, 91, 130, 0.45);
  pointer-events: none;
}
/* Make sure the section's own foreground content sits above the bg layers. */
.concepts__head,
.concepts__grid { position: relative; z-index: 1; }
.concepts__head {
  text-align: center;
  margin-bottom: clamp(3rem, 6vw, 5rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-items: center;
}
.concepts__head h2 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.5rem, 8vw, 7rem);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--cream);
}
.concepts__head .label { color: rgba(242, 237, 228, 0.7); }
.concepts__head p {
  font-family: var(--font-display);
  font-style: italic;
  /* Desktop scale: cumulative +20% then +50% over the original
     clamp(0.72rem, 1.4vw, 1.05rem). Lands at a confident
     editorial pull-quote tier under "Concepts in Development".
     Mobile gets a -20% override below — the desktop's hand-set
     <br> breaks need a slightly larger size to read at the wider
     viewport, but mobile (where text wraps naturally without the
     <br>s) reads better at a quieter scale. */
  font-size: clamp(1.296rem, 2.52vw, 1.89rem);
  color: rgba(242, 237, 228, 0.8);
  /* Hard-disable soft wrapping. Only <br> tags create line breaks. */
  white-space: nowrap;
}
.concepts__grid {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.25rem, 2.5vw, 2rem);
}
.concept-card {
  background: rgba(31, 91, 130, 0.35);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(242, 237, 228, 0.18);
  border-radius: 6px;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  transition: opacity 1200ms ease, transform 200ms ease, border-color 200ms ease, background 200ms ease;
  min-height: 240px;
  position: relative;
  z-index: 1;
}
.concept-card:hover {
  transform: translateY(-2px);
  background: rgba(31, 91, 130, 0.25);
  border-color: rgba(242, 237, 228, 0.32);
}
/* Pure focus mode: while any card is hovered, the others fade fully out so
   the hovered card and the background image are the only things visible.
   pointer-events: none on faded cards prevents flicker; pointer-events: auto
   on the hovered card keeps its mouseleave reliable.
   !important is required because the GSAP reveal-stagger animation writes
   `opacity: 1` as an inline style on every card, which would otherwise win
   over a plain class-based rule. */
.concepts.is-hovering .concept-card {
  opacity: 0 !important;
  pointer-events: none;
}
.concepts.is-hovering .concept-card:hover {
  opacity: 1 !important;
  pointer-events: auto;
}
/* Fallback for browsers without backdrop-filter support */
@supports not ((backdrop-filter: blur(8px)) or (-webkit-backdrop-filter: blur(8px))) {
  .concept-card {
    background: rgba(31, 91, 130, 0.7);
    border: 1px solid rgba(242, 237, 228, 0.15);
  }
}
@media (prefers-reduced-motion: reduce) {
  .concepts__bg { transition: none; }
  .concept-card { transition: border-color 200ms ease; }
  .concept-card:hover { transform: none; }
}
.concept-card__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  line-height: 1.05;
  color: var(--cream);
}
.concept-card__desc {
  font-family: var(--font-body);
  font-size: 0.92rem;
  line-height: 1.55;
  color: rgba(242, 237, 228, 0.78);
}
.concept-card__status {
  margin-top: auto;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta);
}
@media (max-width: 1024px) { .concepts__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 540px) { .concepts__grid { grid-template-columns: 1fr; } }

/* ---------- APPROACH PAGE ---------- */
.approach-hero {
  padding: clamp(7rem, 12vw, 10rem) var(--pad-x) clamp(3rem, 6vw, 5rem);
  text-align: center;
}
.approach-hero h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 13vw, 14rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--teal);
}
.approach-hero p {
  margin: 1.5rem auto 0;
  font-family: var(--font-display);
  font-style: italic;
  font-size: clamp(1.2rem, 2.4vw, 1.75rem);
  color: rgba(17, 17, 17, 0.7);
}

.approach-step {
  padding: clamp(5rem, 10vw, 9rem) var(--pad-x);
  border-top: 1px solid rgba(17, 17, 17, 0.08);
}
.approach-step:nth-of-type(even) { background: var(--cream-soft); }
.approach-step__inner {
  max-width: var(--container);
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}
.approach-step__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 10vw, 9rem);
  line-height: 0.9;
  letter-spacing: -0.03em;
  color: var(--teal);
}
.approach-step__meta {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-text);
  margin-bottom: 0.75rem;
}
.approach-step__body p {
  font-family: var(--font-body);
  font-size: 1.05rem;
  line-height: 1.7;
  max-width: 60ch;
  color: var(--black);
}
@media (max-width: 900px) { .approach-step__inner { grid-template-columns: 1fr; } }

.approach-quote {
  padding: clamp(5rem, 12vw, 10rem) var(--pad-x);
  text-align: center;
  background: var(--teal);
  color: var(--cream);
  border-top: 1px solid rgba(17, 17, 17, 0.08);
}
.approach-quote blockquote {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.6rem, 4vw, 3rem);
  line-height: 1.2;
  color: var(--cream);
  max-width: 36ch;
  margin: 0 auto;
}
.approach-quote .signature-mark {
  margin-top: clamp(1.5rem, 3vw, 2rem);
}

/* ---------- ABOUT PAGE ---------- */
/* Hero section is now just the page eyebrow — the previous large
   "Alex Wall." headline is removed. Padding tightened so the
   eyebrow sits closer to the marquee below. */
.about-hero {
  padding: clamp(5rem, 9vw, 7rem) var(--pad-x) clamp(1.5rem, 3vw, 2.5rem);
  text-align: center;
}

/* Portrait — moved out of the hero into the body's two-column
   layout. About half the previous size (was max-width 720px,
   now 18rem ≈ 288px). The caption beneath identifies the founder
   in place of the removed display headline. */
.about-portrait {
  width: 100%;
  max-width: 18rem;
  margin: 0;
}
.about-portrait .image-slot {
  aspect-ratio: 4 / 5;
  border-radius: 4px;
}
.about-portrait-caption {
  display: block;
  margin-top: 0.85rem;
}
.about-portrait-caption__name {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  /* Bumped 1.05rem → 1.25rem (~+19%) — name reads with more
     presence next to the portrait without dominating it. */
  font-size: 1.25rem;
  line-height: 1.2;
  letter-spacing: -0.005em;
  color: var(--teal-deep);
}
.about-portrait-caption__role {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--terracotta-text);
}

.about-body {
  /* Top padding tightened so the marquee meets the hero close, then
     normal vertical rhythm resumes inside .about-body__inner. */
  padding: clamp(2rem, 4vw, 3.5rem) 0 clamp(5rem, 10vw, 8rem);
}
/* Two-column composition wrapping the portrait + caption (left) and
   the editorial body content (right). The grid sits inside .about-body
   below the marquee. Layout widened (was 64rem → now 74rem) so each
   line of body text gets more horizontal room and the section reads
   shorter overall. */
.about-body__layout {
  max-width: 74rem;
  margin: 0 auto;
  padding: 0 var(--pad-x);
  display: grid;
  /* Portrait column = fixed ~18rem; body column = remaining space. */
  grid-template-columns: 18rem 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

/* Body content column — vertical flex stack for the editorial
   composition (eyebrow → declaration → rule → list → diagnosis →
   application). Width is now controlled by the grid column rather
   than max-width. */
.about-body__inner {
  display: flex;
  flex-direction: column;
  /* Tighter base gap; specific elements override below to give each
     transition its own deliberate amount of vertical space. */
  gap: clamp(1rem, 2vw, 1.5rem);
}

/* Mobile — collapse to single column with portrait above body. */
@media (max-width: 760px) {
  .about-body__layout {
    grid-template-columns: 1fr;
    gap: clamp(2rem, 5vw, 3rem);
  }
  .about-portrait {
    /* Centred on small screens since it's no longer beside the body. */
    max-width: 16rem;
    margin: 0 auto;
  }
  .about-portrait-caption {
    text-align: center;
  }
}

/* ---------- ABOUT — DRIFTING MARQUEE ----------
   Continuous right-to-left scroll of place names with · separators.
   The track holds two identical sequences; animation translates
   from 0 → -50% so set 1 slides off and set 2 (identical) replaces
   it seamlessly. Cream backdrop, terracotta serif glyphs. */
.about-marquee {
  width: 100%;
  overflow: hidden;
  margin-bottom: clamp(3rem, 6vw, 5rem);
  /* Vertical padding sized so the marquee reads as supporting
     typographic motion, not a billboard. */
  padding: clamp(0.75rem, 2vw, 1.5rem) 0;
  /* Soft horizontal mask — place names fade in/out at the edges
     instead of cutting hard. Wider fade region so the gesture
     reads as gentle rather than abrupt. */
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent 0%,
    black 10%,
    black 90%,
    transparent 100%
  );
  mask-image: linear-gradient(
    90deg,
    transparent 0%,
    black 10%,
    black 90%,
    transparent 100%
  );
}
.about-marquee__track {
  display: inline-flex;
  align-items: center;
  gap: clamp(1.2rem, 2.5vw, 2.2rem);
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 400;
  /* Scaled down significantly from 3-6rem — at 6rem the marquee was
     a billboard. 2.4-4.2rem reads as supporting typographic motion
     against the rest of the editorial block. */
  font-size: clamp(2.4rem, 4.2vw, 4.2rem);
  line-height: 1;
  letter-spacing: -0.012em;
  text-transform: uppercase;
  /* Slightly muted terracotta so it sits as a layer rather than
     punching through the page. */
  color: rgba(206, 123, 94, 0.85);
  animation: about-marquee-scroll 50s linear infinite;
  will-change: transform;
}
.about-marquee__item,
.about-marquee__sep {
  flex: 0 0 auto;
}
.about-marquee__sep {
  /* Smaller, lighter, sits as a metering mark between glyphs. */
  font-size: 0.55em;
  opacity: 0.5;
  transform: translateY(-0.2em);
}
@keyframes about-marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .about-marquee__track { animation: none; }
}

/* ---------- ABOUT — EDITORIAL TYPOGRAPHIC BODY ----------
   Composition: eyebrow → declaration → hairline rule → lead
   sentence + bulleted list → italic application line. Reads as a
   structured editorial section rather than a list of paragraphs. */

/* Eyebrow — small uppercase tracked label that anchors the body
   block as a designed section, matching the eyebrow style used
   throughout the site. */
.about-body__eyebrow {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--terracotta-text);
  display: block;
  margin: 0 0 clamp(0.25rem, 0.5vw, 0.5rem);
}

/* Opening declaration — the thesis. Slightly smaller than before
   (clamp 1.6-2.4rem vs old 1.85-3rem) so it sits in proportion with
   the body content beneath rather than dominating. */
.about-body .about-body__declaration {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: -0.012em;
  color: var(--teal-deep);
  /* Widened from 28ch → 36ch so the thesis fits in fewer lines. */
  max-width: 36ch;
  margin: 0;
}

/* Hairline rule — short terracotta line, low opacity. Acts as a
   structural seam between thesis and elaboration. The width is
   intentionally short so it reads as a typographic mark, not a
   page-spanning divider. */
.about-body__rule {
  width: 56px;
  height: 1px;
  background: var(--terracotta);
  border: 0;
  opacity: 0.55;
  margin: clamp(1rem, 2vw, 1.5rem) 0 clamp(0.5rem, 1vw, 0.75rem);
}

/* Body paragraph — generic medium-scale display-serif paragraph.
   Used for the diagnosis paragraph that sits between the list and
   the italic application line. The small margin-top creates an
   intentional breathing space after the list, marking a transition
   to a new "thought" rather than another list item. */
.about-body .about-body__paragraph {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.15rem, 1.6vw, 1.4rem);
  line-height: 1.55;
  color: rgba(17, 17, 17, 0.85);
  /* Widened from 54ch → 64ch — fewer wrapped lines per paragraph. */
  max-width: 64ch;
  margin: clamp(0.75rem, 1.5vw, 1.25rem) 0 0;
}

/* Three-item list — replaces the previous indented prose
   fragments. Each item gets a terracotta em-dash marker that ties
   visually back to the application line's terracotta italic. The
   indent is now functional (hanging em-dash) rather than just
   pushing the text right. */
.about-body__list {
  list-style: none;
  margin: clamp(0.4rem, 1vw, 0.75rem) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(0.4rem, 0.8vw, 0.6rem);
}
.about-body__list li {
  position: relative;
  padding-left: 1.6em;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.15rem, 1.6vw, 1.4rem);
  line-height: 1.5;
  color: rgba(17, 17, 17, 0.85);
  /* Widened from 52ch → 62ch so longer items (the fourth one
     especially) wrap less. */
  max-width: 62ch;
}
.about-body__list li::before {
  content: '—';
  position: absolute;
  left: 0;
  top: 0;
  color: var(--terracotta);
  font-weight: 500;
}

/* Application line — italic terracotta. Only colour shift in the
   block. Extra margin-top above to mark the pivot from elaboration
   to conclusion. font-weight 400 (down from 500) so the italic is
   the only emphasis, not double-emphasised. */
.about-body .about-body__application {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.3rem, 2.2vw, 1.7rem);
  line-height: 1.4;
  letter-spacing: -0.005em;
  color: var(--terracotta);
  /* Widened from 46ch → 58ch — italic body fits in fewer lines. */
  max-width: 58ch;
  margin: clamp(1.25rem, 2.5vw, 2rem) 0 0;
}
/* Adjacent application paragraphs (the two-paragraph application
   block) sit closer together — a single thought broken across two
   stanzas. The first one keeps the larger top margin to mark its
   transition from the diagnosis paragraph above; the second only
   needs paragraph-level breathing space below the first. */
.about-body .about-body__application + .about-body__application {
  margin-top: clamp(0.6rem, 1.2vw, 1rem);
}

/* Mobile — list indent reduced for narrow viewports. */
@media (max-width: 600px) {
  .about-body__list li {
    padding-left: 1.2em;
  }
}

.about-close {
  padding: clamp(5rem, 12vw, 10rem) var(--pad-x);
  text-align: center;
  background: var(--cream-soft);
  border-top: 1px solid rgba(17, 17, 17, 0.06);
}
.about-close blockquote {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.5rem, 3.5vw, 2.6rem);
  line-height: 1.25;
  color: var(--teal);
  max-width: 52ch;
  margin: 0 auto;
  text-wrap: balance;
}
.about-close .signature-mark {
  margin-top: clamp(1.5rem, 3vw, 2rem);
}
.about-close .cta { margin-top: 2.5rem; }

/* ---------- CONTACT PAGE ---------- */
.contact-hero {
  padding: clamp(7rem, 12vw, 10rem) var(--pad-x) clamp(2.5rem, 5vw, 4rem);
}
.contact-hero__inner {
  max-width: 64rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: flex-start;
}
.contact-hero h1 {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 12vw, 12rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--teal);
}

.contact-form-wrap {
  padding: 0 var(--pad-x) clamp(4rem, 8vw, 7rem);
}
.contact-form {
  max-width: 56rem;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}
.contact-form__field { display: flex; flex-direction: column; gap: 0.5rem; }
.contact-form__field--full { grid-column: 1 / -1; }
.contact-form__field label {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--terracotta-text);
}
.contact-form__field input,
.contact-form__field select,
.contact-form__field textarea {
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(17, 17, 17, 0.18);
  padding: 0.65rem 0.25rem;
  font-family: var(--font-body);
  font-size: 1rem;
  color: var(--black);
  border-radius: 0;
  transition: border-color var(--dur-hover) ease;
}
.contact-form__field input:focus,
.contact-form__field select:focus,
.contact-form__field textarea:focus {
  outline: none;
  border-bottom-color: var(--terracotta);
}
.contact-form__field textarea { resize: vertical; min-height: 120px; }
.contact-form__submit { grid-column: 1 / -1; margin-top: 1rem; }
.contact-direct {
  margin-top: clamp(2rem, 4vw, 3rem);
  text-align: center;
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: rgba(17, 17, 17, 0.7);
}
@media (max-width: 720px) { .contact-form { grid-template-columns: 1fr; } }

/* ---------- VIDEO BLOCK (Third Street case study) ---------- */
.video-block { position: relative; }
.video-block .image-slot { aspect-ratio: 16 / 9; border-radius: 4px; overflow: hidden; }
.video-block__head {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1rem;
}
.video-block__unmute {
  position: absolute;
  bottom: 1rem; right: 1rem;
  width: 44px; height: 44px;
  background: rgba(17, 17, 17, 0.65);
  color: var(--cream);
  border-radius: 999px;
  display: grid; place-items: center;
  z-index: 2;
}
.video-block__unmute:hover { background: var(--terracotta); }
.video-block__unmute svg { width: 20px; height: 20px; fill: currentColor; }
/* Icon swap driven by aria-pressed: button starts pressed=false (video
   muted) → show .icon-muted (speaker with diagonal cut). After click,
   pressed=true (video unmuted) → show .icon-unmuted (speaker w/ waves). */
.video-block__unmute[aria-pressed="false"] .icon-unmuted,
.video-block__unmute[aria-pressed="true"] .icon-muted { display: none; }
.video-block__unmute[aria-pressed="true"] { background: var(--terracotta); }

/* ---------- 11. MOBILE REFINEMENTS ---------- */
@media (max-width: 600px) {
  .home-hero__title { font-size: clamp(3rem, 17vw, 6rem); letter-spacing: -0.03em; }

  /* Phrase cycler ("operations", etc.) +50% on mobile so the phrase
     reads as a confident counterpoint to HOSPITALITY above rather
     than disappearing into the type stack. Was clamp(1.5rem, 6.4vw,
     6.8rem) → 9.6vw / 4rem max bumps the rendered size from ~25px
     to ~37px on a 390px-wide phone. */
  .home-hero__phrase-cycler { font-size: clamp(2.25rem, 9.6vw, 4rem); }

  /* Hero video initial size on mobile — bumped from 20vw × 25vw
     (~80px × 100px on a 390px phone, postage-stamp scale) to
     40vw × 50vw (~155px × 195px), a substantial 4:5 portrait that
     reads as a real hero element from the moment the page lands.
     Aspect 4:5 (0.8) preserved so the JS Phase A proportional
     growth math (PROPORTIONAL_ASPECT = 20/25 = 0.8) still tracks
     correctly — width target = height target × 0.8 holds. */
  .home-hero__media {
    width: 40vw;
    height: 50vw;
  }

  /* Hero byline + scroll hint — POSITIONS SWAPPED on mobile.
     The hero video grows during the pin; on shorter viewports
     (or wider phones in landscape) the expanding video can reach
     the byline's old position and visually clip it. Putting the
     byline at the very bottom (where the scroll hint used to be)
     keeps it permanently below the video's expansion path, no
     matter the viewport aspect ratio. The scroll hint moves up
     to where the byline used to be — when the video reaches that
     band, the user is already scrolling so the prompt has done
     its job. */
  .home-hero__sub--bottom {
    font-size: 0.69rem;
    bottom: clamp(2rem, 4vh, 3.5rem);
  }

  /* Scroll hint sits above the byline now, more faded on mobile —
     subtle prompt rather than confident affordance, since the
     typographic stack and video already imply scrollability. */
  .home-hero__scroll-hint {
    color: rgba(31, 91, 130, 0.4);
    bottom: clamp(8rem, 17vh, 12rem);
  }
  .home-hero__scroll-hint-arrow { opacity: 0.55; }

  /* Thesis statement — bumped +30% on top of the previous +20%
     pass. Lands at ~19px on a 390px phone, comfortable body-copy
     scale that gives the editorial passage real presence without
     the "billboard" weight of the previous default. */
  .thesis__statement { font-size: clamp(1.2rem, 4.91vw, 2.18rem); line-height: 1.55; }

  /* Shared "small caps eyebrow/caption" mobile scale. All four home
     page section openers (Career rail, Thesis, Modes, Work-preview)
     plus the thesis closing caption use the same 0.518rem mobile
     size so the editorial metadata tier reads consistently across
     the page. The shared 0.74rem desktop tier elsewhere (footer
     headings, case-study eyebrows, approach meta) keeps its
     desktop scale — those live in different contexts and each
     section retains its own weight there. */
  .thesis__eyebrow,
  .thesis__caption,
  .career-rail .label,
  .modes__head .label,
  .work-preview__text .label {
    font-size: 0.518rem;
  }

  /* Shared display heading scale for all home page section openers
     on mobile. Career rail "The work.", Work-preview "Case studies."
     (both .display--lg) and Modes "How AJW works." all land at the
     same clamp range. Was scoped only to .career-rail; now generalised
     so every opener heading on the home page reads at the same
     confident weight. */
  .display--lg { font-size: clamp(3.4rem, 9.75vw, 5.4rem); }

  /* Career rail item spacing — tighten the gap between each image
     and its caption (so each venue reads as a single unit), and
     expand the gap between one item's caption and the next item's
     image (so venues feel cleanly separated). */
  .career-rail__item { gap: 0.3rem; }
  .career-rail__caption {
    margin-top: 0.4rem;
    /* Re-pad the caption now that the grid extends past the section
       padding (see below) — keeps text inset from screen edges
       while images go full-bleed. */
    padding-left: var(--pad-x);
    padding-right: var(--pad-x);
  }
  /* Career rail grid extends edge-to-edge on mobile via negative
     margins matching the section's --pad-x. Images fill the full
     viewport width, captions stay padded via the rule above. */
  .career-rail__grid {
    gap: 4rem 0;
    margin-left: calc(-1 * var(--pad-x));
    margin-right: calc(-1 * var(--pad-x));
  }

  /* Caption text reductions on mobile — venue name and role line
     -20%, location/year -40%. Pulls the metadata down to a quieter
     scale that lets each image breathe as the primary element. */
  .career-rail__venue { font-size: 1.04rem; }
  .career-rail__what { font-size: 0.749rem; }
  .career-rail__where { font-size: 0.475rem; }

  /* Career rail entry animation on mobile — handled via inline JS
     in initCareerRailMobileReveal() (scripts.js). The previous
     CSS-only approach with .is-revealed + transitions ran into a
     cascade issue we couldn't pin down — even with !important on
     the revealed-state rule, the computed values stayed at the
     unrevealed state. Driving the animation directly from JS
     bypasses the CSS class system entirely.
     The CSS just sets a default initial state so the items start
     hidden before JS picks them up. JS then animates them in. */
  .career-rail__item[data-reveal-image].cr-mobile-init {
    opacity: 0;
    transform: translateY(80px) scale(1.04);
    transition: opacity 1200ms cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 1200ms cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  /* Unified mobile aspect ratio for career rail venues 01–07 —
     all use a 3:2 landscape crop matching how Hyde Beach actually
     renders (its natural image is landscape ~1.5 aspect; the
     desktop slot was 4:5 portrait but with height:auto on the img
     the visible photograph rendered at its natural landscape
     proportion, leaving slot whitespace). Setting all seven slots
     to 3:2 with object-fit: cover gives a consistent landscape
     tile across the rail without empty space.

     Item 08 is the AJW Fox 11 News video; aspect-ratio: auto
     keeps its natural framing so the broadcast composition isn't
     cropped. */
  .career-rail__item--01 .image-slot,
  .career-rail__item--02 .image-slot,
  .career-rail__item--03 .image-slot,
  .career-rail__item--04 .image-slot,
  .career-rail__item--05 .image-slot,
  .career-rail__item--06 .image-slot,
  .career-rail__item--07 .image-slot {
    aspect-ratio: 3 / 2;
    overflow: hidden;
  }
  .career-rail__item--01 .image-slot img,
  .career-rail__item--02 .image-slot img,
  .career-rail__item--03 .image-slot img,
  .career-rail__item--04 .image-slot img,
  .career-rail__item--05 .image-slot img,
  .career-rail__item--06 .image-slot img,
  .career-rail__item--07 .image-slot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
  }
  .career-rail__item--08 .image-slot {
    aspect-ratio: auto;
  }

  /* Concepts intro lede ("Each concept is developed...") — on
     desktop this paragraph uses white-space: nowrap with hand-set
     <br> tags for editorial line breaks, but at the larger mobile
     font-size the longest segment (~50 chars) overflows narrow
     phones (e.g. iPhone SE at 375px). On mobile we let the text
     wrap naturally, hide the desktop <br> breaks, AND drop the
     font size -20% from the desktop scale so the paragraph reads
     comfortably at phone widths. Desktop stays at its larger
     hand-set scale (set in the base .concepts__head p rule). */
  .concepts__head p {
    white-space: normal;
    font-size: clamp(1.0368rem, 2.016vw, 1.512rem);
  }
  .concepts__head p br {
    display: none;
  }

  /* Modes section ("Three ways in / How AJW works.") on mobile —
     center-aligned to match career-rail and work-preview opener
     heads. Heading sized to match the shared .display--lg mobile
     range so all three home page section openers feel like the
     same composition. */
  .modes__head {
    align-items: center;
    text-align: center;
  }
  .modes__head h2 {
    font-size: clamp(3.4rem, 9.75vw, 5.4rem);
    max-width: none;
  }

  /* Work preview ("The Work / Case studies.") — same centered
     treatment on mobile so the third opener head matches the
     centered career-rail and modes heads. CTA inside the column
     stays auto-sized rather than full-width. */
  .work-preview__text {
    align-items: center;
    text-align: center;
  }

  /* Mode card body text -20% on mobile so the three card stack
     reads as quieter editorial detail instead of competing slabs.
     Headings stay at their existing scale so each mode still has
     a confident title. */
  .mode p { font-size: 0.784rem; line-height: 1.65; }

  /* "See the work →" link right-aligned in each mode card on
     mobile — breaks up the vertical stack of three cards visually,
     creating a zigzag rhythm where the eye can pick up each
     successive CTA without scanning down a single column edge. */
  .mode .link {
    align-self: flex-end;
    text-align: right;
  }

  /* Work-preview card descriptors ("District Strategy · Santa Monica",
     "Turnaround · Santa Monica") -25% on mobile so the metadata
     line below each venue name reads as a quieter sub-tier rather
     than competing with the title. The venue name itself stays at
     its existing scale. */
  .work-preview__card-desc { font-size: 0.561rem; }

  /* Work-preview lede ("Real work. Real execution. Proven thinking.
     From individual venues to district-scale impact.") matches the
     mode card body size on mobile so descriptive copy across the
     home page reads at one consistent body-tier scale. */
  .work-preview__text .body {
    font-size: 0.784rem;
    line-height: 1.65;
  }

  /* Override the desktop accordion's heavy dark overlay on
     INACTIVE cards. On desktop, inactive cards are narrow strips
     and use rgba(17,17,17, 0.62–0.88) gradient to recede them
     visually. On mobile every card is a full-width tile, so all
     cards get the same lighter active-style overlay (soft bottom
     gradient for meta-text readability, transparent image area).
     Without this fix, only Third Street (which has .is-active
     baked into the markup as the desktop default) renders with a
     bright image — the other 4 cards were almost-black under the
     heavier overlay regardless of the JS brightness filter. */
  .work-preview__card::after {
    background: linear-gradient(
      to top,
      rgba(17, 17, 17, 0.55) 0%,
      rgba(17, 17, 17, 0.22) 28%,
      transparent 58%
    );
  }

  .home-hero__top { display: none; }

  /* ---------- CASE STUDIES PAGE — MOBILE ---------- */

  /* Page hero "Case Studies." — bumped up on mobile so it lands
     as the confident editorial anchor for the page. Was clamp(3rem,
     13vw, 14rem) → ~51px on a 393px phone; now scales up to ~75px
     while keeping the desktop max cap intact. */
  .cs-hero h1 { font-size: clamp(4.5rem, 19vw, 14rem); }

  /* Quick-jump TOC — smaller text + tighter gaps so all six labels
     fit cleanly in 2 lines on a phone instead of awkward wrapping.
     -25% font (0.72rem → 0.54rem) and gap halved from 1.15em → 0.6em. */
  .case-studies-jump {
    font-size: 0.54rem;
    gap: 0.6em 0.5em;
  }

  /* Per-case-study heading group — applies to every <article class="case-study">
     so all five sections (Third Street, Casa Martin, Melrose Place,
     Cause & Cure, INDSTRY) inherit the same mobile scale relationship. */

  /* Eyebrow ("№ 01 — The North End", etc.) -20% on mobile:
     0.74rem → 0.592rem. Reads as a quieter editorial label. */
  .case-study__eyebrow { font-size: 0.592rem; }

  /* Case study title ("Third Street Promenade.", etc.) +25% on
     mobile so each title anchors its section confidently. Was
     clamp(2.5rem, 8vw, 7rem) → 40px floor on a phone; now floors
     at 50px (3.125rem). */
  .case-study__title { font-size: clamp(3.125rem, 10vw, 7rem); }

  /* Meta line ("Santa Monica · 2025 · Ongoing", etc.) -20% on mobile:
     0.78rem → 0.624rem. Sub-tier metadata under the title. */
  .case-study__meta { font-size: 0.624rem; }

  /* Lede ("A district-scale hospitality strategy...", etc.) -20%
     on mobile. Was clamp(1.3rem, 2.6vw, 1.9rem); now scales to a
     quieter pull-quote at ~17px instead of ~21px. */
  .case-study__lede { font-size: clamp(1.04rem, 2.08vw, 1.52rem); }

  /* Body copy in each case-study block (under "The Opportunity",
     "The Problem", etc.) -20% on mobile. Was 1rem → 0.8rem. */
  .case-study__block p { font-size: 0.8rem; line-height: 1.7; }

  /* Video caption (Third Street's Fox 11 segment) — split the
     "Fox 11 News · Featured" left and "Click to unmute" right so
     the user immediately sees the audio control on the same line.
     The HTML markup for the two halves is wrapped in spans so
     flex-justify can push them to opposite ends of the caption row. */
  .case-study__head-media__caption {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.75rem;
  }

  /* "Discuss a similar engagement" CTA — -20% smaller AND centred
     on mobile. The base .cta uses em-based padding so reducing the
     font-size shrinks the whole pill button proportionally. Switch
     from inline-flex to block-level flex with auto horizontal
     margins + fit-content width so the button sits dead-centre in
     its column. Applies to all five case-study sections via the
     shared .case-study__cta class. */
  .case-study__cta {
    font-size: 0.624rem;
    display: flex;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
  }

  /* ---------- CONCEPTS IN DEVELOPMENT — MOBILE LAYOUT ----------
     On desktop, hovering a concept card swaps the section background
     to that concept's image. On mobile there's no hover, so we put
     the image inside each card as a scroll-driven backdrop:
       - Card becomes a 4:5 portrait tile with full-bleed bg image
       - Name anchors top-left (+30% scale, hero of the composition)
       - Description anchors bottom-right (block position, text-aligned
         left within the block for readability)
       - Top + bottom gradient overlays guarantee text contrast
         regardless of the image's natural brightness
       - Image opacity is scroll-driven via JS (initConceptCardsMobile-
         Spotlight) — 0 below viewport, peaks at 0.65 when card is
         centred, fades back to 0 as it exits the top */
  .concept-card {
    aspect-ratio: 4 / 5;
    min-height: 0;
    padding: 0;
    display: block;
    overflow: hidden;
    /* Transparent card background so it blends into the section's
       teal backdrop when the image isn't lit. Earlier rgba teal
       made the card read as a distinct dark slab even with no
       image — the user reported a "dark → light → dark" flicker
       between cards that was actually the card-bg-vs-image contrast.
       Letting the card sit on the section's own teal eliminates
       that disconnect. */
    background: transparent;
    /* CSS vars driven by JS — image URL and current spotlight
       opacity. The same opacity drives both the image AND the
       gradient overlays so when there's no image to read, there
       are no dark bands sitting on top of nothing. */
    --concept-bg: none;
    --concept-bg-opacity: 0;
  }
  /* Image layer — full bleed beneath text + overlays. */
  .concept-card::before {
    content: '';
    position: absolute;
    inset: 0;
    background-image: var(--concept-bg);
    background-size: cover;
    background-position: center;
    opacity: var(--concept-bg-opacity);
    transition: opacity 80ms linear;
    border-radius: inherit;
    z-index: 0;
    pointer-events: none;
  }
  /* Stacked gradient overlay — dark band at top (anchors the name)
     plus a stronger dark band at bottom (anchors the description).
     Overlay opacity tracks the image opacity so the dark bands only
     exist when there's an image needing them; otherwise the card
     reads as plain teal section bg. */
  .concept-card::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
      linear-gradient(to bottom,
        rgba(17, 17, 17, 0.45) 0%,
        rgba(17, 17, 17, 0.18) 22%,
        transparent 40%),
      linear-gradient(to top,
        rgba(17, 17, 17, 0.6) 0%,
        rgba(17, 17, 17, 0.28) 30%,
        transparent 55%);
    opacity: var(--concept-bg-opacity);
    transition: opacity 80ms linear;
    border-radius: inherit;
    z-index: 1;
    pointer-events: none;
  }
  .concept-card__name {
    position: absolute;
    top: 1.25rem;
    left: 1.25rem;
    right: 1.25rem;
    z-index: 2;
    /* +50% bump on top of the previous +30%. Original desktop was
       clamp(1.35rem, 2.2vw, 1.75rem); now scaled up to ~42px floor
       on phones so the venue name reads as the confident headline
       of the diagonal composition. */
    font-size: clamp(2.6325rem, 4.29vw, 3.4125rem);
    line-height: 1;
  }
  .concept-card__desc {
    position: absolute;
    bottom: 1.25rem;
    right: 1.25rem;
    /* Body block pinned bottom-right with text right-aligned —
       text rags against the right edge of the card for a clean
       diagonal composition with the top-left venue name. Width
       bumped from 60% → 80% so longer descriptions breathe across
       more of the card before wrapping, reducing the number of
       narrow lines stacked against the right edge. */
    max-width: 80%;
    text-align: right;
    z-index: 2;
    font-size: 0.78rem;
    line-height: 1.55;
  }
  /* Status label (rare; used by some cards) — keep hidden on mobile
     since the absolute layout doesn't have room for a third element. */
  .concept-card__status { display: none; }

  /* ---------- SITE FOOTER — MOBILE LAYOUT ----------
     Existing default at this breakpoint stacked all 4 columns
     (Brand → Pages → Follow → Newsletter) into a single column.
     Restructure on mobile so the footer reads as three stacked
     sections instead:
       Row 1: Brand block, content centred
       Row 2: Pages | Follow side-by-side (2-col)
       Row 3: Newsletter, full width
     Implementation: 2-column grid with explicit grid-row/column
     placement on each child. Brand spans both columns and centres
     its content; Pages + Follow take one column each on row 2;
     Newsletter spans both on row 3. */
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    gap: clamp(2rem, 6vw, 3rem) clamp(1rem, 4vw, 2rem);
  }
  .footer-grid > div:nth-child(1) {
    grid-column: 1 / -1;
    grid-row: 1;
    text-align: center;
  }
  /* Reset the negative-left-margin compensation on the brand mark
     when the column is centred — the offset was for left-aligned
     desktop only. Logo + paragraphs all sit on the centre axis. */
  .footer-grid > div:nth-child(1) .footer-brand__mark {
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 0;
  }
  /* Hide "Los Angeles. Founded 2025." and "@ajwpresents" on mobile —
     the brand block reads cleaner with just the logo. Desktop keeps
     both lines. */
  .footer-grid > div:nth-child(1) p {
    display: none;
  }
  .footer-grid > div:nth-child(2) { grid-column: 1; grid-row: 2; }
  .footer-grid > div:nth-child(3) { grid-column: 2; grid-row: 2; }
  .footer-grid > div:nth-child(4) { grid-column: 1 / -1; grid-row: 3; }

  /* Footer bottom row — centred on mobile. Existing rule uses
     justify-content: space-between which pushes copyright left
     and the legal links right; on a phone that width is too tight
     for that pattern to read cleanly. Stack and centre instead. */
  .footer-bottom {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
  }
  .footer-bottom .footer-legal {
    justify-content: center;
  }

  /* Approach page closing pull-quote ("The crowd isn't something
     you chase. It's something you build by holding a standard.")
     — at the current max-width (36ch) the lines were wrapping with
     orphaned single words ("chase." and "standard." each alone on
     a line). Tighter max-width plus text-wrap: balance lets the
     browser re-break the lines into balanced halves. */
  .approach-quote blockquote {
    max-width: 22ch;
    text-wrap: balance;
  }
}
