/* ===========================================================================
   MASLI — stylesheet. Direction: "Paper".

   Every value here is traceable to the Paper design handoff (2026-09-04) or,
   where the handoff is silent, to wiki/company/brand.md.

   This direction deliberately departs from brand.md on four rules. They are
   recorded here because a reader of this file should not have to guess which
   differences are decisions and which are drift:

     1. Ground is warm paper (#faf6ef), not the monochrome white brand.md
        calls canonical.
     2. A serif display face (Newsreader) sets every heading. brand.md fixes
        the system at Geist alone.
     3. A blinking terminal caret appears once per hero and once per closing
        band. brand.md forbids "anything that moves while the visitor is
        still" — this is the one thing on the site that does.
     4. The signal colour fills the primary button on hover. brand.md reserves
        primary fills for --ink and says the signal is "a mark, not a mood".
     5. The positioning line is set as one flowing sentence and keeps its dash,
        separated by weight and colour alone. brand.md says that at display
        size it splits into two blocks and the dash comes out.

   Until brand.md is reconciled with this direction, that page and this file
   disagree on those four points and agree everywhere else.

   Structure:
     1. Typeface  — Geist / Geist Mono / Newsreader, self-hosted
     2. Tokens    — colour, space, radius, motion
     3. Base      — reset, document, type scale, links, focus
     4. Layout    — shell, sections, eyebrow
     5. Header / footer
     6. Components
     7. Writing   — /writing and the readiness map: rating mark, table, index
     8. Writing   — the divergence article: pair, data table, figure row,
                    funnel, source register
     9. Motion / print
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. Typeface

   Geist and Geist Mono, (c) 2023 Vercel in collaboration with basement.studio.
   Newsreader, copyright 2020 The Newsreader Project Authors. Both SIL Open Font
   License 1.1. Each licence ships beside the files it covers, at
   /fonts/OFL-Geist.txt and /fonts/OFL-Newsreader.txt, with an inventory in
   /fonts/README.txt — the OFL requires the notice and licence to travel with
   the font on redistribution, and one licence file cannot stand in for the
   other because the copyright holders differ.

   Self-hosted, not loaded from a font CDN: the site makes no third-party
   requests at all, and _headers ships a Content-Security-Policy of
   "default-src 'none'; font-src 'self'" that would block a Google Fonts
   request outright. The design prototypes hot-link Google Fonts; that is a
   property of the prototype, not something to port.

   Static instances, not variable files. brand.md fixes the palette of weights,
   and shipping a weight axis makes every intermediate weight available —
   available is how a type scale drifts.

   Newsreader is split latin / latin-ext by unicode-range so an English page
   fetches only what it renders. Note for the open "second language" question:
   Newsreader has no Cyrillic subset at all, so a Bulgarian page cannot use
   this display face.
   --------------------------------------------------------------------------- */

@font-face {
  font-family: 'Geist';
  src: url('/fonts/Geist-Regular.d8bce822db.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Geist';
  src: url('/fonts/Geist-Medium.b0a0867cda.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Geist';
  src: url('/fonts/Geist-SemiBold.b1e6a1dd21.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Geist Mono';
  src: url('/fonts/GeistMono-Regular.e4507fb4fb.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-400-latin.2836743090.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-400-latin-ext.e051076693.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-500-latin.cd987c00ac.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-500-latin-ext.d90fbe92db.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-600-latin.b0228f9db9.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-600-latin-ext.6490ee4fb4.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Italic ships at 500 only, because 500 is the only weight set in italic. */
@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-500Italic-latin.cb87489bd0.woff2') format('woff2');
  font-weight: 500;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  src: url('/fonts/Newsreader-500Italic-latin-ext.5434162ccc.woff2') format('woff2');
  font-weight: 500;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------------------------------------------------------------------------
   2. Tokens

   One palette. There is no dark adaptation in this direction: Paper is a
   single deliberate ground, and a warm cream page is what a visitor gets
   whatever their system is set to. meta[name=color-scheme] on each page is
   set to "light" so form controls and scrollbars agree.

   Contrast ratios are computed against --paper, and the second figure against
   --paper-sunk where an element appears on the closing band too.
   --------------------------------------------------------------------------- */

:root {
  --sans: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
  --mono: 'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo,
    Consolas, 'Liberation Mono', monospace;
  --serif: 'Newsreader', 'Iowan Old Style', 'Palatino Linotype', Palatino,
    Georgia, 'Times New Roman', serif;

  /* Ground. */
  --paper: #faf6ef;
  --paper-sunk: #f3ecdf;      /* closing band */

  /* Ink. */
  --ink: #1c1913;             /* 16.27:1 / 14.92:1 */
  --ink-muted: #544e42;       /*  7.66:1 /  7.02:1 — body copy */
  --ink-soft: #6d675b;        /*  5.21:1 /  4.78:1 — inactive nav, small meta */
  --ink-faint: #8a8272;       /*  3.53:1 /  3.24:1 — LARGE text and UI edges only */

  /* Lines. */
  --rule: #e8e0d2;            /* hairline dividers — decorative */
  --rule-strong: #d9d2c4;     /* timeline rail — decorative */
  --edge: #a89f8d;            /* inactive timeline dots — decorative, 2.43:1 */

  --signal: #b8380f;          /*  5.40:1 /  4.95:1 — clears AA as text */

  /* Space. */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s7: 28px;
  --s8: 32px;
  --s10: 40px;
  --s11: 44px;
  --s12: 48px;
  --s14: 56px;
  --s16: 64px;
  --s18: 72px;
  --s20: 80px;
  --s22: 88px;
  --s24: 96px;

  /* Radius. Buttons only — no card radii and no shadows anywhere. */
  --r-button: 6px;

  /* Layout. */
  --shell: 1200px;
  --gutter: var(--s14);

  /* Motion. */
  --t-fast: 120ms;
  --t-base: 160ms;
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
}

@media (max-width: 48rem) {
  :root { --gutter: var(--s6); }
}

/* ---------------------------------------------------------------------------
   3. Base
   --------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  /* Sticky footer: contact and 404 are short enough that the footer would
     otherwise sit halfway up a tall screen with empty page beneath it. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  font-synthesis: none;   /* never fake a weight or an italic from another file */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body > main { flex: 1 0 auto; }

/* Everything outside main keeps its intrinsic height: as flex items these would
   otherwise be shrinkable, and the footer is the first thing to get squashed on
   a short viewport. */
body > .site-header,
body > .closing,
body > .promise,
body > .site-footer { flex: none; }

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

/* Every heading is serif. That is the whole point of this direction. */
h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 500;
  text-wrap: balance;
}

/* Display — the home hero. Set as one sentence in two registers: the claim at
   weight 600 in full ink, the qualifier at 400 in --ink-faint. At 62px both
   halves are large text, so --ink-faint clears its 3:1 threshold here. */
.display {
  font-size: clamp(2.375rem, 1.6rem + 3.2vw, 3.875rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
}

.display__lead { font-weight: 600; color: var(--ink); }
.display__tail { font-weight: 400; color: var(--ink-faint); }

/* Inner page title. */
.page-title {
  font-size: clamp(2.25rem, 1.65rem + 2.6vw, 3.625rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
}

/* Section heading. */
h2 {
  font-size: clamp(1.75rem, 1.4rem + 1.5vw, 2.375rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

h3 { font-size: 1.375rem; line-height: 1.25; }

/* Inline code: a literal value quoted in prose — a header directive, a storage
   key. Mono is for data, and a file name or a stored word is data. No tint and
   no box: Paper has no filled panels, so the typeface carries the distinction. */
code {
  font-family: var(--mono);
  font-size: 0.875em;
  color: var(--ink);
}

a { color: var(--ink); text-decoration: none; }
a:hover { color: var(--signal); }

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

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

/* The skip link is invisible until it takes focus, then behaves as a button. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--s2);
  z-index: 10;
  padding: var(--s2) var(--s3);
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--r-button);
  font-size: 0.8125rem;
}

.skip-link:focus { left: var(--s4); color: var(--paper); }

/* Utilities. These exist so no page needs a style="" attribute — which is what
   lets _headers ship "style-src 'self'" with no 'unsafe-inline' escape hatch.
   An inline style anywhere reopens that hole for the whole site. */
.lede {
  margin-top: var(--s6);
  font-size: 1rem;
  color: var(--ink-muted);
  max-width: 62ch;
}

.section-lede {
  margin-top: var(--s3);
  font-size: 0.96875rem;
  color: var(--ink-muted);
  max-width: 60ch;
}

/* ---------------------------------------------------------------------------
   4. Layout

   A section owns its vertical rhythm and its full-bleed top rule; the shell
   inside it caps and centres the content. The rule therefore runs edge to
   edge while the copy stays on a 1200px measure.
   --------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: var(--s14) var(--s18);
  border-top: 1px solid var(--rule);
}

.section--deep { padding-block: var(--s14) var(--s20); }

/* The tiers on the services page and the rules on the approach page sit
   directly under their hero with no dividing rule — the hero already
   introduced them. */
.section--flush { padding-block: 0 var(--s18); border-top: 0; }
.section--rules { padding-block: var(--s6) var(--s20); border-top: 0; }

.hero { padding-block: var(--s24) var(--s18); }
.hero--inner { padding-block: var(--s22) var(--s16); }
.hero--tight { padding-block: var(--s22) var(--s14); }

@media (max-width: 48rem) {
  .section, .section--deep { padding-block: var(--s10) var(--s12); }
  .hero, .hero--inner, .hero--tight { padding-block: var(--s12) var(--s10); }
}

/* The eyebrow above a section heading: mono, uppercase, in the signal colour. */
.eyebrow {
  display: block;
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--signal);
  margin-bottom: var(--s5);
}

.eyebrow--wide { margin-bottom: var(--s8); }
.eyebrow--faq { margin-bottom: var(--s10); }

/* ---------------------------------------------------------------------------
   5. Header and footer
   --------------------------------------------------------------------------- */

.site-header { border-bottom: 1px solid var(--rule); }

.site-header__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s6);
  padding-block: var(--s5);
}

/* The wordmark is set, not drawn: Geist SemiBold, uppercase, tracked 0.16em —
   the tracking is what makes five letters read as a mark. The signal bar in
   front of it is the one place the signal colour appears by default. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 600;
  font-size: 0.9375rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  flex: none;
}

.wordmark::before {
  content: '';
  width: 22px;
  height: 2px;
  background: var(--signal);
  flex: none;
}

.wordmark:hover { color: var(--ink); }

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s7);
  font-size: 0.875rem;
}

/* The site ships no JavaScript, so there is no disclosure menu to open: below
   the breakpoint the nav simply takes a row of its own under the wordmark and
   the call button. Four links fit on one row at 390px — Services, Approach,
   Writing, Contact measure about 270px against 342px of available width. A
   fifth does not, and would need a different shape rather than a smaller gap. */
@media (max-width: 48rem) {
  .site-header__in { gap: var(--s3) var(--s4); }
  .nav { order: 3; width: 100%; gap: var(--s5); }
}

.nav a {
  color: var(--ink-soft);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}

.nav a[aria-current] {
  color: var(--ink);
  border-bottom-color: var(--signal);
}

.site-footer {
  border-top: 1px solid var(--rule);
  font-size: 0.8125rem;
  /* --ink-soft, not the --ink-faint the prototype used: 13px is small text and
     --ink-faint is 3.53:1, short of the 4.5:1 AA asks of it. Same family, one
     step darker, threshold cleared. */
  color: var(--ink-soft);
}

.site-footer__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3) var(--s6);
  padding-block: var(--s6);
}

.site-footer nav { display: flex; flex-wrap: wrap; gap: var(--s6); }
.site-footer a { color: var(--ink-soft); }

/* ---------------------------------------------------------------------------
   6. Components
   --------------------------------------------------------------------------- */

/* -- Terminal line. A mono command in the signal colour with a blinking block
      caret, once above the hero and once above the closing band. The caret is
      the one element on this site that moves without being asked to; the
      reduced-motion block at the end of the file holds it lit. ---------------- */

.term {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--signal);
  margin-bottom: var(--s7);
}

.term__caret {
  display: inline-block;
  width: 8px;
  height: 14px;
  margin-left: 6px;
  vertical-align: -2px;
  background: var(--signal);
  animation: blink 1.1s steps(1) infinite;
}

@keyframes blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

/* -- Button. --------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 13px 24px;
  border: 1px solid transparent;
  border-radius: var(--r-button);
  background: var(--ink);
  color: var(--paper);
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}

.btn:hover { background: var(--signal); color: var(--paper); }

.btn--ghost {
  background: transparent;
  color: var(--ink);
  /* --ink-faint at 3.53:1, not the prototype's --edge at 2.43:1: this is the
     visible boundary of a control, which WCAG 1.4.11 holds to 3:1. */
  border-color: var(--ink-faint);
}

.btn--ghost:hover {
  background: transparent;
  border-color: var(--signal);
  color: var(--signal);
}

.btn--sm { padding: 8px 16px; font-size: 0.8125rem; }
.btn--lg { padding: 14px 26px; font-size: 1rem; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  align-items: center;
  margin-top: var(--s10);
}

/* A text link that carries an underline rule rather than a fill. */
.link-rule {
  font-size: 0.875rem;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 2px;
  transition: color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease);
}

.link-rule:hover { color: var(--signal); border-color: var(--signal); }

/* -- Home hero. Two columns; the right one is a rail of supporting lines
      separated by a hairline. ------------------------------------------------ */

.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: var(--s18);
}

.hero-aside {
  border-left: 1px solid var(--rule);
  padding-left: var(--s11);
  display: flex;
  flex-direction: column;
  gap: 22px;
  align-self: center;
}

.hero-aside p {
  font-size: 0.96875rem;
  color: var(--ink-muted);
}

@media (max-width: 64rem) {
  .hero-split { grid-template-columns: 1fr; gap: var(--s10); }
  .hero-aside {
    border-left: 0;
    border-top: 1px solid var(--rule);
    padding-left: 0;
    padding-top: var(--s8);
  }
}

/* -- Slash list. The mono slash is the signal device on a list of commitments;
      it marks each line as something the engagement is held to. -------------- */

.slashes {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 0.875rem;
  color: var(--ink-muted);
}

.slashes li {
  display: grid;
  grid-template-columns: 14px 1fr;
  gap: 10px;
}

.slashes li::before {
  content: '/';
  font-family: var(--mono);
  color: var(--signal);
}

.slashes--tight { gap: 9px; margin-top: var(--s1); }

/* -- Columns. Three or two abreast, 48px apart, no boxes. ------------------- */

.cols-3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s12);
}

/* Headings carry no bottom margin of their own, so the gap belongs to whatever
   follows them. .timeline and .spec set their own; this is the columns' turn. */
h2 + .cols-3 { margin-top: var(--s11); }

@media (max-width: 64rem) { .cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 48rem) { .cols-3 { grid-template-columns: 1fr; gap: var(--s10); } }

/* -- Engagement / tier column. ---------------------------------------------- */

.card {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* The services page heads each column with a 2px rule; the lead tier's is in
   the signal colour, which is what marks it without a badge or a fill. */
.card--ruled { border-top: 2px solid var(--ink); padding-top: var(--s6); }
.card--lead { border-top-color: var(--signal); }

.card__ord {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.card__ord--lead { color: var(--signal); }

.card__name { font-size: 1.75rem; }

/* The price is a figure, so it is mono. "Scoped individually" occupies the same
   slot at the same size — the absence of a number has to look deliberate. */
.card__price {
  font-family: var(--mono);
  font-size: 0.875rem;
  color: var(--signal);
}

.card__body { font-size: 0.90625rem; color: var(--ink-muted); }

.card__meta {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
  border-top: 1px solid var(--rule);
  padding-top: var(--s3);
  margin-top: auto;
}

/* -- Horizontal timeline (the method on the home page). The rail is one
      absolutely positioned hairline behind a row of dots; the dots are opaque
      and sit on it. -------------------------------------------------------- */

.timeline {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  position: relative;
  margin-top: var(--s12);
}

.timeline::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 4px;
  height: 1px;
  background: var(--rule-strong);
}

.timeline > li { position: relative; padding-right: var(--s8); }
.timeline > li:last-child { padding-right: 0; }

.timeline__dot {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--edge);
  position: relative;
}

.timeline__dot--first { background: var(--signal); }

.timeline__label {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--ink);
  margin: 18px 0 var(--s2);
}

.timeline__label--first { color: var(--signal); }

.timeline__body { font-size: 0.875rem; line-height: 1.6; color: var(--ink-muted); }

@media (max-width: 64rem) {
  .timeline { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s10) var(--s12); }
  .timeline::before { content: none; }   /* a rail across a wrapped grid is a lie */
  .timeline > li { padding-right: 0; }
}

@media (max-width: 48rem) {
  .timeline { grid-template-columns: 1fr; gap: var(--s8); }
}

/* -- Vertical timeline (the four rules on the approach page). --------------- */

.rules {
  position: relative;
  max-width: 980px;
}

.rules::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 10px;
  bottom: 10px;
  width: 1px;
  background: var(--rule-strong);
}

.rule {
  display: grid;
  grid-template-columns: 40px 200px minmax(0, 1fr);
  gap: 0 var(--s8);
  padding-bottom: var(--s14);
}

.rule:last-child { padding-bottom: 0; }

.rule__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--edge);
  margin-top: var(--s2);
  position: relative;
}

.rule__dot--first { background: var(--signal); }

.rule__label {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--ink);
  margin-top: var(--s1);
}

.rule__label--first { color: var(--signal); }

.rule h2 {
  font-size: clamp(1.5rem, 1.25rem + 1vw, 1.875rem);
  line-height: 1.2;
  margin-bottom: 14px;
}

.rule p {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--ink-muted);
  max-width: 64ch;
}

.rule p + p { margin-top: var(--s3); }

/* Below the breakpoint the label moves above the heading and the rail stays
   where it is, so the sequence still reads down the left edge. */
@media (max-width: 48rem) {
  .rule { grid-template-columns: 40px minmax(0, 1fr); }
  .rule__label { grid-column: 2; margin-bottom: var(--s2); }
  .rule__content { grid-column: 2; }
}

/* -- Specification table. Rows of claim and verdict, not cards. The verdict is
      mono and uppercase; "always" and "required" take the signal colour
      because they are the commitments, and the rest stay quiet. ------------- */

.spec {
  display: flex;
  flex-direction: column;
  max-width: 900px;
  margin-top: var(--s10);
}

.spec__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s8);
  align-items: baseline;
  padding-block: var(--s4);
  border-top: 1px solid var(--rule);
}

.spec__row:last-child { border-bottom: 1px solid var(--rule); }

.spec__k { font-size: 0.9375rem; color: var(--ink); }

.spec__v {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: right;
}

.spec__v--yes { color: var(--signal); }

@media (max-width: 34rem) {
  .spec__row { gap: var(--s3); }
}

/* -- FAQ. A flat two-column grid: every answer is visible, because a question
      a visitor has to click is a question they may not know they have. ------- */

.faq {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s11) var(--s16);
}

.faq h3 {
  font-style: italic;
  font-size: 1.3125rem;
  margin-bottom: 10px;
}

.faq p { font-size: 0.90625rem; color: var(--ink-muted); }

@media (max-width: 64rem) {
  .faq { grid-template-columns: 1fr; gap: var(--s10); }
}

/* -- Stall columns: italic serif sub-head over body copy. ------------------- */

.stall h3 { font-style: italic; margin-bottom: var(--s3); }
.stall p { font-size: 0.90625rem; color: var(--ink-muted); }

/* While the three sit side by side, reserve two lines for the sub-head so the
   paragraphs under them start on a shared baseline. One of the three wraps and
   the others do not, and padding the copy to match would be the wrong fix —
   reserving the space is not. Dropped once the columns stack, where a reserved
   empty line is just a gap. */
@media (min-width: 48.0625rem) {
  .stall h3 { min-height: calc(2 * 1.25em); }
}

/* -- Closing band. Full bleed, sunk ground, once per page. ------------------ */

.closing {
  background: var(--paper-sunk);
  border-top: 1px solid var(--rule);
  padding-block: var(--s22);
}

.closing--inner { padding-block: var(--s20); }

.closing__in { max-width: 760px; }

.closing h2 {
  font-size: clamp(1.875rem, 1.35rem + 2.2vw, 2.625rem);
  letter-spacing: -0.015em;
  margin-bottom: 18px;
}

.closing--home h2 { font-size: clamp(1.875rem, 1.3rem + 2.4vw, 2.75rem); margin-bottom: var(--s5); }

.closing p {
  font-size: 1rem;
  color: var(--ink-muted);
  max-width: 54ch;
  margin-bottom: 30px;
}

.closing--home p { max-width: 56ch; margin-bottom: var(--s8); }

.closing__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s4);
  align-items: center;
}

/* The contact page ends on a single serif paragraph rather than a call to
   action — the page has already given the address, so the last thing on it is
   what happens after you use it. */
.promise {
  background: var(--paper-sunk);
  border-top: 1px solid var(--rule);
  padding-block: var(--s16);
  margin-top: auto;
}

.promise p {
  font-family: var(--serif);
  font-size: clamp(1.25rem, 1.05rem + 0.8vw, 1.5rem);
  font-weight: 500;
  line-height: 1.45;
  max-width: 44ch;
}

.promise em { font-style: italic; color: var(--signal); }

/* -- Centred page (404). ---------------------------------------------------- */

.centred {
  min-height: 50vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--s24);
}

/* ---------------------------------------------------------------------------
   7. Writing — the section index and the readiness map

   Everything below belongs to /writing/ai-readiness-map and nothing else yet.
   It adds three components the site did not have: a rating mark, a rating
   table and a section index. No new token is invented — every value here is a
   system variable or a 4px multiple.

   Three names differ from the design handoff on purpose. The handoff's ".hero"
   and ".label" would have collided with, or been too generic for, a stylesheet
   every page loads, and its ".caret" is the site's existing .term__caret.
   --------------------------------------------------------------------------- */

/* -- The section index at /writing. The masthead sets the section name against
      the date; the lead entry carries the article and, beside it, the same plate
      the article opens with, generated from the same ratings.

      There is no Recent grid and no archive list: there is one entry. Both come
      back as soon as there is a second, and neither is invented in the meantime.
      There is no subscribe form either — a form that cannot deliver is a
      mechanism whose failure is visible, which this site does not ship. ------- */

.masthead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s8);
}

.masthead__title {
  font-size: clamp(2.5rem, 1.8rem + 3vw, 4rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
}

.masthead .meta-label { padding-bottom: var(--s3); }

.lead {
  border-top: 1px solid var(--ink);
  padding-top: var(--s5);
}

.lead__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--s16);
  align-items: start;
}

.lead__title {
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  max-width: 18ch;
}

.lead__dek {
  font-size: 1.125rem;
  line-height: 1.55;
  color: var(--ink-muted);
  max-width: 52ch;
  margin-top: var(--s5);
}

.lead__meta {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
  margin-top: var(--s6);
}

.lead__action { margin-top: var(--s6); }

/* Beside the lead entry the plate has no rule of its own — .lead already drew
   one across the whole block — and its marks come down to 3px. */
.plate--compact {
  margin-top: 0;
  border-top: 0;
  padding-top: 0;
}

.plate--compact .plate__grid { gap: var(--s3); }

.mark--sm { gap: 2px; }
.mark--sm i { width: 3px; height: 12px; }

/* -- Hero. Shallower than .hero--inner: this is a reference document, and the
      plate below has to be reachable without a scroll on a laptop. ----------- */

.article-hero { padding-top: var(--s16); }

.article-hero h1 { max-width: 20ch; margin-top: var(--s5); }

.standfirst {
  font-size: 1.1875rem;
  line-height: 1.5;
  max-width: 60ch;
  margin-top: var(--s6);
}

/* The dated line under the standfirst. The dot is one of the eight places on
   this page where the signal colour is spent. */
.snapshot {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  margin-top: var(--s5);
}

.snapshot i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--signal);
  flex: none;
}

/* A mono label that is not the signal-coloured .eyebrow: these sit above data,
   not above a section heading. */
.meta-label {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.prose {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  max-width: 62ch;
  color: var(--ink-muted);
}

.prose--lead { margin-top: var(--s12); }
.prose--note { margin-top: var(--s5); }

/* -- Rating mark. Five fixed slots; the number filled IS the rating, so the
      count carries it and colour never has to. One fixed width, so eleven
      tables scan as a single column.

      Level 1 is the only place on the page where a mark takes the accent, and
      the map has exactly one level-1 row — automated payments. ---------------- */

.mark {
  display: inline-flex;
  align-items: flex-end;
  gap: 3px;
  line-height: 0;
}

.mark i { width: 4px; height: 13px; background: var(--rule); }
.mark i.on { background: var(--ink); }
.mark--l1 i.on { background: var(--signal); }

/* Legend only. */
.mark--lg { gap: var(--s1); }
.mark--lg i { width: 5px; height: 18px; }

/* -- Hero plate. The page has no photograph; its image is the whole map drawn
      with the same component the tables use, so the two can never disagree.
      Eleven columns, one per function, 53 marks. ----------------------------- */

.plate {
  margin-top: var(--s12);
  border-top: 1px solid var(--ink);
  padding-top: var(--s4);
}

.plate__cap {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s6);
  margin-bottom: var(--s6);
}

.plate__grid {
  display: grid;
  grid-template-columns: repeat(11, minmax(0, 1fr));
  gap: var(--s6);
}

.plate__col { display: block; }

.plate__col span.n {
  display: block;
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--ink-soft);
  padding-bottom: 10px;
  border-bottom: 1px solid var(--rule);
  transition: color var(--t-base) var(--ease),
              border-color var(--t-base) var(--ease);
}

.plate__col:hover span.n { color: var(--signal); border-color: var(--signal); }

.plate__stack {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin-top: var(--s3);
}

/* -- Legend. The block the page is designed to be screenshotted from. -------- */

.legend { margin-top: var(--s8); }

.legend__row {
  display: grid;
  grid-template-columns: 56px 22ch minmax(0, 1fr);
  gap: var(--s8);
  align-items: baseline;
  padding-block: 18px;
  border-top: 1px solid var(--rule);
}

.legend__row:last-child { border-bottom: 1px solid var(--rule); }

.legend__name { font-weight: 500; font-size: 1.0625rem; color: var(--ink); }
.legend__what { color: var(--ink-muted); max-width: 62ch; }

/* -- Four questions. Two columns by CSS only: the DOM order stays 01–11
      because the copy refers to "question 4" by its number. ------------------ */

.qs {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(2, auto);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--s16);
  margin-top: var(--s8);
  max-width: 1080px;
}

.qs li {
  display: grid;
  grid-template-columns: 3ch minmax(0, 1fr);
  gap: var(--s4);
  padding-block: var(--s5);
  border-top: 1px solid var(--rule);
}

.qs li:nth-child(2), .qs li:nth-child(4) { border-bottom: 1px solid var(--rule); }
.qs span.n { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-soft); }
.qs p { color: var(--ink-muted); max-width: 52ch; }

/* -- Section head. ---------------------------------------------------------- */

.sechead {
  display: flex;
  align-items: baseline;
  gap: var(--s6);
  border-top: 1px solid var(--ink);
  padding-top: 14px;
  margin-top: var(--s16);
}

.sechead h2 {
  font-size: clamp(1.75rem, 1.4rem + 1.5vw, 2.125rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.sechead__n { font-family: var(--mono); font-size: 0.75rem; color: var(--ink-soft); }

/* Sections without a number still need the index slot filled, or their heading
   falls out of the column the eleven numbered ones sit in. An em dash was there
   first and read as a missing value; a 22px rule in the signal colour replaced
   it and was worse, because it was wider than the numerals it stood beside and
   pushed four headings out of alignment.

   What is here is the smallest accent the system owns — the same 6px dot as the
   snapshot line — in a slot exactly 2ch wide, the width of the mono "01". The
   column holds, and the mark is small enough not to outrank the one level-1
   rating that has to be the loudest red on the page. */
.sechead__n--dot {
  display: inline-block;
  position: relative;
  width: 2ch;
  height: 0.75rem;
}

.sechead__n--dot::before {
  content: '';
  position: absolute;
  left: 0;
  bottom: 3px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--signal);
}

.sechead__count {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-left: auto;
  white-space: nowrap;
}

/* -- Rating table. A real <table> with no borders except one hairline per row:
      the site separates content with rules and actual alignment, never boxes.

      The column widths live on the header cells, NOT in a <colgroup>.
      table-layout: fixed reads its widths from the first row, and a dropped
      colgroup silently splits the table into three equal thirds. ------------- */

.rtable {
  width: 100%;
  max-width: 1030px;
  table-layout: fixed;
  border-collapse: collapse;
  margin-top: var(--s7);
}

.rtable th {
  text-align: left;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-bottom: 10px;
}

.rtable th:nth-child(1) { width: 320px; }
.rtable th:nth-child(2) { width: 76px; }

.rtable td {
  border-top: 1px solid var(--rule);
  padding-block: 15px;
  vertical-align: baseline;
}

.rtable tr:last-child td { border-bottom: 1px solid var(--rule); }
.rtable__task { padding-right: var(--s8); }

.rtable__note {
  display: block;
  max-width: 60ch;
  color: var(--ink-muted);
  font-size: 0.875rem;
  line-height: 1.6;
}

/* The task cell is a list of terms on one continuous rail, never a paragraph.
   The rail is a border-left on each term with zero gap, so the segments tile
   into an unbroken line; a per-term ::before would travel with a wrapped term
   and leave a hanging rule at the start of the next line. */
.tt { display: flex; flex-direction: column; }

.tt .t {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.4;
  padding: 2px 0 2px var(--s3);
  border-left: 1px solid var(--rule-strong);
}

/* A single-term task has nothing to thread together, so it drops the rail. */
.tt:has(.t:only-child) .t { padding-left: 0; border-left: 0; }

/* Used only where the source copy itself marks a head with a colon. */
.tt__head {
  display: block;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.4;
  margin-bottom: var(--s1);
}

.tt--scoped .t { font-size: 0.875rem; font-weight: 400; color: var(--ink-soft); }

/* Every row carries an id, so a single rating can be linked to and argued
   with. :target marks the row the reader was sent to with the same rail the
   task terms use — never a fill, because this site has no filled panels. */
.rtable tr:target .rtable__task {
  box-shadow: inset 3px 0 0 var(--signal);
  padding-left: var(--s3);
}

/* The section number is the section's own anchor. */
.sechead__n a {
  color: var(--ink-soft);
  transition: color var(--t-base) var(--ease);
}

.sechead__n a:hover { color: var(--signal); }

/* The snapshot date repeated where the reader actually finishes. */
.article-date { margin-top: var(--s16); }

/* -- Section index. Inline under the hero, not a sticky rail: a rail tracks
      scroll position, which means something moves while the reader is still.
      A printed reference opens with contents. -------------------------------- */

.sindex { margin-top: var(--s16); }

.sindex__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s6);
  border-bottom: 1px solid var(--ink);
  padding-bottom: 10px;
}

.sindex__list {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(4, auto);
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--s12);
}

.sindex__list li {
  display: grid;
  grid-template-columns: 2.5ch minmax(0, 1fr) auto;
  gap: var(--s3);
  align-items: baseline;
  padding-block: 11px;
  border-bottom: 1px solid var(--rule);
}

.sindex__list a {
  font-size: 0.875rem;
  transition: color var(--t-base) var(--ease);
}

.sindex__n, .sindex__count {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
}

/* -- How to use this map, and the coda that closes the article. ------------- */

.howto { max-width: 62ch; margin-top: var(--s6); }

.howto p {
  padding-block: var(--s5);
  border-top: 1px solid var(--rule);
  color: var(--ink-muted);
}

.howto p:last-child { border-bottom: 1px solid var(--rule); }

.coda {
  font-family: var(--serif);
  font-size: clamp(1.375rem, 1.1rem + 1.2vw, 1.625rem);
  line-height: 1.3;
  max-width: 44ch;
  margin-top: var(--s12);
}

/* -- Article breakpoints. 62.5rem collapses the legend and the questions;
      45rem restacks the tables. The header has its own at 48rem. ------------- */

@media (max-width: 62.5rem) {
  .plate__grid { gap: var(--s4); }
  .legend__row { grid-template-columns: 56px minmax(0, 1fr); gap: var(--s4) var(--s6); }
  .legend__what { grid-column: 2; }
  .qs { display: block; max-width: 62ch; }
  .qs li:nth-child(2) { border-bottom: 0; }
  .qs li:last-child { border-bottom: 1px solid var(--rule); }
}

@media (max-width: 45rem) {
  .article-hero { padding-top: var(--s8); }
  .plate__grid { grid-template-columns: repeat(6, minmax(0, 1fr)); row-gap: var(--s5); }
  .plate__cap { flex-direction: column; gap: var(--s1); }
  .sindex__list { display: block; }
  .sechead { margin-top: var(--s12); gap: var(--s4); }

  /* Each row becomes task-left / mark-right with the note on a full-width
     third line. The note is never truncated or hidden behind a disclosure —
     it is the reason the row exists. */
  .rtable, .rtable tbody, .rtable tr, .rtable td {
    display: block;
    width: auto;
    max-width: none;
  }

  .rtable thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .rtable tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 32px;
    column-gap: var(--s4);
    border-top: 1px solid var(--rule);
    padding-block: 14px;
  }

  .rtable td { border: 0; padding: 0; }
  .rtable__task { grid-column: 1; grid-row: 1; padding-right: 0; }
  .rtable__mark { grid-column: 2; grid-row: 1; margin-top: 5px; }
  .rtable__note { grid-column: 1 / -1; margin-top: 6px; font-size: 0.84375rem; max-width: none; }
  .rtable tr:last-child { border-bottom: 1px solid var(--rule); }
  .rtable tr:last-child td { border-bottom: 0; }
}

/* ---------------------------------------------------------------------------
   8. Writing — the divergence article

   Everything below belongs to /writing/four-times-apart and nothing else yet.
   It adds five components the site did not have: a divergence pair, a data
   table, a figure row, a funnel and a source register. As in section 7, no new
   token is invented — every value here is a system variable or a 4px multiple.

   The bar is deliberately one primitive shared by the pair and the funnel, for
   the same reason the readiness map draws its plate with the component its
   tables use: two pictures of the same quantity cannot then disagree.

   The signal is spent eight times at rest on this page — nav underline,
   terminal caret, hero snapshot dot, the probability-sample figure and its
   bar, the two section eyebrows, the final funnel row, and the closing
   snapshot dot. Hover and focus spend a ninth and a tenth. Anything added
   below that takes the accent has to take it from one of those.
   --------------------------------------------------------------------------- */

/* -- The bar. A flat track in --rule with a filled span; the span carries the
      percentage as its width and nothing else encodes it. No radius, no
      gradient, no label inside the fill. ------------------------------------- */

.bar {
  height: 16px;
  background: var(--rule);
}

.bar > i {
  display: block;
  height: 100%;
  background: var(--ink);
}

/* Bar widths. The site ships no style= attributes, so a percentage that is part
   of the data gets a class rather than an inline width. The same class serves
   the pair and the funnel wherever the quantity is the same. */
.bar > .w88 { width: 88%; }
.bar > .w66 { width: 66%; }
.bar > .w33 { width: 33%; }
.bar > .w20 { width: 19.8%; }
.bar > .w07 { width: 7%; }
.bar > .w06 { width: 6%; }

/* -- Divergence pair (Figure 1). Two measurements of the same subject drawn to
      one shared scale, each with the instrument that produced it. The figure
      taken from a probability sample is the one that takes the accent: on a
      page about which numbers to trust, the accent is the recommendation. ---- */

.pair {
  margin-top: var(--s14);
  border-top: 1px solid var(--ink);
  padding-top: var(--s7);
}

.pair__cap { margin-bottom: var(--s8); }

.pair__row {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  gap: var(--s8);
  align-items: start;
}

.pair__row + .pair__row { margin-top: var(--s11); }

.pair__fig {
  font-family: var(--mono);
  font-size: 2.5rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.pair__claim {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.375rem;
  line-height: 1.3;
  max-width: 44ch;
}

.pair .bar { margin-top: var(--s5); }

.pair__src {
  font-family: var(--mono);
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin-top: var(--s3);
}

.pair__row--probability .pair__fig { color: var(--signal); }
.pair__row--probability .bar > i { background: var(--signal); }

/* The reconciliation. It is the point of the component, so it sits inside the
   figure rather than after it. */
.pair__note {
  border-top: 1px solid var(--rule);
  margin-top: var(--s10);
  padding-top: var(--s6);
}

.pair__note p {
  color: var(--ink-muted);
  max-width: 62ch;
  text-wrap: pretty;
}

/* -- Data table. Same rules as .rtable — hairline per row, mono uppercase
      heads, widths on the header cells because table-layout: fixed reads them
      from the first row.

      A note row spans the full width and reads the rows above it. The row
      immediately before one drops its own border so the note stays attached to
      what it explains rather than floating between two groups. -------------- */

.dtable {
  width: 100%;
  max-width: 1030px;
  table-layout: fixed;
  border-collapse: collapse;
  margin-top: var(--s10);
}

.dtable th {
  text-align: left;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 0 var(--s4) var(--s3) 0;
  border-bottom: 1px solid var(--ink);
}

.dtable td {
  padding: var(--s4) var(--s4) var(--s4) 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: baseline;
}

.dtable th:last-child,
.dtable td:last-child { padding-right: 0; }

.dtable__n {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.dtable__m {
  color: var(--ink-muted);
  font-size: 0.9375rem;
}

.dtable__d {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.dtable tr:has(+ tr.dtable__noterow) > td { border-bottom: 0; }
.dtable tr.dtable__noterow > td { padding: 0 0 var(--s4); }

.dtable__note {
  display: block;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: 62ch;
}

/* Column widths, per table. */
.dtable--ladder th:nth-child(1) { width: 30%; }
.dtable--ladder th:nth-child(2) { width: 10%; }
.dtable--ladder th:nth-child(3) { width: 26%; }
.dtable--ladder th:nth-child(4) { width: 18%; }

.dtable--functions th:nth-child(1) { width: 52%; }
.dtable--functions th:nth-child(2) { width: 20%; }

/* -- Figure row. Four measures on one rule. The figure is set in the serif,
      not the mono: these are read as quantities, not looked up as data, and
      inequalities and units belong in the same face as the numeral. --------- */

.figrow {
  margin-top: var(--s10);
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--rule);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s10);
  padding-block: var(--s7);
}

.figrow__n {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 2.75rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.figrow__c {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-muted);
  margin-top: var(--s3);
}

/* -- Funnel. Five descending rows on the shared bar, one survey and one
      fieldwork window, so the rows are comparable to each other and to nothing
      else. The last row takes the accent: it is the exception, exactly as
      level 1 is on the readiness map. ---------------------------------------- */

.funnel {
  margin-top: var(--s10);
  border-top: 1px solid var(--ink);
  padding-top: var(--s7);
}

.funnel__cap { margin-bottom: var(--s7); }

.funnel__row {
  display: grid;
  grid-template-columns: 70px minmax(0, 480px) minmax(0, 1fr);
  gap: var(--s6);
  align-items: center;
  padding-block: var(--s3);
  border-top: 1px solid var(--rule);
}

.funnel__row:last-of-type { border-bottom: 1px solid var(--rule); }

.funnel__pct {
  font-family: var(--mono);
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.funnel__label { font-size: 0.9375rem; }

.funnel__row--exception .funnel__pct,
.funnel__row--exception .funnel__label { color: var(--signal); }
.funnel__row--exception .bar > i { background: var(--signal); }

.funnel__src {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
  margin-top: var(--s4);
}

/* -- Six reasons. Two columns reading left to right, because the copy does not
      refer to them by number the way the readiness map's four questions do. -- */

.reasons {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--s20);
  margin-top: var(--s10);
}

.reasons li {
  display: grid;
  grid-template-columns: 3ch minmax(0, 1fr);
  gap: var(--s4);
  border-top: 1px solid var(--rule);
  padding-block: var(--s5);
}

.reasons li:nth-child(5),
.reasons li:nth-child(6) { border-bottom: 1px solid var(--rule); }

.reasons__n {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.reasons__t {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.25rem;
  line-height: 1.3;
}

.reasons__b {
  color: var(--ink-muted);
  font-size: 0.9375rem;
  margin-top: var(--s3);
  text-wrap: pretty;
}

/* -- Source register. Grouped like .legend__row: the group label says which
      instrument, and every entry carries its sample and its FIELDWORK date,
      never its publication date. That pairing is the article's argument, so it
      is the register's only column. ------------------------------------------ */

.register + .register { margin-top: var(--s11); }

.register__label { padding-bottom: var(--s4); }

.register__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s8);
  align-items: baseline;
  border-top: 1px solid var(--rule);
  padding-block: var(--s4);
}

.register__row:last-child { border-bottom: 1px solid var(--rule); }

.register__meta {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
}

/* -- Section index, second entry onward. The lead entry keeps its plate; every
      entry after it is a ruled row carrying date, title and dek. The Recent grid
      the first version of /writing left out comes back here, at the size one
      further entry actually needs. -------------------------------------------- */

.entries {
  margin-top: var(--s16);
  border-top: 1px solid var(--ink);
}

.entries__label { padding: var(--s5) 0 var(--s4); }

.entry {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: var(--s8);
  align-items: baseline;
  border-top: 1px solid var(--rule);
  padding-block: var(--s6);
}

.entry:last-child { border-bottom: 1px solid var(--rule); }

.entry__meta {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
}

.entry__title { font-size: 1.5rem; line-height: 1.2; letter-spacing: -0.01em; }

.entry__dek {
  color: var(--ink-muted);
  font-size: 0.9375rem;
  max-width: 62ch;
  margin-top: var(--s3);
}

/* -- Closing band, coda variant. The article ends on the instruction rather
      than on a call to action, so this band carries a coda and the snapshot
      instead of a heading and buttons.

      .closing p already sets a size, a colour and a bottom margin, and it
      out-specifies .coda on its own; the modifier is what lets the coda keep
      its own type without raising specificity elsewhere. -------------------- */

.closing--coda p { margin-bottom: 0; }

.closing--coda .coda {
  margin-top: 0;
  color: var(--ink);
  font-size: clamp(1.375rem, 1.1rem + 1.2vw, 1.625rem);
  max-width: 44ch;
}

.closing--coda .snapshot {
  margin-top: var(--s11);
  font-size: 0.75rem;
  max-width: none;
  color: var(--ink-soft);
}

.closing--coda .closing__note {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--ink-soft);
  max-width: none;
  margin-top: var(--s2);
  padding-left: 14px;
}

/* -- Article breakpoints. 62.5rem stacks the pair and halves the figure row
      and the reasons; 45rem restacks the tables and the funnel. -------------- */

@media (max-width: 62.5rem) {
  .pair__row { grid-template-columns: minmax(0, 1fr); gap: var(--s3); }
  .pair__row + .pair__row { margin-top: var(--s8); }
  .figrow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s7) var(--s8); }
  .reasons { grid-template-columns: minmax(0, 1fr); column-gap: 0; max-width: 62ch; }
  .reasons li:nth-child(5) { border-bottom: 0; }
  .register__row { grid-template-columns: minmax(0, 1fr); gap: var(--s1); }
}

@media (max-width: 45rem) {
  .entry { grid-template-columns: minmax(0, 1fr); gap: var(--s2); }
  .pair__fig { font-size: 2rem; }
  .pair__claim { font-size: 1.25rem; }
  .bar { height: 12px; }
  .figrow { grid-template-columns: minmax(0, 1fr); gap: var(--s6); }

  /* The funnel keeps its bar and moves the label under it; the percentage stays
     beside the bar, because reading the two together is the whole row. */
  .funnel__row { grid-template-columns: 56px minmax(0, 1fr); row-gap: var(--s2); }
  .funnel__label { grid-column: 1 / -1; }

  /* Tables restack as labelled blocks. The head is removed from the flow and
     each cell names itself, so no value is left without its column. The note
     row is never hidden — it is the reason the group exists. */
  .dtable, .dtable tbody, .dtable tr, .dtable td {
    display: block;
    width: auto;
    max-width: none;
  }

  .dtable thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .dtable tr {
    border-top: 1px solid var(--rule);
    padding-block: 14px;
  }

  .dtable td { border: 0; padding: 0; }
  .dtable td + td { margin-top: var(--s1); }

  .dtable td[data-l]::before {
    content: attr(data-l);
    display: block;
    font-family: var(--mono);
    font-size: 0.625rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-bottom: 2px;
  }

  .dtable tr.dtable__noterow { border-top: 0; padding-top: 0; }
  .dtable tr.dtable__noterow > td { padding: 0; }
  .dtable tr:last-child { border-bottom: 1px solid var(--rule); }
}

/* ---------------------------------------------------------------------------
   9. Motion

   Motion responds to the visitor. There are no scroll reveals, no parallax and
   no ambient loops on this site — with one exception, the terminal caret,
   which blinks on its own. This block is the visitor's opt-out: the caret is
   held lit rather than removed, so the line still reads as a prompt.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .term__caret { animation: none; opacity: 1; }
}

/* Printing: a visitor who prints a page should get the text, not the chrome. */
@media print {
  .site-header, .site-footer, .skip-link, .closing, .term__caret { display: none; }
  body { color: #000; background: #fff; }
  .section { padding-block: var(--s8); border-color: #ccc; }
}

/* The consent bar. Fixed to the bottom so it is answerable without scrolling,
   on the sunken paper with a hairline above it rather than a shadow — Paper has
   no shadows, and this is a band, not a card.

   Both buttons are the same size and the same style on purpose. Declining has
   to cost what accepting costs; an emphasised Accept beside a faint Decline is
   the pattern regulators keep calling a dark one, and it would be the only
   place on this site where a control was styled to steer rather than to work. */
.consent {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 20;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4) var(--s8);
  padding: var(--s5) var(--gutter);
  background: var(--paper-sunk);
  border-top: 1px solid var(--rule-strong);
}

.consent__text {
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: 68ch;
}

.consent__text a {
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 1px;
}

.consent__actions {
  display: flex;
  gap: var(--s3);
  flex: none;
}

@media (max-width: 48rem) {
  .consent { padding-inline: var(--s6); }
  .consent__actions { width: 100%; }
  .consent__actions .btn { flex: 1; }
}

/* The privacy page's live copy of the current choice. */
.consent-state {
  font-family: var(--mono);
  font-size: 0.8125rem;
  color: var(--ink-soft);
  margin-bottom: var(--s4);
}
