/* ============================================================
   Chroma — landing page
   Paper #F8F8F8 · Ink #1E1F1F · Black #010101 (owner, 2026-09-08; was #030303) · monotone only, no accent
   Display: Neue Haas Grotesk Display (Archivo fallback)
   Body: Inter 400–500, never thin
   ============================================================ */

@font-face {
  font-family: "Inter";
  src: url("fonts/Inter-Regular.otf") format("opentype");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("fonts/Inter-Medium.otf") format("opentype");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("fonts/Inter-SemiBold.otf") format("opentype");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("fonts/Inter-Bold.otf") format("opentype");
  font-weight: 700;
  font-display: swap;
}
/* Neue Haas Grotesk Display if installed locally; Archivo covers the rest */
@font-face {
  font-family: "Haas Display";
  src: local("Neue Haas Grotesk Display Pro 95 Black"),
       local("NeueHaasDisplayPro-95Black"),
       local("NeueHaasDisplay-Black");
  font-weight: 900;
}
@font-face {
  font-family: "Haas Display";
  src: local("Neue Haas Grotesk Display Pro 75 Bold"),
       local("NeueHaasDisplayPro-75Bold"),
       local("NeueHaasDisplay-Bold");
  font-weight: 700;
}
@font-face {
  font-family: "Haas Display";
  src: local("Neue Haas Grotesk Display Pro 55 Roman"),
       local("NeueHaasDisplayPro-55Roman"),
       local("NeueHaasDisplay-Roman");
  font-weight: 400;
}

/* Page transition veil (site/main.js) — a solid cut between pages, GSAP-driven
   rather than the native View Transition API, so it behaves the same in every
   browser. Static in the markup as the first child of body and opaque by
   default, so it masks the very first paint rather than whatever JS gets to
   after the browser finishes parsing; main.js fades it away once the page has
   landed, and fades it back in before an internal link actually navigates. */
.page-veil {
  position: fixed;
  inset: 0;
  z-index: 500;
  background: var(--black);
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .page-veil { display: none; }
}

/* First-visit loader (site/js/loader.js + loader-transition.js) — same
   "opaque by default, masks first paint" trick as .page-veil, sitting
   above it. Skipped via the inline script right after its markup in
   index.html (sessionStorage.chroma_intro_seen, or reduced motion — also
   gated here at the CSS level as belt-and-suspenders, same as .page-veil,
   so a slow/broken script never leaves a stuck opaque overlay).
   2026-09-08 v3 (owner): black ground; the wordmark top-left on the hero's
   exact wordmark position; the C mark centred, its five segments lighting
   up with the count; the count set huge bottom-left; a 3px line along the
   foot. Nothing spins. */
.loader {
  position: fixed;
  inset: 0;
  z-index: 600;
  background: var(--black);
  color: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* Sits on the hero's own wordmark: loader.js measures .hero-frame .hero-mark
   img and sets left/top/height inline, so the hero's wordmark fades in
   exactly underneath it and nothing jumps on Enter. These are the fallback. */
.loader-wordmark {
  position: absolute;
  left: calc(clamp(0.75rem, 1.2vw, 1.25rem) + clamp(0.5rem, 1.8vw, 2rem));
  top: calc(clamp(1rem, 2.4vw, 2.2rem) + 1.4rem);
  height: 23px;
  pointer-events: none;
}
.loader-wordmark img { display: block; height: 100%; width: auto; }
/* The mark as the loading icon: segments rest at 14% and each comes up to
   full paper as the count crosses its fifth (loader.js sets --lit 0..1 per
   segment). opacity only. */
.loader-mark {
  width: clamp(3.5rem, 6.4vw, 5rem);
  aspect-ratio: 1;
  transform: translateY(-6vh);
  transition: opacity 0.35s var(--ease-out);
}
.loader-mark svg { display: block; width: 100%; height: 100%; overflow: visible; }
.loader-mark .seg { fill: var(--paper); opacity: calc(0.14 + 0.86 * var(--lit, 0)); transition: opacity 0.42s var(--ease-out); }
/* The count: the loader's one bold move. Huge, tight, tabular, bottom-left
   on the page's own gutter; the leading zeros sit back until they mean
   something. */
.loader-count {
  position: absolute;
  left: var(--pad-x, 1.5rem);
  bottom: 1.6rem;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(5.5rem, 15vw, 14rem);
  line-height: 0.78;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  color: var(--paper);
  transition: opacity 0.45s var(--ease-out);
}
.loader-count .z { opacity: 0.22; }
.loader-video {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(100vw, calc(100vh * 16 / 9));
  aspect-ratio: 16 / 9;
  height: auto;
  object-fit: fill;
  clip-path: inset(2px);
  transform: translate(-50%, -50%) scale(0.55) translateY(-8vh);
}
.loader-dissolve {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* Plain bold type, no pill/container/background of any kind. The hover
   only scales the text up — full-contrast paper throughout, never dimmed or
   lightened, since a hover state's job is to draw the eye in, not reduce
   readability. Brutalist: big, tight, no chrome at rest or on hover. */
.loader-prompt {
  position: absolute;
  left: 50%;
  bottom: 14%;
  transform: translateX(-50%) translateY(6px) scale(1);
  transform-origin: 50% 100%;
  z-index: 1;
  padding: 0.1em 0.06em;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(1.5rem, 3.4vw, 2.25rem);
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--paper);
  opacity: 0;
  cursor: pointer;
  pointer-events: none;
  transition: opacity 0.5s var(--ease-out), transform 0.2s var(--ease-out);
}
.loader.is-ready .loader-prompt {
  opacity: 1;
  transform: translateX(-50%) translateY(0) scale(1);
  pointer-events: auto;
  animation: loader-prompt-pulse 1.8s ease-in-out 0.5s infinite;
}
.loader.is-ready .loader-prompt:hover,
.loader.is-ready .loader-prompt:focus-visible {
  animation-play-state: paused;
  opacity: 1;
  transform: translateX(-50%) translateY(0) scale(1.1);
}
.loader.is-ready .loader-prompt:active { transform: translateX(-50%) scale(1.02); }
@keyframes loader-prompt-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}
/* The line along the foot: 3px, paper on a 12% track, scaled on X. */
.loader-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: rgba(248, 248, 248, 0.12);
  z-index: 1;
  transition: opacity 0.3s var(--ease-out);
}
.loader-progress-fill {
  height: 100%;
  width: 100%;
  background: var(--paper);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.25s var(--ease-out);
}
/* ENTER sits under the mark, not on the count's baseline. */
.loader-prompt { bottom: auto; top: calc(50% + 4.5rem - 6vh); }
@media (max-width: 900px) {
  .loader-mark { transform: translateY(-10vh); }
  .loader-count { bottom: 1.2rem; }
  .loader-prompt { top: calc(50% + 4.5rem - 10vh); }
}
/* v4 "wordmark" mode (owner's second idea, 2026-09-09; .loader.loader-wm):
   just the wordmark, big in the centre. A 12% ghost underneath, the full
   paper copy on top clipped from the left and let out with the count
   (loader.js sets --fill 0..1), then loader.js flies the whole thing to
   the hero's wordmark slot top-left (transform only) while the hero fades
   in under it. Nothing else on the ground. Scoped on .wm-big, not .loader:
   the wordmark is lifted onto <body> for the flight and must keep these. */
.loader-wordmark.wm-big {
  position: relative;
  left: auto;
  top: auto;
  height: auto;
  width: clamp(16rem, 62vw, 58rem);
  transform-origin: 0 0;
  will-change: transform;
}
.wm-big img { display: block; width: 100%; height: auto; }
/* Owner (2026-09-09): "not just left to right". The paper copy rises from the foot of the letters with a soft
   edge (a feathered mask, 45% of the height wide) — the wordmark fills like a level coming up, not a bar going
   across; the ghost brightens 8% -> 22% under it as the count climbs. Stepped 1% by loader.js, no transition. */
.wm-big .wm-ghost { opacity: calc(0.08 + 0.14 * var(--fill, 0)); transition: opacity 0.35s var(--ease-out); }
.wm-big .wm-fill {
  position: absolute;
  inset: 0;
  -webkit-mask-image: linear-gradient(to top, #000 calc(var(--fill, 0) * 145% - 45%), transparent calc(var(--fill, 0) * 145%));
  mask-image: linear-gradient(to top, #000 calc(var(--fill, 0) * 145% - 45%), transparent calc(var(--fill, 0) * 145%));
}
/* In flight the clip is fully open and the ghost is redundant. */
.wm-big.is-flying .wm-fill { -webkit-mask-image: none; mask-image: none; }
.wm-big.is-flying .wm-ghost { opacity: 0; }
/* v5 "dither" mode (owner, 2026-09-11: "way diff"; .loader.loader-dither): the whole screen is the field canvas
   (js/loader.js makeField: the C printing out of black as an ordered-dither bitmap, then the cell-by-cell exit),
   and one mono micro-label bottom-left on the page's gutter carries the count. Nothing else on the ground. */
.loader-dither .loader-field { position: absolute; inset: 0; display: block; }
.loader-tag {
  position: absolute;
  left: var(--pad-x, 1.5rem);
  bottom: 1.5rem;
  display: flex;
  gap: 1.25rem;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--paper);
  transition: opacity 0.25s var(--ease-out);
}
.loader-tag-l { opacity: 0.45; }
body.loader-lock { overflow: hidden; }
/* While locked the reserved gutter is empty (no scrollbar drawn) and painted with the root background — the
   loader is position: fixed and stops at the gutter, so paint the root black too or a paper strip shows. */
html.loader-lock { background: var(--black); }
@media (prefers-reduced-motion: reduce) {
  .loader { display: none; }
}

:root {
  /* Statement spacing (owner, 2026-09-06: "increase the padding, and make
     it even from both sections"). --stmt-gap is the clear black the reader
     sees between the sentence and whatever sits above or below it; the
     hero's foot (--hero-pb, under the wordmark) and Work's head
     (--work-pt, above "Selected Work") are folded into the statement's
     own padding so the two gaps come out identical. */
  --stmt-gap: clamp(12rem, 30vh, 20rem);
  --hero-pb: 3.5rem;
  --work-pt: clamp(6rem, 12vh, 9rem);
  --paper: #F8F8F8;
  --ink: #1E1F1F;
  --black: #010101;
  --grey-40: rgba(30, 31, 31, 0.4);
  --grey-60: rgba(30, 31, 31, 0.6);
  --paper-40: rgba(248, 248, 248, 0.45);
  --paper-60: rgba(248, 248, 248, 0.65);
  --hairline-dark: rgba(30, 31, 31, 0.14);
  --hairline-light: rgba(248, 248, 248, 0.16);
  --display: "Haas Display", "Archivo", "Helvetica Neue", Arial, sans-serif;
  --body: "Inter", "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SFMono-Regular", "Cascadia Mono", Consolas, monospace;
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  /* Wider than it was (owner, 2026-08-22: "so much padding on the left and
     right"): the container runs to 100rem and the gutters are a touch
     narrower, so wide screens get page, not margin. */
  --pad-x: clamp(1.25rem, 3vw, 3rem);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* scrollbar-gutter (2026-09-09): the first-visit loader scroll-locks the body (overflow: hidden), which on
   Windows/Linux classic scrollbars also REMOVES the scrollbar — so the instant loader.js let go, the document
   widened back by ~17px and the whole hero reflowed in one frame mid-fade (CTA, routes, meta, the WebGL canvas
   all snapped sideways). Reserving the gutter keeps the locked and unlocked layouts pixel-identical. Overlay
   scrollbars (macOS, mobile) never had the problem and are unaffected. */
html { scroll-behavior: smooth; overflow-anchor: none; scrollbar-gutter: stable; }

/* Lenis (site/js/smooth-scroll.js) — from the library's own stylesheet, inlined
   so smooth scroll costs no extra request. These only apply once Lenis has
   passed its gates and put .lenis on <html>. */
html.lenis,
html.lenis body { height: auto; }
.lenis:not(.lenis-autoToggle).lenis-stopped { overflow: clip; }
.lenis [data-lenis-prevent],
.lenis [data-lenis-prevent-wheel],
.lenis [data-lenis-prevent-touch] { overscroll-behavior: contain; }
.lenis.lenis-smooth iframe { pointer-events: none; }

body {
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.6;
  font-weight: 500;
  background-color: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* The whole-page invert. Long enough not to snap, short enough to feel like
     a state change rather than an animation. */
  transition: background-color 380ms var(--ease-out);
}
body.is-dark,
body.is-tail-dark { background-color: var(--black); }
@media (prefers-reduced-motion: reduce) {
  body { transition: none; }
}

/* Film grain — retired 2026-09-09 (owner: the black read "more of a gray, not one set colour" and snapped when
   the loader — which sat above it — left). The ground is flat --black everywhere now; the rule is kept, off. */
body::after {
  display: none;
  content: "";
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  opacity: 0.05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

::selection { background: rgba(30, 31, 31, 0.16); color: var(--ink); }

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }

.wrap {
  max-width: 100rem;
  margin-inline: auto;
  padding-inline: var(--pad-x);
}

/* ---------- Nav — inverts via .on-dark, driven by IntersectionObserver ---------- */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 80;
  /* Bare at the top of the page, solid once scrolled — a permanent bar and
     rule sitting over the hero is the heaviest thing on the screen.
     Opaque rather than blurred: a blurred backdrop turns fine imagery to mud. */
  /* No rule under the nav: its own ground is the separation. A hairline here
     draws a line across every full-bleed section it passes over. */
  background: transparent;
  transition: background-color 400ms var(--ease-out);
}
/* Owner (2026-09-07, later): scrolled, the bar had nothing behind it. It now
   folds into a pill - a near-black glass capsule, narrower than the page,
   hung a little under the top edge - and stays that way over paper and
   black alike, so the logo and links are always paper inside it. */
.nav.is-stuck { background: transparent; }
.nav.on-dark.is-stuck { background: transparent; }
.nav-inner {
  border: 1px solid transparent;
  transition:
    max-width 480ms var(--ease-out), padding 480ms var(--ease-out),
    margin 480ms var(--ease-out), border-radius 480ms var(--ease-out),
    background-color 400ms var(--ease-out), border-color 400ms var(--ease-out),
    box-shadow 400ms var(--ease-out);
}
.nav.is-stuck .nav-inner {
  max-width: 58rem;
  margin-top: 0.75rem;
  padding: 0.45rem 0.45rem 0.45rem 1.35rem;
  border-radius: 999px;
  /* Premium pass (owner, 2026-09-07): a lighter, deeper glass - more blur,
     a hairline that reads, a top sheen (::before) and a bottom inset shade
     so the capsule has a lit edge and a weighted underside, plus a short
     contact shadow and a long soft one. */
  background-color: rgba(10, 10, 10, 0.72);
  border-color: rgba(248, 248, 248, 0.14);
  backdrop-filter: blur(24px) saturate(1.2);
  -webkit-backdrop-filter: blur(24px) saturate(1.2);
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.1) inset,
    0 -1px 0 rgba(0, 0, 0, 0.55) inset,
    0 1px 2px rgba(0, 0, 0, 0.5),
    0 18px 44px -20px rgba(0, 0, 0, 0.85);
}
.nav-inner { position: relative; }
.nav-inner::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(180deg, rgba(248, 248, 248, 0.07) 0%, rgba(248, 248, 248, 0) 55%);
  opacity: 0; transition: opacity 400ms var(--ease-out);
}
.nav.is-stuck .nav-inner::before { opacity: 1; }
/* Sliding hover highlight behind the links (js: navHover in main.js) - a
   soft capsule that glides from link to link; the underline stands down in
   the pill. Left/width move it, opacity shows it. */
.nav-links { position: relative; }
.nav-links a { padding: 0.4rem 0.75rem; }
.nav-hover {
  position: absolute; top: 50%; left: 0; height: 2rem; width: 0; z-index: -1;
  transform: translateY(-50%); border-radius: 999px;
  background: rgba(30, 31, 31, 0.07); opacity: 0; pointer-events: none;
  transition: left 260ms var(--ease-out), width 260ms var(--ease-out), opacity 180ms var(--ease-out);
}
.nav-hover.is-jump { transition: opacity 180ms var(--ease-out); }
.nav.on-dark .nav-hover, .nav.is-stuck .nav-hover { background: rgba(248, 248, 248, 0.1); }
@media (prefers-reduced-motion: reduce) { .nav-hover { transition: none; } .nav-inner { transition: none; } }
.nav.is-stuck .nav-logo img { height: 30px; filter: invert(1); } /* bumped from 26 (owner, 2026-09-07) */
.nav.is-stuck .nav-links a { color: var(--paper); }
.nav.is-stuck a.nav-cta { background-image: none; background-color: var(--paper); color: var(--ink); padding: 0.65rem 1.3rem; font-size: 0.95rem; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
.nav.is-stuck a.nav-cta::after { display: none; }
@media (max-width: 900px) {
  .nav.is-stuck .nav-inner { max-width: calc(100% - 2 * var(--pad-x)); margin-top: 0.6rem; padding-left: 1.1rem; }
}
.nav-inner {
  max-width: 100rem;
  margin-inline: auto;
  padding: 1.15rem var(--pad-x);
  /* Three zones: logo left, links dead-centre, contact right. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}
.nav-logo { justify-self: start; }
.nav-cta { justify-self: end; }
.nav-right { justify-self: end; display: flex; align-items: center; gap: 1.25rem; }
.nav-logo img {
  height: 40px;
  width: auto;
  transition: filter 400ms var(--ease-out), opacity 250ms var(--ease-out);
}
.nav.on-dark .nav-logo img { filter: invert(1); }
.nav-links {
  display: flex;
  align-items: center;
  /* Same rhythm, size and weight as the hero header's routes (owner,
     2026-09-07: "make the width and size like how it is on the hero"). */
  gap: 0.25rem;
}
.nav-links a {
  color: var(--ink);
  font-size: 1.0625rem;
  font-weight: 500;
  position: relative;
  transition: color 400ms var(--ease-out);
}
.nav.on-dark .nav-links a { color: var(--paper); }
/* Hover is the gliding capsule only (.nav-hover, navHover in main.js /
   js/nav-hover.js) — the underline is gone on every page (owner, 2026-09-07:
   "just no underlining", same as the hero routes). */
a.nav-cta {
  background-color: var(--ink);
  color: var(--paper);
  padding: 0.6rem 1.3rem;
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 700;
  /* Same liquid dome as the hero pills, scaled to the smaller pill. */
  background-image: radial-gradient(130% 100% at 50% 100%, var(--black) 49.6%, rgba(0, 0, 0, 0) 50%);
  background-repeat: no-repeat;
  background-position: 50% 100%;
  background-size: 100% 0%;
  transition:
    background-size 550ms var(--ease-drawer),
    background-color 400ms var(--ease-out),
    color 400ms var(--ease-out),
    box-shadow 300ms var(--ease-out),
    transform 160ms var(--ease-out);
}
/* Hover is the label roll (see .roll-label) plus a hair of lift — no fill
   change, so the pill reads the same on paper and on black. The liquid dome
   stays defined but never rises here (owner, 2026-08-24: colour flips on the
   black ground looked wrong). */
a.nav-cta:hover { transform: translateY(-1px); }
.nav.on-dark a.nav-cta { background-image: none; background-color: var(--paper); color: var(--ink); }
.nav-cta:active { transform: translateY(-1px) scale(0.97); }
/* Iridescent reflection — owner request (2026-08-22), the one place colour
   is allowed on the site. A narrow spectral band, heavily blurred and at
   low opacity, crosses the pill once on hover like light catching the edge of
   glass; it never rests on the button, so at rest the pill stays pure ink or
   paper. Transform-only, on its own layer. Screen-blended on the ink pill,
   multiplied on the paper one, so both read as a reflection and not a tint. */
a.nav-cta {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
a.nav-cta::after {
  content: "";
  position: absolute;
  top: -60%;
  left: -10%;
  width: 55%;
  height: 220%;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 150, 150, 0.55) 18%,
    rgba(255, 220, 140, 0.6) 34%,
    rgba(160, 255, 190, 0.55) 50%,
    rgba(150, 215, 255, 0.6) 66%,
    rgba(200, 160, 255, 0.55) 82%,
    rgba(255, 255, 255, 0) 100%);
  filter: blur(5px);
  mix-blend-mode: screen;
  opacity: 0.85;
  transform: translateX(-140%) rotate(18deg);
  will-change: transform;
}
a.nav-cta:hover::after {
  transform: translateX(240%) rotate(18deg);
  /* Gentle curve, so the band is visible crossing rather than flashing. */
  transition: transform 1400ms cubic-bezier(0.4, 0.1, 0.3, 1);
}
/* On the paper pill the same band multiplies in, so it needs fuller stops
   to register as a reflection rather than vanish into the white. */
.nav.on-dark a.nav-cta::after {
  mix-blend-mode: multiply;
  opacity: 0.8;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 120, 130, 0.7) 18%,
    rgba(255, 205, 90, 0.75) 34%,
    rgba(120, 230, 170, 0.7) 50%,
    rgba(110, 190, 255, 0.75) 66%,
    rgba(175, 130, 255, 0.7) 82%,
    rgba(255, 255, 255, 0) 100%);
}
@media (prefers-reduced-motion: reduce) {
  a.nav-cta::after { display: none; }
}

/* ---------- Hero — centred, the symbol carrying the whole top of the page ----------
   Dark version (owner decision, 2026-08-22): the hero sits on the same black
   as every other zone, with the mark rendered white. A paper version of this
   block is the planned counterpart; this is the one that ships for now. The
   .zone-black class on the element is what makes the nav/body ground logic
   in main.js treat it as dark. */
.hero {
  position: relative;
  /* Full screen again so the scroll ring can sit at the true foot of the
     viewport (owner, 2026-08-24); the statement below pins on its centre,
     so this costs only a few dozen pixels of scroll before it holds. */
  min-height: 100dvh;
  display: flex;
  align-items: center;
  background: var(--black);
  color: var(--paper);
  padding: clamp(7rem, 14vh, 10rem) 0 clamp(4rem, 8vh, 6rem);
  overflow: hidden;
}
.hero-inner {
  width: 100%;
  max-width: 68rem;
  margin-inline: auto;
  padding-inline: var(--pad-x);
  text-align: center;
}
/* Real geometry, not a picture — it holds the space above the headline and
   tilts to the pointer. Sized off the viewport so it never crowds the type. */
.hero-mark {
  width: min(64vw, 19rem);
  aspect-ratio: 1;
  margin: 0 auto clamp(1.5rem, 3.5vh, 2.5rem);
}
.hero-mark chroma-mark { display: block; width: 100%; height: 100%; }
.hero-headline {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.2rem, 4.6vw, 4.2rem);
  line-height: 1.0;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
.hero-mark { position: relative; }
.hero-sub {
  margin: 2.25rem auto 0;
  max-width: 34rem;
  text-wrap: balance;
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  font-weight: 500;
  line-height: 1.55;
  color: var(--paper-60);
}
.hero-actions {
  margin-top: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}
/* Liquid fill — one hover treatment for every pill: a black dome (a hard-stop
   radial anchored below the pill) floods up as its background-size grows.
   Pure background animation, so the label never fights a stacking context. */
.liquid,
.hero-cta,
.hero-secondary,
.apply-submit {
  /* Image pinned to the pill's bottom edge; the dome (ellipse centred on the
     image's own bottom, vertical radius = image height) rises as the image
     grows, its curved top edge reading as a liquid meniscus. */
  background-image: radial-gradient(130% 100% at 50% 100%, var(--fill, var(--black)) 49.6%, rgba(0, 0, 0, 0) 50%);
  background-repeat: no-repeat;
  background-position: 50% 100%;
  background-size: 100% 0%;
  transition:
    background-size 550ms var(--ease-drawer),
    color 300ms var(--ease-out),
    border-color 300ms var(--ease-out),
    box-shadow 300ms var(--ease-out),
    transform 160ms var(--ease-out);
}
.liquid:hover,
.apply-submit:hover { background-size: 100% 300%; }

/* The hero pills sit on black, where a colour flip on hover half-vanishes
   the pill (owner, 2026-08-24). Their hover is motion only: the label rolls
   up and a copy rises in under it (.roll-label, wrapped at load by main.js),
   with a hair of lift. The paper pill stays paper; the outline pill's
   hairline just firms up to full paper. */
.hero-cta {
  background-color: #F8F8F8;
  color: #1E1F1F; /* literal: the pill is always paper-on-ink, even inside a token-flipped dark zone */
  font-weight: 700;
  font-size: 1.0625rem;
  padding: 1rem 2.1rem;
  border-radius: 999px;
}
.hero-cta:hover { transform: translateY(-2px); }
.hero-cta:active { transform: translateY(-2px) scale(0.97); }
.hero-secondary {
  font-weight: 700;
  font-size: 1.0625rem;
  padding: calc(1rem - 1px) 2.1rem;
  border: 1px solid var(--hairline-light);
  border-radius: 999px;
}
.hero-secondary:hover { border-color: var(--paper); transform: translateY(-2px); }
.hero-secondary:active { transform: translateY(-2px) scale(0.97); }

/* Label roll: two stacked copies inside a clipped line box; on hover both
   travel up one line so the second takes the first's place. Transform-only.
   Line-height is the clip, so descenders are inside the box and never cut. */
.hero-cta, .hero-secondary, a.nav-cta { display: inline-block; }
.roll-label {
  display: block;
  position: relative;
  overflow: hidden;
  line-height: 1.25;
}
.roll-label > span {
  display: block;
  /* Movement on screen, not an entrance — in-out, so the roll is legible
     rather than a snap. */
  transition: transform 420ms var(--ease-in-out);
}
.roll-label > span + span {
  position: absolute;
  left: 0;
  top: 100%;
  width: 100%;
}
.hero-cta:hover .roll-label > span,
.hero-secondary:hover .roll-label > span,
.nav-cta:hover .roll-label > span { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) {
  .roll-label > span { transition: none; }
  .hero-cta:hover .roll-label > span,
  .hero-secondary:hover .roll-label > span,
  .nav-cta:hover .roll-label > span { transform: none; }
  .hero-cta:hover, .hero-secondary:hover, a.nav-cta:hover { transform: none; }
}
.hero-inner { position: relative; z-index: 1; }

.hero-proof {
  margin-top: 2.25rem;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--paper-40);
}
/* Scroll ring — "SCROLL DOWN" around a turning circle at the foot of the
   hero, a small arrow in the middle. Centred with auto margins rather than
   a transform so the hero's entrance tween (which owns `transform`) can't
   knock it off-centre. Constant motion → linear. */
.scroll-ring {
  position: absolute;
  left: 0;
  right: 0;
  /* Right at the foot of the hero (owner, 2026-08-24: lower), not floating
     above it. */
  bottom: clamp(0.75rem, 2vh, 1.5rem);
  /* ~15% bigger (owner, 2026-08-24). */
  width: 6.9rem;
  height: 6.9rem;
  margin-inline: auto;
  color: var(--paper-60);
  z-index: 1;
  transition: color 300ms var(--ease-out);
}
.scroll-ring:hover { color: var(--paper); }
.scroll-ring-text {
  display: block;
  width: 100%;
  height: 100%;
  animation: scroll-ring-spin 16s linear infinite;
}
.scroll-ring-text text {
  fill: currentColor;
  font-family: var(--display);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.08em;
}
.scroll-ring-arrow {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
}
@keyframes scroll-ring-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .scroll-ring-text { animation: none; }
}
@media (max-height: 640px) {
  .scroll-ring { display: none; }
}

/* ---------- Statement — the page's first words, filled in by the scroll ----------
   One centred sentence set big, on the same black. main.js splits it into
   words and pins the section while the scroll scrubs each word from a
   ghosted paper to full paper, so the copy is read at the pace it is
   revealed. Words are fully visible by default — the JS only ever dims
   them — so reduced motion and a script failure both leave the sentence
   plainly readable. */
/* In flow (owner, 2026-09-12: no fixed positioning here). --stmt-gap of clear black above
   the sentence; below it, the Work block is pulled up over the statement's bottom padding
   (margin below) while main.js drifts the sentence down against the scroll and fades it,
   so Work comes up in front of it. */
.statement {
  position: relative;
  width: 100%;
  color: var(--paper);
  /* Owner (2026-09-12): "a point where the only thing on screen is the text". Roughly a
     viewport of clear black above and below the sentence (the bottom also absorbs the
     Work block's -20vh overlap), so on the way down it is alone on screen for a beat
     before it starts to lag. */
  padding: clamp(18rem, 60vh, 34rem) 0 clamp(24rem, 78vh, 44rem);
  text-align: center;
}
.statement-text { will-change: transform, opacity; }
/* Work rides up over the statement: a fifth of a viewport of overlap, painted black
   over black (.zone-black) and stacked above, so the lagging sentence slips beneath it. */
.statement-spacer + .work { margin-top: -20vh; position: relative; z-index: 2; }
/* 2026-09-12 (owner): same voice as the About page's "why we exist" line — Inter Medium at statement size on a
   wide measure, not the bold display face. Quieter, reads as a sentence rather than a headline. */
.statement-text {
  max-width: 44ch;
  margin-inline: auto;
  font-family: var(--body);
  font-weight: 600; /* W4 as picked: Semibold (owner, 2026-09-12) */
  font-size: clamp(1.35rem, 2.1vw, 2.1rem);
  line-height: 1.36;
  letter-spacing: -0.02em;
  text-wrap: pretty;
}
.statement-text .w { display: inline-block; will-change: opacity; }
/* Plain black wrapper carrying .zone-black (index.html), kept from the
   pinned era so the ground/nav observer sees one continuous black. */
.statement-spacer { background: var(--black); }
@media (prefers-reduced-motion: reduce) {
  .statement-spacer + .work { margin-top: 0; }
}
/* Phones (owner, 2026-09-22: "way too much" padding): the viewport of clear black either side reads as a dead
   screen on a phone. About a quarter-screen above, and below just enough for Work's -20vh ride-over plus air. */
@media (max-width: 760px) {
  .statement { padding: clamp(7rem, 24dvh, 12rem) 0 clamp(11rem, 38dvh, 18rem); }
}

/* ---------- Section grounds + gradual fades between black and white ---------- */
/* Grounds meet at a hard edge — no gradient band between them. A whole-page
   flip is not possible here: only ~250px separates the last light line from
   the first dark one, so for most of a 900px viewport both are on screen and
   one of them would always be same-on-same. One black for every dark zone.
   The body ground and nav follow whichever zone is under the nav (main.js). */
.zone-dark,
.zone-black { color: var(--paper); background-color: var(--black); }
.zone-paper { background-color: var(--paper); }

/* One flat black for every section, hero included (owner decision,
   2026-08-22): no per-section radial washes, so the page is a single
   continuous ground and only the content marks where one block ends and
   the next begins. overflow:hidden stays so a motif's scroll drift can
   never leak past its section. */
.work,
.services,
.journal,
.contact {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

/* Dividers — one rule at each black-on-black seam (hero→work, blog→
   contact), aligned to the container's inner edges. A solid hairline, set
   brighter than the 16% token so it reads on the flat black (the owner
   rejected a dot-matrix version outright, 2026-08-24). The black/paper
   edges either side of Services divide themselves. */
/* No rule under the statement block (owner, 2026-08-24) — the statement→Work
   seam is left open. 2026-09-12: the Blog→Contact hairline is gone too
   (owner: it read as arbitrary, floating in the gap between two cards). The
   contact card's own glass edge is the divider; the seam is spacing alone. */

/* ---------- Bitmap motifs ----------
   Botanical stipples from the same halftone system as the loader and the
   footer hands (baked in bitmap idea/motifs/), hung in the corners of each
   section's ground — deliberately large and partly tucked behind the edge,
   the way artwork hangs behind a page rather than sitting inside it (the
   owner rejected a "whole inside the band" pass as too small and missing).
   Dots on transparent, so the section's black shows through between them.
   Sized in vw so they hold their spot at any width; z-index -1 keeps them
   under every bit of content. main.js drifts them against the scroll,
   transform-only. */
.motif {
  position: absolute;
  z-index: -1;
  height: auto;
  pointer-events: none;
  user-select: none;
  will-change: transform;
}
@media (max-width: 900px) {
  .motif { opacity: 0.35; }
}

/* ---------- Services ---------- */
/* The one paper block on the page (owner, 2026-08-22): Services is a single
   big rounded paper card sitting on the black, between the Work and Blog
   zones, so the page reads as a black/white mix rather than one long dark
   run. The card is the .wrap itself — its outer edge lands on the same
   content edge every other section uses, and the content is inset again
   inside it. Everything inside was written in paper-on-black tokens, so the
   tokens are flipped at the section root — every rule below keeps working
   unchanged. Ground and text colours are literal on purpose: var(--paper)
   means ink in here. */
/* Simplified (owner, 2026-08-24): a section head and four plain cards on
   the flat black — no big wrapper card, no motif, no giant type. */
.services {
  position: relative;
  padding: clamp(5rem, 10vh, 8rem) 0 clamp(4.5rem, 9vh, 7rem);
  background-color: var(--black);
  color: var(--paper);
}
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: clamp(3rem, 7vh, 5.5rem);
}
.section-head h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.2rem, 4.6vw, 4rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.section-head-center {
  justify-content: center;
  /* align-items too: the head goes column-direction below 900px, where
     justify-content stops governing the horizontal axis. */
  align-items: center;
  text-align: center;
  margin-bottom: clamp(1.25rem, 3vh, 2rem);
}
/* Services — glass slab (owner, 2026-08-31): the slab keeps its rate-card
   structure (giant heading over a 3px rule, ruled columns) but wears the
   same material as the contact card — one glass object on the black, so
   Services and "Let's build yours." read as a pair. Paper slab retired. */
.services-slab {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border: 1px solid var(--hairline-light);
  border-radius: 16px;
  background-color: rgba(248, 248, 248, 0.04);
  backdrop-filter: blur(18px) saturate(1.05);
  -webkit-backdrop-filter: blur(18px) saturate(1.05);
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.14) inset,
    0 40px 90px -60px rgba(0, 0, 0, 0.95);
  color: var(--paper);
  padding: clamp(1.5rem, 4vw, 4rem);
}
.services-slab::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(85% 70% at 10% 0%, rgba(248, 248, 248, 0.1) 0%, rgba(248, 248, 248, 0) 58%),
    radial-gradient(70% 60% at 100% 100%, rgba(248, 248, 248, 0.055) 0%, rgba(248, 248, 248, 0) 62%);
}
.services-slab-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 2rem;
  padding-bottom: 1rem;
  border-bottom: 3px solid var(--paper);
}
.services-slab-head h2 {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(3rem, 8vw, 8rem);
  /* -0.04em welded the r/v pair at this weight; -0.015em keeps the set
     tight without letters kissing. */
  letter-spacing: -0.015em;
  line-height: 0.9;
}
/* Targeted kern: at 900 weight the r arm still meets the v; a whisker of
   space after the r alone fixes the pair without loosening the word. */
.services-slab-head h2 .kern-rv { letter-spacing: 0.03em; }
.services-slab-link {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--paper);
  text-decoration: none;
  padding-bottom: 0.45rem;
}
.services-slab-link:hover { text-decoration: underline; text-underline-offset: 0.18em; }
.services-slab-link svg { transition: transform 200ms var(--ease-out); }
.services-slab-link:hover svg { transform: translate(2px, -2px); }
.services-slab-link:focus-visible { outline: 2px solid var(--paper); outline-offset: 3px; }
.services-cols {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
.services-col {
  padding: 1.5rem 1.25rem 2rem 0;
  border-right: 1px solid rgba(248, 248, 248, 0.18);
}
.services-col + .services-col { padding-left: 1.25rem; }
.services-col:last-child { border-right: 0; }
/* Index: heavy display numerals in parentheses, full ink, a step down
   from the title (owner pick 09 of services-numbers.html, 2026-08-25). */
.services-num {
  display: block;
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.25rem;
  letter-spacing: -0.03em;
  color: var(--paper);
  font-variant-numeric: tabular-nums;
  margin-bottom: 2.5rem;
}
.services-col h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.3rem, 1.8vw, 1.8rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin-bottom: 1.25rem;
}
.services-col h3 a { color: inherit; text-decoration: none; }
.services-col h3 a:hover { text-decoration: underline; text-underline-offset: 0.12em; text-decoration-thickness: 2px; }
.services-col h3 a:focus-visible { outline: 2px solid var(--paper); outline-offset: 3px; }
.services-col ul { list-style: none; margin: 0; padding: 0; }
.services-col li {
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.45;
  padding: 0.35rem 0;
  border-top: 1px solid rgba(248, 248, 248, 0.16);
}
.services-col li:first-child { border-top: 0; }
@media (max-width: 900px) {
  .services-cols { grid-template-columns: 1fr; }
  .services-col { border-right: 0; padding-left: 0; border-bottom: 1px solid rgba(248, 248, 248, 0.18); }
  .services-col:last-child { border-bottom: 0; }
}
@media (max-width: 520px) {
  .services-cols { grid-template-columns: 1fr; }
  .services-col { border-right: 0; padding-left: 0 !important; border-bottom: 1px solid rgba(248, 248, 248, 0.18); }
  .services-col:last-child { border-bottom: 0; }
  .services-slab-head { flex-direction: column; align-items: flex-start; gap: 1rem; }
}
/* Glass pill — the contact card's material, cut as a button: frosted paper
   at a few percent over the black, a hairline, one inset highlight along the
   top edge. The paper dot at its end is the only solid object; on hover it
   carries the arrow outward and the glass brightens a step. */
.glass-pill {
  display: inline-flex;
  align-items: center;
  gap: 1.1rem;
  padding: 0.55rem 0.55rem 0.55rem 1.6rem;
  border-radius: 999px;
  border: 1px solid rgba(248, 248, 248, 0.18);
  background-color: rgba(248, 248, 248, 0.06);
  backdrop-filter: blur(18px) saturate(1.05);
  -webkit-backdrop-filter: blur(18px) saturate(1.05);
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.16) inset,
    0 24px 50px -36px rgba(0, 0, 0, 0.9);
  color: var(--paper);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: -0.005em;
  transition: background-color 300ms var(--ease-out), border-color 300ms var(--ease-out), transform 160ms var(--ease-out);
}
.glass-pill-dot {
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--paper);
  color: var(--ink);
}
.glass-pill-dot svg { transition: transform 300ms var(--ease-out); }
.glass-pill:hover { background-color: rgba(248, 248, 248, 0.11); border-color: rgba(248, 248, 248, 0.3); }
.glass-pill:hover .glass-pill-dot svg { transform: translate(1px, -1px); }
.glass-pill:active { transform: scale(0.97); }
.glass-pill:focus-visible { outline: 2px solid var(--paper); outline-offset: 4px; }
/* .orbit-all centres itself for the centred Work section; Services is set from
   the left margin, so the link has to return to it. */
/* Both classes, because .orbit-all is declared further down the file and would
   otherwise win the margin on source order. */
.orbit-all.services-all {
  margin-top: clamp(2.5rem, 5vh, 3.5rem);
  margin-inline: 0;
}

/* ---------- Work ---------- */
.work {
  padding: var(--work-pt) 0 clamp(8rem, 16vh, 12rem);
}
.work-note {
  color: var(--paper-60);
  max-width: 34rem;
  margin: 0 auto clamp(3.5rem, 7vh, 5.5rem);
  text-align: center;
  text-wrap: balance;
  font-size: 1.0625rem;
  line-height: 1.6;
}
.orbit-stage { position: relative; }
/* Same editorial rhythm as the full work index (.gallery-grid on work.html):
   a wide feature, then a landscape/square pair, then a feature close. Each
   project reads at the size the index gives it rather than as four equal
   tiles — the row of small circles read as a menu, not as work. */
.orbit {
  display: grid;
  /* minmax(0, 1fr), not bare 1fr — a bare fr track's auto minimum is its
     content's min-content size, and a full-bleed disc image inside a span-12
     card was winning that fight and forcing every track wider than the grid's
     own container on narrow viewports. minmax(0, 1fr) floors it at 0 so the
     tracks — and everything spanning them — actually shrink to fit. */
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: start;
  gap: clamp(2.75rem, 5.5vh, 4.5rem) clamp(1.25rem, 2.5vw, 2rem);
}
.orbit-node-wrap { min-width: 0; }
.orbit-node-wrap.feature { grid-column: span 12; }
.orbit-node-wrap.wide    { grid-column: span 7; }
.orbit-node-wrap.narrow  { grid-column: span 5; }
.orbit-node {
  display: block;
  width: 100%;
  color: var(--paper);
}
.orbit-disc {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 14px;
  overflow: hidden;
  background: rgba(248, 248, 248, 0.05);
}
.orbit-node-wrap.wide   .orbit-disc { aspect-ratio: 1.45; }
.orbit-node-wrap.narrow .orbit-disc { aspect-ratio: 1 / 1; }
.orbit-disc img,
.orbit-disc video {
  /* 14% vertical overscan: main.js scrubs the cover up/down inside the
     clipped frame as the card passes through the viewport, and the extra
     height is what keeps the frame edges covered at either extreme. */
  position: absolute;
  top: -7%;
  left: 0;
  width: 100%;
  height: 114%;
  object-fit: cover;
  /* Hover zoom lives on the individual `scale` property, not `transform` —
     GSAP owns `transform` (entrance settle + scroll parallax) and the two
     compose instead of the CSS transition fighting the scrub. */
  transition: scale 900ms var(--ease-drawer), filter 420ms var(--ease-out);
}
.orbit-node:hover .orbit-disc img,
.orbit-node:hover .orbit-disc video { scale: 1.035; }
.orbit-node-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem clamp(1.25rem, 3vw, 2.5rem);
  margin-top: clamp(1.25rem, 2.5vh, 1.75rem);
}
.orbit-node-title { flex: 1; min-width: 0; }
/* Named on the page, not on hover — a work index should read cold. */
.orbit-node-name {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.75rem, 3.4vw, 2.9rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  transition: font-size 250ms var(--ease-out);
}
.orbit-node-line {
  display: block;
  margin-top: 0.5rem;
  max-width: 34rem;
  font-size: 1.0625rem;
  color: var(--paper-60);
}
/* A real button, not a thin mono label — same display-face, bold-weight pill
   as the rest of the site's secondary actions (.hero-secondary, .orbit-all),
   not the small uppercase letter-spaced mono voice, which read as flimsy at
   this size and against the dark ground. It's a plain link straight to the
   case study. */
.orbit-node-view {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 1.25rem;
  border: 1.5px solid var(--paper-40);
  border-radius: 999px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  color: var(--paper);
  transition: background-color 250ms var(--ease-out), border-color 250ms var(--ease-out),
              color 250ms var(--ease-out), gap 250ms var(--ease-out);
}
.orbit-node-view svg { flex: none; width: 12px; height: 12px; transition: transform 250ms var(--ease-out); }
.orbit-node-view:hover {
  background-color: var(--paper);
  border-color: var(--paper);
  color: var(--ink);
  gap: 0.8rem;
}
.orbit-node-view:hover svg { transform: translate(2px, -2px); }
.orbit-node:focus-visible { outline: none; }
.orbit-node:focus-visible .orbit-disc { outline: 2px solid var(--paper); outline-offset: 5px; }

/* Centred with the rest of the section, not orphaned on the left margin. */
.orbit-all {
  display: flex;
  width: fit-content;
  margin-inline: auto;
  align-items: center;
  gap: 0.5rem;
  margin-top: clamp(3rem, 7vh, 5rem);
  font-weight: 700;
  font-size: 1rem;
  color: var(--paper);
  transition: gap 250ms var(--ease-out), opacity 300ms var(--ease-out);
}
.orbit-all:hover { gap: 0.85rem; }
@media (prefers-reduced-motion: reduce) {
  .orbit-disc img, .orbit-disc video { transition: none; }
  .orbit-node:hover .orbit-disc img,
  .orbit-node:hover .orbit-disc video { transform: none; }
}
@media (max-width: 900px) {
  /* Every card is one-per-row below this width regardless of state, so the
     container itself collapses to a single real column — grid-column: auto
     on every card, not span 12 against it. A span still asking for 12 tracks
     against a 1-column explicit grid makes Grid invent 11 implicit tracks to
     satisfy it, and those still carry the real column-gap between them: same
     bug .contact-grid hit further down this file, where 11 real gaps at a
     clamp()'d width added up to more than the container itself and left
     every minmax(0, 1fr) track — explicit or implicit — at 0. */
  .orbit { grid-template-columns: 1fr; }
  .orbit-node-wrap,
  .orbit-node-wrap.feature, .orbit-node-wrap.wide, .orbit-node-wrap.narrow { grid-column: auto; }
}
@media (max-width: 620px) {
  .orbit { gap: 3rem; }
  .orbit-node-row { flex-wrap: wrap; align-items: flex-start; gap: 0.5rem 1rem; }
}

/* ---------- Journal ---------- */
.journal {
  padding: clamp(7rem, 14vh, 11rem) 0;
}
/* A shelf of issues. Each cover is set live in the site's own faces — no
   images to source, and the covers can never drift off-brand. */
.journal-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 1.8vw, 2rem);
}
@media (max-width: 1180px) {
  .journal-grid { grid-template-columns: repeat(2, 1fr); }
}
.journal-card-link {
  display: flex;
  flex-direction: column;
  height: 100%;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--hairline-light);
  background-color: rgba(248, 248, 248, 0.035);
  box-shadow: 0 1px 0 rgba(248, 248, 248, 0.08) inset;
  transition: transform 500ms var(--ease-out), border-color 400ms var(--ease-out), background-color 400ms var(--ease-out), box-shadow 500ms var(--ease-out);
}
.journal-card { display: flex; }
.journal-card-link:hover {
  transform: translateY(-4px);
  border-color: rgba(248, 248, 248, 0.28);
  background-color: rgba(248, 248, 248, 0.055);
  box-shadow: 0 1px 0 rgba(248, 248, 248, 0.1) inset, 0 30px 50px -34px rgba(0, 0, 0, 0.85);
}
.journal-cover {
  position: relative;
  display: block;
  overflow: hidden;
}
/* Hover zoom on the `scale` property, not `transform`, so it composes with
   the GSAP entrance (main.js) instead of fighting its inline transform. */
.journal-cover img { transition: scale 700ms var(--ease-out); }
.journal-card-link:hover .journal-cover img { scale: 1.03; }
.cover-label {
  font-family: var(--mono);
  font-size: clamp(0.5625rem, 3.4cqw, 0.6875rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.55;
}
.cover-word {
  font-family: var(--display);
  font-weight: 900;
  letter-spacing: -0.04em;
  line-height: 0.9;
  font-size: 26cqw;
}
.cover-foot {
  font-family: var(--mono);
  font-size: clamp(0.5625rem, 3.4cqw, 0.6875rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.4;
}
/* Nº 03 — the word crossed out, which is the whole article. */
.cover-trend { background: var(--black); color: var(--paper); }
.cover-trend .cover-word { font-size: 30cqw; margin-bottom: 4cqw; }
.cover-strike {
  position: relative;
  align-self: flex-start;
}
.cover-strike::after {
  content: "";
  position: absolute;
  left: -3%;
  right: -3%;
  top: 50%;
  height: 0.075em;
  background: currentColor;
  transform: rotate(-4deg);
}
/* Nº 02 — the field-notes issue: paper, ruled, quiet. */
.cover-frogs { background: var(--paper); color: var(--ink); border: 1px solid var(--hairline-dark); }
.cover-stack span { display: block; }
/* Nº 01 — the number is the cover. */
.cover-5k { background: #2c2d2d; color: var(--paper); }
.cover-5k .cover-word { font-size: 34cqw; }
.journal-meta {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 1.15rem 1.25rem 1.3rem;
}
.journal-meta h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1.3vw, 1.25rem);
  letter-spacing: -0.01em;
  line-height: 1.22;
  text-wrap: balance;
}
.journal-excerpt {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--paper-60);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Always on: the link is the card's CTA. Hover only brightens its rule. */
.journal-read {
  align-self: flex-start;
  margin-top: auto;
  padding-top: 1.1rem;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(248, 248, 248, 0.45);
  transition: text-decoration-color 300ms var(--ease-out);
}
.journal-card-link:hover .journal-read { text-decoration-color: var(--paper); }

/* Bento variant of the shelf (landing): 3-column grid, narrow (1) + wide (2)
   then wide + narrow. Wide cards go cover-left / copy-right; every card keeps
   the same glass and the same four parts. */
.journal-bento { grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 1.4vw, 1.5rem); }
.journal-bento .journal-card.is-wide { grid-column: span 2; }
.journal-bento .journal-card-link { border-radius: 18px; padding: 0.7rem; }
.journal-bento .journal-cover.art { border-radius: 11px; }
.journal-bento .is-wide .journal-card-link { flex-direction: row; gap: clamp(1.25rem, 2.4vw, 2.5rem); }
.journal-bento .is-wide .journal-cover.art { flex: 0 0 50%; aspect-ratio: auto; min-height: 20rem; }
.journal-bento .is-wide .journal-meta { justify-content: center; padding: 1.4rem 1.6rem 1.4rem 0; }
.journal-bento .is-wide .journal-meta h3 { font-size: clamp(1.5rem, 2.1vw, 2.125rem); letter-spacing: -0.025em; line-height: 1.1; }
.journal-bento .is-wide .journal-excerpt { -webkit-line-clamp: 3; font-size: 0.9375rem; margin-top: 0.85rem; }
.journal-bento .journal-meta { padding: 1.15rem 0.6rem 0.6rem; }
.journal-bento .journal-meta h3 { font-size: clamp(1.125rem, 1.35vw, 1.3125rem); }
/* Pill CTA instead of the underlined word. */
.journal-bento .journal-read {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: auto;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--hairline-light);
  border-radius: 999px;
  font-size: 0.8125rem;
  text-decoration: none;
  transition: border-color 300ms var(--ease-out), background-color 300ms var(--ease-out);
}
.journal-bento .journal-read { margin-top: 1.25rem; }
.journal-bento .is-wide .journal-read { margin-top: 1.5rem; }
.journal-bento .journal-read svg { transition: transform 200ms var(--ease-out); }
.journal-bento .journal-card-link:hover .journal-read { border-color: var(--paper); background-color: rgba(248, 248, 248, 0.06); }
.journal-bento .journal-card-link:hover .journal-read svg { transform: translate(1px, -1px); }
@media (max-width: 1180px) {
  .journal-bento { grid-template-columns: repeat(2, 1fr); }
  .journal-bento .journal-card.is-wide { grid-column: span 2; }
}
@media (max-width: 900px) {
  .journal-bento { grid-template-columns: 1fr; gap: 1rem; }
  .journal-bento .journal-card.is-wide { grid-column: auto; }
  .journal-bento .is-wide .journal-card-link { flex-direction: column; gap: 0; }
  .journal-bento .is-wide .journal-cover.art { flex: none; aspect-ratio: 16 / 9; min-height: 0; }
  .journal-bento .is-wide .journal-meta { padding: 1.15rem 0.6rem 0.6rem; }
  .journal-bento .journal-meta h3, .journal-bento .is-wide .journal-meta h3 { font-size: 1.1875rem; letter-spacing: -0.01em; line-height: 1.22; }
  .journal-bento .is-wide .journal-excerpt { -webkit-line-clamp: 2; font-size: 0.875rem; margin-top: 0.5rem; }
}

/* ---------- Contact ---------- */
/* Top padding is the whole Blog→Contact seam now (no hairline), so it is
   sized to land the same gap the other card-to-card seams have. */
.contact {
  padding: clamp(3rem, 6vh, 5rem) 0 clamp(4rem, 8vh, 6rem);
}
/* The closing ask, built as one glass object. On a black ground a backdrop
   blur has almost nothing to work with, so the material comes from the
   hairline, the inset top highlight and a soft monotone wash — the blur only
   catches the section's own radial and the grain. */
.contact-card {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border: 1px solid var(--hairline-light);
  border-radius: 16px;
  padding: clamp(2.25rem, 5vw, 4.5rem);
  background-color: rgba(248, 248, 248, 0.04);
  backdrop-filter: blur(18px) saturate(1.05);
  -webkit-backdrop-filter: blur(18px) saturate(1.05);
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.14) inset,
    0 40px 90px -60px rgba(0, 0, 0, 0.95);
}
.contact-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(85% 70% at 10% 0%, rgba(248, 248, 248, 0.1) 0%, rgba(248, 248, 248, 0) 58%),
    radial-gradient(70% 60% at 100% 100%, rgba(248, 248, 248, 0.055) 0%, rgba(248, 248, 248, 0) 62%);
}
/* minmax(0, 1fr), not 1fr: a bare 1fr track keeps an auto min-content floor,
   and at phone width the twelve floors added up to more than the card's inner
   width — the grid overflowed and the card's overflow:hidden clipped the body
   copy mid-word. */
/* Open application form in the contact card (owner, 2026-08-24, after
   inspiration/cta.PNG): heading and one line, then the fields as pills —
   name / email, budget / launch, the project textarea full width, and a
   full-width paper "Send application" pill. */
.contact-head h2 {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.6rem, 5.6vw, 4.9rem);
  line-height: 0.98;
  letter-spacing: -0.025em;
}
.contact-head p {
  margin-top: 1.5rem;
  max-width: 34rem;
  color: var(--paper-60);
}
.contact-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.9rem;
  margin-top: clamp(2.25rem, 5vh, 3.25rem);
}
.cf-half { grid-column: span 1; }
.cf-full { grid-column: 1 / -1; }
.cf-field { display: block; position: relative; }
/* Placeholders carry the label visually, as in the reference; the real
   label stays for screen readers. */
.cf-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.cf-field input,
.cf-field select,
.cf-field textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  font-weight: 500;
  color: var(--paper);
  /* Solid, not a tint (owner, 2026-09-22): the fireworks behind the glass must never show through a field. */
  background-color: #1A1A1A;
  border: 1px solid rgba(248, 248, 248, 0.1);
  border-radius: 999px;
  padding: 1.05rem 1.5rem;
  outline: none;
  transition: border-color 250ms var(--ease-out), background-color 250ms var(--ease-out);
}
.cf-field textarea {
  border-radius: 1.5rem;
  resize: vertical;
  min-height: 9rem;
  line-height: 1.5;
}
.cf-field input::placeholder,
.cf-field textarea::placeholder { color: var(--paper-40); }
/* Custom dropdown: the pill is the container. Open, it rounds off into a
   panel and its options unfold beneath the trigger inside the same shape —
   origin-aware, nothing floats. Heights are driven by GSAP (contact-form.js). */
.cf-drop {
  position: relative;
  align-self: start;
  border-radius: 999px;
  border: 1px solid rgba(248, 248, 248, 0.1);
  background-color: #1A1A1A;   /* solid, as the fields */
  /* The panel folds down from this pill's bottom edge — perspective lives
     here so the hinge reads in 3D. */
  perspective: 900px;
  transition: border-color 250ms var(--ease-out), background-color 250ms var(--ease-out);
}
.cf-drop:hover { border-color: rgba(248, 248, 248, 0.2); }
.cf-drop.is-open {
  border-color: rgba(248, 248, 248, 0.35);
  background-color: #1F1F1F;
  z-index: 5;
}
.cf-drop.is-invalid { border-color: rgba(248, 248, 248, 0.7); }
.cf-drop-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.05rem 1.35rem 1.05rem 1.5rem;
  font: inherit;
  font-size: 1rem;
  font-weight: 500;
  text-align: left;
  color: var(--paper-40);
  background: none;
  border: none;
  cursor: pointer;
  transition: color 250ms var(--ease-out);
}
.cf-drop-btn:focus-visible { outline: none; }
.cf-drop:has(.cf-drop-btn:focus-visible) { border-color: rgba(248, 248, 248, 0.55); }
.cf-drop.has-value .cf-drop-btn { color: var(--paper); }
.cf-drop-btn svg { flex: none; color: var(--paper-60); transition: transform 320ms var(--ease-out); }
.cf-drop.is-open .cf-drop-btn svg { transform: rotate(180deg); }
/* Overlay panel: floats in front of the form (the form stays compact),
   hinged at the top so it folds open like a flap. GSAP drives the fold. */
.cf-drop-list {
  position: absolute;
  top: calc(100% + 0.45rem);
  left: 0;
  right: 0;
  list-style: none;
  margin: 0;
  padding: 0.4rem;
  border-radius: 1.25rem;
  border: 1px solid rgba(248, 248, 248, 0.14);
  background-color: rgba(22, 22, 22, 0.96);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: 0 24px 50px -24px rgba(0, 0, 0, 0.9);
  transform-origin: top center;
}
.cf-drop-list li {
  padding: 0.8rem 1rem;
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--paper-60);
  cursor: pointer;
  transition: background-color 200ms var(--ease-out), color 200ms var(--ease-out);
}
.cf-drop-list li:hover,
.cf-drop-list li:focus-visible { background-color: rgba(248, 248, 248, 0.08); color: var(--paper); outline: none; }
.cf-drop-list li[aria-selected="true"] { background-color: var(--paper); color: var(--ink); }
.cf-field input:hover,
.cf-field select:hover,
.cf-field textarea:hover { border-color: rgba(248, 248, 248, 0.2); }
.cf-field input:focus,
.cf-field select:focus,
.cf-field textarea:focus {
  border-color: rgba(248, 248, 248, 0.55);
  background-color: #1F1F1F;
}
.cf-submit {
  grid-column: 1 / -1;
  margin-top: 0.35rem;
  font: inherit;
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  background-color: var(--paper);
  border: none;
  border-radius: 999px;
  padding: 1.15rem 2rem;
  cursor: pointer;
  transition: background-color 250ms var(--ease-out), transform 160ms var(--ease-out);
}
.cf-submit:hover { background-color: #ffffff; }
.cf-submit:active { transform: scale(0.985); }
.cf-submit:focus-visible { outline: 2px solid var(--paper); outline-offset: 4px; }
.cf-note {
  grid-column: 1 / -1;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--paper-40);
  text-align: center;
}
.cf-note a { color: var(--paper-60); border-bottom: 1px solid var(--hairline-light); }
.cf-note a:hover { color: var(--paper); border-bottom-color: var(--paper); }
@media (max-width: 700px) {
  .contact-form { grid-template-columns: 1fr; }
  /* "When do you want to launch?" has to fit a 340px pill with its chevron. */
  .cf-drop-btn { font-size: 0.875rem; padding: 1rem 1.1rem 1rem 1.2rem; gap: 0.6rem; }
}
/* The button leads and the address follows it — one obvious action, with the
   quieter way in kept alongside for anyone who would rather just write. */
.contact-actions {
  margin-top: clamp(2rem, 4vh, 2.75rem);
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 2.5vw, 2rem);
  flex-wrap: wrap;
}
.contact-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  padding: 1.1rem 2.15rem;
  border-radius: 999px;
  background-color: var(--paper);
  color: var(--ink);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.5) inset,
    0 16px 34px -16px rgba(0, 0, 0, 0.7);
  transition: gap 250ms var(--ease-out), transform 160ms var(--ease-out),
              background-color 250ms var(--ease-out), box-shadow 250ms var(--ease-out);
}
.contact-cta svg { flex: none; transition: transform 250ms var(--ease-out); }
.contact-cta:hover {
  gap: 1rem;
  background-color: #ffffff;
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.5) inset,
    0 20px 40px -16px rgba(0, 0, 0, 0.8);
}
.contact-cta:hover svg { transform: translate(2px, -2px); }
.contact-cta:active { transform: scale(0.97); }
.contact-email {
  font-weight: 600;
  font-size: 1.0625rem;
  color: var(--paper-60);
  border-bottom: 1px solid var(--hairline-light);
  padding-bottom: 0.15rem;
  transition: color 300ms var(--ease-out), border-color 300ms var(--ease-out);
}
.contact-email:hover { color: var(--paper); border-bottom-color: var(--paper); }
.contact-side {
  grid-column: 9 / 13;
  border-left: 1px solid var(--hairline-light);
  padding-left: clamp(1.5rem, 2.5vw, 2.5rem);
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
  align-self: start;
}
/* Headings, not fine print — same rule as every other label on the site. */
.contact-side dt {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.01em;
  color: var(--paper);
  margin-bottom: 0.3rem;
}
.contact-side dd {
  font-size: 1rem;
  font-weight: 500;
  color: var(--paper-60);
}
.contact-side dd a { border-bottom: 1px solid var(--hairline-light); }
.contact-side dd a:hover { border-color: var(--paper); }

/* ---------- Footer ---------- */
.contact { padding-bottom: 0; }
.footer {
  padding: 3rem 0 2.5rem;
  border-top: 1px solid var(--hairline-light);
  margin-top: clamp(4rem, 8vh, 6rem);
}
/* Giant wordmark closing the page — sits fully on the page, not cropped off it.
   The SVG carries matched internal margins, so no padding is needed here: any
   added below it makes the mark sit low rather than centred in its own band. */
.footer-stamp {
  overflow: hidden;
  margin-top: clamp(2rem, 5vh, 4rem);
}
.footer-stamp img {
  width: 100%;
  height: auto;
  display: block;
  opacity: 0.96;
}
.footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
}
.footer-logo img { height: 16px; width: auto; }
.footer-links {
  display: flex;
  gap: 1.75rem;
  font-size: 0.875rem;
  color: var(--paper-60);
}
.footer-links a:hover { color: var(--paper); }
.footer small,
.site-footer small {
  font-size: 0.8125rem;
  color: var(--paper-40);
}
/* Inner pages end on paper and have no .contact section to sit inside, so the
   footer carries its own ground. The cropped-wordmark stamp stays homepage-only. */
.site-footer {
  background: var(--black);
  color: var(--paper);
  padding: clamp(3rem, 6vh, 4.5rem) 0 0;
}
/* One row is too tight below ~640px — the logo collides with the links. */
@media (max-width: 640px) {
  .footer-inner {
    flex-direction: column;
    align-items: flex-start;
    gap: 1.75rem;
  }
  .footer-links { gap: 1.25rem; }
}

/* ---------- Mega footer (homepage) ---------- */
.footer-mega { margin-top: clamp(4rem, 8vh, 6rem); }
/* Landor-style close (owner, 2026-08-24) — centred white wordmark over the
   © line, then a base row: legal stack bottom-left, social icons
   bottom-right. One container-aligned hairline at the top, nothing else. */
.footer-center {
  position: relative;
  padding: clamp(3.5rem, 7vh, 5rem) 0 clamp(3rem, 6vh, 4.5rem);
}
/* Same hairline as the section seams, on the footer's top edge. */
.footer-center::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: rgba(248, 248, 248, 0.26);
}
/* The CTA pair reuses the hero pills (paper fill + outline) — same liquid
   hover, same black ground. Anchored to the left rail, on the same edge as
   the legal stack below, so the footer reads as one composed column. */
.footer-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
}
/* London clock — set like the legal links, stacked over the socials on the
   right rail. Tabular digits keep the seconds from jittering as they tick. */
.footer-right-col { display: flex; flex-direction: column; align-items: flex-end; gap: 1rem; justify-self: end; }
.footer-clock {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--paper-40);
}
.footer-copy {
  font-size: 0.8125rem;
  line-height: 1.7;
  color: var(--paper-40);
  text-align: center;
}
/* Legal stack left, © centred, socials right — one quiet row. */
.footer-base {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: 1.5rem 3rem;
  padding: 0 0 clamp(2rem, 4vh, 3rem);
}
.footer-base .footer-social { justify-self: end; }
.footer-legal-links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
}
.footer-legal-links a {
  font-size: 0.8125rem;
  color: var(--paper-40);
  transition: color 250ms var(--ease-out);
}
.footer-legal-links a:hover { color: var(--paper); }
.footer-social {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}
.footer-social a {
  display: block;
  color: var(--paper-60);
  transition: color 250ms var(--ease-out);
}
.footer-social a:hover { color: var(--paper); }
.footer-social svg { display: block; }
/* The last word: the wordmark set huge, full-bleed viewport edge to edge,
   closing the page — the footer's one bold move. Lives outside .wrap. */
.footer-giant {
  display: block;
  width: 100%;
  height: auto;
  /* Reserve the final height before the SVG loads, so Lenis/ScrollTrigger
     measure the true page bottom and the mark is never cut off. */
  aspect-ratio: 1757.81 / 385.31;
  margin-top: clamp(2.5rem, 6vh, 4.5rem);
  padding-bottom: clamp(1rem, 2.5vh, 2rem);
}
@media (max-width: 700px) {
  .footer-base { grid-template-columns: 1fr; justify-items: start; gap: 1.75rem; }
  .footer-base .footer-copy { text-align: left; }
  .footer-right-col { align-items: flex-start; justify-self: start; }
  .footer-base .footer-social { justify-self: start; }
}

/* ---------- Footer (owner, 2026-09-07, from footer-variations.html V4b) ----------
   The one-card layout without the card: the page already stacks three glass
   slabs (services, blog, the form), so the footer separates by being bare -
   one hairline on top, then the C + the ask + pill, three columns with bold
   display headings over quiet links, a second hairline and the (c) row with
   the clock and the social icons. Under it the wordmark, ghosted to 14%
   paper and ~72% showing, cut by the page's end. */
.footer-plain { overflow: hidden; }
/* Three classes: outranks the inner-page `.site-footer.footer-mega { padding: 0 }` reset below. */
.site-footer.footer-mega.footer-plain { padding: 0; }
.contact .footer-plain { margin-top: 0; }
/* Owner (2026-09-07): more air - two pills under the ask (Start a project /
   Contact us = mailto), Studio + Legal pushed right, wider gaps all round. */
/* No top rule (2026-09-12): the contact card's bottom edge sits directly
   above, so a hairline here doubled it. One rule in the footer, above the
   base row, at the page's seam weight. */
.footer-grid {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); gap: 3.5rem 4rem;
  padding-top: clamp(4rem, 8vh, 6rem);
}
/* Wordmark, not the symbol (owner, 2026-09-12). Tight crop, so height sets the size. */
.footer-brand img { height: 1.375rem; width: auto; display: block; }
.footer-brand p { margin-top: 1.25rem; color: var(--paper-60); max-width: 22rem; line-height: 1.55; font-size: 1rem; }
.footer-brand .footer-actions { margin-top: 2.25rem; }
.footer-col h4 { font-family: var(--display); font-weight: 700; font-size: 1.125rem; letter-spacing: -0.01em; color: var(--paper); }
.footer-col ul { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid; gap: 0.75rem; }
.footer-col a { font-size: 0.9375rem; font-weight: 400; color: var(--paper-60); transition: color 250ms var(--ease-out); }
.footer-col a:hover { color: var(--paper); }
.footer-base-row {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem 2rem; flex-wrap: wrap;
  margin-top: clamp(3.5rem, 7vh, 5.5rem); padding-top: 1.75rem; border-top: 1px solid rgba(248, 248, 248, 0.26);
  font-size: 0.8125rem; color: var(--paper-40);
}
.footer-base-row .footer-right-col { flex-direction: row; align-items: center; gap: 1.75rem; }
.footer-plain .footer-clock { font-size: 0.75rem; }
/* The clip is the sink: its height is 72% of the wordmark's rendered height
   (width x the SVG's own ratio), so the cut sits at the same place on every
   screen. The image keeps its aspect-ratio reserve for the scroll measure. */
.footer-giant-clip { height: calc(0.72 * 100vw * 385.31 / 1757.81); overflow: hidden; margin-top: clamp(2.5rem, 6vh, 4.5rem); }
.footer-plain .footer-giant { margin-top: 0; padding-bottom: 0; opacity: 0.14; }
@media (max-width: 860px) { .footer-grid { grid-template-columns: 1fr 1fr; gap: 3rem 2rem; } .footer-brand { grid-column: 1 / -1; } }
/* Phones: Studio and Legal share a row. */
@media (max-width: 480px) {
  .footer-grid { gap: 2.5rem 1.5rem; }
  .footer-brand .footer-actions { gap: 0.75rem; }
  .footer-base-row { flex-direction: column; align-items: flex-start; gap: 1rem; }
  .footer-base-row .footer-right-col { justify-self: start; }
}

/* ---------- Error pages (404 / 303) ----------
   The number is the page: set huge and bold on paper, one line under it, and
   a single pill home. Nothing else. */
.error-page {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  background: var(--black);
  color: var(--paper);
  padding: clamp(7rem, 14vh, 10rem) 0 clamp(4rem, 8vh, 6rem);
  text-align: center;
}
.error-page .wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
}
.error-code {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(7rem, 26vw, 24rem);
  line-height: 0.85;
  letter-spacing: -0.06em;
}
.error-page h1 {
  margin-top: clamp(1.5rem, 3vh, 2.25rem);
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.error-line {
  margin-top: 0.9rem;
  max-width: 34rem;
  color: var(--paper-60);
}
.error-home {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: clamp(2rem, 4vh, 2.75rem);
  padding: 1rem 2rem;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
  transition: gap 250ms var(--ease-out), transform 160ms var(--ease-out);
}
.error-home svg { flex: none; transition: transform 250ms var(--ease-out); }
.error-home:hover { gap: 1rem; }
.error-home:hover svg { transform: translate(2px, -2px); }
.error-home:active { transform: scale(0.97); }

/* ---------- Cookie pop-up ----------
   A small dark card in the bottom-left, on every ground. Slides up once;
   the footer's "Cookie settings" brings it back. */
.cookie-banner {
  position: fixed;
  left: clamp(1rem, 2vw, 1.5rem);
  bottom: clamp(1rem, 2vw, 1.5rem);
  z-index: 60;
  width: min(22rem, calc(100vw - 2rem));
  padding: 1.25rem 1.35rem 1.35rem;
  border-radius: 1.25rem;
  border: 1px solid rgba(248, 248, 248, 0.14);
  background: rgba(18, 18, 18, 0.96);
  color: var(--paper);
  box-shadow: 0 24px 50px -24px rgba(0, 0, 0, 0.9);
  opacity: 0;
  transform: translateY(0.75rem) scale(0.98);
  transition: opacity 320ms var(--ease-out), transform 420ms var(--ease-out);
}
.cookie-banner.is-in { opacity: 1; transform: none; }
.cookie-text {
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--paper-60);
}
.cookie-text a {
  color: var(--paper);
  border-bottom: 1px solid rgba(248, 248, 248, 0.25);
  transition: border-color 250ms var(--ease-out);
}
.cookie-text a:hover { border-bottom-color: var(--paper); }
.cookie-actions { display: flex; gap: 0.5rem; margin-top: 1rem; }
.cookie-btn {
  font: inherit;
  font-size: 0.9rem;
  font-weight: 700;
  padding: 0.6rem 1.15rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 200ms var(--ease-out), border-color 200ms var(--ease-out), transform 160ms var(--ease-out);
}
.cookie-btn:active { transform: scale(0.96); }
.cookie-accept { background: var(--paper); color: var(--ink); border: 1px solid var(--paper); }
.cookie-accept:hover { background: #ffffff; }
.cookie-decline { background: transparent; color: var(--paper); border: 1px solid rgba(248, 248, 248, 0.25); }
.cookie-decline:hover { border-color: var(--paper); }
@media (prefers-reduced-motion: reduce) {
  .cookie-banner { transition: none; }
}

/* ---------- Legal pages (privacy / terms / cookies) ---------- */
.legal-page {
  background: var(--paper);
  color: var(--ink);
  padding: clamp(8rem, 15vh, 11rem) 0 clamp(5rem, 10vh, 7rem);
}
.legal-body { max-width: 44rem; }
.legal-page h1 {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.4rem, 5vw, 3.5rem);
  letter-spacing: -0.02em;
  line-height: 1.02;
  margin-bottom: 0.9rem;
}
.legal-updated {
  display: block;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(30, 31, 31, 0.5);
  margin-bottom: 3rem;
}
.legal-page h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.3rem;
  letter-spacing: -0.01em;
  margin: 2.6rem 0 0.8rem;
}
.legal-page p,
.legal-page li {
  font-size: 1rem;
  line-height: 1.68;
  color: rgba(30, 31, 31, 0.82);
}
.legal-page p { margin-bottom: 0.9rem; }
.legal-page ul {
  list-style: none;
  padding: 0;
  margin: 0 0 0.9rem;
}
.legal-page li { padding-left: 1.1rem; position: relative; margin-bottom: 0.45rem; }
.legal-page li::before { content: "—"; position: absolute; left: 0; color: rgba(30, 31, 31, 0.4); }
.legal-page a { border-bottom: 1px solid rgba(30, 31, 31, 0.25); }
.legal-page a:hover { border-color: var(--ink); }

/* ---------- Work gallery page ---------- */
/* Work index sits on flat black (owner, 2026-08-25). The gallery flips its
   own tokens at the root so every grey below inverts with it. Blog, About
   and Services flip the same way (owner, 2026-08-26): every page is black. */
.gallery.zone-black,
.about-hero.zone-black,
.ab-hero.zone-black {
  background: var(--black);
  color: var(--paper);
  --ink: #F8F8F8;
  --grey-40: rgba(248, 248, 248, 0.4);
  --grey-60: rgba(248, 248, 248, 0.6);
  --hairline-dark: rgba(248, 248, 248, 0.16);
}
.gallery {
  background: var(--paper);
  color: var(--ink);
  padding: clamp(9rem, 17vh, 13rem) 0 clamp(6rem, 12vh, 9rem);
}
/* Editorial split: huge headline left, intro right, bottom-aligned — the
   intro reads as a deliberate counterweight instead of a caption tucked
   under the h1. */
.gallery-head {
  margin-bottom: clamp(3rem, 6vh, 4.5rem);
  display: grid;
  grid-template-columns: 1fr minmax(0, 30rem);
  align-items: end;
  gap: 1.5rem clamp(3rem, 8vw, 8rem);
}
.gallery-head h1 {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.7rem, 5.6vw, 5rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
}
.gallery-head p {
  font-size: clamp(1rem, 1.4vw, 1.125rem);
  line-height: 1.6;
  color: var(--grey-60);
  text-wrap: balance;
  /* Optical alignment: pull the last line down to the h1's baseline rather
     than the descender box. */
  margin-bottom: 0.45em;
}
@media (max-width: 760px) {
  .gallery-head { grid-template-columns: 1fr; align-items: start; }
  .gallery-head p { margin-bottom: 0; }
}
/* Editorial rhythm: a wide feature, then a landscape/square pair, then an
   offset close. Each tile's aspect matches its generated cover exactly, so the
   browser never crops a wrong-shaped image. */
.gallery-grid {
  /* Fills the .wrap — the head above it spans the full measure, so the grid
     has to as well (a 76rem cap here left it sitting in the left two-thirds
     of the 100rem container). */
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  align-items: start;
  gap: clamp(2.75rem, 5vh, 4.25rem) clamp(1.25rem, 2.5vw, 2rem);
}
.gallery-item.feature { grid-column: span 12; }
.gallery-item.wide    { grid-column: span 7; }
.gallery-item.narrow  { grid-column: span 5; }
.gallery-item.offset  { grid-column: 3 / span 8; }
.gallery-item.feature .gallery-media { aspect-ratio: 16 / 9; }
.gallery-item.wide    .gallery-media { aspect-ratio: 1.45; }
.gallery-item.narrow  .gallery-media { aspect-ratio: 1 / 1; }
.gallery-item.offset  .gallery-media { aspect-ratio: 4 / 3; }
.gallery-item a { display: block; }
.gallery-media {
  overflow: hidden;
  background: rgba(30, 31, 31, 0.05);
}
.gallery-media img,
.gallery-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 900ms var(--ease-drawer);
}
.gallery-item a:hover .gallery-media img,
.gallery-item a:hover .gallery-media video { transform: scale(1.035); }
.gallery-meta { padding-top: 1.15rem; }
.gallery-meta h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.2rem, 1.9vw, 1.5rem);
  letter-spacing: -0.015em;
}
.gallery-lines { margin-top: 0.4rem; }
.gallery-lines > p {
  max-width: 52ch;
  font-size: 0.9375rem;
  line-height: 1.5;
}
.gallery-desc { color: var(--grey-60); }
/* Disciplines sit beneath the description — the description stays put. They
   hold their space in flow at all times, so revealing them shifts nothing. */
.gallery-disciplines {
  margin-top: 0.4rem;
  color: var(--ink);
  font-weight: 600;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 260ms var(--ease-out), transform 260ms var(--ease-out);
}
.gallery-item a:hover .gallery-disciplines { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .gallery-disciplines { transform: none; transition: opacity 260ms var(--ease-out); }
  .gallery-item a:hover .gallery-disciplines { transform: none; }
}
/* Cursor-follow "View" pill. The wrapper is moved by JS with no transition so
   it tracks the pointer exactly; the inner pill owns the fade/scale. The real
   cursor stays visible — this rides alongside it rather than replacing it. */
.gallery-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 120;
  pointer-events: none;
  will-change: transform;
}
.gallery-cursor span {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 1.1rem;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.9);
  transition: opacity 200ms var(--ease-out), transform 280ms var(--ease-out);
}
.gallery-cursor.is-on span { opacity: 1; transform: translate(-50%, -50%) scale(1); }
/* Inverts per the zone under the pointer (set by gallery-cursor.js), not the
   zone under the nav — the two differ for most of a scroll. */
.gallery-cursor.is-inverted span { background: var(--paper); color: var(--black); }
/* Native cursor gives way to the pill while over a tile (pointer devices only —
   never on touch, where there is no hover and no pill). */
@media (hover: hover) and (pointer: fine) {
  /* The pill replaces the pointer over a tile (owner, 2026-08-26). It only
     works because .is-inverted keeps it visible on black — an ink pill on
     the black Work zone once read as "no cursor at all". */
  /* Hidden from the body only while the pill is on (gallery-cursor.js toggles
     body.gc-on with it), never from the tiles: Chrome keeps a scrolled-away
     tile's cursor style until the mouse moves, which left no cursor at all. */
  body.gc-on, body.gc-on * { cursor: none; }
  /* The pill IS the view affordance on pointer devices — the in-card
     "View project" chip would say it twice. It stays for touch, where
     there is no pill. */
  .orbit-node-view { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .gallery-cursor span { transition: opacity 200ms var(--ease-out); transform: translate(-50%, -50%); }
  .gallery-cursor.is-on span { transform: translate(-50%, -50%); }
}
@media (max-width: 900px) {
  .gallery-item.feature,
  .gallery-item.wide,
  .gallery-item.narrow,
  .gallery-item.offset { grid-column: span 12; }
  /* No hover on touch — the disciplines stay visible under the description. */
  .gallery-disciplines { opacity: 1; transform: none; }
}

/* ---------- About page ---------- */
.about-hero {
  background: var(--paper);
  color: var(--ink);
  padding: clamp(9rem, 17vh, 13rem) 0 clamp(4rem, 8vh, 6rem);
}
.about-hero h1 {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.7rem, 5.6vw, 5.5rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  max-width: 20ch;
}
.about-hero p {
  margin-top: 2.25rem;
  max-width: 38rem;
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  font-weight: 500;
  line-height: 1.55;
  color: var(--grey-60);
}
.offer-list { display: flex; flex-direction: column; }
.offer-block {
  display: grid;
  grid-template-columns: 4rem 1fr 1fr;
  gap: 2rem;
  padding: clamp(2.5rem, 5vh, 3.5rem) 0.5rem;
  border-top: 1px solid var(--hairline-light);
}
.offer-block:last-child { border-bottom: 1px solid var(--hairline-light); }
.offer-block .num {
  font-family: var(--mono);
  font-size: 0.875rem;
  opacity: 0.45;
  padding-top: 0.5rem;
}
.offer-block h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  letter-spacing: -0.015em;
  margin-bottom: 0.9rem;
}
.offer-price {
  display: block;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--paper-40);
  margin-bottom: 0.9rem;
}
.offer-block > div > p { max-width: 26rem; color: var(--paper-60); }
.offer-block ul {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  font-weight: 600;
  padding-top: 0.5rem;
}
.offer-block ul li::before { content: "— "; color: var(--paper-40); }

/* ---------- Services page ---------- */
/* The cards on the landing page deep-link into these blocks; the fixed nav
   would otherwise sit on top of whichever heading you arrived at. */
.offer-block[id] { scroll-margin-top: clamp(5.5rem, 11vh, 7.5rem); }
.services-cta-note {
  margin-top: 1.35rem;
  max-width: 46ch;
  color: var(--grey-60);
}
@media (max-width: 900px) {
  .offer-block { grid-template-columns: 2.5rem 1fr; }
  .offer-block ul { grid-column: 2; }
}

/* ---------- Case study pages ---------- */
.case {
  background: var(--paper);
  color: var(--ink);
  padding-top: clamp(8rem, 15vh, 11rem);
}
/* Sits inline with the title, not floating above it — a distinct return
   affordance rather than relying on the browser's own back button, but set
   against the name it's returning from rather than the page edge. */
.case-heading {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2rem);
  margin-bottom: clamp(2rem, 4vh, 3rem);
}
.case-back {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  border: 1.5px solid var(--hairline-dark);
  background: var(--paper);
  color: var(--ink);
  transition: background-color 220ms var(--ease-out), border-color 220ms var(--ease-out),
              color 220ms var(--ease-out), transform 160ms var(--ease-out);
}
.case-back svg { width: 16px; height: 16px; transition: transform 200ms var(--ease-out); }
.case-back:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.case-back:hover svg { transform: translateX(-2px); }
.case-back:active { transform: scale(0.95); }
.case-title {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.9rem, 6.5vw, 6rem);
  letter-spacing: -0.03em;
  line-height: 1;
}
.case-hero img,
.case-hero video,
.case-media img,
.case-media video {
  width: 100%;
  height: auto;
  display: block;
}
/* A smaller, columned intro — the hero video sits at real size on the left
   rather than full-bleed, with the About copy wrapping it on the right
   instead of stacking underneath. An alternative to .case-hero + .case-about
   for a case study where the opening asset is a loop, not a banner shot. */
.case-intro {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
}
.case-intro-media {
  max-width: 420px;
  justify-self: start;
  border-radius: 14px;
  overflow: hidden;
  background: rgba(30, 31, 31, 0.05);
}
.case-intro-media video {
  width: 100%;
  height: 100%;
  display: block;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.case-intro-copy .case-facts { margin-top: clamp(1.5rem, 3vh, 2.25rem); }
.case-about {
  margin-top: clamp(2rem, 4vh, 3rem);
  background: rgba(30, 31, 31, 0.05);
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: clamp(2rem, 4vw, 4rem);
  padding: clamp(1.75rem, 3.5vw, 3rem);
}
.case-about h2,
.case-intro-copy h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.4rem, 2.2vw, 1.75rem);
  margin-bottom: 1rem;
}
.case-about p,
.case-intro-copy p {
  max-width: 32rem;
  color: var(--grey-60);
}
.case-facts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem 2rem;
  align-content: start;
}
/* Same treatment as .work-detail-facts — the case studies carry the identical
   Sector / Scope / Year / Status pairs and must not drift from it. */
.case-facts dt {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 0.25rem;
}
.case-facts dd { font-weight: 500; color: var(--grey-60); }
.case-narrative {
  padding: clamp(5rem, 10vh, 8rem) 0 clamp(2rem, 4vh, 3rem);
}
.case-narrative p {
  max-width: 40rem;
  margin-inline: auto;
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  font-weight: 500;
  line-height: 1.6;
}
.case-section { padding: clamp(3.5rem, 7vh, 5.5rem) 0 clamp(2.25rem, 4vh, 3rem); }
.case-section h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  letter-spacing: -0.015em;
  margin-bottom: 1.25rem;
}
.case-section p {
  max-width: 38rem;
  color: var(--grey-60);
}
.case-section p + p { margin-top: 1.25rem; }
.case-media { display: grid; gap: clamp(1rem, 2vw, 1.5rem); }
.case-media + .case-media { margin-top: clamp(1rem, 2vw, 1.5rem); }
.case-media.two { grid-template-columns: 1fr 1fr; }
/* Discipline the grid: 2-up tiles at 4:3, full rows at 16:9 — portrait
   mockups crop rather than towering over the page. */
.case-media.two img { aspect-ratio: 4 / 3; object-fit: cover; }
.case-media:not(.two) img,
.case-media:not(.two) video { aspect-ratio: 16 / 9; object-fit: cover; }
/* Device mockups are rendered on the page's own paper (#F8F8F8) with only
   their shadows, so the clip has no visible edge — nothing to frame here. */
.case-media.devices video { background: var(--paper); }
.case-hero img, .case-hero video { aspect-ratio: 16 / 8; object-fit: cover; }
/* ---------- Case study, stack variant (Patch) ----------
   Black ground, copy once at the top, then the work itself: image after
   image at the full container width and its own aspect — nothing cropped,
   no section headings between shots. The white-ground renders (devices,
   grid) simply read as bright blocks in the stack. Scoped so the other case
   pages keep their paper layout. */
.case.case-stack {
  background: var(--black);
  color: var(--paper);
  padding-top: clamp(8rem, 15vh, 11rem);
}
.case-stack .case-back {
  border-color: var(--hairline-light);
  background: transparent;
  color: var(--paper);
}
.case-stack .case-back:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }
.case-stack .case-title { font-size: clamp(3.4rem, 9vw, 9rem); letter-spacing: -0.04em; }
.case-stack .case-heading { margin-bottom: clamp(2.5rem, 5vh, 4rem); }
.case-stack-intro {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: clamp(2rem, 6vw, 6rem);
  align-items: start;
  padding-bottom: clamp(4rem, 8vh, 6rem);
}
.case-stack-statement {
  max-width: 34em;
  font-size: clamp(1.25rem, 1.9vw, 1.75rem);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
/* Guideline actions: sit under the statement, before the shots — the reader
   has just been told what the brand is and can open the system itself. The
   interactive build needs a wide screen and a pointer, so that pill is desktop
   only; the PDF stays everywhere. */
.case-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  margin-top: clamp(1.75rem, 3vh, 2.5rem);
}
.case-actions .hero-cta,
.case-actions .hero-secondary { font-size: 1rem; padding-block: 0.85rem; }
.case-actions .hero-secondary { padding-block: calc(0.85rem - 1px); }
.case-actions .roll-label > span {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}
.case-actions .roll-label > span + span { display: flex; }
@media (max-width: 1023px), (pointer: coarse) {
  .case-action-desktop { display: none; }
}
/* Phones only: tablets, laptops and desktops keep the pill. The second query
   catches a phone turned sideways, which is wider than 767px but never tall. */
@media (max-width: 767px), (max-height: 500px) and (pointer: coarse) {
  .case-action-no-phone { display: none; }
}
.case-stack .case-facts { padding-top: 0.35em; }
.case-stack .case-facts dt { color: var(--paper); }
.case-stack .case-facts dd { color: var(--paper-60); }
/* The stack: tight, even gaps; each shot at its own aspect. */
.case-shots {
  display: grid;
  gap: clamp(1rem, 2vw, 1.75rem);
}
/* Chapter blocks inside the stack: a glass slab (contact-card material) that
   sits in the shot grid like a tile, a short line left and one paragraph
   right. A little extra margin so it reads as a pause, not another image. */
.case-stack-copy {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
  gap: clamp(1.5rem, 4vw, 4rem);
  align-items: start;
  margin: clamp(1.5rem, 4vh, 3rem) 0;
  padding: clamp(2.25rem, 4.5vw, 4rem);
  border: 1px solid var(--hairline-light);
  border-radius: 16px;
  background-color: rgba(248, 248, 248, 0.04);
  backdrop-filter: blur(18px) saturate(1.05);
  -webkit-backdrop-filter: blur(18px) saturate(1.05);
  box-shadow:
    0 1px 0 rgba(248, 248, 248, 0.14) inset,
    0 40px 90px -60px rgba(0, 0, 0, 0.95);
}
/* Mark block: the symbol sits in the left column where the heading would,
   heading + paragraph share the right. */
.case-stack-copy.has-mark {
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: center;
  padding: clamp(3rem, 6vw, 5.5rem) clamp(2.25rem, 4.5vw, 4rem);
}
.case-mark {
  width: clamp(12rem, 22vw, 21rem);
  height: auto;
  display: block;
  margin-inline: auto;
}
.case-stack-copy.has-mark h2 {
  font-size: clamp(2.25rem, 4.2vw, 3.75rem);
  max-width: none;
}
.case-stack-copy.has-mark p {
  padding-top: 0;
  margin-top: 1.25rem;
  font-size: clamp(1.0625rem, 1.3vw, 1.25rem);
  color: var(--paper);
  opacity: 0.86;
}
/* Large block (the challenge): heading left, a two-paragraph column right,
   set bigger and in paper so it carries more weight than the chapter breaks. */
.case-stack-copy.is-large {
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  padding: clamp(3rem, 6vw, 5.5rem) clamp(2.25rem, 4.5vw, 4rem);
}
.case-stack-copy.is-large h2 { font-size: clamp(2.25rem, 4.2vw, 3.75rem); }
.case-stack-copy.is-large p {
  padding-top: 0.35em;
  font-size: clamp(1.0625rem, 1.3vw, 1.25rem);
  color: var(--paper);
  opacity: 0.86;
}
.case-stack-copy.is-large p + p { margin-top: 1.25em; padding-top: 0; }
/* Copy pair: a shot and a copy block fused into one slab (the typeface board
   beside the challenge). The image fills the block's height and the shared
   edge is square, so the picture runs straight into the glass. */
.case-copy-pair {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  align-items: stretch;
  margin: clamp(1.5rem, 4vh, 3rem) 0;
}
.case-copy-pair .case-shot { min-height: 0; }
.case-copy-pair .case-shot img {
  height: 100%;
  object-fit: cover;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-radius: 16px 0 0 16px;
}
.case-copy-pair .case-stack-copy {
  grid-template-columns: 1fr;
  gap: 1.75rem;
  margin: 0;
  border-left: 0;
  border-radius: 0 16px 16px 0;
}
.case-copy-pair .case-stack-copy h2 { max-width: none; }
/* Portrait copy pair (a 4:5 post beside its note): the picture keeps its
   whole frame and sets the row height, the copy sits centred in the glass. */
.case-copy-pair.portrait { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); }
.case-copy-pair.portrait .case-shot img { height: auto; aspect-ratio: 4 / 5; }
.case-copy-pair.portrait .case-stack-copy { align-content: center; }
.case-stack-copy h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.75rem, 3.2vw, 3rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  max-width: 12em;
  text-wrap: balance;
}
.case-stack-copy p {
  padding-top: 0.4em;
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.55;
  color: var(--paper-60);
  text-wrap: pretty;
}
.case-shot { margin: 0; }
.case-shot img,
.case-shot video {
  width: 100%;
  height: auto;
  display: block;
  background: #0a0a0a;
  border-radius: 1.25rem;
}
.case-shot figcaption {
  margin-top: 0.85rem;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper-60);
}
.case-shot-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0; /* the tiles touch and read as one slab: only the row's outer corners are rounded */
}
.case-shot-pair .case-shot:first-child img { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.case-shot-pair .case-shot:last-child img { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.case-shot-pair .case-shot:not(:first-child):not(:last-child) img { border-radius: 0; }
/* The one place a crop is allowed: a pair reads as a pair only when the two
   tiles share a height, so both sit at 4:5. */
.case-shot-pair img { aspect-ratio: 4 / 5; object-fit: cover; }
.case-shot-pair.three { grid-template-columns: repeat(3, 1fr); }
/* Tall pair for uncroppable portrait sheets (icon sets): both tiles at 2:3. */
.case-shot-pair.tall img { aspect-ratio: 2 / 3; }
/* 3:4 pair for the slightly squarer portrait shots. */
.case-shot-pair.portrait img { aspect-ratio: 3 / 4; }
/* 16:9 pair for two landscape mockups: native ratio, nothing cropped. */
.case-shot-pair.wide img { aspect-ratio: 16 / 9; }
/* A portrait phone clip on its own row: 4:5 would tower at full width, so it
   sits at ~55% and centred. */
.case-shot-phone video { width: min(100%, 44rem); margin-inline: auto; }
/* Four-up grid: two rows of 16:9 tiles that touch on every side and read as
   one slab; only the slab's outer corners are rounded. Stays 2x2 on phones. */
.case-shot-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; border-radius: 1.25rem; overflow: hidden; }
.case-shot-grid .case-shot img { aspect-ratio: 16 / 9; object-fit: cover; border-radius: 0; }
/* Screens pair: a 16:10 page clip beside a 4:5 phone clip. The columns are
   cut 2:1 so both land on one height at their native ratio, nothing cropped. */
.case-shot-pair.screens { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.case-shot-pair.screens .case-shot:first-child video { aspect-ratio: 16 / 10; border-top-right-radius: 0; border-bottom-right-radius: 0; }
.case-shot-pair.screens .case-shot:last-child video { aspect-ratio: 4 / 5; border-top-left-radius: 0; border-bottom-left-radius: 0; }

/* Interactive palette strip (Patch): the swatch under the cursor widens, the
   rest give way. Same rounded slab silhouette as the old baked PNG. */
.case-palette .palette-strip {
  display: flex;
  aspect-ratio: 16 / 9;
  border-radius: 1.5rem;
  overflow: hidden;
}
.palette-swatch {
  flex: 1 1 0;
  min-width: 0;
  background: var(--c);
  color: #1E1F1F;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-start;
  text-align: left;
  gap: 0.3rem;
  padding: clamp(0.9rem, 1.8vw, 1.8rem);
  border: 0;
  font: inherit;
  cursor: pointer;
  transition: flex-grow 380ms cubic-bezier(0.23, 1, 0.32, 1);
}
.palette-swatch:focus-visible { outline: 2px solid currentColor; outline-offset: -6px; }
.palette-swatch.light-text { color: #F8F8F8; }
.palette-strip:hover .palette-swatch:hover { flex-grow: 2.1; }
.palette-swatch .p-name {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.8;
  white-space: nowrap;
  overflow: hidden;
}
.palette-swatch .p-hex {
  font-size: clamp(1rem, 1.6vw, 1.5rem);
  font-weight: 600;
  white-space: nowrap;
}
@media (max-width: 700px) {
  .case-palette .palette-strip { flex-direction: column; aspect-ratio: auto; height: 34rem; }
  .palette-strip:hover .palette-swatch:hover { flex-grow: 1.8; }
  .palette-swatch { justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .palette-swatch { transition: none; }
}
/* Swatch notes pop-up: a small centred card — the colour as a chip up top,
   name, one line, then Meaning / Psychology. Centred (a modal, not anchored
   to its swatch); enters from 0.96 + fade, never from nothing. */
.swatch-scrim {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(3, 3, 3, 0.55);
  opacity: 0;
  transition: opacity 260ms var(--ease-out);
}
.swatch-scrim.is-open { opacity: 1; }
.swatch-pop {
  position: fixed;
  z-index: 200;
  top: 50%;
  left: 50%;
  width: min(26rem, calc(100vw - 2.5rem));
  max-height: calc(100dvh - 2.5rem);
  overflow: auto;
  border-radius: 1.5rem;
  /* Card ground is transparent: the chip and body each carry their own
     corners, so no paper anti-aliases through behind the colour. */
  background: transparent;
  color: #1E1F1F;
  box-shadow: 0 30px 80px -30px rgba(3, 3, 3, 0.7);
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.96);
  transition: opacity 220ms var(--ease-out), transform 260ms var(--ease-out);
}
.swatch-pop.is-open { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.swatch-pop:focus { outline: none; }
.swatch-pop-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  width: 2.25rem;
  height: 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(248, 248, 248, 0.82);
  border: 0;
  border-radius: 50%;
  color: #1E1F1F;
  cursor: pointer;
  transition: transform 160ms var(--ease-out);
}
.swatch-pop-close:hover { transform: scale(1.06); }
.swatch-pop-close:active { transform: scale(0.94); }
.swatch-pop-chip {
  height: 9.5rem;
  background: var(--c);
  color: #1E1F1F;
  display: flex;
  align-items: flex-end;
  padding: 1.5rem 1.75rem;
  border-radius: 1.5rem 1.5rem 0 0;
}
.swatch-pop-chip.light-text { color: #F8F8F8; }
.swatch-pop-hex {
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.swatch-pop-body {
  padding: 1.5rem 1.75rem 1.75rem;
  background: #F8F8F8;
  border-radius: 0 0 1.5rem 1.5rem;
}
.swatch-pop-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.75rem;
  letter-spacing: -0.02em;
  line-height: 1.05;
}
.swatch-pop-line {
  margin-top: 0.5rem;
  font-size: 1.0625rem;
  font-weight: 500;
  color: var(--grey-60);
}
.swatch-pop-notes {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hairline-dark);
  display: grid;
  gap: 1.1rem;
}
.swatch-pop-notes dt {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.01em;
  margin-bottom: 0.25rem;
}
.swatch-pop-notes dd {
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.55;
  color: var(--grey-60);
}
@media (prefers-reduced-motion: reduce) {
  .swatch-pop { transform: translate(-50%, -50%); transition: opacity 220ms var(--ease-out); }
  .swatch-pop.is-open { transform: translate(-50%, -50%); }
}
.case-stack .case-next { border-top-color: var(--hairline-light); }
.case-stack .case-next .case-next-label { color: var(--paper); }
.case-stack .case-next-card h3 { color: var(--paper); }
.case-stack .case-next-card:hover h3 { color: var(--paper-60); }
.case-stack .case-next-card p { color: var(--paper-60); }
@media (max-width: 900px) {
  .case-stack-intro { grid-template-columns: 1fr; gap: 2.5rem; }
  .case-stack-copy { grid-template-columns: 1fr; gap: 1rem; margin: 1rem 0; padding: 1.75rem 1.5rem; }
  .case-stack-copy p { padding-top: 0; }
  .case-stack-copy.has-mark,
  .case-stack-copy.is-large { grid-template-columns: 1fr; gap: 1.5rem; padding: 2.25rem 1.5rem; }
  .case-mark { width: 9rem; margin-inline: 0; }
  .case-copy-pair, .case-copy-pair.portrait { grid-template-columns: 1fr; margin: 1rem 0; }
  .case-copy-pair .case-shot img { height: auto; border-radius: 16px 16px 0 0; }
  .case-copy-pair .case-stack-copy { margin: 0; border-left: 1px solid var(--hairline-light); border-top: 0; border-radius: 0 0 16px 16px; }
  .case-shot-pair, .case-shot-pair.three, .case-shot-pair.screens { grid-template-columns: 1fr; gap: clamp(1rem, 2vw, 1.75rem); }
  /* Stacked, every tile gets its four corners back; the doubled :nth-child
     outweighs the first/last/middle corner rules above. */
  .case-shot-pair .case-shot:nth-child(n):nth-child(n) img,
  .case-shot-pair.screens .case-shot:nth-child(n):nth-child(n) video { border-radius: 1.25rem; }
}

/* More work: the other three cases side by side, equal — cover, name,
   discipline. Each card is a link; the cover eases up on hover. */
.case-next {
  margin-top: clamp(5rem, 10vh, 8rem);
  border-top: 1px solid var(--hairline-dark);
  padding: clamp(3rem, 6vh, 4.5rem) 0 clamp(4rem, 8vh, 6rem);
}
.case-next .case-next-label {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2rem, 3.5vw, 3rem);
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
  margin-bottom: clamp(1.5rem, 3vh, 2.5rem);
}
.case-next-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1rem, 2vw, 1.75rem); }
.case-next-card { display: block; color: inherit; }
.case-next-card h3 { font-family: var(--display); font-weight: 700; font-size: clamp(1.6rem, 2.4vw, 2.25rem); letter-spacing: -0.025em; line-height: 1.05; margin: 1rem 0 0.35rem; transition: color 300ms var(--ease-out); }
.case-next-card:hover h3 { color: var(--grey-60); }
.case-next-card p { display: inline-flex; align-items: center; gap: 0.4rem; font-weight: 500; color: var(--grey-60); margin: 0; }
.case-next-card p svg { width: 0.8em; height: 0.8em; stroke-width: 1.4; transition: transform 300ms var(--ease-out); }
.case-next-card:hover p svg { transform: translate(0.15em, -0.15em); }
/* Covers are cut 16:9; the tile matches so nothing is cropped at rest. */
.case-next-media { overflow: hidden; aspect-ratio: 16 / 9; }
.case-next-media img,
.case-next-media video { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 700ms var(--ease-out); }
.case-next-card:hover .case-next-media img,
.case-next-card:hover .case-next-media video { transform: scale(1.04); }
@media (max-width: 900px) { .case-next-grid { grid-template-columns: 1fr; gap: 2rem; } }
@media (max-width: 900px) {
  .case-about { grid-template-columns: 1fr; }
  .case-intro { grid-template-columns: 1fr; }
  .case-intro-media { max-width: none; }
  .case-media.two { grid-template-columns: 1fr; }
}

/* ---------- Apply sidebar — glass drawer over a scrim ---------- */
.apply-scrim {
  position: fixed;
  inset: 0;
  z-index: 190;
  background: rgba(3, 3, 3, 0.45);
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
}
.apply-scrim.is-open { opacity: 1; }
/* A column, not a long scroll: the heading block is fixed at the top and only
   the form scrolls, so the submit button is always within reach of the bottom
   of the drawer instead of sitting a screen and a half down the page. */
.apply-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 200;
  width: min(34rem, 100vw);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  isolation: isolate;
  background: rgba(248, 248, 248, 0.9);
  backdrop-filter: blur(22px) saturate(1.15);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  border-left: 1px solid var(--hairline-dark);
  /* Shadow only while open — parked off-canvas it bled a grey gradient onto
     the page's right edge (visible on the paper hero tile on mobile). */
  box-shadow: none;
  color: var(--ink);
  padding: clamp(1.75rem, 4vh, 2.75rem) clamp(1.5rem, 3vw, 2.75rem) 0;
  transform: translateX(102%);
  transition: transform 450ms var(--ease-drawer);
}
.apply-panel.is-open { transform: translateX(0); box-shadow: -40px 0 90px -40px rgba(3, 3, 3, 0.55); }
/* Light raking in from the top-left corner, so the paper reads as a lit sheet
   of glass rather than a flat fill. The only gradient in the drawer. */
.apply-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(85% 45% at 8% 0%, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0) 62%),
    radial-gradient(60% 40% at 100% 100%, rgba(30, 31, 31, 0.05) 0%, rgba(30, 31, 31, 0) 60%);
}
.apply-head { flex: none; padding-right: 3rem; }
.apply-close {
  position: absolute;
  top: 1.4rem;
  right: 1.4rem;
  width: 2.5rem;
  height: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid var(--hairline-dark);
  border-radius: 50%;
  color: var(--ink);
  cursor: pointer;
  transition: background-color 250ms var(--ease-out), color 250ms var(--ease-out), transform 160ms var(--ease-out);
}
.apply-close svg { width: 13px; height: 13px; }
.apply-close:hover { background: var(--ink); color: var(--paper); }
.apply-close:active { transform: scale(0.94); }
.apply-title {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(1.7rem, 2.6vw, 2.15rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.apply-intro {
  margin-top: 0.7rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--grey-60);
}
.apply-intro a {
  color: var(--ink);
  border-bottom: 1px solid var(--grey-40);
  transition: border-color 250ms var(--ease-out);
}
.apply-intro a:hover { border-color: var(--ink); }
/* The only scrolling region in the drawer. overscroll-behavior keeps a flick
   at either end from chaining out to the page behind it. */
.apply-form {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-top: 1.5rem;
  padding-bottom: clamp(1.5rem, 4vh, 2.5rem);
  display: flex;
  flex-direction: column;
  gap: 1.3rem;
}
.apply-field label {
  display: block;
  font-family: var(--display);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 0.15rem;
}
.apply-field input,
.apply-field textarea,
.apply-field select {
  width: 100%;
  font: inherit;
  font-size: 1.0625rem;
  color: var(--ink);
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--grey-40);
  border-radius: 0;
  padding: 0.45rem 0;
  outline: none;
  transition: border-color 250ms var(--ease-out);
}
.apply-field textarea { resize: none; min-height: 3.25rem; }
.apply-field input:focus,
.apply-field textarea:focus { border-bottom-color: var(--ink); }
/* Choice pills — no native select chrome; the picked option fills solid ink. */
.apply-choices { border: none; padding: 0; margin: 0; }
.apply-choices legend {
  display: block;
  font-family: var(--display);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 0.5rem;
  padding: 0;
}
.choice-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.choice input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.choice span {
  display: inline-block;
  padding: 0.55rem 1.15rem;
  border: 1px solid var(--hairline-dark);
  border-radius: 999px;
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  transition: background-color 250ms var(--ease-out), color 250ms var(--ease-out), border-color 250ms var(--ease-out), transform 160ms var(--ease-out);
}
.choice:hover span { border-color: var(--ink); }
.choice span:active { transform: scale(0.96); }
.choice input:checked + span {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}
.choice input:focus-visible + span {
  outline: 1px solid var(--ink);
  outline-offset: 3px;
}
.apply-submit {
  align-self: flex-start;
  margin-top: 0.25rem;
  font: inherit;
  font-weight: 700;
  font-size: 1.0625rem;
  background-color: var(--ink);
  color: var(--paper);
  border: none;
  border-radius: 999px;
  padding: 0.95rem 2.1rem;
  cursor: pointer;
}
.apply-submit:active { transform: scale(0.97); }
.apply-note {
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--grey-40);
}
/* Choice pills tighten up with the rest of the condensed drawer. */
.apply-choices .choice span { padding: 0.45rem 1rem; font-size: 0.9rem; }
@media (prefers-reduced-motion: reduce) {
  .apply-panel, .apply-scrim { transition: none; }
}

/* ---------- Reveal (GSAP adds .in) ---------- */
.reveal { opacity: 0; transform: translateY(38px); }
/* Selected Work comes up further than the rest (owner, 2026-09-12: the standard 38px read too subtle
   after the statement seam). main.js reads the start offset from here and tweens to 0. */
/* :not(.is-revealed) keeps this from out-ranking the landed state, which clears the transform. */
.work .section-head.reveal:not(.is-revealed) { transform: translateY(110px); }
.work .work-note.reveal:not(.is-revealed) { transform: translateY(72px); }
/* Set by main.js once the tween lands, so the element drops off its
   compositing layer and text goes back to grayscale antialiasing. */
.reveal.is-revealed { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  html { scroll-behavior: auto; }
}


/* ---------- Hero — notes board (owner pick, 2026-09-05, hero-variations-19) ----------
   Black ground (owner inverted it the same day). Top board: big chrome C
   with the routes stacked to its right | three blog notes | pill, one
   hairline under it. Field: empty on the right (the intro loop that sat
   there was removed 2026-09-06), the wordmark huge bottom-left, the scroll
   ring bottom-right. The base .hero rules above still apply
   (ground, min-height); these override the centred layout. */
.hero.hero-board {
  display: grid;
  grid-template-rows: auto 1fr;
  align-items: stretch; /* base .hero centres; the field must fill its row */
  padding: 0;
  min-height: 100dvh;
}
.hero-board .board {
  position: relative; z-index: 3;
  display: grid;
  grid-template-columns: auto repeat(3, minmax(0, 1fr)) auto;
  gap: 2rem 3rem;
  align-items: start;
  padding: 1.5rem var(--pad-x) 2.25rem;
  border-bottom: 1px solid rgba(248, 248, 248, 0.26);
}
/* The C stands exactly as tall as the five routes beside it. */
.hero-board .brand { display: flex; align-items: stretch; gap: 1.5rem; margin-right: 1rem; --routes-h: calc(5 * 1.0625rem * 1.6 + 4 * 0.2rem); }
.hero-board .brand .hero-mark { display: block; width: var(--routes-h); height: var(--routes-h); margin: 0; flex: none; }
.hero-board .brand .hero-mark chroma-mark { display: block; width: 100%; height: 100%; }
.hero-board .routes { display: grid; gap: 0.2rem; font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; color: rgba(248, 248, 248, 0.45); }
.hero-board .routes a { transition: color 200ms var(--ease-out); }
.hero-board .routes a[aria-current], .hero-board .routes a:hover { color: var(--paper); }
.hero-board .note { font-size: 0.9375rem; line-height: 1.5; font-weight: 500; color: rgba(248, 248, 248, 0.62); max-width: 18rem; }
/* "Read more" as on the blog cards: Inter, sentence case, an arrow that
   nudges on hover and an underline that draws in. No mono caps here. */
.hero-board .note a { display: flex; width: max-content; align-items: center; gap: 0.35rem; margin-top: 0.75rem; font-size: 0.9375rem; font-weight: 500; color: var(--paper); position: relative; }
.hero-board .note a::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: right; transition: transform 280ms var(--ease-out); }
.hero-board .note a:hover::after { transform: scaleX(1); transform-origin: left; }
.hero-board .note a svg { transition: transform 200ms var(--ease-out); }
.hero-board .note a:hover svg { transform: translate(2px, -2px); }
.hero-board .hero-cta { justify-self: end; font-size: 0.95rem; padding: 0.7rem 1.4rem; }
.hero-board .field { position: relative; min-height: 32rem; overflow: hidden; }
.hero-board .giant { position: absolute; left: var(--pad-x); bottom: var(--hero-pb); width: 46vw; max-width: 42rem; z-index: 2; } /* the tight white svg has no baseline slack */
.hero-board .giant img { display: block; width: 100%; height: auto; }
/* Bottom-right corner, on the wordmark's baseline (owner, 2026-09-05). */
.hero-board .scroll-ring { left: auto; right: var(--pad-x); margin: 0; bottom: 3.5rem; z-index: 2; }
/* The board is the hero's own nav: the fixed .nav stays out of the way
   until the board has scrolled off (main.js tweens it in and out). */
.nav.is-hidden { pointer-events: none; }
@media (max-width: 900px) {
  :root { --hero-pb: 9rem; }
  .hero-board .board { grid-template-columns: 1fr; padding: 1.25rem var(--pad-x) 1.75rem; gap: 1.25rem 1.5rem; }
  .hero-board .brand { margin-right: 0; gap: 1rem; }
  /* The C is as wide as it is tall, so the pill gets its own row under the brand. */
  .hero-board .board .hero-cta { justify-self: start; white-space: nowrap; }
  .hero-board .note { max-width: none; }
  .hero-board .note:nth-child(n+4) { display: none; } /* two notes on a phone */
  .hero-board .field { min-height: 36rem; }
  .hero-board .giant { width: 78vw; bottom: var(--hero-pb); }
  .hero-board .scroll-ring { display: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .nav-links { display: none; }
  /* With the centre column gone, collapse to two zones so Contact stays right. */
  .nav-inner { grid-template-columns: 1fr auto; }
  .hero { min-height: 92dvh; }
  .hero-actions { flex-wrap: wrap; justify-content: center; gap: 0.75rem; }
  .project.half { grid-column: span 12; }
  .project.half .project-media { aspect-ratio: 16 / 10; }
  /* One column outright. Twelve tracks cannot survive here: the gaps alone
     (11 x 2rem) came to more than the card's inner width, which left every
     track at zero and pushed all the content out through the card's edge. */
  .contact-grid { grid-template-columns: 1fr; gap: 0; }
  .contact-main { grid-column: auto; }
  .contact-side {
    grid-column: auto;
    border-left: none;
    border-top: 1px solid var(--hairline-light);
    padding-left: 0;
    padding-top: 2.5rem;
    margin-top: 2.5rem;
  }
  /* One post per row, image-led: the 16:9 cover stays full-width and the
     compact meta stacks beneath it — picture first here too. */
  .journal-grid { grid-template-columns: 1fr; gap: 2.25rem; }
  .journal-meta { padding: 1.2rem 1.25rem 1.4rem; }
  .cover-label,
  .cover-foot { display: none; }
  .cover-trend .cover-word { margin-bottom: 0; }
  .cover-strike { align-self: center; }
  .section-head { flex-direction: column; gap: 0.75rem; }
}

/* ============================================================
   Blog — index gallery and post pages
   The index reuses the work gallery's 12-column rhythm so the two
   archives feel like one studio. Covers are placeholder artwork
   (tools/blog_covers.py) — greyscale, one gesture each.
   ============================================================ */
.gallery-item.third { grid-column: span 4; }
.gallery-item.third .gallery-media { aspect-ratio: 4 / 3; }

/* Date sits above the title as the only metadata on a card. Mono, small,
   quiet — the connective tissue, not a badge. */
.post-date {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-40);
}
.gallery-meta .post-date { display: block; margin-bottom: 0.5rem; }

/* Unwritten posts are shown as objects, not links: no anchor, so the
   "Read more" pill never appears over one and nothing is clickable. The
   tag is the honest signal that it isn't there yet. */
.gallery-item.is-soon .gallery-media { opacity: 0.72; }
.post-soon {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-40);
  border: 1px solid var(--hairline-dark);
  border-radius: 999px;
  padding: 0.15rem 0.5rem;
  margin-left: 0.5rem;
}

/* ---------- Post ----------
   Owner, 2026-09-13: inverted (black ground, paper text, the same token flip
   as the gallery), the mono eyebrow gone, and the page laid out like an
   editorial spread instead of a centred 44rem column. The headline is the
   one loud thing; the lede row pairs the metadata (light, small) with the
   standfirst (Inter 400, large); the body sits in a wide right-hand measure
   with an empty left margin the way a magazine feature does. Weights do the
   work: 900 headline, 400 standfirst and body, 700 crossheads, 600 bold. */
.post.zone-black {
  background: var(--black);
  color: var(--paper);
  --ink: #F8F8F8;
  --grey-40: rgba(248, 248, 248, 0.4);
  --grey-60: rgba(248, 248, 248, 0.62);
  --hairline-dark: rgba(248, 248, 248, 0.16);
}
.post {
  background: var(--black);
  color: var(--paper);
  padding: clamp(8rem, 15vh, 11rem) 0 clamp(5rem, 10vh, 8rem);
}
/* Editorial grid: 12 columns across the full .wrap. */
.post-head, .post-body, .post-end, .post-next {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(1rem, 2vw, 2rem);
}
.post-head > *, .post-body > *, .post-end > *, .post-next > * { grid-column: 1 / -1; }
/* Top row: the back arrow left, date and read time in the corner opposite (owner, 2026-09-13). */
.post-head-top { grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: clamp(2rem, 4vh, 3rem); }
.post-head-top .post-meta { margin: 0; font-size: 0.875rem; }
.post-head .case-back {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 0;
  border-color: var(--hairline-dark);
  background: transparent;
  color: var(--paper);
}
.post-head .case-back:hover { background: var(--paper); border-color: var(--paper); color: var(--black); }
.post-head h1 {
  grid-column: 1 / span 11;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.4rem, 4.6vw, 4.5rem);
  line-height: 1;
  letter-spacing: -0.03em;
  text-wrap: balance;
  max-width: 20ch;
}
/* Lede row: metadata left, standfirst right, sharing a hairline above. */
.post-lede {
  margin-top: clamp(2.25rem, 5vh, 3.5rem);
  padding-top: 1.4rem;
  border-top: 1px solid var(--hairline-dark);
  display: block;
}
.post-meta {
  grid-column: 1;
  font-size: 0.9375rem;
  line-height: 1.5;
  font-weight: 400;
  color: var(--grey-60);
}
.post-standfirst {
  margin: 0;
  max-width: 40ch;
  font-size: clamp(1.25rem, 1.9vw, 1.75rem);
  line-height: 1.38;
  font-weight: 400;
  letter-spacing: -0.012em;
  color: var(--paper);
  text-wrap: pretty;
}
/* Cover: never forced into a frame. Landscape artwork runs the full wrap at
   its own ratio; square (or upright) artwork sits on the body column, held
   to the viewport height so it never becomes a wall. main.js reads the real
   ratio when the file loads and sets .square, so the markup class is only
   the first paint. */
.post-cover {
  margin: clamp(3rem, 7vh, 5.5rem) 0;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: clamp(1rem, 2vw, 2rem);
}
.post-cover img { grid-column: 1 / -1; display: block; width: 100%; height: auto; background: rgba(248, 248, 248, 0.05); }
/* Square artwork (owner, 2026-09-13): picture left, the lede beside it on the right, so the
   opening reads as one spread instead of a tall block under the headline. The lede is moved
   into the cover in the markup for these posts. */
/* Every cover, whatever its ratio (owner, 2026-09-13): the picture on the left at its own
   proportions, the lede beside it on the right, centred on the picture. One opening for all
   thirteen posts, so a 16:9 and a square never need different treatment. The lede lives inside
   .post-cover in the markup. */
.post-cover { grid-template-columns: repeat(12, minmax(0, 1fr)); align-items: center; margin-top: clamp(2.25rem, 5vh, 3.5rem); }
.post-cover img { grid-column: 1 / span 6; width: 100%; height: auto; max-height: 78vh; object-fit: cover; border-radius: 12px; }
.post-cover .post-lede { grid-column: 8 / span 5; margin: 0; padding: 0; border: 0; display: block; }
.post-cover .post-standfirst { font-size: clamp(1.35rem, 2.1vw, 2rem); line-height: 1.32; max-width: none; }
@media (max-width: 900px) {
  .post-cover img { grid-column: 1 / -1; }
  .post-cover .post-lede { grid-column: 1 / -1; margin-top: 1.75rem; }
}
/* Split cover (owner, 2026-09-13): square artwork runs wide on the left, seven
   columns, and the lede (date, read time, standfirst) sits small on the right,
   bottom-aligned to the picture, so the eye goes picture -> note -> article.
   The lede row's hairline moves up here with it. */
.post-cover.split {
  margin-top: clamp(2.25rem, 5vh, 3.5rem);
  padding-top: 1.4rem;
  border-top: 1px solid var(--hairline-dark);
  align-items: end;
}
.post-cover.split img, .post-cover.split.square img { grid-column: 1 / span 7; width: 100%; max-width: none; max-height: none; justify-self: stretch; }
.post-cover.split .post-lede { grid-column: 9 / -1; display: block; margin: 0; padding: 0; border: 0; align-self: end; }
.post-cover.split .post-meta { margin: 0 0 1.25rem; }
.post-cover.split .post-standfirst { max-width: 32ch; font-size: 1.125rem; line-height: 1.5; letter-spacing: 0; }

/* Body: the reading measure starts two columns in and runs to the right
   edge (owner, 2026-09-13: the earlier cols 4-11 / 62ch read too narrow). */
.post-body > * { grid-column: 3 / span 10; max-width: 84ch; }
.post-body p {
  font-size: 1.25rem;
  line-height: 1.62;
  font-weight: 400;
  margin-bottom: 1.5rem;
  color: rgba(248, 248, 248, 0.86);
}
/* The opening paragraph is set larger and a touch heavier: the drop into the piece. */
.post-body > p:first-child {
  font-size: clamp(1.4rem, 1.9vw, 1.7rem);
  line-height: 1.45;
  font-weight: 500;
  color: var(--paper);
  margin-bottom: 2.25rem;
}
.post-body h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  letter-spacing: -0.015em;
  word-spacing: 0.02em;
  line-height: 1.05;
  margin: clamp(3.25rem, 7vh, 5rem) 0 1.25rem;
  color: var(--paper);
}
.post-body h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.7vw, 1.375rem);
  letter-spacing: -0.005em;
  word-spacing: 0.02em;
  line-height: 1.25;
  margin: 2.25rem 0 0.7rem;
  color: var(--paper);
}
.post-body strong { font-weight: 600; color: var(--paper); }
.post-body em { font-style: italic; }
.post-body a { color: var(--paper); text-decoration: underline; text-underline-offset: 0.18em; text-decoration-color: var(--grey-40); transition: text-decoration-color 200ms var(--ease-out); }
.post-body a:hover { text-decoration-color: var(--paper); }
.post-body ul, .post-body ol { padding-left: 1.25rem; margin-bottom: 1.5rem; font-size: 1.25rem; line-height: 1.62; font-weight: 400; color: rgba(248, 248, 248, 0.86); }
.post-body li { margin-bottom: 0.5rem; }
/* A rule to close the piece, not a box around it. */
.post-end {
  margin-top: clamp(4rem, 8vh, 6rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline-dark);
}
.post-end p { grid-column: 1 / -1; max-width: 50rem; font-size: 1.0625rem; line-height: 1.6; font-weight: 400; color: var(--grey-60); }
.post-end a { font-weight: 600; color: var(--paper); }
.post-end a:hover { opacity: 0.6; }

.post-next {
  margin-top: clamp(3rem, 6vh, 4rem);
  align-items: baseline;
}
.post-next-label {
  grid-column: 1 / span 3;
  font-size: 0.9375rem;
  font-weight: 400;
  color: var(--grey-60);
}
.post-next a {
  grid-column: 3 / span 10;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.35rem, 2.4vw, 2rem);
  letter-spacing: -0.012em;
  word-spacing: 0.02em;
  line-height: 1.1;
  color: var(--paper);
  transition: opacity 200ms var(--ease-out);
}
.post-next a:hover { opacity: 0.6; }

/* ---------- Post: contents / article / share (owner, 2026-09-13, "like Clay") ----------
   Below the cover the page splits three ways on the same 12-column grid: a
   small sticky contents nav on the left (the h2s, current one lit), the
   article in a narrower centre measure, and a sticky "Share this article"
   column on the right with the socials as hairline circles. Under 1100px
   the contents list sits above the article and the share row closes it. */
/* Three tracks, not twelve columns: the article gets a fixed centre track so it sits dead
   centre between the asides (owner, 2026-09-13: "actually centered"); the asides share what is left. */
.post-layout {
  display: grid;
  grid-template-columns: minmax(0, 50rem) minmax(0, 1fr);
  column-gap: clamp(2rem, 4vw, 4.5rem);
  align-items: start;
}
.post-layout .post-body { grid-column: 1; display: block; }
.post-layout .post-body > * { grid-column: auto; max-width: 74ch; }
/* Inside the three-column layout the copy is set a notch smaller with more leading and
   more air between paragraphs and crossheads (owner, 2026-09-13: "cluttered and narrow"). */
.post-layout .post-body p { font-size: 1.125rem; line-height: 1.72; margin-bottom: 1.7rem; }
.post-layout .post-body > p:first-child { font-size: clamp(1.3rem, 1.6vw, 1.5rem); line-height: 1.5; margin-bottom: 2.5rem; }
.post-layout .post-body h2 { margin: clamp(3.75rem, 8vh, 5.5rem) 0 1.5rem; }
.post-layout .post-body h3 { margin: 2.75rem 0 0.8rem; }
.post-layout .post-body ul, .post-layout .post-body ol { font-size: 1.125rem; line-height: 1.72; margin-bottom: 1.7rem; }
.post-layout .post-fig { margin: clamp(3rem, 6vh, 4.5rem) 0; }
.post-toc { grid-column: 1; }
.post-share { grid-column: 2; max-width: 17rem; justify-self: end; }
.post-toc, .post-share { position: sticky; top: 6.5rem; }
/* Centred spread (owner, 2026-09-13): the headline sits dead centre and spans wide, the
   picture and standfirst nest under it, then the article runs down the middle with the
   share rail (share, up next, studio) kept on the right in the spare track. A 16:9 cover
   runs large and centred with the standfirst beneath; a square cover (main.js sets .square
   from the file's ratio) sits smaller on the left with the standfirst beside it. */
.post-head h1 { grid-column: 1 / -1; justify-self: center; text-align: center; max-width: 26ch; }
.post-cover { align-items: start; row-gap: 1.75rem; }
.post-cover img { grid-column: 2 / span 10; max-height: 72vh; }
.post-cover .post-lede { grid-column: 3 / span 8; justify-self: center; text-align: center; padding-top: 0; }
.post-cover .post-standfirst { max-width: 52ch; font-size: clamp(1.25rem, 1.8vw, 1.6rem); line-height: 1.4; margin: 0 auto; }
.post-cover.square { align-items: center; }
.post-cover.square img { grid-column: 2 / span 5; max-height: 60vh; }
.post-cover.square .post-lede { grid-column: 8 / span 4; justify-self: start; text-align: left; }
.post-cover.square .post-standfirst { margin: 0; max-width: 30ch; font-size: clamp(1.25rem, 1.8vw, 1.6rem); }
.post-layout { grid-template-columns: minmax(0, 1.3fr) minmax(0, 50rem) minmax(0, 1fr); }
/* Owner (2026-09-13): "bring the content right a bit". The left track is weighted heavier than the
   right, so the article sits a notch right of true centre; the share circles drop to 40px so the
   rail still fits the narrower right track at 1440. */
.post-share .post-share-btn { width: 40px; height: 40px; }
.post-share .post-share-btn svg { width: 15px; height: 15px; }
.post-layout .post-body { grid-column: 2; }
.post-layout .post-body > * { max-width: none; }
.post-share { grid-column: 3; }
@media (max-width: 1100px) {
  .post-cover img, .post-cover.square img { grid-column: 1 / -1; }
  .post-cover .post-lede, .post-cover.square .post-lede { grid-column: 1 / -1; justify-self: center; text-align: center; }
  .post-cover.square .post-standfirst { margin: 0 auto; max-width: 52ch; }
}
}
.post-aside-label {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--grey-60);
  margin-bottom: 1rem;
}
.post-toc ol { list-style: none; margin: 0; padding: 0; }
.post-toc li { margin: 0; }
.post-toc a {
  display: block;
  position: relative;
  padding: 0.3rem 0 0.3rem 1rem;
  font-size: 0.875rem;
  line-height: 1.35;
  font-weight: 400;
  color: var(--grey-60);
  text-wrap: pretty;
  transition: color 200ms var(--ease-out);
}
.post-toc a::before {
  content: "";
  position: absolute;
  left: 0; top: calc(0.3rem + 0.675em);
  width: 6px; height: 1px;
  background: currentColor;
  opacity: 0;
  transform: translateY(-50%) scaleX(0.4);
  transform-origin: left;
  transition: opacity 200ms var(--ease-out), transform 260ms var(--ease-out);
}
.post-toc a:hover { color: var(--paper); }
.post-toc a.is-current { color: var(--paper); font-weight: 500; }
.post-toc a.is-current::before { opacity: 1; transform: translateY(-50%) scaleX(1); }
.post-share-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.post-share-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px; height: 42px;
  border-radius: 999px;
  border: 1px solid var(--hairline-dark);
  color: var(--paper);
  background: transparent;
  cursor: pointer;
  padding: 0;
  font: inherit;
  transition: background-color 220ms var(--ease-out), border-color 220ms var(--ease-out),
              color 220ms var(--ease-out), transform 160ms var(--ease-out);
}
.post-share-btn svg { width: 16px; height: 16px; display: block; }
.post-share-btn:hover { background: var(--paper); border-color: var(--paper); color: var(--black); }
.post-share-btn:active { transform: scale(0.95); }
.post-share-btn.is-done { background: var(--paper); border-color: var(--paper); color: var(--black); }
.post-share-note { margin-top: 0.75rem; font-size: 0.8125rem; color: var(--grey-60); min-height: 1.2em; }

/* ---------- Post figures: greyscale infographics set from the article's own numbers ----------
   One material: paper on black, hairlines, Inter for labels, the display face
   for the big figures. No colour, no shadows, no boxes around the whole thing. */
.post-fig {
  margin: clamp(2.5rem, 5vh, 3.5rem) 0;
  padding: 1.75rem 0 1.25rem;
  border-top: 1px solid var(--hairline-dark);
  border-bottom: 1px solid var(--hairline-dark);
  max-width: none !important;
}
.post-fig figcaption {
  margin-top: 1.25rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--grey-60);
  text-wrap: pretty;
}
.post-fig .fig-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.125rem;
  letter-spacing: -0.01em;
  margin: 0 0 1.25rem;
  color: var(--paper);
}
/* Bands: horizontal ranges on a shared (log) axis. --a/--b are the bar's start/end as %. */
.fig-bands { display: grid; row-gap: 0.7rem; }
.fig-band { display: grid; grid-template-columns: 9rem 1fr; align-items: center; column-gap: 1rem; font-size: 0.875rem; }
.fig-band-label { color: var(--paper); font-weight: 500; line-height: 1.3; }
.fig-band-label small { display: block; font-weight: 400; color: var(--grey-60); }
.fig-band-track { position: relative; height: 26px; background: rgba(248, 248, 248, 0.06); border-radius: 3px; overflow: hidden; }
.fig-band-bar { position: absolute; top: 0; bottom: 0; left: var(--a); width: calc(var(--b) - var(--a)); background: rgba(248, 248, 248, 0.82); border-radius: 3px; }
.fig-band.is-us .fig-band-bar { background: var(--paper); }
.fig-band-us { position: absolute; top: 0; bottom: 0; left: var(--a); width: calc(var(--b) - var(--a)); border: 1.5px solid var(--paper); border-radius: 3px; box-sizing: border-box; }
.fig-band.is-us { margin-top: 0.4rem; padding-top: 0.8rem; border-top: 1px solid var(--hairline-dark); }
.fig-axis { display: flex; justify-content: space-between; margin-top: 0.6rem; padding-left: 10rem; font-size: 0.75rem; color: var(--grey-40); }
.fig-key { display: flex; gap: 1.25rem; flex-wrap: wrap; margin-top: 0.9rem; font-size: 0.8125rem; color: var(--grey-60); }
.fig-key span { display: inline-flex; align-items: center; gap: 0.45rem; }
.fig-key i { width: 14px; height: 10px; border-radius: 2px; background: rgba(248, 248, 248, 0.82); }
.fig-key i.is-outline { background: none; border: 1.5px solid var(--paper); }
/* Timeline: the same tracks read as weeks. */
.fig-weeks { display: flex; justify-content: space-between; padding-left: 10rem; font-size: 0.75rem; color: var(--grey-40); margin-bottom: 0.5rem; }
.fig-band-bar.is-soft { background: rgba(248, 248, 248, 0.42); }
/* Steps: a numbered row, the number set big. */
.fig-steps { display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: 1.25rem; }
.fig-step { border-top: 1px solid var(--hairline-dark); padding-top: 0.8rem; }
.fig-step b { display: block; font-family: var(--display); font-weight: 700; font-size: 1.75rem; letter-spacing: -0.02em; line-height: 1; color: var(--paper); margin-bottom: 0.55rem; }
.fig-step strong { display: block; font-size: 0.9375rem; font-weight: 600; color: var(--paper); margin-bottom: 0.3rem; line-height: 1.3; }
.fig-step span { display: block; font-size: 0.8125rem; line-height: 1.45; color: var(--grey-60); }
/* Compare: two columns of short lines. */
.fig-compare { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
.fig-col h4 { font-family: var(--display); font-weight: 700; font-size: 1rem; margin: 0 0 0.6rem; padding-bottom: 0.6rem; border-bottom: 1px solid var(--paper); color: var(--paper); }
.fig-col.is-dim h4 { border-bottom-color: var(--hairline-dark); color: var(--grey-60); }
.fig-col ul { list-style: none; margin: 0; padding: 0; }
.fig-col li { font-size: 0.9375rem; line-height: 1.45; padding: 0.45rem 0; border-bottom: 1px solid var(--hairline-dark); color: var(--paper); }
.fig-col.is-dim li { color: var(--grey-60); }
.fig-col li:last-child { border-bottom: 0; }
/* Grid of numbered items (the ten sections, the seven parts). */
.fig-cells { display: grid; grid-template-columns: repeat(var(--n, 5), minmax(0, 1fr)); gap: 1px; padding: 1px; }
.fig-cell { background: var(--black); box-shadow: 0 0 0 1px var(--hairline-dark); padding: 0.9rem 0.85rem 1rem; min-height: 6.5rem; }
.fig-cell b { display: block; font-family: var(--display); font-weight: 700; font-size: 1.25rem; letter-spacing: -0.02em; color: var(--grey-40); margin-bottom: 0.6rem; }
.fig-cell span { display: block; font-size: 0.875rem; line-height: 1.35; font-weight: 500; color: var(--paper); }
/* SVG diagrams */
.fig-svg { display: block; width: 100%; height: auto; }
.fig-svg text { font-family: var(--body); font-weight: 500; fill: var(--paper); }
.fig-svg .t-dim { fill: rgba(248, 248, 248, 0.6); font-weight: 400; }
.fig-svg .ln { stroke: rgba(248, 248, 248, 0.5); stroke-width: 1; fill: none; }
.fig-svg .ln-strong { stroke: var(--paper); stroke-width: 1.25; fill: none; }
.fig-svg .fill-dim { fill: rgba(248, 248, 248, 0.08); }
.fig-svg .fill-mid { fill: rgba(248, 248, 248, 0.2); }
.fig-svg .fill-hi { fill: rgba(248, 248, 248, 0.42); }
.fig-svg .t-ink { fill: #010101; font-weight: 600; }
.fig-svg .ln-dash { stroke: var(--paper); stroke-width: 1; stroke-dasharray: 3 4; fill: none; }

/* Share header set in the display face so the column reads as a real
   destination, not a footnote (owner, 2026-09-13: "more bold and bigger"). */
.post-share .post-aside-label {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.6vw, 1.5rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--paper);
  margin-bottom: 1.1rem;
}
.post-share-btn { width: 44px; height: 44px; }
.post-share-btn svg { width: 17px; height: 17px; }
.post-share .post-share-row { gap: 0.4rem; }
/* Two cards beneath: the next piece, and one route back into the studio. */
.post-side-card {
  display: block;
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hairline-dark);
  color: inherit;
}
.post-side-card .post-aside-label { font-size: 0.8125rem; font-weight: 500; color: var(--grey-60); margin-bottom: 0.75rem; }
.post-side-media { overflow: hidden; aspect-ratio: 16 / 10; border-radius: 10px; background: rgba(248, 248, 248, 0.05); }
.post-side-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 700ms var(--ease-out); }
.post-side-card:hover .post-side-media img { transform: scale(1.04); }
.post-side-card h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.125rem;
  letter-spacing: -0.015em;
  line-height: 1.15;
  margin: 0.8rem 0 0.3rem;
  color: var(--paper);
  transition: color 300ms var(--ease-out);
}
.post-side-card:hover h3 { color: var(--grey-60); }
.post-side-card p { font-size: 0.8125rem; color: var(--grey-60); margin: 0; }
.post-side-card.is-studio h3 { margin-top: 0; font-size: 1.2rem; }
.post-side-card.is-studio p { margin-bottom: 1rem; line-height: 1.45; }
.post-side-links { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.post-side-links a {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--hairline-dark);
  border-radius: 999px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--paper);
  transition: background-color 220ms var(--ease-out), border-color 220ms var(--ease-out), color 220ms var(--ease-out), transform 160ms var(--ease-out);
}
.post-side-links a svg { width: 0.7em; height: 0.7em; }
.post-side-links a:hover { background: var(--paper); border-color: var(--paper); color: var(--black); }
.post-side-links a:active { transform: scale(0.97); }
/* Read next: three cover cards on the full grid, the heading set like the work pages'. */
.post-more { margin-top: clamp(4rem, 8vh, 6rem); }
.post-more-label {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2rem, 3.5vw, 3rem);
  letter-spacing: -0.02em;
  line-height: 1;
  margin-bottom: clamp(1.5rem, 3vh, 2.25rem);
  color: var(--paper);
}
.post-more-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1rem, 2vw, 1.75rem); }
.post-more-card { display: block; color: inherit; }
.post-more-media { overflow: hidden; aspect-ratio: 16 / 10; border-radius: 12px; background: rgba(248, 248, 248, 0.05); }
.post-more-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 700ms var(--ease-out); }
.post-more-card:hover .post-more-media img { transform: scale(1.04); }
.post-more-card h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.7vw, 1.5rem);
  letter-spacing: -0.02em;
  line-height: 1.12;
  margin: 1rem 0 0.35rem;
  color: var(--paper);
  text-wrap: balance;
  transition: color 300ms var(--ease-out);
}
.post-more-card:hover h3 { color: var(--grey-60); }
.post-more-card p { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.875rem; font-weight: 400; color: var(--grey-60); margin: 0; }
.post-more-card p svg { width: 0.75em; height: 0.75em; transition: transform 300ms var(--ease-out); }
.post-more-card:hover p svg { transform: translate(0.15em, -0.15em); }
/* Read next as ruled rows, not cards (owner, 2026-09-13: "make it a list like how we work"). */
.post-more-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hairline-dark); }
.post-more-row {
  display: grid;
  grid-template-columns: 3rem 7rem minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 1.5rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--hairline-dark);
  color: inherit;
}
.post-more-row b { font-family: var(--display); font-weight: 700; font-size: 1rem; color: var(--grey-40); }
/* A fixed 3:2 crop box, so a 16:9, 4:3 or square cover all sit the same. */
.post-more-thumb { aspect-ratio: 3 / 2; overflow: hidden; border-radius: 8px; background: rgba(248, 248, 248, 0.05); }
.post-more-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 700ms var(--ease-out); }
.post-more-row:hover .post-more-thumb img { transform: scale(1.06); }
.post-more-row h3 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.35rem, 2.2vw, 1.9rem);
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin: 0;
  color: var(--paper);
  text-wrap: balance;
  transition: color 300ms var(--ease-out);
}
.post-more-row:hover h3 { color: var(--grey-60); }
.post-more-row p { display: inline-flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: var(--grey-60); margin: 0; white-space: nowrap; }
.post-more-row p svg { width: 0.75em; height: 0.75em; transition: transform 300ms var(--ease-out); }
.post-more-row:hover p svg { transform: translate(0.15em, -0.15em); }
@media (max-width: 640px) {
  .post-more-row { grid-template-columns: 5.5rem minmax(0, 1fr); row-gap: 0.3rem; }
  .post-more-row b { display: none; }
  .post-more-thumb { grid-row: 1 / span 2; }
  .post-more-row p { grid-column: 2; }
}
@media (max-width: 900px) { .post-more-grid { grid-template-columns: 1fr; gap: 2rem; } }

@media (max-width: 1100px) {
  .post-layout { display: block; }
  .post-toc, .post-share { position: static; }
  .post-toc { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--hairline-dark); }
  .post-toc ol { columns: 2; column-gap: 2rem; }
  .post-toc li { break-inside: avoid; }
  .post-layout .post-body > * { max-width: 72ch; }
  .post-share { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--hairline-dark); display: grid; grid-template-columns: 1fr 1fr; column-gap: 2rem; max-width: none; }
  .post-share .post-aside-label, .post-share .post-share-row, .post-share .post-share-note { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .post-toc ol { columns: 1; }
  .post-share { grid-template-columns: 1fr; }
  .fig-band { grid-template-columns: 6.5rem 1fr; }
  .fig-axis, .fig-weeks { padding-left: 7.5rem; }
  .fig-steps { grid-template-columns: 1fr 1fr; }
  .fig-compare { grid-template-columns: 1fr; }
  .fig-cells { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .post-head h1 { grid-column: 1 / -1; max-width: none; }
  .post-lede { row-gap: 1.25rem; }
  .post-meta, .post-standfirst { grid-column: 1 / -1; max-width: none; }
  .post-body > *, .post-end p, .post-next a, .post-next-label { grid-column: 1 / -1; max-width: none; }
  .post-cover.square img { grid-column: 1 / -1; width: 100%; max-height: none; }
  .post-cover.split img, .post-cover.split.square img { grid-column: 1 / -1; }
  .post-cover.split .post-lede { grid-column: 1 / -1; margin-top: 1.5rem; }
  .post-cover.split .post-standfirst { max-width: none; }
  .post-next { row-gap: 0.5rem; }
}
@media (max-width: 900px) {
  .gallery-item.third { grid-column: span 6; }
}
@media (max-width: 640px) {
  .gallery-item.third { grid-column: span 12; }
}

/* Landing strip covers carry artwork instead of set type. The spine hairline
   stays — it is what makes them read as objects rather than panels. */
/* Image-led cards: 16:9, the picture owns the card. */
.journal-cover.art { padding: 0; aspect-ratio: 16 / 9; }
.journal-cover.art img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Section head's quiet route to the full archive. Sits on the baseline
   opposite the heading — a link, not a button. */
.section-more {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex: none;
  font-size: 0.875rem;
  font-weight: 600;
  color: rgba(248, 248, 248, 0.6);
  transition: color 200ms var(--ease-out);
}
.section-more:hover { color: var(--paper); }
.section-more svg { transition: transform 200ms var(--ease-out); }
.section-more:hover svg { transform: translate(1px, -1px); }

/* Long-form titles need a tighter leading than the one-word work titles the
   gallery was built for. */
.gallery-meta h2 { line-height: 1.16; text-wrap: balance; max-width: 30ch; }
/* Date and the Soon tag share one line above the title. */
.gallery-meta > .post-date { display: inline-block; margin-bottom: 0.55rem; vertical-align: middle; }
.gallery-meta > .post-soon { display: inline-block; margin-bottom: 0.55rem; vertical-align: middle; }

/* Idle Hands opens on a square photograph rather than a 16:9 clip, so the
   intro media takes its ratio from the asset it holds. */
.case-intro-media img {
  width: 100%;
  height: 100%;
  display: block;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

/* The homepage mega footer carried across every inner page (owner, 2026-08-25).
   Inner pages end on paper, so the footer brings its own black ground; the
   hairline + spacing come from .footer-center, so the old top padding goes. */
.site-footer.footer-mega { padding: 0; }

/* ---------- Services page — inverted slab + deep list on black ----------
   The hero stays paper; every block under it is white on black. The slab
   is the landing-page one with its colours flipped and a fourth column. */
.services-page-slab { padding-top: clamp(4rem, 8vh, 6rem); }
.services-slab-inverted { background: var(--black); color: var(--paper); padding-left: 0; padding-right: 0; }
.services-slab-inverted .services-slab-head { border-bottom-color: var(--paper); }
.services-slab-inverted .services-slab-link { color: var(--paper-60); font-family: var(--mono); font-size: 0.75rem; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; }
.services-slab-inverted .services-num,
.services-slab-inverted .services-col h3 a { color: var(--paper); }
.services-slab-inverted .services-col { border-right-color: var(--hairline-light); }
.services-slab-inverted .services-col li { border-top-color: var(--hairline-light); color: var(--paper-60); }
.services-slab-inverted .services-col h3 a:focus-visible { outline-color: var(--paper); }
.services-cols-4 { grid-template-columns: repeat(4, 1fr); }
.services-detail { padding-top: clamp(5rem, 10vh, 8rem); padding-bottom: clamp(5rem, 10vh, 8rem); }
.services-detail .section-head { align-items: flex-end; }
.section-head-note { max-width: 30ch; color: var(--paper-60); font-size: 1rem; text-align: right; }
.services-detail .offer-block ul { columns: 2; column-gap: 2rem; display: block; }
.services-detail .offer-block ul li { break-inside: avoid; padding-bottom: 0.55rem; }
.services-cta { padding-top: clamp(4rem, 8vh, 6rem); }
.services-cta h2 { font-family: var(--display); font-weight: 900; font-size: clamp(2.2rem, 5vw, 4.5rem); letter-spacing: -0.03em; line-height: 0.95; }
.services-cta .services-cta-note,
.services-cta .hero-proof { color: var(--paper-60); }
@media (max-width: 900px) {
  .services-cols-4 { grid-template-columns: 1fr 1fr; }
  .services-slab-inverted .services-col { border-bottom: 1px solid var(--hairline-light); border-right: 0; padding-left: 0; }
  .services-slab-inverted .services-col:nth-child(odd) { border-right: 1px solid var(--hairline-light); padding-right: 1.25rem; }
  .services-slab-inverted .services-col:nth-child(even) { padding-left: 1.25rem; }
  .services-slab-inverted .services-col:nth-last-child(-n+2) { border-bottom: 0; }
  .section-head-note { display: none; }
}
@media (max-width: 520px) {
  .services-cols-4 { grid-template-columns: 1fr; }
  .services-slab-inverted .services-col { border-right: 0 !important; padding-left: 0 !important; padding-right: 0 !important; border-bottom: 1px solid var(--hairline-light) !important; }
  .services-slab-inverted .services-col:last-child { border-bottom: 0 !important; }
  .services-detail .offer-block ul { columns: 1; }
}

/* ---------- Blog index: masonry mosaic of cards ----------
   Native-ratio covers pack top-down in CSS columns, so mixed shapes
   tile into a mosaic instead of leaving row gaps. Each post is a card —
   the same object language as the landing journal shelf. */
.post-grid {
  columns: 3;
  column-gap: clamp(1.25rem, 2.5vw, 2rem);
}
.post-card { display: block; break-inside: avoid; margin-bottom: clamp(1.25rem, 2.5vw, 2rem); }
.post-card a {
  display: flex; flex-direction: column; width: 100%;
  border: 1px solid var(--hairline-light);
  border-radius: 14px;
  overflow: hidden;
  background-color: rgba(248, 248, 248, 0.035);
  box-shadow: 0 1px 0 rgba(248, 248, 248, 0.08) inset;
  transition: transform 500ms var(--ease-out), border-color 400ms var(--ease-out), background-color 400ms var(--ease-out), box-shadow 500ms var(--ease-out);
}
.post-card a:hover {
  transform: translateY(-4px);
  border-color: rgba(248, 248, 248, 0.28);
  background-color: rgba(248, 248, 248, 0.055);
  box-shadow: 0 1px 0 rgba(248, 248, 248, 0.1) inset, 0 30px 50px -34px rgba(0, 0, 0, 0.85);
}
/* Covers keep their native shape — the mixed ratios are the mosaic. */
.post-card-media { overflow: hidden; background: rgba(248, 248, 248, 0.05); }
.post-card-media img { display: block; width: 100%; height: auto; transition: transform 900ms var(--ease-drawer); }
.post-card a:hover .post-card-media img { transform: scale(1.035); }
.post-card h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.05rem, 1.35vw, 1.25rem);
  letter-spacing: -0.015em;
  line-height: 1.18;
  text-wrap: balance;
  margin-top: 1.1rem;
  padding: 0 1.25rem;
}
.post-card p {
  margin-top: 0.4rem;
  padding: 0 1.25rem;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--grey-60);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.post-card-read {
  display: inline-flex; align-items: center; gap: 0.35rem;
  margin-top: auto; padding: 0.8rem 1.25rem 1.3rem;
  font-size: 0.875rem; font-weight: 500;
  color: var(--ink);
}
.post-card-read svg { transition: transform 200ms var(--ease-out); }
.post-card a:hover .post-card-read svg { transform: translate(2px, -2px); }
@media (max-width: 1000px) { .post-grid { columns: 2; } }
@media (max-width: 600px)  { .post-grid { columns: 1; } }

/* ---------- Services page: price-led columns ----------
   Owner pick 07 of services-page-variations.html (2026-08-26). Art
   direction is gone; the old 48-item "In full" wall is replaced by three
   ruled columns led by the number. */
.price-led { padding: clamp(4rem, 8vh, 6rem) 0 clamp(2rem, 4vh, 3rem); }
.price-cols { display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid var(--paper); }
.price-col { padding: 2rem 1.5rem 2.5rem 0; border-right: 1px solid var(--hairline-light); scroll-margin-top: clamp(5.5rem, 11vh, 7.5rem); }
.price-col + .price-col { padding-left: 1.5rem; }
.price-col:last-child { border-right: 0; }
.price-from {
  display: block;
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2.4rem, 4.5vw, 4.25rem); line-height: 1; letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}
.price-from small { display: block; margin-bottom: 0.5rem; font-family: var(--body); font-size: 0.9375rem; font-weight: 500; letter-spacing: 0; color: var(--paper-60); }
.price-col h3 { font-family: var(--display); font-weight: 700; font-size: 1.4rem; letter-spacing: -0.02em; margin-top: 1.5rem; }
.price-col p { margin-top: 0.6rem; color: var(--paper-60); line-height: 1.6; }
.price-col ul { list-style: none; margin: 1.25rem 0 0; padding: 1rem 0 0; border-top: 1px solid var(--hairline-light); font-size: 0.9375rem; line-height: 1.9; }
@media (max-width: 900px) {
  .price-cols { grid-template-columns: 1fr; }
  .price-col, .price-col + .price-col { border-right: 0; border-bottom: 1px solid var(--hairline-light); padding-left: 0; }
  .price-col:last-child { border-bottom: 0; }
}

/* Inner-page contact block (services.html): the homepage form section without
   the footer nested inside it, so it keeps its own bottom padding. */
.contact-inner { padding-top: clamp(8rem, 16vh, 13rem); padding-bottom: clamp(5rem, 10vh, 8rem); position: relative; overflow: hidden; }
/* Fireworks behind the contact card: services since 2026-09-02, the landing
   page too since 2026-09-04 (.has-fireworks): .wrap is the positioning box, the sky fills it edge to edge
   under the card and is clipped to the card's radius, so no burst shows
   outside the glass. Still (no parallax), on its own layer. */
.contact-inner .wrap, .contact.has-fireworks .wrap { position: relative; isolation: isolate; }
.contact-inner .contact-card, .contact.has-fireworks .contact-card { z-index: 1; }
/* Lighter glass on this card only: at the shared 18px the fireworks behind
   it blur to smudges; at 10px the spokes and tips still read as bursts. */
.contact-inner .contact-card, .contact.has-fireworks .contact-card { backdrop-filter: blur(10px) saturate(1.05); -webkit-backdrop-filter: blur(10px) saturate(1.05); }
.motif-fireworks { left: var(--pad-x); right: var(--pad-x); top: 0; width: auto; height: 100%; object-fit: cover; border-radius: 16px; transform: none; opacity: 1; z-index: 0; }
/* Live version (js/fireworks.js): a canvas the size of .wrap, behind the
   card, replacing the baked PNG when motion is allowed. */
.fireworks-sky { position: absolute; inset: 0 var(--pad-x); z-index: 0; border-radius: 16px; pointer-events: none; }

/* ---- Hero as the frame (owner, 2026-09-06) — the 26 page-card, live ----
   2026-09-07: the outer box is gone (owner: "the frame would only be around
   the image"). Header, statement and meta sit bare on the black, aligned to
   the picture's edges; only the picture keeps a hairline. Side padding is
   tighter than --pad-x so the picture runs nearly edge to edge. */
.hero.hero-frame { --hero-px: clamp(0.75rem, 1.2vw, 1.25rem); display: grid; place-items: stretch; align-items: stretch; padding: clamp(1rem, 2.4vw, 2.2rem) var(--hero-px); min-height: 100dvh; }
/* 2026-09-08: header / stage / foot. The middle row is empty space the bitmap centres itself in; the statement
   and the meta moved down into one bottom row so the animation owns the centre. */
.hero-frame .card { position: relative; z-index: 3; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; height: calc(100dvh - 2*clamp(1rem, 2.4vw, 2.2rem)); }
/* 2026-09-08 (owner): elements a touch more centred — the rows sit inset from the hero edges */
.hero-frame .card > * { padding-left: clamp(0.5rem, 1.8vw, 2rem); padding-right: clamp(0.5rem, 1.8vw, 2rem); }
/* Three zones like the site nav: C left, routes dead-centre, CTA right (owner, 2026-09-07). */
.hero-frame .hd { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding-top: 1.4rem; padding-bottom: 0.9rem; }
.hero-frame .brand { display: flex; align-items: center; gap: 0.9rem; }
/* Wordmark, not the C (owner, 2026-09-07). */
.hero-frame .brand .hero-mark { display: block; height: 23px; /* bumped from 19.3 (owner, 2026-09-07) */ width: auto; aspect-ratio: auto; margin: 0; flex: none; } /* tight svg at the glyph height of the 40px .nav-logo, so both wordmarks render the same size */
.hero-frame .brand .hero-mark img { display: block; height: 100%; width: auto; }
.hero-frame .hd .lk { display: flex; gap: 1.6rem; justify-self: center; font-weight: 500; font-size: 1.0625rem; }
/* Owner (2026-09-07): no dimming on the header routes - full paper - and the
   nav pill's sliding hover capsule (.nav-hover, navHover in main.js) instead
   of an underline. The routes carry the same side padding as the pill's
   links so the capsule hugs them the same way. */
.hero-frame .hd .lk { position: relative; gap: 0.25rem; }
.hero-frame .hd .lk a { color: var(--paper); padding: 0.4rem 0.75rem; }
.hero-frame .hd .lk .nav-hover { background: rgba(248, 248, 248, 0.1); }
.hero-frame .hd .cta { justify-self: end; font-weight: 500; font-size: 1.0625rem; position: relative; display: inline-block; text-decoration: none; }
/* Underline kept, drawn as a hairline under the roll's clip box so the roll
   never cuts it; hover = the pill label roll (owner, 2026-09-07). */
.hero-frame .hd .cta::after { content: ""; position: absolute; left: 0; right: 0; bottom: -0.05em; height: 1px; background: currentColor; }
.hero-frame .hd .cta:hover .roll-label > span { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) { .hero-frame .hd .cta:hover .roll-label > span { transform: none; } }
/* Statement as one set block: equal air above and below, a firm measure,
   left edge on the page centre (owner, 2026-09-07: it read as "slotted"). */
.hero-frame .ft { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: 2rem; padding-top: 1.2rem; padding-bottom: 1rem; }
.hero-frame .st { display: grid; gap: 1.1rem; }
.hero-frame .st p { margin: 0; font-size: clamp(1.1rem, 1.6vw, 1.4rem); line-height: 1.3; font-weight: 500; max-width: 30rem; text-wrap: balance; }
/* Meta strip: no rule above it (owner, 2026-09-07: "I don't like this middle
   line") — the picture's own frame is the only line. The year/name/category
   trio was dropped the same day (owner: "looks a bit amateur"); a quiet
   availability note fills the left, and the right is the page's one clear
   CTA into the work — no underline (owner). */
.hero-frame .meta { display: grid; justify-items: end; gap: 0.55rem; font-size: 0.85rem; font-weight: 500; }
.hero-frame .meta .note { color: rgba(248, 248, 248, 0.45); }
.hero-frame .meta .all { display: inline-flex; align-items: center; gap: 0.4em; text-decoration: none; color: var(--paper); }
/* Hover = the nav's underline, drawn in from the left; the arrow stays put
   (owner, 2026-09-07: "cleaner"). */
.hero-frame .meta .all { position: relative; }
.hero-frame .meta .all::after { content: ""; position: absolute; left: 0; right: 0; bottom: -3px; height: 1px; background: currentColor; transform: scaleX(0); transform-origin: right; transition: transform 280ms var(--ease-out); }
.hero-frame .meta .all:hover::after { transform: scaleX(1); transform-origin: left; }
/* 2026-09-08: no picture box any more — the thorns canvas is the hero's own ground (full bleed, under .card),
   and .pic is only the empty region the bitmap centres itself in (data-center on the canvas). */
.hero-frame .pic { position: relative; padding: 0; min-height: 0; }
.hero-frame > .hero-thorns { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; }
.hero-frame .st .in { width: max-content; font-size: 0.85rem; font-weight: 500; color: rgba(248, 248, 248, 0.6); transition: color 200ms var(--ease-out); }
.hero-frame .st .in:hover { color: var(--paper); }
@media (max-width: 760px) {
  .hero-frame .hd { grid-template-columns: auto 1fr; gap: 1rem; }
  .hero-frame .hd .lk { display: none; }
  .hero-frame .hd .cta { grid-column: 2; }
  .hero-frame .ft { grid-template-columns: 1fr; gap: 1.4rem; padding-bottom: 0.8rem; }
  .hero-frame .meta { justify-items: start; grid-auto-flow: column; justify-content: space-between; width: 100%; }
}

/* ---------- About page (2026-09-09 reformat, second pass) ----------
   Brutalist: type on flat black, ruled, a lot of air. The opener is one
   paragraph, set big and centred on a narrow measure. Motion is scroll
   state (js/about.js): in the offer index the row under the reading line
   inverts to paper; in How we work a timeline fills as the columns pass.
   No seam hairlines between sections; they part by air. */
/* About opener (2026-09-10): one short tagline, the chrome C bleeding in
   from the right edge. Hero is short; the infographic pops up under it. */
.ab-hero { position: relative; overflow: hidden; padding: clamp(7rem, 14vh, 11rem) 0 clamp(3rem, 6vh, 4.5rem); }
/* Short on purpose: the panel below should already peek into the first view. */
/* 2026-09-11 (owner): headline left, the C whole in the right column — no label, no bleed off the edge. */
.ab-open { position: relative; z-index: 1; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 3rem; min-height: calc(50dvh - clamp(7rem, 14vh, 11rem)); }
.ab-open-copy { display: grid; gap: 1.4rem; justify-items: start; }
.ab-hero .ab-opener {
  margin: 0;
  color: var(--paper);
  max-width: 13ch;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(3rem, 7.2vw, 7.6rem);
  line-height: 0.95;
  letter-spacing: -0.045em;
  text-wrap: balance;
}
/* Sized to the shorter hero (2026-09-11): the C must clear the nav pill. */
.ab-open-art { width: min(40vh, 24vw); aspect-ratio: 1; justify-self: end; pointer-events: none; }
.ab-open-art chroma-mark { display: block; width: 100%; height: 100%; pointer-events: auto; }

/* Section spacing lives on .wrap: padding-block only, a shorthand here
   would wipe the side padding of .wrap. */
/* No seam hairlines on this page (owner, 2026-09-09): sections part by air.
   That includes the site-wide rule over Contact. */
.about-page .contact::before { display: none; }
.ab-offer .wrap { padding-block: clamp(6rem, 12vh, 9rem) clamp(11rem, 22vh, 17rem); }
.ab-how .wrap { padding-block: 0 clamp(7rem, 14vh, 11rem); }

/* Section heading. */
.ab-h2 {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.4rem, 5vw, 4.6rem);
  line-height: 1;
  letter-spacing: -0.03em;
}
/* The big numeral, shared by the offer groups and the process columns. */
.ab-num {
  display: block;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.2rem, 3.2vw, 3.2rem);
  line-height: 0.85;
  letter-spacing: -0.05em;
  margin-left: -0.04em;
  font-variant-numeric: tabular-nums;
}

/* Word-scrub paragraphs (js/about.js), kept for reuse. */
.ab-scrub {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2rem, 4.6vw, 4.4rem);
  line-height: 1.06;
  letter-spacing: -0.03em;
  max-width: 21ch;
}
.ab-w { display: inline; }

/* Why we exist (2026-09-12): one centred paragraph in the display face at a middle weight and size, with far
   more air above and below than any other block, so it reads as a pause rather than another section. */
.ab-why .wrap { padding-block: clamp(9rem, 20vh, 16rem) clamp(10rem, 22vh, 18rem); }
/* Owner picked W4 from about-why-variations.html (2026-09-12), one step lighter: Inter Medium, wide measure. */
.ab-why-line { margin: 0 auto; max-width: 44ch; text-align: center; font-family: var(--body); font-weight: 600; /* W4 as picked: Semibold (owner, 2026-09-12) */ font-size: clamp(1.35rem, 2.1vw, 2.1rem); line-height: 1.36; letter-spacing: -0.02em; color: var(--paper); text-wrap: pretty; }
/* Ease-out line (2026-09-12): centred, display face at a middle weight and size, lots of air. */
.ab-ease .wrap { padding-block: clamp(4rem, 10vh, 8rem) clamp(6rem, 12vh, 10rem); }
.ab-ease-line { margin: 0 auto; max-width: 36ch; text-align: center; font-family: var(--body); font-weight: 600; font-size: clamp(1.2rem, 1.8vw, 1.8rem); line-height: 1.4; letter-spacing: -0.015em; color: var(--paper); text-wrap: pretty; }
/* Blog strip on About: shelf padding comes from .journal; trim the bottom so contact sits close. */
.ab-journal { padding-bottom: clamp(5rem, 10vh, 8rem); }

/* What we offer: three numbered groups */
.ab-offer-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
  margin-bottom: clamp(4rem, 9vh, 6.5rem);
}
.ab-offer-link {
  display: inline-block;
  font-weight: 500;
  color: var(--paper);
  border-bottom: 1px solid var(--hairline-light);
  padding-bottom: 0.15rem;
  transition: border-color 200ms ease;
}
.ab-offer-link:hover { border-color: var(--paper); }
.ab-offer-link span { display: inline-block; transition: transform 250ms var(--ease-out); }
.ab-offer-link:hover span { transform: translateX(4px); }

/* What we offer, remade 2026-09-11: one full-width index. Group header rows on the 5/7 split (number + title |
   the line), then the ruled rows. The old two-column grid with a pinned/sticky/in-flow left column is gone — the
   owner rejected every version of it moving. */
.ab-index { --row-pad: 1rem; list-style: none; margin: 0; padding: 0; }
.ab-group-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1.5rem; padding: 2rem 0 1.75rem; border-top: 1px solid var(--paper); }
/* The group's starting price, right-aligned on the title's baseline — same figures as services.html. */
.ab-group-price { flex: none; color: var(--paper-60); font-size: clamp(1rem, 1.3vw, 1.2rem); font-weight: 500; font-variant-numeric: tabular-nums; }
.ab-group-head:not(:first-child) { margin-top: clamp(4rem, 8vh, 6rem); }
.ab-index { --num-w: 3.4rem; }   /* the number column; rows indent past it so they hang under the title */
.ab-group-title { display: flex; align-items: baseline; gap: 1.25rem; }
/* Numbers in the display face, bold, full paper (owner, 2026-09-11: "cleaner, bolder") — the mono micro-label read as a footnote. */
/* Number and title share one size and weight — one heading line, the number an index to it (owner, 2026-09-11:
   the smaller number "didn't fit hierarchically"). */
.ab-group-title .n,
.ab-group-title h3 { margin: 0; font-family: var(--display); font-weight: 700; font-size: clamp(1.6rem, 2.6vw, 2.6rem); letter-spacing: -0.03em; line-height: 1.02; }
.ab-group-title .n { flex: 0 0 var(--num-w); color: var(--paper-60); font-variant-numeric: tabular-nums; }
/* The rows: hairline ruled, indented to the title's column so they hang under it; the reading-line inversion
   (js/about.js .is-active) is the section's only motion. */
.ab-row {
  padding: 0.85rem var(--row-pad) 0.85rem calc(var(--num-w) + 1.25rem);   /* text hangs under the group title */
  border-top: 1px solid var(--hairline-light);
  color: var(--paper-40);
  font-size: clamp(1.15rem, 1.8vw, 1.65rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.15;
  transition: background-color 180ms ease, color 180ms ease;
}
.ab-row:last-child { border-bottom: 1px solid var(--hairline-light); }
.ab-row.is-active { background-color: var(--paper); color: var(--black); }
.ab-row:hover:not(.is-active) { color: var(--paper); }

/* How we work: the process diagram. Four big rings stepping up and down
   across the row, a line zigzagging through their centres. The line is an
   SVG path (js/about.js draws it from the ring positions): a hairline base
   and a paper fill drawn on with stroke-dashoffset as you scroll; a ring
   fills to paper when the fill reaches it. */
.ab-how-head { margin-bottom: clamp(3rem, 7vh, 5rem); }

.ab-diagram { --ring: clamp(6rem, 9vw, 9.5rem); --zig: clamp(2.5rem, 5vw, 5rem); position: relative; }
.ab-zig {
  position: absolute;
  left: 0; top: 0;
  width: 100%;
  height: calc(var(--ring) + var(--zig));
  overflow: visible;
  pointer-events: none;
}
.ab-zig path { fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.ab-zig-base { stroke: rgba(248, 248, 248, 0.22); }
.ab-zig-fill { stroke: var(--paper); }
/* The head: a paper dot riding the tip of the fill (js/about.js moves it). */
.ab-zig-head { fill: var(--paper); opacity: 0; transition: opacity 200ms ease; }
.ab-zig-head.is-on { opacity: 1; }
.ab-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 3rem);
}
.ab-step { position: relative; display: flex; flex-direction: column; }
/* The ring slot is as tall as ring + zig, so the text below lines up. */
.ab-ring {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--ring);
  height: var(--ring);
  margin-bottom: var(--zig);
  border-radius: 50%;
  border: 2px solid rgba(248, 248, 248, 0.5);
  background: var(--black);
  color: var(--paper);
  font-family: var(--display);
  font-weight: 900;
  font-size: calc(var(--ring) * 0.34);
  line-height: 1;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  transition: background-color 260ms ease, color 260ms ease, border-color 260ms ease, transform 320ms var(--ease-out);
}
.ab-step:nth-child(even) .ab-ring { margin-top: var(--zig); margin-bottom: 0; }
.ab-ring.is-lit { background: var(--paper); border-color: var(--paper); color: var(--black); transform: scale(1.03); }
/* The pulse: a ring-shaped echo that expands off the circle as it lights. */
.ab-ring::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  border: 1px solid var(--paper);
  opacity: 0;
  pointer-events: none;
}
.ab-ring.is-lit::after { animation: ab-pulse 900ms var(--ease-out) forwards; }
@keyframes ab-pulse {
  from { opacity: 0.35; transform: scale(1); }
  to { opacity: 0; transform: scale(1.22); }
}
/* The text under a ring sits dim until its ring lights. */
.ab-step h3, .ab-step p { opacity: 0.6; transition: opacity 500ms ease; }
.ab-step.is-lit h3 { opacity: 1; }
.ab-step.is-lit p { opacity: 1; }
.ab-step h3 {
  margin-top: clamp(1.75rem, 3.5vh, 2.5rem);
  min-height: 2.1em; /* room for two lines, so every paragraph starts level */
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.35rem, 1.9vw, 1.75rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
/* The How-we-work panel (2026-09-11): one hairline frame on the flat black
   (no fill, no glow). It sits half in view under the hero and grows from 0.9
   scale to full as it scrolls up — scrubbed, via about.js. Origin is its top
   edge so the visible edge stays put. */
.ab-panel { border: 1px solid var(--hairline-light); border-radius: 16px; padding: clamp(2rem, 4vw, 4rem) clamp(1.5rem, 3.5vw, 3.5rem); transform-origin: 50% 0; will-change: transform, opacity; }
/* Values: numbered ruled rows, one line each. */
.ab-step p { margin-top: 0.75rem; max-width: 22rem; color: var(--paper-60); line-height: 1.5; font-size: 1rem; }

@media (max-width: 1100px) {
  .ab-zig { display: none; }
  .ab-step:nth-child(even) .ab-ring { margin-top: 0; margin-bottom: var(--zig); }
  .ab-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 3.5rem; }
}
@media (max-width: 900px) {
  .ab-hero { padding: 6rem 0 3.5rem; }
  .ab-open { min-height: 0; grid-template-columns: 1fr; row-gap: 2.5rem; }
  .ab-open-art { order: -1; width: min(48vw, 14rem); justify-self: end; }
  .ab-hero .ab-opener { max-width: 9ch; font-size: clamp(2.8rem, 12vw, 3.8rem); }
  .ab-panel { padding: 1.6rem 1.1rem; border-radius: 12px; }
  .ab-offer-head { flex-direction: column; align-items: flex-start; gap: 1.25rem; }
  .ab-why .wrap { padding-block: 6rem 7rem; }
  .ab-ease .wrap { padding-block: 3rem 4.5rem; }
  .ab-group-head { padding: 1.5rem 0 1.25rem; }
  .ab-index { --num-w: 2.6rem; }
  .ab-group-head:not(:first-child) { margin-top: 3rem; }
  .ab-index { --row-pad: 0.75rem; }
  .ab-row { padding: 0.95rem 0.75rem 0.95rem calc(var(--num-w) + 1.25rem); }
  .ab-how-head { flex-direction: column; align-items: flex-start; }
  .ab-how-head p { text-align: left; }
}
@media (max-width: 600px) {
  /* Phones: the price drops under the title, hung in the title's column, so the title keeps its line. */
  .ab-group-head { flex-direction: column; gap: 0.4rem; }
  .ab-group-price { padding-left: calc(var(--num-w) + 1.25rem); }
  .ab-diagram { --ring: 5.5rem; --zig: 1.5rem; }
  .ab-step h3 { min-height: 0; } /* one column: no level-line to hold */
  .ab-steps { grid-template-columns: 1fr; row-gap: 3rem; }
}
}
@media (max-width: 600px) {
  .ab-steps { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .ab-row, .ab-offer-link span, .ab-ring, .ab-zig-head, .ab-step h3, .ab-step p { transition: none; }
  .ab-ring.is-lit::after { animation: none; }
}

/* ---------- Services page, rows (2026-09-20) ----------
   Owner, after clay.global/services: one quiet row per discipline, the copy
   on one side and a single picture of that work on the other, sides
   alternating, a lot of black between them. No rules, no tiles, no strip. */
.svc-hero { padding-bottom: clamp(2rem, 4vh, 3rem); }
/* Two set lines, one per span (owner, 2026-09-22) */
.svc-hero h1 { max-width: none; font-size: clamp(2.9rem, 6.6vw, 6.8rem); }
.svc-hero h1 span { display: block; white-space: nowrap; }
.svc-hero-row { margin-top: clamp(2rem, 4vh, 3rem); }
.svc-hero p { margin-top: 0; max-width: 36rem; }

.svc-rows { padding: clamp(4rem, 9vh, 7rem) 0 clamp(6rem, 12vh, 9rem); }
.svc-row {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: clamp(1rem, 2vw, 2rem);
  align-items: center; scroll-margin-top: clamp(5rem, 10vh, 7rem);
}
.svc-row + .svc-row { margin-top: clamp(6rem, 15vh, 11rem); }
.svc-row-text { grid-column: 1 / span 5; grid-row: 1; }
.svc-row-media { grid-column: 8 / span 5; grid-row: 1; margin: 0; }
.svc-row.is-land .svc-row-media { grid-column: 7 / span 6; }
.svc-row:nth-child(even) .svc-row-text { grid-column: 8 / span 5; }
.svc-row:nth-child(even) .svc-row-media { grid-column: 1 / span 5; }
.svc-row.is-land:nth-child(even) .svc-row-media { grid-column: 1 / span 6; }
.svc-row-media img, .svc-row-media video {
  display: block; width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover;
  background: #0a0a0a; border-radius: 1rem;
}
.svc-row.is-land .svc-row-media img, .svc-row.is-land .svc-row-media video { aspect-ratio: 16 / 9; }
/* Web row reel: two clips stacked, faded between by main.js. 16:9 so neither
   device rig is cropped. */
.svc-reel { position: relative; }
.svc-row.is-land .svc-reel video { opacity: 0; transition: opacity 900ms ease; }
.svc-reel video + video { position: absolute; inset: 0; height: 100%; }
.svc-row.is-land .svc-reel video.is-on { opacity: 1; }
/* Social row slider: a snap-scrolling track, one slide per view */
.svc-slider-track {
  display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
  border-radius: 1rem; background: #0a0a0a; overscroll-behavior-x: contain;
}
.svc-slider-track::-webkit-scrollbar { display: none; }
.svc-slider-track:focus-visible { outline: 2px solid var(--paper); outline-offset: 4px; }
.svc-slider .svc-slider-track > * { flex: 0 0 100%; scroll-snap-align: start; border-radius: 0; }
.svc-slider-nav { display: flex; align-items: center; justify-content: space-between; margin-top: 0.5rem; }
.svc-slider-dots { display: flex; gap: 0.4rem; flex: 1 1 auto; min-width: 0; }
.svc-slider-dots button {
  position: relative; flex: 1 1 0; max-width: 2.25rem; height: 2.75rem; padding: 0; border: 0; background: none; cursor: pointer;
}
.svc-slider-dots button::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px; border-radius: 1px;
  background: var(--paper); opacity: 0.22; transition: opacity 250ms ease;
}
/* the fill: main.js runs it 0 to 1 over the slide's two seconds; slides already
   played stay full, the ones to come stay empty */
.svc-slider-dots span {
  position: absolute; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px; border-radius: 1px;
  background: var(--paper); transform: scaleX(0); transform-origin: 0 50%;
}
.svc-slider-dots button.is-done span { transform: scaleX(1); }
.svc-slider-arrows { display: flex; margin-right: -0.6rem; }
.svc-slider-arrows button {
  display: grid; place-items: center; width: 2.75rem; height: 2.75rem; padding: 0; border: 0; background: none;
  color: var(--paper); cursor: pointer; transition: opacity 200ms ease;
}
.svc-slider-arrows svg { transition: transform 200ms var(--ease-out); }
.svc-slider-arrows button:disabled { opacity: 0.25; cursor: default; }
.svc-slider-arrows button:active:not(:disabled) svg { transform: scale(0.94); }
@media (hover: hover) {
  .svc-slider-dots button:hover::after { opacity: 0.6; }
  .svc-slider-arrows button[data-dir="1"]:not(:disabled):hover svg { transform: translateX(3px); }
  .svc-slider-arrows button[data-dir="-1"]:not(:disabled):hover svg { transform: translateX(-3px); }
}
.svc-row-text h2 {
  font-family: var(--display); font-weight: 700; font-size: clamp(2.1rem, 3.4vw, 3.25rem);
  line-height: 1.05; letter-spacing: -0.02em;
}
.svc-row-text > p { margin-top: 1.25rem; max-width: 32rem; line-height: 1.6; text-wrap: pretty; color: var(--paper-60); }
/* Deliverables as the About page's ruled index (owner, 2026-09-22): hairline rows, the one under the reading
   line inverts to paper (js/services.js). The rows bleed out by their own padding so the text stays on the
   heading's edge while the paper fill has room around it. */
.svc-row-text ul, .svc-row-list { --row-pad: 0.9rem; list-style: none; margin: clamp(1.75rem, 3.5vh, 2.5rem) calc(var(--row-pad) * -1) 0; padding: 0; }
.svc-row-text li, .svc-row-list li {
  padding: 0.75rem var(--row-pad);
  border-top: 1px solid var(--hairline-light);
  color: var(--paper-40);
  font-size: clamp(1.05rem, 1.35vw, 1.3rem); font-weight: 500; letter-spacing: -0.02em; line-height: 1.2;
  transition: background-color 180ms ease, color 180ms ease;
}
.svc-row-text li:last-child, .svc-row-list li:last-child { border-bottom: 1px solid var(--hairline-light); }
.svc-row-text li.is-active, .svc-row-list li.is-active { background-color: var(--paper); color: var(--black); }
@media (hover: hover) { .svc-row-text li:hover:not(.is-active), .svc-row-list li:hover:not(.is-active) { color: var(--paper); } }
.svc-row-text > .svc-row-meta { margin-top: clamp(1.75rem, 3.5vh, 2.5rem); font-size: 0.9375rem; }
.svc-row-meta span { display: block; margin-bottom: 0.35rem; color: var(--paper); font-weight: 500; font-variant-numeric: tabular-nums; }
.svc-row-meta a { color: var(--paper); border-bottom: 1px solid var(--hairline-light); transition: border-color 200ms ease; }
.svc-row-meta a:hover { border-color: var(--paper); }
.svc-row-plain { align-items: start; }
.svc-row-plain .svc-row-list { grid-column: 8 / span 5; grid-row: 1; margin-top: 0.35rem; margin-right: 0; }
/* text always left, list right, whichever side the alternation would put it on */
.svc-row.svc-row-plain .svc-row-text { grid-column: 1 / span 5; }

@media (max-width: 800px) {
  .svc-hero { padding: 6rem 0 1.5rem; }
  .svc-hero h1 { font-size: clamp(2rem, 8.6vw, 3.6rem); }
  .svc-rows { padding: 3rem 0 4.5rem; }
  .svc-row + .svc-row { margin-top: 5rem; }
  .svc-row .svc-row-text, .svc-row .svc-row-media, .svc-row .svc-row-list { grid-column: 1 / -1 !important; grid-row: auto; }
  .svc-row .svc-row-media { order: -1; margin-bottom: 2rem; }
  .svc-row-media img, .svc-row-media video { border-radius: 0.75rem; }
  .svc-reel { margin-bottom: 2rem; }
  .svc-slider-track { border-radius: 0.75rem; }
  .svc-row-plain .svc-row-list { margin-top: 2rem; margin-right: calc(var(--row-pad) * -1); }
}

/* Selected text on the black grounds was invisible (ink on 16% ink). Paper
   on every dark zone; the legal pages stay on paper and keep the ink rule. */
.zone-black ::selection,
.zone-black::selection,
.site-footer ::selection,
.nav.on-dark ::selection { background: rgba(248, 248, 248, 0.3); color: var(--paper); }

/* ---------- Mobile menu (js/mobile-menu.js, owner 2026-09-22) ----------
   Under 900px the routes live behind a hamburger: three paper lines on the LEFT, first in the nav pill and first in
   the landing hero's header row. The menu is a full-screen black sheet: close cross + wordmark on top (where the
   burger was), the four routes centred and set big in Inter (the nav's own face; Haas Display only exists on the
   studio machine, so on a phone it fell back to Archivo), a paper CTA and the address centred at the foot. */
.nav-burger { display: none; }
@media (max-width: 900px) {
  .nav-burger {
    display: inline-grid; place-content: center; gap: 5px; flex: none;
    width: 2.75rem; height: 2.75rem; padding: 0; margin: 0 0 0 -0.6rem; border: 0; border-radius: 999px;
    background: none; color: var(--paper); cursor: pointer;
    -webkit-tap-highlight-color: transparent; transition: transform 160ms var(--ease-out);
  }
  .nav-burger span { display: block; width: 20px; height: 1.5px; border-radius: 1px; background: currentColor; }
  .nav-burger:active { transform: scale(0.94); }
  .nav-burger:focus-visible { outline: 2px solid var(--paper); outline-offset: 2px; }
  .nav:not(.is-stuck) .nav-burger { color: var(--ink); }
  .nav.on-dark .nav-burger, .nav.is-stuck .nav-burger { color: var(--paper); }
  /* the pill: burger | wordmark | Contact */
  .nav-inner:has(> .nav-burger) { grid-template-columns: auto 1fr auto; column-gap: 0.35rem; }
  .nav.is-stuck .nav-inner:has(> .nav-burger) { padding-left: 0.95rem; }
  /* the hero header: burger | wordmark | Start a project */
  .hero-frame .hd:has(> .nav-burger) { grid-template-columns: auto 1fr auto; column-gap: 0.35rem; }
  .hero-frame .hd .cta { grid-column: 3; justify-self: end; }
}

.m-menu {
  position: fixed; inset: 0; z-index: 300;
  display: flex; flex-direction: column;
  padding: 0 var(--pad-x) max(1.75rem, env(safe-area-inset-bottom));
  background: var(--black); color: var(--paper);
  overflow-y: auto; overscroll-behavior: contain;
}
.m-menu[hidden] { display: none; }
.m-menu-top { display: flex; align-items: center; gap: 0.35rem; min-height: 4.5rem; padding-top: 0.6rem; }
.m-menu-logo img { display: block; height: 23px; width: auto; }
.m-menu-close {
  position: relative; flex: none; width: 2.75rem; height: 2.75rem; margin-left: -0.6rem; padding: 0; border: 0;
  background: none; color: var(--paper); cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: transform 160ms var(--ease-out);
}
.m-menu-close span { position: absolute; left: 50%; top: 50%; width: 20px; height: 1.5px; margin: -0.75px 0 0 -10px; border-radius: 1px; background: currentColor; }
.m-menu-close span:first-child { transform: rotate(45deg); }
.m-menu-close span:last-child { transform: rotate(-45deg); }
.m-menu-close:active { transform: scale(0.94); }
.m-menu-close:focus-visible { outline: 2px solid var(--paper); outline-offset: 2px; border-radius: 999px; }
.m-menu-links { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; margin-block: auto; padding-block: 2rem; }
.m-menu-links a { display: block; padding: 0.3rem 0.5rem; color: var(--paper); text-decoration: none; text-align: center; }
.m-line { display: block; overflow: hidden; padding-bottom: 0.08em; }
.m-word {
  display: block; font-family: var(--body); font-weight: 600; letter-spacing: -0.04em; line-height: 1.05;
  font-size: clamp(2.5rem, 11.5vw, 3.75rem);
}
.m-menu-links a[aria-current="page"] .m-word { color: var(--paper-40); }
.m-menu-foot { display: flex; flex-direction: column; align-items: center; gap: 1.1rem; }
.m-menu-foot .m-menu-cta { font-size: 1rem; padding: 0.95rem 1.9rem; }
.m-menu-mail { font-size: 0.95rem; font-weight: 500; color: var(--paper-60); text-decoration: none; }
html.m-menu-open, html.m-menu-open body { overflow: hidden; }
@media (min-width: 901px) { .m-menu { display: none; } }

/* ---------- Phones: landing Services slab (owner, 2026-09-22: "make cleaner") ----------
   The (01) numeral stood on its own line with 2.5rem under it, so each group took three steps to start. On a
   phone the numeral and title share one heading line, the rows run the slab's full width, and the rows step
   back to 60% paper so the three titles carry the hierarchy. */
@media (max-width: 760px) {
  .services-slab { padding: 1.75rem 1.25rem 0.75rem; }
  .services-slab-head { padding-bottom: 1.1rem; }
  .services-col {
    display: grid; grid-template-columns: auto 1fr; column-gap: 0.7rem; align-items: baseline;
    padding: 1.6rem 0 1.4rem !important;
  }
  .services-num { margin: 0; font-size: 1.05rem; color: var(--paper-40); }
  .services-col h3 { margin: 0 0 0.85rem; font-size: 1.45rem; }
  .services-col ul { grid-column: 1 / -1; }
  .services-col li { padding: 0.55rem 0; font-size: 0.95rem; color: var(--paper-60); }
}

/* ---------- Phones: landing Blog strip, condensed (owner, 2026-09-22) ----------
   Four full-width cover cards ran to about two screens. On a phone each post is one compact row: a square cover
   on the left, the title and a two-line excerpt beside it. The whole row is the link, so the "Read article" pill
   stands down. */
@media (max-width: 760px) {
  .journal-bento { gap: 0.6rem; }
  .journal-bento .journal-card-link,
  .journal-bento .is-wide .journal-card-link { flex-direction: row; align-items: center; gap: 0.95rem; padding: 0.55rem; border-radius: 14px; }
  .journal-bento .journal-cover.art,
  .journal-bento .is-wide .journal-cover.art { flex: 0 0 5.75rem; width: 5.75rem; height: 5.75rem; aspect-ratio: 1; min-height: 0; border-radius: 9px; }
  .journal-bento .journal-meta,
  .journal-bento .is-wide .journal-meta { padding: 0.15rem 0.35rem 0.15rem 0; justify-content: center; min-width: 0; }
  .journal-bento .journal-meta h3,
  .journal-bento .is-wide .journal-meta h3 { font-size: 1.02rem; line-height: 1.22; letter-spacing: -0.01em; }
  .journal-bento .journal-excerpt,
  .journal-bento .is-wide .journal-excerpt { -webkit-line-clamp: 2; font-size: 0.8125rem; line-height: 1.4; margin-top: 0.3rem; }
  .journal-bento .journal-read { display: none; }
}

/* ---------- Phones: "Let's build yours." card (owner, 2026-09-22) ----------
   The card's clamp padding plus the page gutter left the fields a narrow column in the middle of the screen.
   On a phone the card's own inset drops to about the page gutter, the heading and fields step down a size. */
@media (max-width: 760px) {
  .contact-card { padding: 2rem 1.1rem 1.5rem; }
  .contact-head h2 { font-size: 2.6rem; }
  .contact-head p { margin-top: 1rem; font-size: 1rem; line-height: 1.5; }
  .contact-form { gap: 0.6rem; margin-top: 1.75rem; }
  .cf-field input, .cf-field textarea { padding: 0.95rem 1.25rem; font-size: 1rem; }
  .cf-drop-btn { padding: 0.95rem 1.1rem 0.95rem 1.25rem; font-size: 0.95rem; }
  .cf-field textarea { min-height: 7.5rem; border-radius: 1.25rem; }
  .cf-submit { padding: 1.05rem 2rem; }
}
@media (max-width: 760px) {
  /* condensed shelf, condensed air around it */
  .journal { padding: 4.5rem 0; }
}
