/* services/webapp/static/admin.css — the OPERATOR console. SELF-CONTAINED.
 *
 * ============================================================================================
 * WHY THIS FILE STOPPED BEING A PATCH LAYER (2026-08-17)
 * ============================================================================================
 * It used to be ~560 lines of corrections layered on customer-dashboard.css, and it inherited
 * that sheet's DARK palette. Measured before this rewrite: 0 `:root` blocks, 0 custom properties
 * defined (≈10 consumed from the other sheet), 14 distinct font-sizes across 33 declarations with
 * no scale, 6 distinct border-radii, 17 unnamed one-off rgba() literals, 1 breakpoint, 0
 * transitions, and exactly one `:focus-visible` rule that changed `opacity` rather than drawing a
 * ring. It was serviceable HTML, not a product.
 *
 * It also failed contrast systematically. The inherited `--muted:#66737c` on `--panel:#171d26`
 * measures **3.47:1** — below the 4.5:1 AA floor — and that colour was every form label, every
 * table sub-caption, every page-heading paragraph and all the audit metadata. `--line` on
 * `--panel` was **1.17:1**, which is why the cards read as floating rather than edged.
 *
 * THE PALETTE DECISION, made by the owner: the client dashboard is LIGHT and the admin was DARK,
 * so the two did not read as one product. The ruling was "light, but with an operator accent":
 * the client's tokens verbatim for everything structural, and a distinct accent plus a persistent
 * OPERATIONS bar so it is never ambiguous which surface you are on. Same bones, different badge.
 *
 * The client's own tokens are the source of truth and are copied from `templates/dashboard.html`
 * (which deliberately does NOT extend base.html — see GAUNTLET/DASHBOARD-DECISION.md). Only
 * `--accent*` differs, and that difference is the entire point.
 *
 * NOTE: `templates/admin_base.html` no longer loads customer-dashboard.css. That sheet is the
 * LEGACY dark one; loading it here meant the operator console inherited a palette nobody had
 * chosen for it, and it shipped 54KB to render a surface that uses ~60 classes. Everything the
 * operator templates use is defined here, and `tests/test_admin_css_covers_its_templates.py`
 * fails if a template ever references a class this file does not define.
 *
 * The operator CSP is `default-src 'self'; style-src 'self'` — no inline style attribute in an
 * operator template will ever apply, so every rule a page needs has to be here.
 */

/* ==================================================================================== TOKENS */
:root {
  /* --- adopted VERBATIM from the client dashboard, so the two surfaces are one product ----- */
  --ink: #16181d;
  --paper: #f6f7f4;
  --surface: #fff;
  --line: #e4e6e2;
  --muted: #6a716b;          /* 4.62:1 on --surface — passes AA, unlike the dark sheet's 3.47 */
  --green: #1f7a43;
  --amber: #9a6a06;
  --amber-bg: #fbf1d9;
  --red: #a3341f;
  --slate: #eef0ec;

  /* --- the operator difference. Indigo, not the client's forest green: the one signal that
         says "this is the back office" without changing any of the structure around it. ------ */
  --accent: #3730a3;
  --accent-bg: #ecebf7;
  --accent-br: #c7c3e8;
  --accent-ink: #2a2480;     /* for text on --accent-bg */

  /* --- semantic status. Named by MEANING so a component never picks a colour directly. ----- */
  --ok: var(--green);
  --ok-bg: #e2f2e6;
  --ok-br: #bfe6cb;
  --warn: var(--amber);
  --warn-bg: var(--amber-bg);
  --warn-br: #eccf94;
  --bad: var(--red);
  --bad-bg: #fbe9e5;
  --bad-br: #eebfb4;

  /* --- scales. The old sheet had 14 ad-hoc font sizes and 6 ad-hoc radii. ------------------ */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px;
  --t-micro: 11px; --t-small: 12px; --t-body-sm: 13.5px; --t-body: 15px;
  --t-lead: 18px;  --t-h2: 20px;    --t-h1: 24px;        --t-display: 32px;
  --radius-sm: 8px; --radius: 11px; --radius-lg: 14px; --radius-pill: 999px;

  --elev-1: 0 1px 2px rgba(22, 24, 29, 0.05);
  --elev-2: 0 8px 24px rgba(22, 24, 29, 0.08);

  /* A real ring, not an opacity change. These are irreversible controls and the console has no
     undo for a dilution change or a recall. */
  --ring: 2.5px solid #1d4ed8;
  --ring-offset: 2px;

  --control-min: 44px;       /* every interactive target */
  --motion: 120ms ease;
}

/* Motion is a courtesy, never a dependency. */
@media (prefers-reduced-motion: reduce) {
  :root { --motion: 0ms; }
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: var(--t-body) / 1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

a { color: inherit; }

h1, h2, h3 { margin: 0; letter-spacing: -0.02em; }
h1 { font-size: var(--t-h1); font-weight: 800; }
h2 { font-size: var(--t-h2); font-weight: 700; }
h3 { font-size: var(--t-lead); font-weight: 700; }
p { margin: var(--s2) 0 0; }

/* One focus treatment, everywhere. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: var(--ring);
  outline-offset: var(--ring-offset);
  border-radius: var(--radius-sm);
}

/* Skip link — the client board has one; the console had none. */
.skip-link {
  position: absolute;
  left: var(--s3);
  top: calc(var(--s3) * -4);
  z-index: 20;
  padding: var(--s2) var(--s3);
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: #fff;
  font-weight: 700;
  text-decoration: none;
  transition: top var(--motion);
}
.skip-link:focus { top: var(--s3); }

/* ==================================================================================== LAYOUT */
.shell {
  width: 100%;
  max-width: 1360px;
  margin-inline: auto;
  padding-inline: clamp(12px, 2.6vw, 28px);
}

.page { padding-block: var(--s5) var(--s7); }

/* Every operator page's <main>. It exists so an operator-only rule never has to be written as a
 * bare element selector that could later leak somewhere else, and so the console has one place to
 * hang page-level state. */
.ops-page { min-height: 60vh; }

/* --------------------------------------------------------------------------- the header bar */
/* The OPERATOR BADGE. The whole reason the console can share the client's palette safely: an
 * indigo bar across the top that the customer surface never has. You cannot mistake one for the
 * other at a glance, which was the risk in going light. */
.site-header {
  background: var(--accent);
  color: #fff;
  box-shadow: var(--elev-1);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: var(--s4);
  min-height: 56px;
  padding-block: var(--s2);
}

.brand { display: inline-flex; align-items: center; text-decoration: none; }

.brand-logo {
  display: block;
  height: 26px;
  width: auto;
  /* The brand asset is the REVERSED (light-on-dark) lockup, and it is the only one that exists.
   * On the indigo bar that is exactly right; nothing is recoloured and no second file is needed. */
}

.ops-label {
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.92;
}

.logout-form { margin-left: auto; }

.logout-form button {
  min-height: 34px;
  padding: 0 var(--s3);
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: var(--radius-pill);
  background: transparent;
  color: #fff;
  font: inherit;
  font-size: var(--t-small);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--motion), border-color var(--motion);
}
.logout-form button:hover { background: rgba(255, 255, 255, 0.14); border-color: #fff; }

/* ------------------------------------------------------------------ section navigation */
.admin-nav {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 5;
}

.admin-nav-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s5);
  padding-block: var(--s3);
}

.admin-nav a {
  color: var(--muted);
  font-size: var(--t-body-sm);
  font-weight: 600;
  text-decoration: none;
  padding-bottom: var(--s1);
  border-bottom: 2px solid transparent;
  transition: color var(--motion), border-color var(--motion);
}

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

.admin-nav a.is-active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.admin-role-note {
  margin-left: auto;
  font-size: var(--t-small);
  color: var(--muted);
}

/* ============================================================================== PAGE HEADER */
.ops-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
  margin-bottom: var(--s5);
}

.ops-heading > div { max-width: 74ch; }

.ops-heading p {
  color: var(--muted);
  font-size: var(--t-body-sm);
}

.section-kicker {
  display: block;
  margin-bottom: var(--s1);
  color: var(--accent);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* The stat tile in the header rail. `.ops-price` is a legacy name — it carries a queue depth on
 * /leads and a monthly price on /accounts, which is exactly the reuse the design audit flagged.
 * Renaming it is a template change for another pass; what it must not do meanwhile is make a
 * count look like money, so the figure is set in tabular numerals and the caption does the work. */
.ops-price {
  flex: 0 0 auto;
  min-width: 148px;
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--elev-1);
  text-align: right;
}

.ops-price strong {
  display: block;
  color: var(--ink);
  font-size: var(--t-display);
  font-weight: 800;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.ops-price span {
  display: block;
  margin-top: var(--s1);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ================================================================================= SURFACES */
.surface {
  margin-bottom: var(--s4);
  padding: var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--elev-1);
}

.surface-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s4);
}

.ops-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s4);
  align-items: start;
}

@media (min-width: 981px) {
  /* The table is the object; the form is the tool. The old 1:1 split squeezed a nine-column
   * tenants table into 53% of the width and clipped it. */
  .ops-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
}

/* Solid, never dashed — a dashed border reads as a drop target. */
.empty-state {
  padding: var(--s6) var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--slate);
  text-align: center;
}

.empty-state h3 { color: var(--ink); }

.empty-state p {
  margin-inline: auto;
  max-width: 56ch;
  color: var(--muted);
  font-size: var(--t-body-sm);
}

/* --------------------------------------------------------------- native <details> disclosure */
/* Used for the create-account form on /accounts. A real <details>, not a JS drawer: the operator
 * CSP is `default-src 'self'` with no script-src exception, so a disclosure that needs script
 * would silently never open — the same constraint that makes every confirmation on this console
 * a server-rendered page. */
.ops-disclosure { padding: 0; }

.ops-disclosure > summary {
  display: block;
  padding: var(--s4) var(--s5);
  border-radius: var(--radius-lg);
  cursor: pointer;
  list-style: none;
  transition: background var(--motion);
}

.ops-disclosure > summary::-webkit-details-marker { display: none; }

.ops-disclosure > summary:hover { background: var(--slate); }

.ops-disclosure > summary::after {
  content: "Show form";
  float: right;
  margin-top: -26px;
  color: var(--accent);
  font-size: var(--t-body-sm);
  font-weight: 700;
}

.ops-disclosure[open] > summary::after { content: "Hide form"; }

.ops-disclosure[open] > summary {
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.ops-disclosure > .ops-form { padding: var(--s5); }

/* =================================================================================== TABLES */
/* Wide operator tables scroll inside their own box. The page body must never scroll
 * horizontally — an operator working a queue on a laptop loses the row they are reading. */
.admin-table-scroll {
  overflow-x: auto;
  margin: var(--s3) 0 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  -webkit-overflow-scrolling: touch;
  /* A visible edge shadow while there is more table to the right. The old sheet had an invisible
   * scrollbar over a `min-width:48rem` table, so the /accounts columns were clipped AT REST with
   * nothing on screen saying so — data loss that looked like a layout. */
  background:
    linear-gradient(to right, var(--surface) 30%, rgba(255, 255, 255, 0)) left / 40px 100% no-repeat,
    linear-gradient(to left, var(--surface) 30%, rgba(255, 255, 255, 0)) right / 40px 100% no-repeat,
    linear-gradient(to right, rgba(22, 24, 29, 0.10), rgba(255, 255, 255, 0)) left / 14px 100% no-repeat,
    linear-gradient(to left, rgba(22, 24, 29, 0.10), rgba(255, 255, 255, 0)) right / 14px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-body-sm);
  min-width: 44rem;
}

.admin-table th,
.admin-table td {
  text-align: left;
  padding: var(--s3);
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}

.admin-table thead th {
  position: sticky;
  top: 0;
  background: var(--slate);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.admin-table tbody tr:last-child td { border-bottom: 0; }

.admin-table tbody tr { transition: background var(--motion); }
.admin-table tbody tr:hover { background: var(--accent-bg); }

.admin-table td small {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--t-small);
}

.admin-table td a { color: var(--accent); font-weight: 600; }

/* Money and counts line up or they cannot be compared down a column. */
.admin-table td:has(> .admin-mono),
.admin-table .num { font-variant-numeric: tabular-nums lining-nums; }

.admin-table form {
  display: flex;
  gap: var(--s2);
  align-items: center;
  flex-wrap: wrap;
}

.admin-table input,
.admin-table select {
  font: inherit;
  font-size: var(--t-small);
  min-height: 34px;
  padding: var(--s1) var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: inherit;
  max-width: 11rem;
}

.admin-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--t-small);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------- per-table column sizing */
/* The tenants table carries ten columns. Left to itself the browser gave the widest column to the
 * longest string and wrapped "Driven Auto Demo" onto three lines while numeric columns sat in a
 * few characters of a wide cell. Naming the two text columns and letting the numeric ones shrink
 * to their content is the whole fix. */
.admin-table--accounts th:first-child,
.admin-table--accounts td:first-child { min-width: 13rem; }

.admin-table--accounts td:first-child a {
  display: inline-block;
  text-wrap: balance;
}

.admin-table--accounts th:nth-child(8),
.admin-table--accounts td:nth-child(8) { min-width: 11rem; }

/* Counts and rates take only what they need, so the text columns get the rest. */
.admin-table--accounts td.num,
.admin-table--accounts th:nth-child(n + 4):nth-child(-n + 7),
.admin-table--accounts th:nth-child(9) { width: 1%; white-space: nowrap; }

.admin-truncate {
  display: inline-block;
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

/* ====================================================================== FILTERS AND PAGING */
.admin-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--s3);
  margin-bottom: var(--s4);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--slate);
}

.admin-filters label {
  display: block;
  margin-bottom: var(--s1);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.admin-filters input,
.admin-filters select {
  font: inherit;
  font-size: var(--t-body-sm);
  min-height: 38px;
  /* Sized to their CONTENT. These used to be 1,320px wide holding the word "pending (0)". */
  width: auto;
  min-width: 11rem;
  max-width: 20rem;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: inherit;
}

.admin-filters .button { margin-left: auto; }

.admin-pager {
  display: flex;
  gap: var(--s3);
  margin-top: var(--s4);
}

/* =================================================================================== FORMS */
.ops-form,
.ops-created {
  display: grid;
  gap: var(--s2);
  max-width: 44rem;
}

.ops-form label,
.ops-created label {
  margin-top: var(--s2);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ops-form input,
.ops-form select,
.ops-form textarea,
.ops-created input {
  width: 100%;
  min-height: var(--control-min);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-body);
  transition: border-color var(--motion), box-shadow var(--motion);
}

.ops-form input:hover,
.ops-form select:hover { border-color: #cfd3cd; }

.ops-form > small,
.ops-created small {
  color: var(--muted);
  font-size: var(--t-small);
  line-height: 1.5;
}

.ops-form-split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--s3);
}

/* Fields declare their own natural width; only genuinely long values run the full column. */
.ops-form input[type="number"],
.ops-form input[inputmode="numeric"] { max-width: 11rem; }
.ops-form select { max-width: 26rem; }
.ops-form-split select,
.ops-form-split input[type="number"] { max-width: none; }

/* ------------------------------------------------------- checkbox / radio are not text fields */
.ops-form input[type="checkbox"],
.ops-form input[type="radio"],
.ops-created input[type="checkbox"],
.ops-created input[type="radio"] {
  width: 1.05rem;
  height: 1.05rem;
  min-height: 0;
  margin: 0;
  padding: 0;
  flex: 0 0 auto;
  accent-color: var(--accent);
  cursor: pointer;
}

/* `.ops-confirm` is the acknowledgement row — a checkbox beside the sentence it commits you to.
 * It is the last thing a person reads before an irreversible act, so it is set as BODY COPY, not
 * as the 8px uppercase micro-label the other form labels use. It shipped with no rule at all;
 * see DOCS/78. */
.ops-form label.ops-confirm,
.ops-created label.ops-confirm {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  margin-top: var(--s3);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--slate);
  color: var(--ink);
  font-size: var(--t-body-sm);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
  transition: border-color var(--motion), background var(--motion);
}

.ops-form label.ops-confirm:hover { border-color: var(--accent-br); }

.ops-form label.ops-confirm input[type="checkbox"] { margin-top: 3px; }

.ops-form label.ops-confirm:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-bg);
}

.ops-form label.ops-confirm strong { font-weight: 700; }
.ops-form label.ops-confirm em { font-style: italic; }

/* The acknowledgement in front of a destructive action carries the danger colour, so the row that
 * says "I am authorised to change it" cannot be mistaken for the row above it. */
.admin-danger .ops-form label.ops-confirm,
.admin-recall .ops-form label.ops-confirm {
  border-color: var(--bad-br);
  background: var(--bad-bg);
}

/* ================================================================================== BUTTONS */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--control-min);
  padding: 0 var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-body-sm);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--motion), border-color var(--motion), color var(--motion);
}

.button:hover { border-color: #cfd3cd; background: var(--slate); }

.button:disabled,
.button[disabled] { opacity: 0.5; cursor: not-allowed; }

/* One button SYSTEM: primary and destructive are the same shape, different intent. Previously the
 * two most consequential buttons on /policy were a filled cyan and a hollow red-on-red — they did
 * not read as the same control at all. */
.button--primary {
  border-color: var(--accent);
  background: var(--accent);
  color: #fff;
}
.button--primary:hover { border-color: var(--accent-ink); background: var(--accent-ink); }

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

.button--danger-soft {
  border-color: var(--bad);
  background: var(--bad);
  color: #fff;
}
.button--danger-soft:hover { border-color: #8a2b1a; background: #8a2b1a; }

.button--full { width: 100%; }

.ops-form .button { justify-self: start; margin-top: var(--s3); }
.ops-form .button--full { justify-self: stretch; }

/* `.ops-preview` is the WITHDRAWAL-REASON preview: the exact sentence the paying dealer will read,
 * rendered under the reason field by the same function his screen calls. It is quoted material,
 * not a form hint, so it is set as body copy behind a rule rather than as the 11px uppercase
 * micro-label the surrounding fields use — an operator has to be able to READ it as a sentence.
 * No colour alarm: the preview is normal operating information, and the destructive act already
 * owns the red. */
.ops-preview {
  margin: 0;
  padding: var(--s2) var(--s3);
  border-left: 3px solid var(--line);
  background: var(--slate);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-size: var(--t-body-sm);
  line-height: 1.5;
}

.ops-preview-kicker {
  display: block;
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ============================================================================ STATUS TOKENS */
/* ONE pill component. It carries account status, lead flags and verdicts; every variant is a
 * background/border pair over the same shape, so a new status is a token, not a new component. */
.pill {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--slate);
  color: var(--ink);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.pill--bought,
.pill--ok { border-color: var(--ok-br); background: var(--ok-bg); color: var(--ok); }

.pill--working,
.pill--called,
.pill--offer { border-color: var(--accent-br); background: var(--accent-bg); color: var(--accent-ink); }

.pill--passed,
.pill--unworked,
.pill--new,
.pill--viewed { border-color: var(--line); background: var(--slate); color: var(--muted); }

.pill--danger,
.pill--bad { border-color: var(--bad-br); background: var(--bad-bg); color: var(--bad); }

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

/* `.admin-flag` is the inline ON/OFF marker in prose. Neutral by default: an auto-approve that is
 * ON is a normal operating state, and the old red border made it read as an alarm. */
.admin-flag {
  display: inline-block;
  padding: 1px var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--slate);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
}

.admin-flag--hot {
  border-color: var(--accent-br);
  background: var(--accent-bg);
  color: var(--accent-ink);
}

/* ================================================================================== NOTICES */
.admin-notice,
.auth-error {
  margin-bottom: var(--s5);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--ok-br);
  border-left: 3px solid var(--ok);
  border-radius: var(--radius-sm);
  background: var(--ok-bg);
  color: var(--ink);
  font-size: var(--t-body-sm);
}

.auth-error {
  border-color: var(--bad-br);
  border-left-color: var(--bad);
  background: var(--bad-bg);
}

.admin-note {
  color: var(--muted);
  font-size: var(--t-body-sm);
}

.admin-gate-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
}

.admin-back {
  display: inline-block;
  margin-top: var(--s5);
  color: var(--accent);
  font-size: var(--t-body-sm);
  font-weight: 600;
}

/* The supply gate panel — the arithmetic that says whether the pond can feed another dealer.
 * Measured ceiling ~38.6 deliverable leads/day; one exclusive account at 10/weekday takes a
 * quarter of it. It is a decision surface, not one more neutral card. */
.ops-supply { border-left: 3px solid var(--accent); }

.ops-supply p {
  margin: var(--s2) 0 0;
  color: var(--ink);
  font-size: var(--t-lead);
  line-height: 1.45;
  font-variant-numeric: tabular-nums lining-nums;
}

.ops-supply small {
  display: block;
  margin-top: var(--s3);
  color: var(--muted);
  font-size: var(--t-small);
}

/* ------------------------------------------------------------- the contract / danger blocks */
.admin-contract,
.admin-recall {
  margin: var(--s4) 0;
  padding: var(--s4);
  border: 1px solid var(--bad-br);
  border-left: 3px solid var(--bad);
  border-radius: var(--radius-sm);
  background: var(--bad-bg);
}

.admin-contract h3,
.admin-recall h3 {
  margin-bottom: var(--s2);
  color: var(--bad);
  font-size: var(--t-body-sm);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.admin-contract p,
.admin-recall p { font-size: var(--t-body-sm); line-height: 1.55; }

.admin-danger { border-color: var(--bad-br); }

/* ============================================================================ DETAIL VIEWS */
.admin-dl {
  display: grid;
  grid-template-columns: minmax(9rem, 15rem) 1fr;
  gap: var(--s2) var(--s4);
  margin: 0;
  font-size: var(--t-body-sm);
}

.admin-dl dt {
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding-top: 2px;
}

.admin-dl dd { margin: 0; overflow-wrap: anywhere; }

.admin-kv {
  list-style: none;
  padding: 0;
  margin: var(--s3) 0 0;
  display: grid;
  gap: var(--s2);
  font-size: var(--t-body-sm);
}

.admin-kv strong {
  margin-right: var(--s2);
  color: var(--muted);
  font-weight: 600;
}

.admin-timeline {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--s3);
  font-size: var(--t-body-sm);
}

.admin-timeline li {
  padding-left: var(--s4);
  border-left: 2px solid var(--accent-br);
}

.admin-timeline span {
  display: block;
  color: var(--muted);
  font-size: var(--t-small);
}

.admin-bulk {
  margin-top: var(--s5);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--slate);
  display: grid;
  gap: var(--s3);
}

.admin-bulk legend {
  padding: 0 var(--s2);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.admin-bulk label { font-size: var(--t-body-sm); }

.admin-bulk input[type="text"],
.admin-bulk input:not([type]),
.admin-bulk select {
  width: 100%;
  min-height: var(--control-min);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: inherit;
  font: inherit;
  font-size: var(--t-body-sm);
}

.admin-bulk small { color: var(--muted); font-size: var(--t-small); }

.admin-days {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--slate);
}

.admin-days legend {
  padding: 0 var(--s2);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.admin-days label {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-body-sm);
}

/* ============================================================================== LOGIN SCREEN */
.auth-body {
  display: grid;
  place-items: center;
  min-height: 100vh;
  background: var(--paper);
}

.auth-shell {
  width: 100%;
  max-width: 26rem;
  padding: var(--s4);
}

.auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  margin-bottom: var(--s5);
}

/* The login page has no indigo header bar to sit on, so the reversed lockup needs its own dark
 * plate rather than being invisible on paper. */
.auth-brand img {
  height: 30px;
  width: auto;
  padding: var(--s2) var(--s3);
  border-radius: var(--radius-sm);
  background: var(--accent);
}

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

.auth-card h1 { margin-bottom: var(--s2); }

.auth-card > p {
  margin-bottom: var(--s4);
  color: var(--muted);
  font-size: var(--t-body-sm);
}

/* ================================================================================= UTILITY */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================================= BREAKPOINTS */
/* Four, matching the client dashboard, instead of the single 780px the old sheet had. */
@media (max-width: 980px) {
  .ops-heading { flex-direction: column; }
  .ops-price { align-self: stretch; text-align: left; }
}

@media (max-width: 760px) {
  .page { padding-block: var(--s4) var(--s6); }
  .surface { padding: var(--s4); }
  .admin-dl { grid-template-columns: 1fr; gap: 2px 0; }
  .admin-dl dd { margin-bottom: var(--s3); }
  .admin-role-note { margin-left: 0; flex-basis: 100%; }
  .admin-filters .button { margin-left: 0; }
  .admin-nav-inner { gap: var(--s4); }
}

@media (max-width: 520px) {
  .admin-filters input,
  .admin-filters select { width: 100%; max-width: none; }
  .ops-price strong { font-size: var(--t-h1); }
}

/* ==================================================================================== PRINT */
/* An operator prints a lead or an account to take into a call. The chrome is noise on paper. */
@media print {
  .site-header,
  .admin-nav,
  .logout-form,
  .admin-filters,
  .admin-pager,
  .admin-bulk,
  .admin-back { display: none !important; }

  body { background: #fff; }
  .surface { border-color: #ccc; box-shadow: none; break-inside: avoid; }
  .admin-table-scroll { overflow: visible; background: none; }
}

/* ================================================================== OPERATOR SIGN-IN FORM
 * THIS FORM HAD NO LAYOUT RULES AT ALL. `.auth-card` styled the box and `.auth-body` centred it,
 * and then the form inside was raw HTML: label and input are both inline-level by default, so the
 * rendered page read
 *
 *     Email [input] Password
 *     [input]
 *
 * — two labels colliding with one field and the second input orphaned on the next line. The
 * customer door never showed this because `customer-dashboard.css` carries `.auth-card form`
 * rules; this stylesheet simply never got them. Found by opening the page, not by reading it.
 *
 * Deliberately NOT reusing `.ops-form`: those rules lean on `justify-self`, i.e. on being inside
 * the console's grid, and this page has no grid to sit in. The VISUAL language is copied exactly
 * (uppercase micro labels, full-width bordered controls, the same focus ring) so the sign-in page
 * looks like the console it opens, but the layout is its own and cannot be broken from a distance.
 */
.auth-card form {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
}

.auth-card label {
  margin-top: var(--s3);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.auth-card label:first-of-type { margin-top: 0; }

.auth-card input[type="email"],
.auth-card input[type="password"],
.auth-card input[type="text"] {
  width: 100%;
  min-height: var(--control-min);
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-body);
}
.auth-card input:hover { border-color: #cfd3cd; }

/* The submit is the only action on the page, so it gets room rather than sitting on the field. */
.auth-card form .button { margin-top: var(--s4); }

/* THE LOCKUP. The reversed logo needs a dark plate on paper or it disappears, but the previous
 * rule padded a 30px image inside an indigo chip barely larger than the wordmark, which read as a
 * button. Give it a proper plate with the operator indigo and let the mark breathe. */
.auth-brand img {
  /* The asset is 4725x1418 -- a WORDMARK, 3.3:1. At the previous 30px it rendered 57px wide
     inside a chip barely bigger than itself, which read as a small indigo button rather than a
     logo. 46px puts the mark at ~153px: a lockup, and still subordinate to the H1 under it. */
  height: 46px;
  padding: var(--s3) var(--s4);
}

/* One line of orientation under the card: which door this is, and where the other one is. An
 * operator who lands here by muscle memory when they wanted the dealer board should be told,
 * rather than left guessing why their dealer password is refused. */
.auth-aside {
  margin-top: var(--s4);
  color: var(--muted);
  font-size: var(--t-small);
  text-align: center;
  line-height: 1.6;
}
.auth-aside a { color: var(--accent); }

/* ============================================== THE EMAILED SIGN-IN BLOCK ON THE OPERATOR DOORS
 * (2026-09-01) The console's sign-in went passwordless, which put three controls on this surface
 * that this sheet had never heard of, and the dealer door had shipped the identical three
 * unstyled the day before — `login.html` rendered `.auth-alt`, `.auth-alt-rule` and
 * `.button--link` against a stylesheet with zero rules for any of them, so the emailed block read
 * as a stack of unlabelled fragments on the primary sign-in path.  These are the same rules
 * customer-dashboard.css grew that morning, restated in THIS sheet's tokens (the two files share
 * no variables — light indigo here, dark green there — so importing was never available).
 *
 *   * `.auth-alt` is a child of `.auth-card form`, which is `display:flex; gap:var(--s1)`, so the
 *     DIV is one flex item and its own children fall outside that gap entirely.  The
 *     `.auth-card form .button { margin-top: var(--s4) }` rule reaches them, but nothing separates
 *     the label, the input and the small print, so they render flush.
 *   * `.auth-alt-rule` is a labelled divider.  Undrawn, the word "or" sits on the page as a bare
 *     orphan line between two buttons.
 *   * the code input needs `input[type="text"]`, which is already covered above, and the small
 *     print under each control needs a size that is not body copy.
 */
.auth-alt {
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  margin-top: var(--s4);
}

/* The rule is drawn with borders on a flex row rather than a pseudo-element with a background,
 * so it needs no swatch to sit on and cannot show as a patch if the card's surface changes. */
.auth-alt-rule {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s2);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.auth-alt-rule::before,
.auth-alt-rule::after {
  flex: 1;
  border-top: 1px solid var(--line);
  content: "";
}

/* `.auth-card form .button` gives every button `margin-top: var(--s4)`; inside this stack the
 * gap already spaces them, and 16px on top of that pushed the break-glass button away from the
 * field it belongs with. */
.auth-alt .button { margin-top: var(--s2); }

/* The explanatory line under a control. Small, muted, and never the same size as body copy —
 * an operator has to be able to tell an instruction from a sentence about their account. */
.auth-card form small,
.auth-help {
  color: var(--muted);
  font-size: var(--t-small);
  line-height: 1.5;
}

.auth-help {
  display: block;
  margin-top: var(--s2);
}

/* The break-glass banner and the code page's `<code>` spans name a variable and a file path, so
 * they are set in a mono face at a size that survives being read down a phone line at 6am. */
.auth-card code {
  padding: 1px var(--s1);
  border-radius: 4px;
  background: var(--slate);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--t-small);
}
