/* Relay — one stylesheet for the marketing site, the docs, and the dashboard.
   The identity: ink on paper, monospace for anything the machine said, and a single cobalt
   accent. Green, amber and red are reserved for delivery states, never for decoration. */

/* ---------------------------------------------------------------- tokens */
:root {
  --paper: #fbfaf8;
  --surface: #ffffff;
  --surface-2: #f4f3ef;
  --surface-3: #ecebe5;
  --ink: #14171d;
  --ink-soft: #2e3541;
  --muted: #5b6573;
  --faint: #8b94a1;
  --line: #e4e2dc;
  --line-strong: #d2cfc6;

  --accent: #2438e0;
  --accent-hover: #1a2bb8;
  --accent-ink: #ffffff;
  --accent-soft: #eceefe;
  --accent-line: #c6cbfb;

  --ok: #0f7a4a;
  --ok-soft: #e3f3ea;
  /* Chart fills, kept apart from the text colours above.
     A bar needs 3:1 against the surface; text needs 4.5:1. Using one colour for both means
     either the text is illegible or the bars are muddy, and this palette was muddy.
     More importantly, the old bounced amber and complained red were ΔE 0.8 apart under
     deuteranopia — the same colour to roughly one man in twelve — and ΔE 12.7 even with full
     colour vision, on a chart whose only job is saying what went wrong. Complained is now a
     crimson-magenta, which carries a blue component and so survives red-green colour blindness.
     Measured, not chosen: every pair clears the separation floor. */
  --ok-mark: #02a07a;
  --warn-mark: #e2900a;
  --bad-mark: #d6206e;
  --muted-mark: #adaaa0;
  /* A brighter green for dots and small filled shapes — things with nothing written on them, so
     nothing has to stay legible against them. The text green cannot follow it there: --ok sits at
     4.68:1 on the badge background and 4.5 is the floor, so one step lighter is unreadable. A
     white tick on a green this light measures 1.9:1, which looks fresh and cannot be seen. */
  --ok-dot: #11b57f;
  --warn: #8d5b00;
  --warn-soft: #faefd8;
  --bad: #b42318;
  --bad-soft: #fce9e7;
  --info: #1d5da4;
  --info-soft: #e7eff9;
  /* Record types, one hue each, so five rows of DNS read as five kinds of thing. Chosen apart from
     the status colours: a green TXT beside a red "missing" would say two contradictory things. */
  --type-cname: #6d4aff;
  --type-mx: #c2570c;
  --type-txt: #0e7f86;

  /* Chart marks are their own tokens, not the UI accent: each mode's pair is stepped to sit in
     that mode's lightness band and to stay separable under colour-vision deficiency. */
  --chart-1: #2438e0;
  --chart-2: #b42318;
  --chart-grid: #ebe9e4;

  --shadow-sm: 0 1px 2px rgb(20 23 29 / 0.06), 0 1px 1px rgb(20 23 29 / 0.04);
  --shadow-md: 0 4px 16px -4px rgb(20 23 29 / 0.10), 0 2px 6px -2px rgb(20 23 29 / 0.06);
  --shadow-lg: 0 24px 48px -16px rgb(20 23 29 / 0.18), 0 8px 20px -8px rgb(20 23 29 / 0.10);

  --radius: 8px;
  --radius-sm: 5px;
  --radius-lg: 14px;

  --sans: "Public Sans", ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
  --display: "Archivo", var(--sans);
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --gutter: clamp(20px, 5vw, 56px);
  --measure: 66ch;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #0c0f14;
    --surface: #13171e;
    --surface-2: #1a1f28;
    --surface-3: #222833;
    --ink: #e9ecf1;
    --ink-soft: #c6ccd6;
    --muted: #98a1ae;
    --faint: #6f7987;
    --line: #232935;
    --line-strong: #333b48;

    --accent: #8a97ff;
    --accent-hover: #a3adff;
    --accent-ink: #0b0e18;
    --accent-soft: #1b2140;
    --accent-line: #313a66;

    --ok: #56cc92;
    --ok-soft: #102a1f;
    /* Their own values rather than the light ones reused: a fill that reads well on paper reads
       as a highlighter pen on near-black, and the lightness band a chart needs is different. */
    --ok-mark: #0eab7f;
    --warn-mark: #c4860f;
    --bad-mark: #e23c81;
    --muted-mark: #5f5f57;
    --ok-dot: #2fd39b;
    --warn: #e0ad51;
    --warn-soft: #2c2210;
    --bad: #f28b82;
    --bad-soft: #2e1616;
    --info: #78aeea;
    --info-soft: #14212f;
    --type-cname: #a996ff;
    --type-mx: #f0934f;
    --type-txt: #4cc4c9;

    --chart-1: #5b6be8;
    --chart-2: #d9645c;
    --chart-grid: #1f242e;

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
    --shadow-md: 0 4px 16px -4px rgb(0 0 0 / 0.5);
    --shadow-lg: 0 24px 48px -16px rgb(0 0 0 / 0.66);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --paper: #0c0f14;
  --surface: #13171e;
  --surface-2: #1a1f28;
  --surface-3: #222833;
  --ink: #e9ecf1;
  --ink-soft: #c6ccd6;
  --muted: #98a1ae;
  --faint: #6f7987;
  --line: #232935;
  --line-strong: #333b48;

  --accent: #8a97ff;
  --accent-hover: #a3adff;
  --accent-ink: #0b0e18;
  --accent-soft: #1b2140;
  --accent-line: #313a66;

  --ok: #56cc92;
  --ok-soft: #102a1f;
  --warn: #e0ad51;
  --warn-soft: #2c2210;
  --bad: #f28b82;
  --bad-soft: #2e1616;
  --info: #78aeea;
  --info-soft: #14212f;
  --type-cname: #a996ff;
  --type-mx: #f0934f;
  --type-txt: #4cc4c9;

  --chart-1: #5b6be8;
  --chart-2: #d9645c;
  --chart-grid: #1f242e;

  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.4);
  --shadow-md: 0 4px 16px -4px rgb(0 0 0 / 0.5);
  --shadow-lg: 0 24px 48px -16px rgb(0 0 0 / 0.66);
  color-scheme: dark;
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 650;
  line-height: 1.12;
  letter-spacing: -0.021em;
  text-wrap: balance;
  margin: 0;
}

p { margin: 0; }
img, svg, video { max-width: 100%; }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }
hr { border: 0; border-top: 1px solid var(--line); margin: 0; }

code, pre, .mono, kbd { font-family: var(--mono); font-feature-settings: "calt" 0; }

:where(button, a, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

.shell { width: min(100%, 1200px); margin-inline: auto; padding-inline: var(--gutter); }
.shell--narrow { width: min(100%, 780px); }
/* Grid items take their min-content width by default, so one long unbreakable string would
   widen the whole column. Every stack opts out of that. */
.stack { display: grid; gap: 16px; }
.stack > * { min-width: 0; }
.row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.row--between { justify-content: space-between; }
.push { margin-left: auto; }
.dim { color: var(--faint); }
.muted { color: var(--muted); }
.nowrap { white-space: nowrap; }
.tabular { font-variant-numeric: tabular-nums; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow--accent { color: var(--accent); }

/* ---------------------------------------------------------------- controls */
.btn {
  --btn-bg: var(--surface);
  --btn-fg: var(--ink);
  --btn-line: var(--line-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 16px;
  border: 1px solid var(--btn-line);
  border-radius: var(--radius-sm);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font: 500 0.9375rem/1.2 var(--sans);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 120ms ease, border-color 120ms ease, transform 80ms ease;
}
.btn:hover { --btn-line: var(--faint); color: var(--btn-fg); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: 0.5; pointer-events: none; }
/* Half-strength blue still reads as the button to press. A primary button that cannot be pressed
   yet goes grey instead, so "not yet" does not look like "go". */
.btn--primary[disabled] {
  opacity: 1;
  background: var(--surface-3);
  border-color: var(--line);
  color: var(--faint);
  box-shadow: none;
}

.btn--primary {
  --btn-bg: var(--accent);
  --btn-fg: var(--accent-ink);
  --btn-line: transparent;
  font-weight: 600;
}
.btn--primary:hover { --btn-bg: var(--accent-hover); --btn-fg: var(--accent-ink); }
.btn--ghost { --btn-bg: transparent; --btn-line: transparent; color: var(--muted); }
.btn--ghost:hover { --btn-bg: var(--surface-2); color: var(--ink); }
.btn--danger { color: var(--bad); }
.btn--danger:hover { --btn-bg: var(--bad-soft); --btn-line: var(--bad); }
.btn--lg { padding: 13px 24px; font-size: 1rem; }
.btn--sm { padding: 5px 10px; font-size: 0.8125rem; }
.btn--block { width: 100%; }

.field { display: grid; gap: 6px; }
.field > label { font-size: 0.8125rem; font-weight: 600; color: var(--ink-soft); }
.field .hint { font-size: 0.8125rem; color: var(--muted); }

input[type="text"], input[type="email"], input[type="url"], input[type="number"],
input[type="search"], select, textarea {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: 400 0.9375rem/1.45 var(--sans);
}
input::placeholder, textarea::placeholder { color: var(--faint); }
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline-offset: 1px; }
textarea { resize: vertical; min-height: 84px; }
select {
  appearance: none;
  padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 16px center, right 11px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.check { display: flex; gap: 10px; align-items: flex-start; font-size: 0.9375rem; }
.check input { margin-top: 3px; accent-color: var(--accent); width: 16px; height: 16px; }

/* ---------------------------------------------------------------- badges, pills, code */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font: 500 0.75rem/1.5 var(--mono);
  letter-spacing: 0.01em;
  white-space: nowrap;
  border: 1px solid transparent;
}
.badge::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.badge--ok { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 26%, transparent); }
.badge--bad { background: var(--bad-soft); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 26%, transparent); }
.badge--warn { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 26%, transparent); }
.badge--info { background: var(--info-soft); color: var(--info); border-color: color-mix(in srgb, var(--info) 26%, transparent); }
.badge--neutral { background: var(--surface-2); color: var(--muted); border-color: var(--line); }

.chip {
  display: inline-block;
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface-2);
  font: 400 0.75rem/1.6 var(--mono);
  color: var(--muted);
}

code:not(pre code) {
  padding: 0.12em 0.36em;
  border-radius: 4px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-size: 0.86em;
  color: var(--ink-soft);
}

pre {
  margin: 0;
  padding: 16px 18px;
  overflow-x: auto;
  font-size: 0.8125rem;
  line-height: 1.65;
  tab-size: 2;
}
pre code { background: none; border: 0; padding: 0; font-size: inherit; color: inherit; }

/* One consistent syntax palette, used by the tiny highlighter in app.js. */
.tok-str { color: var(--ok); }
.tok-num { color: var(--info); }
.tok-key { color: var(--accent); }
.tok-punc { color: var(--faint); }
.tok-com { color: var(--faint); font-style: italic; }
.tok-cmd { color: var(--ink); font-weight: 600; }
.tok-flag { color: var(--muted); }
.tok-bool { color: var(--warn); }

/* ---------------------------------------------------------------- code panel */
.panel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.panel__bar {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  min-height: 40px;
}
.panel__title {
  font: 500 0.75rem/1 var(--mono);
  color: var(--muted);
  padding: 0 6px;
  letter-spacing: 0.02em;
}
.panel__body { background: var(--surface); }

.tab {
  appearance: none;
  border: 0;
  background: none;
  padding: 9px 11px;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font: 500 0.8125rem/1 var(--sans);
  cursor: pointer;
}
.tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
.tab:hover { color: var(--ink); }

.copy {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--muted);
  border-radius: 4px;
  padding: 3px 9px;
  font: 500 0.75rem/1.5 var(--sans);
  cursor: pointer;
}
.copy:hover { color: var(--ink); border-color: var(--faint); }
.copy[data-copied="true"] { color: var(--ok); border-color: var(--ok); }

/* ---------------------------------------------------------------- site chrome */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--line);
}
.site-header__inner { display: flex; align-items: center; gap: 24px; min-height: 62px; }
.site-header__actions { flex-wrap: nowrap; }
.site-nav { display: flex; align-items: center; gap: 22px; }
.site-nav a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9375rem;
  font-weight: 500;
}
.site-nav a:hover, .site-nav a[aria-current="page"] { color: var(--ink); }

.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}
.brand__mark {
  width: 24px; height: 24px;
  border-radius: 6px;
  background: var(--accent);
  color: var(--accent-ink);
  display: grid;
  place-items: center;
  flex: none;
}
.brand__mark svg { width: 14px; height: 14px; display: block; }

.site-footer {
  border-top: 1px solid var(--line);
  margin-top: 96px;
  padding-block: 48px 64px;
  color: var(--muted);
  font-size: 0.875rem;
}
.site-footer__grid {
  display: grid;
  grid-template-columns: 1.4fr repeat(3, minmax(0, 1fr));
  gap: 32px;
}
.site-footer h4 {
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 12px;
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.site-footer a { color: var(--muted); text-decoration: none; }
.site-footer a:hover { color: var(--ink); }

/* ---------------------------------------------------------------- landing */
.hero {
  position: relative;
  padding-block: clamp(56px, 9vw, 104px) clamp(48px, 7vw, 80px);
  overflow: hidden;
}
/* A faint routing grid behind the hero: the paths a message takes, not decoration for its own sake. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--line) 70%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--line) 70%, transparent) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 78% 62% at 50% 0%, #000 20%, transparent 78%);
  pointer-events: none;
}
.hero__inner {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 64px);
  align-items: center;
}
.hero__copy { display: grid; gap: 22px; justify-items: start; }
.hero h1 {
  font-size: clamp(2.5rem, 5.4vw, 4rem);
  font-weight: 700;
  letter-spacing: -0.033em;
  max-width: 14ch;
}
.hero__lede { font-size: clamp(1.0625rem, 1.5vw, 1.1875rem); color: var(--muted); max-width: 46ch; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 12px; }
.hero__note { font-size: 0.8125rem; color: var(--faint); font-family: var(--mono); }

.tagline {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 5px 12px 5px 7px;
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font: 500 0.8125rem/1.4 var(--sans);
  text-decoration: none;
}
.tagline .chip {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: transparent;
  font-size: 0.6875rem;
  font-weight: 600;
}

/* The send/receive pair in the hero: request above, what came back below. */
.hero__demo { display: grid; gap: 14px; min-width: 0; }
.wire {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: center;
  padding-left: 4px;
  font: 500 0.75rem/1 var(--mono);
  color: var(--faint);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.wire::after { content: ""; height: 1px; background: var(--line); }

.result {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.result__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  font-size: 0.875rem;
}
.result__head strong { font-weight: 600; }

.track { list-style: none; margin: 0; padding: 10px 14px 14px; display: grid; gap: 0; }
.track li {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  gap: 12px;
  align-items: baseline;
  padding: 7px 0;
  font-size: 0.875rem;
}
.track li + li { border-top: 1px dashed var(--line); }
.track__dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--line-strong);
  justify-self: center;
  align-self: center;
  position: relative;
}
.track li[data-tone="ok"] .track__dot { background: var(--ok); }
.track li[data-tone="info"] .track__dot { background: var(--info); }
.track li[data-tone="bad"] .track__dot { background: var(--bad); }
.track li[data-live="true"] .track__dot::after {
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 50%;
  border: 1px solid currentColor;
  color: var(--ok);
  opacity: 0;
  animation: ping 2.4s ease-out infinite;
}
@keyframes ping {
  0% { transform: scale(0.6); opacity: 0.8; }
  70%, 100% { transform: scale(1.5); opacity: 0; }
}
.track__when { font: 400 0.75rem/1.6 var(--mono); color: var(--faint); }
.track__what { font-family: var(--mono); font-size: 0.8125rem; }

section.band { padding-block: clamp(56px, 8vw, 96px); }
section.band--tint { background: var(--surface-2); border-block: 1px solid var(--line); }
.band__head { display: grid; gap: 14px; margin-bottom: 40px; max-width: 62ch; }
.band__head h2 { font-size: clamp(1.75rem, 3vw, 2.375rem); }
.band__head p { color: var(--muted); font-size: 1.0625rem; }

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.facts > div { padding: 22px 24px; border-right: 1px solid var(--line); display: grid; gap: 4px; }
.facts > div:last-child { border-right: 0; }
.facts dt { font-size: 0.8125rem; color: var(--muted); order: 2; }
.facts dd {
  margin: 0;
  order: 1;
  font-family: var(--display);
  font-size: 1.75rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

.steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; counter-reset: step; }
.step { display: grid; gap: 10px; align-content: start; }
.step__n {
  counter-increment: step;
  font: 500 0.75rem/1 var(--mono);
  color: var(--accent);
  letter-spacing: 0.1em;
}
.step__n::before { content: "0" counter(step); }
.step h3 { font-size: 1.0625rem; }
.step p { color: var(--muted); font-size: 0.9375rem; }

.features { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.feature { background: var(--surface); padding: 26px; display: grid; gap: 9px; align-content: start; }
.feature__icon { color: var(--accent); width: 20px; height: 20px; }
.feature h3 { font-size: 1rem; font-weight: 650; }
.feature p { color: var(--muted); font-size: 0.9375rem; }
.feature code { font-size: 0.8em; }

.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: clamp(32px, 5vw, 64px); align-items: center; }
.split__copy { display: grid; gap: 18px; align-content: start; }
.split__copy h2 { font-size: clamp(1.625rem, 2.6vw, 2.125rem); }
.split__copy p { color: var(--muted); }
.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.checklist li { display: grid; grid-template-columns: 18px 1fr; gap: 11px; align-items: start; font-size: 0.9375rem; }
.checklist svg { width: 16px; height: 16px; color: var(--ok); margin-top: 4px; }

.dns {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: 0.75rem;
}
.dns th {
  text-align: left;
  font-family: var(--sans);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 600;
  padding: 0 12px 8px;
}
.dns td { padding: 7px 12px; border-top: 1px solid var(--line); white-space: nowrap; }
.dns td:last-child { color: var(--muted); }

.cta {
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(120% 140% at 8% 0%, var(--accent-soft) 0%, transparent 60%),
    var(--surface);
  padding: clamp(32px, 5vw, 56px);
  display: grid;
  gap: 20px;
  justify-items: center;
  text-align: center;
}
.cta h2 { font-size: clamp(1.75rem, 3vw, 2.375rem); }
.cta p { color: var(--muted); max-width: 52ch; }

/* ---------------------------------------------------------------- docs */
.docs { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 48px; align-items: start; padding-block: 48px 96px; }
.docs__nav { position: sticky; top: 86px; display: grid; gap: 4px; font-size: 0.875rem; max-height: calc(100vh - 110px); overflow-y: auto; }
.docs__nav a { color: var(--muted); text-decoration: none; padding: 4px 10px; border-radius: 5px; border-left: 2px solid transparent; }
.docs__nav a:hover { background: var(--surface-2); color: var(--ink); }
.docs__nav .group { margin-top: 14px; }
.docs__body { display: grid; gap: 40px; min-width: 0; }
.docs__body h2 { font-size: 1.5rem; scroll-margin-top: 86px; }
.docs__body h3 { font-size: 1.0625rem; scroll-margin-top: 86px; }
.docs__body p, .docs__body li { color: var(--muted); max-width: var(--measure); }
.docs__body ul { padding-left: 20px; display: grid; gap: 6px; margin: 0; }

.endpoint { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface); }
.endpoint__head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; background: var(--surface-2); border-bottom: 1px solid var(--line);
}
.endpoint__path { font: 500 0.875rem/1.4 var(--mono); color: var(--ink); }
.endpoint__body { padding: 16px; display: grid; gap: 14px; }
.method {
  font: 600 0.6875rem/1.6 var(--mono);
  letter-spacing: 0.08em;
  padding: 1px 7px;
  border-radius: 4px;
  background: var(--accent-soft);
  color: var(--accent);
  border: 1px solid var(--accent-line);
}
.method--post { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.method--delete { background: var(--bad-soft); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 30%, transparent); }
.method--patch { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }

.params { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.params th { text-align: left; font-size: 0.6875rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint); padding-bottom: 6px; font-weight: 600; }
.params td { padding: 8px 12px 8px 0; border-top: 1px solid var(--line); vertical-align: top; color: var(--muted); }
.params td:first-child { font-family: var(--mono); font-size: 0.8125rem; color: var(--ink); white-space: nowrap; }
.params td:nth-child(2) { font-family: var(--mono); font-size: 0.75rem; color: var(--faint); white-space: nowrap; }

/* ---------------------------------------------------------------- auth pages */
.auth {
  position: relative;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 40px var(--gutter);
  overflow: hidden;
}
/* The same routing grid as the hero, so signing in belongs to the same place as the site. */
.auth::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--line) 70%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--line) 70%, transparent) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, #000 10%, transparent 72%);
  pointer-events: none;
}
.auth__card {
  position: relative;
  width: min(100%, 428px);
  display: grid;
  gap: 24px;
  padding: 36px 34px 28px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
/* Without this a single unbreakable string, such as a sign-in link, sets the column width and
   pushes everything else out past the card's edge. */
.auth__card > * { min-width: 0; }
.auth__card h1 { font-size: 1.5rem; }
.auth__card p { color: var(--muted); font-size: 0.9375rem; }

.auth__icon {
  width: 42px;
  height: 42px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent);
  display: grid;
  place-items: center;
  border: 1px solid var(--accent-line);
}
.auth__icon svg { width: 20px; height: 20px; }

/* The card reads as three blocks: who this is, what to do, and the small print. The gaps inside
   each block are smaller than the gaps between them, which is the whole of the structure. */
.auth__intro { display: grid; gap: 9px; margin-top: -4px; }
.auth__intro h1 {
  font-size: 1.625rem;
  line-height: 1.2;
  letter-spacing: -0.026em;
  font-weight: 640;
}
.auth__intro p {
  max-width: 36ch;
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--muted);
}

.auth__form { display: grid; gap: 18px; }

/* The label is set as an eyebrow rather than a sentence. There is one field on the page, so it
   does not need to compete with the heading; it needs to say which box this is. */
.auth__form .field { gap: 8px; }
.auth__form .field > label {
  font-size: 0.6875rem;
  font-weight: 650;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
}

/* Bigger than a field in a settings form, deliberately. Typing an address is the entire task on
   this page, and a 15px box in the middle of a card looks like an afterthought. The recessed
   fill lifts to the card's own surface on focus, so the box you are typing in is the lit one. */
.auth__form input[type="email"] {
  padding: 13px 14px;
  font-size: 1rem;
  letter-spacing: -0.006em;
  background: var(--surface-2);
  transition: border-color 120ms ease, background-color 120ms ease, box-shadow 120ms ease;
}
.auth__form input[type="email"]:hover { border-color: var(--faint); }
.auth__form input[type="email"]:focus {
  outline: none;
  background: var(--surface);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* A box-shadow is not painted in Windows high-contrast mode, so the ring above would leave a
   keyboard user with no focus indicator at all. Hand the outline back. */
@media (forced-colors: active) {
  .auth__form input[type="email"]:focus { outline: 2px solid Highlight; outline-offset: 1px; }
}

.auth__foot {
  margin-top: -2px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: 0.8125rem;
  line-height: 1.75;
  color: var(--faint);
  text-align: center;
}
.auth__foot a { color: var(--ink-soft); font-weight: 500; }

/* A link the developer is meant to act on, not just read. */
.linkbox {
  display: grid;
  gap: 12px;
  padding: 14px 16px;
  border: 1px solid var(--warn-soft);
  border-left: 3px solid var(--warn);
  border-radius: var(--radius-sm);
  background: var(--warn-soft);
  min-width: 0;
}
.linkbox__head { font-size: 0.875rem; font-weight: 600; color: var(--warn); }
.linkbox__note { font-size: 0.8125rem; color: var(--muted); }
.linkbox__url {
  font: 400 0.75rem/1.6 var(--mono);
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 9px 11px;
  overflow-wrap: anywhere;
  /* Tall enough that an ordinary sign-in link never scrolls, capped so a pathological one
     cannot push the buttons off the card. */
  max-height: 9.6em;
  overflow-y: auto;
}
.linkbox__actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------------------------------------------------------------- dashboard */
.app { display: grid; grid-template-columns: 236px minmax(0, 1fr); min-height: 100dvh; }

/* The rail.
 *
 * A column, not a grid with align-content:start. As a grid everything piled at the top and the
 * account block floated in the middle of the sidebar with empty space under it; as a column the
 * footer can be pushed to the bottom where it belongs.
 *
 * A gradient rather than a flat panel. A single fill beside a page of the same family of colours
 * reads as one undifferentiated surface with a line drawn down it; a few percent of vertical
 * shift is enough to say this is a different plane without anybody noticing why.
 */
.sidebar {
  border-right: 1px solid var(--line);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  padding: 18px 12px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  position: sticky;
  top: 0;
  height: 100dvh;
  overflow-y: auto;
  /* A hairline. A full-width scrollbar down a 236px rail is furniture, and the rail rarely
     scrolls at all. */
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
.sidebar::-webkit-scrollbar { width: 3px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }
.sidebar::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }

.sidebar__nav { display: grid; gap: 1px; }
.sidebar__nav a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  min-height: 36px;
  /* Reserved, so the active row's border never nudges the label sideways by a pixel. */
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 500;
  transition: background-color 120ms ease, color 120ms ease;
}
.sidebar__nav a > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar__nav a:hover { background: var(--surface-3); color: var(--ink); }

/* The page you are on: a wash, a hairline, and a bar down the inside edge.
 *
 * The bar is an inset box-shadow rather than a pseudo-element or a left border, so it costs no
 * extra node and takes no space — the row does not move when it becomes the active one. The wash
 * is angled so the row has a direction rather than reading as a flat block of colour. */
.sidebar__nav a[aria-current="page"] {
  background: linear-gradient(
    100deg,
    color-mix(in srgb, var(--accent) 14%, transparent),
    color-mix(in srgb, var(--accent) 5%, transparent)
  );
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
  box-shadow: inset 3px 0 var(--accent);
  color: var(--accent);
  font-weight: 600;
}
.sidebar__nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sidebar__nav a > svg { width: 16px; height: 16px; flex: none; opacity: 0.85; }
.sidebar__nav a[aria-current="page"] svg { opacity: 1; }

/* The group heading. Much smaller than the rows under it, which is the whole reason the groups
   read as labels and not as more links. */
/* A group, drawn as a row rather than as a label.
   The heading now behaves like a nav item that happens to open something, which is what it is. */
.sidebar__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  min-height: 36px;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--muted);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background-color 120ms ease, color 120ms ease;
}
/* Safari and older Chrome draw their own triangle unless both of these are said. */
.sidebar__head::-webkit-details-marker { display: none; }
.sidebar__head::marker { content: ''; }
.sidebar__head > svg:first-child { width: 16px; height: 16px; flex: none; opacity: 0.85; }
.sidebar__head > span { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar__head:hover { background: var(--surface-3); color: var(--ink); }
.sidebar__head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Open, in the brand's accent: the same wash, hairline and inset bar the current page gets.
   
   Deliberately the same treatment rather than a second invented one. There are only two things a
   rail ever needs to say — this is where you are, and this is what you have opened — and giving
   them one visual language means neither has to be learned. The bar is an inset box-shadow, so it
   costs no space and the row does not move when it opens. */
.sidebar__group[open] > .sidebar__head {
  background: linear-gradient(
    100deg,
    color-mix(in srgb, var(--accent) 12%, transparent),
    color-mix(in srgb, var(--accent) 4%, transparent)
  );
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
  box-shadow: inset 3px 0 var(--accent);
  color: var(--accent);
}
.sidebar__group[open] > .sidebar__head > svg:first-child { opacity: 1; }

.sidebar__chev {
  width: 11px;
  height: 11px;
  flex: none;
  opacity: 0.55;
  transition: transform 140ms ease;
}
.sidebar__group[open] > .sidebar__head .sidebar__chev { transform: rotate(90deg); opacity: 0.8; }

.sidebar__group { display: grid; gap: 1px; margin-bottom: 3px; }

/* The children, on a rail. The indent is what says "inside"; an icon on every one of these would
   be fourteen small pictures nobody reads. */
.sidebar__kids {
  display: grid;
  gap: 1px;
  margin: 3px 0 5px 20px;
  padding-left: 9px;
  border-left: 1px solid var(--line);
}
/* Open, the rail takes the heading's colour, so the heading and what it opened read as one piece
   rather than a highlighted row above a grey line. Softened, not the full accent: at full strength
   a line this long outshouts the heading it belongs to. Two pixels, with a pixel of padding given
   back, so the links do not shift sideways when a group opens. */
.sidebar__group[open] > .sidebar__kids {
  padding-left: 8px;
  border-left: 2px solid color-mix(in srgb, var(--accent) 50%, transparent);
}
.sidebar__kids a { min-height: 32px; padding: 6px 10px; font-size: 0.875rem; }
.sidebar__kids a > svg { display: none; }
/* A child is the page you are on, not a section: no bar down the edge, since the rail is already
   drawing one two pixels to its left. */
.sidebar__kids a[aria-current="page"] { box-shadow: none; }

/* Folded, a group still has to say the page you are on is inside it — or folding one hides where
   you are. */
.sidebar__group:not([open]):has(a[aria-current="page"]) > .sidebar__head {
  color: var(--accent);
}
.sidebar__group:not([open]):has(a[aria-current="page"]) > .sidebar__head > svg:first-child { opacity: 1; }

/* The foot of the sidebar is one identity block, not three stray links. An avatar anchors it,
   the two lines of identity truncate rather than wrap, and the actions sit on their own row. */
/* margin-top:auto is the whole fix for the gap: in a column it pushes this to the bottom and
   lets the navigation keep the slack, rather than leaving the account block stranded halfway
   down with white space beneath it. */
.sidebar__foot {
  margin-top: auto;
  border-top: 1px solid var(--line);
  padding: 12px 6px 2px;
  display: grid;
  gap: 8px;
  font-size: 0.8125rem;
}
/* The admin console is not one of the account's pages, so it is separated from them rather than
   added to the end of the list where it would read as another page of this account. */
.sidebar__nav--admin {
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.userbox { display: flex; align-items: center; gap: 10px; min-width: 0; padding: 0 4px; }
.userbox__avatar {
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background: var(--surface-3);
  color: var(--ink-soft);
  font: 600 0.8125rem/1 var(--sans);
  text-transform: uppercase;
}
.app--admin .userbox__avatar { background: var(--ink); color: var(--paper); }
.userbox__text { display: grid; gap: 1px; min-width: 0; }
.userbox__name {
  font-weight: 500;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.userbox__sub {
  font-size: 0.75rem;
  color: var(--faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Theme toggle, docs, sign out. They sit on one line under the account rather than wrapping into
   a ragged block, and they are quiet: none of the three is a thing anybody came here to do. */
.sidebar__actions {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 2px;
}
/* These were made transparent to keep them quiet and ended up looking like plain text, which is
   the opposite of useful for the only way out of the admin console. Quiet is a filled chip on a
   tinted background — still secondary to everything above it, still obviously a thing you press. */
.sidebar__actions .btn {
  padding: 5px 10px;
  font-size: 0.75rem;
  color: var(--ink-soft);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.sidebar__actions .btn:hover {
  background: var(--surface-3);
  border-color: var(--line-strong);
  color: var(--ink);
}
.sidebar__actions .btn:active { transform: translateY(0.5px); }
/* The toggle is an icon; everything after it is a word, so the words go to the right together. */
.sidebar__actions > :first-child { margin-right: auto; }
.sidebar__foot select { font-size: 0.8125rem; padding: 6px 10px; }

/* The button that opens the rail on a phone, and the sheet it dims. Both do nothing at all until
   the narrow-screen rules below turn them on. */
.navbtn {
  display: none;
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface-2);
  color: var(--ink-soft);
  cursor: pointer;
}
.navbtn svg { width: 18px; height: 18px; }
.navbtn:hover { border-color: var(--line-strong); color: var(--ink); }
.navbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.scrim { display: none; }

/*
  The column is declared, not left implicit.

  min-width: 0 lets .main shrink inside .app — but .main is itself a grid, and a grid with no
  grid-template-columns places its children in an implicit `auto` column, which means max-content.
  So the topbar and the content kept the width of the widest thing inside them (the seven-tab
  settings strip, 501px) and pushed the whole dashboard off a phone screen: every page could be
  dragged sideways. minmax(0, 1fr) is the permission to be narrower than the contents, and it has
  to be given at every grid on the way down, not only at the top.
*/
.main { min-width: 0; display: grid; grid-template-rows: auto 1fr; grid-template-columns: minmax(0, 1fr); }
.content { min-width: 0; }
.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px var(--gutter);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 20;
}
.topbar h1 { font-size: 1.125rem; font-weight: 650; }
.content { padding: 26px var(--gutter) 72px; display: grid; gap: 24px; align-content: start; }

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; }
.tile {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 16px 18px;
  display: grid;
  gap: 3px;
}
.tile__label { font-size: 0.8125rem; color: var(--muted); }
.tile__value {
  font-family: var(--display);
  font-size: 1.875rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.tile__foot { font-size: 0.8125rem; color: var(--faint); }
.tile--alert { border-color: color-mix(in srgb, var(--bad) 40%, var(--line)); background: var(--bad-soft); }
.tile--alert .tile__value, .tile--alert .tile__label { color: var(--bad); }

.card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}
.card__head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line);
}
.card__head h2, .card__head h3 { font-size: 0.9375rem; font-weight: 650; }
.card__body { padding: 18px; display: grid; gap: 16px; }
.card__foot { padding: 12px 18px; border-top: 1px solid var(--line); background: var(--surface-2); font-size: 0.875rem; }

.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
table.data th {
  text-align: left;
  padding: 9px 18px;
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  font-weight: 600;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.data td { padding: 11px 18px; border-bottom: 1px solid var(--line); vertical-align: middle; }
table.data tr:last-child td { border-bottom: 0; }
table.data tbody tr:hover { background: var(--surface-2); }
table.data a { color: inherit; text-decoration: none; }
table.data a:hover { color: var(--accent); }
.cell-main { font-weight: 500; }
.cell-sub { color: var(--faint); font-size: 0.8125rem; }

.empty { padding: 48px 24px; text-align: center; display: grid; gap: 10px; justify-items: center; }
.empty h3 { font-size: 1rem; }
.empty p { color: var(--muted); font-size: 0.9375rem; max-width: 44ch; }

.flash {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid;
  font-size: 0.9375rem;
  min-width: 0;
  overflow-wrap: anywhere;
}
.flash > * { min-width: 0; }
.flash--ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 34%, transparent); color: var(--ok); }
.flash--bad { background: var(--bad-soft); border-color: color-mix(in srgb, var(--bad) 34%, transparent); color: var(--bad); }
.flash--warn { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 34%, transparent); color: var(--warn); }
.flash--info { background: var(--info-soft); border-color: color-mix(in srgb, var(--info) 30%, transparent); color: var(--info); }
.flash strong { font-weight: 650; }

.secret {
  display: grid;
  gap: 8px;
  padding: 14px 16px;
  border: 1px dashed var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
}
.secret__value {
  font: 500 0.875rem/1.5 var(--mono);
  word-break: break-all;
  color: var(--ink);
}

.timeline { list-style: none; margin: 0; padding: 0; display: grid; }
.timeline li {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  gap: 14px;
  padding: 0 0 18px;
  position: relative;
}
.timeline li::before {
  content: "";
  position: absolute;
  left: 6px;
  top: 14px;
  bottom: -4px;
  width: 1px;
  background: var(--line);
}
.timeline li:last-child { padding-bottom: 0; }
.timeline li:last-child::before { display: none; }
.timeline__dot {
  width: 13px; height: 13px;
  border-radius: 50%;
  border: 2px solid var(--surface);
  background: var(--line-strong);
  margin-top: 4px;
  box-shadow: 0 0 0 1px var(--line-strong);
  z-index: 1;
}
.timeline li[data-tone="ok"] .timeline__dot { background: var(--ok-dot); box-shadow: 0 0 0 1px var(--ok-dot); }
.timeline li[data-tone="bad"] .timeline__dot { background: var(--bad); box-shadow: 0 0 0 1px var(--bad); }
.timeline li[data-tone="warn"] .timeline__dot { background: var(--warn); box-shadow: 0 0 0 1px var(--warn); }
.timeline li[data-tone="info"] .timeline__dot { background: var(--info); box-shadow: 0 0 0 1px var(--info); }
.timeline__body { display: grid; gap: 3px; min-width: 0; }
.timeline__title { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; font-size: 0.9375rem; }
.timeline__meta { font-size: 0.8125rem; color: var(--muted); }
.timeline__payload {
  margin-top: 4px;
  font: 400 0.75rem/1.6 var(--mono);
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 5px;
  padding: 8px 10px;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

.kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 8px 20px; font-size: 0.875rem; align-items: baseline; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.preview-frame {
  width: 100%;
  min-height: 420px;
  border: 0;
  background: #fff;
  display: block;
  color-scheme: light;
}

.filters { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.filters input[type="search"] { max-width: 280px; }
.filters select { width: auto; min-width: 140px; }

.pager { display: flex; gap: 10px; align-items: center; justify-content: space-between; }

.records { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.records th {
  text-align: left; padding: 0 12px 7px 0;
  font-family: var(--sans); font-size: 0.6875rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--faint); font-weight: 600;
}
.records td { padding: 9px 12px 9px 0; border-top: 1px solid var(--line); vertical-align: top; font-family: var(--mono); }
.records td:last-child { padding-right: 0; }
.records .value { color: var(--muted); }
/* The copy button sits beside the value rather than inside the text flow, so a long record
   wraps on its own and the button stays put. */
.records .cell { display: flex; align-items: flex-start; gap: 8px; }
/* Wraps at the <wbr> after each dot first, and inside a label only when one is too long for the
   column on its own. break-all wrapped anywhere, which split "_domainkey" into two lines that
   read as two values. */
.records .cell > span { min-width: 0; overflow-wrap: anywhere; }
.records .cell .copy { flex: none; margin-top: 1px; }

details.raw { border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2); }
details.raw summary { cursor: pointer; padding: 9px 14px; font-size: 0.875rem; color: var(--muted); }
details.raw summary:hover { color: var(--ink); }
details.raw pre { border-top: 1px solid var(--line); background: var(--surface); }

.theme-toggle {
  appearance: none;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--muted);
  border-radius: var(--radius-sm);
  width: 32px; height: 32px;
  display: grid; place-items: center;
  cursor: pointer;
  flex: none;
}
.theme-toggle:hover { color: var(--ink); }
.theme-toggle svg { width: 15px; height: 15px; }
.theme-toggle .moon { display: none; }
:root[data-theme="dark"] .theme-toggle .moon { display: block; }
:root[data-theme="dark"] .theme-toggle .sun { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .moon { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .sun { display: none; }
}

/* ---------------------------------------------------------------- responsive */
@media (max-width: 1000px) {
  .hero__inner, .split { grid-template-columns: minmax(0, 1fr); }
  .steps, .features { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .docs { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .docs__nav { position: static; max-height: none; display: flex; flex-wrap: wrap; gap: 8px; }
  .docs__nav .group { display: none; }
}

/*
  The rail becomes a drawer.

  It used to become a horizontal strip of twelve links across the top, which scrolled sideways and
  hid the account block entirely — so on a phone there was no way to switch account, no theme
  toggle, and, worse, no way to sign out at all. A drawer keeps the whole rail, in the shape people
  already know from every application they use on a phone.

  Off-canvas by transform rather than by display, so it slides rather than appearing, and so the
  links inside it keep their tab order and their focus behaviour. inert would be tidier for the
  closed state but is not safe to rely on yet; the transform plus visibility keeps it out of the
  way of a screen reader and out of the tab order between screens.
*/
@media (max-width: 860px) {
  .app { grid-template-columns: minmax(0, 1fr); }

  .sidebar {
    position: fixed;
    z-index: 60;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(84vw, 300px);
    height: 100dvh;
    border-right: 1px solid var(--line-strong);
    box-shadow: 18px 0 60px rgb(0 0 0 / 0.28);
    transform: translateX(-102%);
    visibility: hidden;
    /* visibility is switched at the end of the close and at the start of the open, never eased.
       Eased, it stays hidden for the whole opening slide — and a hidden element cannot take
       focus, so the first link could not be focused for the first two hundred milliseconds it was
       on screen. Delayed only on the way out, it keeps the drawer out of the tab order while
       closed without ever being in the way while it opens. */
    transition: transform 200ms cubic-bezier(0.32, 0.72, 0.3, 1), visibility 0s linear 200ms;
    /* The notch, and the home indicator at the bottom of a modern phone. */
    padding-top: calc(18px + env(safe-area-inset-top));
    padding-bottom: calc(18px + env(safe-area-inset-bottom));
  }

  .scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 55;
    background: rgb(8 10 14 / 0.5);
    backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 200ms ease;
  }

  .navbtn { display: grid; }
  /* The rail is fixed and off-canvas here, so it no longer holds its own column open. Without
     this the topbar row would start behind where the rail used to be. */
  .app--admin .sidebar { background: linear-gradient(180deg, var(--surface-2), var(--surface)); }

  /* Open. The attribute is on the root element so one toggle moves the drawer, the scrim, the
     button's own state and the page's scroll lock together. */
  :root[data-nav="open"] .sidebar {
    transform: translateX(0);
    visibility: visible;
    transition: transform 200ms cubic-bezier(0.32, 0.72, 0.3, 1), visibility 0s;
  }
  :root[data-nav="open"] .scrim { opacity: 1; }
  /* The page behind must not scroll while the drawer is over it — scrolling the thing you cannot
     see is the single most disorienting thing a drawer can do. */
  :root[data-nav="open"] body { overflow: hidden; }

  /* The rail's own scrollbar is never wanted here; the drawer scrolls as one piece. */
  .sidebar { scrollbar-width: none; }
  .sidebar::-webkit-scrollbar { width: 0; }

  /* Bigger targets. A 36px row is comfortable with a mouse and mean with a thumb. */
  .sidebar__nav { gap: 2px; }
  .sidebar__nav a { min-height: 44px; padding: 10px 12px; font-size: 0.9375rem; }
  .sidebar__nav a > svg { width: 18px; height: 18px; }
  .sidebar__head { min-height: 44px; padding: 10px 12px; font-size: 0.9375rem; }
  .sidebar__head > svg:first-child { width: 18px; height: 18px; }
  .sidebar__kids a { min-height: 40px; font-size: 0.9375rem; }
  .sidebar__label { padding: 18px 12px 6px; font-size: 0.6875rem; }
  .sidebar__foot { display: grid; }
  .sidebar__actions .btn { padding: 7px 12px; font-size: 0.8125rem; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar, .scrim { transition: none; }
}


@media (max-width: 640px) {
  .steps, .features { grid-template-columns: minmax(0, 1fr); }
  .site-header__inner { gap: 12px; }
  .site-nav { gap: 14px; font-size: 0.875rem; }
  .hide-sm { display: none; }
  .hero h1 { font-size: clamp(2.125rem, 9vw, 2.75rem); }
  .facts > div { border-right: 0; border-bottom: 1px solid var(--line); }
  .facts > div:last-child { border-bottom: 0; }
  .content { padding-inline: 20px; }
  .topbar { padding-inline: 20px; }
}

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

@media print {
  .sidebar, .topbar, .site-header, .site-footer { display: none; }
}

/* ---------------------------------------------------------------- chart */
.chart { display: grid; gap: 12px; }
.chart__legend { display: flex; gap: 16px; flex-wrap: wrap; font-size: 0.8125rem; color: var(--muted); }
.chart__key { display: inline-flex; align-items: center; gap: 7px; }
.chart__swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.chart__swatch--1 { background: var(--chart-1); }
.chart__swatch--2 { background: var(--chart-2); }
.chart__plot { width: 100%; height: auto; display: block; overflow: visible; }
.chart__plot .grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart__plot .axis { fill: var(--faint); font: 400 10px var(--mono); }
.chart__plot .bar-1 { fill: var(--chart-1); }
.chart__plot .bar-2 { fill: var(--chart-2); }
.chart__plot .hit { fill: transparent; }
.chart__plot .hit:hover + .bars rect, .chart__plot g:hover > .hit + .bars rect { opacity: 0.78; }
.chart__empty { color: var(--faint); font-size: 0.875rem; padding: 24px 0; text-align: center; }

/* ================================================================ landing, refined */

/* Display type is set tighter and heavier than the UI, and only here. */
.hero h1 {
  font-size: clamp(2.625rem, 5.8vw, 4.25rem);
  font-weight: 700;
  letter-spacing: -0.038em;
  line-height: 1.02;
  max-width: 13ch;
}
.hero__lede {
  font-size: clamp(1.0625rem, 1.35vw, 1.1875rem);
  line-height: 1.55;
  color: var(--muted);
  max-width: 44ch;
}
.hero__copy { gap: 24px; }
.band__head h2 { letter-spacing: -0.028em; }

/* The timeline fills in once on load. It starts dimmed but fully legible, so a screenshot or a
   reader who arrives late sees the finished state rather than an empty box. */
.track li { opacity: 0.5; }
@media (prefers-reduced-motion: no-preference) {
  .track li { animation: settle 520ms cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
  .track li:nth-child(1) { animation-delay: 120ms; }
  .track li:nth-child(2) { animation-delay: 420ms; }
  .track li:nth-child(3) { animation-delay: 720ms; }
  .track li:nth-child(4) { animation-delay: 1020ms; }
}
@media (prefers-reduced-motion: reduce) {
  .track li { opacity: 1; }
}
@keyframes settle {
  from { opacity: 0.5; transform: translateY(3px); }
  to { opacity: 1; transform: none; }
}
.track li:last-child { padding-bottom: 2px; }

/* ---------------------------------------------------------------- the wire */
/* A real SMTP conversation, with the event each line produces marked against it. */
.wires {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}
.transcript { display: grid; gap: 0; }
.transcript__row {
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: baseline;
  padding: 3px 14px;
  font: 400 0.78rem/1.75 var(--mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.transcript__row:first-child { padding-top: 12px; }
.transcript__row:last-child { padding-bottom: 12px; }
.transcript__dir { color: var(--faint); user-select: none; }
.transcript__row--out .transcript__dir { color: var(--accent); }
.transcript__row--out .transcript__text { color: var(--ink); font-weight: 500; }
.transcript__text { color: var(--muted); min-width: 0; }
.transcript__row--ok .transcript__text { color: var(--ok); }
.transcript__row--bad .transcript__text { color: var(--bad); }
.transcript__event {
  justify-self: end;
  align-self: center;
  font: 500 0.6875rem/1.6 var(--mono);
  padding: 1px 8px;
  border-radius: 999px;
  white-space: nowrap;
  border: 1px solid;
}
.transcript__event--ok { color: var(--ok); background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.transcript__event--bad { color: var(--bad); background: var(--bad-soft); border-color: color-mix(in srgb, var(--bad) 30%, transparent); }
.transcript__event--info { color: var(--info); background: var(--info-soft); border-color: color-mix(in srgb, var(--info) 30%, transparent); }

.outcome {
  display: grid;
  gap: 8px;
  padding: 14px 16px;
  border-top: 1px dashed var(--line);
  background: var(--surface-2);
  font-size: 0.875rem;
}
.outcome strong { font-weight: 650; }
.outcome p { color: var(--muted); }
.outcome ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; color: var(--muted); }
.outcome li { display: grid; grid-template-columns: 14px minmax(0, 1fr); gap: 9px; align-items: start; }
/* The text of each item is wrapped in one span: a grid container makes every child element its
   own item, so an unwrapped sentence containing <code> would break across rows. */
.outcome li > span { min-width: 0; }
.outcome li::before { content: "→"; color: var(--faint); font-family: var(--mono); font-size: 0.8125rem; line-height: 1.6; }
.outcome li code { padding-block: 0; }
/* Both panels in a pair stay the same height, with the outcome pinned to the bottom. */
.wires > .panel { display: grid; grid-template-rows: auto 1fr auto; }

/* ---------------------------------------------------------------- inverted band */
/* One dark section, where the argument is about failure. It is a deliberate flip, so it defines
   its own complete palette rather than inheriting half of one. */
.band--invert {
  --surface: #171b22;
  --surface-2: #1d222b;
  --ink: #f3f4f6;
  --ink-soft: #d5d9e0;
  --muted: #9aa3b2;
  --faint: #767f8d;
  --line: #2a303a;
  --line-strong: #3b4350;
  --accent: #8d9aff;
  --accent-hover: #a6b0ff;
  --accent-ink: #10131b;
  --accent-soft: #1e2440;
  --accent-line: #333c66;
  --ok: #5ccf95;
  --ok-soft: #12291f;
  --warn: #e3b25c;
  --warn-soft: #2b2312;
  --bad: #f4948b;
  --bad-soft: #2f1a19;
  background: #0f1319;
  color: var(--ink);
  border-block: 1px solid #222832;
}
.band--invert .eyebrow { color: var(--faint); }
.band--invert .eyebrow--accent { color: var(--accent); }
.band--invert .band__head p,
.band--invert .split__copy p { color: var(--muted); }
.band--invert .tile { background: var(--surface); border-color: var(--line); }
.band--invert .card { background: var(--surface); border-color: var(--line); }
.band--invert .card__head,
.band--invert .card__foot { border-color: var(--line); background: var(--surface-2); }
.band--invert .btn { --btn-bg: transparent; --btn-fg: var(--ink); --btn-line: var(--line-strong); }
.band--invert .btn--primary { --btn-bg: var(--accent); --btn-fg: var(--accent-ink); }

/* ---------------------------------------------------------------- features, restructured */
.feature { transition: background-color 140ms ease; }
.feature:hover { background: var(--surface-2); }
.feature__meta {
  margin-top: 2px;
  font: 400 0.75rem/1.6 var(--mono);
  color: var(--faint);
}
.features--lead { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.features--lead .feature { padding: 30px; gap: 11px; }
.features--lead .feature h3 { font-size: 1.125rem; }

/* ---------------------------------------------------------------- facts, refined */
.facts dd { font-variant-numeric: tabular-nums; letter-spacing: -0.03em; }
.facts dd small { font-size: 0.9375rem; font-weight: 500; color: var(--muted); letter-spacing: 0; margin-left: 4px; }
.facts > div { padding: 24px 26px; }

/* ---------------------------------------------------------------- CTA, refined */
.cta { position: relative; overflow: hidden; }
.cta__rule {
  width: 52px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
}

@media (max-width: 900px) {
  .wires { grid-template-columns: minmax(0, 1fr); }
  .features--lead { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------------- template gallery */
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.starter {
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: 8px;
  padding: 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  transition: border-color 120ms ease, background-color 120ms ease;
}
.starter:hover { border-color: var(--line-strong); background: var(--surface-2); }
.starter__category {
  font: 500 0.6875rem/1 var(--mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.starter h3 { font-size: 1rem; font-weight: 650; }
.starter p { font-size: 0.875rem; color: var(--muted); }
.starter__subject {
  font: 400 0.75rem/1.5 var(--mono);
  color: var(--faint);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 6px 9px;
  overflow-wrap: anywhere;
}
.starter__foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.starter__vars { font-size: 0.8125rem; color: var(--faint); }

/* ---------------------------------------------------------------- admin chrome */
/* The admin area uses the same components with different chrome, so nobody acts on the wrong
   account because two screens looked identical. */
.app--admin .sidebar { background: var(--surface-2); border-right-color: var(--line-strong); }
.app--admin .topbar { background: var(--surface-2); }
.brand__mark--admin { background: var(--ink); color: var(--paper); }
.admin-tag {
  font: 500 0.625rem/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  padding: 3px 6px;
  border-radius: 4px;
  margin-left: 2px;
}
td.over { color: var(--bad); font-weight: 600; }

/* Admin controls: one action per row, each labelled with what it does. A wrapping row of four
   buttons made "pause" and "suspend" sit next to each other at unpredictable places. */
.card__body--rows { padding: 0; }
.ctl {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 16px 20px;
  border-top: 1px solid var(--line);
}
.ctl:first-child { border-top: 0; }
.ctl__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.ctl__text .muted { font-size: 0.8125rem; overflow-wrap: anywhere; }
.ctl__text label { margin: 0; }
.ctl__act {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.ctl__act input[type="text"] { width: 240px; }
.ctl__act input[type="number"] { width: 120px; }
/* The one action that cannot be undone from this page gets its own tint. */
.ctl--grave { background: color-mix(in oklab, var(--bad) 7%, transparent); }
/* A control whose form needs more than one field: it goes under the explanation rather than
   beside it, because two inputs squeezed into the right-hand column are two inputs nobody reads
   the labels of. */
.ctl--stack { flex-direction: column; align-items: stretch; gap: 12px; }
.ctl__form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ctl__form input[type="email"] { flex: 1 1 220px; min-width: 0; }
.ctl__form input[type="text"] { flex: 2 1 260px; min-width: 0; }
.ctl--plain { display: block; }
.ctl--plain .kv { margin: 0; }

@media (max-width: 720px) {
  .ctl { flex-direction: column; align-items: stretch; gap: 10px; }
  .ctl__act { justify-content: flex-start; }
  .ctl__act input[type="text"] { width: 100%; }
}

/* Allowance meter. Over the line it turns red rather than running past the end of its track,
   because a bar that overflows itself reads as a rendering fault rather than as a fact. */
.allowance { margin-top: 16px; }
.meter {
  appearance: none;
  display: block;
  width: 100%;
  height: 8px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
.meter::-webkit-progress-bar { background: var(--surface-2); }
.meter::-webkit-progress-value { background: var(--ok); border-radius: 999px; }
.meter::-moz-progress-bar { background: var(--ok); }
.meter--near::-webkit-progress-value { background: var(--warn); }
.meter--near::-moz-progress-bar { background: var(--warn); }
.meter--over::-webkit-progress-value { background: var(--bad); }
.meter--over::-moz-progress-bar { background: var(--bad); }
.allowance .cell-sub { margin-top: 6px; }

/* The usage figure and its 30-day bars. The chart is plain SVG with a <title> per bar, so it
   needs no script and a screen reader gets the numbers. */
.usage-figure { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.usage-figure__value { font: 650 2.5rem/1 var(--display); letter-spacing: -0.02em; }
.usage-figure__label { color: var(--muted); }
.spark { display: block; width: 100%; height: auto; }
.spark__bar { fill: var(--chart-1); }
.spark__bar:hover { fill: var(--accent-hover); }

/* A held message: the evidence beside the two decisions. Wide enough to read the finding,
   because "release or reject" is not a judgement anyone should make from a status word. */
.holds { display: grid; }
.hold {
  display: flex;
  align-items: flex-start;
  gap: 24px;
  padding: 16px 20px;
  border-top: 1px solid var(--line);
}
.hold:first-child { border-top: 0; }
.hold__body { flex: 1; min-width: 0; display: grid; gap: 4px; }
.hold__head { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.hold__findings { display: grid; gap: 4px; margin-top: 8px; }
.finding {
  display: grid;
  gap: 2px;
  padding: 8px 10px;
  border-left: 2px solid var(--bad);
  background: var(--surface-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: 0.875rem;
}
.finding .muted { font-size: 0.8125rem; overflow-wrap: anywhere; }
.hold__act { display: flex; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; }

@media (max-width: 720px) {
  .hold { flex-direction: column; gap: 12px; }
}

/* ---------------------------------------------------------------- charts */
/* Marks carry the colour; text never does. Touching segments are separated by a gap in the
   surface colour rather than a stroke, because a stroke is ink that is not data. */
.chart { margin: 0; display: grid; gap: 14px; }
.chart__svg { display: block; width: 100%; height: auto; overflow: visible; }
.chart__grid { stroke: var(--chart-grid); stroke-width: 1; shape-rendering: crispEdges; }
.chart__tick {
  font: 400 11px/1 var(--sans);
  fill: var(--faint);
  font-variant-numeric: tabular-nums;
}

.mark--ok { fill: var(--ok-mark); }
.mark--warn { fill: var(--warn-mark); }
.mark--bad { fill: var(--bad-mark); }
.mark--muted { fill: var(--muted-mark); }

/* The hit target is the whole column, not the painted sliver. A reader aims at a date. */
.chart__hit { fill: transparent; cursor: default; }
.chart__col:hover .mark,
.chart__hit:focus-visible ~ .mark { filter: brightness(1.12); }
.chart__col:hover .chart__hit,
.chart__hit:focus-visible { fill: var(--surface-2); fill-opacity: 0.5; }
.chart__hit:focus { outline: none; }
.chart__hit:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Identity is never colour alone: every key carries its name. */
.chart__legend { display: flex; gap: 18px; flex-wrap: wrap; padding: 0; font-size: 0.8125rem; color: var(--muted); }
.key { display: inline-flex; align-items: center; gap: 7px; }
.key__mark { width: 10px; height: 10px; border-radius: 2px; flex: 0 0 auto; }
/* The same fills as the bars they label. A legend in a different shade from the chart is a
   legend that has to be worked out rather than read. */
.key__mark--ok { background: var(--ok-mark); }
.key__mark--warn { background: var(--warn-mark); }
.key__mark--bad { background: var(--bad-mark); }
.key__mark--muted { background: var(--muted-mark); }

/* The tooltip enhances; it never gates. Every value is in here too. */
.chart__table > summary {
  font-size: 0.8125rem;
  color: var(--muted);
  cursor: pointer;
  width: max-content;
}
.chart__table > summary:hover { color: var(--ink); }
.chart__table .table-wrap { margin-top: 10px; max-height: 320px; overflow: auto; }

.chart-tip {
  position: fixed;
  z-index: 60;
  min-width: 160px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  font-size: 0.8125rem;
  pointer-events: none;
}
.chart-tip[hidden] { display: none; }
.chart-tip__day { font-weight: 600; margin-bottom: 6px; }
/* Values lead, labels follow: here the reader has the series and wants the number. */
.chart-tip__row { display: flex; align-items: baseline; gap: 8px; }
.chart-tip__key { width: 12px; height: 2px; border-radius: 1px; flex: 0 0 auto; align-self: center; }
.chart-tip__key--ok { background: var(--ok); }
.chart-tip__key--warn { background: var(--warn); }
.chart-tip__key--bad { background: var(--bad); }
.chart-tip__key--muted { background: var(--line-strong); }
.chart-tip__value { font-weight: 600; font-variant-numeric: tabular-nums; margin-left: auto; }
.chart-tip__label { color: var(--muted); }
.chart-tip__total {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 8px;
}

/* A tile's trend: the run de-emphasised, the current period picked out. */
.tile__trend { margin-top: 10px; }
.spark-tile { display: block; width: 100%; height: 28px; }
.spark-tile__bar { fill: var(--line-strong); }
.spark-tile__bar--now { fill: var(--accent); }

/* ------------------------------------------------------- operational strip */
.strip {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  padding: 10px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 0.875rem;
  color: var(--muted);
}
.strip__item { display: inline-flex; align-items: center; gap: 8px; }
a.strip__item { color: var(--bad); text-decoration: none; }
a.strip__item:hover { text-decoration: underline; }
.strip__item--bad { color: var(--bad); }
.strip__item strong { color: var(--ink); font-weight: 600; }
.strip__item--bad strong { color: var(--bad); }
.strip__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line-strong); }
.strip__dot--ok { background: var(--ok-dot); }
.strip__dot--busy { background: var(--accent); }
.strip__dot--bad { background: var(--bad); }

/* ------------------------------------------------------- segmented control */
.segmented {
  display: inline-flex;
  padding: 2px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.segmented__item {
  padding: 5px 12px;
  border-radius: 4px;
  font: 500 0.8125rem/1.3 var(--sans);
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}
.segmented__item:hover { color: var(--ink); }
.segmented__item.is-on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }

/*
  Seven tabs do not fit on a phone.
  
  Settings is 501px of tab strip inside a 375px screen, and because nothing here scrolled, the
  strip pushed the entire dashboard sideways: every page could be dragged left and right, the way
  no site anybody uses behaves. It scrolls itself now.

  The scrollbar is hidden rather than styled. A strip this short shows its own overflow — the last
  tab is visibly cut — and a bar under six words is more furniture than information. Snapping means
  a flick lands on a tab rather than between two.
*/
@media (max-width: 760px) {
  /* The strip sits in a flex row inside a flex topbar, and a flex item's default min-width is
     auto — it refuses to shrink below its content whatever max-width says. Both ancestors have to
     give permission before the scroll container below can do anything at all. */
  .topbar > .row { min-width: 0; }
  .segmented {
    display: flex;
    min-width: 0;
    max-width: 100%;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .segmented::-webkit-scrollbar { display: none; }
  .segmented__item { scroll-snap-align: start; flex: 0 0 auto; }
}

/* A long table scrolls its rows under its own header rather than losing it off the top. */
.table-wrap { position: relative; }
.data thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-2);
}

/* ------------------------------------------------------------ command palette */
.omni {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--muted);
  font: 400 0.875rem/1.2 var(--sans);
  cursor: pointer;
}
.omni:hover { color: var(--ink); border-color: var(--faint); }
.omni svg { width: 15px; height: 15px; }
kbd {
  font: 500 0.6875rem/1 var(--mono);
  padding: 3px 5px;
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--muted);
  white-space: nowrap;
}

.pal { position: fixed; inset: 0; z-index: 80; display: grid; place-items: start center; }
.pal[hidden] { display: none; }
.pal__backdrop { position: absolute; inset: 0; background: rgb(12 15 20 / 0.42); }
.pal__panel {
  position: relative;
  width: min(100% - 32px, 620px);
  margin-top: 12vh;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.pal__input {
  width: 100%;
  padding: 16px 18px;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  font-size: 1rem;
  background: transparent;
}
.pal__input:focus { outline: none; }
.pal__list { max-height: min(52vh, 420px); overflow-y: auto; padding: 6px; }
.pal__item {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--ink);
}
.pal__item.is-active { background: var(--accent-soft); }
.pal__item:hover { background: var(--surface-2); }
.pal__kind {
  flex: 0 0 62px;
  font: 500 0.6875rem/1.4 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
}
.pal__body { display: grid; gap: 1px; min-width: 0; }
.pal__title { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pal__sub { font-size: 0.8125rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pal__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  border-top: 1px solid var(--line);
  background: var(--surface-2);
  font-size: 0.8125rem;
  flex-wrap: wrap;
}
.pal__hints { display: inline-flex; align-items: center; gap: 5px; }

@media (max-width: 720px) {
  .omni span { display: none; }
  .omni kbd { display: none; }
  .pal__panel { margin-top: 6vh; }
  .pal__hints { display: none; }
}

/* ---------------------------------------------------------------- pricing */
/* Four plans, and auto-fit put three across with the fourth stranded on its own line across a
   wide band of widths — the worst of the arrangements available, and the one a 1280px laptop
   lands on. Explicit steps can never produce it: four, then two by two, then a column. */
.plans {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
  margin-top: 8px;
}
@media (max-width: 1080px) { .plans { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .plans { grid-template-columns: minmax(0, 1fr); } }
.plan {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 26px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  min-width: 0;
}
.plan--quiet { background: transparent; box-shadow: none; border-style: dashed; }
.plan h3 { font-size: 1.125rem; }
.plan__price {
  font: 650 2rem/1 var(--display);
  letter-spacing: -0.02em;
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
.plan__price small { font: 400 0.8125rem/1.4 var(--sans); color: var(--muted); }
.plan__desc { color: var(--muted); font-size: 0.9375rem; }
.plan__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 0.9375rem; }
.plan__list li { display: flex; gap: 9px; align-items: baseline; color: var(--ink-soft); }
.plan__list li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  flex: 0 0 auto;
  transform: translateY(-2px);
}
.plan .btn { margin-top: auto; }
.measure { max-width: var(--measure); }

/* A heading a reader can send to somebody. Hidden until the heading is hovered or the link
   itself has focus, so it never competes with the words. */
.anchor {
  margin-left: 10px;
  color: var(--faint);
  text-decoration: none;
  font-weight: 400;
  opacity: 0;
  transition: opacity 120ms ease;
}
h2:hover .anchor, h3:hover .anchor, .anchor:focus-visible { opacity: 1; }
.anchor:hover { color: var(--accent); }

/* The docs navigation says where the reader is, not only where they last clicked. */
.docs__nav a.is-current {
  color: var(--ink);
  font-weight: 600;
  background: var(--accent-soft);
}

/* A checkbox with a sentence beside it, aligned on the first line of text rather than centred
   on a paragraph that wraps to three. */
.check { display: flex; gap: 10px; align-items: flex-start; font-size: 0.9375rem; }
.check input { margin-top: 4px; flex: 0 0 auto; }

/* An application, read side by side with what the account has actually done. */
.application { display: grid; gap: 14px; }
.application__answer { display: grid; gap: 4px; }
.application__answer dt { font-size: 0.8125rem; color: var(--muted); }
.application__answer dd {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  padding: 10px 12px;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
}

/* ---------------------------------------------------------------- pricing calculator */
.calc {
  margin-top: 28px;
  padding: 26px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: grid;
  gap: 20px;
}
.calc__head { display: grid; gap: 8px; }
.calc__head h3 { font-size: 1.125rem; }
.calc__head p { color: var(--muted); font-size: 0.9375rem; }

.calc__control { display: grid; gap: 10px; }
.calc__control label {
  font-size: 0.8125rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.calc__control input[type="range"] { width: 100%; accent-color: var(--accent); }
.calc__volume {
  font: 650 1.5rem/1 var(--display);
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* The tick labels sit under the track rather than inside a datalist, because browsers render
   datalist marks inconsistently and several ignore the labels entirely. */
.calc__ticks {
  list-style: none;
  margin: -12px 0 0;
  padding: 0;
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

.calc__cells {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 2px;                      /* the surface showing through, as everywhere else */
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.calc__cell { background: var(--surface); padding: 18px; display: grid; gap: 6px; align-content: start; }
.calc__cell--ours { background: var(--accent-soft); }
.calc__label { font-size: 0.8125rem; color: var(--muted); }
.calc__cell--ours .calc__label { color: var(--ink-soft); }
.calc__figure {
  font: 650 2rem/1 var(--display);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.calc__figure--rival { color: var(--muted); }
.calc__split { font-size: 0.8125rem; color: var(--muted); }

/* Green only when we are actually cheaper. The same cell turns amber when we are not, because a
   calculator that can only show good news is not a calculator. */
.calc__cell--for { background: var(--ok-soft); }
.calc__cell--for .calc__figure { color: var(--ok); }
.calc__cell--against { background: var(--warn-soft); }
.calc__cell--against .calc__figure { color: var(--warn); }

.calc__table summary { cursor: pointer; font-size: 0.875rem; color: var(--muted); }
.calc__table table { width: 100%; border-collapse: collapse; margin-top: 14px; font-size: 0.875rem; }
.calc__table th, .calc__table td {
  text-align: right;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.calc__table thead th { color: var(--muted); font-weight: 500; border-bottom-color: var(--line-strong); }
.calc__table th[scope="row"], .calc__table td:nth-child(2) { text-align: left; }
.calc__better { color: var(--ok); }
.calc__worse { color: var(--warn); }

.calc__source { font-size: 0.8125rem; color: var(--faint); max-width: var(--measure); }
.calc__source a { color: inherit; }
/* The method, under the table it is the method for. */
.calc__note {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--faint);
  max-width: var(--measure);
  margin: 12px 0 4px;
}
.calc__note a { color: inherit; }

@media (max-width: 720px) {
  /* Seven columns of currency will not fit a phone, and a table that scrolls sideways inside the
     page is easier to read than one squeezed until the figures wrap. */
  .calc__table > table { display: block; overflow-x: auto; }
  .calc__figure { font-size: 1.625rem; }
}

/* ---------------------------------------------------------------- the delivery flow diagram */
/*
  overflow-x: clip, because the animation below paints outside this box: the pulse ends its
  travel at translateX(28px) and the second card swells past its own width. Twenty of those
  pixels were landing outside the viewport on a phone, which is why the whole page could be
  dragged sideways — the one thing a page must never do, and the thing every reader notices
  immediately because no site they use behaves that way.

  clip rather than hidden. hidden makes this a scroll container, which means the overflow becomes
  scrollable here instead of on the page; the pixels are decorative and should simply not exist.
*/
.flow { margin: 0; display: grid; gap: 18px; overflow-x: clip; }

.flow__track {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 34px;                      /* wide enough to hold a connector between the cards */
}
.flow__stage {
  position: relative;
  display: grid;
  gap: 9px;
  align-content: start;
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  min-width: 0;
}

/* The connector. A rotated corner rather than an arrow glyph, so it stays crisp at any zoom and
   takes its colour from the theme instead of the font. */
.flow__stage + .flow__stage::before {
  content: "";
  position: absolute;
  left: -23px;
  top: 34px;
  width: 9px;
  height: 9px;
  border-top: 2px solid var(--line-strong);
  border-right: 2px solid var(--line-strong);
  transform: rotate(45deg);
}

/* The two stages that carry a cost are the argument, so they are the two that are coloured.
   Ours is filled; Amazon's is outlined and dashed, because that box is not our infrastructure
   and the drawing should not imply it is. */
.flow__stage--ours { background: var(--accent-soft); border-color: var(--accent-line); }
.flow__stage--aws { border-style: dashed; border-color: var(--line-strong); box-shadow: none; }

.flow__icon { color: var(--accent); display: block; }
.flow__icon svg { width: 20px; height: 20px; display: block; }
.flow__stage--aws .flow__icon { color: var(--muted); }

.flow__title { font-size: 1rem; display: grid; gap: 2px; }
.flow__note {
  font: 400 0.75rem/1.3 var(--sans);
  color: var(--muted);
  letter-spacing: 0.02em;
}
.flow__stage--aws .flow__note { color: var(--accent); font-weight: 500; }
.flow__body { font-size: 0.875rem; color: var(--muted); }

.flow__bill {
  justify-self: start;
  margin-top: 2px;
  padding: 3px 9px;
  font-size: 0.75rem;
  font-weight: 500;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--ink-soft);
}
.flow__stage--ours .flow__bill { background: var(--accent); color: var(--accent-ink); }

/* The return path runs the other way, so it gets its own lane instead of another arrow in the
   track. Flattening both directions onto one line is what makes most of these unreadable. */
.flow__return {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 0.875rem;
  color: var(--muted);
}
.flow__return strong { color: var(--ink); font-weight: 600; }
.flow__return-icon { color: var(--accent); flex: 0 0 auto; }
.flow__return-icon svg { width: 18px; height: 18px; display: block; }

.flow figcaption { font-size: 0.875rem; color: var(--muted); max-width: var(--measure); }

@media (max-width: 900px) {
  .flow__track { grid-template-columns: repeat(2, 1fr); }
  /* Two across, the third card starts a new row, so its connector would point at the edge of
     the page rather than at the card before it. */
  .flow__stage:nth-child(3)::before { display: none; }
}
@media (max-width: 620px) {
  .flow__track { grid-template-columns: 1fr; gap: 30px; }
  .flow__stage:nth-child(3)::before { display: block; }
  /* Stacked, the flow runs downward, so the connector turns with it. */
  .flow__stage + .flow__stage::before {
    left: 50%;
    top: -20px;
    transform: rotate(135deg) translate(-4px, 4px);
  }
}

/* ---------------------------------------------------------------- the product, in a window */
.shot {
  margin: 0;
  display: grid;
  gap: 14px;
}
.shot__chrome {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.shot__dots { display: flex; gap: 6px; flex: 0 0 auto; }
.shot__dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); }
.shot__url {
  flex: 1 1 auto;
  padding: 3px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 400 0.75rem/1.6 var(--mono);
  color: var(--muted);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Says what it is, in the frame, where nobody can miss it and mistake the figures for real. */
.shot__tag {
  flex: 0 0 auto;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--warn-soft);
  color: var(--warn);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.shot__body {
  display: grid;
  gap: 16px;
  padding: 20px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
/* The preview borrows the application's own components, which are sized for a full page. A
   notch smaller here keeps the window reading as a window rather than as more of the site. */
.shot__body .tile__value { font-size: 1.5rem; }
.shot__body .card__head h3 { font-size: 0.9375rem; }
.shot__body .timeline { margin: 0; }
.shot figcaption { font-size: 0.875rem; color: var(--muted); max-width: var(--measure); }

@media (max-width: 620px) {
  .shot__body { padding: 14px; gap: 12px; }
  .shot__url { display: none; }   /* the tag matters more than the address at this width */
  /* Four full-width tiles turn the window into a phone-and-a-half of scrolling before the
     chart appears. Two across keeps the whole preview glanceable. Scoped to the preview: what
     the real dashboard should do at this width is a separate question with a real user behind
     it, and not one to answer from inside a marketing page. */
  .shot__body .tiles { grid-template-columns: 1fr 1fr; }
  .shot__body .tile__value { font-size: 1.25rem; }
}

/* ---------------------------------------------------------------- metrics */

/* The one figure somebody came for, given the room that implies, with the counts they already
   knew kept beside it rather than above it. */
.headline {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) 2fr;
  gap: 16px;
  align-items: stretch;
}
.headline__main {
  display: grid;
  gap: 6px;
  align-content: center;
  padding: 22px 24px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.headline__label {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.headline__value {
  font: 650 3rem/1 var(--display);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.headline__foot { font-size: 0.8125rem; color: var(--muted); }
.headline__side { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }

.gauges { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.gauge {
  display: grid;
  gap: 8px;
  padding: 18px 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--radius);
}
/* The border carries the state. A whole card flooded with colour reads as an alarm even when
   the rate is fine, and then nobody reads the one that is not. */
.gauge--ok { border-left-color: var(--ok); }
.gauge--warn { border-left-color: var(--warn); }
.gauge--bad { border-left-color: var(--bad); }
.gauge--quiet { border-left-color: var(--line-strong); }

.gauge__head { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; }
.gauge__label { font-weight: 600; font-size: 0.9375rem; }
.gauge__limit { font-size: 0.75rem; color: var(--muted); }
.gauge__value {
  font: 650 2rem/1 var(--display);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.gauge--warn .gauge__value { color: var(--warn); }
.gauge--bad .gauge__value { color: var(--bad); }
.gauge--quiet .gauge__value { color: var(--muted); }
.gauge__foot { font-size: 0.8125rem; color: var(--muted); }

.gauge__bar { width: 100%; height: 5px; border: 0; border-radius: 999px; }
.gauge__bar::-webkit-progress-bar { background: var(--surface-3); border-radius: 999px; }
.gauge__bar::-webkit-progress-value { background: var(--ok); border-radius: 999px; }
.gauge__bar::-moz-progress-bar { background: var(--ok); border-radius: 999px; }
.gauge--warn .gauge__bar::-webkit-progress-value { background: var(--warn); }
.gauge--warn .gauge__bar::-moz-progress-bar { background: var(--warn); }
.gauge--bad .gauge__bar::-webkit-progress-value { background: var(--bad); }
.gauge--bad .gauge__bar::-moz-progress-bar { background: var(--bad); }

/* Figures line up under one another or they cannot be compared down a column. */
.data .num { text-align: right; font-variant-numeric: tabular-nums; }
.num--warn { color: var(--warn); }
.num--bad { color: var(--bad); }

/* An SMTP diagnostic is the server's own words and should look like a quotation, not like prose
   we wrote. It can be long, so it wraps rather than widening the table past the page. */
.reason {
  font-size: 0.8125rem;
  white-space: normal;
  word-break: break-word;
  color: var(--ink-soft);
}

@media (max-width: 860px) {
  .headline { grid-template-columns: minmax(0, 1fr); }
  .gauges { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 520px) {
  .headline__side { grid-template-columns: minmax(0, 1fr); }
  .headline__value { font-size: 2.25rem; }
}

/* ---------------------------------------------------------------- flows */

/* A flow is a document, and the box it is edited in should look like one. Monospace, tab-sized
   indentation, and no spellcheck squiggles under JSON keys. */
.code-input {
  width: 100%;
  font: 400 0.8125rem/1.6 var(--mono);
  tab-size: 2;
  padding: 14px 16px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  resize: vertical;
  min-height: 300px;
}
.code-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

/* The triggering event, shown as it arrived. Scrolls rather than widening the card, because one
   long URL in a payload should not push the page sideways. */
.payload {
  margin: 0;
  padding: 14px 16px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow-x: auto;
  font: 400 0.8125rem/1.6 var(--mono);
  color: var(--ink-soft);
}

/* The drafting box. Tinted so it reads as a different kind of action from the editor below it —
   one produces a draft, the other commits it — without shouting. */
.card--accent {
  background: var(--accent-soft);
  border-color: var(--accent-line);
}
.card--accent textarea {
  width: 100%;
  font: inherit;
  padding: 12px 14px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  resize: vertical;
}

/* ---------------------------------------------------------------- the flow builder */
/* Any author rule that sets display beats the browser's own [hidden] rule, so an element with
   display:grid stays visible however firmly it is hidden. Several components here set display on
   the same elements that get toggled, so hidden is restated once, loudly, rather than being
   worked around at each call site. */
[hidden] { display: none !important; }

.bd { display: grid; gap: 0; }
.bd__views { gap: 6px; }
.bd__views .btn.is-on { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }

/* ---------------------------------------------------------------- the flow canvas
   Cards on a dotted field, joined by curved wires, laid out by the script from the structure of
   the flow. Nothing here stores a position: every number the script writes is computed on each
   render, and this file only says what the pieces look like. */
.fc {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  overflow: hidden;
}

/* The field. Two dot layers at different scales, so zooming has something to bite on and the
   surface does not read as flat paper at every size. */
.fc__port {
  position: relative;
  height: clamp(360px, 62vh, 640px);
  overflow: hidden;
  cursor: grab;
  touch-action: none;
  background-image:
    radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--faint) 40%, transparent) 1px, transparent 0),
    radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--faint) 18%, transparent) 1px, transparent 0);
  background-size: 96px 96px, 24px 24px;
}
.fc__port.is-panning { cursor: grabbing; }

.fc__stage {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}

.fc__wires { position: absolute; top: 0; left: 0; overflow: visible; pointer-events: none; }
.fc__wire {
  stroke: var(--line-strong);
  stroke-width: 1.5;
  stroke-linecap: round;
}

/* A step. The type is said by the icon and by the colour of the left edge rather than by a word,
   which leaves the whole width of the card for the two things that differ between steps: what it
   is called, and what it does. */
.fc__node {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 11px;
  height: 62px;
  padding: 0 14px;
  box-sizing: border-box;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  text-align: left;
  transition: border-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}
.fc__node:hover { box-shadow: var(--shadow); transform: translateY(-1px); }
.fc__node:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.fc__node.is-editing {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft), var(--shadow);
}
/* A step nothing can reach. Drawn rather than hidden, because a node that exists and cannot run
   is a mistake worth seeing. */
.fc__node.is-orphan { border-style: dashed; opacity: 0.75; }

.fc__node--send { border-left-color: var(--accent); }
.fc__node--wait { border-left-color: var(--line-strong); }
.fc__node--await { border-left-color: var(--warn); }
.fc__node--if { border-left-color: var(--ink-soft); }
.fc__node--stop { border-left-color: var(--ok); }

.fc__icon { width: 18px; height: 18px; flex: 0 0 auto; color: var(--muted); }
.fc__node--send .fc__icon { color: var(--accent); }
.fc__node--await .fc__icon { color: var(--warn); }
.fc__node--stop .fc__icon { color: var(--ok); }

.fc__text { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
.fc__id {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fc__summary {
  font-size: 0.75rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Shown on hover and whenever it has focus, so it is reachable by keyboard without being a
   delete button sitting permanently beside every step. */
.fc__drop {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--faint);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 120ms ease, color 120ms ease, border-color 120ms ease;
}
.fc__node:hover .fc__drop,
.fc__drop:focus-visible { opacity: 1; }
.fc__drop:hover { color: var(--bad); border-color: var(--bad); }

/* The "+" on a wire. Centred on the point it sits at, so the script can give it a midpoint
   without also having to know how big it is. */
.fc__plus {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease, transform 120ms ease;
}
.fc__plus:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  transform: translate(-50%, -50%) scale(1.12);
}
.fc__plus:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.fc__branch {
  position: absolute;
  transform: translate(-50%, -50%);
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  font: 500 0.6875rem/1.4 var(--sans);
  color: var(--muted);
  white-space: nowrap;
  pointer-events: none;
}

/* What starts the flow, said once, in the corner. It is not a step — nothing routes into it and
   nothing can be inserted before it — so it is a caption rather than a card. */
.fc__trigger {
  position: absolute;
  top: 12px;
  left: 12px;
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 0.75rem;
  font-weight: 500;
  pointer-events: none;
}

.fc__zoom {
  position: absolute;
  top: 12px;
  right: 12px;
  display: grid;
  gap: 4px;
}
.fc__zoomBtn {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--ink-soft);
  font-size: 0.875rem;
  line-height: 1;
  cursor: pointer;
}
.fc__zoomBtn:hover { border-color: var(--line-strong); color: var(--ink); }
.fc__zoomBtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The panel for the step being edited. Under the canvas rather than floating over it: a flow is
   read top to bottom, and a panel covering the diagram hides the thing being changed. */
.fc__panel {
  margin-top: 14px;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 16px;
  display: grid;
  gap: 12px;
}
.fc__panelHead { display: flex; align-items: center; gap: 12px; }
.fc__panelHead h3 { font-size: 0.9375rem; font-family: var(--mono); flex: 1 1 auto; min-width: 0; }
.fc__panelClose {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.fc__panelClose:hover { color: var(--ink); border-color: var(--line-strong); }
.fc__panel input, .fc__panel select { width: 100%; }
.fc__hint { font-size: 0.75rem; color: var(--muted); }

.fc__broken {
  padding: 18px;
  border: 1px dashed var(--bad);
  border-radius: var(--radius);
  color: var(--bad);
  font-size: 0.875rem;
}

@media (max-width: 640px) {
  /* Shorter, because on a phone the canvas competes with the JSON below it for a screen that has
     room for one of them. */
  .fc__port { height: 60vh; }
}

@media (prefers-reduced-motion: reduce) {
  .fc__node, .fc__plus { transition: none; }
  .fc__node:hover { transform: none; }
  .fc__plus:hover { transform: translate(-50%, -50%); }
}

/* ---------------------------------------------------------------- the event picker */
.events { display: grid; gap: 10px; }
.events legend { font-weight: 600; font-size: 0.9375rem; padding: 0; }

.events__bar { display: flex; gap: 12px; align-items: center; }
.events__search {
  flex: 1 1 auto;
  min-width: 0;
  padding: 8px 12px;
  font: inherit;
  font-size: 0.875rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.events__count { flex: 0 0 auto; font-size: 0.8125rem; color: var(--muted); }

.events__list {
  max-height: 340px;
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.events__group { padding: 4px 0 8px; }
.events__group + .events__group { border-top: 1px solid var(--line); }
.events__groupName {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  padding: 10px 14px 4px;
}
.events__none { padding: 16px 14px; font-size: 0.875rem; color: var(--muted); }

.ev {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: start;
  gap: 10px;
  padding: 8px 14px;
  cursor: pointer;
}
.ev:hover { background: var(--surface-2); }
/* The native box is hidden rather than removed, so it keeps its keyboard behaviour and its place
   in the form. Everything visible is drawn from it. */
.ev input { position: absolute; opacity: 0; width: 0; height: 0; }
.ev__box {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  border: 1.5px solid var(--line-strong);
  border-radius: 4px;
  background: var(--surface);
  position: relative;
  flex: 0 0 auto;
}
.ev input:checked + .ev__box { background: var(--accent); border-color: var(--accent); }
.ev input:checked + .ev__box::after {
  content: "";
  position: absolute;
  left: 4.5px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--accent-ink);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.ev input:focus-visible + .ev__box { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The colour says what kind of news the event is, using the same meanings as everywhere else:
   green arrived, amber needs attention, red went wrong. */
.ev__dot { width: 7px; height: 7px; border-radius: 50%; margin-top: 7px; flex: 0 0 auto; }
.ev__dot--ok { background: var(--ok-dot); }
.ev__dot--warn { background: var(--warn); }
.ev__dot--bad { background: var(--bad); }
.ev__dot--info { background: var(--accent); }
.ev__dot--neutral { background: var(--line-strong); }

.ev__text { display: grid; gap: 2px; min-width: 0; }
.ev__text code { font-size: 0.8125rem; }
.ev__blurb { font-size: 0.8125rem; color: var(--muted); }

/* ---------------------------------------------------------------- the flow, moving
   A message travelling the diagram: it leaves the application, lights each stage as it passes,
   and arrives. It is the one thing on the page that says "this is a pipeline and things move
   through it" without a paragraph saying so.

   CSS rather than canvas. A few hundred bytes against six hundred kilobytes of WebGL, crisp at
   any zoom, correct in dark mode for free, and nothing for a screen reader to trip over.

   Only transform, opacity and colour animate. The browser never reflows the page to draw this,
   so it costs nothing on a phone. */

.flow__track { position: relative; }

/* The wave.
   A band of light that sweeps the whole row, wide enough to be a wave rather than a glint. It
   sits behind the cards and is masked to the track, so it reads as something passing underneath
   them. */
.flow__track::before {
  content: "";
  position: absolute;
  inset: -12px -40px;
  z-index: 0;
  pointer-events: none;
  border-radius: var(--radius-lg);
  background: linear-gradient(
    100deg,
    transparent 0%,
    color-mix(in oklab, var(--accent) 0%, transparent) 30%,
    color-mix(in oklab, var(--accent) 26%, transparent) 45%,
    color-mix(in oklab, var(--accent) 42%, transparent) 50%,
    color-mix(in oklab, var(--accent) 26%, transparent) 55%,
    transparent 70%,
    transparent 100%
  );
  background-size: 220% 100%;
  animation: flow-wave 3.2s cubic-bezier(0.45, 0, 0.3, 1) infinite;
}
.flow__stage { z-index: 1; }

@keyframes flow-wave {
  0% { background-position: 130% 0; }
  70%, 100% { background-position: -70% 0; }
}

/* The pulse: a dot with a glow and a tail, riding the front of the wave. */
.flow__stage + .flow__stage::after {
  content: "";
  position: absolute;
  left: -30px;
  top: 30px;
  z-index: 2;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 5px color-mix(in oklab, var(--accent) 24%, transparent),
              0 0 16px 3px color-mix(in oklab, var(--accent) 70%, transparent),
              -18px 0 12px -6px color-mix(in oklab, var(--accent) 55%, transparent);
  opacity: 0;
  animation: flow-pulse 3.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.flow__stage:nth-child(2)::after { animation-delay: 0.25s; }
.flow__stage:nth-child(3)::after { animation-delay: 0.55s; }
.flow__stage:nth-child(4)::after { animation-delay: 0.85s; }

@keyframes flow-pulse {
  0% { opacity: 0; transform: translateX(-16px) scale(0.3); }
  7% { opacity: 1; transform: translateX(-8px) scale(1.3); }
  22% { opacity: 1; transform: translateX(18px) scale(1); }
  32% { opacity: 0; transform: translateX(28px) scale(0.4); }
  100% { opacity: 0; transform: translateX(28px) scale(0.4); }
}

/* The connector brightens as the wave crosses it. */
.flow__stage + .flow__stage::before {
  animation: flow-wire 3.2s ease-in-out infinite;
}
.flow__stage:nth-child(2)::before { animation-delay: 0.25s; }
.flow__stage:nth-child(3)::before { animation-delay: 0.55s; }
.flow__stage:nth-child(4)::before { animation-delay: 0.85s; }

@keyframes flow-wire {
  0%, 5% { border-color: var(--line-strong); }
  13%, 24% { border-color: var(--accent); }
  38%, 100% { border-color: var(--line-strong); }
}

/* Each card is lifted differently as the wave passes under it — a different height, a different
   tilt, a different settle. Identical motion on four cards reads as four things bobbing; varied
   motion reads as one wave travelling beneath them, which is the thing being shown. */
.flow__stage .flow__card {
  animation-duration: 3.2s;
  animation-iteration-count: infinite;
  animation-timing-function: cubic-bezier(0.34, 1.4, 0.5, 1);
  will-change: transform;
}
.flow__stage:nth-child(1) .flow__card { animation-name: flow-lift-1; animation-delay: 0s; }
.flow__stage:nth-child(2) .flow__card { animation-name: flow-lift-2; animation-delay: 0.3s; }
.flow__stage:nth-child(3) .flow__card { animation-name: flow-lift-3; animation-delay: 0.6s; }
.flow__stage:nth-child(4) .flow__card { animation-name: flow-lift-4; animation-delay: 0.9s; }

/* First: rises and leans back, the way something does when it is pushed off. */
@keyframes flow-lift-1 {
  0%, 3% { transform: translateY(0) rotate(0deg); box-shadow: var(--shadow-sm); }
  13% { transform: translateY(-9px) rotate(-0.7deg); box-shadow: 0 14px 28px -12px rgba(36, 56, 224, 0.4); }
  30%, 100% { transform: translateY(0) rotate(0deg); box-shadow: var(--shadow-sm); }
}
/* Second: the highest, and it swells. This is the card with our name on it. */
@keyframes flow-lift-2 {
  0%, 3% { transform: translateY(0) scale(1); box-shadow: var(--shadow-sm); }
  13% { transform: translateY(-13px) scale(1.025); box-shadow: 0 20px 36px -14px rgba(36, 56, 224, 0.5); }
  32%, 100% { transform: translateY(0) scale(1); box-shadow: var(--shadow-sm); }
}
/* Third: leans forward as it hands over. */
@keyframes flow-lift-3 {
  0%, 3% { transform: translateY(0) rotate(0deg); }
  13% { transform: translateY(-8px) rotate(0.7deg); }
  30%, 100% { transform: translateY(0) rotate(0deg); }
}
/* Fourth: lands, and rocks once as it settles. Arrival should feel like arrival. */
@keyframes flow-lift-4 {
  0%, 3% { transform: translateY(0) scale(1); }
  12% { transform: translateY(-11px) scale(1.02); }
  22% { transform: translateY(2px) scale(0.995); }
  30% { transform: translateY(-2px) scale(1); }
  38%, 100% { transform: translateY(0) scale(1); }
}

/* Arrival: the last icon swells and turns green. */
.flow__stage:last-child .flow__icon {
  animation: flow-arrive 3.2s ease-in-out infinite;
  animation-delay: 1s;
}
@keyframes flow-arrive {
  0%, 8% { transform: scale(1); color: var(--muted); }
  16% { transform: scale(1.45); color: var(--ok); }
  28% { transform: scale(1); color: var(--ok); }
  55%, 100% { transform: scale(1); color: var(--muted); }
}

/*
  Stacked, the wave is not a wave.

  Side by side, four cards lifting one after another from left to right read as a single swell
  travelling underneath them, which is the thing the diagram is about. Below 620px the cards are
  in one column, and the same animation reads as the page itself breathing: four boxes rising and
  swelling in turn, forever, with nothing to travel along. People described it as the page zooming
  in and out, and said it was unsettling. They are right — a page that moves on its own with no
  input is a page that appears to be doing something to you.

  The wire and the pulse stay. They are small, they stay inside their own connector, and running
  down a column is a direction a column actually has.
*/
@media (max-width: 620px) {
  .flow__stage .flow__card,
  .flow__stage:last-child .flow__icon {
    animation: none;
  }
}

/* The return path carries events back the other way, so its rule fills downward after the
   message has arrived. */
.flow__return { position: relative; overflow: hidden; }
.flow__return::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--ok);
  box-shadow: 0 0 8px color-mix(in oklab, var(--ok) 50%, transparent);
  transform: translateY(-100%);
  animation: flow-return 3s ease-in-out infinite;
  animation-delay: 1.1s;
}
@keyframes flow-return {
  0%, 20% { transform: translateY(-100%); }
  38%, 70% { transform: translateY(0); }
  88%, 100% { transform: translateY(100%); }
}

/* Somebody who has asked their operating system to stop things moving has usually asked for a
   reason. The diagram is complete without any of this, so it all stops — and each element is
   given its resting state, because the blanket rule alone would freeze things at whatever
   keyframe they finished on, which for anything that fades out means invisible. */
@media (prefers-reduced-motion: reduce) {
  .flow__track::before,
  .flow__stage + .flow__stage::after,
  .flow__stage + .flow__stage::before,
  .flow__stage .flow__card,
  .flow__stage:last-child .flow__icon,
  .flow__return::after {
    animation: none;
  }
  .flow__track::before { opacity: 0; }
  .flow__stage + .flow__stage::after { opacity: 0; }
  .flow__stage + .flow__stage::before { border-color: var(--line-strong); }
  .flow__stage .flow__card { transform: none; }
  .flow__stage:last-child .flow__icon { transform: none; color: var(--muted); }
  .flow__return::after { transform: translateY(0); }
}

/* ---------------------------------------------------------------- charts, arriving
   Columns rise from the baseline once, as the chart comes into view, and then stop.

   Once, not looping. A chart is data, and data that keeps moving reads as live — which would be
   a lie on a marketing page showing an example fortnight, and a distraction on a dashboard where
   somebody is trying to read a number.

   The animation is added by script, so a reader with JavaScript off gets a chart that is simply
   there rather than a chart that is permanently flat. */
.chart--grow .chart__col {
  transform-box: fill-box;
  transform-origin: bottom;
  transform: scaleY(0.001);
}
.chart--grow.is-in .chart__col {
  animation: chart-grow 620ms cubic-bezier(0.22, 1, 0.3, 1) forwards;
}

/* Left to right, a beat apart, so the eye reads it as time passing rather than as everything
   appearing at once. Capped at fourteen: beyond that the last column would wait a second and a
   half, and nobody waits that long to read a chart. */
.chart--grow.is-in .chart__col:nth-child(n + 1) { animation-delay: 0ms; }
.chart--grow.is-in .chart__col:nth-of-type(2) { animation-delay: 35ms; }
.chart--grow.is-in .chart__col:nth-of-type(3) { animation-delay: 70ms; }
.chart--grow.is-in .chart__col:nth-of-type(4) { animation-delay: 105ms; }
.chart--grow.is-in .chart__col:nth-of-type(5) { animation-delay: 140ms; }
.chart--grow.is-in .chart__col:nth-of-type(6) { animation-delay: 175ms; }
.chart--grow.is-in .chart__col:nth-of-type(7) { animation-delay: 210ms; }
.chart--grow.is-in .chart__col:nth-of-type(8) { animation-delay: 245ms; }
.chart--grow.is-in .chart__col:nth-of-type(9) { animation-delay: 280ms; }
.chart--grow.is-in .chart__col:nth-of-type(10) { animation-delay: 315ms; }
.chart--grow.is-in .chart__col:nth-of-type(11) { animation-delay: 350ms; }
.chart--grow.is-in .chart__col:nth-of-type(12) { animation-delay: 385ms; }
.chart--grow.is-in .chart__col:nth-of-type(13) { animation-delay: 420ms; }
.chart--grow.is-in .chart__col:nth-of-type(n + 14) { animation-delay: 455ms; }

@keyframes chart-grow {
  from { transform: scaleY(0.001); }
  to { transform: scaleY(1); }
}

@media (prefers-reduced-motion: reduce) {
  .chart--grow .chart__col,
  .chart--grow.is-in .chart__col {
    animation: none;
    transform: none;
  }
}

/* ---------------------------------------------------------------- legal pages */
.legal { padding-block: 48px 96px; }
.legal h1 { font-size: clamp(1.9rem, 4vw, 2.6rem); letter-spacing: -0.03em; }
.legal__meta { font-size: 0.8125rem; color: var(--faint); }

/* A contents list, because these are read by somebody looking for one clause rather than read
   through. It is a plain list of links so it works before any script runs. */
.legal__toc {
  padding: 16px 18px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.legal__toc ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  font-size: 0.875rem;
}
.legal__toc a { color: var(--ink-soft); }

.legal__section { display: grid; gap: 14px; padding-top: 34px; scroll-margin-top: 24px; }
.legal__section + .legal__section { border-top: 1px solid var(--line); }
.legal__section h2 { font-size: 1.25rem; letter-spacing: -0.02em; }
.legal__section p { max-width: var(--measure); color: var(--ink-soft); }
.legal__section .data { font-size: 0.9375rem; }
.legal__section .data th[scope="row"] { white-space: nowrap; padding-right: 20px; }
.legal__section .checklist { gap: 10px; }

/* The consent tick on the sign-in form. Generous hit area, because it is required and a target
   somebody has to aim at is a target somebody gets wrong on a phone. */
.consent {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: start;
  padding: 4px 2px;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--muted);
  cursor: pointer;
}
/* Drawn rather than left native. The platform checkbox is a grey Windows square that ignores
   the card it sits on and looks broken in dark mode, and this one is required, so it is the
   control everybody has to touch. */
.consent input {
  appearance: none;
  -webkit-appearance: none;
  margin: 1px 0 0;
  width: 18px;
  height: 18px;
  border: 1px solid var(--line-strong);
  border-radius: 5px;
  background: var(--surface-2);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.consent input::after {
  content: "";
  width: 9px;
  height: 5px;
  border-left: 2px solid var(--accent-ink);
  border-bottom: 2px solid var(--accent-ink);
  transform: rotate(-45deg) translate(1px, -1px);
  opacity: 0;
  transition: opacity 90ms ease;
}
.consent:hover input { border-color: var(--faint); }
.consent input:checked { background: var(--accent); border-color: var(--accent); }
.consent input:checked::after { opacity: 1; }
.consent input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* High-contrast mode paints none of the above. Give the real control back rather than a blank
   square nobody can tell the state of. */
@media (forced-colors: active) {
  .consent input { appearance: auto; -webkit-appearance: auto; }
}
.consent a { color: var(--ink-soft); }

/* ---------------------------------------------------------------- adding credit */
.topup { display: grid; gap: 16px; }

/* Amounts as buttons, not a dropdown and a Continue. Choosing how much credit to buy is not a
   decision that deserves two steps, and one button per amount is one tap on a phone. */
.topup__steps { display: flex; flex-wrap: wrap; gap: 8px; }
.topup__step {
  padding: 10px 18px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: 600 0.9375rem/1.2 var(--sans);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease, transform 80ms ease;
}
.topup__step:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.topup__step:active { transform: translateY(1px); }
.topup__step:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.topup__custom {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  padding-top: 4px;
  border-top: 1px solid var(--line);
}
.topup__custom .field { flex: 1 1 220px; min-width: 0; }

/* The symbol sits inside the box rather than beside it, so what is being typed reads as one
   amount rather than as a currency and a number that happen to be next to each other. */
.topup__amount { position: relative; display: flex; align-items: center; }
.topup__symbol {
  position: absolute;
  left: 12px;
  color: var(--muted);
  font-size: 0.9375rem;
  pointer-events: none;
}
.topup__amount input { padding-left: 30px; font-variant-numeric: tabular-nums; }

.topup__switch {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 0.8125rem;
  color: var(--muted);
}

/* ---------------------------------------------------------------- sender registrations */

/* Two columns of fields where there is room, one where there is not. A business form is eight
   short questions, and eight full-width boxes is a page of scrolling for no reason. */
.grid-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
}

/* The decision, as one row per application.
   The reason box is wide because it is a sentence somebody else has to act on, not a word. */
.decide { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.decide input[type="text"] { width: 240px; min-width: 0; font-size: 0.8125rem; padding: 5px 9px; }

/* The checklist under the sender kinds is prose rather than ticks, so it loses the tick column. */
.card__body .checklist li { grid-template-columns: 1fr; font-size: 0.8125rem; color: var(--muted); }
.card__body .checklist li strong { color: var(--ink-soft); text-transform: capitalize; }

@media (max-width: 860px) {
  /* The application's three answers are the whole decision, so on a narrow screen they get the
     width and the reason box goes underneath rather than beside. */
  .decide input[type="text"] { width: 100%; }
}
.decide__short { width: 130px; }

/* The dialog that explains a switched-off button.
   A real <dialog>, so Escape and the backdrop are the browser's rather than ours. */
.why {
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  max-width: min(92vw, 440px);
  box-shadow: var(--shadow-lg);
}
.why::backdrop { background: rgb(8 10 14 / 0.55); backdrop-filter: blur(2px); }
.why__inner { display: grid; gap: 12px; padding: 22px; margin: 0; }
.why__title { font-size: 1.0625rem; font-weight: 650; }
.why__body { font-size: 0.9375rem; line-height: 1.6; color: var(--muted); }
.why__actions { display: flex; justify-content: flex-end; }

/* A file input is the ugliest control the platform ships. This is the least that makes it
   belong: the button half gets the same treatment as every other button here. */
input[type="file"] {
  width: 100%;
  padding: 8px 10px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--muted);
  font: 400 0.875rem/1.4 var(--sans);
  cursor: pointer;
}
input[type="file"]:hover { border-color: var(--accent); }
input[type="file"]::file-selector-button {
  margin-right: 12px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: 500 0.8125rem/1.2 var(--sans);
  cursor: pointer;
}
input[type="file"]::file-selector-button:hover { border-color: var(--line-strong); }

/* ---------------------------------------------------------------- a person

   An avatar is a picture or two letters, and the two have to occupy exactly the same box or the
   header moves when somebody uploads a photograph. One class, one set of sizes, both shapes. */
.avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 999px;
  object-fit: cover;
  background: var(--accent-soft);
  color: var(--accent);
  font: 600 0.75rem/1 var(--sans);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  overflow: hidden;
}
.avatar--sm { width: 26px; height: 26px; font-size: 0.6875rem; }
.avatar--md { width: 40px; height: 40px; font-size: 0.875rem; }
.avatar--lg { width: 64px; height: 64px; font-size: 1.25rem; border-radius: 16px; }

/* The account menu in the public header.

   A <details>, so the browser gives it the keyboard behaviour for free. The panel is absolutely
   positioned off the summary, which means the header does not change height when it opens. */
.usermenu { position: relative; }
.usermenu__chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px 4px 4px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font: 500 0.875rem/1 var(--sans);
  cursor: pointer;
  list-style: none;
  white-space: nowrap;
}
.usermenu__chip::-webkit-details-marker { display: none; }
.usermenu__chip:hover { border-color: var(--line-strong); }
.usermenu__chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.usermenu__name { max-width: 10ch; overflow: hidden; text-overflow: ellipsis; }
.usermenu__chev { width: 14px; height: 14px; color: var(--faint); transition: transform 0.15s ease; }
.usermenu[open] .usermenu__chev { transform: rotate(180deg); }

.usermenu__panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 40;
  min-width: 220px;
  display: grid;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}
.usermenu__who {
  display: grid;
  gap: 2px;
  padding: 8px 10px 10px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
  font-size: 0.8125rem;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.usermenu__panel a,
.usermenu__panel button {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink);
  font: 400 0.875rem/1.2 var(--sans);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.usermenu__panel a:hover,
.usermenu__panel button:hover { background: var(--surface-2); }
.usermenu__panel form { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--line); }
.usermenu__panel button { color: var(--muted); }

/* The box at the foot of the rail is a link now, so it needs to look pressable without becoming
   another button in a column that already has three. */
a.userbox {
  border-radius: var(--radius-sm);
  padding: 4px;
  color: inherit;
  text-decoration: none;
}
a.userbox:hover { background: var(--surface-2); }
img.userbox__avatar { object-fit: cover; }

/* The profile page's own header: the picture, then who it belongs to. */
.profile__head { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.profile__name { font-size: 1.0625rem; }

/* ---------------------------------------------------------------- helping somebody publish DNS */

/* Where to go, before what to type. One quiet box above the table, not a second card. */
.dnsguide {
  display: grid;
  gap: 10px;
  margin: 16px 0 12px;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.dnsguide__where { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; }
.dnsguide__where p { margin: 0; flex: 1 1 320px; }
.dnsguide__go { display: grid; justify-items: start; gap: 4px; }
.dnsguide__dest { font-size: 0.75rem; color: var(--faint); }
.dnsguide__tips { margin: 0; padding-left: 18px; display: grid; gap: 4px; color: var(--muted); }
.dnsguide__zone { margin: 0; font-size: 0.8125rem; color: var(--muted); }

.dnsshare {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin: 0 0 16px;
  font-size: 0.875rem;
}
.dnsshare__label { color: var(--muted); }
.dnsshare .cell { display: flex; gap: 8px; align-items: center; flex: 1 1 280px; min-width: 0; }
.dnsshare__url { flex: 1 1 auto; min-width: 0; font-family: var(--mono); font-size: 0.8125rem; }

/* The short name is what goes in the box, so it leads; the full name is reference. */
.records__name { color: var(--ink); font-weight: 600; }
.records__help { margin-top: 6px; font-family: var(--sans); font-size: 0.8125rem; color: var(--muted); }
/* The name and the value are what get copied, so they share the width between them. */
/* No fixed widths: the browser sizes the name and value columns to what they hold, which is what
   keeps a DKIM key and its value on one line each at an ordinary laptop width. */
.records td:first-child { width: 1%; white-space: nowrap; }
.rhead { display: grid; justify-items: start; gap: 6px; }
.rhead__opt { font: 400 0.6875rem/1 var(--sans); color: var(--faint); }

.dnsshared { display: grid; gap: 16px; padding-block: 40px 64px; }
.dnsshared h1 { margin: 0; }

/* ---------------------------------------------------------------- the records table, dressed

   What a customer copies, laid out so it is obvious what to copy. The name and the value sit in
   soft chips with the copy control inside them, so the button belongs to the thing it copies
   rather than floating beside it. */
.records td { padding: 14px 12px 14px 0; vertical-align: top; }
.records tbody tr { transition: background 120ms ease; }
.records tbody tr:hover { background: color-mix(in srgb, var(--surface-2) 70%, transparent); }

.rtype {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 6px;
  font: 700 0.6875rem/1.2 var(--mono);
  letter-spacing: 0.04em;
  color: var(--type-color);
  background: color-mix(in srgb, var(--type-color) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--type-color) 28%, transparent);
}
.rtype--cname { --type-color: var(--type-cname); }
.rtype--mx { --type-color: var(--type-mx); }
.rtype--txt { --type-color: var(--type-txt); }

.rchip {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 5px 5px 5px 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.rchip__text { flex: 1 1 auto; min-width: 0; overflow-wrap: break-word; font: 500 0.78125rem/1.5 var(--mono); color: var(--ink); }
.rchip--value .rchip__text { font-weight: 400; color: var(--ink-soft); }
.rchip + .records__meta { margin-top: 6px; }
.records__meta { display: block; font-size: 0.75rem; color: var(--faint); }

/* The copy control: an icon, tinted in the accent, that becomes a tick for a moment when it has
   done its job. The words are still there for a screen reader, which is told "Copied". */
.copyicon {
  flex: none;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: var(--accent-soft);
  color: var(--accent);
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease, transform 120ms ease;
}
.copyicon:hover { background: var(--accent); color: var(--accent-ink); }
.copyicon:active { transform: scale(0.94); }
.copyicon:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.copyicon svg { width: 15px; height: 15px; grid-area: 1 / 1; }
.copyicon__done { opacity: 0; transform: scale(0.6); transition: opacity 120ms ease, transform 160ms ease; }
.copyicon[data-copied="true"] { background: var(--ok-soft); color: var(--ok); }
.copyicon[data-copied="true"] .copyicon__copy { opacity: 0; }
.copyicon[data-copied="true"] .copyicon__done { opacity: 1; transform: scale(1); }
.copyicon[data-copied="false"] { background: var(--bad-soft); color: var(--bad); }

/* The one mistake the page can name, said as a callout rather than as red text in a column. */
.records__fix {
  display: flex;
  gap: 10px;
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--bad) 30%, transparent);
  border-left: 3px solid var(--bad);
  background: var(--bad-soft);
  color: var(--ink);
  font: 400 0.8125rem/1.5 var(--sans);
}
.records__fix svg { flex: none; width: 16px; height: 16px; margin-top: 2px; color: var(--bad); }
.records__fix code { background: var(--surface); padding: 1px 6px; border-radius: 4px; font-weight: 600; }

.records__why { margin-top: 14px; font-size: 0.8125rem; color: var(--muted); }
.records__why summary { cursor: pointer; width: fit-content; color: var(--ink-soft); font-weight: 500; }
.records__why summary:hover { color: var(--accent); }
.records__why dl { display: grid; grid-template-columns: max-content 1fr; gap: 8px 14px; margin: 12px 0 0; }
.records__why dt { display: flex; align-items: center; gap: 8px; font-family: var(--mono); color: var(--ink); }
.records__why dd { margin: 0; }
@media (max-width: 640px) { .records__why dl { grid-template-columns: 1fr; } .records__why dd { margin-bottom: 6px; } }

/* ---------------------------------------------------------------- the approval bar

   A step to take, not a fault, so it is quiet: a slim line with a pulsing amber dot and the one
   action, rather than a block of warning colour above every page. */
.approvalbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
  padding: 10px 10px 10px 16px;
  border: 1px solid color-mix(in srgb, var(--warn) 26%, var(--line));
  border-radius: 999px;
  background: color-mix(in srgb, var(--warn-soft) 60%, var(--surface));
  font-size: 0.875rem;
  color: var(--ink-soft);
}
.approvalbar__dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--warn-mark);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--warn-mark) 22%, transparent);
}
.approvalbar__text { flex: 1 1 auto; min-width: 0; }
.approvalbar__text strong { color: var(--ink); font-weight: 600; }
.approvalbar .btn { flex: none; border-radius: 999px; }
@media (max-width: 640px) {
  .approvalbar { flex-wrap: wrap; border-radius: var(--radius); }
  .approvalbar .btn { width: 100%; justify-content: center; }
}
