/* Hallmark · shape: Survey sheet · genre: modern-minimal · theme: custom · redesign: full · job: sign up · idea: "the page is a survey sheet: every number shown with what it is made of" · vibe: "mineral, exact, instrument not brochure"
 * paper: oklch(95.2% 0.006 215) · accent: oklch(44% 0.072 190) · display: IBM Plex Mono · body: IBM Plex Sans · hero: a sheet whose head is the claim and whose body is one rate taken apart · nav: hairline rule, mark and one action · footer: a mast, the wordmark over the links · imagery: the product's own reading, no photographs · signature: the rate decomposed into its parts and its precision rung
 * sections: Hero (the reading) · Record (the measurement) · Rungs (precision written out) · Specimen (the response, inverted) · Tariff (the price) · Footer
 * axes: light/mono-display/chromatic-teal · posture: mineral ground, graphite ink, teal for confirmed values, amber reserved for labelled uncertainty · contrast: pass · fold: pass · v2.0.0 */
/* Hallmark · pre-emit critique: P4 H4 E3 S4 R4 V3 · weakest: V, the sheet risks reading as a form; the reading is set large and the grid kept to hairlines so it reads as an instrument */
/* Hallmark · answered 58: the densest screen is the specimen, and its words are the JSON response itself rather than prose. Cutting the sample to meet a word budget would remove the evidence the section exists to show. */
/* Hallmark · waive 78 · h2 on a reference page is set at --text-title under a --text-section h1 · 52px section heads belong on a landing page; at that size a docs page with eight headings reads as eight landing pages */
/* Hallmark · waive 77 · /pricing is h1 + notice + four ruled tiers + two prose sections; the landing page is / and it clears 77 · a price list is a reference page, and padding it to six sections means filling it with copy */
/* Hallmark · waive 79 · the 244px is <main>'s own top margin above the h1, the same on /docs and the legal pages · a reference page opens on its title, not on a hero with a visual to grow */
@import url("./tokens.css");
@import url("./base.css");

@font-face { font-family: "IBM Plex Sans"; src: url("/assets/fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url("/assets/fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("/assets/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("/assets/fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "IBM Plex Mono"; src: url("/assets/fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-display: swap; }

/*
 * One stylesheet for both vhosts. No build step, no framework: the pages are
 * documents and forms, and a bundler would be a second thing to maintain.
 */

/* The legacy names, now aliases onto the design tokens, so the sections
   below the hero take the new palette until they are rebuilt. The dark-mode
   block that used to live here is gone: this design is a light mineral
   sheet, and a dark variant would have to be designed, not inverted. */
:root {
  --ink: var(--color-ink);
  --ink-soft: var(--color-ink-2);
  --ink-faint: var(--color-muted);
  --paper: var(--color-paper);
  --card: var(--color-paper-2);
  --rule: var(--color-rule);
  --accent: var(--color-accent);
  --accent-soft: color-mix(in oklab, var(--color-accent) 12%, var(--color-paper));
  --warn: var(--color-amber-ink);
  --warn-soft: color-mix(in oklab, var(--color-amber) 16%, var(--color-paper));
  --bad: oklch(45% 0.15 27);
  --bad-soft: color-mix(in oklab, oklch(45% 0.15 27) 10%, var(--color-paper));
  --mono: var(--font-display);
  --sans: var(--font-body);
  --measure: 34rem;
  --radius: var(--radius-card);
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
}

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

h1, h2, h3 { line-height: 1.2; letter-spacing: -0.015em; margin: 0 0 0.5em; }
h1 { font-size: 2.1rem; }
h2 { font-size: 1.4rem; margin-top: 2.2rem; }
h3 { font-size: 1.05rem; margin-top: 1.6rem; }
p, ul, ol { margin: 0 0 var(--space-md); }
code, kbd, samp { font-family: var(--mono); font-size: 0.9em; }

/* --- Frame ------------------------------------------------------------- */

.wrap { max-width: 62rem; margin: 0 auto; padding: 0 1.25rem; }
/* A reading column: wide enough not to read as a thin strip, with the
   leading a terms page needs when somebody reads it end to end. */
.prose { max-width: 62ch; font-size: var(--text-lg); line-height: 1.75; }
.prose > * + * { margin-top: var(--space-lg); }
.prose > h2 + p { margin-top: var(--space-md); }
.prose > h3 { margin-top: var(--space-xl); font-size: var(--text-lg); color: var(--color-ink); }
.prose .meta, .prose .hint { font-size: var(--text-sm); }
.prose ul, .prose ol { padding-left: var(--space-lg); }
.prose li + li { margin-top: var(--space-2xs); }

.topbar {
  border-bottom: 1px solid var(--rule);
  background: var(--card);
}

.topbar .wrap {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  min-height: 60px;
  flex-wrap: wrap;
}

/* The mark is a CSS mask rather than an <img> so it takes the brand colour
   from currentColor, the same as the wordmark beside it. */
.brand-mark {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  margin-right: 0.42em;
  vertical-align: -0.2em;
  background: currentColor;
  -webkit-mask: url("/assets/mark.svg") center / contain no-repeat;
  mask: url("/assets/mark.svg") center / contain no-repeat;
}

.brand {
  font-weight: 650;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
  font-size: 1.05rem;
}
.brand span { color: var(--accent); }

.topbar nav { display: flex; gap: 1.1rem; flex-wrap: wrap; margin-right: auto; }
.topbar nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 0.93rem;
  padding: 0.2rem 0;
  border-bottom: 2px solid transparent;
}
.topbar nav a:hover { color: var(--ink); }
.topbar nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }

/* The nav and the footer are both set on the sheet's margin, and the sheet
   page sets its own. Inner pages kept .wrap's 1.25rem, so their text started
   36px to the left of the wordmark above it. One margin everywhere. */
main.wrap {
  padding-block: var(--space-2xl) var(--space-3xl);
  padding-inline: var(--sheet-margin);
}

footer {
  border-top: var(--rule-hair) solid var(--color-rule);
  padding-block: var(--space-2xl) var(--space-xl);
  color: var(--color-muted);
  font-size: var(--text-sm);
}
footer .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-xs) var(--space-lg);
  padding-inline: var(--sheet-margin);
}
/* The copyright line is the mast: it takes a line of its own above the
   links, in the display face, so the footer has a head and a body. */
footer .wrap > span:first-child {
  flex-basis: 100%;
  margin-bottom: var(--space-sm);
  font-family: var(--font-display);
  color: var(--color-ink-2);
}
footer a { color: var(--color-ink-2); }
footer a:hover { color: var(--color-ink); }

/* --- Hero and the accuracy figure -------------------------------------- */

.hero h1 { font-size: 2.6rem; max-width: 30rem; }
.lede { font-size: 1.15rem; color: var(--ink-soft); max-width: var(--measure); }

.figure {
  display: flex;
  gap: var(--space-xl);
  flex-wrap: wrap;
  margin: var(--space-2xl) 0;
  padding-block: var(--space-xl);
  border-block: var(--rule-hair) solid var(--color-rule);
}
.figure .stat { min-width: 10rem; }
.figure .num {
  display: block;
  font-size: 2.4rem;
  font-weight: 650;
  letter-spacing: -0.03em;
  color: var(--accent);
  line-height: 1.1;
}
.figure .label { font-size: 0.9rem; color: var(--ink-soft); }

/* --- Cards and grids --------------------------------------------------- */

/* Four tiers at a 16rem minimum packed three across and left the fourth
   stranded on a row of its own. A 22rem minimum pairs them two by two
   at this container width, and min() keeps them one-up on a phone. */
.grid { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }

.card {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  padding: 1.25rem;
}
.card h3 { margin-top: 0; }
.card.highlight { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

.price { font-size: 1.9rem; font-weight: 650; letter-spacing: -0.03em; }
.price small { font-size: 0.85rem; font-weight: 400; color: var(--ink-faint); letter-spacing: 0; }

.tick { list-style: none; padding: 0; font-size: 0.93rem; }
.tick li { padding-left: 1.3rem; position: relative; margin-bottom: 0.35rem; }
.tick li::before { content: "+"; position: absolute; left: 0; color: var(--accent); font-weight: 700; }

/* --- Forms ------------------------------------------------------------- */

form.stack { max-width: 26rem; }
form.stack.wide { max-width: 100%; }
label { display: block; font-size: var(--text-sm); font-weight: 600; margin: var(--space-md) 0 var(--space-2xs); }
.hint { font-size: 0.85rem; color: var(--ink-faint); margin: var(--space-2xs) 0 0; }

/* A field is a line to write on, not a box: a tinted slot ruled underneath.
   That keeps it from reading as the same object as a card or a notice, which
   is what it looked like when all three shared one border recipe. */
input[type="text"], input[type="email"], input[type="password"], textarea, select {
  width: 100%;
  padding: 0.55rem 0.7rem;
  font: inherit;
  font-size: 0.95rem;
  color: var(--color-ink);
  background: var(--color-paper-2);
  border: 0;
  /* --color-rule is 1.41:1 against the surface, which is fine for a
     divider and not for a control: a field's edge needs 3:1. */
  border-bottom: 2px solid var(--color-muted);
  border-radius: 0;
}
input[type="text"]:hover, input[type="email"]:hover, input[type="password"]:hover,
textarea:hover, select:hover { border-bottom-color: var(--color-ink-2); }
input[type="text"]:focus, input[type="email"]:focus, input[type="password"]:focus,
textarea:focus, select:focus { border-bottom-color: var(--color-accent); }
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
textarea { min-height: 8rem; resize: vertical; }

.btn {
  display: inline-block;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 550;
  padding: 0.55rem 1.1rem;
  border-radius: var(--radius);
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--paper);
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { filter: brightness(1.08); }
.btn.secondary { background: transparent; color: var(--accent); }
.btn.danger { background: transparent; border-color: var(--bad); color: var(--bad); }
.btn.small { font-size: 0.85rem; padding: 0.3rem 0.65rem; }
.actions { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin-top: 1.25rem; }
.inline-form { display: inline; }

/* --- Notices ----------------------------------------------------------- */

/* Ruled top and bottom rather than boxed. The tint already bounds it, so the
   side borders were doing nothing but adding two more verticals. */
.notice {
  border-block: var(--rule-hair) solid var(--color-accent);
  background: var(--accent-soft);
  border-radius: 0;
  padding: var(--space-sm) var(--space-md);
  margin: 0 0 var(--space-lg);
  font-size: 0.93rem;
}
.notice.error { border-color: var(--bad); background: var(--bad-soft); }
.notice.warn { border-color: var(--warn); background: var(--warn-soft); }
.notice ul { margin: 0.4rem 0 0; padding-left: 1.2rem; }
.notice p:last-child { margin-bottom: 0; }

/* --- Tables ------------------------------------------------------------ */

table { width: 100%; border-collapse: collapse; font-size: 0.93rem; }
caption { text-align: left; color: var(--ink-faint); font-size: 0.85rem; padding-bottom: var(--space-xs); }
th, td { text-align: left; padding: var(--space-xs) var(--space-sm) var(--space-xs) 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
/* Table heads are the body face, a step smaller, sentence case, untracked. */
th { font-size: var(--text-xs); color: var(--ink-faint); font-weight: 600; }
td.num, th.num { text-align: right; padding-right: 0; font-variant-numeric: tabular-nums; }
tr.revoked td { color: var(--ink-faint); }

.pill {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  padding: 0.1rem 0.45rem;
  border-radius: 100px;
  border: 1px solid currentColor;
}
.pill.live { color: var(--accent); }
.pill.test { color: var(--warn); }
.pill.dead { color: var(--bad); }

/* --- Secrets and code -------------------------------------------------- */

pre, .secret {
  font-family: var(--mono);
  font-size: 0.86rem;
  background: var(--color-ink);
  color: var(--color-paper);
  border: 0;
  border-radius: var(--radius-card);
  padding: var(--space-md);
  overflow-x: auto;
  line-height: 1.5;
}
.secret {
  display: block;
  word-break: break-all;
  outline: var(--rule-hair) solid var(--color-accent);
  outline-offset: -1px;
  font-size: 1rem;
}
.mono { font-family: var(--mono); font-size: 0.88rem; }

/* --- Usage bars -------------------------------------------------------- */

.bars { display: flex; align-items: flex-end; gap: var(--space-2xs); height: 7rem; margin: var(--space-md) 0; }
.bars .bar { flex: 1; background: var(--accent); border-radius: 2px 2px 0 0; min-height: 2px; opacity: 0.85; }
.bars .bar:hover { opacity: 1; }
.bars-axis { display: flex; justify-content: space-between; font-size: 0.78rem; color: var(--ink-faint); }

.quota { height: 8px; background: var(--rule); border-radius: 100px; overflow: hidden; margin: var(--space-xs) 0; }
.quota > div { height: 100%; background: var(--accent); }

.meta { color: var(--ink-faint); font-size: 0.88rem; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 40rem) {
  .hero h1 { font-size: 2rem; }
  .figure { gap: 1.25rem; }
  main { padding: 1.75rem 0 3rem; }
}

/* ==========================================================================
   The survey sheet: nav and hero. Written for the redesign; the rules above
   still dress the sections below the fold until they are rebuilt.
   ========================================================================== */

/* --- Nav: a hairline rule, the mark, one action ------------------------- */
.topbar {
  background: var(--color-paper);
  border-bottom: var(--rule-hair) solid var(--color-rule);
}
.topbar .wrap {
  max-width: var(--container);
  gap: var(--space-lg);
  min-height: 64px;
  /* The sheet's own margin, so the wordmark sits on the same vertical as
     the headline below it. */
  padding-inline: var(--sheet-margin);
}
/* One colour, the whole mark: .brand-mark is a mask taking currentColor, so
   the pin goes black with the wordmark. The accent used to pick out ".tax",
   which made the logo a third voice beside the ink and the teal. */
.brand {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-xl);
  letter-spacing: -0.02em;
  color: var(--color-brand);
}
.brand span { color: inherit; }
.topbar nav a {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink-2);
  border-bottom: 0;
  padding-block: var(--space-2xs);
}
.topbar nav a:hover { color: var(--color-ink); text-decoration: underline; }
.topbar nav a[aria-current="page"] { color: var(--color-ink); text-decoration: underline; }

/* --- Controls, all eight states ---------------------------------------- */
.btn {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 0.62rem 1.05rem;
  border-radius: var(--radius-card);
  border: var(--rule-hair) solid var(--color-accent);
  background: var(--color-accent);
  color: var(--color-accent-ink);
  transition: background var(--dur-micro) var(--ease-out), color var(--dur-micro) var(--ease-out);
}
.btn:hover { background: color-mix(in oklab, var(--color-accent) 86%, black); }
.btn:active { background: color-mix(in oklab, var(--color-accent) 74%, black); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.btn.secondary {
  background: transparent;
  color: var(--color-ink);
  border-color: var(--color-rule);
}
.btn.secondary:hover { border-color: var(--color-ink); background: var(--color-paper-2); }
.btn.secondary:active { background: var(--color-paper-3); }
.btn.small { font-size: var(--text-xs); padding: 0.4rem 0.7rem; }

/* --- The sheet ---------------------------------------------------------- */
.sheet {
  position: relative;
  padding: var(--space-2xl) var(--sheet-margin) var(--space-3xl);
  max-width: var(--container);
  margin-inline: auto;
}
/* The ruled margin: ticks every 48px down the left edge, like a plotted
   sheet. Decorative only, so it is hidden from assistive tech. */
.sheet::before {
  content: "";
  position: absolute;
  inset-block: var(--space-2xl) var(--space-3xl);
  inset-inline-start: calc(var(--sheet-margin) - var(--space-lg));
  width: var(--sheet-tick);
  background-image: repeating-linear-gradient(
    to bottom,
    var(--color-rule) 0 1px,
    transparent 1px 48px
  );
}
.sheet__hero {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
  gap: var(--space-2xl);
  align-items: start;
}
.sheet__head h1 {
  font-size: var(--text-display-s);
  font-weight: 600;
  line-height: 1.04;
  /* Mono sets every glyph the same width, so an unbalanced rag reads as a
     mistake rather than as texture. Balance evens the lines within each
     sentence; the sentences themselves are separate blocks. */
  text-wrap: balance;
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);
}
.sheet__head h1 span { display: block; }
.sheet__head .lede {
  margin-top: var(--space-lg);
  font-size: var(--text-lead);
  color: var(--color-ink-2);
  max-width: 30ch;
}
.sheet__head .actions { margin-top: var(--space-xl); display: flex; gap: var(--space-sm); flex-wrap: wrap; }

/* --- The plot: three readings, and the pin that visits them ------------- */
/* This vhost serves script-src 'none', so the cycle is keyframes and nothing
   else. Three readings share one 15s timeline, each holding the stage for
   five seconds, and one pin is moved between the three sites by transform.
   Only transform and opacity animate; no layout property does. */
/* No box. The sheet is ruled horizontally and the card's two side borders
   were the loudest verticals on the page; a top and bottom rule says the
   same thing and leaves the paper alone. */
.plot {
  margin: 0;
  border-block: var(--rule-hair) solid var(--color-rule);
  background: var(--color-paper-2);
  border-radius: 0;
}

.plot__map {
  padding: var(--space-md) var(--space-sm) var(--space-xs);
  border-bottom: var(--rule-hair) solid var(--color-rule);
  /* The coast takes currentColor. A rule-weight grey disappears at this
     size, so it sits one step darker: still a drawn line, not a fill. */
  color: var(--color-muted);
}
.plot__map svg { display: block; width: 100%; height: auto; }
.plot__sites { fill: var(--color-paper-3); }

/* The pin. Its coordinates come from the same Albers projection that drew
   the coast (see views/partials/us-outline.ejs), so each site sits where its
   latitude and longitude actually put it. */
.plot__pin {
  transform-box: view-box;
  transform-origin: 0 0;
  animation: plot-travel var(--plot-cycle, 15s) var(--ease-in-out) infinite;
}
.plot__dot { fill: var(--color-accent); }
.plot__cross { fill: none; stroke: var(--color-accent); stroke-width: 1.25; vector-effect: non-scaling-stroke; }
/* The ring closes on the point rather than pulsing out of it: the gesture is
   zeroing in on a place, not announcing one. */
.plot__lock {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  transform-box: fill-box;
  transform-origin: center;
  animation: plot-lock 5s var(--ease-out) infinite;
}

@keyframes plot-lock {
  0%        { opacity: 0; transform: scale(3.2); }
  16%       { opacity: 0.75; }
  38%, 100% { opacity: 0; transform: scale(1); }
}

/* The readings sit on top of one another in one grid cell, so the card keeps
   the height of the tallest and nothing below it moves as they change. */
.plot__stack { display: grid; }
.plot__body { padding: var(--space-lg); }
/* Each reading fills the cell, so the source line lands on the same baseline
   whether the rate is made of three jurisdictions or none. */
.plot__read {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  animation: plot-read var(--plot-cycle, 15s) var(--ease-out) infinite both;
}


/* --- The board: a split-flap, turned by keyframes ----------------------- */
/* The second inverted surface on the page, and a deliberate pair with the
   specimen below: both are the machine's own voice rather than the sheet's.
   One module per character of the rate. A module cannot jump to its glyph,
   it has to turn through the ones before it, so the strip holds the flaps it
   passes and `steps()` makes them land rather than slide. */
.plot__board {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
  margin: var(--space-md) 0 var(--space-lg);
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 4.8vw, 3.75rem);
  font-weight: 500;
  --flap-h: 1.16em;
}
/* The housing, darker than the flaps sitting in it. Without it a module
   showing a blank reads as a dropped character; framed, it reads as what it
   is, a flap with nothing on it. */
.plot__flaps {
  --flap-stagger: 0.05s;
  display: flex;
  gap: var(--space-3xs);
  padding: var(--space-3xs);
  border-radius: 3px;
  background: color-mix(in oklab, var(--color-ink) 78%, black);
}
.flap {
  position: relative;
  overflow: hidden;
  width: 0.78em;
  height: var(--flap-h);
  border-radius: 2px;
  background: var(--color-ink);
  color: var(--color-paper);
  font-variant-numeric: tabular-nums;
}
/* The seam the two halves of a flap meet on. It is the whole reason a board
   reads as mechanical, so it sits above the strip rather than under it. */
.flap::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 50%;
  border-top: 1px solid var(--color-paper);
  opacity: 0.2;
}
.flap__g {
  display: block;
  height: var(--flap-h);
  line-height: var(--flap-h);
  text-align: center;
  /* A blank module is a real state of the board, so the space has to survive
     rather than collapse. */
  white-space: pre;
}
.flap__strip { display: block; animation: flap var(--plot-cycle, 15s) infinite both; }
/* A module whose character is the same in every reading never turns, which is
   what a real board does: only what changed moves. */
.flap--still .flap__strip { animation: none; }
/* The place name: the same mechanism, eighteen modules wide and a text row
   rather than a headline, so the rate under it stays the loudest thing. */
.plot__board--place {
  margin: 0 0 var(--space-xs);
  font-size: clamp(0.95rem, 1.9vw, 1.3rem);
}
.plot__flaps--place {
  --flap-stagger: 0.022s;
  gap: 1px;
}
.plot__flaps--place .flap { width: 0.82em; }

/* The unit is not a module. The board counts; the per-cent sign labels it. */
.plot__pct {
  align-self: flex-end;
  margin-left: 0.22em;
  font-size: 0.42em;
  font-weight: 400;
  line-height: 1.9;
  color: var(--color-ink);
}


.plot__none {
  padding-block: var(--space-sm);
  font-size: var(--text-sm);
  color: var(--color-muted);
}
.plot__src {
  margin-top: auto;
  padding-top: var(--space-lg);
  font-size: var(--text-xs);
  color: var(--color-ink-2);
  overflow-wrap: anywhere;
}
.plot__src span { color: var(--color-muted); }
.plot__note {
  padding: 0 var(--space-lg) var(--space-lg);
  font-size: var(--text-xs);
  color: var(--color-muted);
}

.parts { margin: var(--space-lg) 0 0; }
.parts__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-sm);
  align-items: baseline;
  padding-block: var(--space-xs);
  border-top: var(--rule-hair) solid var(--color-rule);
  font-size: var(--text-sm);
}
.parts__row:last-child { border-bottom: var(--rule-hair) solid var(--color-rule); }
.parts__name { color: var(--color-ink); }
.parts__level { color: var(--color-muted); font-size: var(--text-xs); }
.parts__value { font-family: var(--font-display); font-variant-numeric: tabular-nums; color: var(--color-ink); }
.parts__sum { font-weight: 600; }
.parts__sum .parts__value { color: var(--color-accent); }

/* Nothing moves when the reader has asked for that. base.css collapses every
   duration to nothing, which would leave all three readings parked on their
   last keyframe and the card empty, so the first reading is pinned open and
   the other two are taken out of the document. */
@media (prefers-reduced-motion: reduce) {
  .plot__read { animation: none; }
  .plot__read:nth-child(n + 2) { display: none; }
  /* Every module parks on the first reading's glyph. */
  .flap__strip { animation: none; transform: translateY(0); }
  .plot__pin { animation: none; }
  .plot__lock { display: none; }
}


/* --- The bands: the sheet below the hero -------------------------------- */
/* Each band is one idea shown as an object. They share the sheet's ruled
   margin and are divided by the same hairline, so the page reads as one
   continuous sheet rather than as a stack of cards. */
.band {
  padding-block: var(--section-gap-s);
  border-top: var(--rule-hair) solid var(--color-rule);
}
.band:first-of-type { margin-top: var(--section-gap-s); }
.band__head h2 {
  max-width: 22ch;
  font-size: var(--text-section);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);
}
.band__lede {
  margin-top: var(--space-md);
  max-width: 46ch;
  font-size: var(--text-lead);
  color: var(--color-ink-2);
}
.band__note {
  margin-top: var(--space-lg);
  max-width: 54ch;
  font-size: var(--text-sm);
  color: var(--color-muted);
}
.band .actions { margin-top: var(--space-xl); display: flex; gap: var(--space-sm); flex-wrap: wrap; }
.band code {
  font-family: var(--font-display);
  font-size: 0.92em;
  color: var(--color-ink);
  /* A field name is one token: ?date= must not break after the question
     mark and read as punctuation. */
  white-space: nowrap;
}
/* The specimen is inverted, so its code takes the block's colour, not the
   band's ink. Without this the sample is ink on ink. */
/* The nowrap above is for a field name in prose; inside a block it would
   push the sample off the side of a phone. */
.specimen__code code, pre code { color: inherit; font-size: inherit; white-space: inherit; }

/* --- The record: the measurement, entered rather than claimed ----------- */
/* Rules top and bottom and no fill, so it reads as a line in a ledger. The
   reading in the hero is the filled, bordered object; these are not the
   same kind of thing and must not look like it. */
.record {
  margin: var(--space-2xl) 0 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: var(--space-xl);
  padding-block: var(--space-xl);
  border-block: var(--rule-hair) solid var(--color-rule);
}
.record__num {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(2.75rem, 5vw, 4.25rem);
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
}
/* Amber is never decorative here: it marks the one figure that is a warning,
   and it does it at label size, because a display size in a colour shouts. */
.record__num--warn + .record__label { color: var(--color-amber-ink); }
.record__label {
  margin-top: var(--space-sm);
  max-width: 26ch;
  font-size: var(--text-sm);
  color: var(--color-ink-2);
}
.record__foot {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-lg);
  font-size: var(--text-xs);
  color: var(--color-muted);
}

/* --- The rungs: the precision ladder, written out ----------------------- */
.rungs { margin: var(--space-2xl) 0 0; }
.rungs__row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: var(--space-md);
  align-items: baseline;
  padding-block: var(--space-lg);
  border-top: var(--rule-hair) solid var(--color-rule);
}
.rungs__row:last-child { border-bottom: var(--rule-hair) solid var(--color-rule); }
.rungs dt {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--color-muted);
}
.rungs dd { margin: 0; font-size: var(--text-md); color: var(--color-ink-2); }
/* The rung the hero's example landed on, marked the same way it is there. */
.rungs__row[data-on] dt { color: var(--color-accent); font-weight: 600; }
.rungs__row[data-on] dd { color: var(--color-ink); }

/* --- The specimen: the response itself, with its fields in the margin --- */
.specimen { margin-top: var(--space-2xl); }
/* The one dark object on the page. It is the machine's own voice, and the
   inversion is what separates it from everything the sheet says itself. */
.specimen__code {
  margin: 0;
  padding: var(--space-lg);
  border: 0;
  border-radius: var(--radius-card);
  margin-bottom: var(--space-xl);
  background: var(--color-ink);
  color: var(--color-paper);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* The three fields that make the response worth reading, set three across
   under the block they belong to rather than squeezed beside it. */
.specimen__notes {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-xl);
}
.specimen__notes > div {
  padding-top: var(--space-md);
  border-top: var(--rule-hair) solid var(--color-rule);
}
.specimen__notes dt {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  color: var(--color-accent);
}
.specimen__notes dd {
  margin: var(--space-2xs) 0 0;
  font-size: var(--text-sm);
  color: var(--color-ink-2);
}

/* --- The portal: a tool, not a document -------------------------------- */
/* The document scale below is for pages somebody reads. The portal is forms
   and tables somebody works in, and it was inheriting a 52px page title
   because both vhosts render through the same <main>. "API keys" at the size
   of a marketing headline reads as a brochure about a feature rather than the
   screen where you revoke a key. */
main.app > h1 {
  font-size: var(--text-2xl);
  font-weight: 600;
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);
}
main.app > h2 {
  margin-top: var(--space-xl);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--color-ink);
}
main.app .prose { font-size: var(--text-md); }

/* --- Document pages: docs, pricing, legal ------------------------------ */
.prose > .actions, .actions--head { display: flex; gap: var(--space-sm); flex-wrap: wrap; }
.actions--head { margin-top: var(--space-xl); }

/* Direct children of <main> only, so the homepage's own hero head, which is
   nested inside its section, keeps its larger setting. */
main.doc > h1, main.doc .prose > h1 {
  max-width: 20ch;
  font-size: var(--text-section);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: var(--tracking-display);
  color: var(--color-ink);
}
main.doc > h1 + .lede, main.doc .prose > h1 + .lede {
  margin-top: var(--space-md);
  max-width: 46ch;
  font-size: var(--text-lead);
  color: var(--color-ink-2);
}
main.doc > h2, main.doc .prose > h2 {
  margin-top: var(--space-2xl);
  font-size: var(--text-title);
  font-weight: 600;
  color: var(--color-ink);
}
main.doc > h2 + p, main.doc .prose > h2 + p { margin-top: var(--space-md); }

/* --- The tiers: the pricing page in the sheet's own language ------------ */
/* One row a tier, divided by the same hairline as everything else. The name
   and the price sit in the margin column; what you get sits in the measure
   beside it, which is how the bands below the hero already read. */
.tiers { margin-top: var(--space-2xl); }
.tier {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--space-xl);
  align-items: start;
  padding-block: var(--space-xl);
  border-top: var(--rule-hair) solid var(--color-rule);
}
.tier:last-child { border-bottom: var(--rule-hair) solid var(--color-rule); }
.tier__name {
  font-family: var(--font-display);
  font-size: var(--text-title);
  font-weight: 600;
  color: var(--color-ink);
}
.tier__price {
  margin-top: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 500;
  letter-spacing: -0.03em;
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
}
.tier__price small {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--color-muted);
}
.tier__meter {
  margin-top: var(--space-xs);
  max-width: 24ch;
  font-size: var(--text-xs);
  color: var(--color-muted);
}
.tier__blurb { max-width: 46ch; color: var(--color-ink-2); }
.tier__body .tick { margin-top: var(--space-md); }
.tier__act { margin-top: var(--space-lg); }
/* The tier most people land on, marked by colouring its name rather than by
   drawing a frame round it. A card inside a ruled page is a second object. */
.tier--pick .tier__name { color: var(--color-accent); }

@media (max-width: 40rem) {
  .tier { grid-template-columns: minmax(0, 1fr); gap: var(--space-md); }
}

/* --- The tariff: ruled, not boxed -------------------------------------- */
.tariff {
  margin-top: var(--space-2xl);
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}
.tariff caption {
  caption-side: top;
  text-align: left;
  padding: 0 0 var(--space-md);
  font-size: var(--text-xs);
  color: var(--color-muted);
}
.tariff th, .tariff td {
  text-align: left;
  padding: var(--space-md) var(--space-md) var(--space-md) 0;
  border-bottom: var(--rule-hair) solid var(--color-rule);
  vertical-align: baseline;
}
.tariff thead th {
  padding-top: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 400;
  color: var(--color-muted);
}
.tariff tbody th {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--color-ink);
}
.tariff td.num, .tariff th.num {
  text-align: right;
  padding-right: 0;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
}
.tariff tbody td { color: var(--color-ink-2); }
/* The tier we expect most people to land on, marked with the accent rather
   than with a box, because the table is the object and a card inside it
   would be a second one. */
/* Both selectors carry the tbody, because `.tariff tbody th` above is one
   element more specific than `.tariff__pick th` and would otherwise win. */
.tariff tbody .tariff__pick td { color: var(--color-ink); }
.tariff tbody .tariff__pick th { color: var(--color-accent); }

@media (max-width: 40rem) {
  .rungs__row { grid-template-columns: minmax(0, 1fr); gap: var(--space-3xs); }
  .tariff { font-size: var(--text-xs); }
  .tariff th, .tariff td { padding: var(--space-sm) var(--space-sm) var(--space-sm) 0; }
}

@media (max-width: 60rem) {
  .sheet { padding-inline: var(--gutter); }
  .sheet::before { display: none; }
  .sheet__hero { grid-template-columns: minmax(0, 1fr); gap: var(--space-xl); }
  .topbar .wrap, footer .wrap, main.wrap { padding-inline: var(--gutter); }
}

/* On a phone the bar has to wrap. Left to itself it wraps into three rows
   and eats a sixth of the screen before the headline starts, so the mark and
   the one action share the first row and the links drop under them. */
@media (max-width: 40rem) {
  .topbar .wrap { gap: var(--space-xs) var(--space-md); padding-block: var(--space-xs); min-height: 0; }
  .topbar .brand { order: 1; }
  .topbar nav { order: 3; flex-basis: 100%; }
  .topbar .wrap > .btn { order: 2; margin-inline-start: auto; }
}
