/* ── 01-tokens.css ── */
/* ═══════════════════════════════════════════════════════════════
   TOKENS
   Colour and type values are taken directly from the OVERSTAND
   Brand System (Vol. 1 · 2026). Do not introduce new colours.
   ═══════════════════════════════════════════════════════════════ */

/* Display / wordmark / signage. The Brand System sets this as 'Radikal',
   mapped to Space Grotesk as the licensed visual reference. When URW Radikal
   is licensed, drop the file in and add it ahead of Space Grotesk below. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/SpaceGrotesk-normal.woff') format('woff');
}

/* Editorial / manifesto / callouts. Italic is the working weight. */
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/InstrumentSerif-italic.woff') format('woff');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/InstrumentSerif-normal.woff') format('woff');
}

/* Body / metadata / UI. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/assets/fonts/Inter-normal.woff') format('woff');
}

:root {
  /* ─── Palette ───
     The site runs monochrome on a permanent ink ground. Contrast between
     sections no longer comes from ink/paper alternation - it comes from
     scale, hairlines, whitespace and the selected background images.

     --paper is the Brand System's second colour. It is kept here because the
     mark is still specified as cream on ink for print, packaging and signage,
     but the digital surface uses white. Do not reintroduce it as a ground. */
  --ink:      #000000;
  --paper:    #F5F2EA;
  --white:    #FFFFFF;

  /* Three greys, and only three. No warmth, so nothing reads as cream.

     They had been drifting section by section, which is the kind of
     inconsistency the eye reads as carelessness long before it can name it.
     Each one now has exactly one job:

       100%  display type, item titles, links, the email address
        72%  every lead and body paragraph
        45%  meta labels, and nothing else

     Nothing sits below 45%. A paragraph that should feel quieter moves to
     the indent at body size; it does not get lighter. */
  --grey-100: #E6E6E6;
  --grey-200: #B8B8B8;  /* 72% */
  --grey-300: #737373;  /* 45% */
  --grey-900: #0A0A0A;

  /* ─── Families ─── */
  --font-display: 'Space Grotesk', 'Helvetica Neue', Arial, sans-serif;
  --font-serif:   'Instrument Serif', Georgia, 'Times New Roman', serif;
  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* ─── Display scale ───
     Two display sizes. XL is the one big moment on a page: the hero, the
     manifesto, the contact statement, one of them per page. Display is
     every section headline. A size between the two blurs the ranking,
     because the reader stops knowing whether a line outranks the one above.

     The vw terms are set so the intended bands are reached at the widths
     the site is actually read at: XL lands 96-128px from 1070px up, Display
     lands 72-96px from 1080px up. Below that both keep shrinking, because a
     fixed 96px headline on a phone is not confidence, it is three words to
     a line. */
  --t-display-xl: clamp(2.75rem,  7.2vw,  8rem);   /* 44 - 128px */
  --t-display:    clamp(2.125rem, 6.53vw, 5.875rem); /* 34 - 94px */

  /* Item titles - step, field and principle titles. Repeats inside a
     section, so it ranks below Display rather than varying it. */
  --t-display-m:  clamp(1.625rem, 3.6vw, 3rem);
  --t-display-s:  clamp(1.25rem, 2vw,   1.625rem);

  /* A standalone link set as an object rather than as running text: the
     email address. Small on purpose - it is a destination, not a banner. */
  --t-title: clamp(1.125rem, 1.4vw, 1.25rem);      /* 18 - 20px */

  /* ─── Text scale ───
     Lead is the step between a 100px headline and its copy. Without it the
     paragraph reads as a caption to the headline rather than as the argument.

     Both sizes are set larger than a default web body, and deliberately so.
     Text can only occupy width by being big enough to fill it: at 17px a
     line spanning two thirds of a 1250px bed runs to ninety-odd characters,
     which nobody reads. At 21px the same width is around eighty, at 28px the
     lead is around sixty. The measure stays honest and the page stops
     looking like a narrow column with an empty half beside it.

     They still scale down to 16 and 19px on a phone, where the width is not
     there to be filled in the first place. */
  --t-lede: clamp(1.1875rem, 1.95vw, 1.75rem);     /* 19 - 28px */
  --t-body: clamp(1rem,      1.45vw, 1.375rem);    /* 16 - 22px */
  --t-meta: clamp(0.625rem,  0.72vw, 0.6875rem);

  /* ─── Tracking · locked to the Brand System ─── */
  --track-os:       -0.055em;  /* the OS mark */
  --track-wordmark: -0.045em;  /* OVERSTAND set full */
  --track-display:  -0.035em;  /* headlines */
  --track-meta:      0.22em;   /* uppercase Inter metadata */

  /* ─── Rhythm ─── */
  --margin:  clamp(1.5rem, 6vw, 6rem);
  --gutter:  clamp(1rem, 2.2vw, 2rem);

  /* Eleven of twelve columns, gutters included. Every display headline stops
     here, so one column of air always stands between the longest line and
     the right page margin. A headline that ends flush against the edge does
     not read as confident, it reads as too big for the page - same size, one
     column of air, completely different impression.

     Derived rather than eyeballed: eleven columns plus ten gutters, as a
     share of twelve columns plus eleven gutters. */
  --measure-11: calc(91.6667% - var(--gutter) / 12);
  --section: clamp(5.5rem, 13vh, 11rem);
  --stack:   clamp(2rem, 5vh, 4.5rem);

  /* ─── Motion · slower and calmer than a typical startup site ─── */
  --ease:        cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast:    280ms;
  --dur:         620ms;
  --dur-slow:    1100ms;

  --nav-h: clamp(4.25rem, 7vh, 5.5rem);
}

/* ─── One ground, everywhere ───
   Declared on :root rather than per section, because there is no longer a
   second ground to switch to. Sections that carry a background image sit on
   the same values; the scrim keeps them legible. */
:root {
  --bg:        var(--ink);
  --fg:        var(--white);
  --fg-soft:   var(--grey-200);
  --fg-muted:  var(--grey-300);
  --rule:      rgba(255, 255, 255, 0.16);
  --rule-firm: rgba(255, 255, 255, 0.42);

  /* How far the scrim knocks a background image back so type stays readable.
     Raise it for busy or bright photography. */
  --scrim: 0.62;
}


/* ── 02-base.css ── */
/* ═══════════════════════════════════════════════════════════════
   BASE
   ═══════════════════════════════════════════════════════════════ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  background: var(--ink);
}

body {
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: 1.6;
  background: var(--ink);
  color: var(--white);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
  /* clip rather than hidden: hidden would turn body into a scroll container,
     which changes how position:fixed and scroll observers behave. */
  overflow-x: clip;
}

/* Scroll during the intro is held on <html> - see the intro rules in
   05-sections.css, which are driven synchronously by the head gate. */

img, svg, video { display: block; max-width: 100%; }
img, video { height: auto; }

a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }

::selection { background: var(--white); color: var(--ink); }

/* ─── Focus · visible, sharp, never removed ─── */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

/* ─── Skip link ─── */
.skip {
  position: absolute;
  top: 0; left: 0;
  z-index: 200;
  padding: 1rem 1.5rem;
  background: var(--ink);
  color: var(--white);
  border: 1px solid var(--white);
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  transform: translateY(-101%);
}
.skip:focus-visible { transform: translateY(0); outline-offset: -4px; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ═══════════════════════════════════════════════════════════════
   TYPE PRIMITIVES
   ═══════════════════════════════════════════════════════════════ */

.display {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 0.92;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  text-wrap: balance;
}

.serif {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.005em;
  text-transform: none;
}

/* Metadata: uppercase Inter, generous letter spacing. */
.meta {
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--fg-muted);
}

/* The first paragraph of a section. Every section has one, and it is the
   step that carries the reader down from the headline.

   It used to be set in the serif italic, which spent the brand's one gesture
   on a paragraph nobody reads as a signature, and cost legibility doing it -
   the italic thins out badly at paragraph size on an ink ground. Anything a
   visitor reads for more than two lines is Inter. */
.lede {
  font-size: var(--t-lede);
  line-height: 1.5;
  color: var(--fg-soft);
  /* Sixty characters on the line.

     Not "60ch": the CSS ch unit is the width of a zero, and in Inter a zero
     is narrower than the average letter, so 60ch renders around 75 characters.
     Measured against the real face: 48ch still set 70 characters, so the
     value is 41ch. The grid column is wider than this, so the measure is
     what sets the line, not the column. */
  max-width: 41ch;
  text-wrap: pretty;
}

/* Every paragraph after the first. */
.body-text {
  font-size: var(--t-body);
  line-height: 1.65;
  color: var(--fg-soft);
  max-width: 78ch;
  text-wrap: pretty;
}

/* An aside: a genuine second thought, set at the one indent. Same size and
   same grey as body copy - the position carries the demotion, not the
   colour. A paragraph that should feel quieter is moved, never lightened,
   because there is no grey below 45% and 45% belongs to meta labels. */
.body-aside {
  font-size: var(--t-body);
  line-height: 1.65;
  color: var(--fg-soft);
  max-width: 52ch;
  text-wrap: pretty;
}

/* Hand-set line breaks in display headlines.

   A rag composed for a wide column is a random rag on a narrow one, so the
   breaks are released below the point where the editorial grid itself
   collapses. Above it the shape is a decision; below it the headline is
   allowed to find its own, because there is only one sensible measure left. */
@media (max-width: 899px) {
  br.brk { display: none; }
}

.h-xl { font-size: var(--t-display-xl); }
.h-l  { font-size: var(--t-display); }
.h-m  { font-size: var(--t-display-m); }
.h-s  { font-size: var(--t-display-s); }

/* ─── Placeholder marking ───
   Any content still awaiting real copy is rendered inside .ph so it is
   unmistakable in review, and quiet enough not to wreck the composition. */
.ph {
  color: var(--fg-muted);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
}

/* ═══════════════════════════════════════════════════════════════
   REDUCED MOTION
   Everything remains present and readable; only the movement stops.
   ═══════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  /* Scroll-revealed content is shown outright rather than faded in. */
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
}


/* ── 03-layout.css ── */
/* ═══════════════════════════════════════════════════════════════
   GRID & LAYOUT
   12 columns, large outer margins, generous negative space.
   Sections carry their own ground colour so the page reads as a
   sequence of ink and paper rather than a single scrolling box.
   ═══════════════════════════════════════════════════════════════ */

.section {
  position: relative;
  background: var(--bg);
  color: var(--fg);
  padding-block: var(--section);
}

.section--tight { padding-block: calc(var(--section) * 0.55); }
.section--flush-top { padding-top: 0; }

/* ═══════════════════════════════════════════════════════════════
   SECTION BACKGROUND
   Selected sections carry a full-bleed image. The ground is the
   same ink everywhere, so the image is the contrast - not a
   change of colour.
   ═══════════════════════════════════════════════════════════════ */

.section--media {
  position: relative;
  isolation: isolate;
}

.section-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  background: var(--ink);
}

.section-bg img,
.section-bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Backgrounds run monochrome with the rest of the site. Applied here rather
     than baked into the files, so the originals stay intact and this is one
     line to lift if a shot ever needs its colour.
     Deliberately limited to section backgrounds: case photography keeps its
     colour, because that is the work speaking, not the surface. */
  filter: var(--bg-filter, grayscale(1));
}

/* Knocks the image back so display type stays readable over unknown
   photography. Tune per section with --scrim; this is legibility, not
   decoration, so it stays flat rather than becoming a gradient effect. */
.section-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, var(--scrim));
}

/* The empty state: a near-black field inside a hairline frame, so the
   reserved area is obvious in review without lighting up the page. */
.section-bg--placeholder {
  background: var(--grey-900);
}

.section-bg--placeholder::before {
  content: '';
  position: absolute;
  inset: var(--margin);
  border: 1px solid var(--rule);
}

.section-bg--placeholder::after { background: none; }

/* Tucked just inside the frame's top-right, which is clear of the copy on
   every section that carries a background. */
.section-bg__label {
  position: absolute;
  top: calc(var(--margin) + 1rem);
  right: calc(var(--margin) + 1rem);
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg-muted);
  white-space: nowrap;
}

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

/* ─── The 12-column bed ─── */
.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: var(--stack);
}

/* Column spans. Mobile collapses everything to full width; the editorial
   asymmetry is reintroduced from 900px up. */
[class*='col-'] { grid-column: 1 / -1; }

/* The span goes on grid-column-END. Setting the shorthand instead would put
   the span on the start edge, and any .start-* class would then override it
   and collapse the element to a single column. */
@media (min-width: 900px) {
  .col-1  { grid-column-end: span 1; }
  .col-2  { grid-column-end: span 2; }
  .col-3  { grid-column-end: span 3; }
  .col-4  { grid-column-end: span 4; }
  .col-5  { grid-column-end: span 5; }
  .col-6  { grid-column-end: span 6; }
  .col-7  { grid-column-end: span 7; }
  .col-8  { grid-column-end: span 8; }
  .col-9  { grid-column-end: span 9; }
  .col-10 { grid-column-end: span 10; }
  .col-11 { grid-column-end: span 11; }
  .col-12 { grid-column: 1 / -1; }

  .start-2  { grid-column-start: 2; }
  .start-3  { grid-column-start: 3; }
  .start-4  { grid-column-start: 4; }
  .start-5  { grid-column-start: 5; }
  .start-6  { grid-column-start: 6; }
  .start-7  { grid-column-start: 7; }
  .start-8  { grid-column-start: 8; }
  .start-9  { grid-column-start: 9; }
  .start-10 { grid-column-start: 10; }
  .start-11 { grid-column-start: 11; }
}

/* ─── Editorial devices ─── */
.rule {
  border: 0;
  border-top: 1px solid var(--rule);
  width: 100%;
}

/* Eyebrow above a section, sitting on its own hairline. */
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--gutter);
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: var(--stack);
}

/* align-content:start keeps the gap fixed when the column is taller than its
   contents, instead of spreading the items down the whole grid row. */
.stack-sm { display: grid; gap: 0.75rem; align-content: start; }
.stack-md { display: grid; gap: 1.5rem; align-content: start; }
.stack-lg { display: grid; gap: var(--stack); align-content: start; }

/* Full-bleed escape from the wrap. */
.bleed {
  width: 100vw;
  margin-inline: calc(50% - 50vw);
}

/* ═══════════════════════════════════════════════════════════════
   MEDIA
   Placeholders are neutral surfaces with a label. When a real asset
   is supplied it fills the same frame; nothing else changes.
   ═══════════════════════════════════════════════════════════════ */

.media {
  position: relative;
  width: 100%;
  aspect-ratio: var(--ratio, 16 / 9);
  overflow: hidden;
  background: var(--media-bg, rgba(255, 255, 255, 0.04));
}

.media img,
.media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The empty state: a quiet field, a hairline border, a label. */
.media--placeholder {
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  background: var(--media-bg);
}

.media--placeholder .media__label {
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.media__caption {
  margin-top: 1rem;
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* ═══════════════════════════════════════════════════════════════
   SCROLL REVEAL
   Fade and a small translate. Nothing bounces, nothing overshoots.
   ═══════════════════════════════════════════════════════════════ */

[data-reveal] {
  opacity: 0;
  transform: translateY(1.25rem);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
}

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* Mask reveal, for lines of display type. */
[data-reveal='mask'] {
  opacity: 1;
  transform: none;
  clip-path: inset(0 0 105% 0);
  transition: clip-path var(--dur-slow) var(--ease-out);
}

[data-reveal='mask'].is-revealed { clip-path: inset(0 0 -20% 0); }

/* Until the observer has run, nothing is hidden for users without JS. */
.no-js [data-reveal] { opacity: 1; transform: none; clip-path: none; }


/* ── 04-components.css ── */
/* ═══════════════════════════════════════════════════════════════
   THE OS MARK
   O from OVER, S from STAND. Never redrawn - it is set in the
   display face at the locked tracking, exactly as the wordmark is.
   ═══════════════════════════════════════════════════════════════ */

.os-mark {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 0.7;
  letter-spacing: var(--track-os);
  text-transform: uppercase;
}

.wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: var(--track-wordmark);
  text-transform: uppercase;
  line-height: 0.85;
}

/* ═══════════════════════════════════════════════════════════════
   HEADER
   Quiet, sticky, hairline only once the page has moved.
   ═══════════════════════════════════════════════════════════════ */

.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  color: var(--white);
  /* Transparent only at the very top, where nothing is behind it yet and the
     hero image should reach the edge. The moment the page moves it becomes
     solid, so content passes behind the bar instead of through it. */
  background: transparent;
  transition: background-color 220ms var(--ease);
}

.header.is-stuck { background: var(--ink); }

.header__inner {
  width: 100%;
  max-width: 120rem;
  margin-inline: auto;
  padding-inline: var(--margin);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
}

.header.is-stuck::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  opacity: 0.16;
}

/* Home link - the mark is the only route home. */
.header__home {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.5rem 0;
}

.header__home .os-mark { font-size: 1.5rem; }

.header__home .wordmark {
  font-size: var(--t-meta);
  letter-spacing: var(--track-meta);
  font-weight: 500;
  font-family: var(--font-body);
  color: currentColor;
  opacity: 0.55;
  transition: opacity var(--dur-fast) var(--ease);
}

.header__home:hover .wordmark { opacity: 1; }

/* ─── Desktop navigation ─── */
.nav { display: none; }

@media (min-width: 860px) {
  .nav { display: flex; align-items: center; gap: clamp(1.5rem, 2.6vw, 2.75rem); }
  .nav__toggle { display: none; }
}

.nav__link {
  position: relative;
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  padding: 0.5rem 0;
}

/* Underline draws from the left; it does not slide or bounce. */
.nav__link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0.15rem;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur) var(--ease-out);
}

.nav__link:hover::after,
.nav__link:focus-visible::after,
.nav__link[aria-current='page']::after { transform: scaleX(1); }

.nav__link[aria-current='page'] { opacity: 1; }

/* ─── Mobile ─── */
.nav__toggle {
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  padding: 0.75rem 0;
  color: inherit;
}

@media (min-width: 860px) { .nav__toggle { display: none; } }

.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--ink);
  color: var(--white);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--nav-h) var(--margin) var(--section);
  opacity: 0;
  visibility: hidden;
  /* visibility is stepped rather than interpolated: it flips to visible the
     instant the menu opens (so the links are immediately focusable), and is
     held back until the fade has finished when it closes. Transitioning it
     like opacity would leave the panel computed-hidden on the opening frame,
     and a hidden element silently refuses focus. */
  transition: opacity var(--dur) var(--ease), visibility 0s linear var(--dur);
}

.mobile-nav[data-open='true'] {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur) var(--ease), visibility 0s linear 0s;
}

.mobile-nav__list { display: grid; gap: 0.35rem; }

.mobile-nav__link {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.25rem, 11vw, 4.5rem);
  line-height: 1.05;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  padding: 0.25rem 0;
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}

.mobile-nav[data-open='true'] .mobile-nav__link {
  opacity: 1;
  transform: none;
  transition-delay: var(--i-delay, 0ms);
}

.mobile-nav__link[aria-current='page'] { color: var(--fg-soft); }


/* ═══════════════════════════════════════════════════════════════
   LINKS
   Buttons are rare. Emphasis comes from a rule and an arrow.
   ═══════════════════════════════════════════════════════════════ */

.link {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule-firm);
  transition: border-color var(--dur-fast) var(--ease);
}

.link__arrow {
  display: inline-block;
  transition: transform var(--dur) var(--ease-out);
}

.link:hover { border-bottom-color: currentColor; }
.link:hover .link__arrow,
.link:focus-visible .link__arrow { transform: translateX(0.35rem); }

/* The email address.

   It was set at display size, which made it the loudest thing in the section
   and left it reading as a banner rather than as somewhere to go. A
   destination does not need to be large; it needs to be unmistakably a link
   and unmistakably clickable. Full-strength ink, item-title size, and the
   underline arrives on hover. */
.link-lg {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-title);
  color: var(--fg);
  letter-spacing: var(--track-display);
  line-height: 1.2;
  text-transform: uppercase;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size var(--dur) var(--ease-out);
}

.link-lg:hover,
.link-lg:focus-visible { background-size: 100% 1px; }

/* ═══════════════════════════════════════════════════════════════
   FOOTER
   ═══════════════════════════════════════════════════════════════ */

.footer {
  background: var(--ink);
  color: var(--fg-soft);
  padding-block: calc(var(--section) * 0.5) 2.5rem;
}

.footer__top {
  display: grid;
  gap: var(--stack);
  grid-template-columns: 1fr;
  padding-bottom: var(--stack);
  border-bottom: 1px solid var(--rule);
}

@media (min-width: 700px) {
  .footer__top { grid-template-columns: 1.5fr repeat(3, 1fr); gap: var(--gutter); }
}

.footer__brand { display: grid; gap: 0.85rem; align-content: start; }
.footer__brand .os-mark { font-size: clamp(2.75rem, 6vw, 4.5rem); color: var(--white); }
.footer__brand .wordmark { font-size: var(--t-meta); font-family: var(--font-body); font-weight: 500; letter-spacing: var(--track-meta); }

.footer__col { display: grid; gap: 0.85rem; align-content: start; }
.footer__col h2 { font: inherit; }

.footer__heading {
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.footer__link {
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg);
  transition: color var(--dur-fast) var(--ease);
  justify-self: start;
}

.footer__link:hover,
.footer__link:focus-visible { color: var(--white); }

.footer__bottom {
  margin-top: 2.5rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* ═══════════════════════════════════════════════════════════════
   FORM
   ═══════════════════════════════════════════════════════════════ */

.form { display: grid; gap: 2.25rem; max-width: 44rem; }

.field { display: grid; gap: 0.65rem; }

.field label {
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--fg-muted);
}

.field input,
.field textarea {
  font-family: var(--font-body);
  font-size: var(--t-body);
  color: var(--fg);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-firm);
  border-radius: 0;
  padding: 0.5rem 0 0.85rem;
  transition: border-color var(--dur-fast) var(--ease);
  width: 100%;
}

.field textarea { resize: vertical; min-height: 7rem; line-height: 1.6; }

.field input:hover,
.field textarea:hover { border-bottom-color: var(--fg-muted); }

.field input:focus,
.field textarea:focus {
  outline: none;
  border-bottom-color: var(--fg);
}

.field input:focus-visible,
.field textarea:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }

.form__submit {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-body);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--rule-firm);
  transition: border-color var(--dur-fast) var(--ease);
}

.form__submit:hover { border-bottom-color: currentColor; }
.form__submit:hover .link__arrow { transform: translateX(0.35rem); }
.form__submit[disabled] { cursor: not-allowed; opacity: 0.5; }


/* ── 05-sections.css ── */
/* ═══════════════════════════════════════════════════════════════
   OS INTRO

     O            the O arrives, alone and centred
     OS           the S steps out beside it. The mark is complete,
                  and it holds there.
     OVERSTAND    VER and TAND unfold out of the two anchors

   No per-letter animation and no docking move at the end. The
   anchors stand side by side, so O + VER + S + TAND already spells
   the word: unfolding the two collapsed spans is the assembly. What
   looks like the halves travelling apart is the block re-centring
   as it widens, which costs nothing and is exactly on time.

   Opacity and width only. No scale, no bounce, no overshoot.
   ═══════════════════════════════════════════════════════════════ */

/* Hidden unless the head gate opts this visit in. That keeps the sequence
   off the page entirely for returning visitors, reduced motion and no-JS. */
.intro { display: none; }

html[data-run-intro] .intro {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  place-items: center;
  background: var(--ink);
  color: var(--white);
  transition:
    opacity var(--intro-reveal, 500ms) var(--ease),
    visibility 0s linear var(--intro-reveal, 500ms);
}

/* Scroll is held until the statement is on its way, not until the overlay
   node is finally removed. */
html[data-run-intro] { overflow: hidden; }
html[data-run-intro].intro-released { overflow: visible; }

/* Shrink to fit and centred by the grid above, so the mark stays optically
   centred at every width the word passes through on its way open. */
.intro__mark {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: min(12vh, 13vw);
  line-height: 1.06;
  letter-spacing: var(--track-wordmark);
  text-transform: uppercase;
  white-space: nowrap;
}

/* ─── The anchors ─── */
.intro__anchor {
  display: inline-block;
  opacity: 0;
  transition:
    opacity var(--anchor-dur, 620ms) var(--ease-out),
    transform var(--anchor-dur, 620ms) var(--ease-out);
}

/* The S does not simply appear. It steps out from behind the O, which is
   the moment two letters become the mark. Small on purpose: at this size
   an eighth of an em is already a visible move.

   The landing rule has to repeat the attribute selector, or it loses on
   specificity to the starting position and the S never settles. */
.intro__anchor[data-anchor='s'] { transform: translateX(-0.18em); }
.intro__anchor[data-in] { opacity: 1; transform: none; }
.intro__anchor[data-anchor='s'][data-in] { transform: none; }

/* ─── The unfold ───
   Clipped to zero width, so the letters are revealed out of the anchor
   rather than arriving from somewhere. vertical-align keeps overflow:hidden
   from dragging the baseline; white-space:pre keeps the tracking honest. */
.intro__grow {
  display: inline-block;
  width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: pre;
  vertical-align: bottom;
  will-change: width;
}

/* Opacity finishes well before the width does, so the letters are readable
   for most of the movement instead of catching up at the end. */
.intro[data-unfolding] .intro__grow {
  transition:
    width var(--unfold-dur, 1200ms) var(--ease-out),
    opacity calc(var(--unfold-dur, 1200ms) * 0.55) linear;
}

/* Handover beat 1 - the finished word leaves, rising, while the field
   behind it is still solid. It departs; it does not dissolve into its own
   background. */
.intro[data-exit] .intro__mark {
  opacity: 0;
  transform: translateY(-0.6rem);
  transition:
    opacity var(--intro-exit, 700ms) var(--ease),
    transform var(--intro-exit, 700ms) var(--ease);
}

/* Handover beat 2 - the field clears, uncovering the hero. */
.intro[data-done='true'] { opacity: 0; visibility: hidden; }

/* ═══════════════════════════════════════════════════════════════
   PAGE TRANSITION
   The mark answers the click. Leaving: the page is covered and the
   OS holds for a beat. Arriving: the cover fades and the new page
   is already there underneath.

   This is where the mark belongs in motion - it fires on navigation
   rather than on proximity, so it stays rare, and it never replays
   the full intro sequence. Sits below the intro in the stack.
   ═══════════════════════════════════════════════════════════════ */

.transition {
  position: fixed;
  inset: 0;
  z-index: 140;
  display: grid;
  place-items: center;
  background: var(--ink);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  /* The arriving fade - slower, because there is no hurry once the
     new page has loaded. */
  transition: opacity 420ms var(--ease), visibility 0s linear 420ms;
}

/* Covering, and the state the page is painted in on arrival. The
   leaving fade is quicker so navigation still feels immediate. */
html[data-transition-out] .transition,
html[data-transition-in] .transition {
  opacity: 1;
  visibility: visible;
  transition: opacity 280ms var(--ease), visibility 0s linear 0s;
}

.transition__mark {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(2.75rem, 8vw, 6rem);
  line-height: 0.7;
  letter-spacing: var(--track-os);
  text-transform: uppercase;
  color: var(--white);
  opacity: 0;
  transform: translateY(0.35rem);
  transition: opacity 240ms var(--ease-out), transform 240ms var(--ease-out);
}

html[data-transition-out] .transition__mark,
html[data-transition-in] .transition__mark {
  opacity: 1;
  transform: none;
  transition-delay: 70ms;
}

/* Reduced motion navigates straight there - no cover, no mark. */
@media (prefers-reduced-motion: reduce) {
  .transition { display: none; }
}

/* ═══════════════════════════════════════════════════════════════
   HERO
   Full viewport, ink, no button, no image, no paragraph.
   ═══════════════════════════════════════════════════════════════ */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  background: var(--ink);
  color: var(--white);
  padding-top: var(--nav-h);
}

.hero__inner {
  width: 100%;
  max-width: 120rem;
  margin-inline: auto;
  padding-inline: var(--margin);
  align-self: center;
  padding-block: var(--stack);
}

.hero__statement {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-xl);
  line-height: 0.94;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  max-width: var(--measure-11);
}

/* The one word that carries the idea, set in the editorial serif. */
.hero__statement .serif {
  text-transform: lowercase;
  letter-spacing: -0.01em;
  font-size: 1.06em;
}

/* Beat 3 - the statement is uncovered where it already stands. A hard edge
   travels across it; the type itself never moves.

   It used to slide up out of a mask, which is the most-used entrance on the
   web and reads as a presentation transition - cheap next to the intro, and
   at odds with a page that otherwise moves as little as possible. Wiping in
   place keeps the letterforms still and puts the movement into the reveal.

   The negative inset on the right leaves the italic overshoot and the full
   stop room, so the edge clears them instead of shaving them. */
.hero__line { display: block; }

/* Wiped in where it stands. Each element carries its own delay and duration,
   set on the markup, so the whole schedule lives in content/site.json and
   needs no JavaScript beyond the single .is-ready class. */
.hero__reveal {
  display: inline-block;
  clip-path: inset(0 100% 0 0);
  transition: clip-path var(--dur, 1150ms) var(--ease-out);
  transition-delay: var(--d, 0ms);
}

.hero.is-ready .hero__reveal { clip-path: inset(0 -0.14em 0 0); }

/* The closing word assembles letter by letter - the entrance's own gesture,
   returning on the one word it was built from. Kept on a single line so a
   letter can never wrap away mid-sequence. */
.hero__word { display: inline-block; white-space: nowrap; }

.hero__glyph {
  display: inline-block;
  opacity: 0;
  transform: translateY(0.14em);
  transition:
    opacity var(--glyph-in, 520ms) var(--ease-out),
    transform var(--glyph-in, 520ms) var(--ease-out);
  transition-delay: var(--d, 0ms);
}

.hero.is-ready .hero__glyph { opacity: 1; transform: none; }

/* Without JavaScript nothing ever adds .is-ready, so the statement has to be
   visible from the start or the hero would sit permanently blank. */
.no-js .hero__reveal { clip-path: none; }
.no-js .hero__glyph { opacity: 1; transform: none; }

.hero__foot {
  width: 100%;
  max-width: 120rem;
  margin-inline: auto;
  padding: 0 var(--margin) clamp(1.5rem, 4vh, 2.5rem);
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--gutter);
  opacity: 0;
  /* Last in. The statement should have landed before the furniture appears. */
  transition: opacity var(--dur-slow) var(--ease) 4700ms;
}

.hero.is-ready .hero__foot { opacity: 1; }


.hero__scroll {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--fg-muted);
}

@media (prefers-reduced-motion: no-preference) {
  .hero__scroll .link__arrow { animation: drift 3.2s var(--ease) infinite; }
}

@keyframes drift {
  0%, 100% { transform: translateY(0); opacity: 1; }
  50%      { transform: translateY(0.3rem); opacity: 0.45; }
}

/* ═══════════════════════════════════════════════════════════════
   THE IDEA
   Asymmetric editorial composition. Large type, small metadata,
   one serif statement, short body copy.
   ═══════════════════════════════════════════════════════════════ */

/* O and S are the word's own two anchors - the rest recedes. */
.word-split {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.75rem, 13vw, 12rem);
  line-height: 0.9;
  letter-spacing: var(--track-wordmark);
  text-transform: uppercase;
  /* The letters that are not the mark. Held at the body grey rather than at
     the label grey: this is display type, and at 45% a 12rem letterform
     reads as muddy rather than as quiet. */
  color: var(--fg-soft);
}

.word-split__anchor { color: var(--fg); }

/* The phonetic respelling. Set in the serif italic it was a second signature
   on a page that already spends its one on "overstand" - and two signatures
   are worth less than one. Inter, quiet, sized like a lede. */
.idea__pronunciation {
  font-size: var(--t-body);
  line-height: 1.2;
  color: var(--fg-soft);
}

.idea__statement {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display);
  line-height: 0.98;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
}

.idea__statement .serif { text-transform: lowercase; font-size: 1.06em; }

/* ═══════════════════════════════════════════════════════════════
   FIELDS
   The ground OVERSTAND covers, listed on the homepage as an index
   rather than described. Hairlines and type, no cards - the areas
   themselves are opened up on the How We Work page, and this must
   not turn into a second version of that.
   ═══════════════════════════════════════════════════════════════ */

.fields {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border-top: 1px solid var(--rule);
  /* Closes the block across its full width. The last row rarely fills every
     column, and a rule that stops short of the edge reads as unfinished
     rather than as a decision. */
  border-bottom: 1px solid var(--rule);
}

/* Six groups, so three columns make two full rows. The titles are phrases
   rather than single words now, which also needs the extra width. */
@media (min-width: 640px)  { .fields { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .fields { grid-template-columns: repeat(3, 1fr); } }

.fields__item {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-s);
  line-height: 1.05;
  text-wrap: balance;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  padding: 1.1rem var(--gutter) 1.1rem 0;
  border-bottom: 1px solid var(--rule);
}

/* The line the About section turns on. Set below the body copy at display
   scale so it lands as a statement rather than another sentence. */
.about__punchline {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-s);
  line-height: 1.1;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  text-wrap: balance;
}

/* What a field group opens to. Listed, not described - the page is about how
   the work is approached, and a paragraph per discipline would turn it into
   the service catalogue the brief warns against. */
.disciplines {
  display: grid;
  gap: 0.55rem;
}

.disciplines li {
  font-size: var(--t-body);
  line-height: 1.4;
  color: var(--fg-soft);
}

@media (min-width: 700px) {
  .disciplines { grid-template-columns: repeat(2, 1fr); gap: 0.55rem var(--gutter); }
}

/* ═══════════════════════════════════════════════════════════════
   CASES
   Large, varied, editorial. Never a grid of small agency cards.
   ═══════════════════════════════════════════════════════════════ */

.case-list { display: grid; gap: calc(var(--section) * 0.7); }

.case { position: relative; }

/* Varied scale - the index reads as a sequence, not a template. */
.case--full     { grid-column: 1 / -1; }
.case--portrait { grid-column: 1 / -1; }
.case--cinematic{ grid-column: 1 / -1; }
.case--bleed    { grid-column: 1 / -1; }

@media (min-width: 900px) {
  .case--portrait  .case__media { width: 56%; }
  .case--portrait.case--right .case__media { margin-left: auto; }
  .case--cinematic .case__media { width: 100%; }
}

.case__link { display: block; }

.case__media {
  position: relative;
  overflow: hidden;
  margin-bottom: 1.75rem;
}

.case__media .media {
  transition: transform var(--dur-slow) var(--ease-out);
  will-change: transform;
}

/* 2-3% only. Anything more stops feeling considered. */
@media (hover: hover) and (pointer: fine) {
  .case__link:hover .case__media .media,
  .case__link:focus-visible .case__media .media { transform: scale(1.025); }
}

.case__head {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem var(--gutter);
  padding-bottom: 1.1rem;
  border-bottom: 1px solid var(--rule);
}

/* The rule draws left to right on hover - the same device as the
   navigation underline, and the only cue a case needs. */
.case__head::after {
  content: '';
  position: absolute;
  left: 0; bottom: -1px;
  width: 100%; height: 1px;
  background: var(--white);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-slow) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .case__link:hover .case__head::after,
  .case__link:focus-visible .case__head::after { transform: scaleX(1); }
}

.case__link:focus-visible .case__head::after { transform: scaleX(1); }

.case__index { color: var(--fg-muted); }

.case__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-m);
  line-height: 1;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  transition: transform var(--dur) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .case__link:hover .case__title,
  .case__link:focus-visible .case__title { transform: translateX(0.5rem); }
}

.case__meta {
  margin-top: 1.1rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  color: var(--fg-muted);
}

.case__desc { margin-top: 1.1rem; max-width: 54ch; color: var(--fg-soft); }

/* ═══════════════════════════════════════════════════════════════
   NUMBERED EDITORIAL ROWS
   Used for the framework (see / question / build / deliver) and
   for the areas. Rules, numbers, type. No cards.
   ═══════════════════════════════════════════════════════════════ */

.rows { border-top: 1px solid var(--rule); }

.row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem var(--gutter);
  align-items: baseline;
  padding-block: clamp(1.75rem, 4vh, 3rem);
  border-bottom: 1px solid var(--rule);
}

/* Below the three-column layout the description drops to its own line and
   takes the full width. Without it the text lands in the number column, which
   is sized to two digits, so every step description was squeezed into a third
   of the screen on a phone. */
.row__text { grid-column: 1 / -1; }

@media (min-width: 900px) {
  .row { grid-template-columns: 4rem 1fr 1.1fr; gap: var(--gutter); }
  /* Same component without the number column, for a list that is not a
     sequence. The title keeps the margin either way, so a numbered and an
     unnumbered list still read as siblings. */
  .rows--plain .row { grid-template-columns: 1fr 1.1fr; }
  .row__text { grid-column: auto; }
}

.row__number {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--t-meta);
  letter-spacing: var(--track-meta);
  color: var(--fg-muted);
  padding-top: 0.5em;
}

.row__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-m);
  line-height: 1;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
}

.row__text { color: var(--fg-soft); max-width: 48ch; }

/* Areas open in place - a typographic transition, not a widget. */
.row--expandable { padding: 0; border-bottom: 1px solid var(--rule); }

.row__trigger {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 1rem var(--gutter);
  align-items: baseline;
  width: 100%;
  text-align: left;
  padding-block: clamp(1.5rem, 3.5vh, 2.5rem);
}

@media (min-width: 900px) {
  .row__trigger { grid-template-columns: 4rem 1fr 1.1fr auto; }
}

.row__trigger .row__text { display: none; }

@media (min-width: 900px) {
  .row__trigger .row__text { display: block; }
}

.row__sign {
  position: relative;
  width: 0.75rem; height: 0.75rem;
  align-self: center;
  color: var(--fg-muted);
  transition: color var(--dur-fast) var(--ease);
}

.row__sign::before,
.row__sign::after {
  content: '';
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1px;
  background: currentColor;
}

.row__sign::after {
  inset: 0 auto 0 50%;
  width: 1px; height: 100%;
  transition: transform var(--dur) var(--ease-out);
}

.row__trigger[aria-expanded='true'] .row__sign::after { transform: scaleY(0); }
.row__trigger:hover .row__sign { color: var(--fg); }

@media (hover: hover) and (pointer: fine) {
  .row__trigger:hover .row__title { transform: translateX(0.4rem); }
  .row__title { transition: transform var(--dur) var(--ease-out); }
}

.row__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur) var(--ease-out);
}

.row__trigger[aria-expanded='true'] + .row__panel { grid-template-rows: 1fr; }

.row__panel > div { overflow: hidden; }

.row__panel-inner {
  padding-bottom: clamp(1.5rem, 3.5vh, 2.5rem);
  color: var(--fg-soft);
  max-width: 62ch;
}

@media (min-width: 900px) {
  .row__panel-inner { margin-left: calc(4rem + var(--gutter)); }
}

/* ═══════════════════════════════════════════════════════════════
   MANIFESTO
   Statements arrive one at a time as the reader moves.
   ═══════════════════════════════════════════════════════════════ */

.manifesto { display: grid; gap: clamp(2.5rem, 9vh, 6rem); }

.manifesto__line {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-xl);
  line-height: 0.98;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  max-width: min(18ch, var(--measure-11));
  text-wrap: balance;
}

.manifesto__line--serif {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  text-transform: none;
  letter-spacing: -0.01em;
  color: var(--fg-soft);
  font-size: var(--t-display);
  justify-self: end;
  text-align: right;
  max-width: 14ch;
}

/* The climax. Wider measure than the lines above it, but not the whole page:
   it stops at eleven columns like every other headline, so the column of air
   on the right holds all the way down the manifesto. */
.manifesto__line--climax {
  font-size: var(--t-display-xl);
  max-width: var(--measure-11);
}

.manifesto__line--climax .serif {
  text-transform: lowercase;
  font-size: 1.06em;
  letter-spacing: -0.01em;
}

/* ═══════════════════════════════════════════════════════════════
   CONTACT
   ═══════════════════════════════════════════════════════════════ */

.contact__statement {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-xl);
  line-height: 0.94;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  max-width: var(--measure-11);
}

.contact__statement .serif { text-transform: lowercase; font-size: 1.06em; }

/* The invitation, at section-headline size, directly under the statement.

   It is the one sentence on the page that asks for something, and it was the
   smallest thing on the screen while the email address was set at display
   size. The page shouted an address and whispered the invitation. */
.contact__ask {
  margin-top: var(--stack);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display);
  line-height: 0.98;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  max-width: var(--measure-11);
}

/* Columns 1 and 7 of the page grid, so the two blocks answer to the same
   bed as everything else. align-items:start puts the two meta labels on one
   line instead of letting each column find its own top. */
.contact__details {
  margin-top: var(--section);
  align-items: start;
}

.contact__block { display: grid; gap: 0.9rem; align-content: start; }

/* Links inside a grid column would otherwise stretch to the full column and
   drag their underline with them. */
.contact__block > * { justify-self: start; }

/* ═══════════════════════════════════════════════════════════════
   PAGE HEAD - shared opening for interior pages
   ═══════════════════════════════════════════════════════════════ */

.page-head {
  padding-top: calc(var(--nav-h) + var(--section) * 0.7);
  padding-bottom: calc(var(--section) * 0.55);
}

.page-head__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display-xl);
  line-height: 0.94;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
}

.page-head__title .serif { text-transform: lowercase; font-size: 1.06em; }

/* The second-language heading on the legal pages. Same display face, held
   back by weight and colour, so it reads as the translation it is. */
.page-head__alt { font-weight: 400; }

/* ═══════════════════════════════════════════════════════════════
   PEOPLE
   ═══════════════════════════════════════════════════════════════ */

.people { display: grid; gap: var(--stack) var(--gutter); grid-template-columns: 1fr; }

@media (min-width: 760px) { .people { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px) { .people { grid-template-columns: repeat(3, 1fr); } }

/* One person is not a grid of one.

   A lone portrait in a three-column bed occupies a third of the page with two
   thirds empty beside it, and reads as a colleague who failed to load rather
   than as a composition. Set as a portrait and its copy instead: the picture
   on the left, the text beside it, the pair filling the measure.

   Aligned to the page's twelve columns rather than to arbitrary fractions, so
   the block sits on the same bed as every other section. */
@media (min-width: 900px) {
  .people--single {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    align-items: center;
  }

  .people--single .person {
    grid-column: 1 / span 11;
    display: grid;
    grid-template-columns: 5fr 1fr 6fr;
    align-items: center;
    gap: 0;
  }

  /* The portrait holds the left five columns; the copy starts after a
     one-column gutter and runs to the eleventh. */
  .people--single .person > .media { grid-column: 1; grid-row: 1 / span 3; }
  .people--single .person > *:not(.media) { grid-column: 3; }

  .people--single .person__bio { max-width: 48ch; }
}

.person { display: grid; gap: 1.25rem; align-content: start; }
.person__name { font-family: var(--font-display); font-weight: 600; font-size: var(--t-display-s); letter-spacing: var(--track-display); text-transform: uppercase; line-height: 1; }
.person__bio { color: var(--fg-soft); }

/* ═══════════════════════════════════════════════════════════════
   CASE DETAIL
   ═══════════════════════════════════════════════════════════════ */

.case-meta {
  display: grid;
  gap: 1.5rem var(--gutter);
  grid-template-columns: repeat(2, 1fr);
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

@media (min-width: 760px) { .case-meta { grid-template-columns: repeat(3, 1fr); } }

.case-meta__item { display: grid; gap: 0.5rem; align-content: start; }
.case-meta__value { font-size: var(--t-body); color: var(--fg); text-transform: none; letter-spacing: 0; font-weight: 400; }

.case-body { display: grid; gap: calc(var(--section) * 0.5); }

.case-quote {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: var(--t-display-m);
  line-height: 1.2;
  color: var(--fg);
  max-width: 20ch;
}

.duo { display: grid; gap: var(--gutter); grid-template-columns: 1fr; }
@media (min-width: 700px) { .duo { grid-template-columns: repeat(2, 1fr); } }

.gallery { display: grid; gap: var(--gutter); grid-template-columns: 1fr; }
@media (min-width: 700px) { .gallery { grid-template-columns: repeat(3, 1fr); } }

/* Next case - a large visual preview, not a small link. */
.next-case { display: block; }
.next-case .media { transition: transform var(--dur-slow) var(--ease-out); }

@media (hover: hover) and (pointer: fine) {
  .next-case:hover .media,
  .next-case:focus-visible .media { transform: scale(1.025); }
  .next-case:hover .next-case__title { transform: translateX(0.5rem); }
}

.next-case__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-display);
  line-height: 1;
  letter-spacing: var(--track-display);
  text-transform: uppercase;
  transition: transform var(--dur) var(--ease-out);
}

/* ═══════════════════════════════════════════════════════════════
   LEGAL - readability first, same system
   ═══════════════════════════════════════════════════════════════ */

.legal { display: grid; gap: var(--stack); max-width: 46rem; }
.legal__section { display: grid; gap: 0.85rem; padding-top: 1.5rem; border-top: 1px solid var(--rule); }
.legal__heading { font-family: var(--font-display); font-weight: 600; font-size: var(--t-display-s); letter-spacing: var(--track-display); text-transform: uppercase; line-height: 1.1; }
.legal__body { color: var(--fg-soft); line-height: 1.7; }
