/**
 * OpenStamps for Furniture — the ONE visual system.
 *
 * Every public page links this file. Before 2026-09-03 launch.html carried one palette
 * (paper / pine / brass) and try.html, portal.html, phone.html and the legal pages carried
 * another (chalk / ash / a different pine / a different brass). Three templates glued together
 * is what a visitor saw. This file replaces all of them; a page may add a short <style> block for
 * layout that is genuinely its own, but it may not redefine a token below.
 *
 * Material: uncoated paper, pine-green ink, one brass accent, white cards, hairline rules.
 * Paper is the material; no dark mode. `color-scheme: light` below tells a browser whose user has
 * forced dark to leave the paper and the pine alone rather than invert them into a negative — a
 * dossier read as a negative is a dossier whose shapes still work, but its lamps do not.
 * Type: Source Serif 4 for display, Figtree for UI, ui-monospace for hashes and content ids.
 * Sizes come from the type scale (--fs-*) and gaps from the spacing scale (--sp-*) declared below;
 * a page's own <style> may not write a bare pixel font-size — scripts/check-visual-system.mjs lists
 * the ones that still do. Weights are 400, 600 and 700 only: fonts.css carries both families as
 * variable files spanning 400–700, so an 800 is never drawn by these fonts; the browser fakes it or
 * falls through to the system face.
 * Motion: almost none, and none at all under prefers-reduced-motion.
 *
 * The three states of a check render in SHAPE, not only colour — ◇/◈ holds (unrefuted),
 * ◔ not checked, ✕ refuted — because a dossier is photocopied in greyscale. There is no tick
 * anywhere in this system and scripts/check-display-law.mjs makes sure one never arrives.
 * Lights are red · amber · white · anchored. ⚠ The fourth light used to be called "green"; the word
 * green no longer names a light anywhere on the site (build brief 2026-09-04 §0). The old class is
 * kept below as an alias only until the last page stops emitting it.
 */

/* THE RULE COMES FIRST, THE STORY AFTER, and that order is the whole point. See below.
   ⚠ 2026-09-04: `hidden` must beat a display rule, or the attribute silently does nothing. Measured on
   account.html: #checking carries .status { display: flex }, so el.hidden = true left "Asking this
   deployment whether accounts are enabled…" on screen underneath the answer it was waiting for. */
[hidden] { display: none !important; }
/* ⚠⚠ 2026-09-05, AND THIS RULE HAS NOW BEEN KILLED TWICE BY THE PROSE AROUND IT.
   First it was inserted inside the header comment above: comments do not nest, so the header ended
   early and every declaration after it became garbage — the whole site rendered as unstyled text.
   Then the comment written to warn about that QUOTED the comment terminator, in inverted commas, to
   explain what had gone wrong. A CSS parser does not know the marker is inside a string: the warning
   comment ended at the quote, the prose after it became a malformed rule, and error recovery
   swallowed the very declaration it was guarding. Measured on account.html 2026-09-05: a .status
   element carrying `hidden` computed display:flex, so the rule had never worked from the day it was
   written, on any page. scripts/check-css-parses.mjs missed both because it counted only the markers
   it met while already inside a comment; it now fails on a terminator found outside one, which is the
   signature of a comment that ended sooner than its author believed.
   THE STANDING RULE: never write a comment terminator inside a comment, in quotes or otherwise, and
   never put explanatory prose between a warning and the declaration it protects. */

:root {
  /* paper is the material; no dark mode */
  color-scheme: light;

  /* paper and ink */
  --paper: #f4f1ea;
  --paper-2: #ebe6da;
  --white: #fffdf9;
  --ink: #15201a;
  --ink-2: #3f4a44;
  --mute: #55605a;            /* 5.80:1 paper · 5.26:1 paper-2 · 6.45:1 white */
  --line: rgba(21, 32, 26, .16);
  --line-strong: rgba(21, 32, 26, .34);

  /* the two brand colours, and the ink-safe variant of the accent */
  --pine: #123e2f;
  --pine-2: #1b5541;
  --pine-ink: #f4efe4;        /* text on pine */
  --brass: #a8843f;           /* borders, marks, the em in the wordmark */
  --brass-2: #d1b071;         /* brass on a dark ground */
  --brass-ink: #765b28;       /* brass as small text on paper — ≥ 6:1 */

  /* the three states + informational */
  --holds: #276a46;   --holds-bg: #e9f2ec;
  --gap: #7d5210;     --gap-bg: #f8f0dc;
  --refuted: #a3352c; --refuted-bg: #f7e9e7;
  --info-bg: #eef0ec;

  /* type */
  --display: "Source Serif 4", Georgia, "Times New Roman", serif;
  --ui: Figtree, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, Menlo, Consolas, "Liberation Mono", monospace;

  /* type scale — the steps a page may use. Prose: xs · s · b · l. Headings: h3 · h2 · h1, and
     h1-tool for the working pages (Tools, the desk, the dossier) whose h1 sits above a task bar
     and must not shout. Two chrome steps sit between the prose steps on purpose: --fs-ui is
     buttons, nav, tabs and summaries; --fs-label is the tracked uppercase label (eyebrow, form
     label, table head). Neither is for running text. */
  --fs-xs: 12.5px;
  --fs-s: .875rem;
  --fs-b: 16px;
  --fs-l: 17.5px;
  --fs-h3: 20px;
  --fs-h2: clamp(26px, 3.4vw, 36px);
  --fs-h1: clamp(34px, 5.2vw, 56px);
  --fs-h1-tool: clamp(26px, 3.2vw, 34px);
  --fs-ui: 15px;
  --fs-label: .875rem;
  --header-offset: 5.25rem;
  --bottom-inset: 0px;

  /* spacing scale — 4 · 8 · 12 · 16 · 24 · 32 · 48 · 64 */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;

  /* shape */
  --radius: 2px;
  --tap: 44px;
  --wrap: 1080px;
  --wrap-narrow: 720px;
  --wrap-tool: 880px;

  /* ── THE SECOND GROUND, added 2026-09-05 ──────────────────────────────────────────────────
     The palette already carried --brass-2 ("brass on a dark ground") and --pine-ink ("text on
     pine"). Both were written for a saturated band, and the band was never built: measured on
     2026-09-05, --brass-2 had ZERO uses in the whole repository and --pine-ink had three, all
     inside .btn. So the system was not missing a colour, it was missing the surface its colours
     were made for, and the founder's word for the result was "concrete". Measured, the front
     page's first screen was 0.67% saturated ground against opentimestamps.org's 53.55%.

     ⚠ THE GROUND IS NAMED APART FROM THE INK, and that is load-bearing. --pine is an INK token
     and is REASSIGNED inside a dark band (see .band--forest), so a band painted with var(--pine)
     would repaint itself paper the instant that reassignment landed on its own element. */
  --forest: #123e2f;        /* the working band — same value as --pine, a different job */
  --forest-deep: #0d2f24;   /* the hero and the foot */
  /* ⚠ --pine-2 (#1b5541) IS NOT A GROUND: on it, brass-2 is 4.19:1 and the lit states 4.03–4.35:1,
     all under 4.5. It stays a hover ink and a seam. This line exists because #1b5541 is exactly
     what somebody reaches for when they want "a slightly lighter band". */
  --pine-ink-2: #cdd5cc;    /* secondary on forest — 7.97:1 / 9.65:1 */
  --pine-ink-3: #9fada2;    /* mute on forest      — 5.11:1 / 6.19:1 */
  --paper-hi: #fbf8f2;      /* never reassigned: the hover face of a paper button on forest */

  /* BRASS HAS TWO JOBS AND NEEDS TWO NAMES. --brass is 3.08:1 on paper and 3.42:1 on white:
     correct for a 1–2px rule (a non-text edge wants 3:1), a failure the moment it sets type —
     and it was setting type in seven places. The law is one sentence, and scripts/check-brass.mjs
     is what keeps it: never write `color: var(--brass)`. */
  --brass-type: var(--brass-ink);   /* 5.65:1 paper · 5.11:1 paper-2 · 6.27:1 white */

  /* the three states, lit for a dark ground */
  --holds-lit: #7fc79b;     /* 6.01:1 on forest */
  --gap-lit: #e0b055;       /* 5.99:1 */
  --refuted-lit: #ef9b90;   /* 5.56:1 */

  /* the mark: drawn sizes, not steps on the type scale */
  --mark-size: 23px;
  --mark-sub-size: 10.5px;
  --mark-sub-track: .38em;
  --mark-glyph: 40px;
}

/* ── reset and base ──────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { overflow-x: clip; }
main { overflow-x: clip; }
html { scroll-padding-top: var(--header-offset); }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--fs-b)/1.55 var(--ui);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--display); font-weight: 600; letter-spacing: -.015em; line-height: 1.12; margin: 0 0 .4em; color: var(--pine); }
h1 { font-size: var(--fs-h1); letter-spacing: -.025em; line-height: 1.04; }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-b); font-family: var(--ui); font-weight: 700; }
/* The working pages' h1 (Tools, desk, dossier, farmer page): one class instead of five re-declarations. */
.h1--tool, .tool-head h1, .page-head h1 { font-size: var(--fs-h1-tool); line-height: 1.1; margin-bottom: var(--sp-2); }
p { margin: 0 0 .9em; }
p:last-child { margin-bottom: 0; }
a { color: var(--pine); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--pine-2); }
b, strong { font-weight: 700; }
small { font-size: .85em; }
code, .mono { font-family: var(--mono); font-size: .92em; }
.tnum { font-variant-numeric: tabular-nums; }
img, svg { max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
ul, ol { padding-left: 1.2em; margin: 0 0 .9em; }
hr { border: 0; border-top: 1px solid var(--line); margin: var(--sp-6) 0; }
::selection { background: rgba(168, 132, 63, .28); }
:focus-visible { outline: 3px solid var(--brass); outline-offset: 3px; }

/* gutters: --sp-5 a side on a desk, --sp-4 a side on a phone (the 600px rule below) */
.wrap { width: min(var(--wrap), calc(100% - 2 * var(--sp-5))); margin: 0 auto; }
.wrap--narrow { width: min(var(--wrap-narrow), calc(100% - 2 * var(--sp-5))); }
.wrap--tool { width: min(var(--wrap-tool), calc(100% - 2 * var(--sp-5))); }
.wrap > * { min-width: 0; }

.skip { position: absolute; left: -999px; top: var(--sp-2); z-index: 99; background: var(--white); color: var(--ink); padding: var(--sp-2) var(--sp-4); border: 1px solid var(--line-strong); }
.skip:focus { left: var(--sp-2); }
.vh { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.hidden { display: none !important; }

/* ── chrome: header ──────────────────────────────────────────────────────────────────── */
.site-head { position: sticky; top: 0; z-index: 80; border-bottom: 1px solid var(--line); background: var(--white); overflow: visible; box-shadow: 0 4px 24px rgba(18,62,47,.07); }
.site-head__row { min-height: var(--sp-8); display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-5); position: relative; overflow: visible; }
/* the wordmark is a mark, not a text size — 22px is its drawn size and stays literal */
/* THE LOCKUP. The glyph spans both rows on the left; the name is row 1 and "for industry" row 2,
   so the two lines make one rectangle and the sub-line costs no width.
   WHAT WAS WRONG UNTIL 2026-09-05, and it was a rendering defect rather than a taste question: this
   rule was `display: inline-flex; gap: var(--sp-2)` while every page ships `Open<em>Stamps</em>`.
   The bare text node and the <em> are two separate flex items, so the browser drew EIGHT PIXELS OF
   NOTHING inside the word, on every page: measured openRight 144.8, emLeft 152.8. The name read
   "Open Stamps" and could break across two lines in a narrow header. A grid with the name in one
   span is what makes it one unit; the founder asked for the word "tight together" and this is that. */
.mark {
  display: inline-grid; grid-template-columns: auto auto; align-items: center;
  column-gap: 9px; min-height: var(--tap);
  color: var(--pine); text-decoration: none; white-space: nowrap;
  overflow: visible;
}
/* The glyph is a postage die: perforated rectangle, inner window, brass face, house diamond.
   OpenTimestamps' mark is a stamp; this one is too — pine ink, not their clock. The die turns
   a full revolution; the diamond counter-rotates so the lockup still reads. Reduced-motion
   (below) stops both animations site-wide. */
.mark__glyph {
  grid-row: 1 / 3; width: var(--mark-glyph); height: var(--mark-glyph); display: block;
  overflow: visible; transform-origin: center;
  animation: mark-spin 12s linear infinite;
}
.mark__perforation { fill: var(--pine); }
.mark__window { fill: none; stroke: var(--brass-2); stroke-width: 1.15; }
.mark__die circle { fill: none; stroke: var(--brass-2); stroke-width: 1.25; }
.mark__die-close { fill: none; stroke: var(--brass-2); stroke-width: 2; stroke-linecap: round; }
.mark__seal {
  fill: var(--brass-2);
  transform-box: view-box; transform-origin: center;
  animation: mark-unspin 12s linear infinite;
}
.mark:hover .mark__glyph, .mark:hover .mark__seal { animation-play-state: paused; }
@keyframes mark-spin { to { transform: rotate(360deg); } }
@keyframes mark-unspin { to { transform: rotate(-360deg); } }
/* 23px is the mark's DRAWN size, like the 22px it replaces — a mark is not a step on the type scale */
.mark__name { grid-column: 2; grid-row: 1; font: 600 var(--mark-size)/1 var(--display); letter-spacing: -.022em; color: inherit; }
/* `font: inherit` so a larger lockup scales from ONE font-size instead of pinning "Stamps" to 22px */
.mark em { font: inherit; font-style: normal; color: inherit; }
/* tracked out to the measured width of the name above it; text-indent puts back the trailing
   letter-space so the line ends flush instead of overhanging by one */
.mark__sub {
  grid-column: 2; grid-row: 2; margin-top: 4px; align-self: start;
  font: 700 var(--mark-sub-size)/1 var(--ui);
  letter-spacing: var(--mark-sub-track); text-indent: var(--mark-sub-track);
  text-transform: uppercase; color: var(--brass-type);
}
.site-nav { display: flex; align-items: center; gap: var(--sp-5); }
/* ⚠ nowrap, 2026-09-05: without it a two-word item breaks mid-phrase in the header. Measured on
   terms.html at 900px, four of the six items were set on two lines — "At the / plot", "Check a /
   stamp" — which reads as six items of unequal height rather than one row. The gap tightens below
   the full wrap so six one-line items still fit before the menu button takes over.
   ⚠ :not(.btn) IS LOAD-BEARING, 2026-09-05. `.site-nav a` is specificity (0,1,1) and `.btn` is
   (0,1,0), so the nav's link colour outranked the button's OWN colour no matter which came first in
   the file: the header's primary call to action has been drawing --ink-2 text on a --pine ground —
   measured 1.30:1, effectively unreadable — on every page since the header was written, and no gate
   here reads a rendered colour. A nav link's colour has no business reaching a button; excluding it
   lets .btn and every one of its variants govern buttons wherever they stand, band included. */
.site-nav a:not(.btn) { font: 600 var(--fs-ui)/1.2 var(--ui); color: var(--ink-2); text-decoration: none; padding: var(--sp-3) 0; white-space: nowrap; }
@media (max-width: 1080px) { .site-nav { gap: var(--sp-4); } }
.site-nav a:not(.btn):hover { color: var(--pine); }
.site-nav a:not(.btn)[aria-current="page"] { color: var(--pine); box-shadow: inset 0 -2px 0 var(--brass); }
.site-nav .btn { padding: 0 var(--sp-4); min-height: 40px; }
/* Hamburger is CSS-only (::before / ::after) so field.html can still replace the word "Menu" via
   data-t without wiping an inner icon node. Bars sit to the left of the label. */
.menu-btn {
  display: none; position: relative; flex: none; z-index: 81;
  min-height: var(--tap); min-width: var(--tap);
  padding: 0 var(--sp-3) 0 calc(var(--sp-3) + 1.25rem + var(--sp-2));
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--white); font: 700 var(--fs-ui) var(--ui); color: var(--ink);
}
.menu-btn::before, .menu-btn::after {
  content: ""; position: absolute; left: var(--sp-3); width: 1.125rem; height: 2px;
  background: currentColor; border-radius: 1px; pointer-events: none;
}
.menu-btn::before { top: calc(50% - 5px); box-shadow: 0 5px 0 currentColor; }
.menu-btn::after { top: calc(50% + 5px); }
.menu-btn[aria-expanded="true"] { background: var(--pine); color: var(--pine-ink); border-color: var(--pine); }
.menu-btn[aria-expanded="true"]::before {
  top: 50%; box-shadow: none; transform: translateY(-50%) rotate(45deg);
}
.menu-btn[aria-expanded="true"]::after {
  top: 50%; transform: translateY(-50%) rotate(-45deg);
}

/* Dropdown glyphs. Masked so the mark follows currentColor (pine on the current row, ink otherwise).
   Drawn as 24×24 stroke paths; the fill is the mask, never a tick. */
.site-nav a[data-nav]::before {
  content: ""; width: 1.35rem; height: 1.35rem; flex: none; display: none;
  background: currentColor;
  -webkit-mask: var(--nav-ico) center / contain no-repeat;
  mask: var(--nav-ico) center / contain no-repeat;
}
.site-nav a[data-nav="evidence"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 3h7l5 5v13H7z'/%3E%3Cpath d='M14 3v5h5'/%3E%3Cpath d='M10 13h6M10 17h4'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="guides"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='4' width='7' height='7' rx='1'/%3E%3Crect x='13' y='4' width='7' height='7' rx='1'/%3E%3Crect x='4' y='13' width='7' height='7' rx='1'/%3E%3Crect x='13' y='13' width='7' height='7' rx='1'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="desk"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 18V9h16v9M4 12h16M8 9V6h8v3'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="plot"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 21s7-6.2 7-11a7 7 0 1 0-14 0c0 4.8 7 11 7 11z'/%3E%3Ccircle cx='12' cy='10' r='2.4'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="stamp"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4l8 8-8 8-8-8z'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="phone"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='3' width='8' height='14' rx='1.4'/%3E%3Crect x='11' y='7' width='8' height='14' rx='1.4'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="pricing"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12l9-9h8v8l-9 9z'/%3E%3Ccircle cx='16' cy='8' r='1.2'/%3E%3C/svg%3E"); }
.site-nav a[data-nav="account"] { --nav-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.2'/%3E%3Cpath d='M5.2 19a6.8 6.8 0 0 1 13.6 0'/%3E%3C/svg%3E"); }
.site-nav a[data-hint]::after { content: none; }

/* ── chrome: footer ──────────────────────────────────────────────────────────────────── */
.site-foot { margin-top: var(--sp-8); padding: var(--sp-6) 0; border-top: 1px solid var(--line); font-size: var(--fs-s); color: var(--mute); line-height: 1.6; }
.site-foot__row { display: flex; justify-content: space-between; gap: var(--sp-5) var(--sp-7); flex-wrap: wrap; }
.site-foot a { color: var(--ink-2); }
.site-foot nav { display: flex; flex-wrap: wrap; gap: 0 var(--sp-4); }
.site-foot nav a { display: inline-flex; align-items: center; min-height: var(--tap); white-space: nowrap; }


/* ── buttons ─────────────────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-5); max-width: 100%;
  border: 1px solid var(--pine); border-radius: var(--radius);
  background: var(--pine); color: var(--pine-ink);
  font: 600 var(--fs-ui)/1.2 var(--ui); text-decoration: none; text-align: center; white-space: normal;
}
.btn:hover { background: var(--pine-2); border-color: var(--pine-2); color: var(--pine-ink); }
.btn[disabled], .btn:disabled {
  opacity: 1; cursor: not-allowed;
  background: var(--paper-2); border-color: var(--pine); color: var(--mute);
}
.btn--primary[disabled], .btn--primary:disabled {
  background: var(--paper-2); border-color: var(--pine); color: var(--pine); opacity: 1;
}
.btn--secondary { background: transparent; color: var(--pine); }
.btn--secondary:hover { background: rgba(18, 62, 47, .06); color: var(--pine); }
.btn--quiet { background: transparent; border-color: var(--pine); color: var(--pine); }
.btn--quiet:hover { background: rgba(18, 62, 47, .06); border-color: var(--pine); color: var(--pine); }
.btn--block { display: flex; width: 100%; }
.btn--tall { min-height: 60px; font-size: var(--fs-l); }
.btn--small { min-height: var(--tap); padding: 0 var(--sp-3); font-size: var(--fs-s); }
.btnrow { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-4); }
.btnrow > * { min-width: 0; }

/* ── surfaces and text ───────────────────────────────────────────────────────────────── */
.card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-5); }
.card--flush { padding: 0; overflow: hidden; }
.eyebrow { font: 700 var(--fs-label)/1.3 var(--ui); letter-spacing: .14em; text-transform: uppercase; color: var(--brass-ink); margin: 0 0 var(--sp-3); }
.lede { font-size: var(--fs-l); color: var(--ink-2); max-width: 60ch; }
.small { font-size: var(--fs-s); }
.xs { font-size: var(--fs-xs); }
.muted { color: var(--mute); }
.ink2 { color: var(--ink-2); }
.center { text-align: center; }
.mt-s { margin-top: var(--sp-2); } .mt-m { margin-top: var(--sp-4); } .mt-l { margin-top: var(--sp-6); } .mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
.grid-2 > * { min-width: 0; }
.rule { border: 0; border-top: 1px solid var(--line); margin: var(--sp-5) 0; }

/* ── forms ───────────────────────────────────────────────────────────────────────────── */
.lbl, label.lbl { display: block; font: 700 var(--fs-label)/1.3 var(--ui); letter-spacing: .1em; text-transform: uppercase; color: var(--brass-ink); margin: var(--sp-4) 0 var(--sp-2); }
.field, input.field, textarea.field, select.field {
  display: block; width: 100%; min-width: 0; max-width: 100%; min-height: var(--tap);
  /* 10px vertical is deliberate: with 16px/1.4 it lands the box exactly on --tap, which --sp-3 would overshoot */
  padding: 10px var(--sp-3); border: 2px solid var(--pine); border-radius: var(--radius);
  background: var(--white); color: var(--ink); font: 400 var(--fs-b)/1.4 var(--ui);
}
textarea.field { min-height: 110px; resize: vertical; }
textarea.field.mono { font: var(--fs-xs)/1.5 var(--mono); }
input[type="file"].field { padding: 9px 10px; line-height: 1.4; }
.check { display: flex; gap: var(--sp-3); align-items: flex-start; cursor: pointer; font-weight: 400; }
.check input { width: 18px; height: 18px; min-width: 18px; margin: 3px 0 0; accent-color: var(--pine); }
.check b { display: block; color: var(--pine); }
.check small { display: block; color: var(--ink-2); line-height: 1.5; margin-top: 2px; }
.hash { font: var(--fs-xs)/1.5 var(--mono); background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); word-break: break-all; color: var(--ink-2); }

/* ── disclosure ──────────────────────────────────────────────────────────────────────── */
details.disclose { border-top: 1px solid var(--line); padding: var(--sp-1) 0; }
details.disclose:last-of-type { border-bottom: 1px solid var(--line); }
details.disclose > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--sp-3); min-height: var(--tap); padding: var(--sp-2) 0; font: 600 var(--fs-ui) var(--ui); color: var(--pine); }
details.disclose > summary::-webkit-details-marker { display: none; }
details.disclose > summary::before { content: "+"; width: 18px; text-align: center; color: var(--brass-type); font-weight: 700; flex: none; }
details.disclose[open] > summary::before { content: "−"; }
details.disclose > summary small { font-weight: 400; color: var(--mute); }
/* the body's left edge lines up with the summary text: the 18px glyph column plus its gap */
details.disclose > .disclose__body { padding: var(--sp-1) 0 var(--sp-4) calc(18px + var(--sp-3)); color: var(--ink-2); font-size: var(--fs-ui); }

/* ── the three states ────────────────────────────────────────────────────────────────── */
/* .status is what try.html / dds.html / portal.html scripts emit through statusHTML():
     <div class="status ok|warn|bad|info"><div class="bt">◇</div><div><div class="bt">title</div><div class="bd">body</div></div></div>
   ok is NOT-REFUTED ("nothing contradicted this"), never a pass — hence the hollow diamond.
   The BEM spellings (.status--ok …) are the same rules under the name lib/face.js will emit, so a
   page may move to the shared vocabulary without a flash of unstyled state. */
.status { display: flex; gap: var(--sp-3); align-items: flex-start; padding: var(--sp-4); border: 1px solid var(--line); border-left-width: 3px; border-radius: var(--radius); background: var(--info-bg); margin-top: var(--sp-4); }
.status > * { min-width: 0; }
.status .bt { font-weight: 700; font-size: var(--fs-ui); color: var(--ink); }
.status .bd { color: var(--ink-2); font-size: var(--fs-s); margin-top: 2px; line-height: 1.5; overflow-wrap: anywhere; }   /* a 64-hex content id wraps rather than clips */
.status > .bt:first-child { font-size: 18px; line-height: 1.2; flex: none; width: 20px; text-align: center; }               /* the glyph column; 18px is a glyph size, not a text size */
.status.ok,   .status--ok   { background: var(--holds-bg);   border-color: var(--holds); }
.status.warn, .status--warn { background: var(--gap-bg);     border-color: var(--gap); }
.status.bad,  .status--bad  { background: var(--refuted-bg); border-color: var(--refuted); }
.status.info, .status--info { background: var(--info-bg);    border-color: var(--line-strong); }
.status.ok > .bt:first-child,   .status--ok > .bt:first-child   { color: var(--holds); }
.status.warn > .bt:first-child, .status--warn > .bt:first-child { color: var(--gap); }
.status.bad > .bt:first-child,  .status--bad > .bt:first-child  { color: var(--refuted); }
.status.info > .bt:first-child, .status--info > .bt:first-child { color: var(--brass-type); }
.g-ok { color: var(--holds); } .g-warn { color: var(--gap); } .g-bad { color: var(--refuted); } .g-mute { color: var(--mute); }
.g-anchored { color: var(--holds); }
.grammar { display: flex; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; font-size: var(--fs-s); color: var(--ink-2); }
.grammar span::before { font-weight: 700; margin-right: var(--sp-2); }
.grammar .holds::before { content: "◇"; color: var(--holds); }
.grammar .anchored::before { content: "◈"; color: var(--holds); }
.grammar .gap::before { content: "◔"; color: var(--gap); }
.grammar .refuted::before { content: "✕"; color: var(--refuted); }

/* ── the shared face (lib/face.js) ───────────────────────────────────────────────────── */
/* FACE[outcome] = { glyph, word, formal, gloss } and LIGHT[light] = { glyph, word, gloss } render
   as one inline term — glyph then word — and an optional gloss under it. The classes are named
   by the OUTCOME and the LIGHT, never by a colour, so the markup reads correctly in the greyscale
   photocopy and the CSS cannot be asked to show green. Expected markup:
     <span class="face face--not-refuted"><span class="face__glyph">◇</span> <span class="face__word">holds up</span></span>
   .face--produced is the ◆ "a thing exists" glyph: informational, never a judgement. */
.face { display: inline-flex; align-items: baseline; gap: var(--sp-2); font-weight: 600; color: var(--ink); }
.face__glyph { flex: none; font-weight: 700; line-height: 1; }
.face__word { color: inherit; }
.face__formal { font: 400 var(--fs-xs)/1.4 var(--mono); color: var(--mute); }
.face__gloss { display: block; margin-top: 2px; font-weight: 400; font-size: var(--fs-s); color: var(--ink-2); }
.face--not-refuted .face__glyph, .face--anchored .face__glyph { color: var(--holds); }
.face--not-checked .face__glyph { color: var(--gap); }
.face--refuted .face__glyph { color: var(--refuted); }
.face--produced .face__glyph { color: var(--brass-type); }
/* a row of checks: glyph column, then label / detail — the shape dds.html's rowHTML and portal's
   check rows already draw locally; they can drop their copies once they emit these names */
.face-rows { display: grid; gap: var(--sp-2); margin-top: var(--sp-3); }
.face-row { display: grid; grid-template-columns: 24px 1fr; gap: var(--sp-3); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius); background: var(--white); font-size: var(--fs-s); }
.face-row > * { min-width: 0; }
.face-row .face__glyph { font-size: 18px; line-height: 1.1; text-align: center; }
.face-row b { display: block; color: var(--pine); }
.face-row p { margin: var(--sp-1) 0 0; color: var(--ink-2); overflow-wrap: anywhere; }

/* ── drop zone ───────────────────────────────────────────────────────────────────────── */
.drop { border: 1.5px dashed var(--line-strong); border-radius: var(--radius); padding: var(--sp-7) var(--sp-4); text-align: center; cursor: pointer; background: var(--paper); }
.drop:hover, .drop.over { border-color: var(--pine); background: rgba(18, 62, 47, .05); }
.drop .drop__glyph { font: 400 32px/1 var(--display); color: var(--brass-type); }   /* a glyph size, not a text size */
.drop b { display: block; margin-top: var(--sp-3); font: 600 var(--fs-h3)/1.2 var(--display); color: var(--pine); }
.drop small { display: block; margin-top: var(--sp-2); color: var(--mute); font-size: var(--fs-s); }
.prog { height: 4px; border-radius: 2px; background: var(--line); overflow: hidden; margin-top: var(--sp-4); }
.prog i { display: block; height: 100%; background: var(--pine); width: 0; transition: width .2s; }

/* ── task switcher (tool page) ───────────────────────────────────────────────────────── */
.tasks { display: flex; border-bottom: 1px solid var(--line); background: var(--paper-2); }
.task { flex: 1; min-width: 0; min-height: 52px; padding: var(--sp-3) var(--sp-2); border: 0; background: transparent; font: 700 var(--fs-ui) var(--ui); color: var(--mute); }
.task[aria-selected="true"] { background: var(--white); color: var(--pine); box-shadow: inset 0 -2px 0 var(--pine); }
.task:focus-visible { outline-offset: -3px; }
/* More tabs than a phone is wide: the row scrolls sideways and the right edge fades so the eye is
   told there is more. The fade is a mask on the scroller itself — a pseudo-element would scroll
   away with the content. Tabs stop sharing the width and take their natural size. */
.tabs--scroll { overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; -webkit-overflow-scrolling: touch; -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--sp-6)), transparent); mask-image: linear-gradient(to right, #000 calc(100% - var(--sp-6)), transparent); }
.tabs--scroll::-webkit-scrollbar { display: none; }
.tabs--scroll > .task { flex: 0 0 auto; padding: var(--sp-3) var(--sp-4); white-space: nowrap; }
.tabs--scroll.is-end { -webkit-mask-image: none; mask-image: none; }   /* a page may clear the hint once the last tab is in view */

/* ── the desk's phone control: "Step n of 7" ─────────────────────────────────────────── */
/* Back · label · Next in one row, both buttons tap-sized; the label is the only thing that grows.
   Shown in place of the tab row on phones (the page toggles which one it renders). */
.steps-row { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--paper); }
.steps-row > .btn { flex: none; }
.steps-row__label { flex: 1; min-width: 0; text-align: center; font: 600 var(--fs-s)/1.25 var(--ui); color: var(--ink-2); }
.steps-row__label b { display: block; color: var(--pine); font-size: var(--fs-ui); }
.steps-row__n { font-variant-numeric: tabular-nums; color: var(--mute); }
.steps-row--phone { position: sticky; bottom: 0; z-index: 20; }

/* ── lamps (dossier) ─────────────────────────────────────────────────────────────────── */
.lamp { width: 46px; height: 46px; border-radius: 50%; border: 2px solid var(--line-strong); display: flex; align-items: center; justify-content: center; font-size: 22px; background: var(--white); color: var(--ink-2); flex: none; }   /* 22px is the glyph's drawn size */
.lamp.red,   .light--red   { background: var(--refuted-bg); border-color: var(--refuted); color: var(--refuted); }
.lamp.amber, .light--amber { background: var(--gap-bg); border-color: var(--gap); color: var(--gap); }
.lamp.white, .light--white { background: var(--white); border-color: var(--line-strong); color: var(--ink-2); }
.lamp.anchored, .light--anchored { background: var(--holds-bg); border-color: var(--holds); color: var(--holds); }
/* .lamp.green deleted 2026-09-07: nothing emits it — portal.html's lamp classes are lib/face.js LIGHT keys
   (red · amber · white · anchored), and "green" never names a light anywhere on this site. */

/* ── tables ──────────────────────────────────────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-s); }
.table th, .table td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
.table th { font: 700 var(--fs-label)/1.3 var(--ui); letter-spacing: .08em; text-transform: uppercase; color: var(--brass-ink); }
.scroll-x { overflow-x: auto; max-width: 100%; }

/* ── role router ─────────────────────────────────────────────────────────────────────── */
/* A row of plain links under a lede — "I grow trees · I run a mill · I file the declaration" —
   so a visitor finds their page in one tap. Links, not buttons: launch.html's btn--primary budget is
   two and these are none of them. Each target is --tap tall and the row wraps on a phone. Works as
   <nav class="role-router"><a>…</a></nav> and as <ul class="role-router"><li><a>…</a></li></ul>. */
.role-router { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--sp-5); margin: var(--sp-3) 0 0; padding: 0; list-style: none; }
.role-router li { display: contents; }
.role-router a { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); font: 600 var(--fs-ui)/1.2 var(--ui); color: var(--pine); text-decoration-color: var(--brass); }
.role-router a::after { content: "→"; color: var(--brass-type); font-weight: 400; }
.role-router a:hover { color: var(--pine-2); }
.role-router__lead { flex: 1 0 100%; margin: 0 0 var(--sp-1); font-size: var(--fs-s); color: var(--mute); }

/* ── industry cards (launch + listed) ─────────────────────────────────────────
   Status bar + plate (photo or gradient) + line icon + title. Enabling a listed
   vertical is a status flip in lib/industries.js, not a new site. Never a tick.
   Filter chips hide by `data-kind` (physical / digital / both). `both` stays in
   every filter. Collapsed extras live in <details> so the first screen is four
   money doors; the names stay in the HTML for the launch gate. */
.profilebar { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-3); padding: var(--sp-3) var(--sp-5); border-bottom: 1px solid var(--line); background: var(--paper-2); }
.profilebar .lbl { margin: 0; }
.profilebar .field { flex: 1 1 16rem; min-width: 12rem; }
.profilebar__wire { font: var(--fs-xs) var(--mono); color: var(--mute); }
.profile-note { margin: 0 0 var(--sp-4); font-size: var(--fs-s); color: var(--ink-2); max-width: 70ch; }
.witrow { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); padding: var(--sp-2) var(--sp-4); border: 1px solid var(--line); border-radius: var(--radius); background: var(--white); min-height: 52px; }
.witrow__icon { flex: none; display: flex; color: var(--pine); }
.witrow__icon svg { width: 22px; height: 22px; }
.witrow__name { flex: none; font-weight: 600; font-size: var(--fs-ui); cursor: pointer; }
.witrow__state { flex: 1 1 auto; min-width: 0; font-size: var(--fs-s); color: var(--ink-2); overflow-wrap: anywhere; }
.witrow__state .mono { font-size: var(--fs-xs); }
.witqr { display: flex; gap: var(--sp-4); align-items: center; margin-top: var(--sp-3); padding: var(--sp-4); border: 1px solid var(--brass); border-radius: var(--radius); background: var(--white); }
.witqr img { width: 148px; height: 148px; flex: none; background: #fff; padding: var(--sp-2); border: 1px solid var(--line); border-radius: var(--radius); }
.witqr__say { min-width: 0; font-size: var(--fs-s); color: var(--ink-2); line-height: 1.5; }
.witqr__say b { display: block; font-size: var(--fs-ui); color: var(--pine); }
.switch { flex: none; position: relative; width: 46px; height: 26px; margin: 0; appearance: none; -webkit-appearance: none; background: var(--line-strong); border: 0; border-radius: 13px; cursor: pointer; transition: background .15s; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--white); transition: transform .15s; }
.switch:checked { background: var(--pine); }
.switch:checked::after { transform: translateX(20px); }
.switch:focus-visible { outline: 3px solid var(--brass); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .switch, .switch::after { transition: none; } }
@media (max-width: 600px) {
  .witrow { flex-wrap: wrap; }
  .witrow__name { flex: 1 1 auto; }
  .witrow__state { flex: 1 1 100%; order: 3; }
}
@media (max-width: 480px) { .witqr { flex-direction: column; align-items: flex-start; } }

.industries { margin: 0; }
.industries__lead { margin: 0 0 var(--sp-2); font: 600 var(--fs-s) var(--ui); color: var(--mute); letter-spacing: .04em; text-transform: uppercase; }
.industries__cstp { margin: 0 0 var(--sp-4); max-width: 62ch; font-size: var(--fs-s); color: var(--ink-2); }
.industries__toolbar { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); margin: 0 0 var(--sp-4); }
.industries__filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0; }
.industries__find { flex: 1 1 16rem; min-width: 12rem; }
.industries__find .lbl { margin: 0 0 var(--sp-1); }
.industries__find .field { width: 100%; background: var(--white); color: var(--ink); }
.industries__filters button {
  min-height: var(--tap); padding: 0 var(--sp-3);
  border: 2px solid var(--pine); border-radius: 999px;
  background: var(--white); color: var(--pine);
  font: 600 var(--fs-s) var(--ui); cursor: pointer;
}
.industries__filters button:hover { border-color: var(--pine); color: var(--pine); }
.industries__filters [aria-pressed="true"] { border-color: var(--pine); background: var(--pine); color: var(--paper); }
.industries[data-filter="goods"] [data-kind="digital"],
.industries[data-filter="files"] [data-kind="physical"] { display: none; }
.industries[data-query] [data-miss] { display: none; }
.industries[data-query] .industries__grid:not(:has(> li:not([data-miss]))) { display: none; }
.industries[data-query] .industries__more:not(:has(li:not([data-miss]))) { display: none; }
.industries [data-ind-empty] { margin: 0 0 var(--sp-4); font-size: var(--fs-s); color: var(--mute); }
.industries__grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-3); }
.industries__grid > * { min-width: 0; }
.industries__more { margin-top: var(--sp-4); }
.industries__more summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: var(--tap); padding: var(--sp-2) 0;
  font: 600 var(--fs-ui) var(--ui); color: var(--pine); cursor: pointer; list-style: none;
}
.industries__more summary::-webkit-details-marker { display: none; }
.industries__more summary::after { content: "+"; color: var(--brass-type); font-weight: 400; }
.industries__more[open] summary::after { content: "–"; }
.indcard {
  display: flex; flex-direction: column; min-height: 100%;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; color: inherit; overflow: hidden;
  box-shadow: 0 8px 20px rgba(21, 32, 26, .12);
}
.indcard:hover { border-color: var(--pine); }
.indcard__status {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); background: var(--paper-2);
  font: 600 var(--fs-xs)/1.3 var(--ui); color: var(--ink-2);
}
.indcard__status .face { font-size: inherit; }
.indcard__plate {
  position: relative; display: block; height: 72px; overflow: hidden; background:
    linear-gradient(160deg, var(--pine) 0%, var(--pine-2, #1b5541) 55%, #0d2a20 100%);
}
.indcard--featured .indcard__plate { height: 140px; }
.indcard__plate img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform .45s ease;
}
.indcard:hover .indcard__plate img { transform: scale(1.05); }
.indcard__icon {
  position: absolute; left: 12px; bottom: 10px; width: 28px; height: 28px;
  color: #fff; z-index: 1; filter: drop-shadow(0 1px 2px rgba(0,0,0,.45));
}
.indcard__plate:not(:has(img)) .indcard__icon {
  left: 50%; bottom: 50%; transform: translate(-50%, 50%); width: 32px; height: 32px;
}
.indcard[data-id="construction"] .indcard__plate { background: linear-gradient(160deg, #3d3428 0%, #6a5840 55%, #2a2319 100%); }
.indcard[data-id="packaging"] .indcard__plate { background: linear-gradient(160deg, #5c4a2a 0%, var(--brass) 55%, #3a2e16 100%); }
.indcard[data-id="clothing"] .indcard__plate { background: linear-gradient(160deg, #2a3340 0%, #5a6a78 55%, #1a2228 100%); }
.indcard[data-id="rubber"] .indcard__plate { background: linear-gradient(160deg, #1a1a1a 0%, #3d3a36 55%, #0e0e0e 100%); }
.indcard[data-id="cocoa"] .indcard__plate { background: linear-gradient(160deg, #3d2214 0%, #7a4a28 55%, #24140c 100%); }
.indcard[data-id="coffee"] .indcard__plate { background: linear-gradient(160deg, #2c1810 0%, #5c3a24 55%, #1a0e08 100%); }
.indcard[data-id="leather"] .indcard__plate { background: linear-gradient(160deg, #4a2818 0%, #8a5a38 55%, #2a1810 100%); }
.indcard[data-id="organic"] .indcard__plate { background: linear-gradient(160deg, #2a4a28 0%, #5a7a48 55%, #1a2a18 100%); }
.indcard[data-id="organiccrops"] .indcard__plate { background: linear-gradient(160deg, #3a4a20 0%, #7a8a40 55%, #222810 100%); }
.indcard[data-id="ayurveda"] .indcard__plate { background: linear-gradient(160deg, #4a2030 0%, #8a4060 55%, #241018 100%); }
.indcard[data-id="commodities"] .indcard__plate { background: linear-gradient(160deg, #2c3a32 0%, #4a5c50 55%, #1a2420 100%); }
.indcard[data-id="batteries"] .indcard__plate { background: linear-gradient(160deg, #1a2430 0%, #3a5060 55%, #0e161c 100%); }
.indcard[data-id="electronics"] .indcard__plate { background: linear-gradient(160deg, #142018 0%, #2a4a38 55%, #0a1410 100%); }
.indcard[data-id="pharma"] .indcard__plate { background: linear-gradient(160deg, #243040 0%, #4a6078 55%, #141c28 100%); }
.indcard[data-id="seafood"] .indcard__plate { background: linear-gradient(160deg, #1a3040 0%, #3a6880 55%, #0c1c28 100%); }
.indcard[data-id="cosmetics"] .indcard__plate { background: linear-gradient(160deg, #3a2430 0%, #7a4860 55%, #1c1018 100%); }
.indcard[data-id="digital"] .indcard__plate { background: linear-gradient(160deg, #2a2418 0%, #6a5840 55%, #18140c 100%); }
.indcard[data-id="steel"] .indcard__plate { background: linear-gradient(160deg, #2a2420 0%, #5a4a3a 55%, #141210 100%); }
.indcard[data-id="aluminium"] .indcard__plate { background: linear-gradient(160deg, #3a4048 0%, #8a949c 55%, #1a2024 100%); }
.indcard[data-id="palm"] .indcard__plate { background: linear-gradient(160deg, #2a3a18 0%, #5a7a28 55%, #141c0c 100%); }
.indcard[data-id="soya"] .indcard__plate { background: linear-gradient(160deg, #4a4a20 0%, #8a8a40 55%, #242410 100%); }
.indcard[data-id="cattle"] .indcard__plate { background: linear-gradient(160deg, #3a2a18 0%, #6a4a28 55%, #1c140c 100%); }
.indcard[data-id="invoices"] .indcard__plate { background: linear-gradient(160deg, #3a3428 0%, #7a6a50 55%, #1c1810 100%); }
.indcard[data-id="software"] .indcard__plate { background: linear-gradient(160deg, #242830 0%, #4a5460 55%, #101418 100%); }
.indcard[data-id="carbon"] .indcard__plate { background: linear-gradient(160deg, #2a2018 0%, #5a4030 55%, #14100c 100%); }
.indcard__body { display: flex; flex-direction: column; gap: 4px; padding: var(--sp-3) var(--sp-3) var(--sp-4); }
.indcard__name { font: 600 var(--fs-h3)/1.15 var(--display); color: var(--pine); }
.indcard__when { font: 600 var(--fs-xs)/1.3 var(--ui); color: var(--brass-ink); }
.indcard__blurb { margin: 0; font-size: var(--fs-s); color: var(--ink-2); }
.indcard--listed { box-shadow: none; }
.indcard--listed .indcard__name { color: var(--ink); }
.proof .glyph-svg { display: block; width: 28px; height: 28px; color: var(--brass-type); }
.profile-meta { font-size: var(--fs-s); color: var(--mute); }
.profile-meta code { font: 600 var(--fs-xs)/1.4 var(--mono); color: var(--ink-2); }
.profile-req { margin: var(--sp-2) 0 var(--sp-3); padding-left: 1.2em; }
@media (prefers-reduced-motion: reduce) {
  .indcard__plate img { transition: none; }
  .indcard:hover .indcard__plate img { transform: none; }
}
@media (max-width: 860px) { .industries__grid { grid-template-columns: 1fr 1fr; } .indcard--featured .indcard__plate { height: 110px; } }
@media (max-width: 600px) { .industries__grid { grid-template-columns: 1fr; } }

/* ── the bracket of time (lib/bracket.js) ────────────────────────────────────────────── */
/* bracketSvg({ notBefore, notAfter, round, tsa }) draws not-before ◆ … not-after ◆ with the width
   between, and an open right end when the bracket is one-sided. The SVG reads its colours from
   these custom properties so it prints in hairline black without a second drawing; the classes
   inside the SVG are the hooks. Nothing here says which side is "good": a bracket is a fact. */
.bracket { display: block; width: 100%; max-width: 560px; margin: var(--sp-3) 0; color: var(--ink-2);
  --bracket-line: var(--line-strong); --bracket-edge: var(--pine); --bracket-open: var(--mute); --bracket-accent: var(--brass); --bracket-text: var(--ink-2); }
.bracket svg { display: block; width: 100%; height: auto; overflow: visible; }
.bracket__line { stroke: var(--bracket-line); stroke-width: 1; fill: none; }
.bracket__edge { fill: var(--bracket-edge); stroke: none; }
.bracket__edge--open { fill: none; stroke: var(--bracket-open); stroke-width: 1; stroke-dasharray: 2 3; }
.bracket__width { fill: var(--bracket-accent); font: 600 var(--fs-xs) var(--ui); }
.bracket__label { fill: var(--bracket-text); font: var(--fs-xs)/1.4 var(--mono); }
.bracket__caption { margin: var(--sp-1) 0 0; font-size: var(--fs-xs); color: var(--mute); }
.bracket--inline { display: inline-block; width: 160px; max-width: 100%; margin: 0; vertical-align: middle; }

/* ── receipts (Verify, Chain) ────────────────────────────────────────────────────────── */
/* A receipt is what a dossier actually travels as: one printed sheet with the content id, the
   bracket figure, the rows with their shapes, one gloss line, the reader's policy line and a QR.
   On screen it is a white card with a stronger rule; on paper (below) it is the only thing on the
   page. Shapes carry the state so the photocopy loses nothing. */
.receipt { background: var(--white); border: 1px solid var(--line-strong); border-radius: var(--radius); padding: var(--sp-5); max-width: 720px; font-size: var(--fs-s); color: var(--ink); break-inside: avoid; }
.receipt > * { min-width: 0; }
.receipt__head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-4); padding-bottom: var(--sp-3); margin-bottom: var(--sp-4); border-bottom: 1px solid var(--line); }
.receipt__title { font: 600 var(--fs-h3)/1.15 var(--display); color: var(--pine); margin: 0; }
.receipt__kind { display: block; margin-top: var(--sp-1); font: 700 var(--fs-label)/1.3 var(--ui); letter-spacing: .1em; text-transform: uppercase; color: var(--brass-ink); }
.receipt__id { font: var(--fs-xs)/1.5 var(--mono); color: var(--ink-2); word-break: break-all; }
.receipt__qr { flex: none; width: 112px; height: 112px; }
.receipt__qr svg, .receipt__qr canvas, .receipt__qr img { display: block; width: 100%; height: 100%; image-rendering: pixelated; }
.receipt__rows { list-style: none; margin: 0; padding: 0; }
.receipt__row { display: grid; grid-template-columns: 24px 1fr; gap: var(--sp-2) var(--sp-3); padding: var(--sp-2) 0; border-top: 1px solid var(--line); }
.receipt__row > * { min-width: 0; }
.receipt__row .face__glyph { font-size: 18px; line-height: 1.1; text-align: center; }
.receipt__row b { color: var(--pine); }
.receipt__row p { margin: 2px 0 0; color: var(--ink-2); overflow-wrap: anywhere; }
.receipt__gloss { margin: var(--sp-4) 0 0; padding-top: var(--sp-3); border-top: 1px solid var(--line); font-size: var(--fs-ui); color: var(--ink); }
.receipt__policy { margin: var(--sp-3) 0 0; font: var(--fs-xs)/1.5 var(--mono); color: var(--mute); overflow-wrap: anywhere; }
.receipt__foot { margin: var(--sp-4) 0 0; font-size: var(--fs-xs); color: var(--mute); }

/* ── the map ─────────────────────────────────────────────────────────────────────────── */
/* .map-frame is the one thing the page owns: a box with a height. lib/slippy.js injects its own
   styles for what happens inside it, so nothing below reaches past the frame. .map-consent is the
   paper ground shown in that frame before the visitor opts in to fetching tiles — one sentence,
   one button, nothing loaded. */
.map-frame { position: relative; height: min(70vh, 520px); border: 2px solid var(--pine); border-radius: var(--radius); background: var(--paper-2); overflow: hidden; }
.map-frame > .slippy { position: absolute; inset: 0; }
.map-consent { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-3); padding: var(--sp-5); text-align: center; background: var(--paper-2); color: var(--ink-2); font-size: var(--fs-s); }
.map-consent p { max-width: 44ch; margin: 0; }
.map-consent .btn { flex: none; }

/* Legal-page typography lives in legal.css (its only owner). */

/* ── responsive ──────────────────────────────────────────────────────────────────────── */
/* ⚠ NAV vs LAYOUT ARE TWO BREAKPOINTS. The row used to collapse at 860px, which fitted six nowrap
   links. Then site.js started inserting a balance chip before .menu-btn, and every commercial page
   carries eight destinations plus "Create an account". Those extras clip the last links off the right
   edge — they "disappear". The hamburger now takes over at 1480. .grid-2 stays at 860: that is a
   column count, not a header measurement. */
@media screen {
  .menu-btn { display: inline-flex; align-items: center; justify-content: center; }
  .site-nav {
    display: none; position: fixed; top: calc(var(--sp-8) + var(--sp-2));
    left: auto; right: max(var(--sp-4), calc((100vw - var(--wrap)) / 2)); width: min(30rem, calc(100vw - 2 * var(--sp-4))); z-index: 82;
    flex-direction: column; align-items: stretch; gap: var(--sp-1);
    background: var(--white); border: 1px solid var(--line); border-radius: 12px;
    box-shadow: 0 16px 40px rgba(18, 62, 47, .14);
    padding: var(--sp-3); max-height: calc(100dvh - var(--menu-top, 5rem) - var(--sp-4)); overflow: auto; overscroll-behavior: contain;
    color: var(--ink);
  }
  .site-nav.is-open,
  .menu-btn[aria-expanded="true"] + .site-nav { display: flex; }
  .site-nav a:not(.btn) {
    display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--sp-3); row-gap: 0;
    padding: var(--sp-3) var(--sp-4); border: 0; border-radius: var(--radius);
    min-height: var(--tap); white-space: normal; color: var(--ink);
  }
  .site-nav a[data-nav]::before { display: block; }
  .site-nav a[data-hint]::after {
    content: attr(data-hint); display: block; flex: 1 1 100%;
    margin-left: calc(1.35rem + var(--sp-3)); margin-top: 2px;
    font: 400 var(--fs-xs)/1.35 var(--ui); color: var(--mute);
  }
  .site-nav a:not(.btn):hover { background: var(--paper-2); color: var(--pine); }
  .site-nav a:not(.btn)[aria-current="page"] {
    background: rgba(18, 62, 47, .08); color: var(--pine); font-weight: 700;
    box-shadow: inset 3px 0 0 var(--brass);
  }
  .site-nav a:not(.btn)[aria-current="page"]::after { color: var(--ink-2); font-weight: 400; }
  .site-nav .btn { margin: var(--sp-2) var(--sp-3) var(--sp-1); justify-content: center; min-height: var(--tap); }
}
@media (max-width: 860px) {
  .grid-2 { grid-template-columns: 1fr; }
}
@media (min-width: 861px) {
  .steps-row--phone { display: none; }
}
@media (max-width: 600px) {
  .wrap, .wrap--narrow, .wrap--tool { width: calc(100% - 2 * var(--sp-4)); }
  .btnrow { flex-direction: column; align-items: stretch; }
  .btnrow .btn { width: 100%; }
  /* the sub-line is STACKED now, so it costs no width and is never dropped: the half of the
     name that says what the product is for must survive the device most first visits arrive on */
  .mark__sub { display: block; }
  .card { padding: var(--sp-4); }
  details.disclose > .disclose__body { padding-left: 0; }
  details.disclose > summary { flex-wrap: wrap; }
  details.disclose > summary small { flex: 1 0 100%; padding-left: calc(18px + var(--sp-3)); margin-top: -6px; font-size: var(--fs-s); }
  .site-foot__row { flex-direction: column; }
  .role-router { gap: 0 var(--sp-4); }
  .role-router a { flex: 1 0 100%; border-top: 1px solid var(--line); }
  .receipt { padding: var(--sp-4); }
  .receipt__head { flex-direction: column; }
  .map-frame { height: min(60vh, 420px); }
  .menu-btn { width: var(--tap); padding: 0; font-size: 0; line-height: 0; }
  .menu-btn::before, .menu-btn::after { left: 50%; margin-left: -0.5625rem; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* ── Ask panel (lib/ask.js) ──────────────────────────────────────────────────────────── */
/* First-party, same origin. Not on field.html (no site.js) and not on enterprise.html
   (that page submits nothing). Fixed so it survives the header; print hides it. */
.ask { position: fixed; right: var(--sp-4); bottom: calc(var(--bottom-inset) + var(--sp-4) + env(safe-area-inset-bottom, 0px)); z-index: 50; display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2); }
.ask__toggle, .ask__close {
  min-height: var(--tap); padding: 0 var(--sp-4);
  border: 2px solid var(--brass-ink); border-radius: var(--radius);
  font: 600 var(--fs-ui)/1.2 var(--ui);
}
.ask__toggle {
  background: var(--brass-2); color: var(--forest);
}
.ask__toggle:hover { background: var(--brass); color: var(--forest); }
.ask__toggle[aria-expanded="true"] { background: var(--white); color: var(--pine); }
.ask__close { background: transparent; color: var(--ink); border-color: var(--line-strong); }
.ask__panel {
  width: min(22rem, calc(100vw - 2 * var(--sp-4)));
  max-height: min(32rem, calc(100dvh - var(--bottom-inset) - var(--header-offset) - 5rem));
  overflow: auto;
  padding: var(--sp-4);
  background: var(--white); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 12px 32px rgba(21, 32, 26, .12);
}
.ask__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.ask__title { margin: 0; font: 600 var(--fs-h3)/1.2 var(--display); color: var(--pine); }
.ask__intro, .ask__mailto, .ask__status { margin: 0 0 var(--sp-3); font-size: var(--fs-s); color: var(--ink-2); }
.ask__log { display: flex; flex-direction: column; gap: var(--sp-2); margin: 0 0 var(--sp-3); max-height: 12rem; overflow: auto; }
.ask__line { margin: 0; font-size: var(--fs-s); }
.ask__line--you { color: var(--ink); }
.ask__line--us { color: var(--ink-2); }
.ask__composer { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.ask__input, .ask__field {
  width: 100%; box-sizing: border-box;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--paper); color: var(--ink);
  font: 400 var(--fs-s)/1.4 var(--ui);
}
.ask__label { display: flex; flex-direction: column; gap: var(--sp-1); margin: 0 0 var(--sp-2); font: 600 var(--fs-label)/1.4 var(--ui); letter-spacing: .08em; text-transform: uppercase; color: var(--mute); }
.ask__handoff { margin-bottom: var(--sp-3); }
.ask__honey { position: absolute; left: -9999px; height: 0; overflow: hidden; }
.ask__local, .ask__leave { width: 100%; }

/* ── print ───────────────────────────────────────────────────────────────────────────── */
/* White paper, no chrome. The shapes ◇ ◈ ◔ ✕ are text, so they survive a greyscale copier; the
   coloured borders are asked to print too (print-color-adjust) but nothing depends on them. A
   receipt is one page and does not split; the bracket redraws itself in hairline black through
   the custom properties it reads. dds.html keeps its own narrower rule (only Annex II prints from
   the Statement tab) — that rule is the page's and sits on top of this one. */
@media print {
  @page { margin: 14mm; }
  .site-head, .site-foot, .btn, .menu-btn, .skip, .tasks, .steps-row, .role-router, .drop, .map-consent, .no-print, .ask, .fx { display: none !important; }
  html, body { overflow: visible; }
  body { background: #fff; color: #000; }
  .card, .receipt, .status, .face-row, .receipt__row { background: #fff; break-inside: avoid; page-break-inside: avoid; }
  .card, .receipt, .status, .face-row { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .receipt { max-width: none; border-color: #000; border-radius: 0; box-shadow: none; }
  .receipt--page { break-before: page; page-break-before: always; }
  .receipt + .receipt { margin-top: var(--sp-6); }
  .bracket { max-width: none; --bracket-line: #000; --bracket-edge: #000; --bracket-open: #000; --bracket-accent: #000; --bracket-text: #000; }
  .map-frame { height: 90mm; border-color: #000; }
  a { color: inherit; }
  .receipt a[href]::after, .card a[href]::after { content: none; }   /* a printed URL beside a content id is noise */
}

/* ── the balance chip (site.js) ──────────────────────────────────────────────────────── */
/* site.js puts one of these into .site-head__row on every page that loads it — which is every
   page EXCEPT field.html, and that exclusion is deliberate: the farmer's page shows no balance
   and no price, ever. The chip is a link, never a button, and it is absent altogether when the
   account service answers 503 or fails; there is no empty state to style.
   ◆ is the "a thing exists" glyph. A balance is a quantity, not a judgement, so no state colour
   is used here and nothing in the chip means holds / doesn't hold. */
.balance-chip {
  margin-left: 0; flex: 0 1 auto; min-width: 0;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-3);
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--white); color: var(--ink-2);
  font: 600 var(--fs-s)/1.2 var(--ui); text-decoration: none; white-space: nowrap;
}
.balance-chip:hover { color: var(--pine); border-color: var(--ink-2); }
.balance-chip__glyph { flex: none; color: var(--brass-type); font-weight: 700; }
.balance-chip__n { color: var(--pine); font-variant-numeric: tabular-nums; }
.balance-chip__unit { color: var(--mute); font-weight: 400; overflow: hidden; text-overflow: ellipsis; }
.balance-chip--out { color: var(--pine); }

/* Basket chip: same row as the balance, outside the eight-link nav. The glyph is a shopping basket,
   not a judgement diamond. Count badge stays. */
.cart-chip {
  margin-left: 0; flex: none;
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-3);
  border: 2px solid var(--brass); border-radius: var(--radius);
  background: var(--holds-bg); color: var(--pine);
  font: 600 var(--fs-s)/1.2 var(--ui); text-decoration: none; white-space: nowrap;
}
.cart-chip:hover { border-color: var(--pine); background: var(--white); }
.cart-chip__glyph { flex: none; display: block; width: 2.1rem; height: 2.1rem; color: var(--pine); }
.cart-chip__glyph svg { display: block; width: 100%; height: 100%; }
.cart-chip__n {
  min-width: 1.4em; padding: 0 .35em;
  border-radius: 99px; background: var(--pine); color: var(--pine-ink);
  font-variant-numeric: tabular-nums; text-align: center;
}

/* Display currency. Not a ninth nav href. Stripe still charges euro. */
.fx {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: stretch;
  border: 1px solid var(--line-strong); border-radius: var(--radius);
  overflow: hidden; background: var(--white);
}
.fx__btn {
  min-height: var(--tap); min-width: 2.7rem; padding: 0 var(--sp-2);
  border: 0; border-right: 1px solid var(--line);
  background: transparent; color: var(--ink-2);
  font: 600 var(--fs-s)/1 var(--ui);
}
.fx__btn:last-child { border-right: 0; }
.fx__btn[aria-pressed="true"] { background: var(--pine); color: var(--pine-ink); }
.fx__btn:hover:not([aria-pressed="true"]) { background: var(--paper-2); color: var(--pine); }
@media (max-width: 860px) {
  .site-head__row { gap: var(--sp-2); }
  .fx {
    order: 20; flex: 1 0 100%; margin-left: 0; margin-top: var(--sp-1);
    justify-content: flex-end; background: transparent; border: 0; overflow: visible;
  }
  .fx__btn { border: 1px solid var(--line-strong); border-right-width: 0; background: var(--white); }
  .fx__btn:first-child { border-radius: var(--radius) 0 0 var(--radius); }
  .fx__btn:last-child { border-right-width: 1px; border-radius: 0 var(--radius) var(--radius) 0; }
  .cart-chip { margin-left: auto; }
}

/* ── plan, balance and keys (account.html) ───────────────────────────────────────────── */
/* The meter is legible in a greyscale photocopy by construction: the fill is a solid proportion
   of a ruled track AND the two numbers are printed above it, so nothing depends on the colour of
   the fill. The track carries an aria-label with the same sentence, because a proportion drawn in
   a box is not readable by a screen reader either. */
.meter { margin-top: var(--sp-3); }
.meter__head { margin: 0; }
.meter__num { font: 600 var(--fs-h2)/1.05 var(--display); color: var(--pine); font-variant-numeric: tabular-nums; }
.meter__of { font-size: var(--fs-ui); color: var(--ink-2); }
.meter__track { height: 14px; margin-top: var(--sp-2); max-width: 560px; border: 1px solid var(--line-strong); border-radius: var(--radius); background: var(--paper-2); overflow: hidden; }
.meter__fill { display: block; height: 100%; width: 0; background: var(--pine); }
.meter__legend { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); margin: var(--sp-3) 0 0; padding: 0; list-style: none; font-size: var(--fs-s); color: var(--ink-2); }
.meter__legend b { color: var(--pine); font-variant-numeric: tabular-nums; }

/* The key list. A key is a payment instrument: it spends this account's balance, so the row says
   what it is, when it was made and when it was last used, and the revoke control sits on the row
   rather than behind a menu. ◆ again — the key exists; a revoked one keeps the glyph in mute ink
   rather than taking ✕, which on this site means REFUTED and is a state, not a life-cycle. */
.keys { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: grid; gap: var(--sp-2); }
.keys li { display: grid; grid-template-columns: 24px 1fr auto; gap: var(--sp-2) var(--sp-3); align-items: start; padding: var(--sp-3); border: 1px solid var(--line); border-radius: var(--radius); background: var(--white); font-size: var(--fs-s); }
.keys li > * { min-width: 0; }
.keys__glyph { color: var(--brass-type); font-weight: 700; text-align: center; }
.keys b { display: block; color: var(--pine); overflow-wrap: anywhere; }
.keys p { margin: var(--sp-1) 0 0; color: var(--ink-2); }
.keys .tok { font: var(--fs-xs)/1.5 var(--mono); color: var(--mute); overflow-wrap: anywhere; }
.keys li.is-revoked { background: var(--paper); }
.keys li.is-revoked .keys__glyph { color: var(--mute); }
.keys li.is-revoked b { color: var(--ink-2); }

/* The one-time key. Brass rule down the left because this block is the only thing on the site that
   shows a secret; it is shown once and the server keeps only its SHA-256. */
.newkey { margin-top: var(--sp-3); padding: var(--sp-4); border: 1px solid var(--brass); border-left-width: 3px; border-radius: var(--radius); background: var(--white); }
.newkey > p { max-width: 70ch; }
.newkey input.field { font: var(--fs-xs)/1.5 var(--mono); }

@media (max-width: 600px) {
  .balance-chip { padding: 0 var(--sp-2); gap: var(--sp-1); }
  .balance-chip__unit { display: none; }   /* "◆ 231" plus the aria-label; the word is on the account page */
  .cart-chip__lab { display: none; }
  .fx__btn { min-width: 2.35rem; padding: 0 .4em; font-size: var(--fs-xs); }
  .keys li { grid-template-columns: 24px 1fr; }
  .keys li .btn { grid-column: 2; justify-self: start; }
}
@media print {
  /* a balance is not part of a dossier: it never prints */
  .balance-chip, .cart-chip, .fx, .newkey { display: none !important; }
  .meter__fill { background: #000; }
}

/* ══ THE BAND SYSTEM ═════════════════════════════════════════════════════════════════════════════
   Added 2026-09-05, after the founder said the site was "as grey as concrete" and asked for
   something closer to opentimestamps.org. Measured before the change: the front page's first screen
   was 0.67% saturated ground and the whole site carried ZERO full-bleed colour bands; brass filled
   nothing anywhere; every section on launch.html was the same height and was divided from the next
   by 1px at 1.38:1 contrast. The diagnosis that matters: the page was never low-contrast — pine on
   paper is 10.6:1 and the h1 is 56px — it had no AREA of colour, and only area fixes that.

   A band is a full-bleed horizontal register:  <section class="band band--forest"><div class="wrap">
   Sections are block-level, so a full-bleed ground needs no negative-margin trick and cannot cause a
   horizontal scrollbar. Bands butt directly against one another: the change of ground IS the rule, so
   a band carries no border, and the hairline comes back only where two bands share a ground.
   ⚠ THE CADENCE RULE: no two adjacent bands may share a ground. That, and not any single colour, is
   what gives a page a pulse instead of four identical slabs. */
.band { padding: clamp(var(--sp-7), 5.5vw, var(--sp-8)) 0; }
.band--paper { background: var(--paper); }
.band--paper-2 { background: var(--paper-2); }
.band--forest { background: var(--forest); }
.band--forest-deep { background: var(--forest-deep); }
.band--paper + .band--paper, .band--paper-2 + .band--paper-2 { border-top: 1px solid var(--line); }
.band--tight { padding: var(--sp-6) 0; }
.band--tall { padding: clamp(var(--sp-8), 7vw, 96px) 0; }

/* ── standing on the forest ──────────────────────────────────────────────────────────────────────
   ONE reassignment block, and every component already written in this file is correct on a dark
   ground without being touched and without knowing where it is standing. This is why the band is
   cheap: outside :root, site.css resolves colour through var() almost everywhere, so reassigning
   the tokens inside a subtree carries .eyebrow, .lede, .lbl, .status, .face, .grammar, .role-router,
   .table, .disclose, .hash and .steps-row across for nothing. A component added next month is
   correct on the band without anybody remembering to write a variant for it. */
.band--forest, .band--forest-deep, .site-foot--forest {
  color: var(--pine-ink);
  --ink: var(--pine-ink);
  --ink-2: var(--pine-ink-2);
  --mute: var(--pine-ink-3);
  --pine: var(--pine-ink);
  --pine-2: var(--paper-hi);
  --brass-ink: var(--brass-2);
  --brass-type: var(--brass-2);
  --line: rgba(244, 239, 228, .18);
  --line-strong: rgba(244, 239, 228, .38);
  --paper: var(--forest-deep);
  --paper-2: var(--forest-deep);
  --holds: var(--holds-lit); --gap: var(--gap-lit); --refuted: var(--refuted-lit);
  --holds-bg: rgba(127, 199, 155, .10);
  --gap-bg: rgba(224, 176, 85, .10);
  --refuted-bg: rgba(239, 155, 144, .10);
  --info-bg: rgba(244, 239, 228, .07);
}
/* ⚠ --white IS DELIBERATELY NOT REASSIGNED, and this is the law that stops the band becoming a dark
   mode. A card standing on the forest is a SHEET OF PAPER laid on it: paper is still the material,
   the evidence is still read on paper, and a dossier is never printed on pine. A sheet therefore has
   to take its INK back too, or it renders near-white text on a near-white card. */
.band--forest :is(.card, .receipt, .face-row, .keys li, .plans, .newkey, .lamp, .map-frame, .sheet, .field, .table, .tabs, .drop, .status, .indcard, .industries__filters button, .pay-card, .verdict, .plotmap),
.band--forest-deep :is(.card, .receipt, .face-row, .keys li, .plans, .newkey, .lamp, .map-frame, .sheet, .field, .table, .tabs, .drop, .status, .indcard, .industries__filters button, .pay-card, .verdict, .plotmap) {
  --ink: #15201a; --ink-2: #3f4a44; --mute: #55605a;
  --pine: #123e2f; --pine-2: #1b5541;
  --brass-ink: #765b28; --brass-type: #765b28;
  --line: rgba(21, 32, 26, .16); --line-strong: rgba(21, 32, 26, .34);
  --paper: #f4f1ea; --paper-2: #ebe6da;
  --holds: #276a46; --gap: #7d5210; --refuted: #a3352c;
  --holds-bg: #e9f2ec; --gap-bg: #f8f0dc; --refuted-bg: #f7e9e7; --info-bg: #eef0ec;
  color: var(--ink);
}
/* a sheet laid on the forest floor: one darker hairline of contact and one short shadow, no lift */
.band--forest :is(.card, .receipt, .plans, .sheet, .indcard, .industries__filters button, .pay-card, .status, .verdict),
.band--forest-deep :is(.card, .receipt, .plans, .sheet, .indcard, .industries__filters button, .pay-card, .status, .verdict) {
  border-color: rgba(21, 32, 26, .22);
  box-shadow: 0 12px 26px -18px rgba(7, 26, 20, .85);
}
/* Hex, not tokens. Token reassignment on the card is the law; headings still inherited cream
   --pine from the band when a descendant selector missed. Measured 1.13:1 on pricing.html
   floor cards. A coloured .rung-head h3 keeps its own later rule. */
.band--forest :is(.card, .receipt, .plans, .sheet, .pay-card, .status, .indcard, .verdict, .plotmap, .map-frame),
.band--forest-deep :is(.card, .receipt, .plans, .sheet, .pay-card, .status, .indcard, .verdict, .plotmap, .map-frame) {
  border-color: #123e2f;
}
.band--forest :is(.card, .receipt, .plans, .sheet, .pay-card) :is(h1, h2, h3, h4),
.band--forest-deep :is(.card, .receipt, .plans, .sheet, .pay-card) :is(h1, h2, h3, h4),
.band--forest .indcard__name, .band--forest-deep .indcard__name,
.band--forest .status .bt, .band--forest-deep .status .bt,
.band--forest .verdict .vw, .band--forest-deep .verdict .vw,
.band--forest .card summary, .band--forest-deep .card summary {
  color: #123e2f;
}
.band--forest :is(.card, .receipt, .plans, .sheet, .pay-card, .status, .indcard, .verdict) :is(p, li, dd, dt, td, th, label, small, .bd, .vg, .vc, .muted, .indcard__blurb, .indcard__status, .indcard__when),
.band--forest-deep :is(.card, .receipt, .plans, .sheet, .pay-card, .status, .indcard, .verdict) :is(p, li, dd, dt, td, th, label, small, .bd, .vg, .vc, .muted, .indcard__blurb, .indcard__status, .indcard__when) {
  color: #15201a;
}
.band--forest .plans .amt, .band--forest-deep .plans .amt { color: #15201a; }
.band--forest .plans .inc, .band--forest-deep .plans .inc { color: #3f4a44; }
.band--forest .plans b, .band--forest-deep .plans b { color: #123e2f; }
.band--forest .field, .band--forest-deep .field {
  background: #fffdf9;
  color: #15201a;
  border: 2px solid #123e2f;
}
.band--forest .industries__filters button, .band--forest-deep .industries__filters button {
  background: #fffdf9;
  color: #123e2f;
  border: 2px solid #123e2f;
}
.band--forest .industries__filters [aria-pressed="true"],
.band--forest-deep .industries__filters [aria-pressed="true"] {
  background: #123e2f;
  color: #f4efe4;
  border-color: #123e2f;
}
.band--forest :is(.card, .receipt, .plans, .sheet, .pay-card) a:not(.btn),
.band--forest-deep :is(.card, .receipt, .plans, .sheet, .pay-card) a:not(.btn) {
  color: #123e2f;
  text-decoration-color: #765b28;
}
/* the primary action on a forest band is PAPER, never brass: brass names evidence, and an action is
   not evidence */
.band--forest .btn, .band--forest-deep .btn {
  background: var(--pine-ink); border-color: var(--pine-ink); color: var(--forest);
}
.band--forest .btn:hover, .band--forest-deep .btn:hover {
  background: var(--paper-hi); border-color: var(--paper-hi); color: var(--forest-deep);
}
.band--forest .btn--secondary, .band--forest-deep .btn--secondary,
.band--forest .btn--quiet, .band--forest-deep .btn--quiet {
  background: transparent; border-color: rgba(244, 239, 228, .45); color: var(--pine-ink);
}
.band--forest .btn--secondary:hover, .band--forest-deep .btn--secondary:hover,
.band--forest .btn--quiet:hover, .band--forest-deep .btn--quiet:hover {
  background: rgba(244, 239, 228, .10); border-color: var(--pine-ink); color: var(--pine-ink);
}
/* ⚠ TOKENS, NOT LITERALS, for the same reason the heading rule below had to go: this is a DESCENDANT
   selector and it reaches inside the white sheets standing on the band. Written as --pine-ink and
   --brass-2 it painted near-white links on white cards — measured 1.13:1 on pricing.html's
   "§ 3.1 Floors" and on enterprise.html's contact address. --pine and --brass-type are reassigned by
   the band AND reassigned back by the sheet, so one rule is correct in both places. */
/* ⚠ THE THIRD INSTANCE OF THE SAME MISTAKE, 2026-09-05, found by a red team after two were already
   fixed. The button rules above are descendant selectors, and --pine-ink and a literal rgba() are not
   tokens the .sheet block can reassign — so a .btn standing on a white card on a forest band drew
   paper-coloured text on a paper-coloured ground. Measured on account.html's billing card: 1.13:1 for
   the label and 1.06:1 for the border, on the two controls that take money — "Buy 500 closed stamps —
   €99" and "Billing, invoices and cards" were two blank gaps. The card is shown to every signed-in
   account on every deployment. A button on a sheet is an ordinary button; --pine and --pine-ink are
   both correct inside the sheet, so re-asserting is enough and no new token is needed. */
.band--forest :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) .btn,
.band--forest-deep :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) .btn {
  background: var(--pine); border-color: var(--pine); color: var(--pine-ink);
}
.band--forest :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) .btn:hover,
.band--forest-deep :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) .btn:hover {
  background: var(--pine-2); border-color: var(--pine-2); color: var(--pine-ink);
}
.band--forest :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) :is(.btn--secondary, .btn--quiet),
.band--forest-deep :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) :is(.btn--secondary, .btn--quiet) {
  background: transparent; border-color: var(--line-strong); color: var(--pine);
}
.band--forest :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) :is(.btn--secondary, .btn--quiet):hover,
.band--forest-deep :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) :is(.btn--secondary, .btn--quiet):hover {
  background: rgba(21, 32, 26, .05); border-color: var(--ink-2); color: var(--pine);
}
/* the focus ring follows the ground it lands on: brass-2 is 5.79:1 on the band but only 2.03:1 on a
   white sheet, so a keyboard user lost the ring exactly where the forms are */
.band--forest :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) :focus-visible,
.band--forest-deep :is(.card, .receipt, .plans, .newkey, .sheet, .pay-card) :focus-visible { outline-color: var(--pine); }
.band--forest a:not(.btn), .band--forest-deep a:not(.btn) {
  color: var(--pine); text-decoration-color: var(--brass-type);
}
.band--forest :focus-visible, .band--forest-deep :focus-visible { outline-color: var(--brass-2); }
.band--forest ::selection, .band--forest-deep ::selection { background: rgba(209, 176, 113, .32); }
/* ⚠ THERE IS NO HEADING RULE HERE, AND THAT IS DELIBERATE, 2026-09-05. This block used to carry
   `.band--forest h1,h2,h3 { color: var(--pine-ink) }`, which is a DESCENDANT selector: it reached
   inside the white sheets standing on the band too, so every heading on a card on a forest band was
   painted near-white on near-white — measured 1.13:1 on pricing.html's "The honest reason to pay."
   and on four headings of enterprise.html. The base rule already says `h1,h2,h3 { color: var(--pine) }`
   and --pine is reassigned to the paper ink by the band and back to dark green by the sheet, so the
   headings were already correct in both places and this rule could only break one of them. */

/* ── the grain: two declarations, no image, no request, no motion ────────────────────────────────
   A saw kerf rules the top of every forest band on two coprime frequencies (7 and 19) so it never
   reads as a machine rule, and the deep band carries end grain from a heart off the bottom-left
   corner on two periods that do not divide each other (37 and 61), so the ring spacing is irregular
   the way a tree's is. Both are gradients: zero bytes, no request, and both vanish in print. */
.band--forest, .band--forest-deep { position: relative; }
.band--forest::before, .band--forest-deep::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 5px; pointer-events: none;
  background: repeating-linear-gradient(90deg,
    rgba(244, 239, 228, .17) 0 1px, transparent 1px 7px,
    rgba(244, 239, 228, .09) 7px 8px, transparent 8px 19px);
}
.band--forest-deep {
  background-image:
    repeating-radial-gradient(circle at 12% 122%, transparent 0 36px, rgba(168, 132, 63, .085) 36px 37px),
    repeating-radial-gradient(circle at 12% 122%, transparent 0 60px, rgba(244, 239, 228, .05) 60px 61px);
}
.band--forest-deep > .wrap { position: relative; }

/* ── brass finally gets an area ──────────────────────────────────────────────────────────────────
   Measured 2026-09-05: brass filled NOTHING on any page — zero elements used it as a background
   sitewide. It survived as a text colour on five elements and a 1px border on seven, which is not a
   brand colour, it is a tint on a rule. The law that gives it a job: brass marks a thing that was
   SEALED. It is never a hover, never a button, never emphasis. */
.card--evidence, .receipt { border-top: 2px solid var(--brass); }
.band--forest :is(.card--evidence, .receipt),
.band--forest-deep :is(.card--evidence, .receipt) { border-top-color: var(--brass-2); }
/* ⚠ PRE-EXISTING CONTRAST FAILURES, found by measuring rather than by reading, 2026-09-05. Every one
   of these set var(--brass) as TEXT: 3.08:1 on paper, 3.42:1 on white, against this site's own
   4.5:1 bar. --brass-type is the token they were all reaching for (5.65 paper / 6.27 white). Shape
   still carries the meaning, as the display law requires; now the colour carries it too. */
/* ⚠ These were repointed AT THEIR OWN DECLARATIONS above rather than shadowed from here, which is
   what this block used to do. Shadowing lost: `details.disclose > summary::before` outranks
   `.disclose summary::before`, so the "+" stayed at 3.08:1 while the override looked correct in
   the diff. scripts/check-brass.mjs now says so in as many words when it convicts a line. */

/* ── the four lights get a second channel ────────────────────────────────────────────────────────
   ⚠ THIS FILE'S OWN HEADER SAYS the states must render in SHAPE and not only colour, "because a
   dossier is photocopied in greyscale". That was true of the outcome glyphs and FALSE of the four
   lights: until today .lamp was four identical 46px circles differing only in hue, so a photocopied
   dossier showed four grey discs and a reader could not tell an anchored light from a refuted one.
   Hue is exactly what a copier eats. Each light now carries a frame that survives greyscale —
   refuted double-struck, not-checked dashed, not-checked-yet a hairline, anchored solid with a
   struck corner. The colours are unchanged; the redundancy is what is new. */
.lamp.red, .light--red { border-width: 2px; outline: 1px solid var(--refuted); outline-offset: 2px; }
.lamp.amber, .light--amber { border-style: dashed; }
.lamp.white, .light--white { border-width: 1px; }
.lamp.anchored, .light--anchored { box-shadow: inset -9px -9px 0 -5px var(--holds); }

/* ── the gauge: the bracket drawn as a measurement, not described in a paragraph ──────────────────
   A span between two edges. A filled diamond is an edge that was bought; a dashed circle is an edge
   that never was, and the open span fades out rather than stopping — because an unfunded stamp does
   not fail, it stops being known above that point. Both edges read the SAME two custom properties as
   the span, so a page cannot state its own reading twice and then disagree with itself. */
.gauge { position: relative; height: 46px; width: 100%; --from: 0%; --to: 100%; }
.gauge__track {
  position: absolute; left: 0; right: 0; top: 22px; height: 7px;
  border-top: 1px solid var(--line-strong);
  background-image: repeating-linear-gradient(90deg, var(--line-strong) 0 1px, transparent 1px 12px);
}
.gauge__span {
  position: absolute; top: 20px; height: 5px;
  left: var(--from); right: calc(100% - var(--to)); background: var(--brass);
}
.gauge__span--open { background: linear-gradient(90deg, var(--brass) 40%, transparent); }
.gauge__edge {
  position: absolute; top: 15px; width: 15px; height: 15px; margin-left: -7.5px;
  background: var(--brass); clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
.gauge__edge--open { background: none; border: 1.5px dashed var(--mute); border-radius: 50%; clip-path: none; }
.gauge__edge--from { left: var(--from); }
.gauge__edge--to { left: var(--to); }
.gauge__cap { position: absolute; top: 0; font: 700 var(--fs-label)/1 var(--ui); letter-spacing: .12em; text-transform: uppercase; color: var(--mute); white-space: nowrap; }
.gauge__cap--from { left: var(--from); }
.gauge__cap--to { left: var(--to); transform: translateX(-100%); }
.band--forest .gauge__span, .band--forest-deep .gauge__span,
.band--forest .gauge__edge, .band--forest-deep .gauge__edge { background: var(--brass-2); }
.band--forest .gauge__span--open, .band--forest-deep .gauge__span--open {
  background: linear-gradient(90deg, var(--brass-2) 40%, transparent);
}

/* ── print: the forest is ink, and ink is not what a dossier is made of ──────────────────────────
   Everything load-bearing has to survive being printed and then photocopied in grey, so the bands
   flatten to white, the grain goes, the sheets lose their shadows, and the structure the change of
   ground was carrying comes back as a rule. */
@media print {
  .band, .band--forest, .band--forest-deep, .site-foot--forest {
    background: #fff !important; background-image: none !important; color: #000 !important;
    padding: 0 0 var(--sp-6);
    --ink: #000; --ink-2: #000; --mute: #333; --pine: #000; --pine-ink: #000;
    --line: #999; --line-strong: #000; --brass: #000; --brass-type: #000; --brass-ink: #000;
    /* ⚠ --brass-2 was missed here, so every gauge span, every gauge edge and every brass mark that a
       band had switched to it printed at 2.07:1 pale tan on white — legible on screen, gone on paper,
       on a product whose output is read from paper in a folder. */
    --brass-2: #000; --pine-ink-2: #000; --pine-ink-3: #333;
  }
  .band--forest::before, .band--forest-deep::before { display: none !important; }
  .band--forest :is(.card, .receipt, .plans, .sheet),
  .band--forest-deep :is(.card, .receipt, .plans, .sheet) { box-shadow: none; border-color: #000; }
  .band + .band { border-top: 1px solid #999; padding-top: var(--sp-5); }
}

/* Shared compact navigation and responsive working surfaces. */
.site-head__row { gap: var(--sp-3); flex-wrap: nowrap; }
.site-head__row > .mark { margin-right: auto; }
.site-head__row > .cart-chip { margin-left: 0; }
.nav-preferences { margin: var(--sp-2) var(--sp-3) 0; padding: var(--sp-4) 0 var(--sp-2); border-top: 1px solid var(--line); }
.nav-preferences__label { font-size: var(--fs-s); font-weight: 600; margin-bottom: var(--sp-2); }
.nav-preferences__note { font-size: var(--fs-xs); color: var(--mute); margin: var(--sp-2) 0 0; }
.nav-preferences .fx { display: flex; width: 100%; margin: 0; order: initial; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.nav-preferences .fx__btn { flex: 1; font-size: var(--fs-s); border: 0; border-right: 1px solid var(--line); border-radius: 0; }
.nav-preferences .fx__btn:last-child { border-right: 0; }
.nav-preferences .fx__btn[aria-pressed="true"] { background: var(--pine); color: var(--pine-ink); }
.site-nav a:not(.btn) { transition: background .15s ease; }
.site-head .menu-btn,.cart-chip,.balance-chip { border-radius: 6px; }
.btn { border-radius: 5px; transition: background .15s ease, border-color .15s ease, box-shadow .15s ease; }
.btn:focus-visible { outline-offset: 4px; }
input.field,select.field,textarea.field { border-radius: 5px; }
input.field:focus,select.field:focus,textarea.field:focus { border-color: var(--pine); box-shadow: 0 0 0 3px rgba(18,62,47,.09); }
button:disabled { cursor: not-allowed; }
.workflow-path { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-4) 0; }
.workflow-path a { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--tap); padding: var(--sp-2) var(--sp-3); text-decoration: none; border: 1px solid var(--line); border-radius: 5px; font-size: var(--fs-s); }
.workflow-path a[aria-current="page"] { color: var(--pine-ink); background: var(--forest); border-color: var(--forest); }
.workflow-path a:hover { box-shadow: inset 0 -2px var(--brass); }
.commercial-note { background: var(--paper-2); border-left: 3px solid var(--brass); padding: var(--sp-4); margin: var(--sp-5) 0; border-radius: 0 8px 8px 0; }
@media (max-width: 860px) {
  body:has(#tabChain) { --bottom-inset: 58px; }
  main input:not([type="checkbox"]):not([type="radio"]),main select,main textarea,.ask input,.ask textarea { font-size: 1rem !important; }
  main input[type="file"] { max-width: 100%; }
  .site-head .mark { column-gap: 6px; }
}
@media (max-width: 420px) {
  .site-head__row { width: calc(100% - 24px); gap: 6px; }
  .site-head .mark__glyph { width: 1.65rem; }
  .site-head .mark__name { font-size: 1.05rem; }
  .site-head .mark__sub { font-size: .55rem; letter-spacing: .12em; }
  .site-head .cart-chip { min-width: var(--tap); padding: 0 8px; }
  .site-head .cart-chip__lab { display: none; }
  .site-head .balance-chip { font-size: .875rem; }
  .site-head .balance-chip--out { padding: 0 6px; }
}
