/*
 * BlckRhino Send — the platform's single stylesheet.
 *
 * Design language: "instrument of record". Send's product is delivery
 * assurance (docs/Send2.0_spec.md §3) — a signed, timestamped, independently
 * checkable record of what was delivered to whom. The interface therefore
 * reads like something that *keeps records*: hairline rules, a graphite
 * neutral ramp, tabular figures, monospace for every identifier a human might
 * have to reconcile by eye, and density appropriate to operational work.
 *
 * Consequences of that, stated so they are not "tidied" back in later:
 *   - No decorative gradients, blur, glow or grid overlays. Colour carries
 *     meaning here (status, interactivity) and nothing else, so decorative
 *     colour would dilute the only signal the operator has.
 *   - Borders establish structure, not shadows. One elevation step exists and
 *     it is reserved for content that genuinely floats above the page.
 *   - Radii are small and there are three of them. A record is not a pill.
 *
 * Constraints that shape the implementation:
 *   - CSP forbids inline CSS repo-wide (`style-src 'self'`, app/main.py), so
 *     every dynamic value must be expressible as a class or a native element
 *     attribute. Usage bars are native <progress>; nothing sets a style attr.
 *   - No external fonts and no build step. The previous sheet asked for
 *     "Nunito Sans", which is not in the repo and cannot be fetched under the
 *     CSP — so it silently fell back to system-ui on every machine. The stack
 *     below states that honestly instead of pretending otherwise.
 *   - Dark only. `color-scheme: dark` is declared and there is no light theme;
 *     the palette is built for it rather than inverted into it.
 */

:root {
  /* --- Surface ramp. Graphite, not navy: this is instrumentation. -------- */
  --bg: #0c0e11;
  --bg-sunken: #090b0d;
  --panel: #12151a;
  --panel-quiet: #10131700;
  --raised: #191d23;
  --input: #0a0c0f;

  /* --- Rules. Two weights: structural and emphatic. ---------------------- */
  --line: #232830;
  --line-strong: #333a45;

  /*
    Ink ramp. Three levels of consequence, and nothing between.

    All three clear WCAG AA (4.5:1) against every surface above, including
    `--raised`, which is the lightest background any of them sits on. That is a
    floor, not an aspiration: `--ink-faint` carries field hints, table captions,
    quota footnotes and the audit log's secondary lines — small text that is
    read, not decoration — so a dimmer grey that merely "looked quiet" would be
    illegible for exactly the people who most need it. Verify any change to
    these with a contrast checker before committing it.
  */
  --ink: #e7eaee;
  --ink-dim: #9aa3af;
  --ink-faint: #868e9b;

  /* --- Accent. Interactivity only — never decoration. -------------------- */
  --accent: #4c8dff;
  --accent-quiet: #1c2942;
  --accent-ink: #a8c6ff;

  /* --- Status. Low chroma so a page of them stays readable. -------------- */
  --good: #43b581;
  --good-quiet: #12241d;
  --warn: #d4a13a;
  --warn-quiet: #241d10;
  --bad: #e0655f;
  --bad-quiet: #26150f;

  /* --- Radii. Three steps, deliberately tight. -------------------------- */
  --r-sm: 2px;
  --r-md: 4px;
  --r-lg: 6px;

  /* --- Type scale. Compact and operational. ----------------------------- */
  --fs-micro: 11px;
  --fs-meta: 12px;
  --fs-sm: 13px;
  --fs-base: 14px;
  --fs-section: 15px;
  --fs-page: 19px;
  --fs-display: 24px;

  /* --- Spacing rhythm. 4px base; these are the only steps used. ---------- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  /* The one elevation step. Used by nothing that is merely a panel. */
  --lift: 0 8px 24px rgba(0, 0, 0, .45);

  --focus: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);

  /*
    The only motion in this stylesheet. It exists so a hover or focus reads as
    a state change rather than a repaint, and it is short enough to feel like
    the control responding instead of animating. Nothing here moves, scales,
    fades in on load, or animates on scroll — and `prefers-reduced-motion`
    reduces even this to nothing.
  */
  --tap: 90ms ease-out;
}

* {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-base);
  line-height: 1.5;
  /* Numbers line up in tables, counters and quota readouts without each of
     those having to ask for it. */
  font-variant-numeric: tabular-nums;
}

/* --- Layout ------------------------------------------------------------- */

/* 760px keeps a single-column form at a readable measure. Operational
   surfaces opt into `.wide` for their tables. */
.shell {
  width: min(760px, 100% - var(--sp-6));
  margin: 0 auto;
  padding: var(--sp-5) 0 var(--sp-7);
}

/* Operational surfaces (admin, org, records, verifier) need the width for
   their tables; the sending and auth flows deliberately do not. */
.shell.wide {
  width: min(1240px, 100% - var(--sp-6));
}

/* --- Masthead ----------------------------------------------------------- */

.platform-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
}

.platform-logo {
  display: block;
  width: 132px;
  height: 60px;
  object-fit: contain;
  object-position: left center;
}

.header-side {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
}

/* The signed-in identity. A label, not a badge — who you are is context, and
   context should not compete with the work. */
.secure-session {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.secure-session > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.secure-session svg,
.platform-footer svg,
.site-nav svg,
.notice > svg,
button svg,
.button svg {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.7;
}

/* --- Navigation --------------------------------------------------------- */

.site-nav {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-1);
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px var(--sp-2);
  border-radius: var(--r-sm);
  color: var(--ink-dim);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.site-nav a:hover {
  background: var(--raised);
  color: var(--ink);
  text-decoration: none;
}

/* Current page is marked by ink and a rule, not a filled pill. */
.site-nav a[aria-current="page"] {
  box-shadow: inset 0 -1px 0 var(--accent);
  color: var(--ink);
}

a {
  color: var(--accent-ink);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

:is(a, button, summary, [tabindex], input, select, textarea, label.drop-zone):focus-visible {
  outline: none;
  box-shadow: var(--focus);
  border-radius: var(--r-sm);
}

/* State changes on interactive surfaces only. See --tap. */
:is(a, button, .button, .stat, .site-nav a, .admin-nav a, .drop-zone,
    .verify-drop-zone, input, select, textarea, summary) {
  transition: background-color var(--tap), border-color var(--tap),
    color var(--tap), box-shadow var(--tap);
}

/* --- Panels ------------------------------------------------------------- */

/*
  `.card` is the one container primitive, and it is a *panel*: a flat, ruled
  region of the page. It is not raised, not blurred and not rounded to speak
  of. Most pages are a short stack of these; that stack is the page's
  structure, so panels are separated by their own rules rather than by gaps
  large enough to lose the reading thread.
*/
.card {
  padding: var(--sp-5);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
}

.card + .card {
  margin-top: var(--sp-4);
}

.card.narrow {
  width: min(100%, 460px);
  margin-inline: auto;
}

/* Retained for the few genuinely centred moments (a spent link, a dead end).
   Deliberately does not centre body copy — only the short block that is the
   whole message. */
.card.centered {
  text-align: center;
}

.card.centered .field-hint,
.card.centered label,
.card.centered .checkbox-row {
  text-align: left;
}

.hidden {
  display: none !important;
}

.divider {
  height: 1px;
  margin: var(--sp-5) 0;
  border: 0;
  background: var(--line);
}

/* --- Typography --------------------------------------------------------- */

h1,
h2,
h3 {
  margin: 0;
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.25;
}

h1 {
  font-size: var(--fs-page);
}

h2 {
  font-size: var(--fs-section);
}

h3 {
  font-size: var(--fs-sm);
}

/*
  Page header. Replaces the old kicker + oversized-heading + long-paragraph
  stack: the title says what the page is, the note says what the reader needs
  to know before acting, and anything else belongs where it is used.
*/
.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
}

.page-head > div:first-child {
  min-width: 0;
}

/* A header with nothing under it is just a heading: no rule, no trailing gap.
   Several panels are header-only in some states (an account with no pooled org
   plan, an org with no controls yet) and the dangling rule read as a bug. */
.card > .page-head:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: 0;
}

.page-head-note,
.section-note {
  margin: 6px 0 0;
  max-width: 68ch;
  color: var(--ink-dim);
  font-size: var(--fs-sm);
}

.section-note {
  margin-bottom: var(--sp-3);
}

.page-head-aside {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* A section heading inside a panel: quiet rule above, title, optional note. */
.section-head {
  margin: var(--sp-5) 0 var(--sp-3);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}

.section-head:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* Breadcrumb on detail pages. Structural, so it is a nav, not an eyebrow. */
.crumbs {
  margin: 0 0 var(--sp-2);
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.crumbs a {
  color: var(--ink-dim);
}

.muted {
  color: var(--ink-dim);
}

.intro {
  max-width: 68ch;
  margin: var(--sp-2) 0 0;
  color: var(--ink-dim);
  font-size: var(--fs-base);
}

.small {
  font-size: var(--fs-sm);
}

code,
.mono {
  font-family: var(--mono);
  font-size: .92em;
  font-variant-ligatures: none;
}

/* Inline code in prose needs to be findable without becoming a chip. */
p code,
li code,
td code,
caption code,
.field-hint code,
.section-note code {
  padding: 1px 4px;
  border-radius: var(--r-sm);
  background: var(--raised);
  color: var(--ink);
}

.checklist {
  margin: var(--sp-3) 0 0;
  padding-left: 18px;
  color: var(--ink-dim);
  font-size: var(--fs-sm);
  line-height: 1.65;
}

.checklist li + li {
  margin-top: var(--sp-1);
}

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

label {
  display: block;
  margin: 0 0 6px;
  font-size: var(--fs-meta);
  font-weight: 600;
  color: var(--ink);
}

.field + .field,
.field-block + .field-block {
  margin-top: var(--sp-4);
}

label .optional {
  margin-left: 6px;
  color: var(--ink-faint);
  font-weight: 400;
}

.field-grid {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.field-grid + .field-grid,
.field-grid + label,
form > label:not(:first-child) {
  margin-top: var(--sp-4);
}

.inline-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-2);
}

input[type=text],
input[type=email],
input[type=search],
input[type=number],
input[type=url],
input[type=tel],
input[type=date],
select,
textarea {
  width: 100%;
  min-width: 0;
  min-height: 34px;
  padding: 7px 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--input);
  color: var(--ink);
  font: inherit;
  font-variant-numeric: tabular-nums;
}

textarea {
  min-height: 76px;
  line-height: 1.5;
  resize: vertical;
}

/* A field's width should suggest how much belongs in it. A retention of "7"
   or a price of "0" in a 590px box tells the operator nothing about what is
   expected there. */
input[type=number] {
  max-width: 14ch;
}

input[type=date] {
  max-width: 20ch;
}

select {
  /* Native arrow only; no background-image, which would need a data URI and
     would drift from the ink ramp. */
  padding-right: 6px;
}

input::placeholder,
textarea::placeholder {
  color: var(--ink-faint);
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--accent);
  outline: none;
}

input[aria-invalid="true"] {
  border-color: var(--bad);
}

input:disabled,
textarea:disabled,
select:disabled {
  border-color: var(--line);
  color: var(--ink-faint);
  cursor: not-allowed;
}

input[readonly] {
  background: var(--bg-sunken);
  color: var(--ink-dim);
}

/* One-time codes and PINs: the field should look like the thing it takes. */
.otp-input {
  max-width: 168px;
  padding: 8px 10px;
  font-family: var(--mono);
  font-size: 17px;
  letter-spacing: .28em;
  text-indent: .28em;
  text-align: center;
}

.checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  font-size: var(--fs-sm);
}

.checkbox-row input[type=checkbox] {
  width: 15px;
  height: 15px;
  margin: 2px 0 0;
  flex: 0 0 auto;
  accent-color: var(--accent);
}

.checkbox-row label {
  margin: 0;
  font-weight: 400;
  line-height: 1.5;
}

/* The option's name, then its consequence on its own line. Run together they
   read as one long sentence and the actual choice disappears into it. */
.checkbox-row label > strong {
  display: block;
  font-weight: 600;
}

.checkbox-row label > .muted {
  display: block;
  margin-top: 2px;
  max-width: 78ch;
  font-size: var(--fs-meta);
}

.field-hint {
  margin: 6px 0 0;
  max-width: 74ch;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
  line-height: 1.5;
}

.field-hint.centered,
p.centered {
  text-align: center;
}

.form-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

.form-actions.center {
  justify-content: center;
}

/* Keeps a lone form inside a flex row from stretching. */
.form-actions form {
  display: contents;
}

.error {
  margin: 6px 0 0;
  color: var(--bad);
  font-size: var(--fs-meta);
}

.error:empty {
  display: none;
}

/* --- Buttons ------------------------------------------------------------ */

/*
  Four weights, and the distinction is *consequence*, not decoration:
    default    the one thing this page is for
    .secondary a real alternative
    .ghost     a way out, or a rarely-wanted option
    .danger    destroys something
  The primary button is accent-filled. The old sheet made it near-white,
  which read as louder than the accent while carrying no meaning.
*/
button,
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 32px;
  padding: 6px var(--sp-3);
  border: 1px solid var(--accent);
  border-radius: var(--r-sm);
  background: var(--accent);
  color: #06101f;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

button:hover:not(:disabled),
.button:hover {
  background: #6ba1ff;
  border-color: #6ba1ff;
  text-decoration: none;
}

button:disabled,
.button[aria-disabled="true"] {
  border-color: var(--line);
  background: var(--raised);
  color: var(--ink-faint);
  cursor: not-allowed;
}

button.secondary,
.button.secondary {
  border-color: var(--line-strong);
  background: var(--raised);
  color: var(--ink);
}

button.secondary:hover:not(:disabled),
.button.secondary:hover {
  border-color: var(--ink-faint);
  background: #21262e;
}

button.ghost,
.button.ghost {
  border-color: transparent;
  background: transparent;
  color: var(--ink-dim);
}

button.ghost:hover:not(:disabled),
.button.ghost:hover {
  background: var(--raised);
  color: var(--ink);
}

/* Destructive. Outlined rather than filled: it should be findable and never
   the thing a hurried operator hits by reflex. */
button.danger,
.button.danger {
  border-color: #5c2b2b;
  background: transparent;
  color: #eb8b86;
}

button.danger:hover:not(:disabled),
.button.danger:hover {
  border-color: var(--bad);
  background: var(--bad-quiet);
  color: #f4a9a5;
}

/* Federated sign-in. Equal weight to each other, secondary to the code path. */
.sso-row {
  display: grid;
  gap: var(--sp-2);
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  margin-top: var(--sp-3);
}

.sso-row .button {
  justify-content: flex-start;
}

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

/*
  A notice is marked by a status rule on its leading edge. Tinted panels at
  full width were competing with content for attention on pages that carry
  three or four of them.
*/
.notice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding: 10px var(--sp-3);
  border: 1px solid var(--line);
  border-left: 2px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--bg-sunken);
  color: var(--ink-dim);
  font-size: var(--fs-sm);
  text-align: left;
}

.notice > svg {
  margin-top: 3px;
}

.notice.info {
  border-left-color: var(--accent);
}

.notice.good {
  border-left-color: var(--good);
}

.notice.warn {
  border-left-color: var(--warn);
}

.notice.bad {
  border-left-color: var(--bad);
  color: #d9b6b3;
}

.admin-notice {
  margin: 0 0 var(--sp-4);
}

/* --- Status indicators -------------------------------------------------- */

/*
  A badge states a *state*. It is a small square-cornered tag with a status
  dot, not a pill: pills read as navigation, and these are never clickable.
  The old sheet used them for state, counts, plan names, retention windows and
  raw config keys at once, which is why pages looked confettied. Counts and
  attributes now live in `.meta-list`; badges are for state only.
*/
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--raised);
  color: var(--ink-dim);
  font-size: var(--fs-micro);
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
}

.badge::before {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  content: "";
  opacity: .8;
}

.badge.good {
  border-color: #23503c;
  background: var(--good-quiet);
  color: #6fce9f;
}

.badge.warn {
  border-color: #4d3d18;
  background: var(--warn-quiet);
  color: #dfb45c;
}

.badge.bad {
  border-color: #522724;
  background: var(--bad-quiet);
  color: #ec8f8a;
}

.badge-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--sp-3);
}

.page-head-aside .badge-row,
.badge-row:first-child {
  margin-top: 0;
}

/*
  Attributes of a thing — plan retention, max file size, a config key. Reads
  as a caption line rather than a row of chips, which is what it is.
*/
.meta-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin: var(--sp-2) 0 0;
  padding: 0;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
  list-style: none;
}

/* Wrap between attributes, never inside one: "Last seen 2026-08-26 13:15"
   broken over two lines reads as two separate facts. */
.meta-list > li {
  display: flex;
  gap: 5px;
  white-space: nowrap;
}

.meta-list strong {
  color: var(--ink-dim);
  font-weight: 500;
}

/* --- Key/value blocks --------------------------------------------------- */

/*
  A definition list, laid out as aligned rows. The old auto-fit grid gave a
  thirteen-item delivery block a ragged, unreadable shape and put labels and
  values in different visual columns on every row. On a record — where two
  parties reconcile values line by line — alignment is the whole job.
*/
.detail-grid {
  display: grid;
  margin: var(--sp-3) 0 0;
  gap: 0;
  grid-template-columns: minmax(140px, 220px) minmax(0, 1fr);
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm);
}

.detail-grid > div {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: baseline;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
}

.detail-label {
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.detail-value {
  min-width: 0;
  color: var(--ink);
  overflow-wrap: break-word;
}

.detail-value.mono {
  overflow-wrap: anywhere;
}

/* Two columns of key/value rows where there is room, so a long record does
   not become a single tall ribbon. */
.detail-grid.split {
  grid-template-columns: minmax(140px, 200px) minmax(0, 1fr) minmax(140px, 200px) minmax(0, 1fr);
}

.detail-grid.split > div {
  grid-column: auto / span 2;
}

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

/*
  Operational tables. These are the product's working surface, so they get the
  density: 12px text, tight rows, uppercase micro headers, and a hairline
  between rows rather than zebra fill. `.table-wrap` scrolls horizontally
  because a transfer table has eight real columns and truncating any of them
  loses the answer somebody came for.
*/
.table-wrap {
  margin-top: var(--sp-3);
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-meta);
}

/*
  Operational tables (the `.wide` surfaces: admin, org, records) keep a floor
  width inside their scroll container. Without it a narrow viewport does not
  scroll the table — it *compresses* it, and an eight-column transfer row whose
  filename cell has been squeezed to 60px becomes six lines tall, leaving the
  columns you can actually see as tall empty bands. Scrolling a correctly
  proportioned table is the better trade.

  Deliberately not applied to the narrow shell: the recipient download page and
  the record file lists have three columns and fit as they are.
*/
.shell.wide table.data-table {
  min-width: 720px;
}

/* A caption explains the table; it reads as prose above it, not as a row. */
table.data-table caption {
  padding: 9px var(--sp-3);
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
  color: var(--ink-faint);
  font-size: var(--fs-meta);
  line-height: 1.5;
  text-align: left;
}

table.data-table th,
table.data-table td {
  padding: 7px var(--sp-3);
  text-align: left;
  vertical-align: top;
  white-space: nowrap;
}

table.data-table thead th {
  position: sticky;
  top: 0;
  border-bottom: 1px solid var(--line-strong);
  background: var(--raised);
  color: var(--ink-faint);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}

table.data-table tbody tr + tr td {
  border-top: 1px solid var(--line);
}

table.data-table tbody tr:hover td {
  background: #14181e;
}

/*
  `break-word`, not `anywhere`: the old sheet split `cvanniekerk@blckrhino.com`
  into "cvanniekerk@blckrhino." / "com" mid-token in the audit log. Wrap at
  sensible boundaries, and only break inside a token for hashes, which have no
  boundaries to wrap at.
*/
table.data-table td.wrap {
  white-space: normal;
  overflow-wrap: break-word;
}

table.data-table td.mono,
table.data-table td .mono {
  overflow-wrap: anywhere;
}

table.data-table td.numeric,
table.data-table th.numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Secondary detail inside a cell: filenames under a count, a note under a
   plan. Indented by nothing — it is the same column, one level quieter. */
table.data-table td .muted.small {
  display: block;
  margin-top: 2px;
  color: var(--ink-faint);
  font-size: var(--fs-micro);
  white-space: normal;
  overflow-wrap: break-word;
}

/* A cell whose only content is an action keeps the row height honest. */
table.data-table td form {
  display: inline-flex;
}

table.data-table td button {
  min-height: 24px;
  padding: 2px var(--sp-2);
  font-size: var(--fs-micro);
}

/* The audit log's detail column: the widest, most variable content in the
   product. Capped so one verbose row cannot set the table's width. */
.audit-detail {
  max-width: 46ch;
  white-space: normal;
}

.empty-state {
  padding: var(--sp-5) var(--sp-4);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  margin-top: var(--sp-3);
  color: var(--ink-dim);
  font-size: var(--fs-sm);
  text-align: center;
}

/* --- Section navigation (admin, org) ------------------------------------ */

/*
  A tab strip, not a floating pill bar. The active section is joined to the
  content below it by sharing its rule, which is what makes a tab a tab.
*/
.admin-nav {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 0;
  margin-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line);
}

.admin-nav-label {
  display: inline-flex;
  align-items: center;
  margin-right: var(--sp-3);
  color: var(--ink-faint);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.admin-nav a {
  padding: 7px var(--sp-3);
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--ink-dim);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.admin-nav a:hover {
  color: var(--ink);
  text-decoration: none;
}

.admin-nav a[aria-current="page"] {
  border-bottom-color: var(--accent);
  color: var(--ink);
}

/* --- Overview tiles ----------------------------------------------------- */

/*
  Counts on the admin landing page. A tile is a link to the list behind it, so
  it is styled as a quiet target with an emphatic figure — the figure is the
  content, the label is the caption, and `.stat.attention` is how the two
  numbers that actually need a human get to look different from the six that
  are merely true.
*/
/*
  Real gaps and a border per tile, rather than a 1px grid gap showing a
  container background through. With `auto-fit` the last row is usually short,
  and the container-background trick rendered that leftover space as one large
  phantom tile.
*/
.stat-grid {
  display: grid;
  margin-top: var(--sp-3);
  gap: var(--sp-2);
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
  color: var(--ink);
  text-decoration: none;
}

.stat:hover {
  border-color: var(--line-strong);
  background: var(--raised);
  text-decoration: none;
}

.stat-value {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.15;
}

.stat-label {
  color: var(--ink-dim);
  font-size: var(--fs-meta);
  font-weight: 500;
}

.stat-foot {
  color: var(--ink-faint);
  font-size: var(--fs-micro);
}

/* Something here needs attention: the figure takes the status colour and a
   marker rule. Nothing else on the tile changes, so scanning still works. */
.stat.attention {
  box-shadow: inset 2px 0 0 var(--warn);
}

.stat.attention .stat-value {
  color: var(--warn);
}

/* --- Filter bars -------------------------------------------------------- */

.filter-form {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
}

.filter-fields {
  flex: 1 1 160px;
  min-width: 0;
}

/* A date needs one date's worth of room. Left to grow with the text fields it
   took a quarter of the bar to show "yyyy/mm/dd". */
.filter-fields:has(input[type=date]),
.filter-fields:has(select) {
  flex: 0 0 auto;
}

.filter-fields input[type=date] {
  width: auto;
}

.filter-fields label {
  margin-bottom: 4px;
  color: var(--ink-faint);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.filter-actions {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/*
  Filtering is the primary action *of the bar*, never of the page, so it takes
  the secondary weight. Enforced here rather than by asking four templates to
  remember a class.
*/
.filter-actions button[type=submit] {
  border-color: var(--line-strong);
  background: var(--raised);
  color: var(--ink);
}

.filter-actions button[type=submit]:hover:not(:disabled) {
  border-color: var(--ink-faint);
  background: #21262e;
}

.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.pager-links {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

/* --- Action rows -------------------------------------------------------- */

/*
  One row per administrative action: what it does on the left, the control on
  the right. Destructive rows are marked on the leading edge so that a column
  of buttons cannot be misread — this is the list where "Suspend" and "Resend
  invite" sit two rows apart.
*/
.action-rows {
  margin-top: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}

.action-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--panel);
}

.action-row + .action-row {
  border-top: 1px solid var(--line);
}

.action-row > div:first-child {
  min-width: 0;
}

.action-row strong {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 600;
}

.action-row p {
  margin: 3px 0 0;
  max-width: 76ch;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.action-row form,
.knob-controls {
  flex: 0 0 auto;
}

.action-row:has(button.danger) {
  box-shadow: inset 2px 0 0 #5c2b2b;
}

.knob-controls {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/*
  Saving one policy knob is that row's action, not the page's. Seven accent
  buttons down a settings page is a column of noise with no hierarchy in it —
  and it makes the genuinely destructive controls elsewhere in /admin harder to
  read by comparison. Same reasoning as `.filter-actions`.
*/
.knob-controls button[type=submit] {
  border-color: var(--line-strong);
  background: var(--raised);
  color: var(--ink);
}

.knob-controls button[type=submit]:hover:not(:disabled) {
  border-color: var(--ink-faint);
  background: #21262e;
}

.knob-controls .inline-row {
  grid-template-columns: minmax(72px, 116px) auto;
}

.knob-row .meta-list {
  margin-top: 6px;
}

/* --- Quota meters ------------------------------------------------------- */

.quota-grid {
  display: grid;
  margin-top: var(--sp-3);
  gap: var(--sp-2);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

.quota-item {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
}

.quota-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.quota-value {
  color: var(--ink);
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* Native <progress> so a usage bar needs no inline style (CSP) and no JS.
   Flat fill, not a gradient: the bar reports one quantity. */
.quota-meter,
.file-meter {
  display: block;
  width: 100%;
  height: 4px;
  margin-top: 10px;
  appearance: none;
  border: none;
  border-radius: var(--r-sm);
  background: var(--line);
  color: var(--accent);
  overflow: hidden;
}

.quota-meter::-webkit-progress-bar,
.file-meter::-webkit-progress-bar {
  border-radius: var(--r-sm);
  background: var(--line);
}

.quota-meter::-webkit-progress-value,
.file-meter::-webkit-progress-value {
  border-radius: var(--r-sm);
  background: var(--accent);
}

.quota-meter::-moz-progress-bar,
.file-meter::-moz-progress-bar {
  border-radius: var(--r-sm);
  background: var(--accent);
}

/* Exhausted, not merely full: the bar changes meaning, so it changes colour. */
.quota-meter.full::-webkit-progress-value {
  background: var(--bad);
}

.quota-meter.full::-moz-progress-bar {
  background: var(--bad);
}

.quota-foot {
  margin: 8px 0 0;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

/* --- Send page ---------------------------------------------------------- */

/*
  The three steps of a send. Numbered because the order is real — files, then
  recipient, then authentication — and the number is set in the rule rather
  than as a bar of accent colour beside the text.
*/
.step {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}

.step:first-of-type {
  margin-top: var(--sp-4);
}

.step-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

/* The step number is a marker, not an ornament: present enough to scan the
   sequence, quiet enough that the step's name is what you read. */
.step-num {
  display: grid;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  place-items: center;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  color: var(--ink-dim);
  font-family: var(--mono);
  font-size: var(--fs-micro);
  font-weight: 600;
}

.upload-heading {
  margin: 0;
  font-size: var(--fs-section);
}

/*
  The drop zone. Still unmistakably a target, no longer the whole page: the
  old 280px-tall dashed panel pushed the recipient field below the fold on a
  laptop, which is the field a sender actually has to fill in.
*/
.drop-zone {
  display: flex;
  min-height: 128px;
  padding: var(--sp-5) var(--sp-4);
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
  text-align: center;
  cursor: pointer;
}

.drop-zone:hover,
.drop-zone.dragover {
  border-color: var(--accent);
  background: var(--accent-quiet);
}

.drop-zone strong {
  font-size: var(--fs-base);
  font-weight: 600;
}

.drop-zone span,
.drop-zone small {
  color: var(--ink-dim);
  font-size: var(--fs-sm);
}

.drop-zone small {
  max-width: 62ch;
  margin-top: 6px;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.drop-icon {
  display: grid;
  width: 22px;
  height: 22px;
  margin-bottom: 6px;
  place-items: center;
  color: var(--ink-faint);
}

.drop-icon svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.6;
}

.drop-zone:hover .drop-icon,
.drop-zone.dragover .drop-icon {
  color: var(--accent);
}

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: var(--sp-3) 0 var(--sp-2);
  color: var(--ink-dim);
  font-size: var(--fs-meta);
}

/* The upload queue. A list of rows, ruled like a table, because that is what
   it is — and it becomes a receipt table on completion. */
.file-list {
  display: flex;
  flex-direction: column;
}

.file-list:not(:empty) {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}

.file-row {
  padding: var(--sp-3);
  background: var(--panel);
}

.file-row + .file-row {
  border-top: 1px solid var(--line);
}

.file-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
}

.file-name {
  font-size: var(--fs-sm);
  font-weight: 500;
  overflow-wrap: anywhere;
}

.file-meta {
  margin-top: 2px;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.file-side {
  display: flex;
  flex: 0 0 auto;
  align-items: flex-end;
  flex-direction: column;
  gap: var(--sp-1);
}

.file-status {
  color: var(--ink-dim);
  font-size: var(--fs-meta);
  text-align: right;
}

.file-status.good {
  color: var(--good);
}

.file-status.bad {
  color: var(--bad);
}

/* Small, but still visibly a control: a bare ghost button at this size read as
   a caption and nobody would think to click it. */
.file-remove {
  min-height: 22px;
  padding: 1px 6px;
  border-color: var(--line-strong);
  font-size: var(--fs-micro);
}

/* Retained: send.js writes to `.progress > div` on older paths. */
.progress {
  height: 4px;
  margin-top: 10px;
  overflow: hidden;
  border-radius: var(--r-sm);
  background: var(--line);
}

.progress > div {
  width: 0;
  height: 100%;
  background: var(--accent);
}

/* --- Authenticator pairing ---------------------------------------------- */

.qr-panel {
  display: grid;
  align-items: start;
  gap: var(--sp-5);
  grid-template-columns: auto minmax(0, 1fr);
  margin-top: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
  text-align: left;
}

/* The QR must stay a true white quiet-zone to scan reliably. */
.qr-code {
  display: block;
  width: 168px;
  height: 168px;
  padding: 8px;
  border-radius: var(--r-sm);
  background: #fff;
}

.qr-manual h3 {
  margin-bottom: 4px;
}

.manual-key {
  margin: var(--sp-2) 0;
  padding: 8px 10px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--input);
  font-family: var(--mono);
  font-size: var(--fs-sm);
  letter-spacing: .06em;
  overflow-wrap: anywhere;
  user-select: all;
}

.resend-form {
  margin-top: var(--sp-3);
}

/* --- Records (Delivery Proof / Receipt) --------------------------------- */

/*
  A record rendering is a *document*, and it is read next to the counterparty's
  copy and next to the signed JSON. So it is set as a document: a measured
  column, numbered sections, and values in monospace wherever a human is
  expected to compare them character by character.

  The old rendering was seven identical glassmorphic cards, which gave the
  cryptographic identity of the record exactly the same weight as the footer
  about who issued it.
*/
.record-head {
  padding-bottom: var(--sp-4);
  border-bottom: 2px solid var(--line-strong);
}

.record-issuer {
  margin: 0 0 var(--sp-2);
  color: var(--ink-faint);
  font-size: var(--fs-meta);
  letter-spacing: .04em;
  text-transform: uppercase;
}

.record-head h1 {
  font-size: var(--fs-display);
}

.record-subtitle {
  margin: 6px 0 0;
  max-width: 72ch;
  color: var(--ink-dim);
  font-size: var(--fs-base);
}

.record-summary {
  margin: var(--sp-3) 0 0;
  max-width: 76ch;
}

.record-section {
  margin-top: var(--sp-6);
}

.record-section > h2 {
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}

.record-section > h3 {
  margin-top: var(--sp-4);
  color: var(--ink-dim);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* The record's own hash and id: the two values everything else hangs off. */
.record-fingerprint {
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent);
  border-radius: var(--r-sm);
  background: var(--bg-sunken);
}

.record-fingerprint .detail-label {
  display: block;
  margin-bottom: 3px;
}

.record-fingerprint .mono {
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
}

/*
  What the record proves, and what it does not. docs/Send2.0_spec.md §3.1 is
  explicit that overclaiming destroys the record's value, so the two lists are
  the same size, the same weight and side by side — the limits are not a
  footnote and must never be restyled into one.
*/
.claims {
  display: grid;
  gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  margin-top: var(--sp-3);
}

.claims > section {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
}

.claims h3 {
  margin-bottom: var(--sp-2);
  font-size: var(--fs-sm);
}

.claims-proves {
  border-left: 2px solid var(--good) !important;
}

.claims-limits {
  border-left: 2px solid var(--warn) !important;
}

.claims ul {
  margin: 0;
  padding-left: 18px;
  color: var(--ink-dim);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.claims li + li {
  margin-top: 6px;
}

/* --- Verifier ----------------------------------------------------------- */

/*
  The public verifier is the one page a stranger may arrive at cold, holding a
  record in a dispute. It is allowed more presence than an admin table — but
  it earns that with the verdict, not with a hero.
*/
.verify-hero h1 {
  font-size: var(--fs-display);
}

.verify-hero-copy {
  max-width: 72ch;
}

/* The verifier's properties: a caption strip, not an icon grid. */
.verify-properties {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  margin: var(--sp-4) 0 0;
  padding: var(--sp-3) 0 0;
  border-top: 1px solid var(--line);
  list-style: none;
}

.verify-properties li {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.verify-properties strong {
  font-size: var(--fs-meta);
  font-weight: 600;
}

.verify-properties span {
  color: var(--ink-faint);
  font-size: var(--fs-micro);
}

.verify-section-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
}

.verify-section-heading > div {
  min-width: 0;
}

.verify-drop-zone {
  position: relative;
  display: flex;
  min-height: 116px;
  margin-top: var(--sp-3);
  padding: var(--sp-5) var(--sp-4);
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 3px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
  cursor: pointer;
  text-align: center;
}

.verify-drop-zone:hover,
.verify-drop-zone:focus-within,
.verify-drop-zone.dragover {
  border-color: var(--accent);
  background: var(--accent-quiet);
}

.verify-drop-zone.has-file {
  border-style: solid;
  border-color: var(--good);
  background: var(--good-quiet);
}

.verify-drop-zone strong {
  font-size: var(--fs-base);
}

.verify-drop-zone > span:not(.drop-icon),
.verify-drop-zone small {
  color: var(--ink-dim);
  font-size: var(--fs-sm);
}

.verify-drop-zone small {
  max-width: 64ch;
  margin-top: 5px;
  color: var(--ink-faint);
  font-size: var(--fs-meta);
}

.verify-file-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.verify-paste {
  margin-top: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
}

.verify-paste summary {
  padding: 9px var(--sp-3);
  color: var(--ink-dim);
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 500;
}

.verify-paste[open] summary {
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}

.verify-paste > label,
.verify-paste > textarea {
  margin: 0 var(--sp-3);
  width: calc(100% - var(--sp-5));
}

.verify-paste > label {
  margin-top: var(--sp-3);
}

.verify-paste > textarea {
  margin-bottom: var(--sp-3);
}

.verify-status {
  margin: var(--sp-3) 0 0;
  color: var(--ink-dim);
  font-size: var(--fs-sm);
}

.verify-status:empty {
  display: none;
}

/*
  The verdict. This is the answer the page exists to give, so it is the one
  place in the product that is allowed to be loud — a full-width banded
  statement with the status carried on a thick leading rule.
*/
.verify-verdict {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
}

.verify-verdict > div {
  min-width: 0;
}

.verify-verdict h2 {
  font-size: var(--fs-page);
}

.verify-verdict.good {
  border-color: #23503c;
  border-left-color: var(--good);
  background: var(--good-quiet);
}

.verify-verdict.bad {
  border-color: #522724;
  border-left-color: var(--bad);
  background: var(--bad-quiet);
}

.verify-verdict .muted {
  max-width: 76ch;
  margin: 6px 0 0;
  font-size: var(--fs-sm);
}

.verify-result-columns {
  display: grid;
  margin-top: var(--sp-5);
  gap: var(--sp-5);
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

.verify-result-columns > div > h3 {
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
}

.verify-result-columns .section-note {
  margin-top: 6px;
}

.verification-checks {
  display: flex;
  flex-direction: column;
  margin-top: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}

.verification-checks:empty {
  display: none;
}

/* The server-rendered (no-JavaScript) result lists every check at once, so it
   goes multi-column. Real gaps, not a container background: the check count is
   variable and a short last row must not read as an empty check. */
.server-checks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-2);
  border: 0;
}

.verification-check {
  display: flex;
  min-width: 0;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: 9px var(--sp-3);
  background: var(--panel);
}

.server-checks .verification-check {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.verification-checks:not(.server-checks) .verification-check + .verification-check {
  border-top: 1px solid var(--line);
}

.verification-check-mark {
  display: grid;
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  margin-top: 1px;
  place-items: center;
  border-radius: 50%;
  background: var(--line);
  color: var(--ink-dim);
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
}

.verification-check.good .verification-check-mark {
  background: var(--good-quiet);
  color: var(--good);
}

.verification-check.bad .verification-check-mark {
  background: var(--bad-quiet);
  color: var(--bad);
}

.verification-check.warn .verification-check-mark {
  background: var(--warn-quiet);
  color: var(--warn);
}

.verification-check > span:last-child {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 1px;
}

.verification-check strong {
  font-size: var(--fs-meta);
  font-weight: 600;
}

.verification-check small {
  color: var(--ink-faint);
  font-size: var(--fs-micro);
  line-height: 1.5;
}

.verify-facts {
  margin-top: var(--sp-5);
}

.verify-meaning {
  margin-top: var(--sp-5);
}

/* The independent path: three ordered steps, then the command. */
.verify-steps {
  display: grid;
  margin: var(--sp-3) 0 0;
  padding: 0;
  gap: var(--sp-2);
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  list-style: none;
}

.verify-steps li {
  display: flex;
  min-width: 0;
  align-items: flex-start;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--panel);
}

.verify-steps li > span {
  flex: 0 0 auto;
  color: var(--ink-faint);
  font-family: var(--mono);
  font-size: var(--fs-meta);
}

.verify-steps div {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 2px;
}

.verify-steps strong {
  font-size: var(--fs-meta);
}

.verify-steps small {
  color: var(--ink-faint);
  font-size: var(--fs-micro);
  line-height: 1.5;
}

.verify-command {
  margin: var(--sp-3) 0 0;
  padding: 10px var(--sp-3);
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--input);
  color: var(--accent-ink);
  font-size: var(--fs-meta);
}

/* --- Recipient download ------------------------------------------------- */

/*
  The recipient's page. The files are the entire point, so they are the first
  and heaviest thing on it; the account pitch is a single quiet line at the
  bottom rather than a second panel of equal weight.
*/
.download-summary {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-3);
  margin-top: var(--sp-2);
  color: var(--ink-dim);
  font-size: var(--fs-sm);
}

.sender-note {
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-left: 2px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--bg-sunken);
  color: var(--ink);
  font-size: var(--fs-sm);
}

.sender-note .detail-label {
  display: block;
  margin-bottom: 3px;
}

.signup-aside {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  color: var(--ink-faint);
  font-size: var(--fs-sm);
}

/* --- Footer ------------------------------------------------------------- */

/* `.support-text` lived here for a support message that no template and no
   route ever rendered — dead before this pass, and removed with it. */

.platform-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  color: var(--ink-faint);
  font-size: var(--fs-meta);
  text-align: center;
}

.platform-footer a {
  color: var(--ink-dim);
  text-decoration: underline;
}

/* Deploy fingerprint. Monospace because it is an identifier meant to be compared
   against a commit, and quiet because it is for the one person who just ran a
   deploy rather than for everyone reading the page. */
.build-tag {
  padding: 1px 5px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--bg-sunken);
  color: var(--ink-faint);
  font-family: var(--mono);
  font-size: var(--fs-micro);
  user-select: all;
}

/* --- Responsive --------------------------------------------------------- */

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

  .detail-grid.split > div {
    grid-column: 1 / -1;
  }
}

@media (max-width: 720px) {
  .shell,
  .shell.wide {
    width: min(100% - var(--sp-4), 1240px);
    padding: var(--sp-4) 0 var(--sp-6);
  }

  .platform-header {
    align-items: flex-start;
    flex-direction: column;
    gap: var(--sp-3);
  }

  /* Sections first, identity second — the same reading order as the DOM. */
  .header-side {
    justify-content: space-between;
    width: 100%;
  }

  .platform-logo {
    width: 108px;
    height: 48px;
  }

  .card {
    padding: var(--sp-4);
  }

  .page-head,
  .verify-section-heading,
  .verify-verdict {
    align-items: flex-start;
    flex-direction: column;
    gap: var(--sp-3);
  }

  /* Key/value rows stack: a 140px label column beside a long hash is worse
     than a label above it. */
  .detail-grid,
  .detail-grid.split {
    grid-template-columns: minmax(0, 1fr);
  }

  .detail-grid > div,
  .detail-grid.split > div {
    grid-column: 1 / -1;
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
  }

  /* Admin action rows stack so the control is never squeezed to nothing. */
  .action-row {
    align-items: stretch;
    flex-direction: column;
    gap: var(--sp-3);
  }

  .qr-panel {
    justify-items: center;
    grid-template-columns: minmax(0, 1fr);
    text-align: center;
  }

  .qr-manual {
    text-align: left;
  }

  .admin-nav {
    /* The section list stays one scrollable row rather than reflowing into a
       three-line block that pushes the page down. */
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .admin-nav::-webkit-scrollbar {
    display: none;
  }

  .admin-nav-label {
    display: none;
  }

  table.data-table thead th {
    position: static;
  }
}

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

  .toolbar {
    align-items: flex-start;
    flex-direction: column;
    gap: var(--sp-2);
  }

  .file-top {
    flex-direction: column;
  }

  .file-side {
    align-items: flex-start;
    flex-direction: row;
    justify-content: space-between;
    width: 100%;
  }

  .file-status {
    text-align: left;
  }

  .signup-aside {
    align-items: flex-start;
    flex-direction: column;
  }
}

/* Touch: 32px is comfortable with a mouse and not with a thumb. */
@media (pointer: coarse) {
  button,
  .button {
    min-height: 40px;
    padding: 8px var(--sp-4);
  }

  input[type=text],
  input[type=email],
  input[type=search],
  input[type=number],
  input[type=url],
  input[type=tel],
  input[type=date],
  select,
  textarea {
    min-height: 40px;
  }

  .site-nav a {
    padding: 8px var(--sp-2);
  }

  table.data-table td button {
    min-height: 32px;
    padding: 4px var(--sp-2);
  }
}

/* There is no decorative motion in this sheet; this covers scroll behaviour
   and anything a future addition introduces. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: .01ms !important;
  }
}

@media (prefers-contrast: more) {
  :root {
    --ink-dim: #c3cad4;
    --ink-faint: #9aa3af;
    --line: #3a424e;
    --line-strong: #55606f;
  }
}

@media print {
  /* A Delivery Proof or Receipt is printed and filed. */
  :root {
    --bg: #fff;
    --bg-sunken: #fff;
    --panel: #fff;
    --raised: #f4f5f7;
    --input: #fff;
    --ink: #000;
    --ink-dim: #333;
    --ink-faint: #555;
    --line: #bbb;
    --line-strong: #888;
  }

  html {
    color-scheme: light;
  }

  .platform-header,
  .platform-footer,
  .site-nav,
  .form-actions,
  .admin-nav {
    display: none;
  }

  .card {
    border: 0;
    padding: 0;
  }

  .record-section {
    break-inside: avoid;
  }
}
