/*
 * One stylesheet, hand-written, no build step (PLAN.md "UI"). Everything that
 * differs between the two themes is a custom property on :root — nothing below
 * the theme blocks should contain a raw colour, because scattered hex is what
 * made this file impossible to theme the first time.
 *
 * Theme resolution order, and all three matter:
 *   1. :root                                  → light, the default
 *   2. @media (prefers-color-scheme: dark)    → follows the OS when unset
 *   3. :root[data-theme="light"|"dark"]       → an explicit choice, and it must
 *      win in BOTH directions, which is why (3) repeats the full palette rather
 *      than only the dark one.
 * The inline script in <head> stamps data-theme before first paint.
 */

:root {
  color-scheme: light;

  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-sunken: #f7f8fa;
  --ink: #1b1d21;
  --ink-soft: #3f444c;
  --muted: #6b7280;
  --line: #e3e5ea;
  --line-strong: #cfd3da;

  --accent: #2f5fd0;
  --accent-ink: #ffffff;
  --accent-soft: #eef2fd;

  --ok: #17663d;
  --ok-line: #b7e0c6;
  --ok-bg: #eefaf2;
  --warn: #8a5a08;
  --warn-line: #f0d79a;
  --warn-bg: #fdf7e9;
  --bad: #a92626;
  --bad-line: #f2c1c1;
  --bad-bg: #fdf1f1;

  --focus: #2f5fd0;
  --shadow: 0 1px 2px rgba(16, 20, 28, 0.05), 0 1px 3px rgba(16, 20, 28, 0.04);

  --radius: 10px;
  --radius-sm: 6px;

  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 24px;
  --s6: 32px;

  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --bg: #101216;
    --surface: #191c21;
    --surface-sunken: #14171b;
    --ink: #e4e7ec;
    --ink-soft: #c2c7d0;
    --muted: #8f96a3;
    --line: #2a2f37;
    --line-strong: #3a414b;

    --accent: #7ea6ff;
    --accent-ink: #0f1319;
    --accent-soft: #1b2740;

    --ok: #6dd39b;
    --ok-line: #2a4d3a;
    --ok-bg: #14251c;
    --warn: #e5be6a;
    --warn-line: #4d4023;
    --warn-bg: #26200f;
    --bad: #f08b8b;
    --bad-line: #552b2b;
    --bad-bg: #2a1717;

    --focus: #7ea6ff;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
  }
}

/* An explicit choice beats the media query both ways. */
:root[data-theme='light'] {
  color-scheme: light;

  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-sunken: #f7f8fa;
  --ink: #1b1d21;
  --ink-soft: #3f444c;
  --muted: #6b7280;
  --line: #e3e5ea;
  --line-strong: #cfd3da;

  --accent: #2f5fd0;
  --accent-ink: #ffffff;
  --accent-soft: #eef2fd;

  --ok: #17663d;
  --ok-line: #b7e0c6;
  --ok-bg: #eefaf2;
  --warn: #8a5a08;
  --warn-line: #f0d79a;
  --warn-bg: #fdf7e9;
  --bad: #a92626;
  --bad-line: #f2c1c1;
  --bad-bg: #fdf1f1;

  --focus: #2f5fd0;
  --shadow: 0 1px 2px rgba(16, 20, 28, 0.05), 0 1px 3px rgba(16, 20, 28, 0.04);
}

:root[data-theme='dark'] {
  color-scheme: dark;

  --bg: #101216;
  --surface: #191c21;
  --surface-sunken: #14171b;
  --ink: #e4e7ec;
  --ink-soft: #c2c7d0;
  --muted: #8f96a3;
  --line: #2a2f37;
  --line-strong: #3a414b;

  --accent: #7ea6ff;
  --accent-ink: #0f1319;
  --accent-soft: #1b2740;

  --ok: #6dd39b;
  --ok-line: #2a4d3a;
  --ok-bg: #14251c;
  --warn: #e5be6a;
  --warn-line: #4d4023;
  --warn-bg: #26200f;
  --bad: #f08b8b;
  --bad-line: #552b2b;
  --bad-bg: #2a1717;

  --focus: #7ea6ff;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
}

* {
  box-sizing: border-box;
}

/* Any author `display` rule beats the UA stylesheet's `[hidden] { display: none }`,
   so a hidden flex row (the CSV mapping's attribute-name box) stays visible
   without this. Found in Chrome, 2026-08-05. DO NOT REMOVE. */
[hidden] {
  display: none !important;
}

html {
  background: var(--bg);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* ----------------------------------------------------------------- focus */

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Only suppress the ring for pointer users; keyboard focus always shows one. */
:focus:not(:focus-visible) {
  outline: none;
}

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

/* ---------------------------------------------------------------- topbar */

.topbar {
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding: var(--s3) var(--s5);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

.topbar nav {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-left: auto;
}

.topbar nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 15px;
  padding: 6px 2px;
  border-bottom: 2px solid transparent;
}

.topbar nav a:hover {
  color: var(--ink);
  border-bottom-color: var(--line-strong);
}

/* Now a link into /settings/security, so it has to out-specify `.topbar nav a`
   to keep reading as a quiet label rather than a ninth nav item. */
.topbar nav a.who {
  color: var(--muted);
  font-size: 13px;
  white-space: nowrap;
  border-bottom-color: transparent;
}

.topbar nav a.who:hover {
  color: var(--ink-soft);
  border-bottom-color: var(--line-strong);
}

.brand {
  font-weight: 700;
  font-size: 17px;
  letter-spacing: -0.01em;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}

/* Eight nav links plus the tenant line plus Log out is a lot for one row: with
   nothing stopping them, flex shrinks the two shortest items and "cf-email" and
   "Log out" each break across two lines. */
.topbar nav a,
.topbar nav button.link {
  white-space: nowrap;
}

/*
 * Between the hamburger breakpoint and a comfortable desktop, the tenant/email
 * line is what gives. It is the least load-bearing thing in the bar — the
 * dashboard names the tenant in a heading, and the mobile drawer still shows it
 * (this rule is scoped above the drawer's breakpoint so it does not reach it).
 */
@media (min-width: 1041px) and (max-width: 1150px) {
  /*
   * The tenant name goes; the address stays, because the address is now the
   * link to /settings/security and hiding the whole thing left that screen
   * unreachable in a 110px-wide band. The name is the part that can go — the
   * dashboard carries it in a heading and the mobile drawer still shows it.
   */
  .topbar nav a.who .who-tenant {
    display: none;
  }
}

/* The hamburger and the theme control. Both are chrome, not content, so they
   are quiet until hovered or focused. */
.iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 40px;
  padding: 0 var(--s2);
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.iconbtn:hover {
  color: var(--ink);
  background: var(--surface-sunken);
  border-color: var(--line);
}

.iconbtn svg {
  width: 18px;
  height: 18px;
  display: block;
}

.navtoggle {
  display: none;
}

a {
  color: var(--accent);
}

main {
  max-width: 780px;
  margin: var(--s5) auto var(--s6);
  padding: 0 var(--s5);
}

/* The unsubscribe pages have no app chrome: a recipient is not a tenant, and
   showing them a navigation bar into someone else's account would be wrong. */
body.standalone main {
  max-width: 520px;
  margin-top: 64px;
}

/* ----------------------------------------------------------------- cards */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s5);
  box-shadow: var(--shadow);
}

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

h1 {
  margin-top: 0;
  font-size: 25px;
  line-height: 1.25;
  letter-spacing: -0.02em;
}

h2 {
  font-size: 18px;
  letter-spacing: -0.01em;
}

h3 {
  font-size: 15px;
}

/* ----------------------------------------------------------------- forms */

label {
  display: block;
  margin: 0 0 var(--s4);
  font-weight: 600;
  font-size: 15px;
}

input,
textarea,
select {
  display: block;
  width: 100%;
  margin-top: var(--s1);
  padding: 10px 12px;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
}

input:hover,
textarea:hover,
select:hover {
  border-color: var(--muted);
}

::placeholder {
  color: var(--muted);
  opacity: 1;
}

.hint {
  display: block;
  margin-top: var(--s1);
  font-weight: 400;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

button {
  min-height: 40px;
  padding: 9px 16px;
  font: inherit;
  font-weight: 600;
  font-size: 15px;
  color: var(--accent-ink);
  background: var(--accent);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

button:hover {
  filter: brightness(1.08);
}

/* A link that starts an action, styled as the button it behaves like — the
   "New campaign" affordance is a navigation, not a form submit. */
a.button {
  display: inline-block;
  min-height: 40px;
  padding: 9px 16px;
  font-weight: 600;
  font-size: 15px;
  color: var(--accent-ink);
  background: var(--accent);
  border-radius: var(--radius-sm);
  text-decoration: none;
}

button.secondary {
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
}

button.secondary:hover {
  background: var(--surface-sunken);
  filter: none;
}

button.link {
  min-height: 0;
  padding: 0;
  color: var(--accent);
  background: none;
  border: 0;
  font-weight: 400;
  font-size: inherit;
  text-decoration: underline;
}

button.link:hover {
  filter: none;
}

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

/* ---------------------------------------------------------------- flashes */

.flash {
  margin: 0 0 var(--s4);
  padding: var(--s3) var(--s4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-sunken);
  color: var(--ink-soft);
  font-size: 15px;
}

.flash p {
  margin: 0;
}

.flash p + p {
  margin-top: var(--s2);
}

.flash-error {
  color: var(--bad);
  border-color: var(--bad-line);
  background: var(--bad-bg);
}

.flash-ok {
  color: var(--ok);
  border-color: var(--ok-line);
  background: var(--ok-bg);
}

/* ------------------------------------------------------------------ done */

/*
 * "There is nothing left for you to do here." The two screens that needed this
 * (webhook, domain) each had a correct-but-buried status pill and an open form
 * underneath, which reads as unfinished work however the label is worded.
 */
.done {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  margin: 0 0 var(--s4);
  padding: var(--s4);
  border: 1px solid var(--ok-line);
  border-radius: var(--radius-sm);
  background: var(--ok-bg);
  color: var(--ok);
}

.done svg {
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 1px;
}

.done p {
  margin: 0;
  color: var(--ok);
}

.done p + p {
  margin-top: var(--s1);
}

.done strong {
  display: block;
  font-size: 16px;
}

/* ----------------------------------------------------------------- stats */

.stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s4) var(--s6);
  margin: 0 0 var(--s5);
}

.stats dt {
  font-size: 13px;
  color: var(--muted);
}

.stats dd {
  margin: 2px 0 0;
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* --------------------------------------------- tiles, records, pills ---- */

.tiles,
.records,
.rows-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.tile {
  padding: var(--s4) 0;
  border-top: 1px solid var(--line);
}

.tile h2 {
  margin: 0;
}

.tile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.tile-head h1,
.tile-head h2 {
  margin: 0;
}

.tile p {
  margin: 6px 0 0;
}

.pill {
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid var(--line);
  background: var(--surface-sunken);
  color: var(--muted);
}

.pill-ok {
  color: var(--ok);
  border-color: var(--ok-line);
  background: var(--ok-bg);
}

.pill-warn {
  color: var(--warn);
  border-color: var(--warn-line);
  background: var(--warn-bg);
}

.pill-bad {
  color: var(--bad);
  border-color: var(--bad-line);
  background: var(--bad-bg);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s3) var(--s4);
  margin-top: var(--s4);
}

.actions form {
  margin: 0;
}

.mono,
code {
  font-family: var(--mono);
  font-size: 13px;
}

.breakable {
  overflow-wrap: anywhere;
}

/* The provider's own words, never paraphrased — kept visually distinct. */
.verbatim {
  margin: var(--s2) 0 0;
  padding: var(--s2) var(--s3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: 13px;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------ copy field */

.copyfield {
  margin: var(--s2) 0 var(--s3);
}

.copyfield-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.copyfield-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
}

.copyfield code {
  display: block;
  margin-top: var(--s1);
  padding: 10px 12px;
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  user-select: all;
}

.copyfield .hint {
  margin-top: 6px;
}

/* 40px square: a copy button is one of the two things anyone taps on the DNS
   screen, and the old text link was ~30px tall with no hit padding. */
button.copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 40px;
  min-height: 40px;
  padding: 0 var(--s2);
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

button.copy:hover {
  color: var(--ink);
  background: var(--surface-sunken);
  border-color: var(--line);
  filter: none;
}

button.copy svg {
  width: 16px;
  height: 16px;
  display: block;
}

button.copy .copy-done {
  display: none;
}

button.copy.is-copied {
  color: var(--ok);
}

button.copy.is-copied .copy-idle {
  display: none;
}

button.copy.is-copied .copy-done {
  display: block;
}

/* ---------------------------------------------------------------- record */

.record {
  padding: var(--s4) 0;
  border-top: 1px solid var(--line);
}

.record-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}

.record h3 {
  margin: 0;
  font-size: 15px;
}

.record .hint:empty {
  display: none;
}

/* ------------------------------------------------------- definition rows */

.rows {
  margin: var(--s4) 0 0;
}

.rows div {
  display: flex;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--line);
}

.rows dt {
  font-size: 14px;
  color: var(--muted);
}

.rows dd {
  margin: 0;
  text-align: right;
  overflow-wrap: anywhere;
}

.rows-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: var(--s2) 0;
}

.rows-list li form {
  margin: 0;
}

/* ---------------------------------------------------------------- tables */

/*
 * Wide tables scroll inside their own box. The page body must never scroll
 * sideways — a horizontally scrolling document on a phone makes every screen
 * feel broken, not just the one with the table.
 */
.tablewrap {
  margin: var(--s4) 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.grid {
  width: 100%;
  margin: var(--s4) 0;
  border-collapse: collapse;
}

/*
 * No forced min-width: the header cells are `white-space: nowrap`, so a table
 * that genuinely cannot fit creates its own overflow and scrolls, while a
 * three-column one lays out inside 390px instead of being clipped mid-pill by
 * a width it never needed.
 */
.tablewrap .grid {
  margin: 0;
}

.grid th,
.grid td {
  padding: 10px var(--s3) 10px 0;
  text-align: left;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.grid th {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}

.grid tbody tr:hover {
  background: var(--surface-sunken);
}

.grid td.tick,
.grid th.tick {
  width: 28px;
  padding-right: 0;
}

.grid input[type='checkbox'] {
  width: auto;
  margin: 0;
}

/* ------------------------------------------------- filters, bulk actions */

.filters,
.bulkbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin: var(--s4) 0;
}

.filters input,
.filters select,
.bulkbar select {
  width: auto;
  min-width: 160px;
  margin-top: 0;
}

label.inline {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  margin: 0 0 var(--s2);
}

label.inline input,
label.inline select {
  width: auto;
  margin-top: 0;
}

label.check {
  font-weight: 400;
}

label.check input {
  width: auto;
}

.pager {
  display: flex;
  justify-content: space-between;
  gap: var(--s4);
  margin: var(--s4) 0 0;
  padding-top: var(--s3);
  border-top: 1px solid var(--line);
  font-size: 15px;
}

form.danger {
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}

.record .muted.mono {
  max-width: 45%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ------------------------------------------------------- template editor */

textarea.code {
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
  tab-size: 2;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
  resize: vertical;
  background: var(--surface-sunken);
}

/*
 * The preview is tenant-authored HTML in a sandboxed frame, so it cannot be
 * measured from here — a fixed tall box with its own scrollbar is the honest
 * option, and it matches how the email will actually be read: in a window.
 *
 * It stays WHITE in dark mode on purpose: it shows what the recipient will get,
 * and a dark-themed preview of an email that will arrive light is a lie.
 */
iframe.preview {
  display: block;
  width: 100%;
  height: 640px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color-scheme: light;
}

label.inline input[type='color'] {
  width: 44px;
  height: 34px;
  padding: 2px;
}

/*
 * Two `label.inline`s in a row are inline-flex boxes with no whitespace
 * between them (JSX eats it), so they need an explicit gap or they read as one
 * run-on label.
 */
.swatches {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s6);
  margin-bottom: var(--s2);
}

.swatches label.inline {
  margin-bottom: 0;
}

/* Maintenance actions on an already-configured thing. Collapsed by default:
   an empty input with a Save button beside it reads as unfinished setup no
   matter how the label is worded, which is exactly how the stored signing
   secret was misread. */
.reveal {
  margin-top: var(--s4);
  border-top: 1px solid var(--line);
  padding-top: var(--s3);
}

/* The rule exists to separate maintenance from the setup above it. When the
   reveal IS the card's only content there is nothing to separate, and the
   border reads as an empty section. */
.card > .reveal:first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.reveal > summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 14px;
  padding: 6px 0;
}

.reveal > summary:hover {
  color: var(--ink);
}

.reveal[open] > summary {
  margin-bottom: var(--s2);
}

/* -------------------------------------------------------------- sign-in */

/*
 * The handover code, read off one screen and typed into another. Big, spaced
 * and monospaced because that is the whole job: someone is holding a phone at
 * arm's length copying six characters. The alphabet already excludes I, O, 0
 * and 1 (src/lib/cross-browser.ts); this makes what remains unambiguous too.
 */
.handover-code {
  display: inline-block;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  background: var(--accent-soft);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--s3) var(--s4);
  margin: var(--s2) 0 var(--s4);
}

/* ------------------------------------------- the nav's own breakpoint ---- */

/*
 * 1040px, and it is NOT the phone breakpoint — the two are separate on purpose.
 * Eight nav links plus "Log out" plus the theme control measure ~1000px on one
 * row even with the tenant line hidden, so below that the bar overflowed and
 * took the whole page sideways with it. This breakpoint is set by what the
 * navigation actually measures; everything else on the page is still
 * comfortable down to ~700px and is handled in the block after this one.
 */
@media (max-width: 1040px) {
  .topbar {
    flex-wrap: wrap;
    gap: var(--s2);
  }

  .navtoggle {
    display: inline-flex;
  }

  /* The nav drops to its own row (order 3), so these two are what sits on the
     right of the top row. */
  .themetoggle {
    margin-left: auto;
  }

  /* Only the signed-in nav collapses. The signed-out one is two short links and
     fits on a phone as it is — hiding it behind a hamburger would put the login
     link one tap further away for no gain. */
  .topbar nav.mainnav {
    display: none;
    order: 3;
    width: 100%;
    margin-left: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--s2) 0 var(--s3);
    border-top: 1px solid var(--line);
  }

  .topbar nav.mainnav.is-open {
    display: flex;
  }

  .topbar nav.mainnav a {
    padding: 11px 2px;
    font-size: 16px;
    border-bottom: 1px solid var(--line);
  }

  .topbar nav.mainnav a:hover {
    border-bottom-color: var(--line);
  }

  .topbar .who {
    padding: 11px 2px 0;
    white-space: normal;
  }
}

/* ------------------------------------------------------------- phone ---- */

@media (max-width: 700px) {
  main {
    margin: var(--s4) auto var(--s5);
    padding: 0 var(--s4);
  }

  .card {
    padding: var(--s4);
    border-radius: var(--radius-sm);
  }

  h1 {
    font-size: 21px;
  }

  .topbar {
    padding: var(--s2) var(--s4);
  }

  .tile-head,
  .record-head,
  .copyfield-head {
    flex-wrap: wrap;
  }

  .rows div {
    flex-direction: column;
    gap: 2px;
  }

  .rows dd {
    text-align: left;
  }

  .record .muted.mono {
    max-width: 100%;
  }

  .filters input,
  .filters select,
  .bulkbar select {
    width: 100%;
    min-width: 0;
  }

  .stats {
    gap: var(--s4) var(--s5);
  }

  /*
   * Inside a scroll container, let the cells keep their natural width instead
   * of compressing to fit. Without this a table squeezes its widest column
   * until an email address wraps to one word per line and the row is unreadable
   * — the scrollbar exists precisely so that does not have to happen. A table
   * whose content does fit (the 3-column domain list) is unaffected.
   */
  .tablewrap .grid th,
  .tablewrap .grid td {
    white-space: nowrap;
  }

  iframe.preview {
    height: 420px;
  }

  /* Anything tappable clears 44px. */
  button,
  a.button,
  button.copy,
  .iconbtn {
    min-height: 44px;
  }

  button.copy,
  .iconbtn {
    min-width: 44px;
  }
}
