/* ============================================================
   Xtrius Design System — scoped to .xt-scope
   Source: https://api.anthropic.com/v1/design/h/2H1gB0bWuOHAXgNL1VZiPQ
            xtrius-design-system/project/colors_and_type.css

   Loaded once from _md3_app_layout.html (same pattern as
   billing_dispatch.css). Inert outside .xt-scope — variables live
   on the wrapper, component classes prefixed .xt-*.

   PlatformAdmin (super-admin) section opts in by wrapping content
   inside <div class="xt-scope">...</div>.
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Source+Serif+4:opsz,wght@8..60,400;8..60,500;8..60,600;8..60,700&display=swap');

.xt-scope, .xt-scope *, .xt-scope *::before, .xt-scope *::after {
  box-sizing: border-box;
}

.xt-scope {
  /* Token definitions moved to static/css/md3/tokens.css :root (Phase 1 of
     design-token consolidation). --xt-* now resolve app-wide; this file keeps
     only the .xt-scope type/reset and .xt-* component rules, all of which
     read var(--xt-*) from :root. */

  /* ----- Apply baseline to the wrapper ----- */
  background: var(--xt-bg-1);
  color: var(--xt-fg-1);
  font-family: var(--xt-font-body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  padding: var(--xt-s-6) var(--xt-s-5);
}

@media (max-width: 768px) {
  .xt-scope { padding: var(--xt-s-5) var(--xt-s-4); }
}

/* ============================================================
   Typography — scoped resets so MD3 chrome stays untouched.
   ============================================================ */

.xt-scope h1, .xt-scope h2, .xt-scope h3,
.xt-scope h4, .xt-scope h5, .xt-scope h6 {
  margin: 0;
  color: var(--xt-fg-1);
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-semibold);
  letter-spacing: -0.005em;
}
.xt-scope h1 {
  font-family: var(--xt-font-display);
  font-size: 40px; line-height: 1.10; letter-spacing: -0.015em;
}
.xt-scope h2 {
  font-family: var(--xt-font-display);
  font-size: 32px; line-height: 1.15; letter-spacing: -0.01em;
}
.xt-scope h3 { font-size: 24px; line-height: 1.25; }
.xt-scope h4 { font-size: 20px; line-height: 1.30; }

.xt-scope p { margin: 0 0 var(--xt-s-4) 0; text-wrap: pretty; color: var(--xt-fg-2); }
.xt-scope p:last-child { margin-bottom: 0; }

.xt-scope a {
  color: var(--xt-fg-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color var(--xt-dur-fast) var(--xt-ease);
}
.xt-scope a:hover { color: var(--xt-action-accent-hover); text-decoration-thickness: 2px; }

.xt-scope code, .xt-scope kbd, .xt-scope samp, .xt-scope pre,
.xt-scope .xt-mono, .xt-scope .xt-num {
  font-family: var(--xt-font-mono);
  font-feature-settings: 'tnum' 1, 'zero' 1;
}

.xt-scope hr, .xt-scope .xt-rule {
  border: 0;
  border-top: 1px solid var(--xt-border-1);
  margin: var(--xt-s-6) 0;
}

/* Utility */
.xt-eyebrow {
  font-family: var(--xt-font-mono);
  font-weight: var(--xt-w-medium);
  font-size: 12px;
  line-height: 1.4;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--xt-fg-3);
}
.xt-display-l {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-semibold);
  font-size: 56px; line-height: 1.05; letter-spacing: -0.02em;
}
.xt-caption { font-size: 13px; line-height: 1.45; color: var(--xt-fg-3); }
.xt-body-s  { font-size: 14px; line-height: 1.50; }
.xt-muted   { color: var(--xt-fg-3); }
.xt-mono    { font-family: var(--xt-font-mono); font-feature-settings: 'tnum' 1, 'zero' 1; }

/* ============================================================
   Page chrome — top header strip for each PlatformAdmin page.
   ============================================================ */

.xt-page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--xt-s-4);
  padding-bottom: var(--xt-s-4);
  margin-bottom: var(--xt-s-6);
  border-bottom: 1px solid var(--xt-border-1);
}
.xt-page-header__title { display: flex; flex-direction: column; gap: var(--xt-s-2); }
.xt-page-header__eyebrow { /* uses .xt-eyebrow */ }
.xt-page-header__h1 {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-semibold);
  font-size: 40px;
  line-height: 1.10;
  letter-spacing: -0.015em;
  color: var(--xt-fg-1);
  display: flex;
  align-items: baseline;
  gap: var(--xt-s-3);
}
.xt-page-header__mark {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-regular);
  color: var(--xt-fg-3);
}
.xt-page-header__actions { display: flex; gap: var(--xt-s-2); align-items: center; }
.xt-page-header__count {
  font-family: var(--xt-font-mono);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.02em;
  color: var(--xt-fg-3);
}

/* ============================================================
   Icon button — square ghost trigger for table-row actions.
   ============================================================ */

.xt-icon-btn {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 28px; height: 28px;
  border: 1px solid transparent;
  border-radius: var(--xt-r-sm);
  background: transparent;
  color: var(--xt-fg-2);
  cursor: pointer;
}
.xt-icon-btn:hover { border-color: var(--xt-border-1); background: var(--xt-bg-2); color: var(--xt-fg-1); }
.xt-icon-btn[disabled],
.xt-icon-btn[aria-disabled="true"] { opacity: .4; cursor: not-allowed; pointer-events: none; }
/* P7: void/delete row-action skin reads true danger-red per the xt-table
   proposedCss (_new_sections.json::xt-table), not ember. */
.xt-icon-btn--danger { color: var(--xt-danger); }
.xt-icon-btn--danger:hover { background: var(--xt-danger-bg); border-color: var(--xt-danger-bg); color: var(--xt-danger); }
/* Bordered variant for dense list rows where the ghost default reads too
   flat (bonds/RO row actions). */
.xt-icon-btn--bordered {
  width: 30px; height: 30px;
  border: 1px solid var(--xt-rule);
  background: var(--xt-paper-3);
  color: var(--xt-fg-3);
  transition: border-color var(--xt-dur-fast) var(--xt-ease),
              color var(--xt-dur-fast) var(--xt-ease);
}
.xt-icon-btn--bordered:hover { border-color: var(--xt-signal); background: var(--xt-paper-3); color: var(--xt-signal); }

/* ============================================================
   Text-first table row-actions (de-icon arc — PRs 2-7 pattern).
   Desktop: "View · Edit · Delete" text links. Mobile/dense: each
   item collapses to a compact glyph + aria-label. The glyph is the
   accessible fallback (never the only channel) and the visible word
   is the accessible name on desktop. Markup from the row_actions /
   row_action / row_action_link macros in partials/_md3_macros.html.
   ============================================================ */
.xt-rowact {
  display: inline-flex;
  align-items: center;
  gap: var(--xt-s-2);
  justify-content: flex-end;
  white-space: nowrap;
  /* Anchor for the absolutely-positioned overflow menu. */
  position: relative;
}
.xt-rowact__item {
  display: inline-flex;
  align-items: center;
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--xt-signal);
  font: inherit;
  font-size: 13px;
  font-weight: var(--xt-w-medium);
  line-height: 1;
  cursor: pointer;
  text-decoration: none;
  border-radius: var(--xt-r-sm);
}
.xt-rowact__item:hover,
.xt-rowact__item:focus-visible { text-decoration: underline; }
.xt-rowact__item:focus-visible { outline: 2px solid var(--xt-signal); outline-offset: 2px; }
.xt-rowact__item--danger { color: var(--xt-danger); }
.xt-rowact__item[disabled],
.xt-rowact__item[aria-disabled="true"] { opacity: .4; cursor: not-allowed; pointer-events: none; }
/* Link-color guard parity with .xt-code-link so the app-shell global
   `body.xt-app a` rule doesn't repaint the anchor variant. The scope rule
   also underlines every anchor at rest — row actions are underline-on-hover
   only (matches the button variant), so reset it here and re-state the
   hover/focus affordance at matching specificity. */
body.xt-app a.xt-rowact__item,
.xt-scope a.xt-rowact__item { color: var(--xt-signal); text-decoration: none; }
body.xt-app a.xt-rowact__item:hover, body.xt-app a.xt-rowact__item:focus-visible,
.xt-scope a.xt-rowact__item:hover, .xt-scope a.xt-rowact__item:focus-visible { text-decoration: underline; }
body.xt-app a.xt-rowact__item--danger,
.xt-scope a.xt-rowact__item--danger { color: var(--xt-danger); }
/* Standalone danger text link (transfer success card) — same repaint guard,
   same underline-on-hover-only treatment as the rowact anchors. */
body.xt-app a.xt-text-danger,
.xt-scope a.xt-text-danger { color: var(--xt-danger); text-decoration: none; }
body.xt-app a.xt-text-danger:hover, body.xt-app a.xt-text-danger:focus-visible,
.xt-scope a.xt-text-danger:hover, .xt-scope a.xt-text-danger:focus-visible { text-decoration: underline; }
/* "·" dot separator between consecutive text items (desktop only). */
.xt-rowact__item + .xt-rowact__item::before {
  content: "·";
  margin: 0 var(--xt-s-2) 0 0;
  color: var(--xt-fg-3);
  text-decoration: none;
  display: inline-block;
}
/* Desktop: show the word, hide the glyph. */
.xt-rowact__glyph { display: none; }
.xt-rowact__label { display: inline; }

/* ── Automatic overflow ("More" disclosure) — desktop only ──────────
   row-actions-overflow.js reveals the trigger + relocates trailing items
   into the menu when the inline set can't fit the Actions column. The
   trigger is a TEXT word ("More" + a small caret), NOT an icon-button. */
.xt-rowact__more { display: inline-flex; align-items: center; gap: 2px; }
.xt-rowact__more[hidden] { display: none; }
.xt-rowact__caret {
  font-size: 11px;
  line-height: 1;
  transition: transform var(--xt-dur-fast, .12s) var(--xt-ease, ease);
}
.xt-rowact__more[aria-expanded="true"] .xt-rowact__caret { transform: rotate(180deg); }

/* Menu surface — mirrors the .xt-chip-menu table-filter popover conventions
   (paper-3 card, soft shadow, rounded, [hidden] hides). Right-aligned to the
   group since row-actions sit at the trailing edge. */
.xt-rowact__menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 168px;
  padding: var(--xt-s-1) 0;
  background: var(--xt-paper-3);
  border: 1px solid var(--xt-rule);
  border-radius: var(--xt-r-md);
  box-shadow: 0 2px 6px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.06);
  text-align: left;
  white-space: nowrap;
}
.xt-rowact__menu[hidden] { display: none; }
/* Relocated items stack as full-width menu rows: no inline "·" separator,
   the word always shows (glyph stays hidden as on desktop), comfortable hit
   area. role="menuitem" is set by the JS when it moves each node in. */
.xt-rowact__menu .xt-rowact__item {
  width: 100%;
  justify-content: flex-start;
  padding: var(--xt-s-2) var(--xt-s-4);
  border-radius: 0;
  font-weight: var(--xt-w-regular, 400);
}
.xt-rowact__menu .xt-rowact__item:hover,
.xt-rowact__menu .xt-rowact__item:focus-visible {
  text-decoration: none;
  background: var(--xt-surface-container, var(--xt-bg-2));
}
.xt-rowact__menu .xt-rowact__item:focus-visible { outline-offset: -2px; }
.xt-rowact__menu .xt-rowact__item + .xt-rowact__item::before { content: none; }
.xt-rowact__menu .xt-rowact__label { display: inline; }
/* Mobile / dense: collapse each item to its glyph; aria-label keeps the
   accessible name. The separator + word are hidden. */
@media (max-width: 768px) {
  .xt-rowact { gap: var(--xt-s-1); }
  .xt-rowact__item {
    width: 28px; height: 28px;
    justify-content: center;
    border: 1px solid transparent;
    border-radius: var(--xt-r-sm);
    color: var(--xt-fg-2);
  }
  .xt-rowact__item--danger { color: var(--xt-danger); }
  .xt-rowact__item:hover { text-decoration: none; border-color: var(--xt-border-1); background: var(--xt-bg-2); }
  /* Glyph-only here — no underline affordance; must outrank the desktop
     anchor hover guard above (same selectors, later in file). */
  body.xt-app a.xt-rowact__item:hover, body.xt-app a.xt-rowact__item:focus-visible,
  .xt-scope a.xt-rowact__item:hover, .xt-scope a.xt-rowact__item:focus-visible { text-decoration: none; }
  .xt-rowact__glyph { display: inline-flex; font-size: 18px; }
  .xt-rowact__label { display: none; }
  .xt-rowact__item + .xt-rowact__item::before { content: none; }
  /* The overflow pattern is desktop-only — each item already glyph-collapses
     here, so the "More" disclosure must never appear. JS also skips ≤768px;
     this is the defensive CSS guard so the scaffold can't leak on mobile. */
  .xt-rowact__more,
  .xt-rowact__menu { display: none !important; }
}

/* ============================================================
   Sub-tab strip (sub-module nav within a section, e.g. catalog vs pending)
   ============================================================ */

.xt-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--xt-border-1);
  overflow-x: auto;
  margin-bottom: var(--xt-s-4);
}
.xt-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  font-family: var(--xt-font-body);
  font-size: 13px;
  font-weight: 500;
  color: var(--xt-fg-3);
  border-bottom: 2px solid transparent;
  text-decoration: none;
  white-space: nowrap;
  background: transparent;
}
.xt-tab:hover { color: var(--xt-fg-1); }
.xt-tab[aria-selected="true"],
.xt-tab[aria-current="page"],
.xt-tab.is-active {
  color: var(--xt-signal-ink);
  border-bottom-color: var(--xt-signal);
}

/* ============================================================
   Card
   ============================================================ */

.xt-card {
  background: var(--xt-bg-2);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
  padding: var(--xt-s-5);
}
.xt-card--feature { padding: var(--xt-s-6); }
.xt-card--flush   { padding: 0; }
.xt-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--xt-s-3);
  margin-bottom: var(--xt-s-4);
}
.xt-card__title {
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-semibold);
  font-size: 15px;
  letter-spacing: 0;
  color: var(--xt-fg-1);
  margin: 0;
}
.xt-card__sub { /* uses .xt-eyebrow */ }
.xt-card__body { color: var(--xt-fg-2); }
.xt-card__footer {
  margin-top: var(--xt-s-4);
  padding-top: var(--xt-s-3);
  border-top: 1px solid var(--xt-border-1);
  font-size: 13px;
  color: var(--xt-fg-3);
}

/* ============================================================
   KPI / Stat row
   ============================================================ */

.xt-stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--xt-s-4);
  margin-bottom: var(--xt-s-6);
}
.xt-stat {
  background: var(--xt-bg-2);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
  padding: var(--xt-s-5);
  display: flex; flex-direction: column; gap: var(--xt-s-2);
}
.xt-stat__eyebrow {
  font-family: var(--xt-font-mono);
  font-weight: var(--xt-w-medium);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--xt-fg-3);
}
.xt-stat__value {
  font-family: var(--xt-font-mono);
  font-feature-settings: 'tnum' 1, 'zero' 1;
  font-weight: var(--xt-w-semibold);
  font-size: 36px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--xt-fg-1);
}
.xt-stat__value--signal { color: var(--xt-signal); }
.xt-stat__value--ember  { color: var(--xt-ember); }
/* `.xt-stat__value--danger` is defined in the lean P9 block below. */
.xt-stat__hint {
  font-family: var(--xt-font-body);
  font-size: 13px;
  color: var(--xt-fg-3);
}
.xt-stat__delta {
  font-family: var(--xt-font-mono);
  font-size: 12px;
  color: var(--xt-success);
}
.xt-stat__delta--down { color: var(--xt-danger); }

/* ============================================================
   Buttons
   ============================================================ */

.xt-scope a.xt-btn,
.xt-scope a.xt-btn:hover {
  text-decoration: none;
}
/* Beat .xt-scope a's link-color rule by tag+two-class specificity.
   P4 semantic ladder: the three SOLID variants (primary/accent/danger)
   carry inverse text; secondary uses fg-1, ghost uses fg-2. */
.xt-scope a.xt-btn--primary,
.xt-scope a.xt-btn--primary:hover,
.xt-scope a.xt-btn--accent,
.xt-scope a.xt-btn--accent:hover,
.xt-scope a.xt-btn--danger,
.xt-scope a.xt-btn--danger:hover { color: var(--xt-fg-inverse); }
.xt-scope a.xt-btn--secondary,
.xt-scope a.xt-btn--secondary:hover { color: var(--xt-fg-1); }
.xt-scope a.xt-btn--ghost,
.xt-scope a.xt-btn--ghost:hover { color: var(--xt-fg-2); }

/* Nav-style links inside scope inherit color from their container class,
   never the body link-color. Catches every mobile bottom-nav variant. */
.xt-scope a.xt-mobile-bottomnav__item,
.xt-scope a.xt-mobile-bottomnav__item:hover,
.xt-scope a.xt-mobile-bottom-nav__item,
.xt-scope a.xt-mobile-bottom-nav__item:hover,
.xt-scope a.xt-mbnav__item,
.xt-scope a.xt-mbnav__item:hover,
.xt-scope a.xt-mock-nav-pill,
.xt-scope a.xt-mock-nav-pill:hover {
  text-decoration: none;
  color: inherit;
}

/* ----------------------------------------------------------------------
   P1 gate — core-app anchor-as-button parity (body.xt-app).
   The core tenant body carries `xt-app` (set in _md3_app_layout.html). The
   bare `.xt-*` component rules already render there, but anchors styled as
   buttons (<a class="xt-btn--*">, added in P4) would otherwise inherit the
   editorial body link colour/underline from the host stylesheet. These
   additive, `.xt-*`-only guards mirror the `.xt-scope` set above so an
   <a class="xt-btn"> matches its <button> twin under body.xt-app too. They
   match NO `.md3-*` element, so they shift nothing on un-migrated pages.
   ---------------------------------------------------------------------- */
body.xt-app a.xt-btn,
body.xt-app a.xt-btn:hover {
  text-decoration: none;
}
body.xt-app a.xt-btn--primary,
body.xt-app a.xt-btn--primary:hover,
body.xt-app a.xt-btn--accent,
body.xt-app a.xt-btn--accent:hover,
body.xt-app a.xt-btn--danger,
body.xt-app a.xt-btn--danger:hover { color: var(--xt-fg-inverse); }
body.xt-app a.xt-btn--secondary,
body.xt-app a.xt-btn--secondary:hover { color: var(--xt-fg-1); }
body.xt-app a.xt-btn--ghost,
body.xt-app a.xt-btn--ghost:hover { color: var(--xt-fg-2); }

/* ============================================================
   .xt-btn ladder — SEMANTIC redefinition (importance -> colour)
   Source: _revised_sections.json :: button-ladder (FINAL).
   ALL variants share ONE lean size: ~28px tall, 5px 14px pad,
   13px / weight 500, var(--xt-r-sm) corners. Colour signifies
   importance, not decoration. Token-driven; no raw hex. PDF excepted.
     primary  = INK hero (the ONE high-importance action per view)
     accent   = COBALT default affirmative (Save/Add/Approve/Apply)
     danger   = RED destructive (Void/Delete)
     secondary= OUTLINE (Reprint/Mark Returned)
     ghost    = TRANSPARENT low-emphasis (Cancel/Back)
     block    = full-width modifier (shipped P1) — sm = dense modifier
   ============================================================ */
.xt-btn {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--xt-s-2);
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-medium);
  font-size: 13px;
  line-height: 1;
  height: 28px;
  padding: 5px 14px;
  border-radius: var(--xt-r-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--xt-dur-fast) var(--xt-ease),
              color var(--xt-dur-fast) var(--xt-ease),
              border-color var(--xt-dur-fast) var(--xt-ease),
              transform var(--xt-dur-fast) var(--xt-ease);
}
.xt-btn .material-symbols-outlined { font-size: 16px; }
.xt-btn:active { transform: translateY(1px); }

/* PRIMARY = INK hero — the ONE high-importance action per view
   (Issue Bond, Confirm Delivery). Charcoal solid, inverse text. */
.xt-btn--primary {
  background: var(--xt-ink);
  color: var(--xt-fg-inverse);
  border-color: var(--xt-ink);
}
.xt-btn--primary:hover {
  background: var(--xt-ink-2);
  border-color: var(--xt-ink-2);
}
/* ACCENT = COBALT default affirmative — Save · Add · Record Payment ·
   Approve · New Release Order · Apply. Solid signal, inverse text. */
.xt-btn--accent {
  background: var(--xt-signal);
  color: var(--xt-fg-inverse);
  border-color: var(--xt-signal);
}
.xt-btn--accent:hover {
  background: var(--xt-signal-2);
  border-color: var(--xt-signal-2);
}
/* ACCEPT = affirmative alias of accent — the legal-modal "Agree & close"
   action on the public signup page (templates/pages/signup.html). signup
   ships its own higher-specificity `.xt-scope .xt-btn--accept` inline rule,
   so this global def changes nothing there; it exists so the variant
   resolves to a real token-driven rule app-wide (P4 ladder guard). */
.xt-btn--accept {
  background: var(--xt-signal);
  color: var(--xt-fg-inverse);
  border-color: var(--xt-signal);
}
.xt-btn--accept:hover {
  background: var(--xt-signal-2);
  border-color: var(--xt-signal-2);
}
/* DANGER = RED destructive — Void · Delete. Solid danger, inverse text. */
.xt-btn--danger {
  background: var(--xt-danger);
  color: var(--xt-fg-inverse);
  border-color: var(--xt-danger);
}
.xt-btn--danger:hover {
  background: color-mix(in srgb, var(--xt-danger) 85%, #000);
  border-color: color-mix(in srgb, var(--xt-danger) 85%, #000);
}
/* SECONDARY = OUTLINE — Reprint · Mark Returned · Back. Transparent bg,
   1px neutral border, primary-ink text. Same lean size as the solids. */
.xt-btn--secondary {
  background: transparent;
  color: var(--xt-fg-1);
  border-color: var(--xt-border-1);
}
.xt-btn--secondary:hover {
  background: var(--xt-bg-2);
  border-color: var(--xt-border-2);
}
/* GHOST = TRANSPARENT low-emphasis — Cancel · Back. No border,
   muted text, soft tint on hover. */
.xt-btn--ghost {
  background: transparent;
  color: var(--xt-fg-2);
  border-color: transparent;
}
.xt-btn--ghost:hover { background: var(--xt-bg-2); color: var(--xt-fg-1); }
/* EMBER = HUMAN-IN-THE-LOOP — approvals, pending-sign, activation. Solid
   ember, inverse text. Reserved for actions that need a human decision
   (Activate bond, Save as Pending) — never a routine affirmative. */
.xt-btn--ember {
  background: var(--xt-ember);
  color: var(--xt-fg-inverse);
  border-color: var(--xt-ember);
}
.xt-btn--ember:hover {
  background: var(--xt-ember-2);
  border-color: var(--xt-ember-2);
}

/* Selected/active state — apply `.is-active` alongside any variant to tint a
   button that represents the current selection (zone selectors, filter
   toggles). Replaces the retired `.md3-button--active`. */
.xt-btn.is-active {
  background: var(--xt-signal-bg);
  color: var(--xt-signal-ink);
  border-color: var(--xt-signal);
}

/* SMALL density variant — table rows / dense toolbars. Composes with
   any colour; only the geometry tightens. */
.xt-btn--sm {
  height: 24px;
  padding: 4px 10px;
  font-size: 12px;
}
.xt-btn--sm .material-symbols-outlined { font-size: 14px; }

/* Shared states */
.xt-btn[disabled], .xt-btn--disabled { opacity: 0.4; cursor: not-allowed; }
.xt-btn:focus-visible { outline: 2px solid var(--xt-signal); outline-offset: 2px; }

/* ============================================================
   Code link / ID chip (UAT #12)
   Promoted from billing_payments .bp-code-btn — the app-wide
   standard for clickable business-ID references (INV #, RO #,
   bond #, receipt #). Graphite mono chip, hover/focus -> signal.
   Built from existing --xt-* tokens only; no new tokens.
   ============================================================ */
.xt-code-link {
  display: inline-block;
  border: none;
  background: var(--xt-graphite-bg);
  color: var(--xt-graphite-ink);
  font-family: var(--xt-font-mono);
  font-size: 12px;
  padding: 2px 7px;
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: background var(--xt-dur-fast) var(--xt-ease), color var(--xt-dur-fast) var(--xt-ease);
}
.xt-code-link:hover,
.xt-code-link:focus-visible {
  background: var(--xt-signal-bg);
  color: var(--xt-signal);
}
.xt-code-link:focus-visible { outline: 2px solid var(--xt-signal); outline-offset: 2px; }
/* Underline reset so <a class="xt-code-link"> doesn't inherit the global
   .xt-scope a underline (mirrors the .xt-btn anchor-reset twins above). */
body.xt-app a.xt-code-link,
.xt-scope a.xt-code-link { text-decoration: none; color: var(--xt-graphite-ink); }
body.xt-app a.xt-code-link:hover,
body.xt-app a.xt-code-link:focus-visible,
.xt-scope a.xt-code-link:hover,
.xt-scope a.xt-code-link:focus-visible { color: var(--xt-signal); }

/* ============================================================
   Badges
   ============================================================ */

/* ============================================================
   .xt-badge — DENSITY pass (this section OWNS the lean badge CSS).
   Leaner pill: tighter horizontal padding, smaller mono type, smaller
   dot — so badges read compact in dense tables instead of running wide.
   Mono + uppercase + leading dot + the 7 brand variants + the full
   state->variant map are UNCHANGED; only the geometry tightens.
   Supersedes the prior .xt-badge block in xtrius_design.css.
   ============================================================ */
.xt-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--xt-font-mono);
  font-weight: var(--xt-w-medium);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 1px 7px;
  border-radius: var(--xt-r-pill);
  border: 1px solid var(--xt-border-1);
  color: var(--xt-fg-2);
  background: var(--xt-paper-3);
  white-space: nowrap;
}

/* Brand variants — fill + ink + matched border (UNCHANGED hues) */
.xt-badge--success { color: var(--xt-success);      background: var(--xt-success-bg);  border-color: var(--xt-success-bg); }
.xt-badge--warning { color: var(--xt-warning);      background: var(--xt-warning-bg);  border-color: var(--xt-warning-bg); }
.xt-badge--danger  { color: var(--xt-danger);       background: var(--xt-danger-bg);   border-color: var(--xt-danger-bg); }
.xt-badge--info    { color: var(--xt-signal-ink);   background: var(--xt-signal-bg);   border-color: var(--xt-signal-bg); }
.xt-badge--ember   { color: var(--xt-ember-ink);    background: var(--xt-ember-bg);    border-color: var(--xt-ember-bg); }
.xt-badge--plan    { color: var(--xt-graphite-ink); background: var(--xt-graphite-bg); border-color: var(--xt-graphite-bg); }
.xt-badge--neutral { color: var(--xt-fg-2);         background: var(--xt-paper-2);     border-color: var(--xt-border-1); }

/* Leading status dot — leaner 5px (was 6px), still currentColor */
.xt-badge__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* Mobile — geometry already lean; keep nowrap so the dot+label pill
   never breaks onto two lines in a narrow card cell. */
@media (max-width: 768px) {
  .xt-badge { white-space: nowrap; }
}

/* ============================================================
   .xt-table — ONE canonical Xtrius brand ledger table (P7 fold).
   Folds .cs-table (neutral --md-sys) + the old superadmin .xt-table +
   the .md3-table re-skin into a single brand-token-sourced shape.
   Xtrius mono-uppercase underlined header, hairline rows, signal
   links, in-cell .xt-badge pills, RIGHT mono-tabular numerics,
   ghost .xt-icon-btn actions, mobile CARD-STACK <768px.
   Reads var(--xt-*) DIRECT — no --md-sys indirection.
   The .xt-table--matrix variant (dashboard drilldown) opts OUT of the
   card-stack: it keeps its own display:grid mobile layout in
   static/css/md3/dashboard-drilldown.css, so the @media block below is
   scoped .xt-table:not(.xt-table--matrix).
   ============================================================ */

.xt-table-wrap {
  background: var(--xt-bg-3);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
  overflow: hidden;
}

.xt-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--xt-bg-3);
  color: var(--xt-fg-1);
  font-family: var(--xt-font-body);
  font-size: 14px;
}

/* Contained ledger — rounded bordered container promoted to the DEFAULT
   (matches the Billing > Payments table the rest of the app now inherits).
   `border-collapse: separate` is required for `border-radius` to round a
   <table>'s corners (collapsed borders ignore radius); `border-spacing: 0`
   keeps the hairline row/header rules edge-to-edge exactly as before.
   `overflow: hidden` clips the header + last-row backgrounds to the radius.
   Matrix variant opts OUT (keeps its own grid). Sticky-header/first-column
   contexts reset below — they can't sit under overflow:hidden. */
.xt-table:not(.xt-table--matrix) {
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
  overflow: hidden;
  border-collapse: separate;
  border-spacing: 0;
}

/* position:sticky silently no-ops under an overflow:hidden ancestor, so the
   contained look can't sit on the <table> itself for the sticky-header /
   sticky-first-column tables (recent-activity, chart-card). Keep the table
   unclipped... */
.recent-activity .xt-table,
.xt-chart-card__scroll .xt-table {
  border: none;
  border-radius: 0;
  overflow: visible;
}
/* ...and move the rounded border onto the SCROLL CONTAINER instead. It already
   carries overflow for scrolling, so border-radius clips its corners to the
   contained look while sticky keeps working — the scroll container IS the
   sticky context, so rounding it is safe (clipping an ancestor between the
   sticky cell and this container is what would break it). */
.recent-activity .md3-table-host__scroll,
.xt-chart-card__scroll {
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
}

/* Header — mono eyebrow, uppercase, single ink underline rule */
.xt-table thead th {
  font-family: var(--xt-font-mono);
  font-size: 11px;
  font-weight: var(--xt-w-medium);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-align: left;
  color: var(--xt-fg-3);
  background: var(--xt-bg-2);
  padding: 10px var(--xt-s-4);
  border-bottom: 2px solid var(--xt-border-2);
  white-space: nowrap;
  vertical-align: middle;
}

/* Body — IBM Plex Sans, hairline rows, hover tint, no zebra */
.xt-table tbody td {
  font-family: var(--xt-font-body);
  font-size: 14px;
  color: var(--xt-fg-1);
  text-align: left;
  vertical-align: middle;
  padding: 12px var(--xt-s-4);
  border-bottom: 1px solid var(--xt-border-1);
}
.xt-table tbody tr:last-child td { border-bottom: none; }
.xt-table tbody tr:hover td { background: var(--xt-bg-2); }

/* Numerics — RIGHT mono tabular (header + body).
   `.xt-table .xt-cell--num` (0,2,0) already out-specifies the thead
   `text-align:left` (0,1,1), so it covers header cells too — no separate
   `thead th.xt-cell--num` selector needed. */
.xt-table .xt-cell--num {
  text-align: right;
  font-family: var(--xt-font-mono);
  font-feature-settings: 'tnum' 1, 'zero' 1;
  font-variant-numeric: tabular-nums;
}
.xt-table .xt-cell--num code { font-family: inherit; }

/* Muted / strong cell modifiers */
.xt-table .xt-cell--muted  { color: var(--xt-fg-3); }
.xt-table .xt-cell--strong { font-weight: var(--xt-w-medium); }

/* Actions cell — right-aligned ghost icon-button cluster */
.xt-table .xt-cell--actions {
  text-align: right;
  white-space: nowrap;
}
.xt-table .xt-cell--actions .xt-icon-btn + .xt-icon-btn { margin-left: var(--xt-s-1); }

/* Footer (totals) — mono, tint surface, top rule */
.xt-table tfoot td {
  font-family: var(--xt-font-mono);
  font-size: 13px;
  font-weight: var(--xt-w-semibold);
  color: var(--xt-fg-1);
  padding: 12px var(--xt-s-4);
  background: var(--xt-bg-2);
  border-top: 1px solid var(--xt-border-2);
  border-bottom: 0;
}

/* Row state modifiers (folded from cs-row--*; the inline reports section /
   total / accent / danger / muted rows). */
.xt-table tbody tr.xt-row--danger td { background: var(--xt-danger-bg); }
.xt-table tbody tr.xt-row--danger td:first-child { box-shadow: inset 3px 0 0 var(--xt-danger); }
.xt-table tbody tr.xt-row--muted td { color: var(--xt-fg-3); }
.xt-table tbody tr.xt-row--accent td,
.xt-table tbody tr.xt-row--accent:hover td { background: var(--xt-ember-bg); }
.xt-table tfoot tr.xt-row--total td,
.xt-table tbody tr.xt-row--total td {
  font-weight: var(--xt-w-semibold);
  border-top: 2px solid var(--xt-border-1);
}
.xt-table tbody tr.xt-row--section td {
  font-family: var(--xt-font-mono);
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--xt-fg-3);
  background: var(--xt-bg-2);
  border-bottom: 1px solid var(--xt-border-2);
}
/* Batch H — the per-pricing-window breakdown row under a storage line (Bill
   Details drawer). The row is a single full-width `.bill-window-block-cell` that
   owns its own padding/background/border (see `.bill-window-block*` below), so
   this rule only needs to drop the inter-row top border so the block reads as a
   child of the line above it, not a peer line. (Pre-collapse this styled many
   per-cell sub-`<td>`s with a tint + inset rail; those are gone now that the
   breakdown is one colspan cell.) */
.xt-table tbody tr.xt-row--window td { border-top: 0; }

/* Storage Charges per-lot block (rate-basis redesign). Each pricing segment is a
   REAL table row in the bill Charges table — the shared macro
   (_window_breakdown_rows.html) feeds BOTH the PDF (templates/reports/pdf/bill.html,
   which re-implements these rules inline with resolved hex — weasyprint loads no
   external CSS) and the in-app Bill Detail modal (_pay_bill_detail.html). Each
   segment declares its Rate Basis via a pill (Base rate vs Pricing window); the
   maths reads across Bags · Billed · Rate · Amount. */
.bwb-table td { vertical-align: top; }
.bwb-num { text-align: right; font-family: var(--xt-font-mono); font-feature-settings: 'tnum' 1; }
.bwb-muted { color: var(--xt-fg-3); }
.bwb-basis { white-space: nowrap; }
.bwb-lotcell .bwb-lot { display: block; font-weight: 700; color: var(--xt-fg-1); }
.bwb-lotcell .bwb-lotsub { display: block; font-size: 11px; color: var(--xt-fg-3); margin-top: 2px; }
.bwb-lotcell .bwb-lotcard { display: block; font-size: 11px; font-weight: 700; color: var(--xt-fg-1); margin-top: 4px; }
.bwb-period .bwb-days { display: block; font-size: 11px; color: var(--xt-fg-3); margin-top: 2px; }
.bwb-pill {
  display: inline-block; font-size: 10px; font-weight: 700;
  padding: 1px 7px; border-radius: var(--xt-r-sm); white-space: nowrap;
}
.bwb-pill--base { background: var(--xt-bg-2); color: var(--xt-fg-3); }
.bwb-pill--window { background: var(--xt-ember-bg); color: var(--xt-ember); }
.bwb-basis-note { display: block; font-size: 10px; color: var(--xt-fg-3); margin-top: 2px; }
.bwb-billed .bwb-billed-val { display: block; font-weight: 600; color: var(--xt-fg-1); }
.bwb-billed .bwb-formula { display: block; font-size: 11px; color: var(--xt-fg-3); margin-top: 2px; }
.bwb-ratesuffix { font-size: 11px; color: var(--xt-fg-3); }
.bwb-segrange { color: var(--xt-fg-2); padding-left: 18px; }
.bwb-config { display: block; font-size: 11px; color: var(--xt-fg-3); margin-top: 2px; }
.bwb-table tr.bwb-seg td { background: var(--xt-paper-3); border-top: 1px dashed var(--xt-rule); }
.bwb-table tr.bwb-ins td { background: var(--xt-ember-bg); }
.bwb-table tr[data-lot-header] td { border-bottom: 1px solid var(--xt-rule); }

/* ============================================================
   Mobile CARD-STACK <768px — the desktop/mobile divergence.
   thead hides; each row becomes a stacked card; each cell becomes a
   label/value flex row driven by td[data-label] mono-uppercase eyebrows.
   Scoped :not(.xt-table--matrix) — the matrix keeps its own grid layout.
   ============================================================ */
@media (max-width: 768px) {
  .xt-table:not(.xt-table--matrix) thead { display: none; }
  .xt-table:not(.xt-table--matrix),
  .xt-table:not(.xt-table--matrix) tbody,
  .xt-table:not(.xt-table--matrix) tr,
  .xt-table:not(.xt-table--matrix) td { display: block; width: 100%; }

  .xt-table:not(.xt-table--matrix) tbody tr {
    /* border-box so width:100% absorbs the 16px×2 padding. Without it the
       content-box row + padding overflowed → card sized to content, leaving
       empty viewport (Stock Records All Inwards). Global rule — covers every
       full-page .xt-table list and dialog-body lists alike. */
    box-sizing: border-box;
    border-bottom: 1px solid var(--xt-border-1);
    padding: var(--xt-s-3) var(--xt-s-4);
  }
  .xt-table:not(.xt-table--matrix) tbody tr:last-child { border-bottom: none; }
  .xt-table:not(.xt-table--matrix) tbody tr:hover td { background: transparent; }

  .xt-table:not(.xt-table--matrix) tbody td {
    border: none;
    padding: var(--xt-s-1) 0;
    text-align: left;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--xt-s-3);
    /* Override the md3/table.css mobile rules (max-width:30vw, white-space:
       nowrap, overflow:hidden, text-overflow:ellipsis) written for the
       non-card compact table — they leak into the card-stack and clamp each
       value to 30% of the viewport, leaving a wide empty right gutter. That is
       the "extra space" #1319's tr box-model fix never reached. Let the value
       fill the card and wrap. */
    max-width: none;
    min-width: 0;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }

  /* Eyebrow label from data-label — mono uppercase 0.09em */
  .xt-table:not(.xt-table--matrix) td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-family: var(--xt-font-mono);
    font-size: 10px;
    font-weight: var(--xt-w-medium);
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--xt-fg-3);
  }

  .xt-table:not(.xt-table--matrix) .xt-cell--num { text-align: right; }
  .xt-table:not(.xt-table--matrix) .xt-cell--actions { justify-content: flex-end; gap: var(--xt-s-2); }
  .xt-table:not(.xt-table--matrix) .xt-cell--actions::before { margin-right: auto; }
}

/* Empty state */
.xt-empty {
  padding: var(--xt-s-7) var(--xt-s-5);
  text-align: center;
  color: var(--xt-fg-3);
  border: 1px dashed var(--xt-border-2);
  border-radius: var(--xt-r-md);
  background: var(--xt-bg-2);
}
.xt-empty h4 { color: var(--xt-fg-2); margin-bottom: var(--xt-s-2); }

/* ============================================================
   Inputs
   ============================================================ */

.xt-input, .xt-select, .xt-textarea {
  width: 100%;
  box-sizing: border-box;
  font-family: var(--xt-font-body);
  font-size: 14px;
  color: var(--xt-fg-1);
  background: var(--xt-bg-3);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-sm);
  padding: 10px var(--xt-s-3);
  transition: border-color var(--xt-dur-fast) var(--xt-ease),
              box-shadow var(--xt-dur-fast) var(--xt-ease);
}
.xt-input:focus, .xt-select:focus, .xt-textarea:focus {
  outline: none;
  border-color: var(--xt-signal);
  box-shadow: 0 0 0 1px var(--xt-signal);
}
.xt-input::placeholder { color: var(--xt-fg-4); }

.xt-field { display: flex; flex-direction: column; gap: 6px; }
.xt-field__label {
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-medium);
  font-size: 13px;
  color: var(--xt-fg-2);
}
.xt-field__hint  { font-size: 12px; color: var(--xt-fg-3); }
.xt-field__error { font-size: 12px; color: var(--xt-danger); }

/* ------------------------------------------------------------------------
   P6 LEAN DENSITY OVERRIDE — inputs + field stack (app-wide).
   Source: _revised_sections.json :: form-grid. The boxes shipped too big in
   P1 (14px / 10px). This override pins the shared density directive used by
   every form: .xt-input/.xt-select height 32px, padding 6px 10px, font 13px
   (~4/3 the height of a lean .xt-btn); .xt-textarea keeps the denser
   padding/font but grows with rows (min-height 56px); .xt-field gap tightens
   to 4px + label 12px to sit with the denser controls. Authored AFTER the
   P1 base so it wins the cascade. Token-driven; zero raw hex.
   ------------------------------------------------------------------------ */
.xt-input,
.xt-select,
.xt-textarea {
  font-size: 13px;
  padding: 6px 10px;
}
.xt-input,
.xt-select {
  height: 32px;
  line-height: 1.2;
}
.xt-textarea {
  height: auto;
  min-height: 56px;
  line-height: 1.4;
}
.xt-field { gap: 4px; }
/* A `.xt-field` carrying `.hidden` must actually collapse. `.xt-field` sets
   display:flex, which ties `.hidden{display:none}` on specificity and wins by
   load order, so the field would never hide (e.g. the rate-card VA-Service-Type
   row, toggled by category). This higher-specificity rule lets `.hidden` win. */
.xt-field.hidden { display: none; }
/* …but a `.xt-field` that opts into a responsive reveal (`hidden md:flex`, the
   desktop filter-row pattern — e.g. the multi-receipt report) must still show
   at its breakpoint. The collapse rule above (0,2,0) otherwise beats Tailwind's
   `.md\:flex` (0,1,0) and the field stays hidden at EVERY width. Restore the
   reveal with matching specificity, scoped to ≥md. */
@media (min-width: 768px) {
  .xt-field.hidden.md\:flex { display: flex; }
}
.xt-field__label { font-size: 12px; }

/* ============================================================
   Toolbar — search + filter chips + primary action
   ============================================================ */

.xt-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--xt-s-3);
  padding: var(--xt-s-3) 0;
  margin-bottom: var(--xt-s-4);
  flex-wrap: wrap;
}
.xt-toolbar__group { display: flex; align-items: center; gap: var(--xt-s-2); flex-wrap: wrap; }
.xt-toolbar__search {
  position: relative;
  display: flex; align-items: center;
}
.xt-toolbar__search .xt-input { padding-left: 36px; min-width: 280px; }
.xt-toolbar__search-icon {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  color: var(--xt-fg-3);
  pointer-events: none;
}
/* P11b: the orphaned toolbar-chip `.xt-chip` primitive (base + :hover +
   --active) was DELETED here. It had ZERO template consumers and, linked AFTER
   md3/components.css, its bordered/pill base clobbered the canonical folded
   `.xt-chip` state-modifier system (--warn/--danger/--quiet/--selected/--legacy)
   by source order. The SOLE `.xt-chip` base now lives in md3/components.css. */

/* ============================================================
   Two-column layout (e.g., tenant_detail)
   ============================================================ */

.xt-two-col {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--xt-s-5);
}
@media (max-width: 960px) { .xt-two-col { grid-template-columns: 1fr; } }

/* ============================================================
   Mobile dataset tabs — promoted PR 5 from xt_sa_plans_mobile mockup.
   Use when a page has 2+ distinct data sets per design rule §2.
   Shared across plans / analytics / leads / future surfaces.
   ============================================================ */
.xt-mobile-tabs {
  display: flex; gap: 4px;
  padding: 4px;
  margin: 14px 0 12px;
  background: var(--xt-paper-2);
  border: 1px solid var(--xt-rule);
  border-radius: var(--xt-r-pill);
}
.xt-mobile-tab {
  flex: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 8px 12px;
  font-family: var(--xt-font-body); font-weight: 500; font-size: 13px;
  color: var(--xt-ink-3);
  background: transparent;
  border: 0;
  border-radius: var(--xt-r-pill);
  text-decoration: none;
  cursor: pointer;
}
.xt-mobile-tab:hover { color: var(--xt-ink); }
.xt-mobile-tab--active {
  background: var(--xt-paper-3);
  color: var(--xt-ink);
  box-shadow: 0 1px 2px rgba(11,18,32,0.06);
}
.xt-mobile-tab__count {
  font-family: var(--xt-font-mono); font-size: 11px; font-weight: 500;
  letter-spacing: 0.06em;
  background: var(--xt-graphite-bg); color: var(--xt-graphite-ink);
  padding: 1px 7px; border-radius: var(--xt-r-pill);
}
.xt-mobile-tab--active .xt-mobile-tab__count {
  background: var(--xt-signal-bg); color: var(--xt-signal-ink);
}
.xt-scope a.xt-mobile-tab,
.xt-scope a.xt-mobile-tab:hover { text-decoration: none; color: inherit; }

.xt-section + .xt-section { margin-top: var(--xt-s-6); }
.xt-section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--xt-s-3);
  padding-bottom: var(--xt-s-3);
  margin-bottom: var(--xt-s-4);
  border-bottom: 1px solid var(--xt-border-1);
}
.xt-section__head h3 {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-semibold);
  font-size: 24px;
  letter-spacing: -0.005em;
}
.xt-section__head .xt-eyebrow { color: var(--xt-fg-3); }

/* ============================================================
   Definition list (key-value rows)
   ============================================================ */

.xt-dl {
  display: grid;
  grid-template-columns: minmax(160px, max-content) 1fr;
  row-gap: var(--xt-s-3);
  column-gap: var(--xt-s-5);
  font-size: 14px;
}
.xt-dl dt {
  font-family: var(--xt-font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--xt-fg-3);
  align-self: baseline;
}
.xt-dl dd {
  margin: 0;
  color: var(--xt-fg-1);
}
.xt-dl dd.xt-mono { font-family: var(--xt-font-mono); }

/* ============================================================
   Brand mark — × in display serif
   ============================================================ */

.xt-mark {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-regular);
  display: inline-block;
}
.xt-mark--sq {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 28px; height: 28px;
  background: var(--xt-ink);
  color: var(--xt-paper);
  border-radius: var(--xt-r-sm);
  font-size: 22px;
  line-height: 1;
}

/* ============================================================
   Mode switch (Switch to App Mode banner on dashboard)
   ============================================================ */

.xt-mode-switch {
  display: flex; align-items: center; gap: var(--xt-s-4);
  padding: var(--xt-s-4) var(--xt-s-5);
  background: var(--xt-bg-2);
  border: 1px solid var(--xt-border-1);
  border-left: 3px solid var(--xt-ember);
  border-radius: var(--xt-r-md);
  margin-bottom: var(--xt-s-6);
}
.xt-mode-switch__hint {
  font-size: 13px;
  color: var(--xt-fg-3);
  flex: 1;
}
@media (max-width: 640px) {
  .xt-mode-switch { flex-direction: column; align-items: stretch; gap: var(--xt-s-2); padding: var(--xt-s-3) var(--xt-s-4); }
  .xt-mode-switch > * { flex: initial; }
  .xt-mode-switch .xt-btn { width: 100%; justify-content: center; }
}

/* ============================================================
   Charts container — neutralize MD3 card chrome inside
   ============================================================ */

.xt-chart-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--xt-s-4);
  margin-bottom: var(--xt-s-6);
}
.xt-chart-card {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--xt-bg-2);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
  padding: var(--xt-s-4) var(--xt-s-5) var(--xt-s-3);
}
.xt-chart-card__title {
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-semibold);
  font-size: 15px;
  color: var(--xt-fg-1);
  margin: 0 0 var(--xt-s-1) 0;
}
.xt-chart-card__sub {
  font-family: var(--xt-font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--xt-fg-3);
  margin-bottom: var(--xt-s-3);
}
.xt-chart-card__canvas { height: 240px; position: relative; }

/* ============================================================
   Tabs
   ============================================================ */

.xt-tabs {
  display: flex;
  gap: var(--xt-s-4);
  border-bottom: 1px solid var(--xt-border-1);
  margin-bottom: var(--xt-s-5);
}
.xt-tab {
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-medium);
  font-size: 14px;
  color: var(--xt-fg-3);
  padding: var(--xt-s-3) 0;
  border: 0;
  background: transparent;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: color var(--xt-dur-fast) var(--xt-ease),
              border-color var(--xt-dur-fast) var(--xt-ease);
}
.xt-tab:hover { color: var(--xt-fg-1); }
.xt-tab--active { color: var(--xt-fg-1); border-bottom-color: var(--xt-signal); }

/* ============================================================
   Pagination row
   ============================================================ */

.xt-pager {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--xt-s-3) var(--xt-s-4);
  border-top: 1px solid var(--xt-border-1);
  background: var(--xt-bg-2);
  font-family: var(--xt-font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--xt-fg-3);
}

/* ============================================================
   Alerts / banners (inline messages)
   ============================================================ */

.xt-alert {
  display: flex; gap: var(--xt-s-3);
  padding: var(--xt-s-3) var(--xt-s-4);
  border: 1px solid var(--xt-border-1);
  border-left: 3px solid var(--xt-graphite);
  border-radius: var(--xt-r-md);
  background: var(--xt-bg-2);
  font-size: 14px;
  color: var(--xt-fg-2);
}
.xt-alert--info    { border-left-color: var(--xt-signal); background: var(--xt-signal-bg); color: var(--xt-signal-ink); }
.xt-alert--warning { border-left-color: var(--xt-warning); background: var(--xt-warning-bg); color: #6F4A0F; }
.xt-alert--danger  { border-left-color: var(--xt-danger); background: var(--xt-danger-bg); color: #6A1818; }
.xt-alert--ember   { border-left-color: var(--xt-ember); background: var(--xt-ember-bg); color: var(--xt-ember-ink); }

/* P1 — global flash channel wrapper (_xt_flash.html). Stacks persistent
   .xt-alert messages with consistent spacing. Fed by Flask flash() (no call
   sites today — true no-op until P3 rollout). */
.xt-flash { display: flex; flex-direction: column; gap: var(--xt-s-3); margin-bottom: var(--xt-s-4); }
.xt-flash:empty { display: none; }
.xt-alert__text { display: block; line-height: 1.45; }

/* ============================================================
   Page footer (global chrome) — copyright + legal links.
   Lives HERE (loaded by base.html on EVERY page) rather than in
   xt-page-chrome.css, so auth / error / legal pages that extend
   base.html directly (and never load xt-page-chrome.css) still get
   the styled footer. The app-shell edge-to-edge bleed
   (margin-inline) stays in xt-page-chrome.css — it only resolves
   inside .xt-main and would overflow elsewhere.
   ============================================================ */
.xt-page-footer {
  margin-top: auto;
  border-top: 1px solid var(--xt-rule);
  padding: 14px 22px;
  background: var(--xt-bg-1, #F4F5F7);
}
/* copyright (left) + legal links (right) on one capped, centred row that
   wraps on narrow viewports. */
.xt-page-footer__inner {
  width: 100%;
  max-width: var(--xt-canvas-max, 1320px);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--xt-s-4, 16px);
  flex-wrap: wrap;
}
.xt-page-footer__text {
  font-family: var(--xt-font-mono);
  font-size: 11px; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--xt-fg-3);
}
.xt-page-footer__links {
  display: flex;
  gap: var(--xt-s-4, 16px);
  flex-wrap: wrap;
}
.xt-page-footer__links a {
  font-family: var(--xt-font-mono);
  font-size: 11px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--xt-fg-3); text-decoration: none;
}
.xt-page-footer__links a:hover { color: var(--xt-signal); }
@media print {
  .xt-page-footer { border-top-color: #ccc; }
}

/* ============================================================
   Reduced motion
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .xt-scope *, .xt-scope *::before, .xt-scope *::after {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
  }
}

/* ============================================================
   MD3 CHROME OVERRIDES — re-skin MD3 components inside the
   Xtrius pilot scope. Body class `xt-platformadmin` opts in.
   Future arcs: add `xt-app` class to expand coverage.
   Selectors stay specific so MD3 surfaces outside the scope
   remain untouched.
   ============================================================ */

body.xt-platformadmin {
  /* Xtrius tokens now resolve from :root in static/css/md3/tokens.css
     (Phase 1 of design-token consolidation), so the body inherits them
     app-wide without an inline duplicate of the token block. */
  background: var(--xt-paper);
  color: var(--xt-ink);
  font-family: var(--xt-font-body);
}

/* P10: the platformadmin .md3-topbar* / .md3-menu-btn* / .md3-user-pill*
   topbar reskins are retired. The shell is now natively `.xt-appbar` /
   `.xt-nav-link` / `.xt-account-pill` for everyone (superadmin renders the
   same partials), self-styled in md3/xt-shell.css. */

/* P11b: the platformadmin chip / main+content-bg / card reskin blocks are
   retired. The chip folded to native `.xt-chip` (md3/components.css) and the
   main/content/card surfaces self-style off the brand tokens app-wide, so the
   override no longer changes anything for superadmin — it renders the same
   native `.xt-*` surfaces as the core app. (`.md3-card*` was already 0× in
   templates — P11a; the dead reskin went with the chip/main slice.) The P10
   shell reskins — menu-surface / module-menu / bottom-nav / bottom-sheet —
   were retired earlier (folded to native `.xt-*` in md3/xt-shell.css). */

/* P11d: the platformadmin button / table / input / mode-switch reskins are
   retired. Their `.md3-button*` / `.md3-table*` / `.md3-input*` / `.md3-select`
   / `.md3-textarea` / `.md3-text-field*` / `.md3-sa-mode-switch*` targets are
   0× in templates (superadmin renders the native `.xt-btn` ladder, `.xt-table`,
   `.xt-input`/`.xt-field`, and `.xt-mode-switch` — all self-styling off the
   brand tokens app-wide), so the overrides changed nothing and are deleted.
   The still-live cell/row + label refinements that those blocks ALSO carried
   are preserved natively below. */

/* Tables — superadmin renders native `.xt-table`; the cell/row refinements
   that the retired `.md3-table` reskin also applied to `.xt-cell` / `.xt-row`
   stay (these target live classes). */
body.xt-platformadmin .xt-cell {
  font-family: var(--xt-font-body);
  font-size: 14px;
  color: var(--xt-ink);
  border-bottom: 1px solid var(--xt-rule);
}
body.xt-platformadmin .xt-cell--muted { color: var(--xt-ink-3); }
body.xt-platformadmin .xt-row:hover td { background: var(--xt-paper-2); }
body.xt-platformadmin .md3-table-host__title {
  font-family: var(--xt-font-display);
  font-weight: 600;
  color: var(--xt-ink);
}

/* Badges — P2: the `body.xt-platformadmin .md3-badge` reskin block was
   deleted when all superadmin badge callers folded onto the canonical
   `.xt-badge` (macros/_badges.html). Superadmin now renders the same badge
   as the core app. */

/* Inputs — superadmin renders native `.xt-input` / `.xt-field`; only the live
   `label` refinement of the retired input reskin is kept. */
body.xt-platformadmin label {
  font-family: var(--xt-font-body);
  font-size: 13px;
  color: var(--xt-ink-2);
}

/* Modal / dialog — P8b: the platformadmin md3-dialog* / md3-form-dialog*
   reskin is retired. The form dialogs folded to dialog.xt-dialog--native in
   P8a and the JS-built confirm folded to xt-dialog--confirm in P8b; both
   self-style off the brand surface (--xt-bg-3) with no platformadmin override
   needed. Superadmin fully unifies to the native xt dialog in P11. */

/* Page title h1/h2 within content */
body.xt-platformadmin #md3-content h1,
body.xt-platformadmin #md3-content h2 {
  font-family: var(--xt-font-display);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--xt-ink);
}

/* Material Symbols outlined — neutralize default color drift */
body.xt-platformadmin .material-symbols-outlined { color: inherit; }

/* Numerics — P11d: the `.md3-num` / `[data-num]` reskin is retired. The
   superadmin pages render native `.xt-num` (folded from `.md3-num`; its mono +
   tabular rule lives in md3/components.css, loaded app-wide), so the override
   changed nothing. */

/* Mode-switch banner — P11d: the `.md3-sa-mode-switch*` reskin is retired.
   The superadmin sandbox banner renders native `.xt-mode-switch` (self-styled
   in md3/components.css), so the override changed nothing. */

/* Filter chips strip — `.md3-filter-chip` is a SANCTIONED live composite (the
   dashboard filter strip, not folded), so its reskin keeps its consumer. */
body.xt-platformadmin .xt-chip-filter,
body.xt-platformadmin .md3-filter-chip { border-radius: var(--xt-r-pill); font-family: var(--xt-font-body); }

/* Pagination — `.md3-pagination` is a SANCTIONED live composite (table-host
   pager, not folded), so its reskin keeps its consumer. */
body.xt-platformadmin .md3-pagination {
  font-family: var(--xt-font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--xt-ink-3);
}

/* Tabs — P11d: the `.md3-tab*` / `[role="tab"]` reskin is retired. Superadmin
   renders native `.xt-tab` / `.xt-tabs` (folded from `.md3-tab*`; styled in
   md3/tabs.css + xtrius_design.css), so the platformadmin override is
   redundant ("superadmin fully native"). */

/* ============================================================
   Auth screens (login / forgot / reset) — generic, no role leak.
   Scoped under .xt-scope so non-auth base.html consumers stay
   unaffected.
   ============================================================ */

.xt-scope .xt-auth-brand {
  display: flex; flex-direction: column; align-items: center;
  gap: 12px; text-align: center;
}
.xt-scope .xt-auth-brand__mark {
  font-family: var(--xt-font-display);
  font-weight: 400;
  font-size: 72px; line-height: 1;
  color: var(--xt-ink);
  letter-spacing: -0.02em;
}
.xt-scope .xt-auth-brand__wordmark {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-semibold);
  font-size: 28px; line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--xt-ink);
  margin: 0;
}
.xt-scope .xt-auth-brand__rule {
  width: 56px; height: 1px;
  background: var(--xt-rule-2);
  margin: 4px 0;
}
.xt-scope .xt-auth-brand__eyebrow {
  font-family: var(--xt-font-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--xt-ink-3);
}
.xt-scope .xt-auth-brand__tagline {
  font-family: var(--xt-font-body);
  font-size: 14px;
  line-height: 1.5;
  color: var(--xt-fg-3);
  max-width: 360px;
  margin: 0;
}
.xt-scope .xt-auth-card {
  background: var(--xt-paper-2);
  border: 1px solid var(--xt-rule);
  border-radius: var(--xt-r-md);
  padding: 32px;
}
.xt-scope .xt-auth-card__head {
  margin-bottom: 24px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--xt-rule);
}
.xt-scope .xt-auth-card__head h2 {
  font-family: var(--xt-font-display);
  font-weight: var(--xt-w-semibold);
  font-size: 22px;
  margin: 0 0 4px;
  color: var(--xt-ink);
}
.xt-scope .xt-auth-card__head p {
  font-size: 13px;
  color: var(--xt-fg-3);
  margin: 0;
}
.xt-scope .xt-auth-field {
  display: flex; flex-direction: column; gap: 6px;
}
.xt-scope .xt-auth-field__eyebrow {
  font-family: var(--xt-font-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--xt-ink-3);
}
.xt-scope .xt-auth-field--mono input { font-family: var(--xt-font-mono); }
.xt-scope .xt-auth-field-row {
  display: flex; justify-content: flex-end;
  font-family: var(--xt-font-mono);
  font-size: 12px;
}
.xt-scope .xt-auth-field-row a { color: var(--xt-signal-ink); text-decoration: none; }
.xt-scope .xt-auth-field-row a:hover { text-decoration: underline; }
.xt-scope .xt-auth-foot-links {
  display: flex; align-items: center; justify-content: center;
  gap: 8px;
  font-family: var(--xt-font-mono);
  font-size: 12px;
}
.xt-scope .xt-auth-foot-links a { color: var(--xt-signal-ink); text-decoration: none; }
.xt-scope .xt-auth-foot-links a:hover { text-decoration: underline; }
.xt-scope .xt-auth-foot-links__sep { color: var(--xt-ink-4); }
.xt-scope .xt-auth-method-group {
  display: flex; flex-direction: column;
  gap: 8px;
  border: 0; padding: 0; margin: 0;
}
.xt-scope .xt-auth-method-group legend {
  font-family: var(--xt-font-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--xt-ink-3);
  margin-bottom: 4px;
  padding: 0;
}
.xt-scope .xt-auth-method-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--xt-rule);
  border-radius: var(--xt-r-sm);
  background: var(--xt-paper-3);
  cursor: pointer;
}
.xt-scope .xt-auth-method-row:has(input:checked) {
  border-color: var(--xt-signal);
  background: var(--xt-signal-bg);
  color: var(--xt-signal-ink);
}
.xt-scope .xt-auth-method-row__icon { display: inline-flex; color: var(--xt-ink-3); }
.xt-scope .xt-auth-method-row:has(input:checked) .xt-auth-method-row__icon { color: var(--xt-signal-ink); }
.xt-scope .xt-auth-method-row__label {
  font-family: var(--xt-font-body);
  font-weight: 500;
  font-size: 14px;
  color: var(--xt-ink);
}
.xt-scope .xt-auth-method-row__sub {
  font-family: var(--xt-font-mono);
  font-size: 11px;
  color: var(--xt-ink-3);
}
.xt-scope .xt-auth-method-row input[type="radio"] { accent-color: var(--xt-signal); }
.xt-scope .xt-auth-back {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--xt-font-mono);
  font-size: 12px;
  color: var(--xt-signal-ink);
  text-decoration: none;
}
.xt-scope .xt-auth-back:hover { text-decoration: underline; }
.xt-scope .xt-auth-alert--danger {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 12px 14px;
  background: var(--xt-ember-bg);
  border: 1px solid var(--xt-ember);
  border-left-width: 3px;
  border-radius: var(--xt-r-sm);
  color: var(--xt-ember-ink);
  font-size: 13px;
  margin-bottom: 16px;
}
.xt-scope .xt-auth-shell {
  min-height: 100vh;
  background-image: linear-gradient(180deg, var(--xt-paper-2) 0%, var(--xt-paper) 60%);
  padding: 64px 32px;
}
.xt-scope .xt-auth-main {
  max-width: 480px;
  margin: 0 auto;
}
@media (max-width: 480px) {
  .xt-scope .xt-auth-shell { padding: 32px 16px; }
  .xt-scope .xt-auth-card { padding: 24px 20px; }
  .xt-scope .xt-auth-brand__mark { font-size: 56px; }
  .xt-scope .xt-auth-brand__wordmark { font-size: 22px; }
}

/* ── Email-OTP verification (WI-5) — step indicator, OTP entry, meta row.
   Ports static/mockups/email_otp_verify.html onto real --xt-* tokens. */
.xt-scope .xt-auth-steps {
  display: flex; align-items: center; gap: 6px;
  margin-bottom: var(--xt-s-4);
  font-family: var(--xt-font-mono);
  font-size: 11px; color: var(--xt-ink-4);
}
.xt-scope .xt-auth-steps__dot {
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600;
  background: var(--xt-paper-3); border: 1px solid var(--xt-rule);
  color: var(--xt-ink-3);
}
.xt-scope .xt-auth-steps__dot--done {
  background: var(--xt-success-bg); border-color: var(--xt-success);
  color: var(--xt-success);
}
.xt-scope .xt-auth-steps__dot--cur {
  background: var(--xt-signal); border-color: var(--xt-signal); color: #fff;
}
.xt-scope .xt-auth-steps__bar { flex: 1; height: 2px; background: var(--xt-rule); }
.xt-scope .xt-auth-steps__label { color: var(--xt-ink-3); }
.xt-scope .xt-auth-steps__label--cur { color: var(--xt-ink); font-weight: 600; }

/* Single accessible OTP field styled as segmented digits (autocomplete=
   one-time-code). One input (not six) so the entry stays keyboard/paste/SMS-
   autofill friendly with NO inline JS (CSP) — the segmented LOOK comes from the
   wide letter-spacing over a monospace face. */
.xt-scope .xt-auth-otp-input {
  width: 100%;
  text-align: center;
  font-family: var(--xt-font-mono);
  font-size: 28px; font-weight: 600;
  letter-spacing: 14px; text-indent: 14px;
  padding: 12px 8px;
  color: var(--xt-signal-ink);
  border: 1px solid var(--xt-rule-2);
  border-radius: var(--xt-r-sm);
  background: var(--xt-paper-3);
}
.xt-scope .xt-auth-otp-input:focus {
  outline: none; border-color: var(--xt-signal-2);
  background: var(--xt-signal-bg);
}
.xt-scope .xt-auth-otp-meta {
  display: flex; justify-content: space-between; align-items: center;
  gap: 8px; flex-wrap: wrap;
  font-family: var(--xt-font-mono); font-size: 12px;
  color: var(--xt-ink-4);
  margin: var(--xt-s-2) 0 var(--xt-s-4);
}
.xt-scope .xt-auth-otp-meta a { color: var(--xt-signal-ink); text-decoration: none; font-weight: 500; }
.xt-scope .xt-auth-otp-meta a:hover { text-decoration: underline; }
.xt-scope .xt-auth-otp-meta button.xt-auth-otp-resend {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--xt-signal-ink); font-family: inherit; font-size: inherit;
  font-weight: 500;
}
.xt-scope .xt-auth-otp-meta button.xt-auth-otp-resend:disabled {
  color: var(--xt-ink-4); cursor: default; text-decoration: none;
}
.xt-scope .xt-auth-otp-meta__cool { color: var(--xt-ink-4); }
.xt-scope .xt-auth-alert--ok {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 12px 14px;
  background: var(--xt-success-bg);
  border: 1px solid var(--xt-success);
  border-left-width: 3px;
  border-radius: var(--xt-r-sm);
  color: var(--xt-success);
  font-size: 13px;
  margin-bottom: 16px;
}

/* ============================================================
   Phase 3b — wizard components (BYOD Smart Ingest)
   ============================================================ */

.xt-stepper {
  display: flex; gap: 0; border-bottom: 1px solid var(--xt-border-1);
  margin-bottom: var(--xt-s-6); overflow-x: auto;
}
.xt-step {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 16px;
  font-family: var(--xt-font-body); font-size: 13px; font-weight: 500;
  color: var(--xt-fg-3);
  border-bottom: 2px solid transparent; background: transparent;
  white-space: nowrap;
}
.xt-step__num {
  font-family: var(--xt-font-mono); font-size: 11px;
  padding: 2px 7px; border-radius: var(--xt-r-pill);
  background: var(--xt-bg-2); color: var(--xt-fg-3);
  border: 1px solid var(--xt-border-1);
}
.xt-step--done { color: var(--xt-success); }
.xt-step--done .xt-step__num {
  background: var(--xt-success-bg); color: var(--xt-success);
  border-color: var(--xt-success-bg);
}
.xt-step--active {
  color: var(--xt-signal-ink); border-bottom-color: var(--xt-signal);
}
.xt-step--active .xt-step__num {
  background: var(--xt-signal); color: var(--xt-fg-inverse);
  border-color: var(--xt-signal);
}

.xt-drop-row {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--xt-s-4); margin: var(--xt-s-5) 0;
}
@media (max-width: 600px) {
  .xt-drop-row { grid-template-columns: 1fr; }
}
.xt-drop {
  background: var(--xt-bg-3);
  border: 2px dashed var(--xt-border-2);
  border-radius: var(--xt-r-md);
  padding: var(--xt-s-7) var(--xt-s-5);
  text-align: center; cursor: pointer;
  transition: border-color 200ms, background 200ms;
}
.xt-drop:hover, .xt-drop:focus-visible {
  border-color: var(--xt-signal); background: var(--xt-signal-bg);
}
.xt-drop:focus-visible { outline: 2px solid var(--xt-signal); outline-offset: 2px; }
.xt-drop__icon {
  width: 48px; height: 48px;
  margin: 0 auto var(--xt-s-3);
  color: var(--xt-fg-3);
}
.xt-drop__title {
  font-family: var(--xt-font-body); font-weight: 600; font-size: 16px;
  color: var(--xt-fg-1); margin: 0 0 var(--xt-s-1);
}
.xt-drop__sub { font-size: 13px; color: var(--xt-fg-3); margin: 0; }

.xt-aside {
  background: var(--xt-bg-3);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-md);
  padding: var(--xt-s-4);
  margin-bottom: var(--xt-s-5);
  display: flex; gap: var(--xt-s-3);
  align-items: flex-start;
}
.xt-aside__icon { color: var(--xt-signal); flex-shrink: 0; margin-top: 2px; }
.xt-aside__text { font-size: 13px; color: var(--xt-fg-2); margin: 0; }
.xt-aside__text strong { color: var(--xt-fg-1); font-weight: 600; }

.xt-actions {
  display: flex; gap: var(--xt-s-3);
  justify-content: flex-end;
  padding-top: var(--xt-s-4);
  border-top: 1px solid var(--xt-border-1);
}
.xt-actions__left { margin-right: auto; }

/* Dialog overlay (multi-bin split, inline edit, chamber-pick) */
/* Brand scrim for the div-overlay dialogs (warehouse reserve, verandah
   reject/assign) swapped into #dialog-root. Paired with Tailwind
   `fixed inset-0 z-40`; this rule owns the scrim colour + blur so the markup
   no longer needs `bg-black/40`. Matches dialog.xt-dialog--native::backdrop. */
.xt-dialog-scrim {
  background: var(--xt-scrim);
  backdrop-filter: blur(2px);
}
/* P11d: the dead `.xt-dialog__overlay` rule was deleted (0× in templates — the
   native <dialog>::backdrop + `.xt-dialog-scrim` own the dialog scrim). */
.xt-dialog {
  background: var(--xt-bg-3);
  border-radius: var(--xt-r-md);
  box-shadow: var(--xt-elev-3);
  max-width: 480px; width: 100%;
  padding: var(--xt-s-5);
}
.xt-dialog__title {
  font-family: var(--xt-font-display); font-size: 22px;
  margin: 0 0 var(--xt-s-3);
}
.xt-dialog__body { font-size: 14px; color: var(--xt-fg-2); }
.xt-dialog__actions {
  display: flex; gap: var(--xt-s-2); justify-content: flex-end;
  margin-top: var(--xt-s-5);
}

/* ============================================================================
   PHASE P1 — Xtrius FOUNDATION gap primitives (KEYSTONE).
   CSS-only; NO callers wired here (rollout lands in P2–P10). Each block's
   literal CSS is lifted verbatim from the signed-off mockup section data:
     docs/superpowers/mockups/2026-06-03-component-consistency-xtrius/
       _sections_data.json   → key `alerts_toast`        (toast + alert success)
       _revised_sections.json → key `bill_detail_dialog`  (native dialog shell,
                                                            cs-row--accent/--total)
       _revised_sections.json → key `form-grid`           (form-grid family)
       _revised_sections.json → key `button-ladder`       (.xt-btn--block)
       _revised_sections.json → key `release_orders`      (.xt-badge--sm, [data-ro-state])
       _revised_sections.json → key `bonds_list_detail`   (lean .xt-stat family,
                                                            cs-row--danger/--muted,
                                                            .cs-cell--actions, .xt-doc-row)
   Token-only colour (var(--xt-*)); sanctioned literals: none added here.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   (1) Transient toast — .xt-toast + window.showToast (static/js/xt-toast.js).
   Source: _sections_data.json :: alerts_toast. Speaks the .xt-alert language
   (3px left accent + tinted brand container + status ink). Fixed bottom-center
   via .xt-toast-host; single window.showToast appends .xt-toast nodes here.
   The mockup-only demo host `.xt-toast-host--demo` is intentionally NOT shipped.
   --------------------------------------------------------------------------- */

/* NEW — .xt-alert--success (the shipped .xt-alert lacked success) + the mono
   eyebrow shared by alert & toast. */
.xt-alert--success {
  border-left-color: var(--xt-success);
  background: var(--xt-success-bg);
  color: var(--xt-success);
}
.xt-alert__eyebrow,
.xt-toast__eyebrow {
  display: block;
  font-family: var(--xt-font-mono);
  font-weight: var(--xt-w-medium);
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: currentColor;
  opacity: 0.82;
  margin-bottom: 2px;
}

.xt-toast-host {
  position: fixed;
  bottom: var(--xt-s-5);
  left: 50%;
  transform: translateX(-50%);
  z-index: 10001;
  display: flex;
  flex-direction: column;
  gap: var(--xt-s-2);
  width: min(420px, calc(100vw - var(--xt-s-6)));
  pointer-events: none;
}

.xt-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--xt-s-3);
  padding: var(--xt-s-3) var(--xt-s-4);
  border: 1px solid var(--xt-border-1);
  border-left: 3px solid var(--xt-graphite);
  border-radius: var(--xt-r-md);
  background: var(--xt-bg-3);
  color: var(--xt-fg-2);
  box-shadow: var(--xt-elev-2);
  font-size: 14px;
  pointer-events: auto;
  transform: translateY(8px);
  opacity: 0;
  animation: xt-toast-in var(--xt-dur-base) var(--xt-ease) forwards;
}

.xt-toast__icon { flex-shrink: 0; margin-top: 1px; font-size: 20px; }
.xt-toast__body { flex: 1; min-width: 0; }
.xt-toast__text { display: block; color: inherit; line-height: 1.45; }

.xt-toast__close {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin: -2px -4px 0 0;
  padding: 0;
  border: 0;
  border-radius: var(--xt-r-sm);
  background: transparent;
  color: currentColor;
  opacity: 0.6;
  cursor: pointer;
  transition: opacity var(--xt-dur-fast) var(--xt-ease),
              background var(--xt-dur-fast) var(--xt-ease);
}
.xt-toast__close .material-symbols-outlined { font-size: 18px; }
.xt-toast__close:hover { opacity: 1; background: var(--xt-bg-2); }
.xt-toast__close:focus-visible { outline: 2px solid var(--xt-signal); outline-offset: 2px; }

/* Tone variants — mirror the .xt-alert mapping (accent + tinted bg + ink). */
.xt-toast--success { border-left-color: var(--xt-success); background: var(--xt-success-bg); color: var(--xt-success); }
.xt-toast--info    { border-left-color: var(--xt-signal);  background: var(--xt-signal-bg);  color: var(--xt-signal-ink); }
.xt-toast--warning { border-left-color: var(--xt-warning); background: var(--xt-warning-bg); color: var(--xt-warning); }
.xt-toast--danger  { border-left-color: var(--xt-danger);  background: var(--xt-danger-bg);  color: var(--xt-danger); }
.xt-toast--ember   { border-left-color: var(--xt-ember);   background: var(--xt-ember-bg);   color: var(--xt-ember-ink); }

/* Exit state — JS adds .is-leaving before removing the node. */
.xt-toast.is-leaving {
  animation: xt-toast-out var(--xt-dur-fast) var(--xt-ease) forwards;
}

@keyframes xt-toast-in {
  from { transform: translateY(8px); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}
@keyframes xt-toast-out {
  from { transform: translateY(0);   opacity: 1; }
  to   { transform: translateY(8px); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .xt-toast,
  .xt-toast.is-leaving { animation: none; transform: none; opacity: 1; }
}

/* ---------------------------------------------------------------------------
   (3) Native dialog — dialog.xt-dialog--native. Source: _revised_sections.json
   :: bill_detail_dialog. Top-layer UA chrome (reset border/padding, ::backdrop)
   so the brand surface works with showModal(); centered by UA margin:auto;
   mobile = centered card (max-height 85vh / margin auto / body-only scroll).
   NO callers reclassed (bill-detail wiring is P8). The old non-native
   <div class="xt-dialog"> (BYOD-ingest) above is left untouched (P8).
   --------------------------------------------------------------------------- */
dialog.xt-dialog--native {
  border: none;
  margin: auto;
  padding: 0;                       /* head/body/actions own their padding */
  /* The universal border-box reset (line 16) is scoped to .xt-scope; the core
     app shell (body.xt-app) has no border-box reset, so .xt-* dialogs default
     to content-box. The form dialog (padding:0) is unaffected either way, but
     the confirm variant sets padding on the box itself — under content-box its
     24px L/R padding adds OUTSIDE the width cap, overflowing the mobile sheet
     (width:100% -> 390 + 48 = 438 at a 390 viewport, clipping the actions).
     Pin border-box on the whole native dialog family so padding is included in
     the width cap (no-op for the padding:0 form dialog; future-proof). */
  box-sizing: border-box;
  max-width: min(880px, 96vw);
  width: 100%;
  max-height: 90vh;
  overflow: hidden;                 /* body scrolls, not the frame */
  display: flex;
  flex-direction: column;
  background: var(--xt-bg-3);
  color: var(--xt-fg-1);
  border-radius: var(--xt-r-md);
  box-shadow: var(--xt-elev-3);
}
dialog.xt-dialog--native:not([open]) { display: none; }
dialog.xt-dialog--native::backdrop {
  background: var(--xt-scrim);
  backdrop-filter: blur(2px);
}
/* Form-wrapped dialogs (the superadmin lead/tenant/plan/sales-team/catalog +
   _override forms): the <form> — not .xt-dialog__body — is the dialog's flex
   child, so the body's `flex:1; overflow-y:auto; min-height:0` would not
   participate in the dialog's flex column and a tall form would overflow the
   90vh cap and clip its lower fields + actions instead of scrolling. Make any
   direct-child form the flex column + scroll owner so the inner body scrolls.
   (Covers _override_dialog too: its `class="contents"` is a no-op — the Tailwind
   `contents` utility isn't in the compiled CSS — so its form was a block child;
   this rule is what actually makes it lay out. Harmless if `contents` is ever
   compiled: flex still yields correct body scroll.) */
dialog.xt-dialog--native > form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

/* Header — ONE lean title (~16px) + close, hairline divider. Pinned. */
.xt-dialog__head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--xt-s-3);
  padding: var(--xt-s-3) var(--xt-s-5);
  border-bottom: 1px solid var(--xt-border-1);
}
dialog.xt-dialog--native .xt-dialog__title {
  margin: 0;
  font-family: var(--xt-font-body);
  font-weight: var(--xt-w-semibold);
  font-size: 16px;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--xt-fg-1);
}

/* Body — the scroll region; sections stack with rule-less rhythm. */
dialog.xt-dialog--native .xt-dialog__body {
  padding: var(--xt-s-4) var(--xt-s-5);
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;                    /* lets the flex child actually scroll */
}
.xt-dialog__section + .xt-dialog__section { margin-top: var(--xt-s-4); }
.xt-dialog__section .xt-eyebrow { margin: 0 0 var(--xt-s-2); }

/* Actions — pinned footer above the backdrop, brand rule on top. */
dialog.xt-dialog--native .xt-dialog__actions {
  margin: 0;
  padding: var(--xt-s-3) var(--xt-s-5);
  border-top: 1px solid var(--xt-border-1);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--xt-s-2);
}

/* In-dialog HTMX progress strip (top-layer hides the global overlay). */
.xt-dialog__progress {
  position: absolute; top: 0; left: 0; right: 0;
  height: 2px; overflow: hidden; opacity: 0;
  transition: opacity var(--xt-dur-fast) var(--xt-ease);
  pointer-events: none;
}
.xt-dialog__progress::before {
  content: ''; position: absolute; inset: 0;
  background: var(--xt-signal);
  transform: translateX(-100%);
  animation: xt-dialog-progress 1.2s linear infinite;
}
.xt-dialog--loading .xt-dialog__progress { opacity: 1; }
@keyframes xt-dialog-progress {
  0% { transform: translateX(-100%); }
  60% { transform: translateX(60%); }
  100% { transform: translateX(120%); }
}
@media (prefers-reduced-motion: reduce) {
  .xt-dialog__progress::before { animation: none; opacity: 0.4; transform: none; }
}

/* MOBILE (<=768px) — centered scrollable card, NOT a full-screen takeover. */
@media (max-width: 768px) {
  dialog.xt-dialog--native {
    width: min(440px, calc(100vw - 32px));
    min-width: 0;
    max-width: min(440px, calc(100vw - 32px));
    max-height: 85vh;
    margin: auto;                   /* centered — visible top+bottom backdrop */
  }
  .xt-dialog__head { padding: var(--xt-s-3) var(--xt-s-4); }
  dialog.xt-dialog--native .xt-dialog__title { font-size: 15px; }
  dialog.xt-dialog--native .xt-dialog__body { padding: var(--xt-s-4); }
  dialog.xt-dialog--native .xt-dialog__actions { padding: var(--xt-s-3) var(--xt-s-4); }
}

/* ---------------------------------------------------------------------------
   P8b — JS-built CONFIRM dialog (md3Dialog.confirm). Reuses dialog.xt-dialog
   --native as its base (top-layer chrome reset + ::backdrop + flex column);
   this block adds only the confirm-specific bits the form dialog doesn't need:
   tighter sizing, the headless padded layout (no .xt-dialog__head wrapper —
   the confirm renders a flat title/body/actions stack), and the mobile
   bottom-sheet + drag-handle + swipe variant. Ported verbatim from the
   retired md3/dialog.css (confirm L84-157). The confirm has NO close button /
   no .xt-dialog__head, so its title/body padding is owned HERE (not by the
   native head/body rules which assume the framed form-dialog layout).
   --------------------------------------------------------------------------- */
dialog.xt-dialog--confirm {
  /* tighter than the 880px form dialog; the confirm is a short alert. */
  padding: var(--xt-s-5);           /* the flat stack owns its own padding */
  min-width: min(400px, 90vw);
  max-width: min(560px, 92vw);
  max-height: 85vh;
  overflow-y: auto;                 /* the whole confirm scrolls (no head/body split) */
}
/* The confirm stack is flat (no .xt-dialog__head). Re-assert title/body/actions
   spacing locally so it does NOT inherit the framed-form padding that the
   native head/body rules apply, and survives the dialog.css retirement. */
  /* Deltas only — font-weight/line-height/letter-spacing/color inherited
     from the native .xt-dialog__title base. font-family is kept as the
     P8b "lean body, NOT display serif" regression guard. font-size:16px
     MUST stay AND this block MUST remain after the native
     @media(max-width:768px) 15px rule, or the mobile size flips to 15px. */
dialog.xt-dialog--confirm .xt-dialog__title {
  margin: 0 0 var(--xt-s-3);
  padding: 0;
  font-family: var(--xt-font-body);
  font-size: 16px;
}
dialog.xt-dialog--confirm .xt-dialog__body {
  padding: 0;
  margin-bottom: var(--xt-s-5);
  overflow: visible;
  font-size: 14px;
  color: var(--xt-fg-2);
}
dialog.xt-dialog--confirm .xt-dialog__actions {
  margin: 0;
  padding: 0;
  border-top: none;
  justify-content: flex-end;
}
.xt-dialog__drag-handle { display: none; }

/* Bottom-sheet variant (<=768px). The native <dialog> defaults to centered via
   margin:auto; the sheet anchors to the bottom (top margin auto, bottom 0),
   full-width, top corners rounded, and shows the swipe grab-bar. Ported from
   md3/dialog.css L132-157. */
@media (max-width: 768px) {
  dialog.xt-dialog--native.xt-dialog--sheet {
    margin: auto 0 0 0;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    border-radius: var(--xt-r-md) var(--xt-r-md) 0 0;
    padding-top: var(--xt-s-3);
    touch-action: pan-y;
  }
  .xt-dialog--sheet .xt-dialog__drag-handle {
    display: block;
    width: 32px;
    height: 4px;
    margin: 0 auto var(--xt-s-4);
    background: var(--xt-border-1);
    border-radius: 999px;
  }
  .xt-dialog--sheet .xt-dialog__actions {
    justify-content: stretch;
  }
  .xt-dialog--sheet .xt-dialog__actions .xt-btn {
    flex: 1;
  }
}

/* ---------------------------------------------------------------------------
   Contact-us modal (L9) — compact stacked form inside the native dialog.
   Scoped to #contactUsModal so it can't bleed into other dialogs; composes the
   existing --xt-* tokens only. .xt-field already lays out label+input; these
   rules add the inter-field rhythm + the muted lead/hint copy.
   --------------------------------------------------------------------------- */
#contactUsModal .xt-field + .xt-field { margin-top: var(--xt-s-3); }
.xt-contact-lead {
  margin: 0 0 var(--xt-s-4);
  font-size: 13px;
  line-height: 1.45;
  color: var(--xt-fg-2);
}
.xt-contact-lead--hint {
  margin: var(--xt-s-3) 0 0;
  font-size: 12px;
  color: var(--xt-fg-3);
}

/* ---------------------------------------------------------------------------
   P8a — in-dialog DENSITY + DETAIL-LIST + STATUS helpers. Source:
   _revised_sections.json :: bill_detail_dialog (the LEAN read). All table /
   badge density is SCOPED under .xt-dialog__body so app-wide tables + badges
   stay untouched. The proposedCss targeted .cs-table + .cs-row--accent/--total;
   reconciled to the SHIPPED table convention: P7 folded every in-dialog table
   onto `.xt-table` (cs-table is 0× in templates post-P7), and P7's row
   modifiers are `.xt-table .xt-row--*` (cs-row--* removed) — so the dialog
   density targets ONLY `.xt-table`, and the accent/total rows reuse the
   existing `.xt-row--accent` / `.xt-row--total` (no cs-row--* re-add: P7 pins
   it 0×).
   --------------------------------------------------------------------------- */

/* Bill-summary section rhythm — the detail list + table sit flush in a section. */
.xt-dialog__section .xt-dl,
.xt-dialog__section .xt-table { margin: 0; }

/* Detail list — TIGHT rows (~3px), lean mono dt. Overrides the roomier base
   .xt-dl row-gap for the dense modal read. 13px body / 11px mono dt = the
   shared small size the in-dialog tables match. */
.xt-dialog__section .xt-dl {
  row-gap: var(--xt-s-1);
  column-gap: var(--xt-s-5);
  font-size: 13px;
}
.xt-dialog__section .xt-dl dt,
.xt-dialog__section .xt-dl dd { padding: 3px 0; }
.xt-dialog__section .xt-dl dt {
  font-size: 11px;
  letter-spacing: 0.06em;
}

/* In-dialog tables match the .xt-dl small size: 13px body / 11px header, tighter
   cell padding. Scoped to .xt-dialog__body so app-wide tables are untouched. */
.xt-dialog__body .xt-table tbody td,
.xt-dialog__body .xt-table tfoot td {
  font-size: 13px;
  padding: 7px 12px;
}
.xt-dialog__body .xt-table thead th {
  font-size: 11px;
  padding: 7px 12px;
}

/* MOBILE CARD-STACK (<=768px, matching the P7 .xt-table card-stack breakpoint
   at L645/L659): the desktop in-dialog density above sets 12px horizontal cell
   padding, which OUT-SPECIFIES the P7 card-stack rule
   `.xt-table:not(.xt-table--matrix) tbody td { padding: var(--xt-s-1) 0 }`.
   When the dialog table card-stacks, the 12px each side makes every row ~24px
   wider than the body → horizontal scroll that clips right-aligned values.
   Zero the horizontal padding so the card-stacked cells fit the dialog body.
   Desktop density (7px/12px above) is untouched. */
@media (max-width: 768px) {
  .xt-dialog__body .xt-table:not(.xt-table--matrix) tbody td,
  .xt-dialog__body .xt-table:not(.xt-table--matrix) tfoot td {
    padding-left: 0;
    padding-right: 0;
  }
}

/* In-dialog status badge — tighter pad + smaller dot (1px 7px / 10px / 5px). */
.xt-dialog__body .xt-badge {
  padding: 1px 7px;
  font-size: 10px;
}
.xt-dialog__body .xt-badge .xt-badge__dot { width: 5px; height: 5px; }

/* .xt-dl emphasis + status-colour helpers (token-driven, brand semantics). */
.xt-dl dt.xt-dl__strong { color: var(--xt-fg-1); font-weight: var(--xt-w-semibold); }
.xt-dl dd.xt-dl__strong { font-weight: var(--xt-w-semibold); }
.xt-dl__muted { color: var(--xt-fg-3); font-size: 12px; }
.xt-text-warning { color: var(--xt-warning); }
.xt-text-danger  { color: var(--xt-danger); }

/* sub-line provenance under a primary cell (rate-card chip). */
.xt-table__sub {
  display: flex; align-items: center; gap: 4px;
  font-family: var(--xt-font-mono); font-size: 11px;
  letter-spacing: 0.04em; color: var(--xt-fg-3); margin-top: 2px;
  min-width: 0;
}
.xt-table__sub .material-symbols-outlined { font-size: 14px; }

/* In the <=768px card-stack the .xt-table__sub mono flex row is a non-wrapping
   single line; a long rate-card name overflows the stacked cell and pushes the
   dialog body wider. Let it wrap so the provenance line stays inside the card. */
@media (max-width: 768px) {
  .xt-table__sub {
    flex-wrap: wrap;
    white-space: normal;
    word-break: break-word;
  }
}
.xt-inline-icon {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--xt-ember-ink); font-weight: var(--xt-w-medium);
}
.xt-inline-icon .material-symbols-outlined { font-size: 16px; }

/* Card-stack total-row guard (<=768px, matching the P7 .xt-table card-stack
   breakpoint). At <=768px the in-dialog .xt-table card-stacks; the
   Subtotal/Total footer row must stay a SINGLE aligned line (label left, value
   right), not a stacked card — so this override must fire at the SAME width the
   card-stack does (was 720px, leaving 721-768px inconsistent). */
@media (max-width: 768px) {
  .xt-dialog__body .xt-table tfoot tr.xt-row--total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--xt-s-3);
    padding: 7px 0 2px;
    border-top: 2px solid var(--xt-border-1);
  }
  .xt-dialog__body .xt-table tfoot tr.xt-row--total td {
    display: inline;
    border: none;
    padding: 0;
    font-size: 13px;
    font-weight: var(--xt-w-semibold);
  }
  .xt-dialog__body .xt-table tfoot tr.xt-row--total td.xt-cell--num:last-child {
    text-align: right;
    font-family: var(--xt-font-mono);
    font-variant-numeric: tabular-nums;
  }
  .xt-dialog__body .xt-table tfoot tr.xt-row--total td[colspan] { text-align: left; }
}

/* Bill Summary mobile — keep the .xt-dl a DENSE 2-column key/value grid, NOT
   stacked. Tighten the label column so the value still has room. */
@media (max-width: 768px) {
  .xt-dialog__section .xt-dl {
    grid-template-columns: minmax(96px, max-content) 1fr;
    column-gap: var(--xt-s-3);
    row-gap: var(--xt-s-1);
  }
  .xt-dialog__section .xt-dl dt,
  .xt-dialog__section .xt-dl dd { padding: 2px 0; }
  dialog.xt-dialog--native .xt-dialog__actions .xt-btn { flex: 1 1 auto; justify-content: center; }
}

/* ---------------------------------------------------------------------------
   (4) Form grid — .xt-form-grid (inline --cols:N) + __span2 + .xt-form-actions
   + .xt-field__req. Source: _revised_sections.json :: form-grid. Wraps .xt-field
   stacks; column count set per-instance via style="--cols:N"; collapses to one
   column < 768px. NO callers (rollout P6). The denser .xt-input/.xt-select/
   .xt-textarea + .xt-btn base/variants from that same section are P4/P6, NOT P1.
   --------------------------------------------------------------------------- */
.xt-field__req { color: var(--xt-danger); font-weight: var(--xt-w-semibold); }

.xt-form-grid {
  display: grid;
  grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
  gap: var(--xt-s-4);
  margin-bottom: var(--xt-s-4);
}
.xt-form-grid:last-child { margin-bottom: 0; }
/* Full-bleed field spanning all columns. Caps at the column count, so it is
   a no-op in a 1-col grid. */
.xt-form-grid__span2 { grid-column: 1 / -1; }

.xt-form-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--xt-s-2);
  margin-top: var(--xt-s-5);
}

@media (max-width: 768px) {
  .xt-form-grid { grid-template-columns: 1fr; }
  .xt-form-actions { margin-top: var(--xt-s-4); }
}

/* ---------------------------------------------------------------------------
   New-Tenant provisioning picker (GTM item 12) — radio path-cards + seed
   badges + the pilot_convert reveal. Ported from the signed mockup
   `Context/mockup_sa_tenant_provisioning.html` (left panel); colour is
   token-only (var(--xt-*)). Consumer:
   fragments/superadmin/_new_tenant_modal.html. The `:has()` selected/reveal
   state mirrors the sanctioned .xt-auth-method-row:has(input:checked) pattern.
   --------------------------------------------------------------------------- */
.xt-dialog__headings { min-width: 0; }
.xt-dialog__subtitle {
  font-size: 12.5px;
  color: var(--xt-fg-3);
  margin: 4px 0 0;
}
.xt-pathpick__heading { display: block; margin: var(--xt-s-3) 0 var(--xt-s-2); }
.xt-pathpick { display: flex; flex-direction: column; gap: var(--xt-s-2); }
.xt-pathpick__option {
  position: relative;
  display: flex; gap: var(--xt-s-3); align-items: flex-start;
  border: 1px solid var(--xt-rule-2);
  border-radius: var(--xt-r-md);
  padding: 13px 14px;
  cursor: pointer;
  background: var(--xt-paper-3);
}
.xt-pathpick__input { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
.xt-pathpick__radio {
  flex: none; width: 16px; height: 16px; margin-top: 2px;
  border-radius: var(--xt-r-pill);
  border: 1.5px solid var(--xt-rule-2);
  position: relative;
}
.xt-pathpick__option:has(.xt-pathpick__input:checked) {
  border-color: var(--xt-signal);
  box-shadow: 0 0 0 1px var(--xt-signal);
  background: var(--xt-signal-bg);
}
.xt-pathpick__option:has(.xt-pathpick__input:checked) .xt-pathpick__radio {
  border-color: var(--xt-signal);
}
.xt-pathpick__option:has(.xt-pathpick__input:checked) .xt-pathpick__radio::after {
  content: ""; position: absolute; inset: 3px;
  border-radius: var(--xt-r-pill); background: var(--xt-signal);
}
.xt-pathpick__input:focus-visible + .xt-pathpick__radio {
  outline: 2px solid var(--xt-signal); outline-offset: 2px;
}
.xt-pathpick__option--disabled { opacity: .55; cursor: not-allowed; }
.xt-pathpick__text { display: flex; flex-direction: column; gap: 2px; }
.xt-pathpick__title {
  display: flex; gap: var(--xt-s-2); align-items: center; flex-wrap: wrap;
  font-weight: var(--xt-w-semibold); font-size: 14px; color: var(--xt-fg-1);
}
.xt-pathpick__desc { font-size: 12.5px; color: var(--xt-fg-3); }

/* Seed/wipe/empty badges reuse the canonical .xt-badge --sm --success/--danger
   /--neutral primitive (no bespoke badge CSS). The danger callout reuses
   .xt-alert--danger. Only the reveal container is owned here. */
.xt-convert-target { display: none; margin-top: var(--xt-s-3); }
.xt-pathpick:has(.xt-pathpick__input[value="pilot_convert"]:checked) ~ .xt-convert-target {
  display: block;
}
.xt-convert-target .xt-alert { margin-bottom: var(--xt-s-3); }

/* Free-trial seed-shaping inputs (admin phone + demo sizing) — mirrors the
   public /signup demo-sandbox fields. Revealed only when the free_trial radio
   is checked (its default), same sibling `:has()` reveal as .xt-convert-target. */
.xt-freetrial-fields {
  display: none;
  flex-direction: column;
  gap: var(--xt-s-3);
  margin-top: var(--xt-s-3);
}
.xt-pathpick:has(.xt-pathpick__input[value="free_trial"]:checked) ~ .xt-freetrial-fields {
  display: flex;
}

/* Declared per-location MT capacity (optional) — SA New-Tenant modal. Always
   shown (every provisioning path can declare capacity) so no `:has()` reveal.
   Self-contained: the /welcome/capacity interstitial's .xt-loc-* rules are
   page-scoped to signup_capacity.html, so this modal ports its own compact
   styling from the shared --xt-* tokens (which resolve from :root). */
.xt-declared-cap {
  margin-top: var(--xt-s-3);
  display: flex; flex-direction: column; gap: var(--xt-s-2);
}
.xt-decl-opt {
  margin-left: 6px; font-family: var(--xt-font-mono); font-size: 10px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--xt-fg-4);
}
.xt-decl-hint { margin: 0; }
.xt-decl-rows { display: flex; flex-direction: column; gap: var(--xt-s-2); }
.xt-decl-row {
  display: grid; grid-template-columns: 1fr 140px 34px; gap: var(--xt-s-2);
  align-items: center;
}
.xt-decl-mt { position: relative; }
.xt-decl-mt .xt-input { padding-right: 34px; text-align: right; }
.xt-decl-unit {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  font-family: var(--xt-font-mono); font-size: 11px; color: var(--xt-fg-4);
  pointer-events: none;
}
.xt-decl-del {
  width: 30px; height: 30px; border-radius: var(--xt-r-sm);
  border: 1px solid var(--xt-rule); background: var(--xt-paper-3);
  color: var(--xt-fg-3); cursor: pointer; font-size: 15px; line-height: 1;
}
.xt-decl-del:hover { border-color: var(--xt-danger-bg); color: var(--xt-danger); background: var(--xt-danger-bg); }
.xt-decl-add {
  align-self: flex-start; display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--xt-font-body); font-weight: var(--xt-w-medium);
  font-size: 13px; color: var(--xt-signal-ink); background: none;
  border: 1px dashed var(--xt-rule-2); border-radius: var(--xt-r-sm);
  padding: 8px 14px; cursor: pointer;
}
.xt-decl-add:hover { border-color: var(--xt-signal); background: var(--xt-signal-bg); }

/* ---------------------------------------------------------------------------
   (5) Full-width button modifier — .xt-btn--block. Source:
   _revised_sections.json :: button-ladder. Carries no colour of its own;
   composes with any ladder variant (modal footers, mobile CTAs). NO callers (P4).
   --------------------------------------------------------------------------- */
.xt-btn--block {
  display: flex;
  width: 100%;
  justify-content: center;
}

/* ---------------------------------------------------------------------------
   (6) Small badge + RO-state hook — .xt-badge--sm + .xt-badge[data-ro-state].
   Source: _revised_sections.json :: release_orders. The .xt-badge--<variant>
   colour map already ships above, so the data-ro-state hook adds only a stable
   structural attribute target (no per-state colour rule). NO callers (P2).
   --------------------------------------------------------------------------- */
.xt-badge[data-ro-state] { vertical-align: middle; }
.xt-badge--sm {
  font-size: 10px;
  padding: 1px 6px;
  gap: 4px;
}
.xt-badge--sm .xt-badge__dot { width: 4px; height: 4px; }

/* (7) cs-table row/cell state modifiers REMOVED in P7 — superseded by the
   canonical .xt-table .xt-row--* / .xt-cell--actions block above; cs-row--* is
   now 0× in templates (pinned by tests/test_p7_table_fold_guards.py). */

/* ---------------------------------------------------------------------------
   (8) Attached-document row — .xt-doc-row (+ __icon / __name). Icon + filename
   + open action on the brand card surface; replaces .evidence-card /
   .xt-signed-pdf in P9 (both since removed). min-width:0 + the truncating __name ellipsize the
   filename instead of forcing the row wider than its card. Source:
   _revised_sections.json :: bonds_list_detail. NO callers (P9).
   --------------------------------------------------------------------------- */
.xt-doc-row {
  display: flex;
  align-items: center;
  gap: var(--xt-s-3);
  padding: var(--xt-s-3);
  background: var(--xt-bg-3);
  border: 1px solid var(--xt-border-1);
  border-radius: var(--xt-r-sm);
  min-width: 0;
  max-width: 100%;
}
.xt-doc-row__icon { color: var(--xt-fg-3); flex-shrink: 0; }
.xt-doc-row__name {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  color: var(--xt-fg-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Flush variant — sits directly under a card/iframe edge: drop the box border
   + radius, keep only a hairline top rule. (Replaces the repeated inline
   border/radius override on the bond + RO signed-document rows.) */
.xt-doc-row--flush {
  border: 0;
  border-top: 1px solid var(--xt-rule);
  border-radius: 0;
}

/* ---------------------------------------------------------------------------
   (9) LEAN .xt-stat REDEFINITION (app-wide, divergent=true) + tone rails +
   the State-as-label slot. Source: _revised_sections.json :: bonds_list_detail.
   This REPLACES the shipped roomy .xt-stat (24px pad / 36px value) with the
   definitive lean spec — value 20px (18px mobile) / padding 10px 12px /
   min-height:0 — so later phases (P5 KPI fold) only CONSUME these values. NO
   KPI callers folded here. Authored last so it wins the cascade over the
   shipped .xt-stat block above.
   --------------------------------------------------------------------------- */
.xt-stat {
  padding: 10px 12px;
  gap: var(--xt-s-1);
  min-height: 0;
}
.xt-stat__eyebrow { font-size: 10px; }
.xt-stat__value {
  font-size: 20px;
  line-height: 1.15;
}
.xt-stat__hint { font-size: 12px; line-height: 1.2; }
.xt-stat__value--danger { color: var(--xt-danger); }

/* Tighter stat-row gutters to match the compact tiles. */
.xt-stat-row {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--xt-s-3);
  margin-bottom: var(--xt-s-5);
}

/* Status accent rails (ember = human-in-the-loop / pending; danger =
   under-collateralized). 3px brand left rail; internals untouched. */
.xt-stat--ember  { border-left: 3px solid var(--xt-ember); }
.xt-stat--danger { border-left: 3px solid var(--xt-danger); }

/* State-as-label — the small mono "STATE" caption above the inline state
   badge; the .xt-page-header__state slot right-aligns caption+badge. */
.xt-stat__label {
  display: block;
  font-family: var(--xt-font-mono);
  font-weight: var(--xt-w-medium);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--xt-fg-3);
  margin-bottom: 4px;
}
.xt-page-header__state {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  flex-shrink: 0;
}

@media (max-width: 768px) {
  .xt-stat { padding: 8px 10px; min-width: 0; }
  .xt-stat__value { font-size: 18px; }
  /* State-as-label left-aligns under the title when the header stacks. */
  .xt-page-header__state { align-items: flex-start; }
}

/* ---------------------------------------------------------------------------
   P5 — Card fold support. The .md3-card / .md3-card--filled / --outlined /
   --elevated skins collapse onto the ONE canonical .xt-card surface (no
   aesthetic variants), so no variant aliases are added here — the variant
   classes are dropped from markup. These additions cover the two structural
   gaps the fold needs:
     (a) .xt-chart-card__head + __scroll — md3-chart-card markup carries a
         flex __head (title + sub) and a fixed-height scrollable table region;
         .xt-chart-card shipped only __title/__sub/__canvas, so add them here.
     (b) lean .xt-stat consumers — .xt-kpi-tile simple stat tiles (report
         summary + billing worklist) fold to the P1 lean .xt-stat; no new CSS
         is needed (P1 owns the lean values), the markup just re-points.
   The bonds .bl-bond-surface fold + State-as-label are P9 (a page-surface
   sweep, not a card-wrapper swap) — see the per-phase spec §P9. Dashboard
   .xt-kpi-tile rich tiles (gauge / sparkline / drilldown) are NOT lean stat
   tiles and stay with the dashboard.
   --------------------------------------------------------------------------- */

/* Chart-card header row (title + sub on one baseline-aligned row). */
.xt-chart-card__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--xt-s-3);
  margin-bottom: var(--xt-s-3);
  flex-wrap: wrap;
}
/* Fixed-height scrollable region for chart-cards that host a long table;
   the header stays pinned and the body scrolls (matches the former
   md3-chart-card __scroll behaviour the dashboard relies on). The flex column
   base (display:flex / flex-direction:column / min-height:0) that this region
   needs is folded into the single `.xt-chart-card {}` base block above. */
.xt-chart-card__scroll {
  flex: 1 1 auto;
  max-height: 320px;
  overflow: auto;
  min-height: 0;
}
.xt-chart-card__scroll thead th {
  position: sticky;
  top: 0;
  background: var(--xt-bg-2);
  z-index: 1;
}

/* ---------------------------------------------------------------------------
   P9 — Bonds / Release-Order on-screen surface sweep. Authors the THREE
   primitives the bonds-list / bond-detail / RO-detail markup needs that were
   not yet shipped (everything else — .xt-stat family, .xt-doc-row,
   .xt-page-header__state, .xt-stat__label, .xt-badge--sm — already lands
   above). Source-of-truth: the approved mockup proposedCss
   (docs/.../2026-06-03-component-consistency-xtrius/_rev/
   bonds_list_detail.proposedCss.css L65-76 + L170-183;
   release_orders.proposedCss.css L121-132). Token-driven, no raw hex.
   --------------------------------------------------------------------------- */

/* (1) LEAN page header — CRUD-page sized (matches Stock Inward), not the
   40px marquee .xt-page-header__h1. Modifier-scoped so the marketing-scale
   header elsewhere is untouched. Centres title + state slot on one row. */
.xt-page-header--lean {
  align-items: center;
  padding-bottom: var(--xt-s-3);
  margin-bottom: var(--xt-s-5);
}
.xt-page-header--lean .xt-page-header__title { gap: 2px; min-width: 0; }
.xt-page-header--lean .xt-eyebrow { font-size: 10px; }
.xt-page-header--lean .xt-page-header__h1 {
  font-size: 19px;
  line-height: 1.2;
  letter-spacing: -0.005em;
}

/* (2) Bond/RO action bar — flex row of state-aware buttons. The Void button
   carries inline `margin-left:auto` on desktop to push right; this base only
   sets the row layout (the desktop push is on the markup so gating logic stays
   in the template). Mobile (≤768px) wraps two-up + drops Void full-width. */
.xt-actions--bond {
  display: flex;
  gap: var(--xt-s-2);
  align-items: center;
  flex-wrap: wrap;
}

/* (3) Concise RO-detail back-link — replaces the over-long breadcrumb. ONE
   mono link to the parent bond; the RO number stays the page title. Mirrors
   .xt-auth-back styling. */
.xt-ro-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--xt-font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--xt-signal-ink);
  text-decoration: none;
}
.xt-ro-back:hover { text-decoration: underline; }
.xt-ro-back .material-symbols-outlined { font-size: 15px; }

/* Mobile (≤768px) — stack the lean header, full-width its action cluster, and
   wrap the bond action bar two-up with the Void button dropping full-width so
   nothing spills past the 390px viewport. (The .xt-stat / .xt-page-header__state
   mobile rules ship in the P1 lean block above; not duplicated here.) */
@media (max-width: 768px) {
  .xt-page-header--lean {
    flex-direction: column;
    align-items: stretch;
    gap: var(--xt-s-3);
  }
  .xt-page-header--lean .xt-page-header__actions {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
  .xt-page-header--lean .xt-page-header__actions .xt-btn {
    width: 100%;
    justify-content: center;
  }

  .xt-actions--bond {
    flex-wrap: wrap;
    max-width: 100%;
    gap: var(--xt-s-2);
  }
  .xt-actions--bond .xt-btn {
    flex: 1 1 calc(50% - var(--xt-s-2));
    min-width: 0;
    justify-content: center;
  }
  .xt-actions--bond .xt-btn[style*="margin-left:auto"] {
    margin-left: 0 !important;
    flex: 1 1 100%;
  }
}

/* ============================================================
   BONDS TEMPLATE EDITOR — legacy ledger skin (PR5 partition)
   ------------------------------------------------------------
   The "Bonafide Ledger" skin (folded from bonds_ledger.css in P11c)
   used to cover every bonds + release-orders surface. The 2026-06
   Xtrius-DS redesign arc migrated all of those surfaces onto the
   canonical DS (static/css/bonds_xt.css + app primitives) and the
   arc's final PR retired the unused ledger descendants. The ONLY
   remaining `.xt-card.xt-card--ledger` consumer is the bond template
   editor (templates/pages/billing/bonds_template.html); the rules
   kept below are exactly the families that page consumes: the root
   card, `.sub`, and the single-column `.template-editor` (form column
   only — the live-preview iframe was removed 2026-07-02). The editor's
   `.field` form family rides
   the shared `.xt-card--flush .field` rules further down — the editor
   card co-classes `.xt-card--flush` for exactly that family (the
   modal SHELL chrome stays scoped `.xt-card--flush:not(.xt-card)`,
   so none of it applies to the editor's `.xt-card`).

   --bl-* token NAMES stay aliased to --xt-* at tokens.css :root —
   other features (cost simulator, help) and the editor's inline
   styles still read them.
   ============================================================ */

/* ── Ledger surface root (was .bl-bond-surface) ─────────────────────── */
.xt-card--ledger {
  padding: 16px 18px 20px;
  border-radius: 0;                 /* square ledger frame (not --xt-r-md) */
  background: var(--bl-paper-warm);
  border: 1px solid var(--bl-paper-line);
  font-family: 'IBM Plex Sans', system-ui, sans-serif;
  color: var(--bl-ink);
}
.xt-card--ledger *, .xt-card--ledger *::before, .xt-card--ledger *::after { box-sizing: border-box; }

.xt-card--ledger .sub {
  font-family: var(--xt-font-display);
  font-style: italic;
  font-size: 12px;
  color: var(--bl-ink-mute);
  margin-bottom: 12px;
}

/* a11y-hidden utility — visually removed, tab-reachable + SR-accessible.
   Global: the bonds/RO DS surfaces use it (sentinel-pinned to THIS file —
   do not move to base.css). */
.visually-hidden,
input[type="file"].visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ── Modal chrome (was .bl-bond-surface .xt-card--flush + unscoped children).
   The SHELL is unscoped to `.xt-card--flush:not(.xt-card)` so it skins the
   bonds/RO modals (which carry bare `.xt-card--flush`) wherever they mount —
   incl the standalone RO-void `#ro-modal-host` — WITHOUT touching superadmin's
   `.xt-card.xt-card--flush` cards (which carry BOTH classes). ───────────── */
.xt-card--flush:not(.xt-card) {
  max-width: 560px; margin: 0 auto; background: var(--xt-paper-3);
  border: 1px solid var(--xt-rule); box-shadow: 0 6px 18px rgba(15,20,27,0.08);
}
.xt-card--flush .head { padding: 14px 18px; border-bottom: 1px solid var(--xt-rule); display: flex; justify-content: space-between; align-items: flex-start; }
.xt-card--flush .head h3 { font-family: var(--xt-font-display); font-weight: 500; font-size: 17px; margin: 0 0 4px; }
.xt-card--flush .head .ctx { font-family: var(--xt-font-display); font-style: italic; font-size: 12px; color: var(--xt-ink-3); }
.xt-card--flush .head .x { background: none; border: 1px solid transparent; font-size: 18px; cursor: pointer; color: var(--xt-ink-3); padding: 0 6px; }
.xt-card--flush .body { padding: 18px; }
.xt-card--flush .foot {
  padding: 12px 18px; border-top: 1px solid var(--xt-rule); background: var(--xt-bg-2);
  display: flex; justify-content: flex-end; gap: 8px;
}
.xt-card--flush .warn {
  padding: 10px 12px; background: var(--xt-danger-bg); border-left: 3px solid var(--xt-danger);
  font-size: 12px; color: var(--xt-ink); margin-bottom: 12px; font-family: var(--xt-font-display); font-style: italic;
}

/* Template editor — single column (the redundant live-preview iframe was
   removed 2026-07-02; the form + Preview-PDF anchor are the only children,
   capped at a comfortable form width and left-aligned in the ledger card). */
.xt-card--ledger .template-editor { display: grid; grid-template-columns: minmax(0, 760px); gap: 12px; }
.xt-card--ledger .template-editor .form-col { background: var(--bl-paper); border: 1px solid var(--bl-paper-line); padding: 16px 18px; }
.xt-card--ledger .template-editor .form-col fieldset { border: none; border-top: 1px solid var(--bl-paper-line); padding: 14px 0 4px; margin: 0; }
.xt-card--ledger .template-editor .form-col fieldset:first-of-type { border-top: none; padding-top: 0; }
.xt-card--ledger .template-editor .form-col legend {
  font-family: 'IBM Plex Mono', monospace; font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--bl-ink-mute); padding: 0; margin-bottom: 8px;
}
.xt-card--ledger .template-editor .logo-current {
  display: flex; align-items: center; gap: 10px; margin-top: 6px; padding: 8px; background: var(--bl-paper-warm); border: 1px solid var(--bl-paper-line);
}

/* Editor responsive */
@media (max-width: 720px) {
  .xt-card--flush:not(.xt-card) { max-width: 100%; }
}

/* ============================================================
   RELEASE ORDERS — live component styles (folded from md3/release_orders.css).
   Dead state-pill / summary-chip-BEM / toolbar rules dropped (0× in templates;
   the RO state pill folded onto .xt-badge in P2). --md-sys-* retokened.
   ============================================================ */

/* RO list empty + detail tweaks */
.md3-ro-empty { text-align: center; padding: 2rem 1rem; color: var(--xt-fg-3); }
.md3-ro-empty p { margin: 0.25rem 0; }
/* .md3-ro-evidence-photo removed 2026-06-30 — the RO detail Evidence card
   (with its inline <img> preview) was dropped. */

/* Plan tease */
.md3-ro-tease { text-align: center; padding: 2rem; }
.md3-ro-tease__header { margin-bottom: 1rem; }
.md3-ro-tease__list { display: inline-block; text-align: left; margin: 1rem auto; }
.md3-ro-tease__cta { margin-top: 1rem; }

/* Outward FIFO picker (unscoped — mounts inside/outside the ledger surface) */
.picker-card.md3-ro-picker {
  background: #ffffff; border: 1px solid var(--xt-rule); border-left: 4px solid var(--xt-ember); padding: 12px 14px; margin-bottom: 10px;
}
.picker-card.md3-ro-picker.empty { border-left-color: var(--xt-danger); background: var(--xt-danger-bg); }
.picker-card.md3-ro-picker .head {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-family: 'IBM Plex Mono', 'Menlo', monospace;
  font-size: 11px; letter-spacing: 0.06em; color: #1a1a1a; margin-bottom: 8px;
}
.picker-card.md3-ro-picker .head .material-symbols-outlined { font-size: 18px; color: var(--xt-ember); }
.picker-card.md3-ro-picker.empty .head .material-symbols-outlined { color: var(--xt-danger); }
.md3-ro-picker__client { font-weight: 400; color: var(--xt-ink-3); }
.md3-ro-picker__rationale { font-family: var(--xt-font-display); font-style: italic; font-size: 12px; margin: 6px 0 8px; color: var(--xt-danger); }
.md3-ro-picker__cta { display: inline-flex; align-items: center; gap: 6px; margin-top: 4px; }
.md3-ro-picker__cta-arrow { font-size: 0.95rem; }
.picker-card.md3-ro-picker select {
  width: 100%; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 14px; padding: 9px 11px;
  border: 1px solid var(--xt-rule); background: #ffffff; color: #1a1a1a;
}
.picker-card.md3-ro-picker .xt-eyebrow {
  font-family: 'IBM Plex Mono', 'Menlo', monospace; font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--xt-ink-3);
}
.picker-card.md3-ro-picker .xt-eyebrow .req { color: var(--xt-danger); }
.picker-card.md3-ro-picker .btn {
  font-family: 'IBM Plex Mono', 'Menlo', monospace; font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 9px 14px; border: 1px solid var(--xt-ink); background: var(--xt-paper-3); color: var(--xt-ink); cursor: pointer; text-decoration: none;
  display: inline-flex; align-items: center; gap: 6px;
}
.picker-card.md3-ro-picker .btn.primary { background: var(--xt-ink); color: var(--xt-paper-3); }
.picker-card.md3-ro-picker .btn.primary:hover { background: var(--xt-danger); border-color: var(--xt-danger); }
.picker-card.md3-ro-picker .btn .material-symbols-outlined { font-size: 16px; }

/* Dashboard chip (xt-chip + md3-ro-chip + ro-chip-released/pending) */
.md3-ro-dashboard-chip .xt-chip-row { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.md3-ro-chip { cursor: default; font-size: 0.85rem; }
.ro-chip-released { background: var(--xt-signal-bg); }
.ro-chip-pending  { background: var(--xt-ember-bg); }

/* Create-modal cap banner (unscoped — mounts in `.xt-card--flush`) */
.xt-card--flush .cap-banner,
.cap-banner {
  background: var(--xt-ember-bg); border: 1px solid var(--xt-ember); padding: 10px 12px;
  display: flex; justify-content: space-between; gap: 12px; margin-bottom: 16px;
}
.xt-card--flush .cap-banner .col,
.cap-banner .col { display: flex; flex-direction: column; gap: 2px; }
.xt-card--flush .cap-banner .lbl,
.cap-banner .lbl {
  font-family: 'IBM Plex Mono', 'Menlo', monospace; font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--xt-ink-3);
}
.xt-card--flush .cap-banner .v,
.cap-banner .v { font-family: var(--xt-font-display); font-size: 15px; font-weight: 500; color: #1a1a1a; }
.xt-card--flush .cap-banner .v.remaining,
.cap-banner .v.remaining { color: var(--xt-danger); }

/* Create-modal photo uploader (unscoped) */
.xt-card--flush .photo-uploader,
.field > .photo-uploader {
  display: flex; align-items: center; gap: 12px; padding: 12px; border: 1px dashed var(--xt-rule); background: var(--xt-bg-2); margin-top: 6px;
}
.xt-card--flush .photo-uploader .pick,
.field > .photo-uploader .pick {
  font-family: 'IBM Plex Mono', 'Menlo', monospace; font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 9px 14px; border: 1px solid #1a1a1a; background: #ffffff; color: #1a1a1a; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
}
.xt-card--flush .photo-uploader .name,
.field > .photo-uploader .name { font-family: 'IBM Plex Mono', 'Menlo', monospace; font-size: 11px; color: var(--xt-ink-3); }

/* Form fields — shared by the bonds/RO create modals AND the bond template
   editor (its `.xt-card` co-classes `.xt-card--flush` for exactly this
   family; the modal SHELL above is :not(.xt-card)-scoped so it skips it). */
.xt-card--flush .field { margin-bottom: 14px; }
.xt-card--flush .field > label {
  display: block; font-family: 'IBM Plex Mono', 'Menlo', monospace; font-size: 10px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--xt-ink-3); margin-bottom: 5px;
}
.xt-card--flush .field > label .req { color: var(--xt-danger); }
.xt-card--flush .field input[type=number],
.xt-card--flush .field input[type=text],
.xt-card--flush .field input[type=date],
.xt-card--flush .field input[type=file],
.xt-card--flush .field textarea,
.xt-card--flush .field select {
  width: 100%; font-family: 'IBM Plex Sans', system-ui, sans-serif; font-size: 14px; padding: 9px 11px;
  border: 1px solid var(--xt-rule); background: #ffffff; color: #1a1a1a; box-sizing: border-box;
}
.xt-card--flush .field input:focus,
.xt-card--flush .field textarea:focus,
.xt-card--flush .field select:focus { outline: none; border-color: #1a1a1a; }
.xt-card--flush .field .hint { font-family: var(--xt-font-display); font-style: italic; font-size: 11px; color: var(--xt-ink-3); margin-top: 4px; }

/* Evidence photo widget (create modal) */
.md3-ro-photo-field { display: flex; flex-direction: column; gap: 0.25rem; }
.md3-ro-photo-uploader { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.md3-ro-photo-pick { cursor: pointer; }
.md3-ro-photo-thumb { max-width: 96px; max-height: 96px; border-radius: 0.35rem; object-fit: cover; border: 1px solid var(--xt-rule); }
.md3-ro-photo-name { font-size: 0.85rem; color: var(--xt-fg-3); }
.md3-ro-photo-error { color: var(--xt-danger); font-size: 0.8rem; }
.md3-ro-photo-req { color: var(--xt-danger); font-weight: 600; margin-right: 2px; }
.md3-ro-photo-req-hint { font-size: 0.78rem; color: var(--xt-fg-3); font-style: italic; margin-left: 2px; }

/* ============================================================
   COLUMN PICKER (shared)
   THE one column-picker visual, rendered by
   templates/components/_column_picker.html on every list page.
   Ported from .bp-colpick* (billing_payments.css) under the .xt-colpick
   namespace; behaviours in static/js/report_column_picker.js.
   ============================================================ */
.xt-colpick { position: relative; }
.xt-colpick__btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--xt-rule-2); border-radius: var(--xt-r-sm);
  background: var(--xt-paper-3); color: var(--xt-fg-2);
  font-family: var(--xt-font-body); font-size: 13px; font-weight: 500; cursor: pointer;
  transition: background var(--xt-dur-fast) var(--xt-ease),
              color var(--xt-dur-fast) var(--xt-ease),
              border-color var(--xt-dur-fast) var(--xt-ease);
}
.xt-colpick__btn .material-symbols-outlined { font-size: 16px; }
.xt-colpick__btn:hover { background: var(--xt-paper-2); color: var(--xt-fg-1); }
.xt-colpick__count {
  font-family: var(--xt-font-mono); font-size: 11px; color: var(--xt-fg-4);
}
.xt-colpick__pop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40;
  width: 216px; background: var(--xt-paper-3);
  border: 1px solid var(--xt-rule); border-radius: var(--xt-r-md);
  box-shadow: var(--xt-elev-2); padding: 6px;
}
.xt-colpick__pop[hidden] { display: none; }
.xt-colpick__head {
  font-family: var(--xt-font-mono); font-size: 10px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--xt-fg-4);
  padding: 6px 9px 8px;
}
.xt-colpick__row {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border-radius: var(--xt-r-sm); cursor: pointer;
  font-size: 13px; color: var(--xt-fg-1); user-select: none;
}
.xt-colpick__row:hover { background: var(--xt-paper-2); }
.xt-colpick__row input { width: 15px; height: 15px; accent-color: var(--xt-signal); cursor: pointer; flex-shrink: 0; }
.xt-colpick__row.locked { color: var(--xt-fg-3); cursor: default; }
.xt-colpick__row.locked:hover { background: transparent; }
.xt-colpick__lock { margin-left: auto; color: var(--xt-fg-4); display: inline-flex; }
.xt-colpick__lock .material-symbols-outlined { font-size: 14px; }
.xt-colpick__reset {
  width: 100%; text-align: left; padding: 6px 9px;
  background: none; border: none; cursor: pointer;
  font-family: var(--xt-font-body); font-size: 12px; color: var(--xt-fg-3);
  transition: color var(--xt-dur-fast) var(--xt-ease);
}
.xt-colpick__reset:hover { color: var(--xt-signal); }

/* ── ambient background refresh ─────────────────────────────────────────
   Sections that re-fetch as a side effect of another field changing (the
   inward rate-card picker + VA charges mounts) dim while their htmx
   request is in flight instead of raising the page-blocking loading
   overlay — pair this class with data-no-overlay on the same element. */
.xt-ambient-update.htmx-request {
  opacity: 0.55;
  transition: opacity 0.15s ease;
  pointer-events: none;
}
