/* gledach.de
   =========================================================================
   The ledger system. Adapted from the Refero "Stripe" style, chosen from
   three prototypes in October 2026. The prototypes are kept in prototypes/
   and are excluded from deployment.

   Signature, in one line: weight 300 at display size, one indigo for every
   action, 4px corners, and no shadows anywhere. Depth is a background tint
   progression (white, mist, frost, periwinkle, indigo) plus 1px hairlines
   and 96px gaps. If you reach for a box-shadow, the answer is a tint step.

   Four standing decisions, each paid for once:

   1. The indigo #533afd is the only chromatic colour. It carries actions,
      links, eyebrows, command names in code, and the leading-watcher flag.
      That is already four jobs, which is one more than the source style
      allows. It holds because the last two are monospace and uppercase at
      11px, which nobody reads as a link. Do not give it a fifth.
   2. Muted greys never set a paragraph. Body copy is --midnight-ink. Steel
      and slate are for captions, labels and cadence lines only.
   3. Smoke #839bc8 fails contrast on white at 2.82:1 and is kept out of
      text entirely. It exists in the palette and has no permitted use here.
   4. Tabular numerals are on globally. Most of this site is figures.
   ========================================================================= */

:root {
  /* chroma: one colour, and its two hover and border derivatives */
  --indigo-ink:   #533afd;
  --indigo-hover: #7389ff;
  --indigo-press: #4229e8;
  --lavender:     #b9b9f9;   /* ghost button outlines, emphasised card edges */
  --lilac:        #d6d9fc;   /* dividers inside tinted sections */
  --periwinkle:   #e8e9ff;   /* the deepest tint before the indigo itself */

  /* neutrals */
  --midnight-ink: #061b31;   /* headings and every paragraph */
  --steel:        #50617a;   /* captions and helpers */
  --slate:        #64748d;   /* cadence lines, quiet labels, de-emphasis */
  --white:        #ffffff;
  --mist:         #f8fafd;
  --frost:        #e5edf5;

  --font: 'Inter Tight', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;

  /* major second, 1.125. Tracking tightens as size grows. */
  --text-display: 56px;      --leading-display: 1.03;    --tracking-display: -1.4px;
  --text-heading-lg: 48px;   --leading-heading-lg: 1.03; --tracking-heading-lg: -0.96px;
  --text-heading: 32px;      --leading-heading: 1.1;     --tracking-heading: -0.64px;
  --text-heading-sm: 26px;   --leading-heading-sm: 1.12; --tracking-heading-sm: -0.26px;
  --text-subheading: 22px;   --leading-subheading: 1.1;  --tracking-subheading: -0.22px;
  --text-body-lg: 20px;      --leading-body-lg: 1.4;     --tracking-body-lg: -0.2px;
  --text-body: 16px;         --leading-body: 1.5;        --tracking-body: -0.16px;
  --text-body-sm: 14px;      --leading-body-sm: 1.4;     --tracking-body-sm: -0.14px;
  --text-caption: 12px;      --leading-caption: 1.45;    --tracking-caption: -0.12px;

  --s-8: 8px;   --s-16: 16px; --s-24: 24px; --s-32: 32px;
  --s-40: 40px; --s-48: 48px; --s-64: 64px; --s-80: 80px; --s-96: 96px;

  --max: 1320px;
  --radius: 4px;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--white);
  color: var(--midnight-ink);
  font-family: var(--font);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-body);
  font-weight: 400;
  font-feature-settings: "ss01" on, "tnum" on;
  -webkit-font-smoothing: antialiased;
}

/* The nav is sticky at 69px, so an anchor target has to clear it. */
[id] { scroll-margin-top: 96px; }

.skip {
  position: absolute; left: -9999px;
  background: var(--indigo-ink); color: var(--white);
  padding: 12px var(--s-16); border-radius: var(--radius);
  z-index: 20;
}
.skip:focus { left: var(--s-16); top: var(--s-16); }

/* ── layout ──────────────────────────────────────────────────────── */
.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--s-40); }
.sec { padding: var(--s-96) 0; border-top: 1px solid var(--frost); }
.sec-first { border-top: 0; }
.tint-mist { background: var(--mist); }
.tint-frost { background: var(--frost); }
.tint-peri  { background: var(--periwinkle); }

.measure { max-width: 64ch; }
.measure-tight { max-width: 46ch; }

/* ── type ────────────────────────────────────────────────────────── */
h1, h2, h3, h4 { font-weight: 300; margin: 0; }
.t-display { font-size: clamp(36px, 5.2vw, var(--text-display)); line-height: var(--leading-display); letter-spacing: var(--tracking-display); }
.t-h-lg    { font-size: clamp(32px, 4vw, var(--text-heading-lg)); line-height: var(--leading-heading-lg); letter-spacing: var(--tracking-heading-lg); }
.t-h       { font-size: var(--text-heading); line-height: var(--leading-heading); letter-spacing: var(--tracking-heading); }
.t-h-sm    { font-size: var(--text-heading-sm); line-height: var(--leading-heading-sm); letter-spacing: var(--tracking-heading-sm); }
.t-sub     { font-size: var(--text-subheading); line-height: var(--leading-subheading); letter-spacing: var(--tracking-subheading); font-weight: 300; }
.t-lg      { font-size: var(--text-body-lg); line-height: var(--leading-body-lg); letter-spacing: var(--tracking-body-lg); font-weight: 300; }
.t-sm      { font-size: var(--text-body-sm); line-height: var(--leading-body-sm); letter-spacing: var(--tracking-body-sm); }
.t-cap     { font-size: var(--text-caption); line-height: var(--leading-caption); letter-spacing: var(--tracking-caption); font-weight: 300; color: var(--steel); }

p { margin: 0 0 var(--s-16); }
p:last-child { margin-bottom: 0; }

/* The de-emphasised clause in a display headline. Slate at 4.75:1, not the
   indigo: colour on this page means clickable and a headline is not. */
.quiet { color: var(--slate); font-style: normal; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--indigo-ink);
  margin: 0 0 var(--s-16);
}
.eyebrow-quiet { color: var(--steel); }

code, .mono { font-family: var(--font-mono); font-size: 0.875em; }

a { color: var(--indigo-ink); text-decoration: none; }
a:hover { color: var(--indigo-hover); }
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--indigo-ink);
  outline-offset: 2px;
  border-radius: var(--radius);
}

/* ── buttons: a fill paired with a ghost outline ─────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: var(--s-8);
  font-family: var(--font);
  font-size: var(--text-body-sm);
  font-weight: 400;
  letter-spacing: var(--tracking-body-sm);
  border-radius: var(--radius);
  min-height: 44px;
  padding: 11px var(--s-24);
  border: 1px solid transparent;
  cursor: pointer;
}
.btn-fill { background: var(--indigo-ink); color: var(--white); }
.btn-fill:hover { background: var(--indigo-press); color: var(--white); }
.btn-ghost { color: var(--indigo-ink); border-color: var(--lavender); background: transparent; }
.btn-ghost:hover { border-color: var(--indigo-ink); }
.btn-reverse { background: var(--white); color: var(--indigo-ink); }
.btn-reverse:hover { background: var(--white); color: var(--indigo-press); }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-16); margin-top: var(--s-32); }
.arrow { font-size: 1.1em; line-height: 1; }

/* ── section header: heading left, lead right, hairline under ────── */
.head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s-64);
  align-items: end;
  padding-bottom: var(--s-32);
  border-bottom: 1px solid var(--frost);
  margin-bottom: var(--s-48);
}
.tint-frost .head, .tint-peri .head { border-bottom-color: var(--lilac); }

/* ── nav ─────────────────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 10;
  background: var(--white);
  border-bottom: 1px solid var(--frost);
}
.nav-in {
  max-width: var(--max); margin: 0 auto;
  padding: var(--s-16) var(--s-40);
  display: flex; align-items: center; gap: var(--s-32);
}
.brand {
  display: flex; align-items: center; gap: 10px;
  font-size: var(--text-subheading);
  font-weight: 300;
  letter-spacing: -0.4px;
  color: var(--midnight-ink);
}
.brand:hover { color: var(--midnight-ink); }
.brand-mark { display: inline-flex; gap: 3px; }
.brand-mark i { width: 3px; height: 16px; background: var(--indigo-ink); border-radius: 1px; }
.brand-mark i:nth-child(2) { height: 11px; align-self: flex-end; opacity: 0.6; }
.brand-mark i:nth-child(3) { height: 7px;  align-self: flex-end; opacity: 0.35; }
/* ── brandbar: organisation, then the tool you are in, then the rest ──
   The nav used to carry either five section anchors (index) or five tool
   names (satellites), and neither said that gledach is the organisation and
   the tool is one of its five. This does: `gledach | signal ...`, the same
   shape on every page, with the current tool named and the others behind a
   disclosure. */
.brandbar { display: flex; align-items: center; gap: 10px; }
.brand-sep { width: 1px; height: 18px; background: var(--frost); flex: none; }
.brand-tool {
  font-size: var(--text-subheading);
  font-weight: 400;
  letter-spacing: -0.4px;
  color: var(--midnight-ink);
}
.brand-tool:hover { color: var(--indigo-ink); }
/* On its own page the tool name is where you are, not somewhere to go, so it
   is ink rather than the link colour. The dots are how you leave. */
.brand-tool[aria-current="page"] { color: var(--midnight-ink); cursor: default; }

/* ── the overflow menu ───────────────────────────────────────────────
   A <details> rather than a scripted dropdown, so it opens, closes and takes
   the keyboard with JavaScript off. assets/site.js only adds Escape and
   outside-click dismissal, which are the two things <details> lacks. */
.toolmenu { position: relative; flex: none; }
.toolmenu > summary {
  list-style: none;
  display: grid;
  place-items: center;
  width: 32px; height: 32px;
  border-radius: var(--radius);
  cursor: pointer;
  color: var(--steel);
}
.toolmenu > summary::-webkit-details-marker { display: none; }
.toolmenu > summary:hover { background: var(--mist); color: var(--indigo-ink); }
.toolmenu > summary:focus-visible { outline: 2px solid var(--indigo-ink); outline-offset: 2px; }
.toolmenu[open] > summary { background: var(--periwinkle); color: var(--indigo-ink); }
.dots { display: flex; gap: 3px; }
.dots i { width: 3px; height: 3px; border-radius: 50%; background: currentColor; }

.toolmenu-panel {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  z-index: 20;
  width: 340px;
  background: var(--white);
  border: 1px solid var(--frost);
  border-radius: var(--radius);
  padding: var(--s-8);
}
.toolmenu-head {
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--steel);
  margin: 0;
  padding: var(--s-8) var(--s-8) var(--s-12);
}
.toolmenu-list { list-style: none; margin: 0; padding: 0; }
.toolmenu-list a {
  display: block;
  padding: 10px var(--s-8);
  border-radius: var(--radius);
  color: var(--midnight-ink);
}
.toolmenu-list a:hover { background: var(--mist); color: var(--midnight-ink); }
.toolmenu-list a:hover b { color: var(--indigo-ink); }
.toolmenu-list b {
  display: block;
  font-size: var(--text-body);
  font-weight: 400;
  letter-spacing: var(--tracking-body);
}
.toolmenu-list span {
  display: block;
  font-size: var(--text-caption);
  line-height: var(--leading-caption);
  color: var(--steel);
  margin-top: 2px;
}
.toolmenu-list .tm-slot {
  display: inline;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--slate);
  margin-left: 6px;
}
.toolmenu-list a[aria-current="page"] { background: var(--periwinkle); }
.toolmenu-list a[aria-current="page"] b { color: var(--indigo-ink); }
.toolmenu-foot {
  margin: var(--s-8) 0 0;
  padding: var(--s-12) var(--s-8) var(--s-8);
  border-top: 1px solid var(--frost);
  font-size: var(--text-caption);
  color: var(--steel);
}

.nav-links { display: flex; gap: var(--s-24); margin-left: auto; font-size: var(--text-body-sm); }
.nav-links a { color: var(--steel); }
.nav-links a:hover { color: var(--indigo-ink); }
.nav-links a[aria-current="page"] { color: var(--midnight-ink); }
.nav-cta { display: flex; gap: var(--s-8); }
.nav-cta .btn { min-height: 36px; padding: 7px 14px; }

/* ── hero ────────────────────────────────────────────────────────── */
.hero { padding: var(--s-96) 0 var(--s-80); }
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: var(--s-80);
  align-items: center;
}
.hero-meta { font-size: var(--text-caption); color: var(--steel); margin-top: var(--s-32); }

/* ── console: the frosted panel that carries real output ─────────── */
.console {
  background: var(--mist);
  border: 1px solid var(--frost);
  border-radius: var(--radius);
  overflow: clip;
  margin: 0;
}
.console-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-16);
  padding: 10px var(--s-16);
  border-bottom: 1px solid var(--frost);
  background: var(--white);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--steel);
}
.console pre {
  margin: 0;
  padding: var(--s-24);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  overflow-x: auto;
  color: var(--midnight-ink);
}
.console figcaption { padding: 0 var(--s-24) var(--s-24); }

/* Block elements (U+2581 to U+2588) and box drawing (U+2500) only work if one
   font supplies them all. A face that lacks them falls back per character at a
   different advance width and the columns collapse; a face that has them but
   draws U+2500 near the baseline turns a table rule into a row of underscores.
   Any pre containing either pins its own stack. */
/* Specificity matters here: `.console pre` is (0,1,1) and would beat a bare
   `.blocks` at (0,1,0), which made an earlier version of this rule a no-op. */
.blocks, .console pre.blocks, .cmd pre.blocks, .band pre.blocks {
  font-family: Consolas, 'DejaVu Sans Mono', 'Liberation Mono', 'Courier New', monospace;
}

/* Two tokens in a code block and no more: the binary in indigo, the trailing
   comment muted. A full syntax theme would put more colour on the page than
   this system has room for. */
.c-bin { color: var(--indigo-ink); font-weight: 500; }
.c-cmt { color: var(--slate); }

/* ── copy block. assets/site.js finds [data-copy] and the <code> in it. ── */
.cmd {
  position: relative;
  background: var(--mist);
  border: 1px solid var(--frost);
  border-radius: var(--radius);
}
.cmd pre {
  margin: 0;
  padding: var(--s-24) 84px var(--s-24) var(--s-24);
  overflow-x: auto;
}
.cmd code {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.7;
  display: block;
}
.copy {
  position: absolute; top: 10px; right: 10px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  background: var(--white);
  color: var(--indigo-ink);
  border: 1px solid var(--lavender);
  border-radius: var(--radius);
  padding: 7px 12px;
  min-height: 32px;
  cursor: pointer;
}
.copy:hover { border-color: var(--indigo-ink); }
.copy[data-done] { background: var(--indigo-ink); color: var(--white); border-color: var(--indigo-ink); }

.figure-note { font-size: var(--text-caption); line-height: var(--leading-caption); color: var(--steel); margin-top: var(--s-16); max-width: 76ch; }

/* ── the ink ground, for the product views ───────────────────────────
   This section used to be tint-mist, a very pale blue, behind captures
   that are themselves mostly pale. The whole block read as one
   low-contrast wash and the prose sitting against it had nothing to
   push off. Ink fixes both: the captures pop in a white frame, and
   white text on ink is the most readable combination on the site.

   Indigo scores 1.6:1 on ink and is unusable here, so labels and links
   take lavender (8.9:1) and prose takes white (17.4:1) or lilac. */
.tint-ink { background: var(--midnight-ink); color: var(--white); }
.tint-ink h2, .tint-ink h3, .tint-ink .t-lg { color: var(--white); }
.tint-ink .eyebrow { color: var(--lavender); }
.tint-ink .head { border-bottom-color: #1b3350; }
.tint-ink .figure-note { color: var(--lilac); }
.tint-ink a { color: var(--lavender); }
.tint-ink a:hover { color: var(--white); }

/* ── product capture, and the words that go with it ──────────────────
   The captures stay. A reader deciding whether to run `npm run view`
   needs to see the actual screen they will get, and a rebuilt facsimile
   does not prove that.

   What was wrong was never the image, it was the prose. It sat inside
   the same white card as the capture at 14px steel, so a dense
   screenshot and its explanation were competing inside one box with a
   hairline between them, and the explanation lost.

   So the words now live outside the card entirely, on the ink ground,
   in white at 22px. Maximum separation: prose on dark, image in a white
   frame. They stop competing because they are no longer the same
   object. The caption also comes first, so you read what to look for
   before you look. */
.view { margin: 0 0 var(--s-64); }
.view:last-of-type { margin-bottom: 0; }

.view-label {
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--lavender);
  margin: 0 0 var(--s-12);
}
.view-say {
  margin: 0 0 var(--s-16);
  max-width: 74ch;
  font-size: var(--text-subheading);
  font-weight: 300;
  line-height: 1.4;
  letter-spacing: var(--tracking-subheading);
  color: var(--white);
}
.view-say b { font-weight: 500; }
.view-note {
  margin: 0 0 var(--s-24);
  max-width: 82ch;
  font-size: var(--text-body-sm);
  line-height: 1.55;
  letter-spacing: var(--tracking-body-sm);
  color: var(--lilac);
}
.view-note code { color: var(--white); }

/* A white mat around the capture, so a busy screenshot has a quiet
   border rather than bleeding to the edge of its own frame. */
.view-shot {
  background: var(--white);
  border-radius: var(--radius);
  padding: 14px;
  overflow: clip;
}
.view-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--frost);
  border-radius: 2px;
}

/* ── numbered setup steps ────────────────────────────────────────── */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-16); }
.step {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: var(--s-32);
  background: var(--white);
  border: 1px solid var(--frost);
  border-radius: var(--radius);
  padding: var(--s-32);
}
.step-n { font-family: var(--font-mono); font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.08em; color: var(--indigo-ink); margin: 0; }
.step-n span {
  display: block;
  font-family: var(--font);
  font-size: var(--text-heading-sm);
  font-weight: 300;
  letter-spacing: var(--tracking-heading-sm);
  text-transform: none;
  color: var(--midnight-ink);
  margin-top: 6px;
}
/* The measure belongs on the prose, not on the card's whole right column:
   capping the column left a third of every step empty and made the code
   blocks narrower than they need to be. */
.step-body > p { max-width: 70ch; }

/* ── tag ─────────────────────────────────────────────────────────── */
.tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500;
  letter-spacing: 0.02em;
  padding: 3px var(--s-8);
  border-radius: var(--radius);
  background: var(--periwinkle);
  color: var(--indigo-ink);
}
.tag-quiet { background: var(--frost); color: var(--steel); }

/* ── tiles: the growth unit. A twelfth source is one more tile. ──── */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--s-16);
}
.tile {
  background: var(--white);
  border: 1px solid var(--frost);
  border-radius: var(--radius);
  padding: var(--s-24);
  display: flex; flex-direction: column; gap: var(--s-12);
}
.tile-lead { border-color: var(--lavender); }
.tile-n { font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: 0.08em; color: var(--slate); margin: 0; }
.tile-name {
  font-size: var(--text-subheading);
  font-weight: 300;
  line-height: var(--leading-subheading);
  letter-spacing: var(--tracking-subheading);
}
.tile-name .mono { display: block; font-size: 12px; font-weight: 500; letter-spacing: 0; color: var(--indigo-ink); margin-top: 5px; }
.tile-what { font-size: var(--text-body-sm); line-height: var(--leading-body-sm); letter-spacing: var(--tracking-body-sm); margin: 0; }
.tile-cad {
  margin: auto 0 0;
  padding-top: var(--s-12);
  border-top: 1px solid var(--frost);
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--slate);
}
.tile-lead .tile-cad { color: var(--indigo-ink); }
.tile-empty { background: transparent; border-style: dashed; }
.tile-empty .tile-name, .tile-empty .tile-cad { color: var(--slate); }

/* ── rail: stages, walking up the tint progression ───────────────── */
.rail { display: grid; gap: 1px; background: var(--frost); border: 1px solid var(--frost); border-radius: var(--radius); overflow: clip; }
.rail-step { padding: var(--s-32); display: grid; grid-template-columns: 170px minmax(0, 1fr); gap: var(--s-32); }
.rail-step:nth-child(1) { background: var(--white); }
.rail-step:nth-child(2) { background: var(--mist); }
.rail-step:nth-child(3) { background: #f1f5fb; }
.rail-step:nth-child(4) { background: var(--frost); }
.rail-step:nth-child(5) { background: var(--periwinkle); }
.rail-label { font-family: var(--font-mono); font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.08em; color: var(--indigo-ink); margin: 0; }
.rail-label span {
  display: block;
  font-family: var(--font);
  font-size: var(--text-heading-sm);
  font-weight: 300;
  letter-spacing: var(--tracking-heading-sm);
  text-transform: none;
  color: var(--midnight-ink);
  margin-top: 6px;
}
.rail-body { max-width: 68ch; }

/* ── stat row ────────────────────────────────────────────────────── */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); margin: 0; border-top: 1px solid var(--frost); }
.stats > div { padding: var(--s-24) var(--s-24) var(--s-24) 0; border-bottom: 1px solid var(--frost); }
.stats dt { font-family: var(--font-mono); font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.08em; color: var(--steel); }
.stats dd { margin: var(--s-8) 0; font-size: var(--text-heading-lg); font-weight: 300; line-height: 1; letter-spacing: var(--tracking-heading-lg); }
.stats p { font-size: var(--text-caption); color: var(--steel); margin: 0; }

/* ── cards ───────────────────────────────────────────────────────── */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: var(--s-24); }
.card {
  background: var(--white);
  border: 1px solid var(--frost);
  border-radius: var(--radius);
  padding: var(--s-32);
  display: flex; flex-direction: column; gap: var(--s-16);
}
.card-emph { border-color: var(--lavender); }
.card-go { margin-top: auto; font-size: var(--text-body-sm); }
.card-slot { border-style: dashed; background: transparent; }
a.card { color: var(--midnight-ink); }
a.card:hover { border-color: var(--lavender); color: var(--midnight-ink); }
a.card:hover .card-go { color: var(--indigo-hover); }
a.card .card-go { color: var(--indigo-ink); }

/* ── the indigo band. One per page, and it is the retargeting call. ── */
.band {
  background: var(--indigo-ink);
  color: var(--white);
  border-radius: var(--radius);
  padding: var(--s-48);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: var(--s-64);
  align-items: center;
}
.band a { color: var(--white); }
/* The reverse button is white-filled, so it has to win its ink back from the
   rule above or it renders white on white. */
.band a.btn-reverse { color: var(--indigo-ink); }
.band .eyebrow { color: var(--lavender); }
.band .t-cap { color: var(--lilac); }
/* A white console on the indigo field, so command names can be the real
   accent. Tinting the panel darker forced them to lilac, which is not a blue
   a reader registers as a command. */
.band pre {
  margin: 0;
  background: var(--white);
  border: 1px solid var(--lavender);
  border-radius: var(--radius);
  padding: var(--s-24);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  overflow-x: auto;
  color: var(--midnight-ink);
}

/* ── lead-time bars ──────────────────────────────────────────────── */
.bars { list-style: none; margin: 0; padding: 0; }
.bars li { display: grid; grid-template-columns: 130px minmax(0, 1fr) 118px; gap: var(--s-16); align-items: center; padding: 7px 0; font-size: var(--text-body-sm); }
.bar-track { height: 8px; background: var(--frost); border-radius: 2px; overflow: clip; }
.tint-mist .bar-track, .tint-frost .bar-track { background: var(--lilac); }
.bar-fill { display: block; height: 100%; width: var(--w); background: var(--indigo-ink); border-radius: 2px; }
.bars li:nth-child(n+4) .bar-fill { background: var(--lavender); }
.bar-lag { text-align: right; color: var(--steel); font-size: var(--text-caption); }

/* ── spec table: registers, data sources, grades ─────────────────── */
.spec { width: 100%; border-collapse: collapse; font-size: var(--text-body-sm); }
.spec th, .spec td { text-align: left; padding: var(--s-16) var(--s-16) var(--s-16) 0; border-bottom: 1px solid var(--frost); vertical-align: top; }
.spec thead th {
  font-family: var(--font-mono);
  font-size: 11px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--steel);
  padding-top: 0;
  border-bottom-color: var(--lilac);
}
.spec tbody th { font-weight: 400; }
.spec tbody th .mono { display: block; font-size: 11px; font-weight: 500; color: var(--indigo-ink); margin-top: 3px; }
.spec tr:last-child th, .spec tr:last-child td { border-bottom: 0; }

/* ── blind spots: the audit every tool ships ─────────────────────── */
.blind { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--s-32); }
.blind li { max-width: 50ch; padding-left: var(--s-16); border-left: 2px solid var(--lavender); }
.blind b { font-weight: 500; }

/* ── house rules ─────────────────────────────────────────────────── */
.rules { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--s-40); }
.rules li { max-width: 44ch; }
.rules h3 { font-size: var(--text-body-lg); letter-spacing: var(--tracking-body-lg); margin-bottom: var(--s-8); }

/* ── satellite page head ─────────────────────────────────────────── */
.crumb { font-family: var(--font-mono); font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.08em; margin: 0 0 var(--s-24); }
.crumb a { color: var(--steel); }
.crumb a:hover { color: var(--indigo-ink); }
.crumb span { color: var(--slate); }

/* ── 404 ─────────────────────────────────────────────────────────── */
.lost { padding: var(--s-96) 0; }

/* ── footer ──────────────────────────────────────────────────────── */
.foot { background: var(--mist); border-top: 1px solid var(--frost); padding: var(--s-64) 0 var(--s-40); }
.foot-cols { display: grid; grid-template-columns: 1.4fr repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-40); }
.foot-list { list-style: none; margin: 0; padding: 0; font-size: var(--text-body-sm); }
.foot-list li { padding: 4px 0; }
.foot-list a { color: var(--steel); }
.foot-list a:hover { color: var(--indigo-ink); }
.foot-bottom { margin-top: var(--s-48); padding-top: var(--s-24); border-top: 1px solid var(--frost); display: flex; justify-content: space-between; gap: var(--s-24); flex-wrap: wrap; }

/* ── micro-interaction ───────────────────────────────────────────────
   Feedback, not decoration, and a different thing from the two
   scroll-driven animations below. Those explain a mechanism. These
   answer "did that register?", which is the other legitimate reason for
   motion on a page like this.

   Three rules hold the whole block together:

   1. Only on something you can actually interact with. A transition on a
      static card teaches a reader it is clickable when it is not, which
      is why the collection tiles and the stat rows are not in this list
      despite being the most tempting things to animate.
   2. Never on `outline`. A focus ring has to appear the instant the key
      is pressed; easing it in makes keyboard navigation feel broken.
      Only colour and border are transitioned, so focus stays instant.
   3. Fast enough to feel like causation. 120ms reads as the element
      responding, 300ms reads as an effect playing.

   All of it sits inside a reduced-motion guard, so the site keeps every
   hover state and simply snaps to it. */
@media (prefers-reduced-motion: no-preference) {
  .btn,
  .copy,
  a.card,
  .toolmenu > summary,
  .toolmenu-list a,
  .nav-links a,
  .foot-list a,
  .brand-tool,
  a:not(.card):not(.btn) {
    transition: color 120ms ease, background-color 120ms ease,
                border-color 120ms ease;
  }

  /* An arrow that nudges toward where it is taking you. The only
     ornamental motion here, and it earns the exception by pointing. */
  .arrow, .card-go { transition: transform 150ms ease; }
  .btn:hover .arrow { transform: translateX(3px); }
  a.card:hover .card-go { transform: translateX(2px); }

  /* A press needs an acknowledgement separate from hover, or a click on
     an already-hovered button produces no feedback at all. */
  .btn:active, .copy:active { transform: translateY(1px); }

  /* The menu panel. Base style is the resting state and the keyframe
     supplies a "from" only, which is the same discipline the scroll
     animations below follow. */
  .toolmenu[open] .toolmenu-panel { animation: menu-in 140ms ease-out; }
  @keyframes menu-in { from { opacity: 0; transform: translateY(-4px); } }
}

/* ── entry motion: reveal once, then stay ────────────────────────────
   This was a `view()` timeline, and a view timeline does not play, it
   scrubs. Scroll back up and every card faded out again; scroll down and
   it replayed. The hero looked right only because it was timed rather
   than scroll-driven, which is the inconsistency that gave it away.

   So entry is now class-driven and plays exactly once. assets/site.js
   adds `is-pre` to anything still below the fold, watches it with an
   IntersectionObserver, and on first intersection swaps `is-pre` for
   `is-in` and stops watching. Scrolling back up changes nothing.

   The no-JavaScript guarantee is stronger than before, not weaker: the
   hidden state is applied by script, so with JavaScript off nothing is
   ever hidden and the page is simply complete. Elements already on
   screen when the script runs are skipped entirely, so there is no
   flash of content being hidden after paint.

   `is-pre` is removed at the moment `is-in` is added, and that ordering
   matters. A keyframe set with only a `from` takes its implicit `to`
   from the element's computed style, so leaving `is-pre` on would make
   the animation end at opacity 0: it would fade in and then vanish.
   ------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  .is-pre { opacity: 0; transform: translateY(14px); }
  .view-shot.is-pre { transform: translateY(16px) scale(0.985); }
  .bars.is-pre .bar-fill { width: 0; }

  .is-in {
    animation: reveal 620ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
    /* Items in one row intersect together, so the wave has to come from
       a delay here rather than from a scroll offset. --wave is set by
       column further down and cycles every four. */
    animation-delay: calc(var(--wave, 0) * 80ms);
  }
  @keyframes reveal { from { opacity: 0; transform: translateY(14px); } }

  /* A capture settles rather than appears. The scale is 0.985, small
     enough to register as weight rather than as a zoom. */
  .view-shot.is-in { animation-name: reveal-shot; animation-duration: 720ms; }
  @keyframes reveal-shot {
    from { opacity: 0; transform: translateY(16px) scale(0.985); }
  }

  /* The chart rows do not move. Only the fills grow, top to bottom,
     which is the ordering the chart is arguing for. */
  .bars.is-in { animation: none; }
  .bars.is-in .bar-fill {
    animation: grow 700ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
  @keyframes grow { from { width: 0; } }
  .bars.is-in li:nth-child(1) .bar-fill { animation-delay: 0ms; }
  .bars.is-in li:nth-child(2) .bar-fill { animation-delay: 70ms; }
  .bars.is-in li:nth-child(3) .bar-fill { animation-delay: 140ms; }
  .bars.is-in li:nth-child(4) .bar-fill { animation-delay: 210ms; }
  .bars.is-in li:nth-child(5) .bar-fill { animation-delay: 280ms; }
  .bars.is-in li:nth-child(6) .bar-fill { animation-delay: 350ms; }

  /* The wave, by column. Cycling every four means it repeats per row
     instead of running away across a twelve-item grid, and it does not
     need to know how many columns the grid actually resolved to. */
  :is(.cards, .tiles, .rules, .blind, .steps, .stats) > :nth-child(4n + 2) { --wave: 1; }
  :is(.cards, .tiles, .rules, .blind, .steps, .stats) > :nth-child(4n + 3) { --wave: 2; }
  :is(.cards, .tiles, .rules, .blind, .steps, .stats) > :nth-child(4n + 4) { --wave: 3; }
}

/* ── the hero, on load ───────────────────────────────────────────────
   Above the fold, so a scroll timeline is the wrong tool: it would be
   past its range before the page painted. A plain timed cascade instead,
   staged about 70ms apart, which is slow enough to read as sequence and
   fast enough that the whole hero has landed inside half a second.

   `both` means the element starts at the keyframe, so the page is briefly
   blank here before it runs. That is the one place this system accepts
   that trade, and only because it is a single paint on a static file.
   Everything below the fold keeps the finished state as its base. */
@media (prefers-reduced-motion: no-preference) {
  .hero > .wrap > *:not(.hero-grid),
  .hero-grid > div > *,
  .hero-grid > figure {
    animation: hero-in 560ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
  }
  @keyframes hero-in { from { opacity: 0; transform: translateY(12px); } }

  .hero > .wrap > :nth-child(1),
  .hero-grid > div > :nth-child(1) { animation-delay: 0ms; }
  .hero > .wrap > :nth-child(2),
  .hero-grid > div > :nth-child(2) { animation-delay: 70ms; }
  .hero > .wrap > :nth-child(3),
  .hero-grid > div > :nth-child(3) { animation-delay: 140ms; }
  .hero > .wrap > :nth-child(4),
  .hero-grid > div > :nth-child(4) { animation-delay: 210ms; }
  .hero > .wrap > :nth-child(5),
  .hero-grid > div > :nth-child(5) { animation-delay: 280ms; }

  /* The proof panel comes in with the copy rather than after all of it. */
  .hero-grid > figure { animation-delay: 160ms; }
}

/* The sticky nav earns its edge only once it is floating over content.
   At the very top it is part of the page and a hairline there is just a
   line. Base style is the edge, because that is the state it is in for
   all but the first 64px, and the keyframe takes it away at scroll 0.
   A browser without scroll() keeps the border permanently, which is the
   old behaviour and perfectly fine. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .nav {
      animation: nav-edge linear both;
      animation-timeline: scroll();
      animation-range: 0 64px;
    }
    @keyframes nav-edge { from { border-bottom-color: transparent; } }
  }
}

/* ── responsive ──────────────────────────────────────────────────── */
@media (max-width: 1000px) {
  .hero-grid, .head, .band { grid-template-columns: minmax(0, 1fr); gap: var(--s-40); }
  .head { align-items: start; }
  .rail-step { grid-template-columns: minmax(0, 1fr); gap: var(--s-16); }
  .nav-links { display: none; }
}
@media (max-width: 640px) {
  .wrap { padding: 0 var(--s-16); }
  .nav-in { padding-left: var(--s-16); padding-right: var(--s-16); }
  .sec { padding: var(--s-64) 0; }
  .band { padding: var(--s-32); }
  .bars li { grid-template-columns: 100px minmax(0, 1fr); }
  .bar-lag { grid-column: 2; text-align: left; }
  .spec thead { display: none; }
  .spec tbody th, .spec td { display: block; border-bottom: 0; padding: 2px 0; }
  .spec tbody tr { display: block; padding: var(--s-16) 0; border-bottom: 1px solid var(--frost); }
}
