/* ==========================================================================
   ui.css — THE SHARED PRIMITIVES the enquiry desk and the quote register are
   both built out of.
   --------------------------------------------------------------------------
   WHY THIS FILE EXISTS. Both screens solved the same problems differently:
   two kinds of stat block (`.dk-tiles` and `.jt-conv`), two kinds of chip row,
   two kinds of prose banner (`.rvp-cov` and `.rvp-warn`), two kinds of table
   row. Simon, on the pair: *"The main dashboard is easy to read and tidy, the
   quote and enquiry one is complex and hard to read."* A component that exists
   twice drifts twice, and the drift is most of what reads as unfinished.

   EVERY VALUE HERE IS A TOKEN from core.css's :root. No hex, no magic pixel.
   That is what makes a dark theme a second :root block later rather than a
   second stylesheet.

   THE PREFIX IS `ui-`, verified unused across css/core.css, all css/modules/*,
   driver/driver.css and portal/portal.css before it was chosen —
   tests/css-split-check.js holds that no selector may appear in two files.

   ONE RULE RUNS THROUGH ALL OF IT: colour never carries a fact by itself.
   Every badge draws a dot AND the word; every hatched "we cannot tell" says
   so in text as well as texture.
   ========================================================================== */

/* ---- the page intro strip -----------------------------------------------
   Title-adjacent, but NOT a second h1: the shell's topbar already owns the
   page title, and a screen that printed its own would give a reader two. */
.ui-head{display:flex;align-items:flex-start;gap:var(--sp-3);margin:0 0 var(--sp-4)}
.ui-head__lede{margin:0;font-size:var(--fz-body);line-height:var(--lh-body);
  font-weight:var(--fw-reg);color:var(--text-secondary);max-width:96ch}
.ui-head__lede b{font-weight:var(--fw-semi);color:var(--text-primary)}

/* ---- the info affordance ------------------------------------------------
   A <details>, not a `title=`. CLAUDE.md records the reason twice: a tablet
   has no hover, so the one thing that makes a hatched dash mean something was
   unreachable for the reader most likely to be holding the screen. <details>
   is natively focusable, toggles on Enter and Space, and reports its state to
   a screen reader. `title` is kept alongside for the mouse. */
.ui-info{position:relative;display:inline-block;vertical-align:middle}
.ui-info>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;
  justify-content:center;gap:var(--sp-1);height:22px;min-width:22px;padding:0 var(--sp-1);
  border:1px solid var(--border-default);border-radius:999px;background:var(--bg-surface);
  color:var(--text-tertiary);font-size:var(--fz-caption);line-height:1;font-weight:var(--fw-semi)}
.ui-info>summary::-webkit-details-marker{display:none}
.ui-info>summary::marker{content:""}
.ui-info>summary:hover{color:var(--brand);border-color:var(--brand)}
.ui-info[open]>summary{color:var(--brand-fg);background:var(--brand);border-color:var(--brand)}
.ui-info__label{font-size:var(--fz-small);padding-right:var(--sp-1)}
.ui-info__pop{position:absolute;z-index:40;top:calc(100% + var(--sp-2));left:0;
  width:min(460px,86vw);padding:var(--sp-4);background:var(--bg-surface);
  border:1px solid var(--border-default);border-radius:var(--r-lg);box-shadow:var(--elev-overlay)}
.ui-info--right .ui-info__pop{left:auto;right:0}
.ui-info__pop p{margin:0 0 var(--sp-2);font-size:var(--fz-small);line-height:var(--lh-small);
  font-weight:var(--fw-reg);color:var(--text-secondary)}
.ui-info__pop p:last-child{margin-bottom:0}
.ui-info__pop b{color:var(--text-primary);font-weight:var(--fw-semi)}
.ui-info__pop a{color:var(--brand);font-weight:var(--fw-semi);text-decoration:underline}
.ui-info__h{margin:0 0 var(--sp-2);font-size:var(--fz-caption);line-height:var(--lh-caption);
  letter-spacing:var(--ls-caption);text-transform:uppercase;font-weight:var(--fw-semi);
  color:var(--text-tertiary)}

/* ---- StatTile / StatRow -------------------------------------------------
   ONE component for the desk's three cards and the register's five-across
   number row. A tile is a BUTTON because pressing it applies the matching
   filter — which is what both screens' numbers always implied and only one
   of them did. */
.ui-stats{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin:0 0 var(--sp-3);align-items:stretch}
.ui-stat{flex:1 1 0;min-width:132px;display:flex;flex-direction:column;gap:2px;
  padding:var(--sp-2) var(--sp-3);text-align:left;font-family:var(--font);cursor:pointer;
  background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:var(--r-md);
  box-shadow:var(--elev-raised);transition:border-color .15s,background .15s}
.ui-stat:hover{background:var(--bg-surface-hover);border-color:var(--border-strong)}
.ui-stat__n{font-size:var(--fz-metric);line-height:var(--lh-metric);font-weight:var(--fw-semi);
  font-variant-numeric:tabular-nums;color:var(--text-primary);letter-spacing:0}
.ui-stat__l{font-size:var(--fz-caption);line-height:var(--lh-caption);letter-spacing:var(--ls-caption);
  text-transform:uppercase;font-weight:var(--fw-semi);color:var(--text-tertiary)}
/* THE SELECTED TILE IS NOT SELECTED BY COLOUR ALONE: it carries aria-pressed,
   a brand rule down its leading edge and a heavier border. */
.ui-stat[aria-pressed="true"]{border-color:var(--brand);background:var(--info-bg);
  box-shadow:inset 3px 0 0 var(--brand)}
.ui-stat[aria-pressed="true"] .ui-stat__l{color:var(--info-fg)}
/* The one deliberate primary metric on a screen — the capture rate. It is a
   FIGURE, not decoration, so it gets the brand colour and the accent rule; the
   orange stays a 3px edge, never a fill. */
.ui-stat--metric{flex:0 0 auto;min-width:196px;border-color:var(--border-default);
  box-shadow:inset 3px 0 0 var(--accent),var(--elev-raised)}
.ui-stat--metric .ui-stat__n{color:var(--brand)}
.ui-stat--ok .ui-stat__n{color:var(--success-fg)}
.ui-stat--warn .ui-stat__n{color:var(--warning-fg)}
.ui-stat--bad .ui-stat__n{color:var(--danger-fg)}
.ui-stat__hint{font-size:var(--fz-small);line-height:var(--lh-small);color:var(--text-tertiary);
  font-weight:var(--fw-reg)}

/* ---- one slim line of facts under the tiles ----------------------------
   Counts with names behind them, never a rate. The qualifying clause that
   cannot move (wall-clock, not business hours) rides here; everything that
   qualifies the LIST rather than a NUMBER is in the info popover. */
.ui-facts{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2) var(--sp-4);
  margin:0 0 var(--sp-3);font-size:var(--fz-body);line-height:var(--lh-body);
  font-weight:var(--fw-reg);color:var(--text-secondary)}
.ui-facts b{font-weight:var(--fw-semi);color:var(--text-primary);font-variant-numeric:tabular-nums}
.ui-facts__q{color:var(--text-tertiary);font-size:var(--fz-small)}
.ui-facts__sep{width:1px;height:14px;background:var(--border-default)}
/* The sentence that qualifies a metric sits directly under its row, not a
   paragraph's distance from it. */
.ui-facts--tight{margin-top:calc(var(--sp-1) * -1);margin-bottom:var(--sp-3);
  font-size:var(--fz-small);line-height:var(--lh-small);color:var(--text-tertiary)}

/* ---- FilterBar ----------------------------------------------------------
   Sticky under the shell's 66px topbar. Its z-index sits BELOW the topbar's
   20 so the global search's results still land over it. */
.ui-bar{position:sticky;top:66px;z-index:12;display:flex;flex-direction:column;gap:var(--sp-2);
  padding:var(--sp-2) var(--sp-3);margin:0 0 var(--sp-3);
  background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:var(--r-lg);
  box-shadow:var(--elev-raised)}
.ui-bar__row{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap}
.ui-bar__row--wrap{align-items:flex-start}
.ui-bar__search{flex:1 1 220px;min-width:180px;position:relative;display:flex;align-items:center}
.ui-bar__search::before{content:"⌕";position:absolute;left:var(--sp-3);font-size:16px;
  color:var(--text-tertiary);pointer-events:none;line-height:1}
.ui-bar__search input{width:100%;height:36px;padding:0 var(--sp-3) 0 var(--sp-8);
  font-family:var(--font);font-size:var(--fz-body);font-weight:var(--fw-reg);color:var(--text-primary);
  background:var(--bg-inset);border:1px solid var(--border-default);border-radius:var(--r-sm)}
.ui-bar__search input::placeholder{color:var(--text-tertiary)}
.ui-bar__search input:focus{outline:none;background:var(--bg-surface);border-color:var(--brand);
  box-shadow:0 0 0 3px var(--info-bg)}
.ui-bar__actions{display:flex;align-items:center;gap:var(--sp-2);margin-left:auto}
.ui-bar__spacer{flex:1 1 auto}
/* A quiet status line beside an action — "Mailbox checked 21:02 · nothing new".
   The raw poller string is in the info popover next to it, not printed as UI. */
.ui-bar__note{display:inline-flex;align-items:center;gap:var(--sp-2);font-size:var(--fz-small);
  line-height:var(--lh-small);color:var(--text-tertiary);font-weight:var(--fw-reg);
  max-width:44ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---- SegmentedControl — few, mutually exclusive views ------------------- */
.ui-seg{display:inline-flex;padding:2px;gap:2px;background:var(--bg-inset);
  border:1px solid var(--border-subtle);border-radius:var(--r-md)}
.ui-seg__b{appearance:none;border:0;background:none;font-family:var(--font);cursor:pointer;
  display:inline-flex;align-items:center;gap:var(--sp-2);height:30px;padding:0 var(--sp-3);
  border-radius:var(--r-sm);font-size:var(--fz-small);line-height:var(--lh-small);
  font-weight:var(--fw-semi);color:var(--text-secondary)}
.ui-seg__b:hover{color:var(--text-primary);background:var(--bg-surface-hover)}
.ui-seg__b[aria-pressed="true"]{background:var(--bg-surface);color:var(--brand);
  box-shadow:var(--elev-raised)}
.ui-seg__n{font-variant-numeric:tabular-nums;font-size:var(--fz-caption);
  color:var(--text-tertiary);font-weight:var(--fw-semi)}
.ui-seg__b[aria-pressed="true"] .ui-seg__n{color:var(--brand)}


/* Visually hidden, still read aloud — an action column needs a header for a
   screen reader and needs no words for anybody else. */
.ui-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* The segmented control's slot in the filter bar. */
.ui-seg-wrap{display:flex;align-items:center;flex:0 0 auto}

/* ---- FilterChip — many, count-bearing ---------------------------------- */
.ui-chips{display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center}
.ui-chip{appearance:none;font-family:var(--font);cursor:pointer;display:inline-flex;
  align-items:center;gap:var(--sp-2);height:28px;padding:0 var(--sp-2) 0 var(--sp-3);
  background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--r-sm);
  font-size:var(--fz-small);line-height:var(--lh-small);font-weight:var(--fw-semi);
  color:var(--text-secondary)}
.ui-chip:hover{border-color:var(--border-strong);color:var(--text-primary)}
.ui-chip[aria-pressed="true"]{background:var(--brand);border-color:var(--brand);color:var(--brand-fg)}
.ui-chip__n{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:18px;
  padding:0 var(--sp-1);border-radius:var(--r-sm);background:var(--bg-inset);
  font-size:var(--fz-caption);line-height:var(--lh-caption);font-variant-numeric:tabular-nums;
  color:var(--text-tertiary)}
.ui-chip[aria-pressed="true"] .ui-chip__n{background:rgba(255,255,255,.22);color:var(--brand-fg)}
/* A chip with nothing in it is still OFFERED — "is anything waiting on a
   person?" must not require knowing a chip once existed — but it is visibly
   quieter than one with work behind it. */
.ui-chip--zero{color:var(--text-tertiary);border-color:var(--border-subtle);background:var(--bg-inset)}
.ui-chip--zero .ui-chip__n{background:transparent}
/* A COUNT OF ZERO AND A COUNT THAT CANNOT EXIST ARE DIFFERENT FACTS. The
   hatch is this repo's treatment for every "we cannot tell", and the word
   "not tracked" rides with it so the texture is never the only signal. */
.ui-chip--indet .ui-chip__n{background-color:var(--warning-bg);
  background-image:repeating-linear-gradient(135deg,var(--warning-border) 0 2px,transparent 2px 5px);
  border:1px solid var(--warning-border);color:var(--warning-fg);font-weight:var(--fw-semi)}
.ui-chip--more{border-style:dashed;color:var(--text-tertiary)}

/* ---- StatusBadge — dot + label, driven by the role map ------------------
   `.badge` from core.css stays on the element (screens and suites read it);
   these rules load after core and win the tie, which is why the pill is a
   4px radius here and 999px there. */
.ui-badge{display:inline-flex;align-items:center;gap:var(--sp-2);max-width:100%;
  padding:2px var(--sp-2);border:1px solid transparent;border-radius:var(--r-sm);
  font-size:var(--fz-caption);line-height:var(--lh-caption);letter-spacing:.01em;
  font-weight:var(--fw-semi);white-space:nowrap;text-transform:none}
.ui-badge::before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor;
  flex:0 0 auto}
.ui-badge--neutral{background:var(--neutral-bg);border-color:var(--neutral-border);color:var(--neutral-fg)}
.ui-badge--info{background:var(--info-bg);border-color:var(--info-border);color:var(--info-fg)}
.ui-badge--success{background:var(--success-bg);border-color:var(--success-border);color:var(--success-fg)}
.ui-badge--warning{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-fg)}
.ui-badge--danger{background:var(--danger-bg);border-color:var(--danger-border);color:var(--danger-fg)}
/* The unknown state is its own state — never a flat green, never folded into
   a yes or a no. */
.ui-badge--indet{background-image:repeating-linear-gradient(135deg,
  var(--neutral-border) 0 4px,transparent 4px 8px)}
.ui-badge--indet::before{background:transparent;border:1.5px dashed currentColor;width:8px;height:8px}

/* ---- DataTable ----------------------------------------------------------
   Zebra-free, one clear hover, caption column headers, a sticky header row,
   and NO shadow on a row. The wrapper is the scroll container in both axes so
   a wide table scrolls inside itself and the page body never scrolls
   sideways. */
.ui-tw{background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:var(--r-lg);
  box-shadow:var(--elev-raised);overflow:auto;max-height:var(--ui-tmax,calc(100vh - 300px));
  overscroll-behavior:contain}
.ui-table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}
.ui-table th{position:sticky;top:0;z-index:2;text-align:left;background:var(--bg-surface);
  padding:var(--sp-2) var(--sp-4);border-bottom:1px solid var(--border-default);
  font-size:var(--fz-caption);line-height:var(--lh-caption);letter-spacing:var(--ls-caption);
  text-transform:uppercase;font-weight:var(--fw-semi);color:var(--text-tertiary);white-space:nowrap}
.ui-table td{padding:var(--sp-1) var(--sp-4);border-bottom:1px solid var(--border-subtle);
  font-size:var(--fz-body);line-height:var(--lh-body);font-weight:var(--fw-reg);
  color:var(--text-secondary);vertical-align:top}
.ui-table tbody tr{cursor:pointer;background:var(--bg-surface)}
.ui-table tbody tr:hover{background:var(--bg-surface-hover)}
.ui-table tbody tr:last-child td{border-bottom:0}
/* A row is reachable and operable from the keyboard: tabindex + Enter/Space in
   js/app.js, and a ring that is visible against both the row and its hover. */
.ui-table tbody tr:focus-visible{outline:2px solid var(--brand);outline-offset:-2px;
  background:var(--bg-surface-hover)}
.ui-table .ui-t-num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.ui-table th.ui-t-num{text-align:right}
/* The primary cell, its secondary line, and the truncation that keeps a junk
   goods string from wrapping a row taller than every other one. */
.ui-t1{display:block;font-size:var(--fz-body);line-height:var(--lh-body);
  font-weight:var(--fw-semi);color:var(--text-primary)}
.ui-t2{display:block;font-size:var(--fz-small);line-height:var(--lh-small);
  color:var(--text-tertiary);font-weight:var(--fw-reg)}
.ui-clip{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* One line that ends in its own info affordance: the words truncate, the glyph
   stays put. Without this the disclosure is inside the ellipsis and the one
   route to the full sentence disappears exactly when it is needed. */
.ui-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-1);min-width:0}
/* basis 0, not auto: with `auto` the words ask for their full unwrapped width
   first, and the affordance at the end of the line is pushed onto a line of its
   own — which is a second line in a cell allowed exactly one. */
.ui-line>.ui-clip{flex:1 1 0;min-width:0}
.ui-line>.ui-note{flex:0 0 auto;margin-left:0}
.ui-line>.ui-note[open]{flex:1 0 100%}
.ui-mono{font-variant-numeric:tabular-nums}
/* Missing, and not-tracked, drawn the same way everywhere. */
.ui-miss{color:var(--text-tertiary)}
.ui-indet{background-image:repeating-linear-gradient(135deg,var(--neutral-border) 0 4px,
  transparent 4px 8px);border:1px solid var(--neutral-border);border-radius:var(--r-sm);
  padding:0 var(--sp-1);color:var(--text-secondary);font-size:var(--fz-small);font-weight:var(--fw-semi)}
/* A partial value — a total that is not the whole price — is the VALUE plus a
   marker, never the value with a paragraph under it. */
.ui-partial{display:inline-flex;align-items:center;gap:var(--sp-1);margin-left:var(--sp-1);
  color:var(--warning-fg);font-size:var(--fz-caption);font-weight:var(--fw-semi)}
/* Lineage — the small muted chips under a primary reference. */
.ui-lin{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-1);margin-top:2px}
.ui-lin__c{display:inline-flex;align-items:center;gap:2px;padding:0 var(--sp-1);
  background:var(--bg-inset);border:1px solid var(--border-subtle);border-radius:var(--r-sm);
  font-size:var(--fz-caption);line-height:var(--lh-caption);font-weight:var(--fw-semi);
  color:var(--text-tertiary);font-variant-numeric:tabular-nums}
.ui-lin__c--to{color:var(--info-fg);background:var(--info-bg);border-color:var(--info-border)}
.ui-lin__arrow{color:var(--text-tertiary);font-size:var(--fz-caption)}
/* An owner, and the unassigned state drawn so nobody assumes somebody has it. */
.ui-who{display:inline-flex;align-items:center;gap:var(--sp-2);min-width:0}
.ui-who__a{flex:0 0 auto;width:22px;height:22px;border-radius:50%;background:var(--info-bg);
  color:var(--info-fg);display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--fz-caption);font-weight:var(--fw-semi)}
.ui-who__n{font-size:var(--fz-small);font-weight:var(--fw-semi);color:var(--text-primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ui-who--none .ui-who__a{background:var(--bg-inset);color:var(--text-tertiary);
  border:1px dashed var(--border-strong)}
.ui-who--none .ui-who__n{color:var(--warning-fg);font-style:normal}
/* The quiet row action. A column of solid blue buttons competed with itself
   and with the header CTA; the row itself is the control now, and this is the
   keyboard route to it. */
.ui-go{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;
  border-radius:var(--r-sm);color:var(--text-tertiary);opacity:0;transition:opacity .12s,color .12s}
.ui-table tbody tr:hover .ui-go,.ui-table tbody tr:focus-within .ui-go,.ui-go:focus-visible{opacity:1}
.ui-go:hover{color:var(--brand);background:var(--bg-inset)}
/* An in-cell explanation. Collapsed it is one glyph; open it grows THAT row
   only. It is a <details> rather than an absolutely-positioned popover
   because the table wrapper is a scroll container and would clip one. */
.ui-note{display:inline-block;vertical-align:middle;margin-left:var(--sp-1);line-height:0;max-width:100%}
/* OPEN, IT TAKES THE CELL'S OWN WIDTH AND NO MORE. As a shrink-wrapped
   inline-block its body sized itself to `max-width:52ch` and pushed out past the
   column — measured, 18 elements sitting outside the table's right edge. The
   page still did not scroll sideways (the wrapper is the scroll container, which
   is the point of it) but a note escaping its cell reads as broken. */
.ui-note[open]{display:block;width:100%;line-height:var(--lh-small)}
.ui-note>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;
  justify-content:center;width:15px;height:15px;border-radius:50%;vertical-align:-2px;
  border:1px solid var(--border-default);background:var(--bg-surface);
  color:var(--text-tertiary);font-size:10px;font-weight:var(--fw-semi);line-height:1}
.ui-note>summary::-webkit-details-marker{display:none}
.ui-note>summary::marker{content:""}
.ui-note>summary:hover{color:var(--brand);border-color:var(--brand)}
.ui-note__b{display:block;margin-top:var(--sp-1);padding:var(--sp-2);max-width:100%;
  background:var(--bg-inset);border-left:2px solid var(--border-strong);border-radius:var(--r-sm);
  font-size:var(--fz-small);line-height:var(--lh-small);font-weight:var(--fw-reg);
  color:var(--text-secondary);white-space:normal}
.ui-note--warn>summary{color:var(--danger-fg);border-color:var(--danger-border);background:var(--danger-bg)}
.ui-note--warn .ui-note__b{border-left-color:var(--danger-fg);background:var(--danger-bg);
  color:var(--danger-fg)}

/* ---- Callout — one line, optional Details ------------------------------
   This replaces every full-width prose banner on both screens. The line stays
   at full size; the sentences that qualify the LIST rather than a FIGURE go
   behind the disclosure. Nothing is cut — the disclosure holds the same
   words, in the same order. */
.ui-call{display:flex;align-items:flex-start;gap:var(--sp-3);padding:var(--sp-2) var(--sp-3);
  margin:0 0 var(--sp-2);border:1px solid var(--border-subtle);border-left:3px solid var(--border-strong);
  border-radius:var(--r-md);background:var(--bg-surface);
  font-size:var(--fz-body);line-height:var(--lh-body);font-weight:var(--fw-reg);color:var(--text-secondary)}
.ui-call__i{flex:0 0 auto;width:18px;height:18px;margin-top:1px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--fz-caption);font-weight:var(--fw-semi)}
.ui-call__m{flex:1 1 auto;min-width:0}
.ui-call__m>b{color:var(--text-primary);font-weight:var(--fw-semi)}
.ui-call__a{flex:0 0 auto;display:flex;align-items:center;gap:var(--sp-2)}
.ui-call--info{background:var(--info-bg);border-color:var(--info-border);border-left-color:var(--brand)}
.ui-call--info .ui-call__i{background:var(--brand);color:var(--brand-fg)}
.ui-call--info .ui-call__m>b{color:var(--info-fg)}
.ui-call--warn{background:var(--warning-bg);border-color:var(--warning-border);
  border-left-color:var(--accent)}
.ui-call--warn .ui-call__i{background:var(--accent-fg);color:var(--bg-surface)}
.ui-call--warn .ui-call__m>b{color:var(--warning-fg)}
.ui-call--plain{background:var(--bg-surface);border-left-color:var(--border-strong)}
.ui-call details{display:inline-block;margin:0 0 0 var(--sp-2);vertical-align:baseline}
.ui-call details[open]{display:block;margin:var(--sp-2) 0 0}
.ui-call details>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;
  gap:var(--sp-1);font-size:var(--fz-small);font-weight:var(--fw-semi);color:var(--brand)}
.ui-call details>summary::-webkit-details-marker{display:none}
.ui-call details>summary::marker{content:""}
.ui-call details>summary::after{content:"▾";font-size:9px;line-height:1}
.ui-call details[open]>summary::after{content:"▴"}
.ui-call details p{margin:var(--sp-2) 0 0;font-size:var(--fz-small);line-height:var(--lh-small);
  max-width:104ch}
.ui-call details a{color:var(--brand);font-weight:var(--fw-semi);text-decoration:underline}
.ui-call--warn details>summary,.ui-call--warn details a{color:var(--warning-fg)}

/* ---- EmptyState --------------------------------------------------------- */
.ui-empty{padding:var(--sp-8) var(--sp-6);text-align:left}
.ui-empty__t{display:block;font-size:var(--fz-body);line-height:var(--lh-body);
  font-weight:var(--fw-semi);color:var(--text-primary);margin-bottom:var(--sp-1)}
.ui-empty__b{display:block;font-size:var(--fz-small);line-height:var(--lh-small);
  font-weight:var(--fw-reg);color:var(--text-secondary);max-width:96ch}

/* ---- quiet actions ------------------------------------------------------
   ONE PRIMARY PER REGION. Everything else is one of these: a ghost button or
   a text link. They are sized to the 36px control rhythm of the filter bar,
   not to core.css's 44px touch target, because they sit in a dense row a
   dispatcher works with a mouse. */
.ui-btn{appearance:none;font-family:var(--font);cursor:pointer;display:inline-flex;
  align-items:center;justify-content:center;gap:var(--sp-2);height:36px;padding:0 var(--sp-3);
  border-radius:var(--r-md);font-size:var(--fz-small);line-height:var(--lh-small);
  font-weight:var(--fw-semi);border:1px solid var(--border-default);
  background:var(--bg-surface);color:var(--text-primary);white-space:nowrap}
.ui-btn:hover{background:var(--bg-surface-hover);border-color:var(--border-strong)}
.ui-btn--primary{background:var(--brand);border-color:var(--brand);color:var(--brand-fg)}
.ui-btn--primary:hover{background:var(--brand-hover);border-color:var(--brand-hover)}
.ui-btn--quiet{border-color:transparent;background:transparent;color:var(--brand)}
.ui-btn--quiet:hover{background:var(--info-bg);border-color:transparent}
.ui-btn--sm{height:28px;padding:0 var(--sp-2);font-size:var(--fz-caption)}
.ui-btn:disabled{cursor:not-allowed;color:var(--text-disabled);background:var(--bg-inset);
  border-color:var(--border-subtle)}

/* ---- ONE focus ring, everywhere ---------------------------------------- */
.ui-stat:focus-visible,.ui-seg__b:focus-visible,.ui-chip:focus-visible,.ui-btn:focus-visible,
.ui-go:focus-visible,.ui-info>summary:focus-visible,.ui-note>summary:focus-visible,
.ui-call details>summary:focus-visible,.ui-bar__search input:focus-visible{
  outline:2px solid var(--brand);outline-offset:2px}

/* ---- 1280 → 1920. Nothing here changes what is on screen, only how much
        room it gets: the tiles stay one row to 1280 and the table's flexible
        column takes the rest. -------------------------------------------- */
@media(max-width:1360px){
  .ui-stat{min-width:118px;padding:var(--sp-2) var(--sp-3)}
  .ui-stat__n{font-size:24px;line-height:28px}
  .ui-bar__note{max-width:32ch}
}
@media(prefers-reduced-motion:reduce){
  .ui-go,.ui-stat,.ui-btn{transition:none}
}

/* ---- a plain working panel ---------------------------------------------
   `.card` supplies a border, a radius and a shadow and NO padding — which is
   what left the *Inbound enquiries* callout's heading riding its own border.
   Anything on these two screens that needs a box uses this instead, so the
   padding cannot go missing. */
.ui-panel{padding:var(--sp-4);margin:0 0 var(--sp-3);background:var(--bg-surface);
  border:1px solid var(--border-subtle);border-radius:var(--r-lg);box-shadow:var(--elev-raised)}
.ui-panel .ui-btn{margin-top:var(--sp-2)}
