@charset "UTF-8";
/* ==========================================================================
   OYSTER — website design system
   Built to the locked visual brand (oyster-visual) in its DARK-MODE web
   expression: Ink is the ground, Vellum is the type, colour is a flourish.

   Section index
   00  Fonts
   01  Tokens
   02  Reset + base
   03  Type system
   04  Layout + grid
   05  Grounds + motifs
   06  Site furniture (header, footer, skip link)
   07  Components
   08  Interaction states
   09  Motion + choreography
   10  Responsive
   11  Print + forced colours
   ========================================================================== */

/* 00 · FONTS ============================================================== */

/* Brand tiers 1–3 (TAY / Taylor Penton) — licensed WOFF2 files drop in here.
   Until they land the stacks below fall back gracefully and the page still
   reads correctly; nothing depends on them for layout. */

@font-face {
  font-family: "Makawao";
  src: url("../fonts/tay-makawao-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  size-adjust: 100%;
}

@font-face {
  font-family: "Taxi Driver";
  src: url("../fonts/tay-taxi-driver-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Wingman";
  src: url("../fonts/tay-wingman-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-400-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Sans";
  src: url("../fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* 01 · TOKENS ============================================================= */

:root {
  /* --- Palette 3 (LOCKED — oyster-visual) ----------------------------- */
  --ink: #2a2b2a;
  --vellum: #fffffa;
  --shale: #5e5c6c;
  --tide: #6c8ead;
  --ember: #f3b391;

  /* --- On-dark derivations -------------------------------------------
     The locked palette is specified for a Vellum ground. This site runs on
     Ink, where Shale (2.18:1) and Tide (4.14:1) fall below AA for body and
     small text. These three tokens are the on-dark equivalents, tuned to
     clear AA at their intended size. They are derivations, not new brand
     colours — each is its parent lifted in luminance only.
     Measured against Ink #2A2B2A:                                        */
  --vellum-dim: #c9c8c3;   /* 8.48:1 — secondary body, standfirsts        */
  --vellum-quiet: #a9a7b3; /* 6.00:1 — captions, meta, Shale's on-dark job */
  --tide-lift: #8fabc2;    /* 5.94:1 — small technical labels, mono data    */

  /* Ground steps — Ink shifted, never a new hue */
  --ink-raise: #333433;
  --ink-sink: #232423;
  --hairline: rgb(255 255 250 / 0.14);
  --hairline-strong: rgb(255 255 250 / 0.28);

  /* --- Semantic ------------------------------------------------------- */
  --surface: var(--ink);
  --surface-raise: var(--ink-raise);
  --text: var(--vellum);
  --text-secondary: var(--vellum-dim);
  --text-quiet: var(--vellum-quiet);
  --accent-warm: var(--ember);
  --accent-cool: var(--tide-lift);

  /* --- Type ----------------------------------------------------------- */
  --font-display: "Makawao", "Iowan Old Style", "Palatino Linotype", Palatino,
    "Book Antiqua", Georgia, serif;
  --font-script: "Taxi Driver", "Snell Roundhand", "Segoe Script",
    "Brush Script MT", cursive;
  --font-label: "Wingman", "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
  --font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system,
    "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Fluid scale — 375 → 1440 */
  --t-wordmark: clamp(2.375rem, 1.55rem + 3.5vw, 3.375rem); /* 38 → 54 */
  --t-display: clamp(2rem, 1.2rem + 3.4vw, 3rem);           /* 32 → 48 */
  --t-beat: clamp(1.5rem, 0.98rem + 2.23vw, 2.25rem);       /* 24 → 36 */
  --t-h1: clamp(1.5rem, 1.11rem + 1.67vw, 2.0625rem);       /* 24 → 33 */
  --t-h2: clamp(1.1875rem, 1rem + 0.8vw, 1.4375rem);        /* 19 → 23 */
  --t-h3: clamp(1.125rem, 0.98rem + 0.64vw, 1.3125rem);     /* 18 → 21 */
  --t-lead: clamp(1rem, 0.95rem + 0.27vw, 1.125rem);        /* 16 → 18 */
  --t-body: clamp(0.9375rem, 0.9rem + 0.21vw, 1rem);        /* 15 → 16 */
  --t-small: 0.875rem;                                       /* 14 */
  --t-caption: 0.8125rem;                                    /* 13 */
  --t-label: 0.625rem;                                       /* 10 */
  --t-script: clamp(1.375rem, 1.05rem + 1.34vw, 1.75rem);   /* 22 → 28 */
  --t-script-lg: clamp(1.75rem, 1.2rem + 2.34vw, 2.5rem);   /* 28 → 40 */
  --t-numeral: clamp(2.75rem, 1.6rem + 4.9vw, 4.25rem);     /* 44 → 68 */

  --lh-tight: 1.02;
  --lh-display: 1.06;
  --lh-snug: 1.16;
  --lh-body: 1.45;
  --ls-label: 0.08em;
  --ls-mono: 0.08em;
  --ls-display: -0.01em;

  /* --- Space — 8pt base ------------------------------------------------ */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 5rem;
  --s-9: 8rem;
  --s-10: 11rem;
  --marker-h: 1.05rem;
  --section-y: clamp(5.5rem, 2.75rem + 11vw, 11.5rem);

  /* --- Layout ---------------------------------------------------------- */
  --gutter: clamp(1.5rem, 0.35rem + 4.9vw, 9.5rem); /* 24 → 152 */
  --measure-content: 71rem;  /* 1136 — the hairline-rule width */
  --measure-hero: 62.5rem;   /* 1000 — hero + full-bleed display */
  --measure-prose: 34rem;    /* 544 — long-form reading measure */
  --measure-lead: 48.75rem;  /* 780 — section headline measure */

  /* --- Motion ---------------------------------------------------------- */
  --ease-draw: cubic-bezier(0.22, 0.61, 0.28, 1);
  --ease-rise: cubic-bezier(0.16, 0.84, 0.24, 1);
  --ease-settle: cubic-bezier(0.33, 0, 0.12, 1);
  --dur-quick: 180ms;
  --dur-base: 420ms;
  --dur-slow: 900ms;
  --dur-draw: 1600ms;

  --focus-ring: var(--ember);

  color-scheme: dark;
}

/* 02 · RESET + BASE ======================================================= */

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The header is a scroll-reveal overlay, so anchors need breathing room. */
  scroll-padding-top: 6rem;
}

body {
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  font-synthesis-weight: none;
}

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

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

p,
li {
  text-wrap: pretty;
}

h1,
h2,
h3,
h4 {
  text-wrap: balance;
  font-weight: 400;
}

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

/* 03 · TYPE SYSTEM ======================================================== */

/* Tier 1 — Makawao. Display only: wordmark, hero, the full-bleed moments. */
.t-wordmark {
  font-family: var(--font-display);
  font-size: var(--t-wordmark);
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.t-display {
  font-family: var(--font-display);
  font-size: var(--t-display);
  line-height: var(--lh-display);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* Tier 2 — Taxi Driver. Signature register: tagline, footer mark, end-note. */
.t-script {
  font-family: var(--font-script);
  font-size: var(--t-script);
  line-height: 1.3;
  font-weight: 400;
}

.t-script--lg {
  font-size: var(--t-script-lg);
}

/* Tier 3 — Wingman. Labels and metadata ONLY (never a subhead). */
.t-label {
  font-family: var(--font-label);
  font-size: var(--t-label);
  line-height: 1;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  font-weight: 400;
}

/* Tier 4 — Plex Sans. The working tier. */
.t-beat {
  font-size: var(--t-beat);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  font-weight: 400;
}

.t-h1 {
  font-size: var(--t-h1);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-display);
}

.t-h2 {
  font-size: var(--t-h2);
  line-height: var(--lh-snug);
}

.t-h3 {
  font-size: var(--t-h3);
  line-height: 1.4;
}

.t-lead {
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--text-secondary);
}

.t-body {
  font-size: var(--t-body);
  line-height: var(--lh-body);
  color: var(--text-secondary);
}

.t-caption {
  font-size: var(--t-caption);
  line-height: 1.5;
  color: var(--text-quiet);
}

/* Tier 5 — Plex Mono. Technical text only: hex codes, ratios, dimensions, file paths, data annotations. Eyebrows, section markers, metadata and footer marks are Tier 3 (.t-label). */
/* Tide had drifted out of the site almost entirely — it survived as a token
   and in three component borders. Its documented job is exactly this: small
   technical labels and mono data, at the 5.94:1 on-dark lift. Putting the
   whole mono tier in Tide restores the palette's cool half without adding a
   decorative use anywhere. */
.t-mono {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: var(--ls-mono);
  text-transform: uppercase;
  color: var(--tide-lift);
}

/* Accent word inside a headline — Ember on Ink measures 7.9:1. */
.accent {
  color: var(--ember);
}

.accent-cool {
  color: var(--accent-cool);
}

.u-quiet {
  color: var(--text-quiet);
}

.u-secondary {
  color: var(--text-secondary);
}

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

/* 04 · LAYOUT + GRID ====================================================== */

.shell {
  width: 100%;
  max-width: calc(var(--measure-content) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.shell--hero {
  max-width: calc(var(--measure-hero) + var(--gutter) * 2);
}

.section {
  padding-block: var(--section-y);
  position: relative;
}

.section--tight {
  padding-block: clamp(3rem, 1.5rem + 6vw, 5.5rem);
}

/* The hairline rule + § marker that opens every section. This is the site's
   structural signature — a survey sheet's rule, not a divider. */
/* --rule-pad is read by the marker below so the two stay locked together
   across breakpoints — the marker's whole job is to sit level with the
   eyebrow, and hard-coding its offset broke that at the 1440 breakpoint
   where this padding changes. */
.section-rule {
  --rule-pad: var(--s-7);
  position: relative;
  border-top: 1px solid var(--hairline);
  padding-top: var(--rule-pad);
}

/* --- Section numerals ---------------------------------------------------
   Drawn 0–6 from the brand diagram set, inlined as data URIs and painted as
   masks so they take a token colour and cost no extra requests. Each glyph
   has its own width against a common 16-unit height, so the aspect ratio is
   per-numeral and the row stays optically even. */
/* Top-anchored to the eyebrow rather than floating above it: the marker and
   the eyebrow are the two things that open a section and they should start on
   the same line. --s-8 is the section-rule's own padding-top, so this tracks
   it automatically if that spacing changes. */
.section-rule__marker {
  position: absolute;
  /* the eyebrow's own top padding, so the glyphs start on the eyebrow's
     text top rather than on its box top */
  top: calc(var(--rule-pad) + 0.4rem);
  right: 0;
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

/* The case spine sets its markers in the flow of a two-column head rather
   than pinned to the section rule, so the base marker's absolute positioning
   has to come back off. Everything else — the mono section sign, the drawn
   numeral, the accessible name — is shared. */
.section-rule__marker--flow {
  position: static;
  /* The grid cell is as tall as the heading plus its standfirst; without this
     the flex centring drops the marker to the middle of both. Top-align, then
     nudge so the numeral's cap sits on the h2's. */
  align-self: start;
  align-items: baseline;
  padding-top: 0.5rem;
}

/* The drawn numerals and the mono section sign have to read as one mark.
   They did not: the numerals stood 1.35rem against a 13px § at regular
   weight, so the pair looked like a glyph beside a footnote. The numeral
   comes down ~30%, the sign goes up in size and weight to meet it. */
.marker__sec {
  font-family: var(--font-mono);
  /* --marker-h is the drawn height both glyphs hit. IBM Plex Mono's section
     sign occupies about 0.62em of its box, so the font-size that yields
     --marker-h of ink is --marker-h / 0.62. Weight 600 brings the stroke up
     to the drawn numeral's. */
  font-size: calc(var(--marker-h) / 0.62);
  line-height: 1;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--text-secondary);
  /* mono § sits low in its box; this lifts its ink onto the numeral's top */
  margin-top: -0.28em;
}

.numeral {
  display: block;
  height: var(--marker-h);
  background-color: var(--text-secondary);
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  -webkit-mask-size: contain;
          mask-size: contain;
}

.numeral--0 {
  aspect-ratio: 11 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M7.2 7.2Q7.2-1 5 2.6c-1 1.5-1 7.5.2 9.5s2.1-.4 2.1-4.9m-5.6 6.6C-3.2 7.2 3.7-4.3 9 1.7c2 2.3 2.2 8.4.3 11.9-1.7 3.1-5.4 3.2-7.7.2%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M7.2 7.2Q7.2-1 5 2.6c-1 1.5-1 7.5.2 9.5s2.1-.4 2.1-4.9m-5.6 6.6C-3.2 7.2 3.7-4.3 9 1.7c2 2.3 2.2 8.4.3 11.9-1.7 3.1-5.4 3.2-7.7.2%22/%3E%3C/svg%3E");
}
.numeral--1 {
  aspect-ratio: 8 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%228%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 8 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M0 15q-.2-.7.8-1.2c1.3-.5 1.7-7.6.5-8-1.5-.6 1-6 2.6-5.8 1.4.2 1.5.7 1.3 6.5-.2 5 0 6.4 1 6.7q1 .6 1 1.5c0 1.3-6.4 1.5-7.1.3%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%228%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 8 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M0 15q-.2-.7.8-1.2c1.3-.5 1.7-7.6.5-8-1.5-.6 1-6 2.6-5.8 1.4.2 1.5.7 1.3 6.5-.2 5 0 6.4 1 6.7q1 .6 1 1.5c0 1.3-6.4 1.5-7.1.3%22/%3E%3C/svg%3E");
}
.numeral--2 {
  aspect-ratio: 11 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M1.3 11.6C1.3 11.2 4 8 4.8 7c1-1.6 1.1-2.3.4-3.9-1-2.3-2.5-1.6-2 1 .5 1.5.3 1.8-1 1.8-3.5 0-2.6-4.7 1-5.6 4.3-1.1 7.7 3.5 5.1 7-1.5 2-7 5.7-7 4.4m-.7 3.1c0-2.1 1.1-2.9 4.4-2.9 2 0 4-.4 4.5-.9q1-1.1.9 1c0 1.1-.4 2.4-1 2.8-1 1-8.8.9-8.8 0%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M1.3 11.6C1.3 11.2 4 8 4.8 7c1-1.6 1.1-2.3.4-3.9-1-2.3-2.5-1.6-2 1 .5 1.5.3 1.8-1 1.8-3.5 0-2.6-4.7 1-5.6 4.3-1.1 7.7 3.5 5.1 7-1.5 2-7 5.7-7 4.4m-.7 3.1c0-2.1 1.1-2.9 4.4-2.9 2 0 4-.4 4.5-.9q1-1.1.9 1c0 1.1-.4 2.4-1 2.8-1 1-8.8.9-8.8 0%22/%3E%3C/svg%3E");
}
.numeral--3 {
  aspect-ratio: 9 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%229%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 9 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M1 14.4c-1.6-1.9-1.2-4.1.8-4.4 1.3-.2 1.6 0 1.6 2 0 2.4 1 3 1.7 1.1.9-2.5.4-4.8-1-4.8q-1.3 0-1.4-.8.1-.7 1.4-1.2Q5.5 6 5.5 3.8c0-2.6-2-3-2.2-.5C3 5.3 1 5.6.7 3.6.2.6 5.3-1.3 7.4 1c1.1 1.1 1.1 5 .1 5-.4 0-.1 1.2.6 2.5 3 5.1-3.4 10.2-7.1 5.8%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%229%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 9 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M1 14.4c-1.6-1.9-1.2-4.1.8-4.4 1.3-.2 1.6 0 1.6 2 0 2.4 1 3 1.7 1.1.9-2.5.4-4.8-1-4.8q-1.3 0-1.4-.8.1-.7 1.4-1.2Q5.5 6 5.5 3.8c0-2.6-2-3-2.2-.5C3 5.3 1 5.6.7 3.6.2.6 5.3-1.3 7.4 1c1.1 1.1 1.1 5 .1 5-.4 0-.1 1.2.6 2.5 3 5.1-3.4 10.2-7.1 5.8%22/%3E%3C/svg%3E");
}
.numeral--4 {
  aspect-ratio: 9 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%229%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 9 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M4.2 9c0-.7.4-6.8 0-6.6s-2 6.2-2 6.5q-.1.7.4.8c.4 0 1.6-.2 1.6-.8m-2 6.2q-.2-.7.3-1.1c1.4-.9.7-2.4-1-2.4C0 11.7-.2 11.5.2 10l1.6-5.7Q2.8.3 4 0q2.4-.3 2.4 3.2v3.9c-.3 2-.1 2.5.8 2.5 1.6 0 2.1 1 1 2q-1.1 1-.7 2.5c.5 1.8-4.4 2.7-5.4 1%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%229%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 9 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M4.2 9c0-.7.4-6.8 0-6.6s-2 6.2-2 6.5q-.1.7.4.8c.4 0 1.6-.2 1.6-.8m-2 6.2q-.2-.7.3-1.1c1.4-.9.7-2.4-1-2.4C0 11.7-.2 11.5.2 10l1.6-5.7Q2.8.3 4 0q2.4-.3 2.4 3.2v3.9c-.3 2-.1 2.5.8 2.5 1.6 0 2.1 1 1 2q-1.1 1-.7 2.5c.5 1.8-4.4 2.7-5.4 1%22/%3E%3C/svg%3E");
}
.numeral--5 {
  aspect-ratio: 11 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M1.5 7.7C.7 6 1.5.5 2.5.2q1-.2 1.7 1.5c1 2.4 1.5 2.4 2.4.1 1.2-3 4.6-2 3.6 1q-.6 1.4-3.6 1.8c-2.6.4-3 .7-3 2 .4 1.8-1.4 2.7-2 1.1m-.3 6.8c-.9-.8-1.4-2-1.1-2.5.6-1.7 3.9-1.4 4.4.3q.4 1.4 1.3 1.5c1 0 1-4 0-5.9-3.9-.2-.6-1.4 1-1.4 3.4 0 5 4.4 2.9 8-1.1 2-6.4 2-8.5 0%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M1.5 7.7C.7 6 1.5.5 2.5.2q1-.2 1.7 1.5c1 2.4 1.5 2.4 2.4.1 1.2-3 4.6-2 3.6 1q-.6 1.4-3.6 1.8c-2.6.4-3 .7-3 2 .4 1.8-1.4 2.7-2 1.1m-.3 6.8c-.9-.8-1.4-2-1.1-2.5.6-1.7 3.9-1.4 4.4.3q.4 1.4 1.3 1.5c1 0 1-4 0-5.9-3.9-.2-.6-1.4 1-1.4 3.4 0 5 4.4 2.9 8-1.1 2-6.4 2-8.5 0%22/%3E%3C/svg%3E");
}
.numeral--6 {
  aspect-ratio: 11 / 16;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M6.4 12c1-2.5-.4-5.3-1.8-3.8-1 1-.7 5.8.5 5.8q.6-.2 1.3-2M3 15.6C-.5 14-1 6.5 2 2c2.7-3.7 9.2-2.1 7.7 2-.7 1.6-3.3 1.4-3.8-.4-.5-2-1.7-1.8-1.7.3 0 1.5.5 1.9 3 2.3 2.3.4 2.9.8 3.3 2.5 1 5-2.8 8.6-7.5 6.7%22/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2211%22 height=%2216%22 fill=%22none%22 viewBox=%220 0 11 16%22%3E%3Cpath fill=%22%235e5c6c%22 d=%22M6.4 12c1-2.5-.4-5.3-1.8-3.8-1 1-.7 5.8.5 5.8q.6-.2 1.3-2M3 15.6C-.5 14-1 6.5 2 2c2.7-3.7 9.2-2.1 7.7 2-.7 1.6-3.3 1.4-3.8-.4-.5-2-1.7-1.8-1.7.3 0 1.5.5 1.9 3 2.3 2.3.4 2.9.8 3.3 2.5 1 5-2.8 8.6-7.5 6.7%22/%3E%3C/svg%3E");
}

.stack > * + * {
  margin-top: var(--flow, var(--s-5));
}

.prose {
  max-width: var(--measure-prose);
}

.lead-measure {
  max-width: var(--measure-lead);
}

/* 05 · GROUNDS + MOTIFS =================================================== */

/* The four atmospheric grounds are built here as layered CSS gradients over
   an SVG grain, rather than shipped as the 6336px master PNGs. Same optical
   result, resolution-independent, ~2KB instead of several MB — and the grain
   stays crisp on a 3× display, which a raster ground cannot do.
   Variants map 1:1 to the locked set: Neutral · Warm · Cool · Expressive. */

.ground {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

.ground > * {
  position: relative;
  z-index: 2;
}

/* The ground itself is a supplied plate, not a gradient. Corey, 2026-08-24:
   the grain register is not reproducible in CSS, so the PNG is the artwork
   and the only permitted adjustment is a brand-colour overlay on top, to
   deepen or lighten it for whatever sits on it. That is exactly the two
   layers below — plate on ::before, tone on ::after.

   AVIF leads because fine even grain is the one thing lossy codecs destroy
   first: WebP goes blotchy until roughly q82, at twice the bytes AVIF needs
   at q55. WebP is the fallback leg, and a bare url() catches anything that
   understands neither image-set() nor either format. */
.ground::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--ground-plate-fallback);
  background-image: var(--ground-plate);
  background-size: cover;
  background-position: var(--ground-pos, center);
}

/* Grain. Per 00-Brand-Tokens-Reference: a baked grain PNG tiled at 512px,
   composited at 25% Overlay (30–35% above 1800px, never past 40%). The
   turbulence data-URI below is the documented FALLBACK, not the system —
   the real registers are Oyster_Grain_{Neutral,Warm,Cool}_2048.png and they
   are not reproducible in CSS. Drop those four files into assets/img/grain/
   and each ground's --grain-src takes over with no other change.

   The gradient underneath now runs the spec's three stops rather than the
   four flat ones it had. The missing piece was the #1A1A1C floor: without a
   vignette bottoming out below Ink, an atmospheric ground and a flat Ink
   section measure almost the same and the atmosphere never registers. */
/* The tone layer. Ink at a per-register opacity, because the supplied plates
   run from near-black (Warm) to near-white (Neutral 04) and the type over
   them has a fixed contrast floor. Every value here was set by the
   rendered-pixel audit, not by eye. */
.ground::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: var(--ink);
  opacity: var(--ground-tone, 0.5);
}

/* The four registers. Each is the spec's radial vignette — a lifted centre,
   Ink at the two-thirds mark, and a floor below Ink — with the centre stop
   carrying the register's hue. Neutral is the spec verbatim. */
.ground--neutral {
  --ground-plate: image-set(url("../img/ground/neutral.avif") type("image/avif"),
                            url("../img/ground/neutral.webp") type("image/webp"));
  --ground-plate-fallback: url("../img/ground/neutral.webp");
  --ground-tone: 0.52;
}

.ground--cool {
  --ground-plate: image-set(url("../img/ground/cool.avif") type("image/avif"),
                            url("../img/ground/cool.webp") type("image/webp"));
  --ground-plate-fallback: url("../img/ground/cool.webp");
  --ground-tone: 0.5;
}

.ground--warm {
  --ground-plate: image-set(url("../img/ground/warm.avif") type("image/avif"),
                            url("../img/ground/warm.webp") type("image/webp"));
  --ground-plate-fallback: url("../img/ground/warm.webp");
  --ground-tone: 0.42;
}

.ground--expressive {
  --ground-plate: image-set(url("../img/ground/expressive.avif") type("image/avif"),
                            url("../img/ground/expressive.webp") type("image/webp"));
  --ground-plate-fallback: url("../img/ground/expressive.webp");
  --ground-tone: 0.62;
}

.ground--flat {
  --ground-image: linear-gradient(var(--ink), var(--ink));
  --grain-opacity: 0.16;
}

/* THE DIAGRAM SUBSYSTEM ---------------------------------------------------
   Four tiers, ratified 2026-08-24. Written down here because it had only
   ever lived in a conversation, and a rule nobody can find is a rule that
   gets broken by the next person to touch this file.

   1 · MARK      identity, never decoration — caged-O, wordmark, orbit.
   2 · SECTION   the drawn numerals 0–6, as section markers. Structural.
   3 · PLATE     one large diagram per page, low opacity, behind an
                 atmospheric ground. Ambient. NEVER more than one per page.
   4 · INLINE    small diagrams at text scale, used as punctuation.

   Everything here is tier 3. The site previously ran four authored contour
   plates in six placements, drawn before the real vectors existed. They were
   86% of Home's transfer weight — inline SVG re-downloaded on every page —
   and they no longer matched the brand. Removed 2026-08-24.

   Plates are CSS masks over a token colour, the same mechanism as the orbit:
   one cached external file per diagram, a single <span> in the markup, and
   a colour that can answer to the ground it sits on. */
.motif {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  opacity: var(--motif-opacity, 0.14);
}

.plate {
  display: block;
  width: 100%;
}

@supports (mask-image: url("#o")) or (-webkit-mask-image: url("#o")) {
  .plate {
    background-color: var(--plate-ink, var(--vellum-quiet));
  }
  .plate--solar {
    -webkit-mask: url("../img/diagram-solar-system.svg") center / contain no-repeat;
            mask: url("../img/diagram-solar-system.svg") center / contain no-repeat;
  }
  .plate--terrain {
    -webkit-mask: url("../img/diagram-terrain.svg") center / contain no-repeat;
            mask: url("../img/diagram-terrain.svg") center / contain no-repeat;
  }
  .plate--sun {
    -webkit-mask: url("../img/diagram-sun.svg") center / contain no-repeat;
            mask: url("../img/diagram-sun.svg") center / contain no-repeat;
  }
  .plate--star {
    -webkit-mask: url("../img/diagram-star.svg") center / contain no-repeat;
            mask: url("../img/diagram-star.svg") center / contain no-repeat;
  }
}

.plate--solar   { aspect-ratio: 645 / 217; }
.plate--terrain { aspect-ratio: 600 / 143; }

/* Practice — the method page. Solar System is the one diagram in the set
   that draws things held in relation, which is the argument the page makes. */
.motif--plate-solar {
  top: 50%;
  right: calc(var(--gutter) * -0.15);
  width: min(46vw, 620px);
  transform: translateY(-42%);
  --motif-opacity: 0.12;
}

/* About — terrain. The topography vein the old contours were gesturing at,
   drawn by someone who can draw. Wide band, so it runs under the section. */
.motif--plate-terrain {
  top: 50%;
  left: 50%;
  width: min(78vw, 1060px);
  transform: translate(-50%, -50%);
  --motif-opacity: 0.1;
}

/* 404 gets no plate. It already carries the caged-O with the zero inside —
   which IS the wayfinding mark — plus two lines and one link. A compass
   behind that was a third element competing with the first, and Compass is
   a filled mark rather than an engraved one, so at plate opacity it read as
   a smudge instead of a drawing. The tier-3 rule is one plate per page, not
   one plate per page minimum. */

/* Closing orbit — the contact prompt. The hero's constellation returned at
   the foot of the page, mirrored to the opposite side and dropped to a
   whisper, so Home shuts on the mark it opened with. Deliberately the orbit
   and not a third contour: the contour plates run 5–8KB gzipped each and
   Home already carries three, and a fourth would have been more of the same
   texture rather than a rhyme. */
/* Background usage. Corey's rule: a large diagram used as a section ground
   should almost merge with the atmospheric gradient behind it — the two
   together read as texture, not as an illustration sitting on a surface. So
   this one keeps the export's own Shale rather than the lifted on-dark token,
   which is the opposite of what the hero needs. Contrast rules differ by job,
   not by asset. */
.motif--orbit-close {
  --orbit-ink: var(--shale);
  top: 50%;
  right: calc(var(--gutter) * -0.12);
  width: min(30vw, 380px);
  transform: translateY(-42%) scaleX(-1);
  --motif-opacity: 0.1;
  color: var(--accent-warm);
}

@media (max-width: 63.99em) {
  .motif--orbit-close {
    --motif-opacity: 0.07;
    width: min(56vw, 300px);
  }
}

/* 06 · SITE FURNITURE ===================================================== */

.skip-link {
  position: absolute;
  left: var(--s-4);
  top: var(--s-4);
  z-index: 100;
  padding: var(--s-3) var(--s-5);
  background: var(--ember);
  color: var(--ink);
  font-family: var(--font-label);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--dur-quick) var(--ease-rise);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

.site-header {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  padding: var(--s-5) var(--gutter);
  background: rgb(42 43 42 / 0.82);
  backdrop-filter: blur(14px) saturate(120%);
  border-bottom: 1px solid transparent;
  transition:
    transform var(--dur-base) var(--ease-settle),
    opacity var(--dur-base) var(--ease-settle),
    border-color var(--dur-base) var(--ease-settle);
}

/* Home earns the wordmark space: the header is withheld until the hero has
   been passed (X-WEB-1 §2, Corey's recommended behaviour). */
.site-header[data-reveal="pending"] {
  transform: translateY(-100%);
  opacity: 0;
  pointer-events: none;
}

.site-header[data-reveal="shown"] {
  transform: translateY(0);
  opacity: 1;
  border-bottom-color: var(--hairline);
}

.site-header__mark {
  display: block;
  text-decoration: none;
  color: var(--text);
}

.site-nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 0.3rem + 2.2vw, 2.25rem);
}

.site-nav a {
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--t-small);
  position: relative;
  padding-block: 0.35rem;
}

.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-base) var(--ease-draw);
}

.site-nav a:hover,
.site-nav a:focus-visible {
  color: var(--text);
}

.site-nav a:hover::after,
.site-nav a:focus-visible::after,
.site-nav a[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

.site-nav a[aria-current="page"] {
  color: var(--text);
}

.nav-toggle {
  display: none;
  background: none;
  border: 1px solid var(--hairline-strong);
  color: var(--text);
  padding: var(--s-2) var(--s-4);
  font-family: var(--font-label);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  cursor: pointer;
}

/* --- Footer ------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--hairline);
  padding-block: var(--s-9) var(--s-6);
}

/* The anchor mantra, set in the script tier. Tide, where the hero's tagline
   is Ember — the site opens on the warm half of the palette and closes on
   the cool one, and the two script moments stop reading as the same note
   played twice. --tide-lift is the documented on-dark equivalent; the raw
   Tide measures 2.18:1 here and would sink into the ground. */
.site-footer__mark {
  margin-bottom: var(--s-9);
  color: var(--tide-lift);
}

.footer-cta {
  display: inline-flex;
  font-size: var(--t-lead);
}

.footer-col__voice {
  color: var(--text-quiet);
  max-width: 26ch;
  line-height: var(--lh-body);
  text-transform: none;
  letter-spacing: 0;
}

/* Two stacked layers — Vellum lattice, Ember O — composited back into one
   mark. The wrapper carries the box; the layers fill it. */
.caged-o {
  position: relative;
  display: block;
  width: 3.9rem;
  aspect-ratio: 144 / 133;
  margin-bottom: var(--s-4);
  opacity: 0.9;
}

.caged-o img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1.2fr;
  gap: var(--s-8);
  padding-bottom: var(--s-9);
}

.footer-col__label {
  color: var(--text-quiet);
  margin-bottom: var(--s-4);
  display: block;
}

.footer-links {
  list-style: none;
  padding: 0;
  display: grid;
  gap: var(--s-2);
}

.footer-links a,
.footer-mail {
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--t-small);
  transition: color var(--dur-quick) var(--ease-settle);
}

.footer-links a:hover,
.footer-mail:hover {
  color: var(--ember);
}

.footer-mail {
  font-size: var(--t-lead);
  color: var(--text);
  display: inline-block;
}

.sub-footer {
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
  display: flex;
  justify-content: space-between;
  gap: var(--s-5);
  flex-wrap: wrap;
}

.sub-footer a {
  color: var(--text-quiet);
  text-decoration: none;
}

/* X-WEB-15 · footer targets to 24px, and the Tier 3 footer mark baseline */
.sub-footer { align-items: baseline; }
.sub-footer a { padding-block: 0.4375rem; }
.footer-links { gap: 0; }                                  /* was var(--s-2) at :928 */
.footer-links a { display: inline-block; padding-block: 0.25rem; }

.sub-footer a:hover {
  color: var(--text-secondary);
}

/* 07 · COMPONENTS ========================================================= */

/* --- Eyebrow ------------------------------------------------------------
   Rule (D-22): an eyebrow names the section's JOB, never its content.

   Ember budget. The filled chip used to be the default, which meant Practice
   opened six solid Ember rectangles and About five. A filled chip is louder
   than coloured text, so by the time the reader reached an Ember accent word
   inside a headline — the one place the colour is supposed to mean something
   — Ember had already appeared five times as furniture and read as
   decoration. The chip is now a page-opening gesture (`--lead`, once per
   page) and every eyebrow after it sets in Ember on Ink, which measures
   7.90:1 and so loses nothing but volume. */
.eyebrow {
  display: inline-block;
  padding: 0.4rem 0 0.35rem;
  color: var(--ember);
  font-family: var(--font-label);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  line-height: 1;
  margin-bottom: var(--s-5);
}

/* The filled chip is retired. It was scoped as "first eyebrow on a page,
   never a second", which is a defensible hierarchy rule and read on the page
   as two different eyebrow styles on one screen. One treatment, everywhere:
   plain Ember. Kept as a class for the one-off surfaces that may still want
   it, but nothing on the site uses it. */
.eyebrow--lead {
  padding-inline: 0.7rem;
  background: var(--ember);
  color: var(--ink);
}

.eyebrow--ghost {
  background: transparent;
  color: var(--text-quiet);
  border: 1px solid var(--hairline-strong);
  padding-inline: 0.7rem;
}

/* --- Quiet sentence link — the dominant action on the site (X-WEB-1 §1) - */
.link-quiet {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  color: var(--text);
  text-decoration: none;
  font-size: var(--t-body);
  position: relative;
  padding-bottom: 0.3rem;
}

.link-quiet::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--hairline-strong);
  transition:
    background-color var(--dur-base) var(--ease-settle),
    transform var(--dur-base) var(--ease-draw);
  transform-origin: left;
}

.link-quiet:hover::after,
.link-quiet:focus-visible::after {
  background: var(--ember);
}

.link-quiet__arrow {
  transition: transform var(--dur-base) var(--ease-rise);
}

.link-quiet:hover .link-quiet__arrow {
  transform: translateX(0.28em);
}

.link-quiet--mono {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: var(--ls-mono);
  text-transform: uppercase;
}

/* --- The one hard CTA (max one per page) -------------------------------- */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.75em;
  padding: 1.05rem 1.75rem;
  border: 1px solid var(--hairline-strong);
  color: var(--text);
  text-decoration: none;
  font-size: var(--t-body);
  background: transparent;
  cursor: pointer;
  transition:
    background-color var(--dur-base) var(--ease-settle),
    border-color var(--dur-base) var(--ease-settle),
    color var(--dur-base) var(--ease-settle);
}

.cta:hover,
.cta:focus-visible {
  background: var(--ember);
  border-color: var(--ember);
  color: var(--ink);
}

.cta__arrow {
  transition: transform var(--dur-base) var(--ease-rise);
}

.cta:hover .cta__arrow {
  transform: translateX(0.3em);
}

/* --- RFP path — inline, never a nav item or gated asset ----------------- */
.rfp-line {
  display: inline-block;
  margin-top: var(--s-6);
  font-size: var(--t-caption);
  color: var(--text-quiet);
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 0.35rem;
}

.rfp-line:hover {
  color: var(--text-secondary);
  border-bottom-color: var(--hairline-strong);
}

/* --- The four blocks ----------------------------------------------------
   D-8: the names carry the offer, so they read as four nouns at a glance. */
.blocks {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--s-6);
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
}

.block {
  position: relative;
  padding-top: var(--s-4);
}

/* The tick — a survey mark at each column head. A plain stem crossing the
   rule: a plumb line dropped from the measure. It briefly had a chevron at
   its foot; the arrowhead made it a direction rather than a measurement,
   which is the wrong idea for a survey mark. */
.block::before {
  content: "";
  position: absolute;
  top: calc(var(--s-5) * -1 - 8px);
  left: 0;
  width: 1px;
  height: 17px;
  background: var(--hairline-strong);
}

.block__num {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  color: var(--text-quiet);
  letter-spacing: var(--ls-mono);
  display: block;
  margin-bottom: var(--s-2);
}

.block__name {
  font-size: var(--t-h2);
  line-height: 1.2;
  margin-bottom: var(--s-3);
  display: block;
}

.block__desc {
  font-size: var(--t-caption);
  line-height: 1.55;
  color: var(--text-secondary);
}

.block__so {
  display: block;
  margin-top: var(--s-3);
  font-size: var(--t-caption);
  line-height: 1.55;
  color: var(--accent-cool);
}

.block__deliverables {
  list-style: none;
  padding: 0;
  margin-top: var(--s-4);
  display: grid;
  gap: 0.3rem;
  font-size: var(--t-caption);
  color: var(--text-quiet);
}

/* --- Work cards --------------------------------------------------------- */
.work-cover {
  aspect-ratio: 5 / 3;
  border: 1px solid var(--hairline);
  position: relative;
  overflow: hidden;
  transition: border-color var(--dur-base) var(--ease-settle);
}

.work-cover::before {
  transition: transform var(--dur-slow) var(--ease-settle);
}

/* A survey crosshair at the centre of every cover. */
.work-cover__cross {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-items: center;
  opacity: 0.5;
}

.work-card {
  display: block;
  text-decoration: none;
  color: inherit;
}

.work-card:hover .work-cover {
  border-color: var(--hairline-strong);
}

.work-card:hover .work-cover::before {
  transform: scale(1.035);
}

.work-card__sector {
  margin-top: var(--s-4);
  display: block;
}

.work-card__headline {
  margin-top: var(--s-2);
  font-size: var(--t-h3);
  line-height: 1.3;
  transition: color var(--dur-base) var(--ease-settle);
}

.work-card:hover .work-card__headline {
  color: var(--ember);
}

/* --- Index rows (Field Notes) ------------------------------------------- */
.index-row {
  display: grid;
  grid-template-columns: 6rem 1fr 5rem;
  gap: var(--s-5);
  align-items: baseline;
  padding-block: var(--s-5);
  border-top: 1px solid var(--hairline);
  text-decoration: none;
  color: inherit;
  transition: background-color var(--dur-base) var(--ease-settle);
}

.index-row:hover {
  background: rgb(255 255 250 / 0.03);
}

.index-row__title {
  font-size: var(--t-h3);
  transition: color var(--dur-base) var(--ease-settle);
}

.index-row:hover .index-row__title {
  color: var(--ember);
}

/* --- Reflections (Practice) --------------------------------------------- */
.reflections {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-6);
}

.reflection {
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
  font-size: var(--t-caption);
  line-height: 1.7;
  color: var(--text-secondary);
}

/* --- Engagement schematic ----------------------------------------------- */
.ways-in {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-6);
  position: relative;
}

.way {
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
  position: relative;
}

.way::before {
  content: "";
  position: absolute;
  top: -3px;
  left: 0;
  width: 5px;
  height: 5px;
  background: var(--accent-cool);
  border-radius: 50%;
}

.way__name {
  font-size: var(--t-h3);
  display: block;
  margin-bottom: var(--s-3);
}

/* --- Pull quote / display line ------------------------------------------ */
/* --- Display line — the bespoke moments ---------------------------------
   One device, three registers. Four display lines previously set at the same
   scale in the same band, so the line built to be a page's peak read exactly
   like the line built to close a paragraph — and a moment that repeats four
   times is a component, not a moment. Scale, tracking and the structure
   around each line now carry the intent. The type treatment itself is
   untouched: Makawao, uppercase, balanced — that part is locked. */
.display-line {
  font-family: var(--font-display);
  font-size: var(--t-display);
  line-height: var(--lh-display);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-wrap: balance;
}

/* Cinematic — the peak. At most one per page, and only in a section that
   exists to carry it. Tracking opens up because it's read at distance. */
.display-line--cinematic {
  letter-spacing: 0.035em;
}

/* Close — settles the argument the section just made. A clear step down from
   the peak, so it reads as the signature under a block rather than a second
   headline competing with the first. */
.display-line--close {
  font-size: clamp(1.5rem, 1.12rem + 1.6vw, 2.125rem);
  letter-spacing: 0.03em;
  line-height: 1.24;
}

/* Aside — display scale at the size of a note. Sits beside a column rather
   than above one, so it annotates instead of announcing. */
.display-line--aside {
  font-size: clamp(1.25rem, 1.02rem + 1.05vw, 1.75rem);
  letter-spacing: 0.042em;
  line-height: 1.3;
}

/* Practice's closing turn is the one left-ranged close on the site, so it
   hangs off a short Ember rule instead of Home's centred tick. Two Ember
   hairlines site-wide, both on lines that close an argument — that is what
   the colour was freed up to do. */
.practice__turn {
  margin-top: clamp(3rem, 1.5rem + 6vw, 6rem);
  max-width: 26ch;
  padding-top: var(--s-6);
  position: relative;
}

.practice__turn::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 2.75rem;
  height: 1px;
  background: var(--ember);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-draw) var(--ease-draw) 140ms;
}

.practice__turn[data-shown]::before {
  transform: scaleX(1);
}

.pull-quote {
  font-size: var(--t-h2);
  line-height: 1.4;
  color: var(--text);
  border-left: 1px solid var(--ember);
  padding-left: var(--s-5);
  max-width: 32rem;
}

/* Client quote — a distinct object from the editorial pull quote (D-17):
   theirs is attributed and framed, ours is not. */
.client-quote {
  border: 1px solid var(--hairline);
  padding: var(--s-6);
  max-width: 36rem;
  position: relative;
}

.client-quote__text {
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--text);
}

.client-quote__attr {
  margin-top: var(--s-4);
  display: block;
}

/* --- Margin note -------------------------------------------------------- */
.margin-note {
  border-top: 1px solid var(--hairline-strong);
  padding-top: var(--s-4);
  max-width: 22rem;
}

.margin-note__subhead {
  font-size: var(--t-body);
  display: block;
  margin-bottom: var(--s-3);
}

/* --- Meta strip --------------------------------------------------------- */
.meta-strip {
  display: grid;
  grid-template-columns: repeat(5, auto);
  gap: var(--s-6);
  justify-content: start;
  border-block: 1px solid var(--hairline);
  padding-block: var(--s-4);
}

.meta-strip dt {
  margin-bottom: var(--s-2);
}

.meta-strip dd {
  margin: 0;
  font-size: var(--t-small);
}

/* --- Form --------------------------------------------------------------- */
.field {
  display: grid;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
}

.field label {
  font-family: var(--font-label);
  font-size: var(--t-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-quiet);
}

.field input,
.field textarea {
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--hairline-strong);
  padding: var(--s-3) 0;
  color: var(--text);
  font-size: var(--t-body);
  transition: border-color var(--dur-base) var(--ease-settle);
}

.field input::placeholder,
.field textarea::placeholder {
  color: rgb(255 255 250 / 0.3);
}

.field input:hover,
.field textarea:hover {
  border-bottom-color: rgb(255 255 250 / 0.42);
}

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

.field[data-invalid="true"] input,
.field[data-invalid="true"] textarea {
  border-bottom-color: #e88a6a;
}

.field__error {
  font-size: var(--t-caption);
  color: #f0a487;
  min-height: 1.2em;
}

.signup {
  display: flex;
  border: 1px solid var(--hairline-strong);
  max-width: 20rem;
}

.signup input {
  flex: 1;
  background: transparent;
  border: 0;
  padding: var(--s-3) var(--s-4);
  color: var(--text);
  font-size: var(--t-small);
}

.signup input:focus {
  outline: none;
}

.signup:focus-within {
  border-color: var(--ember);
}

.signup button {
  background: transparent;
  border: 0;
  border-left: 1px solid var(--hairline);
  padding-inline: var(--s-4);
  cursor: pointer;
  color: var(--text-secondary);
  transition:
    background-color var(--dur-quick) var(--ease-settle),
    color var(--dur-quick) var(--ease-settle);
}

.signup button:hover {
  background: var(--ember);
  color: var(--ink);
}

/* --- System states ------------------------------------------------------ */
.state {
  border: 1px solid var(--hairline);
  padding: var(--s-8);
  text-align: center;
  color: var(--text-quiet);
}

.state--loading .state__mark {
  display: inline-block;
  width: 1.5rem;
  height: 1px;
  background: var(--ember);
  margin-bottom: var(--s-4);
  transform-origin: left;
  animation: sweep 1400ms var(--ease-settle) infinite;
}

@keyframes sweep {
  0% { transform: scaleX(0); transform-origin: left; }
  45% { transform: scaleX(1); transform-origin: left; }
  55% { transform: scaleX(1); transform-origin: right; }
  100% { transform: scaleX(0); transform-origin: right; }
}

/* 08 · INTERACTION STATES ================================================= */

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: 1px;
}

/* Ember focus ring measures 7.9:1 against Ink — well clear of the 3:1 floor. */

a,
button {
  -webkit-tap-highlight-color: rgb(243 179 145 / 0.2);
}

[hidden] {
  display: none !important;
}

/* Touch: hover has no equivalent, so the affordance has to be in the rest
   state. Underlines stay drawn rather than revealing. */
@media (hover: none) {
  .link-quiet::after {
    background: var(--hairline-strong);
  }
  .site-nav a::after {
    transform: scaleX(1);
    opacity: 0.4;
  }
}

/* 09 · MOTION + CHOREOGRAPHY ============================================== */

/* Entry: type rises and settles. Staggered by position, not by index, so the
   eye is led down the page rather than around it. */
[data-rise] {
  opacity: 0;
  transform: translateY(1.25rem);
  transition:
    opacity var(--dur-slow) var(--ease-rise),
    transform var(--dur-slow) var(--ease-rise);
  transition-delay: var(--rise-delay, 0ms);
}

[data-rise][data-shown] {
  opacity: 1;
  transform: none;
}

/* Hairline rules draw in from the left — the schematic assembling itself. */
[data-draw] {
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-draw) var(--ease-draw);
}

[data-draw][data-shown] {
  transform: scaleX(1);
}

/* Ground parallax — the ground drifts slower than the type over it. */
@media (prefers-reduced-motion: no-preference) {
  .ground--parallax::before {
    will-change: transform;
    transform: translate3d(0, var(--parallax, 0), 0) scale(1.08);
  }
}

/* Scroll cue */
.scroll-cue {
  animation: cue 2600ms var(--ease-settle) infinite;
}

@keyframes cue {
  0%, 100% { transform: translateY(0); opacity: 0.5; }
  50% { transform: translateY(0.5rem); opacity: 1; }
}

/* --- Route to route ------------------------------------------------------
   The site is a set of separate documents, and until now moving between them
   was a white cut. Cross-document view transitions make it a cross instead.
   Progressive by construction: browsers without support navigate exactly as
   before, and nothing here is required for the page to work. */
@view-transition {
  navigation: auto;
}

::view-transition-old(root) {
  animation: vt-leave 200ms var(--ease-settle) both;
}

::view-transition-new(root) {
  animation: vt-arrive 460ms var(--ease-rise) both;
}

@keyframes vt-leave {
  to { opacity: 0; transform: translateY(-0.4rem); }
}

@keyframes vt-arrive {
  from { opacity: 0; transform: translateY(0.9rem); }
}

/* The footer mark is the one element that holds still while the page changes
   around it — the fixed point the rest of the site moves past. Named only in
   the footer, because a transition name has to be unique per document and the
   404 carries a second copy of the same mark. */
.site-footer__mark .caged-o {
  view-transition-name: oyster-mark;
}

/* --- The caged-O drawing itself ------------------------------------------
   The 404 and the contact confirmation are the two places the site stops and
   asks nothing further of the visitor, so they are the two that can afford a
   moment. Until X-WEB-14 this was a CSS clip-path wipe over the two-file
   static mark. It is now the X-WEB-11 `signature` module — the mark drawn as
   the construction it is, seven beats, ~2.2s, once — which carries its own
   styles and runtime inline (src/_includes/modules/caged-o-signature.njk).
   Context rules for it live with the 404 section below. */


/* Reduced motion: opacity only, no travel, no loops. Not "less animation" —
   a different, still-designed entrance. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  [data-rise] {
    opacity: 1;
    transform: none;
  }
  [data-draw] {
    transform: scaleX(1);
  }
  .site-header[data-reveal="pending"] {
    transform: none;
    opacity: 1;
    pointer-events: auto;
  }

  /* View-transition pseudo-elements live outside the document tree, so the
     universal reset above does not reach them. Cut them explicitly — the
     navigation still happens, it just doesn't animate. */
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* 10 · RESPONSIVE ========================================================= */

/* Tablet — 768. The four blocks become 2×2; the eye still gets four nouns,
   just in two passes. */
@media (max-width: 63.99em) {
  .blocks {
    grid-template-columns: repeat(2, 1fr);
    row-gap: var(--s-7);
  }
  .reflections,
  .ways-in {
    grid-template-columns: 1fr 1fr;
  }
  .footer-grid {
    grid-template-columns: 1fr 1fr;
    row-gap: var(--s-7);
  }
  .meta-strip {
    grid-template-columns: repeat(3, auto);
    row-gap: var(--s-4);
  }
}

/* Mobile — 375. Single column, rhythm preserved: the page gets longer, never
   tighter. Nav collapses to a disclosure list, order unchanged. */
@media (max-width: 47.99em) {
  .blocks,
  .reflections,
  .ways-in,
  .footer-grid {
    grid-template-columns: 1fr;
  }
  .reflections,
  .ways-in {
    row-gap: var(--s-6);
  }
  .index-row {
    grid-template-columns: 1fr;
    gap: var(--s-2);
  }
  .index-row__meta-end {
    justify-self: start;
  }
  .meta-strip {
    grid-template-columns: repeat(2, 1fr);
  }
  .nav-toggle {
    display: inline-block;
  }
  .site-nav {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    background: var(--ink);
    border-bottom: 1px solid var(--hairline);
    padding: var(--s-4) var(--gutter) var(--s-6);
  }
  .site-nav[hidden] {
    display: none;
  }
  .site-nav a {
    width: 100%;
    padding-block: var(--s-3);
    border-bottom: 1px solid var(--hairline);
    font-size: var(--t-lead);
  }
  .site-nav a::after {
    display: none;
  }
  .motif--plate-solar {
    --motif-opacity: 0.08;
    width: 62vw;
  }
  .pull-quote {
    padding-left: var(--s-4);
  }
}

/* 11 · PRINT + FORCED COLOURS ============================================= */

@media print {
  body {
    background: #fff;
    color: #000;
  }
  .site-header,
  .scroll-cue,
  .motif,
  .ground::before,
  .ground::after {
    display: none !important;
  }
  a {
    text-decoration: underline;
  }
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
  }
}

@media (forced-colors: active) {
  .eyebrow,
  .cta {
    border: 1px solid CanvasText;
  }
  .link-quiet::after,
  .site-nav a::after {
    background: CanvasText;
  }
}

/* 12 · PAGE COMPOSITIONS ==================================================
   Section 04 gives the grid; this gives each page its composition. The
   creative strategy calls for restraint across ~70% of the site, contextual
   composition through the middle, and a small number of genuinely bespoke
   moments. The bespoke ones are marked. */

/* --- Home · hero -------------------------------------------------------- */

.hero {
  min-height: 100svh;
  display: grid;
  align-items: center;
  padding-block: clamp(5rem, 3rem + 10vw, 9rem);
}

.hero__inner {
  text-align: center;
  display: grid;
  justify-items: center;
}

/* --- The wordmark ------------------------------------------------------
   The drawn logotype, not Makawao set as type. They are close but not the
   same: the drawn mark is tighter and heavier than the face at the tracking
   the site was using, so setting it as type published an approximation of
   the logo on every page. Painted as a mask so one cached file serves both
   placements and takes its colour from the palette — the export is Ink, for
   light grounds, and this site is dark. The accessible name stays in the DOM
   as visually-hidden text beside it. */
.wordmark {
  display: block;
  width: 100%;
  aspect-ratio: 1364 / 383;
  background-color: currentColor;
  -webkit-mask: url("../img/wordmark.svg") center / contain no-repeat;
          mask: url("../img/wordmark.svg") center / contain no-repeat;
}

/* Hero, variant C — ratified 2026-08-26. Three elements: wordmark, tagline,
   drawn cue. The orbit came out because two marks plus a signature is a
   composition; one mark and a signature is a hero. The wordmark is down 35%
   for the same reason — at 23rem it was filling the frame rather than
   sitting in it, and the intrigue is in what the page withholds. */
.hero__wordmark {
  display: block;
  width: min(15rem, 44vw);
  margin: 0 auto var(--s-6);
  color: var(--text);
}

.site-header__mark .wordmark {
  width: 6.5rem;
}

/* The orbit illustration. Painted as a mask over a token colour so it stays
   one cached external file and still answers to the palette — the export's
   Shale is 2.18:1 on Ink, so on dark it takes Shale's on-dark equivalent.
   Where masks are unsupported the span simply renders nothing, which is the
   right failure for a decorative mark. */
.orbit {
  display: block;
  width: 100%;
  aspect-ratio: 941 / 458;
}

@supports (mask-image: url("#o")) or (-webkit-mask-image: url("#o")) {
  .orbit {
    background-color: var(--orbit-ink, var(--vellum-quiet));
    -webkit-mask: url("../img/orbit.svg") center / contain no-repeat;
            mask: url("../img/orbit.svg") center / contain no-repeat;
  }
}

.hero__orbit {
  width: min(24rem, 74vw);
  margin-bottom: var(--s-8);
}

/* D-1 · the outcome beat is the lead. Two-part break is the line's own
   natural structure, held together on narrow screens. */
.hero__beat {
  max-width: 22ch;
  margin-bottom: var(--s-6);
}

.hero__beat-lead,
.hero__beat-tail {
  display: block;
}

.hero__beat-lead {
  color: var(--text);
}

.hero__beat-tail {
  color: var(--text);
}

/* The hero is the wordmark, the orbit and the tagline — nothing else. The
   outcome beat that used to sit between them explained the thing the page
   spends its next four sections explaining, which is what a hero is for
   NOT doing. The tagline steps up to the large script tier and takes Ember,
   so the one line left is unambiguously the one that matters. */
.hero__tagline {
  margin-bottom: 0;
  color: var(--accent-warm);
}

/* The scroll cue is a drawn mark rather than an arrow character — the one
   piece of UI furniture in the hero, in the brand's own hand. */
.scroll-cue.plate {
  width: 1.4rem;
  background-color: var(--vellum-quiet);
  opacity: 0.75;
}

.hero__cue {
  position: absolute;
  left: 50%;
  bottom: clamp(1.5rem, 4vh, 3rem);
  transform: translateX(-50%);
  color: var(--text-quiet);
  font-size: 1.25rem;
}

/* --- Home · §01 --------------------------------------------------------
   Contextual composition: the contour plate sits in the right margin and
   overlaps the section seam, so the headline reads against terrain. */

/* §01 was a two-column grid so a contour plate could sit beside the body.
   The plate is gone and the second column with it — the four block names
   underneath are what this section actually leads to. */
.whatis {
  position: relative;
}

.whatis__rtb {
  margin-top: var(--s-6);
}

.blocks--home {
  margin-top: clamp(3rem, 1.5rem + 6vw, 6rem);
}

.block__link {
  color: var(--text);
  text-decoration: none;
  transition: color var(--dur-base) var(--ease-settle);
}

.block__link:hover {
  color: var(--ember);
}

/* BESPOKE MOMENT — four hairline columns resolving into one short line
   beneath them. The composition is the argument. */
/* Tide. The site's two display-register moments now split the palette: the
   hero tagline opens in Ember, this closes §01 in Tide. --tide-lift is the
   documented on-dark equivalent; raw Tide measures 2.18:1 here. */
.whatis__close {
  text-align: center;
  position: relative;
  color: var(--tide-lift);
}

/* Tier 4 — inline. The hairline that dropped in above the closing line is
   now a drawn mark: small enough to read as punctuation rather than as an
   illustration, which is the whole distinction between tier 4 and the
   tier-3 plates. It is the only drawn mark on Home besides the hero orbit. */
.whatis__mark {
  display: block;
  width: 2rem;
  margin: clamp(4rem, 2rem + 8vw, 7rem) auto var(--s-6);
  opacity: 0.6;
}

/* --- Home · §02 selected work ------------------------------------------ */

.work-lead {
  position: relative;
  height: 0;
}

/* Oversized numeral as graphic, bleeding left of the grid. */
.work-lead__numeral {
  position: absolute;
  top: calc(var(--s-6) * -1);
  left: -0.06em;
  font-family: var(--font-display);
  font-size: var(--t-numeral);
  line-height: 1;
  opacity: 0.9;
  pointer-events: none;
}

.work-split {
  display: grid;
  grid-template-columns: minmax(0, 1.62fr) 1px minmax(0, 1fr);
  gap: var(--s-7);
  margin-top: var(--s-8);
  align-items: start;
}

.work-split::before {
  content: "";
  grid-column: 2;
  align-self: stretch;
  background: var(--hairline);
}

.work-card--lead {
  grid-column: 1;
}

.work-card--lead .work-cover {
  aspect-ratio: 5 / 3;
}

.work-card__headline--lead {
  font-size: var(--t-h2);
  max-width: 22ch;
}

.work-stack {
  grid-column: 3;
  display: grid;
  gap: var(--s-7);
}

.work-stack .work-cover {
  aspect-ratio: 2 / 1;
}

.work-card__read {
  margin-top: var(--s-4);
  color: var(--text-quiet);
}

.work-split__all {
  margin-top: var(--s-8);
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
}

/* --- Home · practice teaser (full bleed) -------------------------------- */

.teaser {
  min-height: min(90svh, 46rem);
  display: grid;
  align-items: center;
  text-align: center;
  padding-block: clamp(5rem, 3rem + 9vw, 9rem);
  position: relative;
}

/* The vertical rule + tick that enters the section from above — the
   schematic continuing across the seam. */
.teaser__rule {
  position: absolute;
  top: -4.5rem;
  left: 50%;
  width: 1px;
  height: 9.5rem;
  background: var(--hairline-strong);
  transform: translateX(-50%);
  z-index: 2;
}

.teaser__tick {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 10px;
  height: 1px;
  background: var(--hairline-strong);
  transform: translateX(-50%);
}

.plate--sun { aspect-ratio: 37 / 36; }
.plate--star { aspect-ratio: 1; }

.teaser__headline {
  max-width: 18ch;
  margin-inline: auto;
  font-size: clamp(2rem, 1.05rem + 4.05vw, 3.25rem);
}

.teaser__link {
  margin-top: var(--s-8);
}

/* --- Shared page furniture ---------------------------------------------- */

.page-head {
  padding-top: clamp(7rem, 5rem + 8vw, 11rem);
  padding-bottom: var(--section-y);
}

.page-head__bridge {
  max-width: 44rem;
  margin-top: var(--s-6);
  font-size: var(--t-lead);
  color: var(--text-secondary);
}

.cta-wrap {
  margin-top: var(--s-8);
}

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 20rem);
  gap: var(--s-8);
  align-items: start;
}

.rail {
  position: sticky;
  top: 7rem;
}

/* --- Practice ----------------------------------------------------------- */

.blocks--practice {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--s-8) var(--s-7);
  border-top: 0;
  padding-top: 0;
}

.blocks--practice .block {
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
}

.blocks--practice .block::before {
  top: -4px;
}

/* D-15: the "so that…" line is the second thing read in every block, and
   the deliverables sit back so no block out-weights the others. */
.blocks--practice .block__deliverables {
  font-size: var(--t-caption);
  color: var(--text-quiet);
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-4);
  margin-top: var(--s-5);
}

.diff {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s-8);
  align-items: center;
}

/* --- About -------------------------------------------------------------- */

.pair {
  display: grid;
  gap: var(--s-6);
  max-width: 46rem;
}

.pair__term {
  color: var(--text);
  font-weight: 500;
}

/* Who we work with · the orrery band (X-WEB-14). Spans the shell on the page's
   flat surface, between the page-head and the categories, with no ground. The
   page-head's padding-bottom sits INSIDE its Neutral ground, so without its
   own padding-top the orrery touched that edge; section-y above matches the
   Categories section's padding-top below.

   ⚠ INK. The line is Shale's ON-DARK job, --vellum-quiet, set explicitly
   rather than left to the module's fallback. This site's flat surface is Ink
   (body --surface, .ground--flat), and Shale itself measures 2.18:1 there —
   the retired .motif--orbit-close used Shale on purpose because it was a
   texture meant to merge with a gradient at 10% opacity, not a plate meant to
   be read. The lifted token is the documented derivation for exactly this. */
.orrery-band {
  --orbit-ink: var(--vellum-quiet);
  padding-top: var(--section-y);
}

.scaffolds {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-7);
  counter-reset: scaffold;
}

.scaffold {
  border-top: 1px solid var(--hairline);
  padding-top: var(--s-5);
  position: relative;
}

.scaffold::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 0;
  width: 7px;
  height: 7px;
  border: 1px solid var(--accent-cool);
  transform: rotate(45deg) translate(-2px, -2px);
}

/* BESPOKE MOMENT — the About method construct, two beats plus one (D-19,
   re-decided X-WEB-10 2026-09-11). ONE size drives both lines: the last beat
   is set at --values-last and the run at exactly half of it. In Makawao caps
   at 0.03em that makes the run and the last beat the same width (measured
   446 / 445px at 1440), so the single beat holds the same measure as the two
   before it and the pair reads as one lockup, flush on both edges from a
   320px viewport up. The ratio is the device: change the variable, never the
   two sizes separately. The previous sizes (a 28→48 run over one word at 36→68) were
   tuned for a one-word payoff; a multi-word run broke mid-beat on a phone. */
.values {
  --values-last: clamp(2.5rem, 0.6rem + 9.6vw, 4.25rem);  /* 40 → 68 */
  margin-block: clamp(4rem, 2rem + 8vw, 8rem);
  text-align: right;
}

.values__line {
  font-family: var(--font-display);
  font-size: calc(var(--values-last) / 2);                 /* 20 → 34 */
  line-height: 1.1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  display: block;
}

/* A beat never breaks inside itself. The run fits on one line down to a
   320px viewport; narrower than that it breaks between beats, not within. */
.values__beat {
  white-space: nowrap;
}

.values__last {
  display: block;
  font-family: var(--font-display);
  font-size: var(--values-last);
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--ember);
  margin-top: var(--s-3);
  margin-right: -0.04em;
}

.placeholder-note {
  border: 1px dashed var(--accent-cool);
  padding: var(--s-5);
  color: var(--accent-cool);
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  line-height: 1.6;
  letter-spacing: 0.02em;
  max-width: 44rem;
}

/* --- Contact ------------------------------------------------------------ */

.mailto-headline {
  font-size: clamp(1.5rem, 0.6rem + 3.8vw, 3rem);
  line-height: 1.15;
  color: var(--text);
  text-decoration: none;
  display: inline-block;
  border-bottom: 1px solid var(--hairline-strong);
  padding-bottom: 0.15em;
  transition: color var(--dur-base) var(--ease-settle),
    border-color var(--dur-base) var(--ease-settle);
  word-break: break-word;
}

.mailto-headline:hover {
  color: var(--ember);
  border-bottom-color: var(--ember);
}

.form-toggle {
  background: none;
  border: 0;
  padding: 0 0 0.3rem;
  margin-top: var(--s-7);
  color: var(--text-secondary);
  border-bottom: 1px solid var(--hairline-strong);
  cursor: pointer;
  font-size: var(--t-body);
}

.form-toggle:hover {
  color: var(--ember);
  border-bottom-color: var(--ember);
}

.form-wrap {
  margin-top: var(--s-7);
  max-width: 32rem;
}

/* --- Case study --------------------------------------------------------- */

.case-cover {
  min-height: min(74svh, 40rem);
  display: grid;
  align-items: end;
  padding-block: clamp(7rem, 5rem + 8vw, 11rem) var(--s-9);
}

.case-cover__headline {
  font-size: clamp(1.875rem, 1rem + 3.7vw, 3rem);
  line-height: 1.15;
  max-width: 18ch;
  margin-block: var(--s-5);
}

.case-section {
  padding-block: var(--section-y);
  border-top: 1px solid var(--hairline);
}

.case-section__head {
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: var(--s-5);
  margin-bottom: var(--s-7);
}

.case-section__standfirst {
  font-size: var(--t-lead);
  color: var(--text-secondary);
  max-width: 32rem;
}

.end-note {
  padding-block: var(--s-9);
  border-top: 1px solid var(--hairline);
  text-align: center;
}

.end-note__filed {
  display: block;
  margin-top: var(--s-4);
}

/* --- Field Note article -------------------------------------------------- */

.article-body {
  max-width: var(--measure-prose);
  font-size: var(--t-lead);
  line-height: 1.75;
  color: var(--text-secondary);
}

.article-body > * + * {
  margin-top: var(--s-5);
}

.article-body h2 {
  font-size: var(--t-h2);
  color: var(--text);
  margin-top: var(--s-8);
}

.article-body strong {
  color: var(--text);
  font-weight: 500;
}

/* --- 404 ---------------------------------------------------------------- */

.notfound {
  min-height: 100svh;
  display: grid;
  place-items: center;
  text-align: center;
  padding: var(--s-8) 0;
}

/* The mark fills its frame on the 404 and in the confirmation — both are
   moments, not footer furniture, so the base 3.25rem doesn't apply. */
.notfound__mark .caged-o,
.form-confirmation__mark .caged-o {
  width: 100%;
  margin-bottom: 0;
  opacity: 1;
}

/* The signature module paints its own Ink box by default (it was built to sit
   on a stage). Here it sits on the page — the Expressive ground on the 404 —
   so the box goes, and the frame above sets the size, not the module's own
   520px cap. The drawing's palette stays the module's: Vellum Quiet line,
   Ember O, as reviewed in X-WEB-11. */
:is(.notfound__mark, .form-confirmation__mark) .caged-o[data-expression] {
  --caged-ground: transparent;
  --caged-max: 100%;
}

.form-confirmation__mark {
  width: 4.25rem;
  margin-bottom: var(--s-6);
  color: var(--ember);
}

.notfound__mark {
  width: 5rem;
  margin: 0 auto var(--s-7);
  color: var(--ember);
}

/* --- Responsive for compositions ---------------------------------------- */

@media (max-width: 63.99em) {
  .split,
  .diff {
    grid-template-columns: 1fr;
  }
  .work-split {
    grid-template-columns: 1fr;
  }
  .work-split::before {
    display: none;
  }
  .work-card--lead,
  .work-stack {
    grid-column: 1;
  }
  .work-stack {
    grid-template-columns: 1fr 1fr;
  }
  .scaffolds {
    grid-template-columns: 1fr;
  }
  .rail {
    position: static;
  }
  .case-section__head {
    grid-template-columns: 1fr;
    gap: var(--s-3);
  }
}

@media (max-width: 47.99em) {
  .blocks--practice,
  .work-stack {
    grid-template-columns: 1fr;
  }
  .hero__beat {
    max-width: 100%;
  }
  .values {
    text-align: left;
  }
}

/* --- Work gallery + index lists ----------------------------------------- */

.work-gallery {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(2.5rem, 1rem + 5vw, 4.5rem) var(--s-7);
}

/* Every third item runs full width — the gallery breathes instead of
   marching, and the eye gets a rest between pairs. */
.work-gallery > *:nth-child(3n + 1) {
  grid-column: 1 / -1;
}

.work-gallery > *:nth-child(3n + 1) .work-cover {
  aspect-ratio: 21 / 9;
}

.work-gallery > *:nth-child(3n + 1) .work-card__headline {
  font-size: var(--t-h2);
  max-width: 24ch;
}

.index-list {
  border-bottom: 1px solid var(--hairline);
}

@media (max-width: 47.99em) {
  .work-gallery {
    grid-template-columns: 1fr;
  }
  .work-gallery > *:nth-child(3n + 1) .work-cover {
    aspect-ratio: 5 / 3;
  }
}

/* 13 · CORRECTIONS FROM THE RENDER PASS ===================================
   Adjustments made against the built page rather than in the abstract. */

/* The hero cue anchors to the hero, not to the content block inside it. */
.hero { position: relative; }
.hero__cue { z-index: 3; }

.blocks--home {
  margin-top: clamp(2.5rem, 1rem + 4vw, 4rem);
}

/* Four nouns at a glance means four names on one optical line — the
   descriptors align even when "Marketing Operations" takes two. */
.blocks--home .block__name {
  min-height: 2.4em;
}

.whatis__close {
  margin-top: clamp(2.5rem, 1rem + 4.5vw, 4.5rem);
}

/* §02 · the divider rule between the lead case and the stacked pair was
   collapsing to zero height in the grid row. */
.work-split { position: relative; }

.work-split::before {
  align-self: stretch;
  min-height: 100%;
  width: 1px;
  justify-self: center;
}

/* The numeral bleeds left of the grid, aligned to the top of the lead
   card — a graphic, not a heading. */
.work-lead__numeral {
  position: absolute;
  top: -0.62em;
  left: -0.06em;
  font-family: var(--font-display);
  font-size: var(--t-numeral);
  line-height: 1;
  pointer-events: none;
  z-index: 3;
}

.work-split { margin-top: var(--s-9); }

/* Consecutive flat sections were double-padding at the seam. */
.section + .section { padding-top: 0; }

@media (max-width: 63.99em) {
  .work-lead__numeral { position: static; display: block; margin-bottom: var(--s-3); }
}


/* 14 · TEXT ON ATMOSPHERIC GROUNDS ========================================
   Verified by sampling the rendered pixels behind every text node, not by
   the computed background-colour — an automated checker reads a gradient as
   its base colour and passes text that visibly fails over the bright part.

   The rule: over an atmospheric ground, type steps up one tier. Quiet and
   secondary tokens are tuned to Ink, and the grounds are lighter than Ink
   wherever they do their work. */

.ground:not(.ground--flat) .t-body,
.ground:not(.ground--flat) .t-lead,
.ground:not(.ground--flat) .u-secondary,
.ground:not(.ground--flat) p {
  color: var(--text);
}

.ground:not(.ground--flat) .rfp-line {
  color: var(--text);
}

.ground:not(.ground--flat) .t-mono,
.ground:not(.ground--flat) .t-caption,
.ground:not(.ground--flat) .u-quiet,
.ground:not(.ground--flat) .block__num,
.ground:not(.ground--flat) .section-rule__marker,
.ground:not(.ground--flat) .work-card__sector,
.ground:not(.ground--flat) .footer-col__label {
  color: var(--text-secondary);
}

/* Deliverables and margin notes keep their recessive role but clear AA. */
.ground:not(.ground--flat) .block__deliverables {
  color: var(--text-secondary);
}

/* The lift rule above sweeps every <p> on an atmospheric ground, which is
   correct for body copy and wrong for a line that was deliberately given an
   accent — it was quietly repainting the hero tagline Vellum. Both script
   moments are stated at matching specificity so they survive it. Both are
   checked by the rendered-pixel contrast audit, not assumed. */
.ground:not(.ground--flat) .hero__tagline {
  color: var(--accent-warm);
}

.site-footer__mark p,
.ground:not(.ground--flat) .site-footer__mark p {
  color: var(--tide-lift);
}

/* 15 · CRITIQUE PASS =====================================================
   Changes made after a structured design critique of the built pages. */

/* --- The case cover was reading as a broken image -----------------------
   A centred "+" in an empty well is the universal missing-asset affordance,
   and it appeared five times on the page whose whole job is proof. Corner
   registration ticks turn the same frame into a technical plate. */

.work-cover__ticks {
  position: absolute;
  inset: 0.75rem;
  z-index: 3;
  pointer-events: none;
}

.work-cover__ticks i {
  position: absolute;
  width: 10px;
  height: 10px;
  border: 0 solid var(--hairline-strong);
}

.work-cover__ticks i:nth-child(1) { top: 0; left: 0; border-top-width: 1px; border-left-width: 1px; }
.work-cover__ticks i:nth-child(2) { top: 0; right: 0; border-top-width: 1px; border-right-width: 1px; }
.work-cover__ticks i:nth-child(3) { bottom: 0; left: 0; border-bottom-width: 1px; border-left-width: 1px; }
.work-cover__ticks i:nth-child(4) { bottom: 0; right: 0; border-bottom-width: 1px; border-right-width: 1px; }

.work-card:hover .work-cover__ticks i { border-color: var(--ember); }
.work-cover__ticks i { transition: border-color var(--dur-base) var(--ease-settle); }

/* --- One grid, one marker ----------------------------------------------
   The exposed hairline is a notation system, so it can only have one
   notation. Every column rule now starts with the same corner bracket —
   it reads as a registration mark and rhymes with the caged-O — and every
   split derives from a 12-column grid on 1136 with a 32px gutter. */

.blocks,
.reflections,
.ways-in,
.scaffolds,
.work-gallery {
  column-gap: var(--s-6); /* 32 */
}

.way::before,
.scaffold::before {
  content: "";
  position: absolute;
  top: -4px;
  left: -4px;
  width: 9px;
  height: 9px;
  border-left: 1px solid var(--hairline-strong);
  border-top: 1px solid var(--hairline-strong);
  border-radius: 0;
  background: none;
  transform: none;
}

.reflection {
  position: relative;
}

.reflection::before {
  content: "";
  position: absolute;
  top: -4px;
  left: -4px;
  width: 9px;
  height: 9px;
  border-left: 1px solid var(--hairline-strong);
  border-top: 1px solid var(--hairline-strong);
}

/* --- Practice: the missing middle tiers --------------------------------
   Descriptor, promise and capability list were all set at the same 13px,
   so three semantic registers read as one grey block under a 28px title. */

.blocks--practice .block__desc {
  font-size: clamp(1.0625rem, 0.98rem + 0.36vw, 1.1875rem);
  line-height: 1.5;
  color: var(--text);
  margin-top: var(--s-3);
}

/* The promise is a kicker, not a demoted second line — it sits above the
   descriptor, in the data tier, where a label belongs. */
.blocks--practice .block__so {
  order: -1;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--accent-cool);
  margin-top: 0;
  margin-bottom: var(--s-4);
}

.blocks--practice .block {
  display: flex;
  flex-direction: column;
}

.blocks--practice .block__num { order: -3; }
.blocks--practice .block__name { order: -2; margin-bottom: var(--s-2); }

.blocks--practice .block__deliverables {
  font-size: 0.9375rem;
  line-height: 1.5;
  gap: 0;
}

.blocks--practice .block__deliverables li {
  padding-block: 0.42rem;
  border-top: 1px solid var(--hairline);
}

.blocks--practice .block__deliverables li:first-child { border-top: 0; }

/* --- Sector grouping on the Work index ---------------------------------
   The standfirst promises "grouped by sector"; it now is. */

.sector-group + .sector-group { margin-top: clamp(3.5rem, 2rem + 5vw, 6rem); }

.sector-group__head {
  border-top: 1px solid var(--hairline-strong);
  padding-top: var(--s-4);
  margin-bottom: var(--s-6);
  font-size: var(--t-caption);
  color: var(--text-secondary);
}

.sector-group .work-gallery > *:nth-child(3n + 1) {
  grid-column: auto;
}

.sector-group .work-gallery > *:nth-child(3n + 1) .work-cover {
  aspect-ratio: 5 / 3;
}

.sector-group .work-gallery > *:nth-child(3n + 1) .work-card__headline {
  font-size: var(--t-h3);
}

/* A sector with a single case runs full width rather than sitting in a
   half-column beside nothing. Grouping should give the gallery rhythm —
   sector rule, then one wide plate — not leave holes in it. */
.sector-group .work-gallery > *:only-child {
  grid-column: 1 / -1;
}

.sector-group .work-gallery > *:only-child .work-cover {
  aspect-ratio: 21 / 9;
}

.sector-group .work-gallery > *:only-child .work-card__headline {
  font-size: var(--t-h2);
  max-width: 24ch;
}

.sector-group__head + .work-gallery { margin-top: 0; }

/* --- The Ember highlight was breaking across lines and orphaning --------
   The most prominent colour moment on three pages was a ragged two-piece
   blob straddling a line break. Above the phone breakpoint the accent run
   holds together; below it, wrapping matters more than the shape. */
@media (min-width: 48em) {
  .accent { white-space: nowrap; }
}

/* --- Even section pacing ------------------------------------------------
   The rule → pill interval was consistent; the pill → content gap was
   103 / 91 / 32 / 37px in the same structural slot. One token now. */
.section-rule { padding-bottom: var(--s-6); }
.section-rule + * { margin-top: 0; }

/* --- The RFP path is a distinct high-value entry, not fine print -------- */
.rfp-line {
  margin-top: var(--s-7);
  font-size: var(--t-body);
  color: var(--text-secondary);
}

/* --- The valediction was reading as a truncation bug -------------------- */
.valediction {
  display: block;
  margin-top: var(--s-7);
  padding-top: var(--s-5);
  border-top: 1px solid var(--hairline);
  max-width: 12rem;
}

@media (max-width: 47.99em) {
  .blocks--practice .block__deliverables { font-size: var(--t-caption); }
}

/* Honeypot — off-canvas rather than display:none, which some bots detect. */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
