/* ============================================
   Quietwork
   The category standard, executed properly.
   Craft bar: UK SMB fintech (Monzo, Starling, Tide, Xero) + 37signals.
   No governing metaphor. Light ground, plain language, typography-led.
   ============================================ */

:root {
  /* Colour lives in css/palettes.css, which loads before this file. Nothing
     here may carry a raw hex: a palette swap has to be one edit in one file,
     and every stray literal is a place the swap silently misses. What remains
     below is everything that is not colour. */
  --font: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  --measure: 34rem;
  --gutter: clamp(20px, 5vw, 40px);
  --radius: 10px;
  /* Stadium, for the one pill-shaped control on the site. Distinct from
     rounded.pill (50%), which is a circle and would make an ellipse here. */
  --radius-stadium: 50px;
}


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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  font-synthesis-weight: none;
}

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

/* Browser surfaces are part of the design. */
::selection { background: var(--accent); color: #fff; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
::-webkit-scrollbar { width: 12px; }
::-webkit-scrollbar-track { background: var(--bg-alt); }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border: 3px solid var(--bg-alt); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--accent); color: #fff;
  padding: 12px 20px; font-weight: 600; border-radius: 0 0 var(--radius) 0;
}
.skip-link:focus { left: 0; }

.wrap { width: 100%; max-width: 1140px; margin: 0 auto; padding-inline: var(--gutter); }
.col { max-width: 720px; }        /* narrow column, on the page left edge */
.col--tight { max-width: 34rem; } /* 55ch, for a passage that wants to be read slowly */
/* .wrap--wide (1360px) is retired. The homepage was the only page using it,
   which put its content at x=74 while the nav and footer sat at x=184 on the
   same screen: a 110px disagreement down the left edge of the page. The nav
   register is the one that has to hold still between pages, so the content
   moved to meet it. One left edge, on every page and down every page. */

/* Full bleed, escaping the wrap entirely. Used once. */
.bleed {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

/* ---- Type ------------------------------------------------------------ */
/* One family, worked properly. Hierarchy comes from size and weight,
   not from a second typeface brought in to do the job. */

h1, h2, h3 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.12;
  text-wrap: balance;
  color: var(--text);
}
h1 {
  font-size: clamp(2.6rem, 9.2vw, 7.5rem);
  letter-spacing: -0.045em;
  line-height: 0.98;
  padding-bottom: 0.04em;   /* room for descenders at display size */
  text-wrap: balance;
}
h2 { font-size: clamp(1.7rem, 3.8vw, 2.75rem); line-height: 1.06; }
h3 { font-size: 1.15rem; letter-spacing: -0.012em; }
/* An h2 that is structurally correct but secondary in the page's hierarchy,
   so it does not compete with the h1 it sits beside. */
h2.h-sm { font-size: 1.15rem; letter-spacing: -0.012em; }

p { margin: 0 0 1.1em; max-width: var(--measure); }
/* Headings carry no margin of their own, so the gap below one is set here.
   It stays smaller than the space above, which the section padding supplies. */
h2 + p, h3 + p, h2 + blockquote { margin-top: 18px; }
/* Display type sets tight, so the space beneath it has to be set from the
   display size rather than inheriting the body-copy gap. Without this the
   descenders on a two-line headline sit into the paragraph below. */
h1 + p { margin-top: clamp(22px, 3.2vw, 44px); }
.lead { font-size: clamp(1.1rem, 1.9vw, 1.3rem); line-height: 1.55; color: var(--text-muted); }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.18em; }
a:hover { color: var(--accent-dark); }

strong { font-weight: 600; }


/* ---- Sections -------------------------------------------------------- */

.section { padding: clamp(56px, 8vw, 104px) 0; }
.section--alt { background: var(--bg-alt); }
.section--ink { background: var(--bg-ink); color: var(--text-onink); }
.section--ink h2, .section--ink h3 { color: #fff; }
.section--ink p { color: var(--text-onink-muted); }
.section--ink a { color: var(--link-onink); }
/* The link colour above outranks .btn--onink on specificity, which left the
   button's label sitting light-on-white. Buttons opt back out explicitly. */
.section--ink a.btn { color: var(--bg-ink); }
.section--ink a.btn--onink:hover { color: var(--bg-ink); }

.section__head { margin-bottom: clamp(28px, 4vw, 48px); }
.section__head p { margin-top: 14px; }

/* ---- Buttons --------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font: inherit; font-weight: 600; font-size: 1rem;
  padding: 14px 24px; min-height: 50px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  text-decoration: none; cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn--primary { background: var(--accent); color: #fff; border-color: var(--accent); }
/* Hover fills with ink rather than darkening the accent. The darken was a
   dE 9.3 shift of the same hue, which reads as the button going slightly duller
   rather than responding; ink is dE 76.8 from the accent, so the control
   clearly answers. It is also the idiom the system already uses: .pill fills
   with --text on hover and flips its label white. White on the ink measures
   17.82:1.
   Buttons on a coloured or dark ground override this: see .startpoint--accent
   .btn--primary, and .section--ink below, both of which would otherwise fill
   with the ground they sit on and disappear. */
.btn--primary:hover { background: var(--bg-ink); border-color: var(--bg-ink); color: #fff; }
.section--ink a.btn--primary:hover {
  background: #fff; border-color: #fff; color: var(--bg-ink);
}
.btn--secondary { background: transparent; color: var(--text); border-color: var(--line-strong); }
.btn--secondary:hover { border-color: var(--text); color: var(--text); background: transparent; }
.btn--onink { background: #fff; color: var(--bg-ink); border-color: #fff; }
.btn--onink:hover { background: var(--onaccent-hover); border-color: var(--onaccent-hover); color: var(--bg-ink); }
.btn[disabled] { opacity: .55; cursor: not-allowed; }

/* Link rules scoped to a container (.nav__links a, .section--ink a) beat the
   plain .btn--* classes on specificity and were silently recolouring button
   labels. The nav CTA was rendering at 3.2:1. Buttons restate their colour. */
.nav__links a.btn--primary,
.section--ink a.btn--primary { color: #fff; }
.nav__links a.btn--secondary { color: var(--text); }

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }

/* ---- Hero ------------------------------------------------------------ */

.hero { padding: clamp(56px, 9vw, 120px) 0 clamp(44px, 6vw, 80px); }
.hero h1 { max-width: 15ch; }

/* ---- Homepage hero --------------------------------------------------- */
/* Everything below is scoped to .home. Eleven other pages share the .hero
   class and must keep the hero they already have: the poster scale and the
   photograph are a homepage treatment, not a site-wide one. */

.home .hero { padding: clamp(40px, 5vw, 72px) 0 clamp(44px, 6vw, 80px); }

/* Three columns of micro-copy above the headline, the editorial device that
   sets the register before the display type arrives. */
.hero__meta {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px clamp(24px, 5vw, 64px);
  margin: 0 0 clamp(26px, 3.6vw, 44px); padding: 0; list-style: none;
  font-size: 0.875rem; line-height: 1.4; color: var(--text-muted);
}
.hero__meta li:last-child { text-align: right; }

/* Poster scale. The h1 escapes the body grid into the wide register and
   sits above the photograph in the stack. */
.hero__type { position: relative; z-index: 2; }
/* Poster scale, properly. The measure is the viewport, not the body grid.
   Line breaks are authored, and the size is driven by vw so the longest
   line reaches both edges at every width instead of only at one. Balance
   and pretty are both off: at this size the breaks are a design decision,
   not something to delegate to the browser. */
.home .hero__type { padding-inline: var(--gutter); max-width: none; }
.home .hero h1 {
  max-width: none;
  font-size: clamp(2.1rem, 12.7vw, 11.4rem);
  line-height: 0.87;
  letter-spacing: -0.055em;
  text-wrap: wrap;
}
/* The authored breaks only hold while the type is vw-driven. Once the clamp
   floor takes over on very narrow screens, hand wrapping back. */
@media (max-width: 400px) {
  .home .hero h1 { text-wrap: balance; }
  .home .hero h1 br { display: none; }
}

/* The photograph is pulled up so the headline's descenders cut into its top
   edge. Type and image interlock rather than stack. */
/* The photograph is pulled up hard so the last line genuinely sits on it,
   rather than resting politely above it. Type and image occupy the same
   band of the page. */
.hero__shot {
  position: relative; margin: 0;
  margin-top: calc(clamp(20px, 4.4vw, 64px) * -1);
}
.hero__shot img { width: 100%; aspect-ratio: 1600 / 688; object-fit: cover; }
/* Top scrim so the overlapping line stays black on light, bottom scrim so
   the chips and the caption always have a dark ground to sit on. Both are
   contrast devices, not decoration. */
.hero__shot::before, .hero__shot::after {
  content: ''; position: absolute; left: 0; right: 0; z-index: 1;
  pointer-events: none;
}
/* The reference this came from overlaps black type onto a near-white misty
   sky. This photograph is a dark studio, so the scrim has to do that work
   instead: solid at the join, still lifting at 40%, gone by the bottom. */
.hero__shot::before {
  top: 0; height: 44%;
  background: linear-gradient(to bottom,
    var(--bg) 0%,
    rgba(255,255,255,0.96) 28%,
    rgba(255,255,255,0.62) 58%,
    rgba(255,255,255,0) 100%);
}
.hero__shot::after {
  bottom: 0; height: 46%;
  background: linear-gradient(to top, var(--scrim-ink) 0%, var(--scrim-clear) 100%);
}
.hero__overlay {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px 20px;
  padding: clamp(16px, 2.4vw, 28px) var(--gutter);
}
.hero__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.hero__chip {
  display: inline-flex; align-items: center; min-height: 40px;
  padding: 9px 18px; border-radius: var(--radius-stadium);
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.45);
  backdrop-filter: blur(10px);
  color: #fff; text-decoration: none;
  font-size: 0.9375rem; font-weight: 500;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.hero__chip:hover, .hero__chip:focus-visible { background: #fff; color: var(--text); border-color: #fff; }
.hero__where { margin: 0; max-width: none; font-size: 0.875rem; color: #fff; }

/* A black rule directly under a full-bleed photograph reads as a second
   frame edge. On the homepage only, it drops to the hairline. */
.home .hero__body { border-top-color: var(--line); }

/* ---- Statement headings, homepage only ------------------------------- */
/* The reference's second voice is a large mixed roman-and-italic statement,
   not a section label. On this page the h2 steps up to meet it. */

.home main h2:not(.h-sm):not(.door__title) {
  font-size: clamp(2rem, 5.4vw, 4.5rem);
  line-height: 0.96;
  letter-spacing: -0.04em;
  max-width: 16ch;
}
.home .section--ink h2 { max-width: 14ch; }

/* ---- Start point (the audit) ------------------------------------------
   ⚠️ RESTORED 2026-08-26. This block was deleted by accident during one of the
   homepage nav edits: an index-based block replacement in site.css took the
   end marker past the end of the intended rule and swallowed this with it.
   Recovered from backup/2026-08-25-pre-max/site.css.
   The symptom was quiet, which is why it survived several passes unnoticed:
   the section still rendered, it just lost its accent ground, its two-column
   grid and its £600 numeral, so the page's priced conversion block silently
   became a plain white section. A missing component does not throw.
   The audit lifted out of the AI grid, where a priced product sat as one of
   four equal cards. Built entirely from existing tokens: the section rhythm,
   the standard register, the section rule, the lead step and the primary
   button. It no longer borrows the figure-display numeral: see below. */

/* Single column. The price used to sit opposite as a 6rem numeral, which made
   the loudest thing on the homepage a low number, and anchored the whole
   studio to it. The fixed price is still worth stating plainly, so it stays,
   set as a small line under the control where a price belongs. */
.startpoint__grid { display: grid; }
.startpoint__grid h2 { max-width: 14ch; }
.startpoint__grid .lead { margin-top: 16px; max-width: 40ch; }
.startpoint__price {
  margin: 14px 0 0; max-width: 46ch;
  font-size: 0.9375rem; line-height: 1.5;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--text-muted);
}
.startpoint--accent { background: var(--accent); }
.startpoint--accent h2 { color: #fff; }
.startpoint--accent .lead, .startpoint--accent .eyebrow { color: #fff; }
.startpoint--accent .srule { background: rgba(255,255,255,0.65); }
.startpoint--accent .startpoint__price { color: rgba(255,255,255,0.95); }   /* 4.76:1 on the accent ground; 0.82 measured 3.96 and failed AA */
/* The section ground IS the accent, so a primary button on it would be accent
   on accent. .btn--onaccent is the existing inverse and the markup should use
   it here; until it does, this keeps the control visible. */
.startpoint--accent .btn--primary {
  background: #fff; color: var(--accent); border-color: #fff;
}
.startpoint--accent .btn--primary:hover {
  background: var(--onaccent-hover); border-color: var(--onaccent-hover); color: var(--accent);
}


/* ---- Nav width: one value, everywhere ---------------------------------
   The homepage nav ran at 1360 to align with its wide content register while
   the other eighteen pages ran at the standard 1140. Measured, that moved the
   logo 110px horizontally on every click between the homepage and anything
   else (x=74 on home, x=184 elsewhere), which is what reads as the site
   changing size as you navigate. Alignment inside one page is worth less than
   the chrome holding still between pages, so the override is gone.
   The nav and the footer now both sit at 1140 on all nineteen pages. The
   homepage content stays at 1360 on purpose: it is a deliberate wide register,
   and it now reads as wide content bracketed by standard chrome rather than as
   a nav that cannot make its mind up. */

@media (max-width: 700px) {
  .hero__meta { grid-template-columns: 1fr 1fr; gap: 14px 20px; }
  .hero__meta li:last-child { grid-column: 1 / -1; text-align: left; }
  .hero__shot img { aspect-ratio: 4 / 3; }
  .hero__overlay { align-items: flex-start; flex-direction: column; }
}
/* Deliberate scale break: the lead sits well below the display size rather
   than stepping down politely, so the headline reads as the only voice. */
.hero__body {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 56px);
  margin-top: clamp(28px, 4vw, 44px);
  padding-top: clamp(24px, 3vw, 32px);
  border-top: 1px solid var(--text);
  align-items: start;
}
.hero__body .lead { margin: 0; max-width: 40ch; font-size: clamp(1.05rem, 1.5vw, 1.2rem); }
.hero .btn-row { margin-top: 0; }
.hero__note { margin: 14px 0 0; font-size: 0.875rem; color: var(--text-muted); }

@media (max-width: 760px) {
  .hero__body { grid-template-columns: 1fr; gap: 22px; }
}

/* ---- Evidence row ---------------------------------------------------- */
/* Not the big-number-over-small-label template. The client leads, the
   figures sit at reading scale, and the rules do the structural work. */

.evidence { border-top: 1px solid var(--text); padding-top: 18px; max-width: 42rem; }
.evidence__who {
  margin: 0 0 2px; max-width: none;
  font-weight: 600; font-size: 1rem;
}
.evidence__rows { margin: 0; display: grid; }
.evidence__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 24px; padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
.evidence__row dt { color: var(--text); }
.evidence__row dd {
  margin: 0; font-weight: 700; font-size: 1.35rem;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.02em;
}

/* The attribution line under an evidence strip. Required, not optional, when
   the figures are somebody else's: the strip is styled to read as proof, so
   borrowed numbers have to say whose they are on the same screen. */
.evidence__src {
  margin: 14px 0 0; max-width: none;
  font-size: 0.8125rem; line-height: 1.5; color: var(--text-muted);
}

/* ---- Split ----------------------------------------------------------- */

.split {
  display: grid; grid-template-columns: 1fr 1fr;
  column-gap: clamp(28px, 5vw, 64px);
  row-gap: 0;              /* .cta-after owns the space below the text */
  align-items: center;
}
.split--top { align-items: start; }
/* The trailing CTA is a third grid child so that on narrow screens it falls
   after the image it belongs to instead of orphaning it. On desktop it
   returns to the text column. */
.cta-last { grid-column: 1; margin-top: 4px; }
/* Alternate which side the image sits on, for scroll rhythm. On narrow
   screens the heading always leads; an image above its own heading is a
   picture with no caption yet. */
.split--reverse .split__media { order: -1; }
.split__media img, .split__media video {
  border-radius: var(--radius); border: 1px solid var(--line);
  aspect-ratio: 3 / 2; object-fit: cover;
}
/* The founder portrait is 544x630 and is never seen beside the other two. */
.section--ink .split__media img { aspect-ratio: auto; }
.section--ink .split__media img, .section--ink .split__media video { border-color: var(--line-onink); }
figure { margin: 0; }
figcaption { margin-top: 10px; font-size: 0.875rem; color: var(--text-muted); }
.section--ink figcaption { color: var(--text-onink-quiet); }

/* ---- Quote ----------------------------------------------------------- */

/* The only sourced quote on the site was dying at the foot of a text
   column. It is set at its own scale now, against the accent keyline that
   opens every other block. */
.quote {
  margin: clamp(28px, 4vw, 40px) 0 0;
  padding: 0 0 0 clamp(18px, 2.4vw, 26px);
  border-left: 3px solid var(--accent);
}
.section--ink .quote { border-left-color: var(--link-onink); }
.quote p {
  font-size: clamp(1.25rem, 2.3vw, 1.7rem);
  line-height: 1.28; font-weight: 600;
  letter-spacing: -0.022em; color: var(--text);
  margin-bottom: 12px; max-width: 22ch;
}
.section--ink .quote p { color: #fff; }
.quote footer { font-size: 0.9375rem; color: var(--text-muted); max-width: 36ch; }
.section--ink .quote footer { color: var(--text-onink-quiet); }

/* ---- Service list ---------------------------------------------------- */
/* A list, not a grid of icon cards. */

.services { border-top: 1px solid var(--line); margin-top: 8px; }
.service {
  display: grid; grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
  gap: 6px clamp(24px, 5vw, 64px);
  padding: 26px 0;
  border-bottom: 1px solid var(--line);
}
.service { transition: background-color .15s ease; }
.service:hover { background: rgba(74,94,218,0.035); }
.service h3 { margin: 0; }
/* Service rows became links on the section pages; the whole row is the target. */
a.service { text-decoration: none; color: inherit; }

a.service:hover h3 { color: var(--accent); }

.service p { margin: 0; color: var(--text); max-width: 46ch; }

.cta-after { margin-top: 26px; }
.section--flush { padding-top: 0; }
.stack-lg { margin-top: clamp(40px, 5vw, 56px); }
.stack-lg h3 { margin-bottom: 10px; }

/* ---- Checklist ------------------------------------------------------- */

.checklist { margin: 0; padding: 0; list-style: none; counter-reset: step; }
.checklist li {
  position: relative;
  counter-increment: step;
  padding: 0 0 20px 44px;
  max-width: 48ch;
}
.checklist li::before {
  content: counter(step);
  position: absolute; left: 0; top: 1px;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  background: var(--accent-wash); color: var(--accent);
  border-radius: 50%;
  font-size: 0.875rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.checklist li strong { color: var(--text); }
.checklist li:last-child { padding-bottom: 0; }

/* ---- Form ------------------------------------------------------------ */

.form { display: grid; gap: 18px; }
/* Honeypot. Deliberately NOT display:none or visibility:hidden: the trap only
   works if the field is still rendered for a bot that fills every input it
   finds. Clipped to a pixel instead, and taken out of the accessibility tree
   and the tab order by aria-hidden and tabindex on the markup. */
.hp {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.field { display: grid; gap: 7px; }
.field > span { font-weight: 600; font-size: 0.9375rem; }
.field .opt { font-weight: 400; color: var(--text-muted); }
.field input, .field textarea {
  width: 100%; padding: 12px 14px;
  font: inherit; font-size: 1rem;
  color: var(--text); background: #fff;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}
.field input:focus, .field textarea:focus {
  outline: 2px solid var(--accent); outline-offset: 1px;
  border-color: var(--accent);
  /* The browser default ring is replaced, not merely recoloured: the wash
     halo is the same accent used by the section rules, so a focused field
     belongs to the same system as everything else on the page. */
  box-shadow: 0 0 0 4px var(--accent-wash);
}
.field input::placeholder, .field textarea::placeholder { color: var(--placeholder); }
.field textarea { resize: vertical; min-height: 130px; }

.form-success, .form-error { padding: 14px 16px; border-radius: var(--radius); font-size: 0.9375rem; display: none; }
.form-success { background: var(--ok-bg); color: var(--ok); border: 1px solid var(--ok-line); }
.form-error   { background: var(--warn-bg); color: var(--warn); border: 1px solid var(--warn-line); }
.form-success.visible, .form-error.visible { display: block; }
.form-error a { color: var(--warn-link); }

/* ---- Nav ------------------------------------------------------------- */

.nav {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255,255,255,0.92);
  backdrop-filter: saturate(1.6) blur(8px);
  border-bottom: 1px solid transparent;
  transition: border-color .15s ease;
}
.nav.scrolled { border-bottom-color: var(--line); }
.nav__in { display: flex; align-items: center; gap: 20px; min-height: 66px; padding-block: 12px; }
.nav__logo img { width: 128px; }
.nav__links { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nav__links a {
  color: var(--text); text-decoration: none;
  font-size: 1rem; font-weight: 500;
  padding: 9px 12px; border-radius: 8px;
}
.nav__links a:hover { color: var(--text); }
/* The grey tint was the browser-default answer. A blue rule drawing in from
   the left is the same mark the sections open with, at nav scale. */
@media (min-width: 761px) {
  .nav__links a:not(.btn) { position: relative; }
  .nav__links a:not(.btn)::after {
    content: ''; position: absolute; left: 12px; right: 12px; bottom: 5px;
    height: 2px; background: var(--accent);
    transform: scaleX(0); transform-origin: left;
    transition: transform .18s cubic-bezier(.16,1,.3,1);
  }
  .nav__links a:not(.btn):hover::after,
  .nav__links a:not(.btn):focus-visible::after { transform: scaleX(1); }
}
.nav__links .btn { margin-left: 6px; }
.nav__toggle {
  font: inherit;
  display: none; margin-left: auto;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line-strong); border-radius: 8px; cursor: pointer;
}
.nav__toggle span { display: block; width: 18px; height: 2px; background: var(--text); position: relative; }
.nav__toggle span::before, .nav__toggle span::after {
  content: ''; position: absolute; left: 0; width: 18px; height: 2px; background: var(--text);
}
.nav__toggle span::before { top: -6px; }
.nav__toggle span::after { top: 6px; }

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

.foot { background: var(--bg-alt); border-top: 1px solid var(--line); padding: 52px 0 28px; }
.foot__grid { display: flex; flex-wrap: wrap; gap: 28px 64px; margin-bottom: 36px; }
.foot__grid h3 { font-size: 0.875rem; margin-bottom: 10px; }
.foot__grid a { display: block; padding: 5px 0; color: var(--text); text-decoration: none; font-size: 0.9375rem; }
.foot__grid a:hover { color: var(--accent); text-decoration: underline; }
/* The fine-print row. Dropped from 0.875rem to 0.75rem on 2026-08-26 at Owen's
   request: the company disclosures are legally required rather than read, so
   they should sit below the reading sizes rather than compete with them. It is
   the smallest type on the site and the floor for it: --text-muted holds
   5.13:1 here, well past AA, and going further down starts to look like
   something being hidden.
   The line breaks are authored in the markup rather than left to wrapping,
   because the three statements are separate disclosures (trading name, place
   of registration and number, registered office) and running them together as
   one wrapped paragraph made them read as a single sentence. */
.foot__bottom {
  display: flex; flex-wrap: wrap; gap: 8px 24px; justify-content: space-between;
  padding-top: 22px; border-top: 1px solid var(--line);
  font-size: 0.75rem; line-height: 1.6; color: var(--text-muted);
}

/* Inline code. One use on the site, the localStorage key named on the privacy
   page, but an unstyled <code> falls back to the browser's monospace at a
   different optical size and reads as a mistake next to Archivo. */
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
  background: var(--bg-alt);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 1px 5px;
}

/* ---- Cookie ---------------------------------------------------------- */

.cookie-banner {
  position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 150;
  display: none; flex-wrap: wrap; gap: 12px 20px; align-items: center; justify-content: center;
  max-width: 720px; margin: 0 auto;
  padding: 16px 20px;
  background: #fff; border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow-toast);
  font-size: 0.9375rem;
}
.cookie-banner p { margin: 0; max-width: none; }
.cookie-detail {
  flex-basis: 100%; margin-top: 2px; padding: 12px 14px;
  background: var(--bg-alt); border-radius: 8px;
  font-size: 0.875rem; color: var(--text-muted);
}
.cookie-detail p + p { margin-top: 8px; }
.btn--sm { padding: 9px 16px; min-height: 40px; font-size: 0.9375rem; }

/* ---- Motion ---------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ---- Responsive ------------------------------------------------------ */

@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; row-gap: clamp(24px, 5vw, 36px); }
  .split--reverse .split__media { order: 0; }
  .cta-last { grid-column: auto; }
  .service { grid-template-columns: 1fr; gap: 4px; }
}

@media (max-width: 760px) {
  .nav__toggle { display: flex; }
  .nav__links {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: #fff; border-bottom: 1px solid var(--line);
    padding: 8px var(--gutter) 18px;
  }
  .nav__links.open { display: flex; }
  .nav__links a { padding: 13px 0; font-size: 1rem; border-radius: 0; }
  .nav__links a:hover { background: none; }
  .nav__links .btn { margin: 10px 0 0; }
  .hero h1 { max-width: none; }
}

/* ---- Doors ----------------------------------------------------------- */
/* The homepage routes rather than sells. Two ruled columns, not cards:
   the No Card rule holds here as everywhere. */

.doors {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(28px, 5vw, 64px);
  border-top: 1px solid var(--text);
  padding-top: 26px;
}
.door > p { margin-top: 14px; }
.door__list { margin: 18px 0 0; padding: 0; list-style: none; }
/* The li keeps its own padding, because the section pages use this list
   without anchors, as a plain ruled list of inclusions. */
.door__list li { padding: 9px 0; border-bottom: 1px solid var(--line); }
/* Where there is an anchor the whole row is the target, and on the homepage
   it also carries a thumbnail of the work. The negative margin pulls the
   anchor back over the li's padding so the hover tint fills the whole row
   rather than just the text. Pages without thumbnails keep the same row: the
   label grows and the chevron still sits on the right edge. */
.door__list a {
  display: flex; align-items: center; gap: 14px;
  padding: 9px 10px; margin: -9px -10px;
  border-radius: 8px;
  color: var(--text); text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.door__list a:hover { background: var(--accent-wash); color: var(--accent); }
.door__thumb {
  width: 60px; height: 45px; flex: none;
  object-fit: cover; border-radius: 8px;
  border: 1px solid var(--line); background: var(--bg-alt);
  transition: border-color .15s ease;
}
.door__list a:hover .door__thumb { border-color: var(--accent); }
.door__label { flex: 1 1 auto; min-width: 0; font-weight: 500; }


.door .cta-after { margin-top: 22px; }

/* ---- Portfolio ------------------------------------------------------- */
/* Plain images with captions. No frame, no card, no hover lift. */

.folio {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: clamp(20px, 3vw, 32px);
}
.folio figure { margin: 0; }
.folio img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--bg-alt);
}
.folio figcaption { margin-top: 9px; }
.folio strong { display: block; font-weight: 600; color: var(--text); font-size: 0.9375rem; }
.folio span { color: var(--text-muted); font-size: 0.875rem; }

/* ---- Breadcrumb ------------------------------------------------------ */

.crumb {
  font-size: 0.9375rem; color: var(--text-muted);
  margin-bottom: 16px;
}
.crumb a { color: var(--text-muted); }
.crumb a:hover { color: var(--accent); }

/* ---- Two-column prose ------------------------------------------------ */

.duo { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 56px); }
.duo h3 { margin-bottom: 12px; }

@media (max-width: 860px) {
  .doors, .duo { grid-template-columns: 1fr; }
}

/* ---- Tiers ----------------------------------------------------------- */
/* Priced levels as ruled rows. Not pricing cards. */

.tiers { border-top: 1px solid var(--text); }
.tier {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: 10px clamp(24px, 5vw, 56px);
  padding: 28px 0;
  border-bottom: 1px solid var(--line);
}
.tier__name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; }
.tier__name h3 { margin: 0; }
.tier__price {
  font-weight: 700; font-variant-numeric: tabular-nums;
  font-size: 1.15rem; letter-spacing: -0.02em;
}
.tier__level { display: block; font-size: 0.875rem; color: var(--text-muted); margin-top: 4px; width: 100%; }
.tier__body p { margin: 0 0 12px; }
.tier__modules { margin: 0; padding: 0; list-style: none; columns: 2; column-gap: 32px; }
.tier__modules li {
  position: relative; padding: 3px 0 3px 18px;
  font-size: 0.9375rem; break-inside: avoid;
}
.tier__modules li::before {
  content: ''; position: absolute; left: 0; top: 13px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
}

/* ---- Numbered phases ------------------------------------------------- */

.phases { counter-reset: phase; border-top: 1px solid var(--text); }
.phase {
  counter-increment: phase;
  display: grid; grid-template-columns: 3rem minmax(0, 1fr);
  gap: 4px clamp(16px, 3vw, 32px);
  padding: 22px 0; border-bottom: 1px solid var(--line);
}
.phase::before {
  content: counter(phase);
  font-variant-numeric: tabular-nums;
  font-weight: 700; font-size: 1.15rem; color: var(--accent);
}
.phase h3 { margin: 0; }
.phase p { margin: 4px 0 0; color: var(--text); }

@media (max-width: 760px) {
  .tier { grid-template-columns: 1fr; }
  .tier__modules { columns: 1; }
}

/* ---- Chevron -------------------------------------------------------- */
/* One authored mark at a single stroke weight, in place of the unicode
   arrow glyph the craft floor refuses. */

.chev { width: 16px; height: 16px; flex: none; color: var(--text-muted); }
a.service:hover .chev, .door__list a:hover .chev { color: var(--accent); }
a.service h3 { display: flex; align-items: center; gap: 8px; }
.door__list a { justify-content: space-between; }

/* One authored moment: the chevron steps toward the edge on hover. */
.chev { transition: transform .18s cubic-bezier(.16,1,.3,1); }
a.service:hover .chev, .door__list a:hover .chev { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) { .chev { transition: none; } }

/* ---- Door titles ----------------------------------------------------- */
/* The two families are the page's second voice, so they are set at display
   scale rather than as section headings. */

.door__title {
  font-size: clamp(2rem, 4.6vw, 3.4rem);
  letter-spacing: -0.035em;
  line-height: 1;
  margin-bottom: 14px;
}

/* ============================================================
   Homepage elevation
   ------------------------------------------------------------
   Two faults, one remedy each.

   The page sold design and showed none, so real artefacts now sit
   under the hero and against every service row.

   The accent appeared three times in an otherwise greyscale page,
   so it is promoted from button colour to structure: the rule that
   opens every block, the panel behind the case study, a full band
   under the figures, the keyline behind the portrait, and the ring
   on a focused field.
   ============================================================ */

/* Bleeding a band to 100vw overflows by the scrollbar width wherever the
   scrollbar takes layout space. `clip` contains that without turning body
   into a scroll container, which `hidden` would, and which would break the
   sticky nav. */
body { overflow-x: clip; }

/* ---- Section rule: the opening device -------------------------------- */
/* One mark, one weight, one offset, above every block. The full-width
   draw-in rule already on .doors and .services is the same idea; this is
   the version that can sit above a heading without spanning the grid. */

.srule {
  display: block; width: 56px; height: 3px;
  background: var(--accent); border-radius: 4px;
  margin: 0 0 clamp(14px, 2vw, 20px);
  transform-origin: left;
}
.section--ink .srule { background: var(--link-onink); }

/* NOTE: currently unused. The marketing section carried .section--ink for a few
   hours on 2026-08-26 and these were written for it; it is back on --bg-alt.
   Kept rather than deleted because they encode constraints that are true
   whenever these components meet a dark ground, and both are one class away
   from doing so again.
   Ruled columns on the ink ground. .svc opens on `1px solid var(--text)`,
   which is #000000 in the slate palette: invisible on a dark ground rather
   than merely quiet. The rule is the component's whole grouping device, so on
   ink it inverts to white rather than being tinted down. */
.section--ink .svc { border-top-color: #fff; }
/* The pill is a control, so its edge needs 3:1 on whatever it sits on.
   --line-onink is a divider at #2D3239 and nowhere near that, which is why
   there is a separate solved token for boundaries on ink. The container link
   rule would otherwise paint this text --link-onink; a control on a dark
   ground reads better as plain white, and it restates its own colour because
   .section--ink a is a descendant selector that outranks .pill. */
.section--ink .pill {
  border-color: var(--line-onink-strong);
  color: #fff;
}
.section--ink .pill:hover,
.section--ink .pill:focus-visible {
  background: #fff; color: var(--bg-ink); border-color: #fff;
}
.band .srule { background: rgba(255,255,255,0.65); }

@media (prefers-reduced-motion: no-preference) {
  /* scaleX(0) only ever exists inside this query, so the rule can never be
     left invisible for a reader who asked for less motion. */
  .srule {
    transform: scaleX(0);
    animation: srule-draw .7s cubic-bezier(.16,1,.3,1) both;
    animation-timeline: view();
    animation-range: entry 0% entry 55%;
  }
}
@keyframes srule-draw { to { transform: scaleX(1); } }

/* ---- Proof strip ----------------------------------------------------- */
/* Six real artefacts inside the first screen. The homepage routes rather
   than sells, so each tile is a route: the work is the door handle. */

.proof { margin-top: clamp(40px, 6vw, 76px); }
.proof__grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px; background: var(--line);      /* the gap is the hairline */
  border-block: 1px solid var(--line);
}
a.proof__item {
  display: block; background: var(--bg);
  padding-bottom: 14px;
  color: inherit; text-decoration: none;
  transition: background-color .18s ease;
}
a.proof__item:hover { background: var(--accent-wash); }
a.proof__item:focus-visible { outline-offset: -3px; }
.proof__shot { display: block; overflow: hidden; }
.proof__shot img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
a.proof__item:hover .proof__shot img { transform: scale(1.045); }
/* Caption system, identical to .folio: name at the label step, discipline
   at the caption step. Captions read the same everywhere on the site. */
.proof__cap { display: block; padding: 11px 12px 0; }
.proof__cap strong {
  display: block; font-weight: 600; font-size: 0.9375rem;
  letter-spacing: -0.012em; color: var(--text);
  transition: color .15s ease;
}
.proof__cap span { display: block; font-size: 0.875rem; color: var(--text-muted); }
a.proof__item:hover .proof__cap strong { color: var(--accent); }

@media (max-width: 1000px) { .proof__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .proof__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---- Shot ------------------------------------------------------------ */
/* One frame for a supplied image of the work, whatever register it arrives
   in. It carried drawn browser chrome until 2026-08-25, when a photographed
   laptop mockup replaced the placeholder: chrome around a photograph of a
   screen frames the frame twice, so the chrome went.
   The border and shadow went on 2026-08-26 for the same reason one step
   further out. A photograph defines its own edges; a hairline and a drop
   shadow around one are chrome pretending to be a device. Radius only, so the
   corners agree with everything else on the page. */

.shot { border-radius: 14px; overflow: hidden; }
.shot img { width: 100%; display: block; }

/* ---- Showcase -------------------------------------------------------- */
/* The case-study media: one photograph with a device shot overlapping its
   lower right. Both halves of the argument in one picture.
   Rebuilt 2026-08-26 after Owen called it naff, and he was right. It had
   become three nested rectangles: a tinted panel, holding a bordered card,
   holding a photograph that contains its own room. The aside was a fourth,
   66% wide and holding an image that was itself mostly empty studio grey, so
   the largest object in the composition was a box of nothing.
   Fixes, in order of how much they mattered: the phone image was cropped from
   720x540 to 480x440 so the device fills its frame; the aside came down to
   44% so it reads as an inset rather than a second panel; the panel tint,
   padding and both borders went. What is left is a photograph and a device,
   which is what the section was always meant to be. */

.showcase__panel { grid-column: 1 / -1; border-radius: 14px; overflow: hidden; }
.showcase__aside {
  grid-column: 1;
  margin: 0;
  border-radius: 12px;
  overflow: hidden;
}
.showcase__aside img { width: 100%; display: block; }
/* The caption is a direct child of .spot__media. The old `.showcase figcaption`
   selector matched nothing at all, which is why its margin never did anything. */
.spot__media > figcaption { grid-column: 2; align-self: end; margin-top: 0; }

/* ---- Figures band ---------------------------------------------------- */
/* The strongest content on the page was set like a row in a report. It is
   now the page's one colour-blocked moment, and the rhythm change that the
   scroll was missing. White on this accent measures 5.38:1. */

.band {
  background: var(--accent); color: #fff;
  padding: clamp(52px, 7vw, 88px) 0;
}
.band__who {
  margin: 0 0 clamp(26px, 3.6vw, 40px); max-width: none;
  font-size: 1rem; font-weight: 600; color: #fff;
}
.figures {
  margin: 0; display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(22px, 4vw, 48px);
}
.figures > div {
  display: flex; flex-direction: column;
  border-top: 1px solid rgba(255,255,255,0.4);
  padding-top: 16px;
}
/* The numeral leads and the label explains it, which is the reverse of the
   dl source order the markup has to keep. */
.figures dd {
  order: -1; margin: 0;
  font-size: clamp(3.2rem, 8vw, 6rem);
  font-weight: 700; line-height: 0.9; letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums lining-nums;
  color: #fff;
}
.figures dt {
  margin-top: 12px; max-width: 22ch;
  font-size: 0.9375rem; font-weight: 500; color: #fff;
}
@media (max-width: 620px) { .figures { grid-template-columns: 1fr; } }

/* ---- Offset keyline -------------------------------------------------- */
/* The portrait sat on the dark ground as a default rounded card. An accent
   block behind it makes the frame deliberate. */

/* The block is positioned against the image, not the figure: anchoring it to
   the figure put it over the figcaption. */
.frame-offset__media { position: relative; display: block; }
.frame-offset__media::before {
  content: ''; position: absolute; z-index: 0;
  left: -18px; bottom: -14px; width: 55%; height: 62%;
  background: var(--accent); border-radius: 10px;
}
.frame-offset__media img { position: relative; z-index: 1; }
/* Clears the 14px the block hangs below the image. */
.frame-offset figcaption { position: relative; z-index: 2; margin-top: 26px; }
@media (max-width: 480px) { .frame-offset__media::before { left: -10px; bottom: -10px; } }

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

.foot__brand { display: inline-block; margin-bottom: 30px; }
/* These two rules hid the mark and its rule on the homepage, because the page
   used to sign off with a full-width wordmark immediately above the footer and
   the small mark was the same thing said twice. **That wordmark was pulled
   back and these were left behind**, so the homepage became the only page with
   no logo in its footer, for a reason that no longer existed. Removed
   2026-08-26. The footer now renders identically on all nineteen pages, not
   just in markup.
   .home .foot__brand { display: none; }
   .home .foot__grid  { border-top: 0; padding-top: 0; } */
.foot__brand img { width: 118px; }
.foot__grid { border-top: 1px solid var(--line); padding-top: 30px; }

/* ---- Hero settle ----------------------------------------------------- */
/* The headline is deliberately not animated: it is the largest paint on the
   page and holding it back to fade it in would cost the metric that matters.
   The supporting content settles in beneath it instead. 580ms, once. */

@media (prefers-reduced-motion: no-preference) {
  .hero__body { animation: hero-rise .42s cubic-bezier(.16,1,.3,1) .07s both; }
  .hero .proof { animation: hero-rise .42s cubic-bezier(.16,1,.3,1) .16s both; }
}
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

/* ---- The one authored moment ---------------------------------------- */
/* Rules draw themselves in as each block arrives. Content is visible by
   default; only the rule animates, so nothing is hidden if this never runs. */

@media (prefers-reduced-motion: no-preference) {
  /* .doors dropped from this list: each door now opens with its own .srule,
     and a full-width accent line 26px above two short accent stubs was the
     same mark said twice. */
  .evidence, .services, .tiers, .post-list, .phases {
    position: relative;
  }
  .evidence::before, .services::before,
  .tiers::before, .post-list::before, .phases::before {
    content: '';
    position: absolute; top: -1px; left: 0; right: 0; height: 1px;
    background: var(--accent);
    transform: scaleX(0); transform-origin: left;
    animation: rule-draw .9s cubic-bezier(.16,1,.3,1) both;
    animation-timeline: view();
    animation-range: entry 0% entry 60%;
  }
  @keyframes rule-draw { to { transform: scaleX(1); } }
}


/* ============================================================
   Homepage, rebuilt 2026-08-16
   ------------------------------------------------------------
   Structure taken from a reference the user supplied: a flat
   colour lede with the name at poster scale, a client band, a
   featured case study, two service grids either side of a full
   statement, an about, a work grid, a disclosure list beside a
   quote, contact, and the name again at the foot.

   The idiom is Quietwork's, not the reference's. The reference
   is card-heavy; the No Card Rule holds here, so every grid is
   a set of ruled columns or unframed images with captions.

   Everything is scoped to .home or uses a class that exists
   nowhere else, so the other seventeen pages are untouched.
   ============================================================ */

.eyebrow {
  margin: 0 0 10px; max-width: none;
  font-size: 0.875rem; font-weight: 600; color: var(--text-muted);
}

/* ---- 1. Lede --------------------------------------------------------- */
/* The one colour-blocked ground on the page, and the page's loudest
   moment. White on this accent measures 5.38:1, so every weight here is
   pure white rather than a tinted white. */

.lede {
  background: var(--accent); color: #fff;
  padding: clamp(28px, 4vw, 56px) 0 clamp(24px, 3vw, 40px);
  /* Fills the first screen. 68px is the sticky nav, which sits above this in
     flow, so subtracting it stops the two together exceeding the viewport.
     svh not vh: on mobile vh is the largest viewport and overshoots. */
  min-height: calc(100svh - 90px);   /* nav is taller now */
  /* Eyebrow pinned top, wordmark pushed low. space-between spread the three
     parts evenly and left the mark floating mid-screen; an auto top margin on
     the mark absorbs the free space above it instead, so it sits just clear of
     the rule. */
  display: flex; flex-direction: column; justify-content: flex-start;
  /* Contain the wordmark's bleed here rather than leaning on body's
     overflow-x: clip. Local containment keeps document scrollWidth honest,
     which matters because other things measure against it. */
  overflow: clip;
}
/* Cursor-reactive ground, 2026-08-26. The whole block is ONE FLAT COLOUR that
   changes as the pointer moves: x travels between two palette colours, y pulls
   the result toward a third.
   It was a radial gradient centred on the cursor until Owen saw it: "more of a
   gradient, almost like a gradient attached to the cursor. It doesn't look
   right at all." He was right. A gradient that tracks the pointer reads as a
   torch being shone on the page, and it draws attention to the mechanism
   instead of the colour. A flat field changing as a whole reads as the page
   responding. **Do not reintroduce a gradient here.**
   Only background-color is set, so there is nothing to composite and the
   change is a single paint.
   Applied only once main.js attaches (.lede--live): with no pointer there is
   nothing to respond to, so no-JS, coarse pointers and prefers-reduced-motion
   keep the flat accent they have now. */
.lede--live {
  background-color: var(--lede-base, var(--accent));
}
.lede__eyebrow {
  margin: 0; max-width: none;
  font-size: 0.875rem; font-weight: 600; color: var(--lede-fg, #fff);
}
/* The name at poster scale. vw-driven so it reaches both gutters at every
   width, which is the whole point of setting it this big. */
/* The drawn mark, not the name typeset. brand-rules.md: "Always use the
   Quietwork SVG logo. Never typeset the name." It also settles the kerning
   permanently, because the letterfitting is in the artwork. */
/* Typeset, not the SVG. brand-rules.md said never typeset the name; that was
   reversed on 2026-08-26 at the user's direction for this one display use.
   The nav and footer still use the drawn mark.
   Kerning is asked for explicitly: browsers drop optional pairs at large sizes
   in some engines, and the letterfitting is the whole reason the SVG was used
   here before. */
.lede__mark {
  margin: clamp(10px, 1.4vw, 18px) 0 0;
  max-width: none;
  /* text-align: center does not split overflow: when inline content is wider
     than its block, the excess all goes to the end side, which put 211px off
     the right edge and nothing off the left. Sizing the element to its own
     content and centring it as a flex item overflows both sides equally. */
  align-self: center;
  width: max-content;
  margin-top: auto;
  /* Taller by condensing, not by a second typeface. Archivo is variable on a
     width axis, so narrowing to 74% lets the size rise at the same rendered
     width. Measured: the glyph run is 5.941x the font size at 100% width and
     4.552x at 74%. Caps end up about a third taller.
     Pulled back from 25.4vw to 24vw on 2026-08-25 at the user's request. At
     1440 that takes the rendered run from 1665px to 1573px, so the bleed goes
     from ~112px each side to ~66px. It still bleeds on purpose: the honest
     choices are a confident overhang or a clean fit inside the gutters, and
     the state to avoid is "almost fits", which reads as a mistake rather than
     a decision. Below roughly 21.7vw the word fits the viewport and the whole
     device is gone, so that is the floor for any further trim. */
  font-stretch: 74%;
  font-size: 24vw;
  padding-inline: 0;
  white-space: nowrap;
  font-weight: 700;
  line-height: 0.78;
  letter-spacing: -0.055em;
  text-transform: uppercase;
  color: var(--lede-fg, #fff);
  font-kerning: normal;
  font-feature-settings: "kern" 1;
  text-rendering: optimizeLegibility;
}
.lede__foot {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 64px);
  margin-top: clamp(14px, 1.8vw, 26px);
  padding-top: clamp(20px, 2.6vw, 30px);
  border-top: 1px solid currentColor;
  align-items: start;
}
/* Authored line breaks, 2026-08-25. At this size the breaks are a design
   decision rather than something to delegate to the wrapping algorithm, so
   the measure is released and the <br>s govern. That is the same call the
   poster type makes.
   The step came down from 4.6vw because of the third line: "Without the
   headcount." measures 672px at 4.6vw against a 654px column at 1440, so it
   wrapped and the authored three lines became four. 4.4vw brings it to 643px
   and leaves 11px. Both the size and the column are vw-driven, so the ratio
   holds as the viewport changes; it is only the fixed clamp floor that breaks
   it, which is what the narrow-width rule below is for. */
.lede__say {
  margin: 0; max-width: none;
  font-size: clamp(1.85rem, 4.4vw, 4.2rem);
  font-weight: 700; line-height: 0.98; letter-spacing: -0.042em;
  color: var(--lede-fg, #fff);
}
/* The foot held two columns at every width, which nobody chose: it is a
   consequence of there never having been a breakpoint. At 560px that left the
   h1 a 250px column and the paragraph 230px, and the longest authored line
   needs ~325px once the clamp floor binds. Measured, the two-column foot stops
   being able to hold that line at about 680px, so it stacks at 760px and the
   h1 takes the full measure. */
@media (max-width: 760px) {
  .lede__foot { grid-template-columns: minmax(0, 1fr); }
}
/* The floor came down from 2rem to 1.85rem for the same line. At 2rem it
   needed 325px against the 323px column a 375px phone gives, so it wrapped to
   four lines by two pixels. Natural wrapping is not an acceptable fallback
   here: it breaks as "Your in-house digital / team. Without the / headcount.",
   which cuts the sense in the wrong places. 1.85rem brings it to 301px.
   Narrower than the rule below, even that overflows, so the breaks go and a
   measure comes back. */
@media (max-width: 340px) {
  .lede__say br { display: none; }
  .lede__say { max-width: 15ch; }
}
.lede__foot p { color: var(--lede-fg, #fff); max-width: 42ch; }
.lede .btn-row { margin-top: 22px; }

.btn--onaccent { background: #fff; color: var(--accent); border-color: #fff; }
.btn--onaccent:hover { background: var(--onaccent-hover); border-color: var(--onaccent-hover); color: var(--accent); }
.btn--ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,0.6); }
.btn--ghost:hover { background: transparent; color: #fff; border-color: #fff; }
/* Container link rules outrank the plain modifiers, as they did for the nav
   CTA. Both restate their own colour. */
/* The hero's own controls follow the ground, because the ground can now be a
   light colour. The solid button fills with the foreground and takes the
   ground colour as its label, so it inverts correctly whichever way round the
   hero is. The ghost draws itself in the foreground colour at 60%. */
.lede a.btn--onaccent {
  background: var(--lede-fg, #fff); border-color: var(--lede-fg, #fff);
  color: var(--lede-base, var(--accent));
}
.lede a.btn--onaccent:hover {
  background: var(--lede-fg, #fff); border-color: var(--lede-fg, #fff);
  color: var(--lede-base, var(--accent)); opacity: 0.86;
}
.lede a.btn--ghost { color: var(--lede-fg, #fff); border-color: color-mix(in srgb, var(--lede-fg, #fff) 60%, transparent); }
.lede a.btn--ghost:hover { color: var(--lede-fg, #fff); border-color: var(--lede-fg, #fff); }

/* ---- 2. Client band -------------------------------------------------- */

.clients {
  background: var(--bg-alt);
  /* The label sits above the row, so symmetric padding does NOT centre the
     marks: measured at 1440 they had 73px above and 35px below and read as
     sitting low in the band. The bottom pad carries the label's block as well,
     which puts equal air above and below the marks themselves. */
  --band-pad: clamp(22px, 2.6vw, 34px);
  --label-block: calc(1.3125rem + clamp(14px, 1.6vw, 18px));
  padding: var(--band-pad) 0 calc(var(--band-pad) + var(--label-block));
  border-block: 1px solid var(--line);
}
.clients h2 { margin-bottom: clamp(14px, 1.6vw, 18px); color: var(--text-muted); }
.clients__row {
  /* Equal columns, not a flex row, 2026-08-26 at Owen's request. A wrapping
     flex row left-aligns whatever it holds, which is why the wall sat in the
     left three-quarters with a hole on the right. Nine equal tracks put the
     same slot under every mark and fill the measure, so the spacing is even by
     construction rather than by picking gap values. */
  display: grid;
  grid-template-columns: repeat(9, minmax(0, 1fr));
  align-items: center;
  gap: clamp(18px, 2vw, 28px);
  margin: 0; padding: 0; list-style: none;
}
.clients__row li { display: flex; align-items: center; justify-content: center; min-width: 0; }
/* The marks are pre-rendered to #1A1A1A with a real alpha channel, so they need
   no blend mode and sit on any ground. */
/* Equal INK, not equal height. A flat 36px was tried first and read as uneven,
   and the reason is measurable: at one height these nine marks put between 205
   and 1492 square pixels of ink on screen, a 7.3x spread, because coverage runs
   from 13% (Perfect Plant, fine serif) to 47% (RNBW, solid box).
   So each height is solved rather than eyeballed: h = 36 * (median/ink)^0.30,
   where ink is the alpha-weighted area measured off the actual file. The 0.30
   exponent damps it; full area equalisation (0.50) over-corrects and blows the
   delicate marks up to 61px. Landing at 27-49px, which is close to the 24-40px
   the old hand-tuned optical values reached, so this mostly derives what a
   designer's eye had already found.
   ⚠️ Re-solve these if a mark is added, replaced or re-exported. They are a
   function of each file's ink, not arbitrary numbers, and a new mark dropped in
   at someone else's value will be the one that looks wrong. */
.clients__row img { width: auto; max-width: 100%; opacity: 0.85; }
.clients__row li:nth-child(1) img { height: 31px; }  /* Anglesey CC,   24% cover */
.clients__row li:nth-child(2) img { height: 29px; }  /* RTA,           43% */
.clients__row li:nth-child(3) img { height: 27px; }  /* RNBW,          47% */
.clients__row li:nth-child(4) img { height: 36px; }  /* Anglesey Adv,  37% */
.clients__row li:nth-child(5) img { height: 38px; }  /* JT Thomas,     20% */
.clients__row li:nth-child(6) img { height: 46px; }  /* Perfect Plant, 13% */
.clients__row li:nth-child(7) img { height: 49px; }  /* Cadwyn Mon,    14% */
.clients__row li:nth-child(8) img { height: 46px; }  /* Bryngwran,     21% */
.clients__row li:nth-child(9) img { height: 36px; }  /* Sea Kayaking,  44% */

@media (max-width: 1100px) {
  .clients__row { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  .clients__row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Nine marks divide evenly into three rows here. The solved heights are
     scaled by 0.78 rather than flattened, so the ink balance survives; a flat
     phone height would reintroduce the 7.3x spread the desktop values fix. */
  .clients__row li:nth-child(1) img { height: 24px; }
  .clients__row li:nth-child(2) img { height: 23px; }
  .clients__row li:nth-child(3) img { height: 21px; }
  .clients__row li:nth-child(4) img { height: 28px; }
  .clients__row li:nth-child(5) img { height: 30px; }
  .clients__row li:nth-child(6) img { height: 36px; }
  .clients__row li:nth-child(7) img { height: 38px; }
  .clients__row li:nth-child(8) img { height: 36px; }
  .clients__row li:nth-child(9) img { height: 28px; }
}

/* ---- 3. Featured work ------------------------------------------------ */

/* rem, not ch: a ch on the container resolves against the container's own
   font size, which crushed these heads to a fifth of their width. */
.spot__head { max-width: 44rem; margin-bottom: clamp(28px, 4vw, 48px); }
.spot__grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(28px, 5vw, 72px); align-items: start;
}
.spot__text p { max-width: 46ch; }
/* Two artefacts side by side in the reading order, not one stuck on top of
   the other. The inset overlapped the laptop by 45% of its height, which put
   it across the website's own headline: the copy claims the line on the
   brochure cover is the line on the website, and the composition was covering
   half the proof. It also needed a thick ground-coloured ring to stop two dark
   photographs merging, and a 14px white ring around a photo is a sticker.
   Nothing overlaps now, so nothing needs a ring, and the caption occupies the
   space beside the brochure rather than sitting under a hole. */
.spot__media {
  margin: 0;
  display: grid;
  grid-template-columns: 50% minmax(0, 1fr);
  column-gap: clamp(16px, 2.4vw, 28px);
  row-gap: clamp(14px, 2vw, 22px);
}

/* The figures sit at reading scale on a light ground here, ruled rather
   than banded: the lede already spends the page's colour budget. */
.figures--light { margin-top: clamp(36px, 5vw, 64px); }
.figures--light > div { border-top-color: var(--text); }
.figures--light dd { color: var(--text); }
.figures--light dt { color: var(--text-muted); font-weight: 400; }

/* ---- 4 and 6. Service grids ------------------------------------------ */

.svc__head { max-width: 46rem; margin-bottom: clamp(30px, 4vw, 52px); }
.svc__head .lead { margin-top: 16px; max-width: 46ch; }
.svc {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0 clamp(20px, 3vw, 40px);
  border-top: 1px solid var(--text);
}
/* Ruled columns, not boxes. The rule above and the space between are the
   only grouping devices. */
.svc__item {
  display: flex; flex-direction: column; align-items: start;
  padding: 26px 0 30px;
}
/* The reference sets its service titles at display scale, not label scale.
   Mine were at the title step (18px) and read as a contents list beside it.
   Weight stays 600 rather than 700: at this size bold reads as shouting. */
.svc__item h3 {
  margin: 0 0 16px;
  font-size: clamp(1.45rem, 2.5vw, 2.5rem);
  font-weight: 600;
  line-height: 1.0;
  letter-spacing: -0.032em;
  max-width: 12ch;
}
/* Denser than the site default: at this scale 1.65 leading opens the column
   up so far the card stops reading as one object. */
.svc__item p { color: var(--text); max-width: 30ch; line-height: 1.45; }
/* Same specificity as .section--ink p (0,1,1) and declared later, so on a dark
   ground the rule above silently won and painted this copy --text, which is
   #000000 in the slate palette: 1.18:1 on the ink. That is the mixed
   white-and-dark reading Owen spotted, and the reason a component must restate
   its own colour on ink rather than trusting the section to cascade in. */
.section--ink .svc__item p { color: var(--text-onink-muted); }
.svc__item .pill { margin-top: auto; }

.pill {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px; padding: 8px 16px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-stadium);
  color: var(--text); text-decoration: none;
  font-size: 0.9375rem; font-weight: 500;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.pill:hover, .pill:focus-visible { background: var(--text); color: #fff; border-color: var(--text); }
.pill:hover .chev { color: #fff; transform: translateX(4px); }

/* Design carries three items, not four, since slideware moved to marketing. */
.svc--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 1000px) { .svc, .svc--three { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .svc, .svc--three { grid-template-columns: 1fr; } .svc__item { border-bottom: 1px solid var(--line); } }

/* ---- 5. Statement ---------------------------------------------------- */

.say { padding: clamp(72px, 11vw, 168px) 0; }
/* The page's one dark ground, and its loudest moment. It was 4.5rem on white
   and vanished into twelve sections of near-white either side of it. */
/* Specificity: the statement-heading rule is .home main h2:not(.h-sm):not(.door__title),
   which outranks a plain .home .say h2 and was pinning the measure to 16ch.
   Matched here rather than fought with !important. This is the trap DESIGN.md
   names, caught for the fourth time. */
.home .say h2:not(.h-sm):not(.door__title) {
  font-size: clamp(2.3rem, 7.6vw, 7.2rem);
  line-height: 0.94;
  letter-spacing: -0.048em;
  max-width: 26ch;
  color: #fff;
}
/* Inherits headline-home. Only the measure differs: a full statement wants
   a wider one than a section heading. */
.say h2 { max-width: 22ch; }

/* ---- 7. About -------------------------------------------------------- */

.about {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 72px); align-items: center;
}
.about__media { margin: 0; }
.about__media img { border-radius: var(--radius); border: 1px solid var(--line); }
/* The video takes the same treatment the photograph had, so swapping the
   medium did not change the composition. Its own 720x876 aspect is declared
   rather than cropped: the subject is off-centre in frame and a 4:3 crop cut
   the screens he is presenting to, which are half the point of the shot. The
   poster is 621x720, a slightly wider ratio, so object-fit stops it stretching
   in the moment before the first frame arrives. */
.about__media video {
  display: block; width: 100%; height: auto;
  aspect-ratio: 720 / 876; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--bg-alt);
}
.about__media figcaption { margin-top: 12px; }
/* Sits with the caption rather than floating over the picture, which is where
   a play control usually goes and where it covers the thing it controls. */
.video__toggle {
  display: inline-block; margin-left: 10px; vertical-align: baseline;
  font: inherit; font-size: 0.8125rem; font-weight: 500;
  color: var(--text-muted); background: none;
  border: 1px solid var(--line-strong); border-radius: 8px;
  padding: 3px 10px; cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.video__toggle:hover { color: var(--text); border-color: var(--text); }
.video__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---- 8. Work grid ---------------------------------------------------- */
/* The Unframed Portfolio Rule: a plain image with a caption below it. */

.work {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 40px) clamp(20px, 2.6vw, 34px);
}
a.work__item { display: block; color: inherit; text-decoration: none; }
/* One treatment for every tile. The grid mixes photographic mockups, flat
   screenshots and a bare logo on near-white; without a ground and a hairline
   the logo tile floated while the photographs read as bounded. */
.work__shot {
  display: block; overflow: hidden;
  border-radius: var(--radius);
  background: var(--tile);
  border: 1px solid var(--line);
}
.work__shot img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  background: var(--tile);
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
a.work__item:hover .work__shot img { transform: scale(1.04); }
.work__cap { display: block; margin-top: 12px; }
.work__cap strong {
  display: block; font-weight: 600; font-size: 0.9375rem;
  letter-spacing: -0.012em; color: var(--text); transition: color .15s ease;
}
.work__cap span { display: block; font-size: 0.875rem; color: var(--text-muted); }
a.work__item:hover .work__cap strong { color: var(--accent); }

@media (max-width: 900px) { .work { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .work { grid-template-columns: 1fr; } }

/* ---- 9. Disclosure list and quote ------------------------------------ */

.caps {
  display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: clamp(28px, 5vw, 72px); align-items: start;
}
.caps__list { margin-top: 22px; border-top: 1px solid var(--text); }
.caps__list details { border-bottom: 1px solid var(--line); }
.caps__list summary {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 18px 0; cursor: pointer;
  font-weight: 600; font-size: 1.0625rem; letter-spacing: -0.012em;
  list-style: none;
  transition: color .15s ease;
}
.caps__list summary::-webkit-details-marker { display: none; }
.caps__list summary:hover { color: var(--accent); }
.caps__list summary:hover .chev { color: var(--accent); }
.caps__list summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.caps__list .chev { transition: transform .18s cubic-bezier(.16,1,.3,1), color .15s ease; }
.caps__list details[open] summary .chev { transform: rotate(180deg); }
.caps__list details p { margin: 0 0 20px; max-width: 52ch; color: var(--text); }

/* A pull quote in the second column, NOT a card. The bordered box read as a
   testimonial widget bolted onto the page, and boxing a 16ch measure at this
   size left a nine-word rag. The site has one quote primitive (accent rule on
   the left) and this is it, given the column's full measure. */
.quote--panel {
  margin: 0;
  padding: 0 0 0 clamp(18px, 2.2vw, 26px);
}
.quote--panel p { max-width: none; }
.quote--panel footer { max-width: none; }

@media (max-width: 860px) { .caps, .about, .spot__grid { grid-template-columns: 1fr; } }

/* ---- Second proof ----------------------------------------------------- */
/* A lighter companion to the featured case study: text-led, one photograph,
   media on the opposite side so the two proofs do not read as a pair of
   identical slabs. Built from .spot__grid, .srule, .eyebrow and .pill. */

.spot__grid--flip { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
.proof2__media { margin: 0; }
.proof2__media img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--tile);
}
.proof2__media figcaption { margin-top: 12px; }
@media (max-width: 860px) {
  .spot__grid--flip { grid-template-columns: 1fr; }
  .proof2__media { order: 2; }
}


/* ---- Homepage copy density -------------------------------------------- */
/* Nearer the reference's 20px/1.3 without going the whole way, which at this
   measure would start to feel cramped. */
.home .spot__text p,
.home .proof2 p,
.home .about__text p { font-size: 1.15rem; line-height: 1.5; }
.home .svc__head .lead,
.home .spot__head + * { font-size: clamp(1.1rem, 1.9vw, 1.3rem); }


/* ---- Warm band -------------------------------------------------------- */
/* The Y Bark figures had their own colour band before the rebuild and lost it,
   which left the page's best proof set as small text in a white section. This
   restores the moment and gives the long white stretch a third colour block.
   Ink on amber, never white: white measures 2.16:1 here and would fail. */

.band--warm { background: var(--accent-2); color: var(--text); }
.band--warm .band__who { color: var(--text); }
.band--warm .srule { background: var(--text); }
.band--warm .figures > div { border-top-color: rgba(26,26,26,0.32); }
.band--warm .figures dd { color: var(--text); }
.band--warm .figures dt { color: var(--text); font-weight: 500; }


/* ---- Coloured emphasis ------------------------------------------------ */
/* A second emphasis device alongside the serif italic. The italic changes the
   voice; colour changes the volume. Display headings only, never body copy,
   and at most one run per heading. */

.hi { color: var(--accent); }
/* On the ink ground the accent drops to 3.0:1, which is fine for display type
   at these sizes but not for anything smaller, so the lifted tint is used. */
.section--ink .hi, .say .hi { color: var(--link-onink); }
/* On the indigo lede, colour cannot be the device at all: amber measures
   2.49:1 there and the lighter tints only reach 3.6:1, which is too close to
   the floor for the largest text on the site. The serif italic already carries
   the emphasis, so .hi simply stands down. */
.lede .hi { color: inherit; }

/* Leading tight enough that the lines almost touch, which is most of why the
   reference reads as a block of type rather than a paragraph. */
.home .say h2:not(.h-sm):not(.door__title) { line-height: 0.86; }

/* ============================================================
   Maximal pass, 2026-08-25
   Pushed to the reference's level of scale and device density so
   there is a ceiling to edit back from. Snapshot of the previous
   state is in backup/2026-08-25-pre-max/.
   ============================================================ */

/* ---- Mega statement ---------------------------------------------------- */
/* Four lines since 2026-08-26, not three: "decks" left the remit list and
   "the collateral" is wider, so "the collateral, the website" no longer fits
   one line at any sane size. The step went UP rather than the copy being
   trimmed to fit. At three lines the longest line filled 98% of the measure;
   the four-line break dropped that to 79%, which read as the statement having
   shrunk. Measured, not guessed: longest line now 1340px in a 1360px wrap.
   ⚠️ MUST carry :not(.h-sm):not(.door__title). Without them this selector is
   (0,3,1) and loses to .home .say h2:not(.h-sm):not(.door__title) at (0,4,1),
   which is what set the size instead. The whole .mega block was inert from the
   day it was written: its declared 11.4vw never rendered, the statement was
   actually running at that rule's 7.6vw, and changing the .mega value moved
   nothing on screen. Fifth recurrence of the specificity trap on this project,
   and the first where the dead rule was mistaken for the live one. */
.home .say h2.mega:not(.h-sm):not(.door__title) {
  max-width: none;
  font-size: clamp(2.7rem, 8.8vw, 8.4rem);
  line-height: 0.82;
  letter-spacing: -0.05em;
  text-transform: uppercase;
  font-weight: 700;
  color: #fff;
}

/* ---- Interleave -------------------------------------------------------- */
/* A line of type, an image slotted into the next line's space, then the
   closing line. The image is a participant in the typesetting, not an
   illustration beside it. */
.interleave { padding: clamp(56px, 8vw, 120px) 0; background: var(--bg); }
.interleave p {
  margin: 0; max-width: none;
  font-size: clamp(3rem, 13vw, 12.5rem);
  line-height: 0.82;
  letter-spacing: -0.055em;
  text-transform: uppercase;
  font-weight: 700;
}
.interleave__row {
  display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1fr);
  gap: clamp(20px, 4vw, 56px);
  align-items: center;
}
.interleave__shot { margin: 0; }
.interleave__shot img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius);
}
.interleave__b { text-align: left; }

/* The grounding line under the statement. Three words at 12.5rem announce a
   position without saying what it means in practice, which is what makes the
   block read as a slogan; this is the sentence that cashes it.
   It also carries the product name, because a caption under the image broke
   the interlock: the whole device is OVER sitting in the line beside the shot
   and OPINION closing directly beneath it, and a line of 14px type wedged in
   between pushed the last word away and cut the type sandwich in half.
   NOTE THE SELECTOR. `.interleave p` is (0,1,1), so a bare `.interleave__note`
   at (0,1,0) would lose and this paragraph would render at 12.5rem uppercase.
   Sixth time this trap has been hit in this stylesheet: a component restates
   its own size, and it has to outrank the descendant rule to do it. */
.interleave p.interleave__note {
  max-width: 46ch;
  margin-top: clamp(28px, 3.6vw, 48px);
  font-size: clamp(1.1rem, 1.9vw, 1.3rem);   /* the lead step */
  line-height: 1.55;
  letter-spacing: normal;
  text-transform: none;
  font-weight: 400;
  color: var(--text-muted);
}

@media (max-width: 760px) {
  .interleave__row { grid-template-columns: 1fr; }
}

/* ---- Work rail --------------------------------------------------------- */
/* Horizontal scroll with snap, instead of a static grid.
   The tile width is the affordance. It was 400px, and 3 tiles plus 2 gaps came
   to 1268 in a 1280 rail: the fourth was entirely offscreen and the rail read
   as a finished three-up grid, which is exactly why nobody would think to
   scroll it. At 348px a tile is always part-visible at the right edge, and a
   cut-off tile is the only scroll cue that needs no explaining. Because the
   width is in vw and the rail tracks the viewport, that ratio holds at every
   size rather than only at this one. */
.work--rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(clamp(240px, 25vw, 348px), 1fr);
  grid-template-columns: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  padding-bottom: 18px;
  scrollbar-width: thin;
}
.work--rail > * { scroll-snap-align: start; }
@media (max-width: 900px) { .work--rail { grid-template-columns: none; } }

/* Snap and a script driving scrollLeft fight each other: mandatory snap drags
   the rail back to the nearest tile on every frame. main.js adds this class
   while the rail is moving on its own and removes it the moment a person takes
   over, so snap is there for the hand and absent for the animation. */
.work--rail.is-auto { scroll-snap-type: none; }

/* The second cue: the row visibly continues past its edge. Masked rather than
   overlaid with a gradient, because the section ground changes between pages
   and a hard-coded white fade would show as a band on any other ground.
   The classes are toggled from scroll position, so the fade appears only on
   the side that has more to show and never lies about content that is not
   there. */
.work--rail { --fade: 64px; }
.work--rail.has-next {
  mask-image: linear-gradient(to right, #000 0, #000 calc(100% - var(--fade)), transparent 100%);
}
.work--rail.has-prev {
  mask-image: linear-gradient(to right, transparent 0, #000 var(--fade), #000 100%);
}
.work--rail.has-prev.has-next {
  mask-image: linear-gradient(to right, transparent 0, #000 var(--fade), #000 calc(100% - var(--fade)), transparent 100%);
}

/* The pause control sits with the section's existing button rather than
   floating over the rail, where it would cover the work. */
.cta-after--rail { display: flex; align-items: center; gap: clamp(12px, 1.6vw, 20px); flex-wrap: wrap; }
.rail__toggle {
  font: inherit; font-size: 0.875rem; font-weight: 500;
  color: var(--text-muted);
  background: none;
  /* Boundary Grey, not the hairline: this is a control edge and the hairline
     cannot legally bound one. */
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  padding: 7px 14px;
  cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.rail__toggle:hover { color: var(--text); border-color: var(--text); }
.rail__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ---- Say hello --------------------------------------------------------- */
/* The sign-off band, 2026-08-26: pink ground, dark type. It was ink with white
   type and a blue highlight, and neither survives on the pink: white measures
   2.92:1 there and the brand blue 1.75:1. So the whole band inverts. The
   highlight is pure black rather than a colour, because every colour in the
   palette is too close to the pink in luminance to read as emphasis on it. */
.sayhello { background: var(--signoff-bg); color: var(--signoff-fg); padding: clamp(56px, 8vw, 112px) 0 clamp(40px, 5vw, 72px); }
.sayhello .hi { color: var(--signoff-hi); }
.sayhello__big {
  margin: 0; max-width: none;
  /* Same poster step as .interleave p. */
  font-size: clamp(3rem, 13vw, 12.5rem);
  line-height: 0.82; letter-spacing: -0.055em; font-weight: 700;
  color: var(--signoff-fg);
}
.sayhello__meta { margin: clamp(20px, 3vw, 34px) 0 0; max-width: none; color: var(--signoff-fg); font-size: 1.0625rem; }
.sayhello__meta a { color: var(--signoff-fg); }


/* ---- Wordmark pair kerning -------------------------------------------- */
/* Measured, not guessed. Optical ink gaps in QUIETWORK at -0.055em tracking
   came out: QU 16.0, UI 23.8, IE 24.8, ET 5.6, TW -5.3, WO -0.3, OR 12.7,
   RK 12.4 px. Heavy negative tracking breaks the diagonal pairs first, so TW
   and WO were colliding while the flat-stem pairs stayed open.
   Each correction is applied to the second letter of its pair. Flat-stem
   pairs are left wider than round and diagonal ones on purpose: equal ink
   gaps do not read as equal spacing. */
.lede__mark .kI { margin-left: -0.028em; }   /* UI 23.8 -> 16.7 */
.lede__mark .kE { margin-left: -0.030em; }   /* IE 24.8 -> 17.2 */
.lede__mark .kT { margin-left:  0.020em; }   /* ET  5.6 -> 10.7 */
.lede__mark .kW { margin-left:  0.055em; }   /* TW -5.3 ->  8.7 */
.lede__mark .kO { margin-left:  0.040em; }   /* WO -0.3 ->  9.9 */


/* Gap between the wordmark and the rule beneath it. Small, so the mark reads
   as sitting on the rule rather than hovering above it. */
.home .lede > .wrap:last-child { margin-top: clamp(18px, 2.4vw, 38px); }
