/* ==========================================================================
   Colophon — design system
   colophonmethod.com · MIT Licence · Fabio Chinaglia

   Single source of truth for the marketing site. Hand-written CSS, no build
   step, no framework, no external request. The palette is the one already in
   the project's own icon.svg and one-pager; it is extended here, not replaced.

   Reading order
     0  fonts
     1  colour tokens
     2  scale tokens — type, space, measure, motion
     3  base & elements
     4  layout
     5  typography components
     6  links, buttons, focus
     7  components
     8  utilities
     9  motion, print, forced colours

   One rule governs colour: --point and --cell mean something. --point is the
   measured point, --cell is the occupied cell of the quadrant. Neither is ever
   used to make something look nice.
   ========================================================================== */


/* --------------------------------------------------------------------------
   0 · FONTS
   --------------------------------------------------------------------------
   The site ships with no font files and makes no external request. The stacks
   below resolve to fonts already on the reader's machine: an old-style serif
   for the prose, the platform monospace for the record.

   To use the project's own faces — EB Garamond and IBM Plex Mono, both open
   licence — drop the subset .woff2 files in assets/fonts/ and add ONE line to
   each page, before this stylesheet:

       <link rel="stylesheet" href="/assets/fonts.css">

   assets/fonts.css carries the @font-face rules and nothing else, so a site
   without the files never asks for them and never logs a 404. Self-hosted only:
   a Google Fonts <link> would send every reader's IP to a third party, which a
   project whose scripts send nothing anywhere cannot do. The argument is in
   docs/03-design-system.md.
   -------------------------------------------------------------------------- */

:root {
  /* Old-style serif, in order of typographic closeness to EB Garamond. */
  --font-serif: "EB Garamond", "Iowan Old Style", "Palatino Linotype", Palatino,
                "Book Antiqua", Georgia, "Times New Roman", serif;
  /* The record is monospaced everywhere: bytes, digests, commands, counts. */
  --font-mono:  "IBM Plex Mono", ui-monospace, SFMono-Regular, "SF Mono",
                Menlo, Consolas, "Liberation Mono", monospace;
}


/* --------------------------------------------------------------------------
   1 · COLOUR
   --------------------------------------------------------------------------
   Light is the default and is declared on bare :root. Dark is declared twice:
   under prefers-color-scheme for the system setting, and under [data-theme]
   for the explicit override the footer toggle writes. Every ratio below was
   measured, not estimated; the figures are in the design document.
   -------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  /* surfaces */
  --paper:      #fcfcfb;  /* the page */
  --panel:      #f4f4f3;  /* code, register, any inset block */
  --panel-2:    #eeeeec;  /* an inset inside an inset — used sparingly */

  /* text */
  --ink:        #16171a;  /* 17.5:1 on paper — body and headings */
  --quiet:      #5f6166;  /*  6.0:1 on paper,  5.6:1 on panel — secondary prose */
  --quieter:    #6b6d72;  /*  5.0:1 on paper,  4.7:1 on panel — eyebrows, microcopy */

  /* lines */
  --rule:       #d8d8d6;  /* decorative separators only, never a control edge */
  --rule-firm:  #8b8b88;  /* the edge of a control. 3.3:1 on paper, 3.1:1 on panel
                             — WCAG 1.4.11 applies here, so it is darker than --rule */

  /* semantics — see the rule at the top of this file */
  --point:      #e34948;  /* the measured point. Graphic mark. 3.9:1 on paper */
  --point-ink:  #c62f2e;  /* the same meaning, as text.        5.3:1 on paper */
  --cell:       #2a78d6;  /* the occupied cell. Graphic mark.  4.3:1 on paper */
  --cell-ink:   #1f5fae;  /* the same meaning, as text/links.  6.2:1 on paper */
  --cell-fill:  rgba(42,120,214,.09);

  /* the palimpsest: real bytes of a real register, showing through */
  --ghost:      rgba(22,23,26,.055);

  --focus:      var(--cell-ink);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --paper:     #131417;
    --panel:     #1b1c20;
    --panel-2:   #232429;
    --ink:       #e9e8e4;  /* 15.0:1 on paper */
    --quiet:     #9a9ba0;  /*  6.6:1 on paper, 6.1:1 on panel */
    --quieter:   #8a8c92;  /*  5.5:1 on paper, 5.1:1 on panel */
    --rule:      #2e3036;
    --rule-firm: #6a6e79;  /* 3.6:1 on paper, 3.3:1 on panel */
    --point:     #ff6b62;  /*  6.6:1 on paper — legible as text too */
    --point-ink: #ff8078;  /*  7.6:1 on paper */
    --cell:      #6aa6f0;  /*  7.3:1 on paper */
    --cell-ink:  #7fb3f4;  /*  8.5:1 on paper */
    --cell-fill: rgba(106,166,240,.12);
    --ghost:     rgba(233,232,228,.06);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --paper:     #131417;
  --panel:     #1b1c20;
  --panel-2:   #232429;
  --ink:       #e9e8e4;
  --quiet:     #9a9ba0;
  --quieter:   #8a8c92;
  --rule:      #2e3036;
  --rule-firm: #6a6e79;
  --point:     #ff6b62;
  --point-ink: #ff8078;
  --cell:      #6aa6f0;
  --cell-ink:  #7fb3f4;
  --cell-fill: rgba(106,166,240,.12);
  --ghost:     rgba(233,232,228,.06);
}


/* --------------------------------------------------------------------------
   2 · SCALE
   --------------------------------------------------------------------------
   Type is expressed in rem against the reader's own root size, never in px:
   a reader who has set 20px gets a 20px-based site. Body copy is 1.1875rem
   (19px at the 16px default), the size the one-pager settled on.
   -------------------------------------------------------------------------- */

:root {
  /* type scale — a slow ratio, because the page is a document, not a poster */
  --t-3xs:  0.6875rem;  /* 11px — the smallest legible mono, tabular only */
  --t-2xs:  0.75rem;    /* 12px — eyebrows, footer, technical line */
  --t-xs:   0.8125rem;  /* 13px — code inside a block, table numbers */
  --t-sm:   0.9375rem;  /* 15px — captions, secondary prose */
  --t-base: 1.1875rem;  /* 19px — body */
  --t-md:   1.3125rem;  /* 21px — lede, standfirst, pull quote */
  --t-lg:   1.5rem;     /* 24px — h3 */
  --t-xl:   1.875rem;   /* 30px — h2 */
  --t-2xl:  2.375rem;   /* 38px — page title on inner pages */
  --t-display: clamp(3rem, 11vw, 5rem);  /* the home masthead, only there */

  /* leading */
  --lh-tight: 1.05;
  --lh-head:  1.18;
  --lh-body:  1.58;   /* the one-pager's measure; comfortable at 19px */
  --lh-loose: 1.75;   /* mono blocks, where the eye tracks column not line */

  /* space — a 4px grid, named by step, used everywhere */
  --s-1:  0.25rem;
  --s-2:  0.5rem;
  --s-3:  0.75rem;
  --s-4:  1rem;
  --s-5:  1.5rem;
  --s-6:  2rem;
  --s-7:  3rem;
  --s-8:  4rem;
  --s-9:  6rem;
  --s-10: 8rem;

  /* measure — 34rem at 19px is roughly 66 characters */
  --measure:      34rem;   /* prose */
  --measure-mono: 46rem;   /* a register line and a folder tree set to the line */
  --col-wide:     58rem;   /* the container: tables, grids, the quadrant + readout */
  --gutter:       1.25rem;

  --radius: 2px;           /* almost none: this is a printed surface */
  --motion: 120ms;
}


/* --------------------------------------------------------------------------
   3 · BASE
   -------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: var(--t-base);
  line-height: var(--lh-body);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-weight: 500;
  letter-spacing: -.012em;
  line-height: var(--lh-head);
  margin: 0 0 var(--s-3);
  text-wrap: balance;
}
h1 { font-size: var(--t-2xl); line-height: var(--lh-tight); letter-spacing: -.02em; }
h2 { font-size: var(--t-xl); }
h3 { font-size: var(--t-lg); }
h4 {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: 0;
}

p, ul, ol, dl { margin: 0 0 var(--s-4); text-wrap: pretty; }
p:last-child, ul:last-child, ol:last-child { margin-bottom: 0; }

ul, ol { padding-left: 1.15em; }
li { margin-bottom: var(--s-2); }
li:last-child { margin-bottom: 0; }
li::marker { color: var(--quieter); }

strong, b { font-weight: 600; }
em, i { font-style: italic; }
small { font-size: var(--t-sm); }

hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: var(--s-7) 0;
}

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

abbr[title] { text-decoration: underline dotted; cursor: help; }

::selection { background: var(--cell-fill); }


/* --------------------------------------------------------------------------
   4 · LAYOUT
   --------------------------------------------------------------------------
   One column, centred, with an opt-in wide variant. No grid framework: the
   page has a measure and the exceptions to it are named.
   -------------------------------------------------------------------------- */

/* One container, one left edge. The container is the wide one; prose is held to
   the measure inside it, and the objects that carry data — tables, grids, the
   quadrant, the register — extend to the right of the text instead of being
   centred against it. The left edge therefore never moves, from page to page or
   from section to section, which is what makes the site read as one document. */
.page { max-width: var(--col-wide); margin: 0 auto; padding: 0 var(--gutter); }
/* Monospace needs more room than prose: a register line and a folder tree are
   set to the line, not to the measure. */
main .page > .code, main .page > .chain { max-width: var(--measure-mono); }
.facts { max-width: 48rem; }

/* A section is separated by a hairline, the way a book separates its parts. */
.band {
  border-top: 1px solid var(--rule);
  margin-top: var(--s-7);
  padding-top: var(--s-6);
}
/* The closing statement of a page: a heavier rule, once, near the end. */
.band--close { border-top: 2px solid var(--ink); }

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

/* Prose is held to the measure BY DEFAULT, and the exceptions are named.
   It used to be the other way round — `.measure` was opt-in — and the result
   was two line lengths on the same page: whatever carried the class wrapped at
   66 characters, whatever did not ran to 58rem and read as a different column.
   Nobody chooses that; it is what happens when the default is the exception.

   What is deliberately NOT held to the measure, and why: the objects that
   carry data rather than sentences — tables, the quadrant, the three-up grid,
   the two-column ledger, the link lists — extend to the right of the text
   instead of being centred against it, so the left edge never moves. That is
   §7.1, and it is the thing that makes the site read as one document. */
main .page > p,
main .page > .note,
main .page > .rule-block,
main .page > .terms,
main .page > blockquote { max-width: var(--measure); }
/* Controls are not prose: a row of buttons wraps on its own terms. */
main .page > .btn-row { max-width: none; }


@media (min-width: 40rem) { .two-up { grid-template-columns: 1fr 1fr; } }

.three-up { display: grid; gap: var(--s-5); }
@media (min-width: 44rem) { .three-up { grid-template-columns: repeat(3, 1fr); } }


/* --------------------------------------------------------------------------
   5 · TYPOGRAPHY COMPONENTS
   -------------------------------------------------------------------------- */

/* The section label. Mono, uppercase, tracked out: it belongs to the
   apparatus of the document, not to the prose. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--quieter);
  margin: 0 0 var(--s-4);
}

.display {
  font-size: var(--t-display);
  font-weight: 500;
  letter-spacing: -.025em;
  line-height: .95;
  margin: 0;
}

/* The italic line under the name. It is the project's motto and it is set
   the way a motto is set: italic, quiet, no quotation marks. */
.tagline {
  font-style: italic;
  font-size: var(--t-md);
  color: var(--quiet);
  margin: var(--s-2) 0 var(--s-5);
}

.standfirst { font-size: var(--t-md); max-width: var(--measure); margin: 0; }
.lede { font-size: 1.0625rem; }

/* The sentence a page is willing to be quoted on. */
.pull {
  font-size: var(--t-md);
  font-style: italic;
  margin: 0 0 var(--s-4);
  text-wrap: pretty;
}

.fine {
  font-size: var(--t-sm);
  color: var(--quiet);
}

/* A definition list used as a glossary of the four quadrant names, which stay
   in English in any language: they are the classes of a published taxonomy. */
.terms dt {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  color: var(--ink);
  margin-top: var(--s-4);
}
.terms dd { margin: var(--s-1) 0 0; color: var(--quiet); font-size: var(--t-sm); }

blockquote {
  margin: var(--s-5) 0;
  padding-left: var(--s-4);
  border-left: 2px solid var(--rule);
  color: var(--quiet);
}

code, kbd, samp {
  font-family: var(--font-mono);
  font-size: .84em;      /* mono runs large next to a serif; this evens it */
  font-variant-ligatures: none;
}
:not(pre) > code {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: .08em .3em;
  overflow-wrap: break-word;
}


/* --------------------------------------------------------------------------
   6 · LINKS, BUTTONS, FOCUS
   -------------------------------------------------------------------------- */

a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: .18em;
  text-decoration-color: var(--rule-firm);
  transition: text-decoration-color var(--motion) linear;
}
a:hover { text-decoration-color: currentColor; }

/* Focus is never removed and never subtle. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--paper);
  color: var(--ink);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--ink);
  z-index: 10;
}
.skip-link:focus { left: var(--s-4); top: var(--s-2); }

/* The button is a bordered word. No fill, no shadow, no gradient: the page is
   paper and a button is something stamped on it. The primary one is the only
   filled object on the site. */
.btn {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;      /* a long label plus its host still fits at 320px */
  gap: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  line-height: 1.2;
  letter-spacing: .01em;
  text-decoration: none;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  padding: .72rem 1rem;          /* ≥ 44px tall at every size */
  min-height: 44px;
  cursor: pointer;
  transition: border-color var(--motion) linear, background-color var(--motion) linear;
}
.btn:hover { border-color: var(--ink); background: var(--panel); }
.btn--primary {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.btn--primary:hover { background: var(--ink); opacity: .88; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-top: var(--s-5);
}

/* A link that is the end of a section rather than part of a sentence. */


/* --------------------------------------------------------------------------
   7 · COMPONENTS
   -------------------------------------------------------------------------- */

/* 7.1 · Masthead ---------------------------------------------------------- */
/* On every page except the home, where the hero is the masthead. */
.site-head {
  border-bottom: 1px solid var(--rule);
  padding: var(--s-4) 0;
  margin-bottom: var(--s-6);
}
.site-head .page {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-3) var(--s-5);
}
.wordmark {
  font-size: var(--t-lg);
  font-weight: 500;
  letter-spacing: -.015em;
  text-decoration: none;
}
.wordmark span { font-style: italic; color: var(--quiet); font-size: var(--t-sm); }
.site-nav { margin-left: auto; }
.site-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .04em;
}
.site-nav li { margin: 0; }
.site-nav a { text-decoration: none; color: var(--quiet); padding: var(--s-2) 0; display: inline-block; }
.site-nav a:hover { color: var(--ink); }
.site-nav a[aria-current="page"] { color: var(--ink); border-bottom: 1px solid var(--point); }

/* 7.2 · Hero and the palimpsest ------------------------------------------- */
/* The ghost layer is real bytes from a real register, at 5% ink. It is the
   argument of the site made visible: the earlier writing stays under the new.
   aria-hidden, pointer-events none, unselectable — it is texture, not text. */
.hero { position: relative; padding: var(--s-9) 0 var(--s-6); }
.ghost {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
  mask-image: linear-gradient(180deg, transparent, #000 16%, #000 58%, transparent 94%);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 16%, #000 58%, transparent 94%);
}
.ghost pre {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.5;
  color: var(--ghost);
  white-space: pre-wrap;
  word-break: break-all;
}
.hero > *:not(.ghost) { position: relative; }

/* 7.3 · Figure of fact ---------------------------------------------------- */
/* Two numbers that carry an argument. The number is mono and tabular because
   it is a measurement; the gloss beneath it is prose. */
.facts { display: grid; gap: var(--s-5); margin-top: var(--s-5); }
@media (min-width: 40rem) { .facts { grid-template-columns: 1fr 1fr; gap: var(--s-6); } }
.fact { border-left: 2px solid var(--rule); padding-left: var(--s-4); }
.fact-n {
  display: block;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 2.5rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -.03em;
}
.fact p { font-size: var(--t-sm); color: var(--quiet); margin: var(--s-3) 0 0; }

/* 7.4 · The quadrant and its readout -------------------------------------- */
/* The SVG is inline so it inherits the theme tokens. In production the icon of
   a case is generated by build_icon.py from kpi.json and is never drawn by
   hand; the one on the marketing pages is a copy of a generated file. */
.quad-wrap { display: grid; gap: var(--s-6); align-items: center; margin-top: var(--s-5); }
@media (min-width: 44rem) {
  /* Fixed tracks, not fractions: the readout has to sit beside the quadrant,
     not at the far edge of whatever space is left. */
  .quad-wrap { grid-template-columns: minmax(0, 26rem) minmax(0, 16rem); justify-content: start; }
}
/* The quadrant has a real minimum size — below about a hundred pixels a side
   the four labels stop being legible — and a real maximum: past 26rem it stops
   being a mark and starts being an illustration. */
.quad { width: 100%; max-width: 26rem; height: auto; display: block; }
.quad text { font-family: var(--font-mono); }

.readout { display: grid; gap: var(--s-4); }
.readout-n {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 2.1rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: -.03em;
}
.readout-l { font-size: var(--t-sm); color: var(--quiet); margin-top: var(--s-1); }

/* 7.5 · Note and callout --------------------------------------------------- */
/* Three weights, and the border colour is the meaning:
     .note          a rule of the method, stated once and not softened
     .note--point   a caution about a measurement — the point colour, earned
     .note--cell    a fact about the record itself                            */
.note {
  border-left: 2px solid var(--rule);
  padding: 0 0 0 var(--s-4);
  margin: var(--s-5) 0;
  font-size: var(--t-sm);
  color: var(--quiet);
}
.note--point { border-left-color: var(--point); }
.note--cell  { border-left-color: var(--cell); }
.note strong { color: var(--ink); }

/* The binding rule of a page: set at reading size, in the body colour, with a
   heavy left rule. Used once per page at most. */
.rule-block {
  border-left: 3px solid var(--ink);
  padding-left: var(--s-4);
  margin: var(--s-6) 0;
  font-size: var(--t-md);
}
.rule-block p { margin-bottom: var(--s-3); }
.rule-block p:last-child { margin-bottom: 0; font-size: var(--t-base); color: var(--quiet); }

/* 7.6 · Code block with copy ---------------------------------------------- */
/* Without JavaScript this is a <pre> you select and copy, which is what a
   terminal command has always been. The button is inserted by colophon.js and
   only when the clipboard API is actually available. */
.code {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  margin: var(--s-4) 0;
}
.code pre {
  margin: 0;
  padding: var(--s-4);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  line-height: var(--lh-loose);
  color: var(--ink);
  tab-size: 2;
}
.code pre code { background: none; border: 0; padding: 0; font-size: inherit; }
.code-label {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--quieter);
  padding: var(--s-3) var(--s-4) 0;
  display: block;
}
.copy {
  position: absolute;
  top: var(--s-2);
  right: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  min-height: 32px;
  padding: var(--s-2) var(--s-3);
  color: var(--quiet);
  background: var(--paper);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  cursor: pointer;
}
.copy:hover { color: var(--ink); border-color: var(--ink); }
.copy[data-state="done"] { color: var(--cell-ink); border-color: var(--cell); }

/* 7.7 · The register block ------------------------------------------------ */
/* Real lines of a real chain. The hashes are --cell because a digest is the
   thing the record is made of, not because blue is pretty. */
.chain {
  background: var(--panel);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--s-4);
  margin: var(--s-5) 0;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  line-height: var(--lh-loose);
  color: var(--quiet);
  white-space: pre;
}
.chain b { color: var(--ink); font-weight: 500; }
.chain .h { color: var(--cell-ink); }
.chain .gap { color: var(--quieter); }

/* 7.8 · Link list ---------------------------------------------------------- */
/* The navigation shape of the current site: a stack of rows, each a title and
   a line saying what is behind it. It reads as a table of contents. */
.linklist { margin: var(--s-5) 0 0; border-top: 1px solid var(--rule); }
.linklist a {
  display: block;
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
  transition: background-color var(--motion) linear;
}
.linklist a:hover { background: var(--panel); }
.linklist .t { font-size: var(--t-md); }
.linklist .d {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  line-height: 1.6;
  color: var(--quiet);
  margin-top: var(--s-1);
}

/* 7.9 · Table ------------------------------------------------------------- */
.tablewrap { overflow-x: auto; margin: var(--s-5) 0; }
table { border-collapse: collapse; width: 100%; font-size: var(--t-sm); }
caption {
  text-align: left;
  font-size: var(--t-sm);
  color: var(--quiet);
  padding-bottom: var(--s-3);
}
th, td {
  text-align: left;
  padding: var(--s-3) var(--s-3) var(--s-3) 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
thead th {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: var(--t-2xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--quieter);
}
td.num, th.num {
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  /* Right-aligned columns take their gutter on the left: two of them side by
     side would otherwise touch, because the right padding is zero so the last
     column sits flush with the measure. */
  padding-left: var(--s-5);
  padding-right: 0;
  white-space: nowrap;   /* a measured value does not wrap; .tablewrap scrolls */
}
tbody tr:last-child td { border-bottom: 0; }
td code { white-space: nowrap; }

/* 7.10 · Steps ------------------------------------------------------------ */
/* The working cycle. An ordered list whose numbers are set in mono in the
   margin, so the sequence is readable at a glance and the order is the point. */
.steps { list-style: none; margin: var(--s-5) 0 0; padding: 0; counter-reset: step; }
.steps > li {
  counter-increment: step;
  border-top: 1px solid var(--rule);
  padding: var(--s-5) 0 0;
  margin: 0 0 var(--s-5);
  position: relative;
}
.steps > li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .1em;
  color: var(--quieter);
  display: block;
  margin-bottom: var(--s-2);
}
@media (min-width: 48rem) {
  .steps > li { padding-left: 3.5rem; }
  .steps > li::before { position: absolute; left: 0; top: var(--s-5); margin: 0; }
}
.steps h3 { margin-bottom: var(--s-2); }

/* 7.11 · The case card, removed ---------------------------------------------
   Two bordered cards, each with a button that left the site in the middle of a
   page. The cases are already canonical inside signed manifests, so a second
   address for them here would be the one thing the method forbids, and an index
   whose every row is an exit is the flyer this site is written not to be. What
   the site owns is the comparison between the two, so the home now makes the
   comparison in a table and cites the numbers. Recorded here rather than
   deleted silently: a class that disappears without a reason gets reinvented.
   -------------------------------------------------------------------------- */

/* 7.12 · The boundary: outbound links and handoffs ------------------------ */
/* The site explains; GitHub distributes and hosts. Every useful path therefore
   ends outside, and the reader is told so BEFORE the click rather than after.
   There is no generic outbound icon anywhere on this site. An outbound link
   names its host instead, because the host is the thing a reader actually has
   to know before deciding — whose page is this — and an icon does not say it.
   The host is set in mono for the reason everything else on this site is:
   an address is reproducible byte for byte, so it belongs to the record family
   and not to the prose.

   The hierarchy is carried by the fill and by a rule, never by an ornament:
     filled ink        the site's own voice — it never leaves the site
     outlined          a move that continues inside the site
     outlined + host   a handoff
   and the heaviest rule on any page is always the site's own closing rule.
   The dashed rule below is the only broken line on the site: a perforation,
   and it means the document ends here.                                       */

/* The address, printed as part of the link and read as part of it. Host plus
   path, without the scheme; the em rule before it is the project's own mark of
   apposition, and it is a character, not an ornament. It has to wrap: a long
   address inside a control must not push the page sideways at 320px. */
.out-at {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .04em;
  color: var(--quieter);
  overflow-wrap: anywhere;
}
.out-at::before { content: "\2009\2014\2009"; }

/* An outbound link inside prose. At most one per paragraph: two mean the
   paragraph is really a handoff, and belongs in .handoff below. Never inside
   a heading, an eyebrow, a .pull or a .rule-block — the sentences the site
   wants to be quoted on do not send anybody away. */
.out { text-decoration-color: var(--rule-firm); }

/* An outbound control. Never .btn--primary: the one filled object on the site
   is the site's own ink, and the site does not use its own voice to send
   somebody elsewhere. In a row of controls the internal one comes first. */
.btn--out .out-at { color: var(--quiet); }

/* The handoff. Once per page at most, never above the page's own closing
   statement, and never given hero air: --s-5 of padding, not --s-9. When a
   whole block is a handoff — the issue grid on /contribute/ — the host is
   named once on the block and not on every control inside it. */
.handoff {
  border-top: 1px dashed var(--rule-firm);
  margin-top: var(--s-7);
  padding-top: var(--s-5);
}
.handoff > p {
  max-width: var(--measure);
  font-size: var(--t-sm);
  color: var(--quiet);
}
.handoff .linklist { margin-top: var(--s-4); border-top: 0; }

/* 7.13 · The verifier is NOT a component of this system --------------------
   There is deliberately no wrapper, no frame and no dropzone here. /verify/ is
   verifier/verify.html served byte for byte: framing it would break the byte
   identity with the copy inside every bundle, break the repo's invariance
   tests, invalidate the SHA-256 hashes the CSP authorises its inline script
   with, and take away the property the reader is promised — save that page and
   it keeps working with the network off. A page wrapped in a site cannot be
   saved on its own. The site explains the check at /checking/ and hands over;
   it never dresses the artefact.
   -------------------------------------------------------------------------- */

/* 7.14 · Issue grid -------------------------------------------------------- */
/* Contribute is the only page with a conversion, and the conversion is an
   issue. Each row is a kind of finding and the one place it belongs. */
@media (min-width: 46rem) {
  .channel { grid-template-columns: 15rem 1fr; gap: var(--s-5); }
}

/* 7.15 · Prove / does not prove ------------------------------------------- */
.ledger { display: grid; gap: var(--s-6); margin: var(--s-5) 0 0; }
@media (min-width: 44rem) { .ledger { grid-template-columns: 1fr 1fr; gap: var(--s-7); } }
.ledger h3 {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  font-weight: 400;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--quieter);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule);
  margin-bottom: var(--s-4);
}
.ledger ul { list-style: none; padding: 0; margin: 0; }
.ledger li { padding-left: var(--s-4); position: relative; margin-bottom: var(--s-4); }
.ledger li::before {
  position: absolute;
  left: 0;
  font-family: var(--font-mono);
  color: var(--quieter);
}
.ledger--yes li::before { content: "\2713"; }   /* proves */
.ledger--no  li::before { content: "\00d7"; }   /* does not prove */

/* 7.16 · Footer ------------------------------------------------------------ */
/* Minimal: one line of substance, one row of links. The site is not a Colophon
   case and its footer is not a colophon block — it is a document foot. */
.site-foot {
  margin-top: var(--s-9);
  border-top: 1px solid var(--rule);
  padding: var(--s-5) 0 var(--s-6);
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  line-height: 1.9;
  color: var(--quieter);
}
.site-foot a { color: var(--quiet); }
.site-foot a:hover { color: var(--ink); }
.site-foot p { margin: 0; max-width: 40rem; }
.foot-links {
  list-style: none;
  padding: 0;
  margin: var(--s-3) 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-4);
}
.foot-links li { margin: 0; }
/* The footer's Privacy link points at the page you are on when you are on it.
   Leaving it live would be a control that does nothing; marking it says so. */
.foot-links a[aria-current="page"] { color: var(--ink); text-decoration: none; cursor: default; }

/* 7.16b · Scambio di lingua — `.lang` -------------------------------------- */
/* Due parole e un punto medio, dentro la riga di link del footer. La lingua
   corrente non è un link: è inchiostro pieno, e non si può cliccare su dove
   già si è. Nessuna bandiera — una bandiera è un paese, non una lingua — e
   nessun <select>: due voci non sono un menu. §6.20. */
.lang { display: inline-flex; align-items: baseline; gap: .5ch; }
.lang .on { color: var(--ink); }
.lang .sep { color: var(--rule-firm); }

/* Theme toggle: inserted by colophon.js, absent without it, and absent is a
   correct state — prefers-color-scheme already did the work. */
.theme-toggle {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  min-height: 32px;
  padding: var(--s-2) var(--s-3);
  background: transparent;
  color: var(--quiet);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  cursor: pointer;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink); }

/* 7.17 · 404 --------------------------------------------------------------- */
.notfound { padding: var(--s-9) 0 var(--s-6); }
.notfound .code-404 {
  font-family: var(--font-mono);
  font-size: var(--t-2xs);
  letter-spacing: .16em;
  color: var(--point-ink);   /* --point is a graphic mark; as small text it needs 4.5:1 */
  margin: 0 0 var(--s-4);
}


/* --------------------------------------------------------------------------
   8 · UTILITIES
   -------------------------------------------------------------------------- */

.mono { font-family: var(--font-mono); font-size: .9em; }
.nums { font-variant-numeric: tabular-nums; }
.quiet { color: var(--quiet); }
.center { text-align: center; }
.mt-0 { margin-top: 0; }
.mt-5 { margin-top: var(--s-5); }
.mt-6 { margin-top: var(--s-6); }

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

[hidden] { display: none !important; }


/* --------------------------------------------------------------------------
   9 · MOTION, PRINT, FORCED COLOURS
   -------------------------------------------------------------------------- */

/* Nothing on this site animates position, scale or opacity. The only motion is
   a colour easing on hover, and it stops here when it is not wanted. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  :root { --paper: #fff; --ink: #000; --quiet: #444; --quieter: #555; --panel: #fff; }
  .site-nav, .copy, .theme-toggle, .skip-link, .ghost { display: none !important; }
  body { font-size: 11pt; }
  .page { max-width: none; }
  /* On paper the whole address is printed, so the host would be said twice. */
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
  .out-at { display: none; }
  .band, .code, .chain { break-inside: avoid; }
}

@media (forced-colors: active) {
  .btn, .code, .chain { border: 1px solid; }
  .handoff { border-top: 1px dashed; }
  .btn--primary { forced-color-adjust: none; }
  .ghost { display: none; }
}

/* 6.x · The mark ----------------------------------------------------------- */
/* The quadrant with its labels taken away: the frame, the two axes that divide
   it, and the measured point. It is the same figure the method produces, not a
   logo invented beside it — which is why the point keeps --point, the variable
   the quadrant itself uses, and never becomes decoration.
   Inline SVG, never <img>: an SVG loaded as an image sees only the operating
   system's colour scheme, so it would ignore the theme toggle and sit in the
   wrong palette on every page where a reader has overridden it. Inline, the
   frame takes currentColor and the point takes the variable. */
.mark { flex: none; display: block; }
.mark .mark-frame { fill: none; stroke: currentColor; stroke-width: 2; }
.mark .mark-axis  { stroke: currentColor; stroke-width: 1.4; opacity: .34; }
.mark .mark-point { fill: var(--point); }

/* In the masthead the mark is set to a little under the cap height and its
   bottom edge sits on the baseline of the wordmark: a square frame reads
   optically lighter than a letter stem of the same height, so matching cap
   height exactly would make it look small. */
.wordmark { display: inline-flex; align-items: baseline; gap: .42em; }
.wordmark .mark { width: .84em; height: .84em; }

/* In the hero the mark is larger but proportionally smaller against the
   display size, because at that size the frame no longer needs the help. */
/* The container carries the display size so the mark can be set in em against
   the title it stands beside, not against the body text it inherits from. */
.hero-title { display: flex; align-items: baseline; gap: .26em; font-size: var(--t-display); }
.hero-title .mark { width: .52em; height: .52em; }
.hero-title .mark .mark-frame { stroke-width: 1.5; }
.hero-title .mark .mark-axis { stroke-width: 1.1; }
/* The name keeps the wordmark's own weight: `.wordmark span` styles the
   tagline, and the name must not inherit it now that it is wrapped too. */
.wordmark .wordmark-name {
  font-style: normal;
  color: var(--ink);
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
}
