/* The billing panel's look (RM-012): the tokens are billing's own, read from
   website/static/css/site.css, which the billing portal and the billing staff
   panel both wear. A test compares them, so a drift is a failure rather than a
   thing somebody notices a month later.

   The class names are this service's and have not moved: the look follows
   billing through the tokens and the shell's proportions, not by renaming
   everything the templates say. The first attempt at this renamed them and left
   twenty templates speaking a vocabulary nothing styled.

   Colour only through the tokens, never a literal: a literal is how dark green
   ended up on dark green in the Dashmox panel. Two greens: --accent is a fill
   white text sits on, --accent-text is green text on a surface. 12px is the
   floor. Light only, because billing is light only; a dark theme here would be
   this service's own idea rather than the look it follows. */
:root {
  font-family: Inter, "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --text-xs: 12px; --text-sm: 13px; --text-base: 14px; --text-md: 15px; --text-lg: 20px;
  /* Billing's, name for name where it has the name. */
  --bg: #fbfcfa;
  --surface: #ffffff;
  --tint: #f3f7f2;
  --ink: #15251d;
  --ink-2: #4c5b53;
  --line: #e1e8e2;
  --line-strong: #c9d5cc;
  --accent: #277953;
  --accent-hover: #1f6544;
  --accent-text: #1f6544;
  --accent-soft: #e2efe6;
  --lime: #c1dca4;
  --lime-soft: #eef6e3;
  --warn: #6f5812;
  --warn-soft: #f7efdc;
  --terminal: #101915;
  --radius: 18px;
  --radius-sm: 11px;
  /* What this service's own rules call them. One name per thing, pointing at
     billing's value, so a rule written against the old vocabulary still reads
     correctly and a token change happens in one place. */
  --panel: var(--surface);
  --text: var(--ink);
  --muted: var(--ink-2);
  --soft: var(--accent-soft);
  --input: var(--surface);
  --on-accent: #ffffff;
  --success: #2f6b46;
  --danger: #9b3b31;
  --danger-soft: #fbeae7;
  --warning: var(--warn);
  --shadow: 0 12px 32px -20px rgba(20, 58, 38, 0.28);
  /* The rail, which is billing's --terminal in both of its panels. */
  --brand: var(--terminal);
  --on-brand: #d8e3dc;
  --on-brand-strong: #ffffff;
  --on-brand-muted: #93a79b;
  --brand-highlight: var(--lime);
  --on-brand-highlight: #243c2d;
  /* Derived, so they follow the tokens rather than being a second set to keep
     in step. The three the contrast test recomputes are these. */
  --rail-hover: color-mix(in srgb, #d8e3dc 9%, #101915);
  --rail-line: color-mix(in srgb, #d8e3dc 16%, #101915);
  --line-strong-mix: color-mix(in srgb, var(--ink-2) 35%, var(--line));
  --scrim: color-mix(in srgb, var(--terminal) 55%, transparent);
  --row-hover: color-mix(in srgb, var(--tint) 60%, var(--surface));
  --rail-w: 248px;
  color-scheme: light;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--text); font-size: var(--text-base); line-height: 1.55; }
a { color: var(--accent-text); text-underline-offset: 2px; }
h1, h2, h3 { margin: 0; text-wrap: balance; }
h1 { font-size: var(--text-lg); font-weight: 650; line-height: 1.3; }
h2 { font-size: var(--text-md); font-weight: 650; }
h3 { font-size: var(--text-xs); font-weight: 650; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
p { margin: 0; }
code { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: .92em; background: var(--soft); color: var(--text); padding: 1px 4px; border-radius: 4px; overflow-wrap: anywhere; }
pre { overflow-x: auto; background: var(--soft); padding: 10px 12px; border-radius: 6px; font-size: var(--text-sm); }
pre code { padding: 0; background: none; }
button, input, select, textarea { font: inherit; color: inherit; }
/* The browser's own blue on a tick or a radio was the one colour on these
   pages not from the tokens. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }

/* The rail */
.menu-toggle { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.rail { position: fixed; top: 0; bottom: 0; left: 0; width: var(--rail-w); background: var(--brand); color: var(--on-brand);
  display: flex; flex-direction: column; gap: 18px; overflow-y: auto; z-index: 30; padding: 18px 12px 12px; }
.brand { display: flex; align-items: center; gap: 10px; padding: 0 8px; color: var(--on-brand); text-decoration: none; }
.brand-mark { width: 30px; height: 30px; border-radius: 8px; background: var(--brand-highlight); color: var(--on-brand-highlight);
  display: grid; place-items: center; font-weight: 700; font-size: var(--text-md); flex: none; }
.brand-words, .viewer-words { display: flex; flex-direction: column; min-width: 0; }
.brand-name { font-weight: 650; font-size: var(--text-md); color: var(--on-brand-strong); line-height: 1.2; }
.brand-sub { font-size: var(--text-xs); color: var(--on-brand-muted); }
.nav-group { display: flex; flex-direction: column; gap: 2px; }
.nav-caption { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .08em; color: var(--on-brand-muted); padding: 0 10px 4px; font-weight: 600; }
.nav-link { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: 7px; color: var(--on-brand); text-decoration: none; }
.nav-link:hover { background: var(--rail-hover); }
.nav-link[aria-current="page"] { background: var(--brand-highlight); color: var(--on-brand-highlight); font-weight: 600; }
.nav-link .count { margin-left: auto; font-size: var(--text-xs); color: var(--on-brand-muted); font-variant-numeric: tabular-nums; }
.nav-link[aria-current="page"] .count { color: var(--on-brand-highlight); }
.viewer { margin-top: auto; border-top: 1px solid var(--rail-line); padding: 12px 8px 0; display: flex; align-items: center; gap: 10px; color: var(--on-brand); text-decoration: none; min-width: 0; }
.avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--rail-line); color: var(--on-brand-strong); display: grid; place-items: center; font-weight: 600; font-size: var(--text-sm); flex: none; }
.viewer-name { font-weight: 600; font-size: var(--text-sm); color: var(--on-brand-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.viewer-sub { font-size: var(--text-xs); color: var(--on-brand-muted); }
.scrim { display: none; }

/* The top bar and the page */
.main { margin-left: var(--rail-w); min-width: 0; }
.topbar { position: sticky; top: 0; z-index: 20; background: var(--panel); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 14px; padding: 10px 28px; min-height: 56px; }
.menu-btn { display: none; align-items: center; gap: 6px; border: 1px solid var(--line-strong); border-radius: 7px; padding: 6px 10px; cursor: pointer; font-size: var(--text-sm); font-weight: 600; flex: none; background: var(--panel); }
.menu-btn svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.menu-toggle:focus-visible ~ .main .menu-btn { outline: 2px solid var(--accent); outline-offset: 2px; }
.crumbs { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1 1 auto; font-size: var(--text-sm); color: var(--muted); }
.crumbs a { color: var(--muted); text-decoration: none; white-space: nowrap; }
.crumbs a:hover { color: var(--text); text-decoration: underline; }
.crumbs .here { color: var(--text); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.search { flex: 0 1 280px; min-width: 0; }
.search input { width: 100%; background: var(--input); border: 1px solid var(--line-strong); border-radius: 8px; padding: 7px 10px; font-size: var(--text-sm); }
.actions { display: flex; gap: 8px; align-items: center; flex: none; }
.actions form { margin: 0; }
.content { padding: 26px 28px 56px; max-width: 1120px; display: flex; flex-direction: column; gap: 20px; }
.bare { max-width: 460px; margin: 0 auto; padding: 48px 16px; display: flex; flex-direction: column; gap: 18px; }
.bare-brand { display: flex; align-items: center; gap: 10px; color: var(--text); }

/* Pieces */
.btn { display: inline-flex; align-items: center; gap: 6px; border-radius: 7px; padding: 7px 13px; font-size: var(--text-sm); font-weight: 600; cursor: pointer; text-decoration: none; border: 1px solid transparent; line-height: 1.3; white-space: nowrap; }
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: color-mix(in srgb, var(--accent) 88%, var(--text)); }
.btn-quiet { background: var(--panel); color: var(--text); border-color: var(--line-strong); }
.btn-quiet:hover { background: var(--soft); }
.btn-danger { background: var(--panel); color: var(--danger); border-color: var(--danger); }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow); min-width: 0; }
.card-pad { padding: 18px 20px; }
.narrow { max-width: 460px; }
.stack { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.page-head { display: flex; flex-direction: column; gap: 6px; }
.page-head p { color: var(--muted); max-width: 72ch; }
.muted { color: var(--muted); }
.small { font-size: var(--text-sm); }
.xs { font-size: var(--text-xs); }
.nowrap { white-space: nowrap; }
.footnote { max-width: 80ch; }
.notice { background: var(--soft); border: 1px solid var(--line); border-radius: 10px; padding: 10px 14px; font-size: var(--text-sm); max-width: 80ch; }
.warning { border: 1px solid var(--warning); border-radius: 10px; padding: 10px 14px; font-size: var(--text-sm); max-width: 80ch; }
.warning strong { color: var(--warning); }
.problem { border: 1px solid var(--danger); color: var(--danger); border-radius: 8px; padding: 9px 12px; font-size: var(--text-sm); }
.secret code { display: block; padding: 10px 12px; font-size: var(--text-sm); user-select: all; }
.empty { padding: 26px 20px; display: flex; flex-direction: column; gap: 8px; color: var(--muted); }
.empty strong { color: var(--text); font-size: var(--text-md); }
.strong-link { font-weight: 600; color: var(--text); text-decoration: none; }
.strong-link:hover { text-decoration: underline; }

/* Forms */
.field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.field.end { justify-content: flex-end; }
label { font-size: var(--text-sm); font-weight: 500; }
.hint { font-size: var(--text-xs); color: var(--muted); font-weight: 400; }
input[type="text"], input:not([type]), input[type="email"], input[type="password"], input[type="search"], select, textarea {
  background: var(--input); border: 1px solid var(--line-strong); border-radius: 7px; padding: 7px 10px; font-size: var(--text-sm); max-width: 100%; }
input[type="email"], input[type="password"], input:not([type]) { width: 100%; }
textarea { width: 100%; min-height: 78px; resize: vertical; line-height: 1.5; }
select { max-width: 100%; }
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; align-items: start; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.grid-3 .wide { grid-column: 1 / -1; }
.inline-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0; }
.checks { display: flex; flex-wrap: wrap; gap: 8px 16px; }
.checks label, .check { display: inline-flex; gap: 6px; align-items: center; font-weight: 400; }
.states { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.state-choice { display: flex; gap: 8px; align-items: flex-start; font-weight: 400; }
.state-choice input { margin-top: 4px; }
.enrol { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.qr { width: 200px; height: 200px; max-width: 100%; border-radius: 8px; border: 1px solid var(--line); }
.secret-key { font-size: var(--text-md); letter-spacing: .04em; }
.codes { columns: 2; padding-left: 22px; margin: 0; }
.codes li { margin-bottom: 6px; }

/* Tables */
.table-wrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: var(--text-sm); }
th { text-align: left; font-weight: 600; color: var(--muted); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .06em; padding: 10px 14px; border-bottom: 1px solid var(--line); white-space: nowrap; }
td { padding: 10px 14px; border-bottom: 1px solid var(--line); vertical-align: top; }
tr:last-child td { border-bottom: none; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.row-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.row-actions form { margin: 0; }

/* Chips, pills and tags */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip { border: 1px solid var(--line-strong); background: var(--panel); color: var(--text); border-radius: 999px; padding: 4px 11px; font-size: var(--text-sm); text-decoration: none; display: inline-flex; gap: 6px; align-items: center; }
.chip .n { color: var(--muted); font-size: var(--text-xs); font-variant-numeric: tabular-nums; }
.chip[aria-current="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.chip[aria-current="true"] .n { color: var(--on-accent); }
.pill { display: inline-flex; align-items: center; gap: 5px; border-radius: 999px; padding: 1px 9px; font-size: var(--text-xs); font-weight: 600; white-space: nowrap; border: 1px solid currentColor; line-height: 1.6; flex: none; }
.pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.st-open { color: var(--muted); }
.st-progress { color: var(--accent-text); background: var(--soft); border-color: transparent; }
.st-blocked { color: var(--danger); }
.st-held { color: var(--muted); border-style: dashed; }
.st-held::before { background: transparent; border: 1px solid currentColor; }
.st-done { color: var(--success); }
.rs-new { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.rs-confirmed { color: var(--danger); }
.rs-not_reproduced { color: var(--muted); border-style: dashed; }
.rs-known { color: var(--accent-text); background: var(--soft); border-color: transparent; }
.rs-fixed { color: var(--success); }
.rs-declined { color: var(--muted); }
.tag { display: inline-flex; align-items: center; gap: 5px; border-radius: 5px; padding: 0 6px; font-size: var(--text-xs); font-weight: 500; background: var(--soft); color: var(--text); white-space: nowrap; line-height: 1.7; text-decoration: none; }
.tag-dec { color: var(--accent-text); }
.tag-warn { color: var(--warning); background: var(--panel); border: 1px solid currentColor; }
/* The good news version of the same tag: released, shipped, in a release. */
.tag-good { color: var(--accent-text); background: var(--panel); border: 1px solid currentColor; }

/* Lists of items and groups */
.repo-block { display: flex; flex-direction: column; gap: 16px; }
.repo-title { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; border-bottom: 1px solid var(--line); padding-bottom: 8px; }
.repo-title a { color: var(--text); text-decoration: none; }
.section { display: flex; flex-direction: column; gap: 8px; }
.section h3 .n { color: var(--muted); font-weight: 500; letter-spacing: 0; }
.list { display: flex; flex-direction: column; }
.row { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; padding: 12px 16px; color: var(--text); text-decoration: none; align-items: start; }
.row + .row { border-top: 1px solid var(--line); }
.row:hover { background: var(--row-hover); }
.row .pill { margin-top: 2px; }
.row-title { font-weight: 550; min-width: 0; overflow-wrap: anywhere; }
.row-title strong { font-weight: 650; }
.row-meta { grid-column: 2; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: var(--text-xs); color: var(--muted); }

/* An item */
.prose { max-width: 78ch; overflow-wrap: break-word; }
.prose p { margin: 0 0 10px; }
.prose p:last-child { margin-bottom: 0; }
.prose ul { margin: 0 0 10px; padding-left: 20px; }
.prose li + li { margin-top: 4px; }
.prose blockquote { margin: 0 0 10px; padding: 6px 12px; border-left: 3px solid var(--line-strong); background: var(--soft); border-radius: 0 6px 6px 0; }
.dangling { text-decoration: underline wavy var(--warning); text-underline-offset: 3px; cursor: help; }
.facts { display: grid; grid-template-columns: max-content 1fr; gap: 8px 16px; margin: 0; font-size: var(--text-sm); }
.facts dt { color: var(--muted); }
.facts dd { margin: 0; min-width: 0; }
.decisions { display: flex; flex-direction: column; gap: 4px; }

/* The desk */
.detail { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 20px; align-items: start; }
.panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
.panel-body { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; }
.report { padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.report + .report { border-top: 1px solid var(--line); }
.report-text { padding: 8px 12px; border-left: 3px solid var(--accent); background: var(--soft); border-radius: 0 6px 6px 0; font-size: var(--text-md); white-space: pre-wrap; overflow-wrap: anywhere; }
.ctx { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: var(--text-xs); color: var(--muted); }
.ctx b { color: var(--text); font-weight: 600; }
.error-text { font-size: var(--text-sm); }
.activity summary { cursor: pointer; font-size: var(--text-xs); color: var(--muted); }
.activity ul { margin: 6px 0 0; padding-left: 18px; font-size: var(--text-sm); }
.note-row { display: flex; flex-direction: column; gap: 3px; }
.note-row p { white-space: pre-wrap; overflow-wrap: anywhere; max-width: 76ch; }
.suggest-row { display: flex; gap: 10px; align-items: center; justify-content: space-between; flex-wrap: wrap; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; }

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

/* Phones: the rail slides off behind a menu button. Nothing is fixed over the
   top bar, so the button can always be reached, and Sign out is in the top bar
   rather than behind the rail, where a tester on a phone never found it. */
@media (max-width: 639px) {
  .rail { transform: translateX(-100%); transition: transform .2s ease; }
  .menu-toggle:checked ~ .rail { transform: none; }
  .menu-toggle:checked ~ .scrim { display: block; position: fixed; inset: 0; background: var(--scrim); z-index: 25; }
  .main { margin-left: 0; }
  .menu-btn { display: inline-flex; }
  .topbar { flex-wrap: wrap; padding: 8px 16px; gap: 8px 10px; }
  .crumbs { flex: 1 1 0; }
  .search { order: 3; flex: 1 1 100%; }
  .content { padding: 16px 16px 48px; gap: 16px; }
  .row { padding: 12px 14px; }
  .facts { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .facts dd { margin-bottom: 8px; }
  .codes { columns: 1; }
}

/* The planning board. Columns scroll sideways as a set rather than the page
   doing it, so a phone shows one column at a time and the top bar, which holds
   sign out, stays where it is. */
.board { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 10px; align-items: flex-start; }
.column {
  flex: 0 0 300px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px;
  min-height: 110px;
}
.column.over { border-color: var(--accent); background: var(--soft); }
.column-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
.column-head h2 { flex: 1; min-width: 0; font-size: var(--text-base); }
.column-head .count { font-family: ui-monospace, Consolas, monospace; font-size: var(--text-xs); color: var(--muted); }
.column-foot { margin-top: 8px; }
.card-item {
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line);
  border-radius: 7px;
  padding: 9px 11px;
  margin-bottom: 7px;
}
.card-item.dragging { opacity: .45; }
.card-item.drop-above { border-top: 3px solid var(--accent); }
.card-item.k-bug { border-left-color: var(--danger); }
.card-item.k-idea { border-left-color: var(--accent); }
.card-item.k-chore { border-left-color: var(--line-strong); }
.card-item .title { display: block; color: var(--text); font-weight: 600; text-decoration: none; font-size: var(--text-base); }
.card-item .title:hover { color: var(--accent-text); }
.card-item .meta { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; align-items: center; }
.card-item form { margin: 7px 0 0; display: flex; gap: 6px; align-items: center; }
.card-item select { min-height: 34px; font-size: var(--text-sm); padding: 5px 7px; }
.grip { cursor: grab; color: var(--muted); font-size: var(--text-sm); user-select: none; }
.grip:active { cursor: grabbing; }
/* Dragging is the quick way and never the only way: a board that can only be
   dragged cannot be driven on a phone or from a keyboard. */
.move-form { margin-top: 8px; }

/* ---------------------------------------------------------------------------
   The tester front door (RM-026).

   Who meets it: a customer helping us test, arriving from the billing portal,
   often on a phone. So it wears what the rest of Dashmox wears, the real mark
   and billing's tokens, and it is built for a thumb before a mouse.

   Three rules hold the rest of this section together:

   - Colour only through the tokens, and only in pairings contrast_test.go
     names. A literal is how dark green ended up on dark green in the panel.
   - Decoration may sit on a mixed surface; text may not. The glow behind the
     logo and the ring behind a percentage hold no words.
   - No script. The ring is a conic gradient from one number, the tabs are
     links, the file picker is a label. Nothing here waits on JavaScript, which
     also means nothing here breaks when it is blocked.
   --------------------------------------------------------------------------- */
body.front { background: var(--bg); }
/* `panel` is what these templates have always called a box, and no rule ever
   drew one: the tester pages were unstyled blocks on the page background from
   the day they were written. It is the staff side's card with its padding, so
   both halves of the service look like one product. */
.front .panel { background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 18px 20px; min-width: 0; }
.front .panel-head { padding: 0 0 12px; margin-bottom: 4px; }
.front .panel h3 { margin-top: 16px; }
.front .prose { margin-top: 10px; }
.front .field + .field, .front .field + .footnote { margin-top: 14px; }
.front .footnote { margin-top: 14px; }
.front .i { width: 1.05em; height: 1.05em; flex: 0 0 auto; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: 12px; top: 12px; z-index: 10; background: var(--panel); color: var(--accent-text);
  padding: 10px 14px; border-radius: var(--radius-sm); }

/* The bar. It stays while the page scrolls, because what somebody does after
   reading the roadmap is send us something. */
.front-top { position: sticky; top: 0; z-index: 5; background: var(--brand); color: var(--on-brand);
  box-shadow: 0 10px 30px -24px rgba(16, 25, 21, 0.9); }
.front-top .inner, .front-tabs .inner, .front-main, .front-foot .inner {
  max-width: 940px; margin: 0 auto; padding-left: 20px; padding-right: 20px; }
.front-top .inner { display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding-top: 12px; padding-bottom: 12px; }
.front-top a { color: var(--on-brand); text-decoration: none; }
.brand { display: flex; align-items: center; gap: 11px; min-width: 0; }
.brand .mark { width: 38px; height: 38px; flex: 0 0 auto; }
.brand-words { display: flex; flex-direction: column; line-height: 1.1; min-width: 0; }
.wordmark { font-size: 23px; font-weight: 760; letter-spacing: -0.06em; color: var(--on-brand-strong); }
.wordmark span { color: var(--brand-highlight); }
.brand-sub { font-size: var(--text-xs); color: var(--on-brand-muted); letter-spacing: .02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.front-who { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.front-who form { margin: 0; }
.front-top .who-pill { background: var(--brand-highlight); color: var(--on-brand-highlight); }
.btn-ghost { background: none; border: 1px solid var(--on-brand-muted); color: var(--on-brand); }
.btn-ghost:hover { border-color: var(--on-brand-strong); color: var(--on-brand-strong); }

/* Four tabs, with their icons, scrolling sideways on a narrow screen rather
   than wrapping into a second row that pushes the page down. */
.front-tabs { background: var(--brand); border-top: 1px solid var(--rail-line); }
.front-tabs .inner { display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; }
.front-tabs .inner::-webkit-scrollbar { display: none; }
.front-tabs a { display: flex; align-items: center; gap: 7px; padding: 11px 13px; white-space: nowrap;
  font-size: var(--text-sm); font-weight: 600; color: var(--on-brand);
  border-bottom: 2px solid transparent; }
.front-tabs a:hover { color: var(--on-brand-strong); }
.front-tabs a[aria-current] { color: var(--on-brand-strong); border-bottom-color: var(--brand-highlight); }
.front-tabs .i { width: 1.15em; height: 1.15em; }

.front-main { padding: 24px 20px 56px; display: flex; flex-direction: column; gap: 16px; }
.front .filter-tabs { display: flex; flex-wrap: wrap; gap: 6px; }
.front .filter-tabs a { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px;
  border-radius: 999px; border: 1px solid var(--line); background: var(--panel);
  color: var(--muted); text-decoration: none; font-size: var(--text-sm); font-weight: 600; }
.front .filter-tabs a:hover { border-color: var(--line-strong); color: var(--text); }
.front .filter-tabs a[aria-current] { background: var(--soft); border-color: var(--accent);
  color: var(--accent-text); }
.front .filter-tabs .n { font-variant-numeric: tabular-nums; opacity: .75; }

/* The hero. A heading with its icon and one line under it; the welcome's is the
   big one, with the mark and a glow behind it that no text sits on. */
.hero { padding: 6px 2px 2px; }
.hero h1 { display: flex; align-items: center; gap: 10px; font-size: 27px; letter-spacing: -0.02em; }
.hero h1 .i { width: 26px; height: 26px; color: var(--accent-text); }
.hero-lede { color: var(--muted); max-width: 64ch; margin-top: 6px; }
/* Centred text in a box that is not centred reads as left aligned and
   slightly wrong, which is exactly what it is. */
.welcome-hero .hero-lede { margin-left: auto; margin-right: auto; }
.welcome-hero { position: relative; text-align: center; padding: 26px 18px 8px; }
.welcome-hero h1 { justify-content: center; font-size: 31px; }
.hero-mark { width: 96px; height: 96px; padding: 12px; border-radius: 50%; background: var(--lime-soft); }
.hero-badge { display: inline-flex; align-items: center; gap: 8px; margin-top: 12px; padding: 6px 13px;
  border-radius: 999px; background: var(--soft); color: var(--accent-text); font-size: var(--text-sm); }

.who-pill { display: inline-flex; align-items: center; gap: 6px; background: var(--soft);
  color: var(--accent-text); border-radius: 999px; padding: 4px 12px; font-weight: 600;
  font-size: var(--text-sm); }

/* A point: an icon in a tinted circle, a heading, a line. Used by the welcome
   and wherever a page explains itself. */
.point { display: flex; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--line); }
.point:last-of-type { border-bottom: 0; }
.point h2 { font-size: var(--text-md); margin-bottom: 3px; }
.point p { color: var(--muted); font-size: var(--text-sm); }
.point-mark { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 42px; height: 42px; border-radius: 50%; background: var(--soft); color: var(--accent-text); }
.point-mark .i { width: 21px; height: 21px; }
.sent-mark .i, .kind-mark .i { width: 20px; height: 20px; }
.try-mark .i { width: 17px; height: 17px; }
.point-mark.warn { background: var(--warn-soft); color: var(--warning); }
.welcome-points .actions { justify-content: center; margin-top: 18px; }
.btn-big { padding: 12px 22px; font-size: var(--text-md); }

/* A version, with a band of colour down its side saying where it is. */
.versions { display: flex; flex-direction: column; gap: 14px; }
/* Scoped the same way the card is, or the card's own border wins by having
   two classes to this one's one and the band never appears. */
.front .panel.version { border-left: 4px solid var(--line-strong); }
.front .version.v-building, .front .version.v-progress { border-left-color: var(--accent); }
.front .version.v-released, .front .version.v-done { border-left-color: var(--success); }
.front .version.v-planned { border-left-color: var(--lime); }
.version-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.version-head h2 { font-size: 21px; letter-spacing: -0.02em; }
.version-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 7px; }
.count-chip { flex: 0 0 auto; background: var(--tint); color: var(--muted); border-radius: 999px;
  padding: 5px 12px; font-size: var(--text-xs); font-weight: 600; }
/* No markers does not mean no indent: a list keeps the browser's 40px
   until it is told otherwise, and it read as a stray margin. */
.ticks, .steps { list-style: none; padding-left: 0; margin: 0; }
.ticks { display: grid; gap: 7px; margin-top: 8px; }
.ticks li { display: flex; gap: 9px; align-items: flex-start; font-size: var(--text-sm); }
.ticks .i { color: var(--accent-text); margin-top: 2px; }
.faults .i { color: var(--warning); }
/* A line a tester sent us, on the page where they read what is coming. The
   glow is the point of the page for anybody who has sent something: finding
   your own without reading every line. Tinted surface, never a mixed one under
   text: the words stay on --soft, which is a pairing the contrast test holds. */
.ticks li.mine { background: var(--soft); border: 1px solid var(--accent);
  border-radius: var(--radius-sm); padding: 7px 11px; margin: -1px 0;
  box-shadow: 0 0 0 4px var(--lime-soft); }
.ticks li.mine .i { color: var(--accent-text); }
.yours { display: inline-flex; align-items: center; gap: 5px; margin-left: auto;
  color: var(--accent-text); font-size: var(--text-xs); font-weight: 650; white-space: nowrap; }
.yours .i { width: 13px; height: 13px; }
@media (min-width: 720px) { .ticks { grid-template-columns: 1fr 1fr; } }

.invite { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.invite h2 { font-size: var(--text-md); }
.invite .btn { margin-left: auto; }

/* Three numbers about what somebody has sent us. */
.stat-strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.stat-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 13px 15px; display: flex; flex-direction: column; gap: 3px; }
.stat-card.good .stat-n { color: var(--accent-text); }
.stat-n { font-size: 26px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.stat-l { display: flex; align-items: center; gap: 6px; font-size: var(--text-xs); color: var(--muted); }

.sent-list { display: flex; flex-direction: column; gap: 12px; }
.sent { display: flex; gap: 14px; align-items: flex-start; }
.sent-mark { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 50%; background: var(--tint); color: var(--muted); }
.sent.k-bug .sent-mark { background: var(--danger-soft); color: var(--danger); }
.sent.k-idea .sent-mark { background: var(--soft); color: var(--accent-text); }
.sent-body { min-width: 0; }
.sent h2 { font-size: var(--text-md); }
.sent-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 7px; }
.sent-note { margin-top: 8px; font-size: var(--text-sm); color: var(--muted);
  border-left: 2px solid var(--line-strong); padding-left: 10px; }

/* A catalogue, with a ring for how much of it is answered. The ring is one
   conic gradient driven by --answered; no text sits on it. */
.cat-head { display: flex; gap: 16px; align-items: flex-start; }
.ring { flex: 0 0 auto; width: 74px; height: 74px; border-radius: 50%; display: grid; place-items: center;
  background: conic-gradient(var(--accent) calc(var(--answered) * 1%), var(--tint) 0); }
/* One line: a grid made the per cent sign a row of its own under the number. */
.ring span { display: flex; align-items: baseline; justify-content: center; width: 58px; height: 58px;
  border-radius: 50%; background: var(--panel); font-weight: 700; font-variant-numeric: tabular-nums; }
.ring small { font-size: var(--text-xs); font-weight: 600; color: var(--muted); }
.cat-words { min-width: 0; }
.cat-words h2 { font-size: var(--text-lg); }
.cat-meta { display: flex; flex-wrap: wrap; gap: 6px; margin: 7px 0; }
.cat-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 14px;
  padding-top: 14px; border-top: 1px solid var(--line); }
.cat-actions form { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 0; }
.file-field { display: inline-flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.file-label { display: inline-flex; align-items: center; gap: 7px; font-size: var(--text-sm);
  font-weight: 600; color: var(--muted); }
.file-field input[type=file] { font-size: var(--text-sm); max-width: 100%; }

.tries { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.try { display: flex; gap: 12px; padding: 12px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--bg); }
.try.passed { border-color: var(--accent); }
.try-mark { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 32px; height: 32px; border-radius: 50%; background: var(--soft); color: var(--accent-text); }
.try.needs-work .try-mark { background: var(--warn-soft); color: var(--warning); }
.try-head, .try-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.try-meta { margin-top: 6px; }

.steps { display: flex; flex-direction: column; gap: 11px; }
.steps li { display: flex; gap: 12px; align-items: flex-start; font-size: var(--text-sm); }
.step-n { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 24px; height: 24px; border-radius: 50%; background: var(--soft); color: var(--accent-text);
  font-size: var(--text-xs); font-weight: 700; }
.how h2 { display: flex; align-items: center; gap: 8px; }

/* Two cards instead of a dropdown, because this choice decides how the rest of
   the form reads and a closed menu hides half of it behind a tap. */
.kind-choice { border: 0; padding: 0; margin-bottom: 16px; }
.kind-choice legend { font-weight: 600; font-size: var(--text-sm); margin-bottom: 8px; }
.kind-card { display: flex; align-items: center; gap: 12px; padding: 13px 15px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--panel); }
.kind-card + .kind-card { margin-top: 9px; }
.kind-card:hover { border-color: var(--line-strong); }
.kind-card:has(input:checked) { border-color: var(--accent); background: var(--soft); }
.kind-card input { accent-color: var(--accent); width: 18px; height: 18px; flex: 0 0 auto; }
.kind-mark { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 36px; height: 36px; border-radius: 50%; background: var(--tint); color: var(--muted); }
.kind-card:has(input:checked) .kind-mark { background: var(--panel); color: var(--accent-text); }
.kind-words { display: flex; flex-direction: column; line-height: 1.3; }
.kind-words span { font-size: var(--text-sm); color: var(--muted); }
@media (min-width: 620px) {
  .kind-choice { display: flex; gap: 10px; }
  .kind-choice legend { flex-basis: 100%; }
  .kind-card { flex: 1 1 0; }
  .kind-card + .kind-card { margin-top: 0; }
}

.refusal { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 10px; }
/* These hold one icon and one span. A flex container makes every element
   inside it a column of its own, which is how the footer's name and the full
   stop after it ended up side by side. */
.front .notice, .front .problem { display: flex; align-items: center; gap: 9px; }
.footnote.with-mark { display: flex; gap: 9px; align-items: flex-start; }
.front .empty { align-items: center; text-align: center; }
.front .empty .i { width: 30px; height: 30px; color: var(--line-strong); }

.front-foot { border-top: 1px solid var(--line); padding: 20px 0 40px; color: var(--muted); }
.front-foot p { display: flex; gap: 9px; align-items: flex-start; justify-content: center;
  text-align: center; font-size: var(--text-sm); max-width: 70ch; margin-left: auto; margin-right: auto; }
.front-foot .i { color: var(--accent-text); margin-top: 2px; }
.front-foot .xs { font-size: var(--text-xs); margin-top: 8px; }
.front-foot { text-align: center; }

@media (max-width: 560px) {
  /* The bar has to fit a 360px phone, or the whole page scrolls sideways and
     every line of text looks cut off. The brand gives way first, then the
     sign-out button keeps its icon and loses its word. */
  .front-top .inner { gap: 8px; }
  .brand .mark { width: 32px; height: 32px; }
  .wordmark { font-size: 20px; }
  .brand-sub { display: none; }
  .front-who .btn span { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; }
  /* The label is hidden from the eye and not from a screen reader: an icon
     with no name is a button nobody blind can press. */
  .front-tabs a span { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap; }
  .front-tabs a { padding: 12px 16px; }
  .front-tabs .i { width: 1.4em; height: 1.4em; }
  .stat-strip { grid-template-columns: 1fr; }
  .hero h1 { font-size: 23px; }
  .invite .btn { margin-left: 0; }
}
@media (max-width: 860px) {
  .column { flex-basis: 84vw; }
}

/* What is coming: the plan down a line rather than across columns. Every colour
   is a token the rest of the sheet already uses, so the page belongs to the same
   site and a change to the theme reaches it.
   Named `tline`, because `.rail` in this sheet is the navigation. */
.tline { list-style: none; margin: 0; padding: 0 0 0 26px; position: relative; }
.tline::before {
  content: ""; position: absolute; left: 7px; top: 6px; bottom: 6px;
  width: 2px; background: var(--line-strong);
}
.tline-node { position: relative; margin: 0 0 22px; }
.tline-mark {
  position: absolute; left: -26px; top: 6px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--surface); border: 3px solid var(--accent);
}
/* A released version is filled in, so done is visible from the shape as well as
   from the words. */
.tline-node.shipped .tline-mark { background: var(--accent); }
.tline-body {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px 18px;
}
.tline-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.tline-head h2, .tline-head h3 { margin: 0; font-size: var(--text-lg); }
.tline-head h3 { font-size: var(--text-md); }
.tline-why { margin: 8px 0 0; color: var(--muted); font-size: var(--text-base); }
.tline-count { margin: 10px 0 0; font-size: var(--text-sm); color: var(--muted); }
.tline-bar {
  margin-top: 6px; height: 6px; border-radius: 999px;
  background: var(--tint); overflow: hidden;
}
.tline-bar span { display: block; height: 100%; background: var(--accent); }
.tline-group { margin-top: 14px; }
.tline-group h3, .tline-group h4 {
  margin: 0 0 6px; font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--muted);
}
.tline-items { list-style: none; margin: 0; padding: 0; }
.tline-items li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  padding: 7px 0 7px 11px; border-left: 3px solid var(--line-strong);
  border-bottom: 1px solid var(--line);
}
.tline-items li:last-child { border-bottom: 0; }
.tline-items li.k-bug { border-left-color: var(--warn); }
.tline-items li.k-idea { border-left-color: var(--lime); }
.tline-items li.k-chore { border-left-color: var(--line-strong); }
.tline-items li.is-done a { text-decoration: line-through; color: var(--muted); }
.tline-items a { color: var(--text); text-decoration: none; font-size: var(--text-base); }
.tline-items a:hover { text-decoration: underline; }
/* An update sits inside its major, indented, because that is what it is. */
.tline-update {
  margin-top: 16px; padding: 12px 14px;
  background: var(--tint); border-radius: var(--radius-sm);
}
.tline-backlog { margin-top: 10px; }
@media (max-width: 600px) {
  .tline { padding-left: 20px; }
  .tline-mark { left: -20px; width: 12px; height: 12px; border-width: 2px; }
}

/* Approving an item is the instruction to build it, so it is the loudest thing
   on the page without being a warning: the accent, not the danger colour. */
.panel.approve { border-color: var(--accent); }
.panel.approve .hint { margin: 0 0 12px; }
.approved { margin: 0 0 12px; color: var(--accent-text); }
.pill.approved {
  background: var(--accent-soft); color: var(--accent-text); margin: 0;
}

/* === The pass of 19 October ==================================================
   Four things the operator read off the live pages, and one bug behind two of
   them. Written at the end rather than edited in above so the reasoning for
   each stays with the rule, and because every token it uses is already declared
   at the top: this is weight and shape, not a second palette. */

/* --- A button that is a navigation link --------------------------------------
   "the see testers page button is like white an so is the text so when u redo
   the theme u should fix it."

   It was. `button, input, select, textarea { color: inherit }` near the top of
   this file hands a button in the rail the rail's own near-white text, and
   nothing anywhere handed it the rail's background, so it kept the browser's:
   #d8e3dc on ButtonFace. The rail has exactly one button, which is why exactly
   one thing was invisible.

   Seeing the tester pages has to be a button rather than a link, because it
   starts a session (preview.go). So a button that sits in a navigation group is
   told it is one, rather than left to the browser's idea of a button. */
.nav-group button.nav-link {
  background: none;
  border: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: var(--on-brand);
}
.nav-group button.nav-link:hover { background: var(--rail-hover); color: var(--on-brand-strong); }
.nav-form { margin: 0; }

/* --- The rail in sections ----------------------------------------------------
   "the nav needs to be organzied into sections so its easy to navigate."

   It had captions already and the sections were not the trouble: every
   repository sat in the same group as the plan, the timeline and the imports,
   so the one link somebody opens twenty times a day was ninth in a list of
   fourteen. The repositories are their own group and fold away, which is what
   `details` is for, and the groups are spaced so the captions read as headings
   rather than as small text above a list. */
.nav-group + .nav-group { margin-top: 14px; }
.nav-fold > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  list-style: none;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--on-brand-muted);
  padding: 0 10px 4px;
  font-weight: 600;
}
.nav-fold > summary::-webkit-details-marker { display: none; }
.nav-fold > summary::after {
  content: "";
  margin-left: auto;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform .12s;
}
.nav-fold[open] > summary::after { transform: rotate(45deg); }
.nav-fold > div { display: flex; flex-direction: column; gap: 2px; }
/* Billing's icon, name for name, so the two rails are the same object. 18px,
   stroked rather than filled, and never the thing that carries the meaning:
   every one of these sits beside its own word. */
.icon {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --- Tabs -------------------------------------------------------------------
   "some of the pages are huge need tabs."

   Spelled `filter-tabs`, which is what billing calls this strip, because a
   reader moving between the two services in one evening should not meet two
   words for one object. The current one is the tinted pill rather than the
   solid accent: a solid pill in a row of outlines reads as a button somebody
   should press, and this row says where you are.

   They are links, each to a page the server renders. No script decides what is
   shown, so a tab survives a reload, can be opened in another window, and is
   somewhere a link can point. */
.filter-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-tabs a {
  padding: 7px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--panel);
  color: var(--muted);
  font-size: var(--text-base);
  font-weight: 600;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.filter-tabs a:hover { color: var(--text); border-color: var(--line-strong-mix); }
.filter-tabs a[aria-current] { background: var(--soft); border-color: var(--accent); color: var(--accent-text); }
.filter-tabs .n { font-size: var(--text-xs); font-variant-numeric: tabular-nums; color: inherit; opacity: .8; }
@media (max-width: 834px) {
  /* A row of pill links is a row of targets, and forty tall is what both
     phone makers ask for. Billing's own rule, for the same reason. */
  .filter-tabs a { min-height: 40px; }
}

/* --- The board scrolls sideways ---------------------------------------------
   "should be able to scroll horizontally on the plan page."

   `.board` already said `overflow-x: auto` and it could never have worked. It
   is a flex item of `.content`, which is a column flex container, so its cross
   size is its width; `align-items: stretch` sets that to the container's width
   but cannot take it below the item's own min-content width, and min-width is
   `auto` by default. The min-content width of a row of six 300px columns is
   about 1900px, so `.board` was 1900px wide, had nothing to overflow, and
   pushed the document sideways instead. The sticky top bar slid away with it.

   `min-width: 0` is the whole fix: it lets the box be the width of the page,
   which gives its own overflow something to do.

   The page is also given the room. 1120px was set for prose, and five columns
   of cards is not prose; the staff panel in billing uses 1400 for its widest
   tables, and this takes the room it has. */
.board { min-width: 0; scrollbar-width: thin; overscroll-behavior-x: contain; }
.content.wide { max-width: 1480px; }
/* On a phone a column is nearly the whole width, so the scroll settles on one
   rather than between two. Proximity rather than mandatory: a half-swipe to
   read two columns' headings is a thing people do. */
@media (max-width: 760px) {
  .board { scroll-snap-type: x proximity; }
  .column { scroll-snap-align: start; flex-basis: 86%; }
}

/* --- Quick actions ----------------------------------------------------------
   "easier an quicker actions , quick actions etc", and then: "on The Plan page
   should be able to quickly drag those items betyween versions, quickly approve
   or remove".

   Approve is one click, because approving is the common act and it is
   reversible. Remove is a click to open and a click to do, because it is not:
   it sits in a `details` with its own confirmation field, which is the same
   field the item page sends. No typing either way.

   The row is also where the drag handle lives, and the Move select stays: the
   drag is the quick way and never the only one. A board that can only be
   dragged cannot be driven from a phone or a keyboard. */
.quick { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 7px; }
.quick form { margin: 0; }
.btn-small { padding: 4px 9px; font-size: var(--text-xs); }
.card-item .quick-remove { margin: 0; }
.card-item .quick-remove > summary {
  list-style: none;
  cursor: pointer;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--muted);
  padding: 4px 8px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
}
.card-item .quick-remove > summary::-webkit-details-marker { display: none; }
.card-item .quick-remove > summary:hover { color: var(--danger); border-color: var(--danger); }
.card-item .quick-remove[open] > summary { color: var(--danger); border-color: var(--danger); }
.card-item .quick-remove .why { font-size: var(--text-xs); color: var(--muted); margin: 6px 0 4px; }
/* The handle. It is the whole card that drags; this says so. */
.card-item .grip { margin-right: auto; }
.card-item[draggable="true"] { cursor: default; }

/* The drop target, which existed in this stylesheet before anything could
   drag: `.column.over`, `.card-item.dragging` and `.card-item.drop-above` were
   all written for a script that was never written. The board's own hint said
   "Drag a card" for six days over code that could not. They are kept as they
   were and board.js finally sets them. */
.board.dragging-now .column { transition: background .1s; }

/* --- A figure that leads ----------------------------------------------------
   Billing's staff panel puts its numbers on cards above the panels, and this
   had five columns of equal weight and no answer to "how much is there". The
   same card, from the same tokens. */
.stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.stat {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
}
.stat span { display: block; font-size: var(--text-sm); color: var(--muted); }
.stat strong { display: block; margin: 5px 0 1px; font-size: 1.7rem; letter-spacing: -.03em; }
.stat small { font-size: var(--text-xs); color: var(--muted); }
.stat a { color: var(--accent-text); }
@media (max-width: 1100px) { .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .stat-grid { grid-template-columns: 1fr; } }
