/* RebelText operator console.
 *
 * One stylesheet, no build step, no framework. The look follows rebeltext.com:
 * a black ground, cream type, the brand red as the one loud colour, condensed
 * uppercase headings over monospace body text, square corners and hard offset
 * shadows instead of soft ones.
 *
 * Dark is the default because it is the site's look. Light swaps the black
 * ground for the site's cream and keeps the red, and it applies when the OS
 * asks for it or the operator picks it from the top bar (admin.js sets
 * data-theme on <html>). Only tokens change between the two; nothing below the
 * token blocks names a colour that assumes one ground or the other.
 *
 * The CSP is default-src 'self', so the site's web fonts cannot be pulled from
 * Google. The stacks name them first (they are used when installed, or once the
 * files are vendored under /static) and fall back to the nearest system faces. */

:root {
  color-scheme: dark;

  --bg: #000000;
  --surface: #0e0e0e;
  --surface-2: #141414;
  --input: #1b1b1a;
  --border: rgb(255 255 255 / 8%);
  --border-strong: rgb(234 229 205 / 16%);
  --text: #eae5cd;
  --muted: #888880;
  --faint: #525252;

  --primary: #ed462d;
  --primary-hover: #d83c1f;
  --primary-dark: #da3921;
  --rose: #f0b0a6;

  --accent: var(--primary);
  --accent-text: #000000;
  /* Type on a slab filled with --text: primary buttons, the console tag. */
  --on-text: #000000;
  --topbar: rgb(0 0 0 / 92%);
  --login-card: #000000;
  --login-shadow: rgb(0 0 0 / 25%);

  /* Status tints. Red is the brand, so "wrong" is carried by the rose text on a
     dark red wash rather than by the button red itself. */
  --danger: #ff6b55;
  --danger-bg: rgb(237 70 45 / 12%);
  --ok-bg: rgb(110 231 168 / 9%);
  --ok-text: #8fdcaa;
  --warn-bg: rgb(245 194 107 / 10%);
  --warn-text: #f0c674;
  --info-bg: rgb(234 229 205 / 7%);
  --info-text: #d8d3ba;

  --shadow: 6px 6px 0 0 #262626;
  --shadow-cream: 4px 4px 0 0 rgb(234 229 205 / 16%);
  --radius: 0;

  --font-heading: "Barlow Semi Condensed", "Avenir Next Condensed", "Roboto Condensed",
    "Arial Narrow", "Helvetica Neue", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
}

/* The light palette, twice: once for an OS that prefers light and has not been
   overridden to dark, once for an explicit choice of light. CSS has no way to
   share one block between a media query and an attribute selector. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --bg: #f1eee0;
    --surface: #faf8f0;
    --surface-2: #ebe7d4;
    --input: #ffffff;
    --border: rgb(14 14 14 / 9%);
    --border-strong: rgb(14 14 14 / 18%);
    --text: #111110;
    --muted: #62605a;
    --faint: #a29f93;
    --rose: #b8321c;
    --on-text: #eae5cd;

    --danger: #c2321b;
    --danger-bg: rgb(237 70 45 / 10%);
    --ok-bg: rgb(22 120 70 / 9%);
    --ok-text: #1d6e42;
    --warn-bg: rgb(180 110 0 / 10%);
    --warn-text: #8a5300;
    --info-bg: rgb(14 14 14 / 5%);
    --info-text: #3b3a35;

    --shadow: 6px 6px 0 0 #d6d1b8;
    --topbar: rgb(241 238 224 / 92%);
    --login-card: #faf8f0;
    --login-shadow: rgb(0 0 0 / 18%);
  }
}

:root[data-theme="light"] {
  color-scheme: light;

  --bg: #f1eee0;
  --surface: #faf8f0;
  --surface-2: #ebe7d4;
  --input: #ffffff;
  --border: rgb(14 14 14 / 9%);
  --border-strong: rgb(14 14 14 / 18%);
  --text: #111110;
  --muted: #62605a;
  --faint: #a29f93;
  --rose: #b8321c;
  --on-text: #eae5cd;

  --danger: #c2321b;
  --danger-bg: rgb(237 70 45 / 10%);
  --ok-bg: rgb(22 120 70 / 9%);
  --ok-text: #1d6e42;
  --warn-bg: rgb(180 110 0 / 10%);
  --warn-text: #8a5300;
  --info-bg: rgb(14 14 14 / 5%);
  --info-text: #3b3a35;

  --shadow: 6px 6px 0 0 #d6d1b8;
  --topbar: rgb(241 238 224 / 92%);
  --login-card: #faf8f0;
  --login-shadow: rgb(0 0 0 / 18%);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 13px/1.6 var(--font-mono);
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--primary); color: #000; }

code {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted);
}

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

/* ── Top bar ─────────────────────────────────────────────────────────────── */

/* The site's header sits on the red hero. The console keeps the red as a thin
   rule under a plain bar: the brand is present on every page without a slab of
   colour competing with the tables below it. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 0 32px;
  height: 64px;
  background: var(--topbar);
  border-bottom: 1px solid var(--border);
  box-shadow: inset 0 3px 0 var(--primary);
  backdrop-filter: blur(8px);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 20px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}

.brand img { width: 20px; height: 24px; display: block; }

.brand span {
  padding: 2px 6px;
  margin-left: 2px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--on-text);
  background: var(--text);
}

.topbar nav {
  display: flex;
  gap: 4px;
  margin-right: auto;
}

.topbar nav a {
  padding: 8px 12px;
  color: var(--muted);
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 2px solid transparent;
}

.topbar nav a:hover { color: var(--text); }
.topbar nav a.active { color: var(--text); border-bottom-color: var(--primary); }

.signout { display: flex; align-items: center; gap: 14px; margin: 0; }
.who { color: var(--muted); font-size: 12px; }

@media (max-width: 860px) {
  .topbar { flex-wrap: wrap; height: auto; padding: 12px 16px; gap: 8px 16px; }
  .topbar nav { order: 3; width: 100%; overflow-x: auto; margin-right: 0; }
  .signout { margin-left: auto; }
  .who { display: none; }
}

/* The theme toggle cycles auto → light → dark. It is rendered hidden and
   admin.js reveals it, so without script there is no button that does
   nothing. */
.theme-toggle { min-width: 76px; }

/* ── Layout ──────────────────────────────────────────────────────────────── */

main {
  max-width: 1160px;
  margin: 0 auto;
  padding: 40px 32px 80px;
}

/* The signed-out shell: the site's red hero with its faint diagonal grid, and
   the sign-in card sitting on it like the site's black call-to-action. */
body:has(main.centered) {
  background:
    repeating-linear-gradient(45deg, rgb(0 0 0 / 5%) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(-45deg, rgb(0 0 0 / 5%) 0 1px, transparent 1px 64px),
    var(--primary);
}

main.centered {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100vh;
  max-width: 440px;
}

h1, h2, h3 {
  font-family: var(--font-heading);
  text-transform: uppercase;
  line-height: 1.05;
  color: var(--text);
}

h1 { font-size: 40px; font-weight: 800; letter-spacing: -0.005em; margin: 0 0 24px; }
h2 { font-size: 20px; font-weight: 700; letter-spacing: 0.02em; margin: 0 0 14px; }

/* A muted aside inside a heading is a qualifier, not part of the title. */
h1 .muted, h2 .muted {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.05em;
  text-transform: none;
}

section { margin-bottom: 44px; }

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}

.section-head h1, .section-head h2 { margin: 0; }
.section-head h1 + .pill { margin-right: auto; }
.section-head > .muted { font-size: 12px; }

.more {
  color: var(--primary);
  text-decoration: none;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.more:hover { color: var(--text); }

.muted { color: var(--muted); }
.right { text-align: right; }
.negative { color: var(--danger); }

.empty {
  padding: 36px;
  text-align: center;
  color: var(--muted);
  background: var(--surface);
  border: 1px dashed var(--border-strong);
}

/* ── Stats ───────────────────────────────────────────────────────────────── */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow);
}

/* Tiles share borders like the site's feature grid rather than floating as
   separate cards. */
.stat {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 20px 22px;
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  margin: 0 -1px -1px 0;
}

.stat:first-child { box-shadow: inset 3px 0 0 var(--primary); }

.stat-value {
  font-family: var(--font-heading);
  font-size: 34px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.stat-label {
  order: -1;
  color: var(--muted);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ── Tables ──────────────────────────────────────────────────────────────── */

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--border-strong);
}

th, td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

th {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--bg);
  border-bottom-color: var(--border-strong);
}

tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--surface-2); }

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

.name { display: block; font-weight: 500; color: var(--text); }

/* ── Pills ───────────────────────────────────────────────────────────────── */

/* The site's small tag: square, mono, uppercase, tracked out. */
.pill {
  display: inline-block;
  padding: 2px 8px;
  border: 1px solid currentcolor;
  font-size: 10px;
  font-weight: 500;
  line-height: 1.6;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.pill-active { background: var(--ok-bg); color: var(--ok-text); }
.pill-suspended { background: var(--warn-bg); color: var(--warn-text); }
.pill-closed { background: var(--danger-bg); color: var(--danger); }

/* ── Forms ───────────────────────────────────────────────────────────────── */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 20px;
  align-items: center;
}

input, select, button {
  font: inherit;
  padding: 9px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 0;
  background: var(--input);
  color: var(--text);
}

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

input:hover, select:hover, textarea:hover { border-color: rgb(234 229 205 / 30%); }

input[type="search"] { flex: 1; min-width: 0; }
input[type="checkbox"] { accent-color: var(--primary); }

input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}

button:focus-visible, a:focus-visible, summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* The site's call-to-action: a solid slab with a hard offset shadow that the
   button presses into on hover. Primary buttons are cream so the brand red stays
   free to mean "this one is destructive". */
button {
  background: var(--text);
  color: var(--on-text);
  border-color: transparent;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 4px 4px 0 0 var(--primary);
  transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
}

button:hover { transform: translate(2px, 2px); box-shadow: 2px 2px 0 0 var(--primary); }
button:active { transform: translate(4px, 4px); box-shadow: none; }

.signout button, .theme-toggle {
  background: transparent;
  color: var(--muted);
  border-color: var(--border-strong);
  font-weight: 500;
  font-size: 11px;
  padding: 6px 12px;
  box-shadow: none;
}

.signout button:hover, .theme-toggle:hover { color: var(--text); border-color: var(--text); transform: none; }

.clear {
  color: var(--muted);
  text-decoration: none;
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 0 8px;
}

.clear:hover { color: var(--text); }

/* ── Login ───────────────────────────────────────────────────────────────── */

.card {
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow);
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 20px;
  color: var(--text);
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 26px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.login-brand img { width: 26px; height: 30px; display: block; }

.login {
  background: var(--login-card);
  border: 0;
  padding: 36px;
  box-shadow: 12px 12px 0 0 var(--login-shadow);
}

.login h1 { font-size: 44px; margin-bottom: 8px; }
.login .muted { font-size: 12px; margin: 0 0 22px; }

.login form { display: flex; flex-direction: column; gap: 6px; }

.login label, .card label {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 10px;
}

.login button { margin-top: 24px; padding: 13px; font-size: 13px; }

.error, .flash-ok {
  padding: 12px 16px;
  margin: 0 0 20px;
  border: 1px solid currentcolor;
  border-left-width: 4px;
  font-size: 12px;
}

.error { background: var(--danger-bg); color: var(--danger); }
.flash-ok { background: var(--ok-bg); color: var(--ok-text); }

/* On the red login ground a tinted alert disappears; it needs to be solid. */
main.centered .error { background: var(--login-card); color: var(--rose); border-color: var(--login-card); }

/* ── Pager ───────────────────────────────────────────────────────────────── */

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  margin-top: 20px;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.pager a { color: var(--text); text-decoration: none; border-bottom: 1px solid var(--primary); }
.pager a:hover { color: var(--primary); }
.pager .disabled { color: var(--faint); }

/* ── Detail pages ────────────────────────────────────────────────────────── */

.crumbs {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.crumbs span { color: var(--faint); }
.crumbs a { color: var(--primary); text-decoration: none; }
.crumbs a:hover { color: var(--text); }

.subtitle { margin: -14px 0 28px; max-width: 760px; }
.section-head + .subtitle { margin-top: 6px; }

.small { font-size: 11px; }
.warn { color: var(--warn-text); }
.wrap { word-break: break-all; }

td a { color: var(--text); text-decoration: none; }
td a .name, td a code { border-bottom: 1px solid transparent; }
td a:hover .name, td a:hover code, td a:hover { color: var(--primary); }

p a, .notfound a { color: var(--primary); text-decoration: none; }
p a:hover, .notfound a:hover { color: var(--text); }

/* A second table directly under another reads as one continuous section. */
table.stacked { margin-top: 14px; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }

.chip {
  padding: 8px 14px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

.chip strong {
  margin-right: 4px;
  font-family: var(--font-heading);
  font-size: 18px;
  font-weight: 800;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Key/value table for a single record, rather than the column layout used for
   lists. */
table.kv th {
  width: 200px;
  background: transparent;
  vertical-align: top;
  border-bottom-color: var(--border);
  padding-top: 14px;
}

table.kv tbody tr:hover { background: transparent; }

pre.body {
  margin: 0;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--primary);
  white-space: pre-wrap;
  word-break: break-word;
  font-family: var(--font-mono);
  font-size: 13px;
}

.notfound { text-align: center; }
.notfound h1 { font-size: 72px; }

/* ── Status pills ────────────────────────────────────────────────────────── */

/* Message lifecycle. Grouped by what an operator needs to notice: settled and
   fine, still moving, or wrong. */
.pill-msg-delivered, .pill-msg-sent { background: var(--ok-bg); color: var(--ok-text); }
.pill-msg-accepted, .pill-msg-queued, .pill-msg-sending,
.pill-msg-scheduled { background: var(--info-bg); color: var(--info-text); }
.pill-msg-failed, .pill-msg-undelivered,
.pill-msg-rejected { background: var(--danger-bg); color: var(--danger); }
.pill-msg-canceled { background: transparent; color: var(--muted); }

/* Webhook delivery. */
.pill-pending, .pill-sending { background: var(--info-bg); color: var(--info-text); }
.pill-delivered { background: var(--ok-bg); color: var(--ok-text); }
.pill-failed, .pill-dead { background: var(--danger-bg); color: var(--danger); }
.pill-disabled { background: var(--warn-bg); color: var(--warn-text); }

/* 10DLC registration. Approved is the only state that carries traffic. */
.pill-reg-approved { background: var(--ok-bg); color: var(--ok-text); }
.pill-reg-draft { background: transparent; color: var(--muted); }
.pill-reg-submitted, .pill-reg-pending { background: var(--info-bg); color: var(--info-text); }
.pill-reg-failed, .pill-reg-expired,
.pill-reg-suspended { background: var(--danger-bg); color: var(--danger); }

.pill-ledger { background: transparent; color: var(--muted); }
.pill-released, .pill-quarantined { background: var(--warn-bg); color: var(--warn-text); }

/* Volt webhook log. Applied is the only outcome that changed a message; quiet
   outcomes are routine, amber ones deserve a look, red ones were refused or
   broke. */
.pill-volt-applied { background: var(--ok-bg); color: var(--ok-text); }
.pill-volt-ignored, .pill-volt-not_receipt { background: transparent; color: var(--muted); }
.pill-volt-foreign_message { background: var(--info-bg); color: var(--info-text); }
.pill-volt-unknown_message, .pill-volt-unparseable { background: var(--warn-bg); color: var(--warn-text); }
.pill-volt-rejected, .pill-volt-error,
.pill-volt-bad_request { background: var(--danger-bg); color: var(--danger); }

.log-body summary { cursor: pointer; font-size: 11px; }
.log-body pre {
  text-align: left;
  white-space: pre-wrap;
  word-break: break-all;
  max-width: 560px;
  max-height: 420px;
  overflow: auto;
  margin: 8px 0 0;
  font-size: 11px;
}

/* ── Actions ─────────────────────────────────────────────────────────────── */

.actions { display: flex; flex-direction: column; gap: 16px; }

.action {
  padding: 20px 22px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
}

.action h3 { margin: 0 0 6px; font-size: 18px; font-weight: 700; letter-spacing: 0.02em; }
.action .small { margin: 0 0 14px; }

.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  margin: 0 0 10px;
}

.action-row:last-child { margin-bottom: 0; }
.action-row input[type="text"] { flex: 1; min-width: 200px; }
.action-row input[type="number"] { width: 140px; }

/* A row whose inputs are not self-explanatory gets a caption over each one.
   Bottom-aligned so the uncaptioned inputs and the button sit on the same line
   as the captioned ones. */
.action-row.fields { align-items: flex-end; }

.field { display: flex; flex-direction: column; gap: 6px; }

.field > span {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* A checkbox needs its label beside it rather than above, and needs to sit on
   the same baseline as the inputs it shares a row with. */
.check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

.card label.check { font-size: 12px; letter-spacing: 0; text-transform: none; }

.check input { margin: 0; }

/* ── Editable rows ───────────────────────────────────────────────────────── */

/* Some tables are also forms: a brand's name and status are edited where they
   are read, rather than on a separate page that would show the same six fields
   with nothing else on it. A <form> cannot wrap table cells, so each row's form
   element sits in one cell and its inputs reach it by id — which means the
   controls must be sized down to look like table content rather than like a
   form dropped into a table. */
td input[type="text"], td select {
  width: 100%;
  min-width: 90px;
  padding: 5px 8px;
  font-size: 12px;
}

td input[type="text"] + code { display: block; margin-top: 4px; }
td .muted.small { display: block; }

/* An editable row ends in a cell holding a save button beside whatever else
   acts on that row. Those neighbours are usually forms, which are block boxes —
   so without a flex container here the button takes one line and each form
   takes another, and a one-line row stands up three lines tall. */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

/* Save and Quarantine do very different things, and a 6px gap between a benign
   button and a destructive one is a misclick waiting to happen. */
.row-actions .danger-group { margin-left: 20px; }

/* A table carrying form controls has a floor its cells cannot compress past —
   a select has to show enough of a campaign name to pick by. Below that width
   the table overflows, and what falls off the right edge is the actions column:
   the operator loses the buttons rather than a column of digits they could
   guess at. Scrolling the table keeps them reachable. */
.table-scroll { overflow-x: auto; }

/* Destructive actions sit behind a disclosure. The CSP forbids inline script,
   so there is no confirm() to lean on — an explicit expand plus a mandatory
   reason is the friction instead, and it leaves a better audit row than a
   dialog would. */
details.danger summary {
  cursor: pointer;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--primary);
}

details.danger[open] summary { margin-bottom: 10px; }
details.danger {
  border-color: rgb(237 70 45 / 45%);
  background:
    repeating-linear-gradient(-45deg, rgb(237 70 45 / 4%) 0 10px, transparent 10px 20px),
    var(--surface);
}

button.destructive {
  background: var(--primary);
  color: #000;
  box-shadow: 4px 4px 0 0 var(--text);
}

button.destructive:hover { background: var(--primary-hover); box-shadow: 2px 2px 0 0 var(--text); }

button.small-btn, a.small-btn {
  padding: 5px 10px;
  font-size: 11px;
  box-shadow: 3px 3px 0 0 var(--primary);
}

button.small-btn:hover { box-shadow: 1px 1px 0 0 var(--primary); transform: translate(2px, 2px); }
button.destructive.small-btn { box-shadow: 3px 3px 0 0 var(--text); }
button.destructive.small-btn:hover { box-shadow: 1px 1px 0 0 var(--text); }

/* A link dressed as a button, for actions that navigate rather than post. */
a.small-btn {
  display: inline-block;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--on-text);
  background: var(--text);
}

a.small-btn:hover { color: var(--on-text); }

/* ── Tabs ────────────────────────────────────────────────────────────────── */

/* Each tab is a link to ?tab=, not a CSS or script toggle: the URL is the
   state, so a tab can be linked into a ticket and the back button works. */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  margin: 0 0 32px;
  border-bottom: 1px solid var(--border-strong);
}

.tab {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  color: var(--muted);
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}

.tab:hover { color: var(--text); }

.tab.active {
  color: var(--text);
  border-bottom-color: var(--primary);
}

.tab-count {
  padding: 0 6px;
  background: var(--input);
  border: 1px solid var(--border-strong);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}

.tab.active .tab-count {
  background: var(--primary);
  border-color: transparent;
  color: #000;
}

/* The mutating tab is set apart from the read-only ones. */
.tab-danger { color: var(--primary); margin-left: auto; }
.tab-danger:hover { color: var(--rose); }
.tab-danger.active { color: var(--primary); }

@media (max-width: 700px) {
  main { padding: 28px 16px 64px; }
  h1 { font-size: 32px; }
  .tabs { flex-wrap: nowrap; overflow-x: auto; }
  .tab-danger { margin-left: 0; }
}

/* An action that needs one field alongside its button, inside a table cell. */
.inline-form { display: flex; gap: 8px; justify-content: flex-end; }
.inline-form input[type="text"] { width: 130px; padding: 5px 8px; font-size: 11px; }

/* ── Deliverability trace ────────────────────────────────────────────────── */

textarea {
  font: inherit;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 0;
  background: var(--input);
  color: var(--text);
  resize: vertical;
}

textarea.mono { font-family: var(--font-mono); font-size: 12px; }

.card h2 { margin-bottom: 6px; }
.card form { display: flex; flex-direction: column; gap: 6px; }
.card .small { margin: 2px 0 0; }
.card button { align-self: flex-start; margin-top: 22px; padding: 12px 22px; }

/* Volt webhooks. Event checkboxes wrap in one row under their legend, and each
   table row's delete stays a quiet disclosure rather than a card in a cell. */
.card fieldset { border: 0; padding: 0; margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 8px 18px; }
.card fieldset legend {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0;
  margin-bottom: 8px;
}
.card fieldset .check { margin-top: 0; }
.table-scroll + .card, .empty + .card { margin-top: 32px; }
td details.row-delete { display: inline-block; margin-left: 10px; text-align: left; }
td details.row-delete summary {
  cursor: pointer;
  font-size: 11px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--primary);
}
td details.row-delete[open] { display: block; margin: 10px 0 0; }
td details.row-delete button { margin-top: 8px; }
.volt-form { margin-bottom: 28px; }

/* Customer webhook endpoints on the account page. The secret banner is the one
   place a credential is printed, so it is selectable in one click and scrolls
   rather than wrapping mid-token. */
.event-picker { border: 0; padding: 0; margin: 4px 0 12px; display: flex; flex-wrap: wrap; gap: 6px 16px; }
.event-picker legend { font-size: 13px; font-weight: 500; padding: 0; margin-bottom: 6px; }
.secret-once {
  padding: 12px 16px;
  margin: 0 0 20px;
  background: var(--ok-bg);
  color: var(--ok-text);
  border: 1px solid currentcolor;
  border-left-width: 4px;
}
.secret-once h2 { margin: 0 0 4px; font-size: 16px; color: inherit; }
.secret-once .secret {
  display: block;
  overflow-x: auto;
  white-space: nowrap;
  user-select: all;
  padding: 8px 10px;
  color: var(--text);
  background: var(--input);
  border: 1px solid var(--border-strong);
}

/* The live banner is the page saying it is still watching. Paired with the meta
   refresh, which is what actually reloads. */
.live {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  margin: 0 0 24px;
  background: var(--info-bg);
  color: var(--info-text);
  border: 1px solid var(--border-strong);
  border-left: 4px solid var(--primary);
  font-size: 12px;
}

.live-dot {
  width: 8px;
  height: 8px;
  background: var(--primary);
  flex: none;
  animation: pulse 1.4s ease-in-out infinite;
}

@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* Respect a reduced-motion preference: the dot is decoration, and the banner
   still reads correctly without it moving. The buttons' press is decoration
   too. */
@media (prefers-reduced-motion: reduce) {
  .live-dot { animation: none; }
  button, button:hover, button:active { transition: none; transform: none; }
}

/* ── Timeline ────────────────────────────────────────────────────────────── */

.timeline {
  list-style: none;
  margin: 0;
  padding: 22px 22px 4px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
}

.tl {
  position: relative;
  display: flex;
  gap: 16px;
  padding: 0 0 20px 0;
}

/* The connecting rail, drawn from each marker down to the next. The last item
   does not get one, or the timeline would trail off into nothing. */
.tl::before {
  content: "";
  position: absolute;
  left: 5px;
  top: 16px;
  bottom: 0;
  width: 1px;
  background: var(--border-strong);
}

.tl:last-child::before { display: none; }

.tl-marker {
  position: relative;
  z-index: 1;
  flex: none;
  width: 11px;
  height: 11px;
  margin-top: 5px;
  background: var(--surface);
  border: 2px solid var(--muted);
}

.tl-ok .tl-marker { border-color: var(--ok-text); background: var(--ok-text); }
.tl-problem .tl-marker { border-color: var(--primary); background: var(--primary); }

.tl-pending .tl-marker { border-style: dashed; border-color: var(--faint); }
.tl-pending .tl-label { font-style: italic; }

.tl-body { flex: 1; min-width: 0; }

.tl-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
}

.tl-label {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.tl-stage {
  padding: 0 7px;
  background: var(--input);
  border: 1px solid var(--border-strong);
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.05em;
}

.tl-at { font-size: 11px; margin-left: auto; }

.tl-detail {
  font-size: 12px;
  margin-top: 3px;
  word-break: break-word;
}

.live-action {
  margin-left: auto;
  color: var(--text);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
  text-decoration: none;
  border-bottom: 1px solid var(--primary);
}

/* ── Loading ─────────────────────────────────────────────────────────────── */

/* Set by admin.js on the button that submitted a form, until the next page
   replaces this one. The label is hidden rather than swapped so the button
   keeps its width and the row does not jump. The spinner is square, like
   everything else here, and takes the colour the label would have had. */
button[data-loading], a.small-btn[data-loading] {
  --spin: var(--on-text);
  position: relative;
  color: transparent !important;
  cursor: progress;
  pointer-events: none;
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 0 var(--primary);
}

button.destructive[data-loading] { --spin: #000; box-shadow: 2px 2px 0 0 var(--text); }
.signout button[data-loading] { --spin: var(--muted); transform: none; box-shadow: none; }

button[data-loading]::after, a.small-btn[data-loading]::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 12px;
  height: 12px;
  margin: auto;
  border: 2px solid var(--spin);
  border-right-color: transparent;
  animation: spin 0.7s linear infinite;
}

/* A disabled button would otherwise fade, which reads as "not allowed" rather
   than "working on it". */
button[data-loading]:disabled { opacity: 1; }

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  button[data-loading]::after, a.small-btn[data-loading]::after { animation-duration: 2s; }
}

.live-held { background: var(--warn-bg); color: var(--warn-text); border-left-color: var(--warn-text); }
