/* ==========================================================================
   Prototype chrome — device frames, prototype bar, toaster, tour.
   Structural, brand-neutral. Copy into <POC>/assets/css/components.css and
   re-skin with the project's tokens. Requires the token contract.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Phone. A fixed 390x844 canvas scaled to always fit the viewport, so the
   whole device is visible without scrolling the browser. On a real handset
   the frame disappears and the app fills the screen.
   -------------------------------------------------------------------------- */
.phone-stage {
  --phone-fit: 1;
  height: 100dvh; overflow: hidden;
  display: grid; grid-template-columns: auto; place-content: center; place-items: center;
  column-gap: var(--s-10);
  padding: var(--s-4) var(--gutter) calc(var(--pocbar-h) + var(--s-4));
  background: var(--surface-2);
}
.phone {
  position: relative; flex: none;
  width: 390px; height: 844px;
  transform: scale(var(--phone-fit)); transform-origin: center;
  display: flex; flex-direction: column;
  background: var(--bg); color: var(--ink);
  border: 10px solid #15130f; border-radius: 46px;
  box-shadow: 0 40px 80px -20px rgb(0 0 0 / 0.35), 0 0 0 1px rgb(0 0 0 / 0.08);
  overflow: hidden;
}
.phone::before {                      /* notch */
  content: ''; position: absolute; left: 50%; top: 10px; transform: translateX(-50%);
  width: 120px; height: 34px; background: #15130f; border-radius: 20px; z-index: 5;
}
.phone-status {
  display: flex; align-items: center; justify-content: space-between;
  height: 54px; padding: 12px 28px 0; font-size: var(--t-14); font-weight: 600; flex: none;
}
.phone-scroll {
  flex: 1; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  scrollbar-width: none; position: relative; display: flex; flex-direction: column;
}
.phone-scroll::-webkit-scrollbar { display: none; }
.phone-scroll > * { flex-shrink: 0; }   /* or horizontal card rows collapse */
.phone-tabbar {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  height: 84px; padding: 8px 8px 24px; flex: none;
  border-top: 1px solid var(--line); background: var(--surface);
}
.phone-tabbar a {
  position: relative; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 3px;
  font-size: 10.5px; font-weight: 600; color: var(--muted);
  border-radius: var(--r-ctl); min-height: 44px; text-decoration: none;
}
.phone-tabbar a .ico { width: 24px; height: 24px; }
.phone-tabbar a[aria-current="page"] { color: var(--primary); }
.phone-home {
  position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%);
  width: 134px; height: 5px; border-radius: 3px; background: var(--ink); opacity: .9; z-index: 4;
}
.phone { --app-gutter: var(--s-4); }

/* The narration column beside the device: what this screen proves. */
.phone-caption {
  display: none; align-self: center; max-width: 34ch; text-align: left;
  font-size: var(--t-14); line-height: 1.55; color: var(--ink-2);
}
.phone-caption strong {
  display: block; color: var(--ink); font-family: var(--font-display);
  font-size: var(--t-18); font-weight: 600; margin-bottom: var(--s-2);
}
@media (min-width: 1100px) {
  .phone-stage { grid-template-columns: auto minmax(260px, 34ch); }
  .phone-caption { display: block; }
}

/* Step the scale down so the device always fits the window height. */
@media (max-height: 940px) { .phone-stage { --phone-fit: .95; } }
@media (max-height: 880px) { .phone-stage { --phone-fit: .90; } }
@media (max-height: 820px) { .phone-stage { --phone-fit: .84; } }
@media (max-height: 770px) { .phone-stage { --phone-fit: .78; } }
@media (max-height: 700px) { .phone-stage { --phone-fit: .72; } }
@media (max-height: 640px) { .phone-stage { --phone-fit: .66; } }

/* On an actual handset the app IS the page. The frame, notch, status bar and
   home indicator disappear; the app fills the screen minus the prototype bar. */
@media (max-width: 600px) {
  .phone-stage { --phone-fit: 1; padding: 0; height: 100dvh; grid-template-columns: 1fr; background: var(--bg); }
  .phone { width: 100%; height: 100dvh; border: 0; border-radius: 0; box-shadow: none; transform: none; }
  .phone::before, .phone-status, .phone-home { display: none; }
  .phone-caption { display: none; }
  /* The bar is fixed over the viewport, so the app must give up its height or
     the tab bar hides behind it. */
  body.has-pocbar .phone-stage,
  body.has-pocbar .phone { height: calc(100dvh - var(--pocbar-h)); }
  .phone-tabbar { padding-bottom: 8px; height: 64px; }
}

/* --------------------------------------------------------------------------
   Tablet — staff-facing landscape surfaces (kitchen display, POS, field app).
   -------------------------------------------------------------------------- */
.tablet-stage {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-4);
  padding: var(--s-8) var(--gutter) calc(var(--pocbar-h) + var(--s-10));
  min-height: 100dvh; background: var(--surface-3);
}
.tablet {
  --tablet-fit: 1;
  position: relative; width: 1024px; height: 768px;
  transform: scale(var(--tablet-fit)); transform-origin: top center;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg); border: 12px solid #15130f; border-radius: 28px;
  box-shadow: 0 40px 80px -24px rgb(0 0 0 / 0.35);
}
.tablet-scroll { flex: 1; overflow-y: auto; overscroll-behavior: contain; }
@media (max-width: 1140px) { .tablet-stage { --tablet-fit: .82; } }
@media (max-width: 940px)  { .tablet-stage { --tablet-fit: .66; } }
@media (max-width: 760px)  { .tablet-stage { --tablet-fit: .50; } }

/* --------------------------------------------------------------------------
   Bottom sheet — the mobile-native alternative to a modal.
   -------------------------------------------------------------------------- */
.sheet-scrim {
  position: absolute; inset: 0; z-index: var(--z-layer);
  background: rgb(0 0 0 / 0.4); opacity: 0; pointer-events: none;
  transition: opacity var(--dur-2) var(--ease);
}
.sheet {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-layer) + 1);
  max-height: 82%; display: flex; flex-direction: column;
  background: var(--bg); border-radius: var(--r-lg) var(--r-lg) 0 0;
  transform: translateY(100%); transition: transform var(--dur-3) var(--ease-out);
}
.sheet::before {
  content: ''; width: 36px; height: 4px; border-radius: 2px; background: var(--line-strong);
  margin: 10px auto 2px; flex: none;
}
.sheet-body { overflow-y: auto; padding: var(--s-4) var(--app-gutter) var(--s-6); }
.layer-open .sheet-scrim { opacity: 1; pointer-events: auto; }
.layer-open .sheet { transform: translateY(0); }

/* In-frame push notification (mobile surfaces). NOT .push: that is the flex
   spacer utility in base.css, used on every workspace header and panel head. */
.pushnote {
  position: absolute; left: 8px; right: 8px; top: 58px; z-index: var(--z-toast);
  display: flex; gap: var(--s-3); padding: var(--s-3) var(--s-4);
  background: var(--bg); border-radius: var(--r-card); box-shadow: var(--e-3);
  transform: translateY(-140%); transition: transform var(--dur-3) var(--ease-out);
}
.pushnote.in { transform: translateY(0); }

/* --------------------------------------------------------------------------
   Prototype bar — the client's remote control, on every page.
   -------------------------------------------------------------------------- */
.pocbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-pocbar);
  height: var(--pocbar-h); display: flex; align-items: center; gap: var(--s-3);
  padding: 0 var(--s-4); font-size: var(--t-12);
  background: var(--drench); color: var(--on-drench);
  box-shadow: 0 -4px 20px rgb(0 0 0 / 0.2);
}
.pocbar .tagword {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .12em;
  color: var(--accent); font-weight: 500;
}
.pocbar .roles { display: flex; gap: 2px; }
.pocbar .roles a {
  padding: 4px 10px; border-radius: var(--r-full); color: var(--on-drench-muted);
  text-decoration: none; white-space: nowrap;
}
.pocbar .roles a:hover { color: var(--on-drench); background: var(--drench-2); }
.pocbar .roles a[aria-current="true"] { background: var(--primary); color: var(--on-primary); }
.pocbar .mods { display: flex; gap: 4px; }
.pocbar .tag-module {
  font-family: var(--font-mono); font-size: 10px; padding: 2px 6px;
  border: 1px solid var(--drench-line); border-radius: var(--r-full);
  color: var(--on-drench-muted); text-decoration: none;
}
.pocbar .spacer { flex: 1; }
.pocbar button.link {
  background: none; border: 0; color: var(--on-drench-muted);
  font: inherit; cursor: pointer; padding: 4px 6px; white-space: nowrap;
}
.pocbar button.link:hover { color: var(--on-drench); }
body.has-pocbar { padding-bottom: 0; }
@media (max-width: 720px) {
  .pocbar .hide-sm { display: none; }
  /* Never let the bar clip its own controls: let it scroll instead. */
  .pocbar { overflow-x: auto; scrollbar-width: none; justify-content: flex-start; }
  .pocbar::-webkit-scrollbar { display: none; }
  .pocbar > * { flex: none; }
  .pocbar .spacer { flex: 1 0 var(--s-4); }
}
@media (max-width: 420px) { .pocbar .tagword { display: none; } }

/* Module map overlay: outlines the elements proving each module. */
body.show-sow [data-module] { outline: 1px dashed var(--accent-strong); outline-offset: 2px; position: relative; }
body.show-sow [data-module]::after {
  content: attr(data-module); position: absolute; top: -8px; right: -6px; z-index: 2;
  font-family: var(--font-mono); font-size: 9px; line-height: 1;
  padding: 3px 5px; border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent);
}

/* --------------------------------------------------------------------------
   Toaster
   -------------------------------------------------------------------------- */
.toaster {
  position: fixed; right: var(--s-4); bottom: calc(var(--pocbar-h) + var(--s-4));
  z-index: var(--z-toast); display: flex; flex-direction: column-reverse;
  gap: var(--s-2); pointer-events: none;
}
body:not(.has-pocbar) .toaster { bottom: var(--s-4); }
.toast {
  max-width: 42ch; padding: var(--s-3) var(--s-4);
  background: var(--drench); color: var(--on-drench);
  border-radius: var(--r-ctl); box-shadow: var(--e-3);
  font-size: var(--t-14); animation: toast-in var(--dur-3) var(--ease-out);
}
.toast.ok { background: var(--success); } .toast.warn { background: var(--warning); color: var(--on-accent); }
.toast.err { background: var(--danger); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* --------------------------------------------------------------------------
   Guided tour
   -------------------------------------------------------------------------- */
.tour-scrim { position: fixed; inset: 0; z-index: var(--z-tour); background: rgb(0 0 0 / 0.55); }
.tour-hole { position: fixed; z-index: calc(var(--z-tour) + 1); border-radius: var(--r-card);
  box-shadow: 0 0 0 9999px rgb(0 0 0 / 0.55), 0 0 0 3px var(--accent); pointer-events: none; }
.tour-pop {
  position: fixed; z-index: calc(var(--z-tour) + 2); max-width: 34ch;
  padding: var(--s-4); background: var(--bg); color: var(--ink);
  border-radius: var(--r-card); box-shadow: var(--e-3);
}
.tour-pop .step { font-family: var(--font-mono); font-size: var(--t-11); color: var(--muted); }
.tour-pop h3 { font-size: var(--t-16); margin: var(--s-1) 0 var(--s-2); }
.tour-pop p { font-size: var(--t-14); line-height: 1.5; color: var(--ink-2); }
.tour-pop .row { display: flex; gap: var(--s-2); justify-content: flex-end; margin-top: var(--s-4); }

/* Reveal, skip-link and :focus-visible live in base.css — one owner. */

/* ==========================================================================
   SARVA FOAM ERP — component layer.
   Form archetype: LEDGER. Everything below reads its radius, border weight,
   elevation, density and divider strategy from tokens.css. No literals.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. THE SHELL — module rail + contextual panel + workspace header + drawer.
   The rail IS the access model: it contains only the workspaces this user
   owns. See docs/MODULES.md §1.
   -------------------------------------------------------------------------- */
.app {
  display: grid;
  grid-template-columns: var(--rail-w) var(--panel-w) minmax(0, 1fr);
  min-height: 100dvh;
}
body.has-pocbar .app { min-height: calc(100dvh - var(--pocbar-h)); }

/* --- Module rail ---
   Bands: what you own, what you may read, the cross-cutting layers, then you.
   Every item has a flyout label — an unlabelled icon rail is a memory test. --- */
.rail {
  grid-column: 1; position: sticky; top: 0; align-self: start;
  height: 100dvh; display: flex; flex-direction: column; align-items: center;
  gap: 2px; padding: var(--s-2) 0; overflow: visible;
  background: var(--drench); color: var(--on-drench-muted);
  border-right: var(--bw) solid var(--drench-line);
}
body.has-pocbar .rail { height: calc(100dvh - var(--pocbar-h)); }
.rail-mark {
  width: 34px; height: 34px; margin-bottom: var(--s-2); flex: none;
  display: grid; place-items: center; border-radius: var(--r-ctl);
  background: var(--brand-red); color: #fff; position: relative;
  font-family: var(--font-display); font-weight: 700; font-size: var(--t-16);
  letter-spacing: 0.02em; text-decoration: none;
}
/* Band captions: three letters, so the rail explains its own grouping. */
.rail-band {
  font-family: var(--font-display); font-size: 9px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--on-drench-muted); opacity: .62;
  margin: var(--s-2) 0 2px; flex: none;
}
.rail-item {
  width: 44px; height: 40px; flex: none;
  display: grid; place-items: center; border-radius: var(--r-ctl);
  color: var(--on-drench-muted); position: relative; text-decoration: none;
  border: var(--bw) solid transparent;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.rail-item .ico { width: 20px; height: 20px; }
.rail-item:hover { background: var(--drench-2); color: var(--on-drench); }
.rail-item[aria-current="true"] { background: var(--drench-2); color: var(--on-drench); }
.rail-item[aria-current="true"]::before {
  content: ''; position: absolute; left: -8px; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 2px 2px 0; background: var(--accent);
}
/* Read-only: present, reachable, and unmistakably not yours to change. */
.rail-item.is-view { border-color: var(--drench-line); border-style: dashed; opacity: .78; }
.rail-item.is-view:hover { opacity: 1; }
.rail-item .badge-dot {
  position: absolute; top: 5px; right: 6px; width: 7px; height: 7px;
  border-radius: var(--r-full); background: var(--warning);
  border: 1.5px solid var(--drench);
}
.rail-sep { width: 24px; height: var(--bw); background: var(--drench-line); margin: var(--s-3) 0; flex: none; }
.rail-foot { margin-top: auto; display: flex; flex-direction: column; gap: 2px; align-items: center; }
.rail-me {
  width: 30px; height: 30px; margin-top: var(--s-2); flex: none;
  display: grid; place-items: center; border-radius: var(--r-full);
  background: var(--drench-2); color: var(--on-drench); position: relative;
  border: var(--bw) solid var(--drench-line); text-decoration: none;
  font-family: var(--font-display); font-size: var(--t-12); font-weight: 700;
}
.rail-me:hover { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* Flyout label. Absolute so it escapes the 60px rail; the rail is the only
   element on the page with overflow visible for exactly this reason. */
.rail-mark::after, .rail-item::after, .rail-me::after {
  content: attr(data-label) attr(data-sub);
  position: absolute; left: calc(100% + 10px); top: 50%; transform: translateY(-50%);
  z-index: calc(var(--z-layer) + 1); pointer-events: none;
  padding: var(--s-2) var(--s-3); max-width: 220px; width: max-content;
  background: var(--ink); color: var(--surface);
  border-radius: var(--r-card); box-shadow: var(--elev-pop);
  font-family: var(--font-body); font-size: var(--t-13); font-weight: 600;
  line-height: 1.35; text-align: left; white-space: pre-line;
  opacity: 0; visibility: hidden; transition: opacity var(--dur-1) var(--ease);
}
.rail-mark:hover::after, .rail-item:hover::after, .rail-me:hover::after,
.rail-mark:focus-visible::after, .rail-item:focus-visible::after, .rail-me:focus-visible::after {
  opacity: 1; visibility: visible;
}

/* --- Contextual panel: this workspace's sub-modules --- */
.panelnav {
  grid-column: 2; position: sticky; top: 0; align-self: start;
  height: 100dvh; overflow-y: auto;
  background: var(--surface); border-right: var(--rule);
  padding: var(--s-3) 0;
}
body.has-pocbar .panelnav { height: calc(100dvh - var(--pocbar-h)); }
.panelnav-hd {
  padding: var(--s-2) var(--s-4) var(--s-3);
  border-bottom: var(--rule);
}
.panelnav-hd .ws {
  font-family: var(--font-display); font-size: var(--t-18); font-weight: 600;
  line-height: 1.15; letter-spacing: var(--tracking-heading); color: var(--ink);
}
.panelnav-hd .team { margin-top: 2px; }

/* Sub-headings are bands, not just smaller text: a hairline opens each group
   and its screens sit indented under it, so the eye reads sections before it
   reads nineteen links. */
.panelnav-group {
  margin-top: var(--s-2);
  padding: var(--s-3) var(--s-4) var(--s-2);
  border-top: var(--rule);
  color: var(--muted);
}
.panelnav a {
  display: flex; align-items: center; gap: var(--s-2);
  min-height: 30px;
  padding: 6px var(--s-3) 6px calc(var(--s-4) + var(--s-3));
  margin: 0;
  color: var(--ink-2); font-size: var(--t-14); line-height: 1.35;
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
/* The screens above the first sub-heading are the workspace's own top level. */
.panelnav-hd + a { margin-top: var(--s-2); }
.panelnav-group + a { margin-top: 0; }
.panelnav a:hover { background: var(--surface-2); color: var(--ink); }
.panelnav a[aria-current="page"] {
  background: var(--primary-soft); color: var(--primary-strong);
  font-weight: 600; border-left-color: var(--primary);
}
.panelnav a .n { margin-left: auto; color: var(--muted); font-size: var(--t-12); }
.panelnav a[aria-current="page"] .n { color: var(--primary-strong); }

/* --- Workspace header: inside the content column, not spanning the app --- */
.wsmain { grid-column: 3; min-width: 0; display: flex; flex-direction: column; }
.wshead {
  position: sticky; top: 0; z-index: var(--z-sticky);
  min-height: var(--wshead-h); display: flex; align-items: center; gap: var(--s-3);
  padding: 0 var(--s-5); background: var(--surface); border-bottom: var(--rule);
}
.wshead .crumb { display: flex; align-items: center; gap: var(--s-2); font-size: var(--t-13); color: var(--muted); min-width: 0; }
.wshead .crumb a { color: var(--muted); text-decoration: none; }
.wshead .crumb a:hover { color: var(--ink); text-decoration: underline; }
.wshead .crumb .sep { color: var(--line-strong); }
.wshead .crumb strong { color: var(--ink); font-weight: 600; }
.wsbody { padding: var(--s-5); flex: 1 1 auto; min-width: 0; }
.wsbody > * + * { margin-top: var(--s-5); }

.pagehead { display: flex; align-items: flex-start; gap: var(--s-4); flex-wrap: wrap; }
.pagehead .sub { margin-top: var(--s-1); color: var(--muted); font-size: var(--t-14); max-width: 78ch; }

/* Small screens: the rail and panel collapse to an off-canvas drawer. */
/* Breakpoint matches .only-sm / .hide-sm in base.css: the shell must not
   collapse before the button that reopens it appears. */
@media (max-width: 900px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  /* The children carry explicit grid-column values. Left set, a one-column
     grid creates implicit columns 2 and 3 and pushes content off-screen. */
  .rail, .panelnav, .wsmain { grid-column: 1; }
  .rail, .panelnav {
    position: fixed; top: 0; z-index: var(--z-layer); height: 100dvh;
    transform: translateX(-100%); visibility: hidden;
    transition: transform var(--dur-2) var(--ease), visibility 0s linear var(--dur-2);
  }
  .rail { left: 0; }
  .panelnav { left: var(--rail-w); width: var(--panel-w); border-right: var(--rule); }
  body.nav-open .rail, body.nav-open .panelnav {
    transform: none; visibility: visible; transition-delay: 0s;
  }
  body.nav-open .wsmain::after {
    content: ''; position: fixed; inset: 0; z-index: calc(var(--z-layer) - 1);
    background: oklch(0.235 0.022 196 / 0.42);
  }
  .wsbody { padding: var(--s-4); }
}

/* --------------------------------------------------------------------------
   2. PANEL — the ledger's container. Bounded by a hairline, never floated.
   -------------------------------------------------------------------------- */
.panel {
  background: var(--surface);
  border: var(--rule);
  border-radius: var(--r-card);
  box-shadow: var(--elev-card);
}
.panel-hd {
  display: flex; align-items: center; gap: var(--s-3);
  min-height: 38px; padding: var(--s-2) var(--pad-card);
  border-bottom: var(--bw-strong) solid var(--line-strong);
}
.panel-hd h2, .panel-hd h3 { margin: 0; }
.panel-bd { padding: var(--pad-card); }
.panel-bd.flush { padding: 0; }
.panel-ft {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--pad-card); border-top: var(--rule);
  background: var(--surface-2); font-size: var(--t-13); color: var(--muted);
  border-radius: 0 0 var(--r-card) var(--r-card);
}
.panel.accent { border-color: var(--primary-soft-2); }
.panel.flat { background: transparent; border: 0; }

/* --------------------------------------------------------------------------
   3. TABLE — the centrepiece. A ruled grid, because that is what a ledger is.
   -------------------------------------------------------------------------- */
.tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.tbl { width: 100%; border-collapse: collapse; font-size: var(--t-14); }
table.tbl th, table.tbl td {
  padding: var(--s-2) var(--s-3); min-height: var(--h-row);
  /* A ledger is ruled across, not gridded. Vertical rules on every cell were
     what made this read as a spreadsheet rather than a record. */
  border-bottom: var(--row-rule);
  text-align: left; vertical-align: middle;
}
table.tbl thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface); color: var(--muted);
  border-bottom: var(--rule);
  white-space: nowrap; height: 34px; padding-top: 0; padding-bottom: 0;
}
table.tbl tbody tr { transition: background var(--dur-1) var(--ease); }
table.tbl tbody tr:hover { background: var(--primary-soft); }
table.tbl tbody tr[aria-selected="true"] { background: var(--accent-soft); }
table.tbl tbody tr:last-child td { border-bottom: 0; }
/* Numbers never wrap: '\u20b94.20 Cr' broken over two lines is unreadable. */
table.tbl td.num, table.tbl th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
table.tbl td.tight { width: 1%; white-space: nowrap; }
table.tbl a { text-decoration: none; font-weight: 600; }
table.tbl a:hover { text-decoration: underline; }
/* Sort affordance on a column header */
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { color: var(--ink); background: var(--surface-3); }
th.sortable[aria-sort] { color: var(--primary-strong); }
th.sortable[aria-sort="ascending"]::after { content: ' \2191'; }
th.sortable[aria-sort="descending"]::after { content: ' \2193'; }
/* Totals row — a ledger always foots */
table.tbl tfoot td {
  background: var(--surface-2); font-weight: 700; color: var(--ink);
  border-top: var(--bw-strong) solid var(--line-strong); border-bottom: 0;
}

/* Toolbar above a table: search, filters, bulk actions */
.toolbar {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: nowrap;
  padding: var(--s-3) var(--pad-card); border-bottom: var(--rule);
  background: var(--surface);
}
.toolbar .search { flex: 0 1 240px; min-width: 120px; }

/* A single-select filter dimension, labelled inline so it reads as a sentence
   rather than a mystery dropdown. */
.tb-sel { display: inline-flex; align-items: center; }
/* §4.4 date range. The inputs sit on the same baseline and the same height as
   every other toolbar control — a control that ships a few pixels taller than
   its neighbours is what the client sees before anything else. */
.tb-range { display: inline-flex; align-items: center; gap: var(--s-2); flex: 0 0 auto; }
.tb-custom { display: inline-flex; align-items: center; gap: var(--s-2); }
.tb-range .input { width: 8.25rem; }
.tb-range-to { color: var(--muted); font-size: var(--t-12); }
/* The right-hand group moves as one block, so a wrap never strands a lone icon. */
.tb-end { display: inline-flex; align-items: center; gap: var(--s-2); margin-left: auto; flex: 0 0 auto; }
.toolbar .push { display: none; }        /* .tb-end carries the margin now */

/* Too many dimensions for one line: the chips drop to a row of their own and
   every filter stays visible, instead of two of them scrolling out of sight. */
.toolbar-wrap { flex-wrap: wrap; row-gap: var(--s-2); }
.toolbar-wrap .chips { flex: 1 0 100%; order: 2; overflow-x: visible;
  -webkit-mask-image: none; mask-image: none; }
.toolbar-wrap .tb-end { order: 1; }

/* §4.4 — the dimensions past the first row sit one click away, in a row of
   their own under the toolbar, so a register can offer all nine without the
   toolbar breaking. */
.tb-more { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--pad-card); border-bottom: var(--rule); background: var(--surface-2); }
.tb-badge { display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px; margin-left: 4px;
  border-radius: 999px; background: var(--ink); color: var(--surface); font-size: var(--t-12); font-weight: 700; line-height: 1; }
.tb-anchor { position: relative; display: inline-flex; }
.tb-pop { position: absolute; top: calc(100% + 4px); right: 0; z-index: 30; min-width: 230px; }
.tb-view { display: flex; align-items: center; gap: 2px; }
.menu .tb-view > button:first-child { flex: 1 1 auto; min-width: 0; }
.menu .tb-view-x { width: 32px; flex: 0 0 32px; justify-content: center; padding: 0; color: var(--muted); }
.tb-pop-empty { padding: var(--s-2); margin: 0; max-width: 250px; }
.tb-saveview { display: flex; gap: var(--s-2); padding: var(--s-1); }
.tb-saveview .input { flex: 1 1 auto; min-width: 0; }
.menu .tb-saveview button { width: auto; flex: 0 0 auto; justify-content: center; }

@media (max-width: 700px) {
  .toolbar { flex-wrap: wrap; }
  .toolbar .search { flex: 1 1 100%; max-width: none; }
  .tb-end { margin-left: auto; }
}
.bulkbar {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--pad-card);
  background: var(--primary-soft); border-bottom: var(--rule);
  font-size: var(--t-13); color: var(--primary-strong);
}
.pager {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--pad-card); border-top: var(--rule);
  font-size: var(--t-13); color: var(--muted);
}

/* --------------------------------------------------------------------------
   4. BUTTONS
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: var(--h-ctl); padding: 0 var(--s-4);
  font-family: var(--font-body); font-size: var(--t-14); font-weight: 600;
  border: var(--bw) solid transparent; border-radius: var(--r-ctl);
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.btn .ico { width: 16px; height: 16px; flex: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.btn-pri { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }
.btn-pri:hover:not(:disabled) { background: var(--primary-strong); border-color: var(--primary-strong); color: var(--on-primary); }
.btn-sec { background: var(--surface); color: var(--ink); border-color: var(--line-strong); }
.btn-sec:hover:not(:disabled) { background: var(--surface-2); border-color: var(--muted-2); color: var(--ink); }
.btn-ghost { background: transparent; color: var(--ink-2); }
.btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
.btn-danger { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn-danger:hover:not(:disabled) { background: var(--danger-ink); border-color: var(--danger-ink); color: #fff; }
.btn-sm { min-height: var(--h-ctl-sm); padding: 0 var(--s-3); font-size: var(--t-13); }
.btn-lg { min-height: var(--h-ctl-lg); padding: 0 var(--s-5); font-size: var(--t-16); }
.btn-icon { width: var(--h-ctl); padding: 0; }
.btn-icon.btn-sm { width: var(--h-ctl-sm); }
.btn.loading { position: relative; color: transparent !important; pointer-events: none; }
.btn.loading::after {
  content: ''; position: absolute; width: 14px; height: 14px;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: var(--r-full); color: var(--on-primary);
  animation: spin 700ms linear infinite;
}
.btn-sec.loading::after, .btn-ghost.loading::after { color: var(--ink); }
@keyframes spin { to { transform: rotate(360deg); } }

/* Segmented control — view switching in a dense header */
.seg { display: inline-flex; border: var(--bw) solid var(--line-strong); border-radius: var(--r-ctl); overflow: hidden; }
.seg button {
  min-height: var(--h-ctl-sm); padding: 0 var(--s-3);
  font-size: var(--t-13); font-weight: 600; color: var(--muted);
  background: var(--surface); border-right: var(--bw) solid var(--line);
}
.seg button:last-child { border-right: 0; }
.seg button:hover { background: var(--surface-2); color: var(--ink); }
.seg button[aria-pressed="true"] { background: var(--primary); color: var(--on-primary); }

/* --------------------------------------------------------------------------
   5. FORM CONTROLS
   -------------------------------------------------------------------------- */
.field { display: block; }
.field > .label { display: block; margin-bottom: var(--s-1); }
.field .hint { display: block; margin-top: var(--s-1); font-size: var(--t-12); color: var(--muted); }
.field .err { display: flex; align-items: center; gap: 5px; margin-top: var(--s-1); font-size: var(--t-12); color: var(--danger-ink); font-weight: 600; }
.field .err .ico { width: 14px; height: 14px; }

.input, .select, .textarea {
  width: 100%; min-height: var(--h-ctl); padding: 0 var(--s-3);
  background: var(--surface); color: var(--ink);
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-ctl);
  font-size: var(--t-14); font-variant-numeric: tabular-nums;
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.textarea { min-height: 84px; padding: var(--s-2) var(--s-3); line-height: var(--lh-body); resize: vertical; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--muted-2); }
.input:focus, .select:focus, .textarea:focus { border-color: var(--primary); outline: 2px solid var(--accent-strong); outline-offset: -1px; }
/* Placeholders take --muted, never lighter. The pale placeholder is the single
   most common contrast failure and it is banned here. */
.input::placeholder, .textarea::placeholder { color: var(--muted); opacity: 1; }
.input:disabled, .select:disabled, .textarea:disabled { background: var(--surface-3); color: var(--muted); cursor: not-allowed; }
.input[aria-invalid="true"], .select[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger); background: var(--danger-soft); }
.input[readonly] { background: var(--surface-2); }
.select {
  appearance: none; padding-right: var(--s-6);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 14px) 52%, calc(100% - 9px) 52%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.input-sm { min-height: var(--h-ctl-sm); height: var(--h-ctl-sm); font-size: var(--t-13); }
/* One contract for every small control, so a toolbar never mixes heights.
   These MUST come after the base .input/.select, which set min-height to the
   full --h-ctl: same specificity, so source order decides. */
.select-sm { min-height: var(--h-ctl-sm); height: var(--h-ctl-sm);
  padding: 0 var(--s-5) 0 var(--s-2); font-size: var(--t-13); }

.search { position: relative; }
.search .ico { position: absolute; left: var(--s-3); top: 50%; transform: translateY(-50%); width: 16px; height: 16px; color: var(--muted); pointer-events: none; }
.search .input { padding-left: calc(var(--s-3) * 2 + 16px); }

.check { display: inline-flex; align-items: center; gap: var(--s-2); cursor: pointer; font-size: var(--t-14); min-height: 24px; }
.check input { width: 16px; height: 16px; accent-color: var(--primary); cursor: pointer; flex: none; }
.check input:disabled { cursor: not-allowed; }
.check input:disabled + span { color: var(--muted); }

.toggle { display: inline-flex; align-items: center; gap: var(--s-2); cursor: pointer; font-size: var(--t-14); }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle .track {
  width: 36px; height: 20px; flex: none; border-radius: var(--r-full);
  background: var(--line-strong); position: relative;
  transition: background var(--dur-1) var(--ease);
}
.toggle .track::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: var(--r-full); background: var(--surface);
  transition: transform var(--dur-1) var(--ease);
}
.toggle input:checked + .track { background: var(--primary); }
.toggle input:checked + .track::after { transform: translateX(16px); }
.toggle input:focus-visible + .track { outline: 2px solid var(--accent-strong); outline-offset: 2px; }

.file {
  display: flex; align-items: center; gap: var(--s-3); padding: var(--s-4);
  border: var(--bw) dashed var(--line-strong); border-radius: var(--r-ctl);
  background: var(--surface-2); font-size: var(--t-14); color: var(--muted);
}
.file .ico { width: 20px; height: 20px; }

/* Record field list — how a detail screen states its facts */
.dl { display: grid; grid-template-columns: minmax(120px, max-content) 1fr; gap: var(--s-2) var(--s-4); font-size: var(--t-14); }
.dl dt { color: var(--muted); font-family: var(--font-display); font-size: var(--t-12); font-weight: 600; letter-spacing: var(--tracking-label); text-transform: var(--case-head); align-self: center; }
.dl dd { color: var(--ink); font-weight: 500; }

/* --------------------------------------------------------------------------
   6. STATUS VOCABULARY — square tags. They replace rubber stamps on a paper
   batch record, so they are stamped, not pilled. Colour is never the only
   signal: every tag carries a word, and the critical ones carry an icon.
   -------------------------------------------------------------------------- */
.tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px; border-radius: var(--r-ctl);
  font-family: var(--font-display); font-size: var(--t-12); font-weight: 600;
  letter-spacing: 0.04em; text-transform: var(--case-head); white-space: nowrap;
  border: var(--bw) solid transparent;
}
.tag .ico { width: 12px; height: 12px; }
.tag-neutral { background: var(--surface-3); color: var(--ink-2); border-color: var(--line-strong); }
.tag-ok      { background: var(--success-soft); color: var(--success-ink); border-color: var(--success); }
.tag-warn    { background: var(--warning-soft); color: var(--warning-ink); border-color: var(--warning); }
.tag-danger  { background: var(--danger-soft);  color: var(--danger-ink);  border-color: var(--danger); }
.tag-info    { background: var(--info-soft);    color: var(--info-ink);    border-color: var(--info); }
.tag-brand   { background: var(--primary-soft); color: var(--primary-strong); border-color: var(--primary-soft-2); }
.tag-solid   { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }

/* --------------------------------------------------------------------------
   7. DOMAIN COMPONENTS — the parts that exist because this is Sarva Foam.
   -------------------------------------------------------------------------- */

/* 7a. Density grade chip. Density (kg/m3) is the axis this business turns on:
   it drives BOM, yield standard, price, QC spec and how much fits on a truck.
   A SEQUENTIAL ramp, because density is ordered. Ink flips at D130. */
.dchip {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 44px; height: 20px; padding: 0 6px;
  border-radius: var(--r-ctl); border: var(--bw) solid oklch(0.235 0.022 196 / 0.14);
  font-family: var(--font-display); font-size: var(--t-12); font-weight: 700;
  letter-spacing: 0.03em; font-variant-numeric: tabular-nums;
}
.dchip.d80  { background: var(--d-80);  color: var(--d-ink-lo); }
.dchip.d100 { background: var(--d-100); color: var(--d-ink-lo); }
.dchip.d110 { background: var(--d-110); color: var(--d-ink-lo); }
.dchip.d120 { background: var(--d-120); color: var(--d-ink-lo); }
.dchip.d130 { background: var(--d-130); color: var(--d-ink-hi); }
.dchip.d150 { background: var(--d-150); color: var(--d-ink-hi); }
.dscale { display: flex; gap: 2px; align-items: center; }

/* 7b. Lineage breadcrumb — forward/backward genealogy, click-through.
   Present on every record: dispatch -> bundle -> block -> batch -> GRN -> bale. */
.lineage { display: flex; align-items: center; gap: var(--s-1); flex-wrap: wrap; font-size: var(--t-13); }
.lineage a, .lineage span.node {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px var(--s-2); border-radius: var(--r-ctl);
  background: var(--surface-2); border: var(--rule);
  color: var(--ink-2); text-decoration: none; font-weight: 500;
}
.lineage a:hover { background: var(--primary-soft); border-color: var(--primary-soft-2); color: var(--primary-strong); }
.lineage .node.here { background: var(--primary); color: var(--on-primary); border-color: var(--primary); font-weight: 600; }
.lineage .arrow { color: var(--muted-2); flex: none; }
.lineage .ico { width: 13px; height: 13px; }

/* 7c. Cure countdown — a block cannot go to cutting before its cure elapses.
   Gate G7. The most physical control in the system. */
.cure { display: flex; align-items: center; gap: var(--s-3); }
.cure-clock {
  font-family: var(--font-display); font-size: var(--t-22); font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: 0.01em; line-height: 1;
}
.cure-clock.blocked { color: var(--warning-ink); }
.cure-clock.ready   { color: var(--success-ink); }
.cure-bar { height: 6px; border-radius: var(--r-ctl); background: var(--surface-3); overflow: hidden; flex: 1 1 auto; min-width: 80px; }
.cure-bar > i { display: block; height: 100%; background: var(--warning); transition: width var(--dur-3) var(--ease); }
.cure-bar.ready > i { background: var(--success); }

/* 7d. Weighbridge block — gross / tare / net, then the deductions that turn
   net into USABLE kg. Sarva buys waste by weight at unverifiable quality;
   this is where the margin is decided. */
.weigh { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 0; border: var(--rule); border-radius: var(--r-card); overflow: hidden; }
.weigh > div { padding: var(--s-3); border-right: var(--rule); background: var(--surface); }
.weigh > div:last-child { border-right: 0; }
.weigh .k { display: block; }
.weigh .v { font-family: var(--font-display); font-size: var(--t-22); font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; margin-top: 2px; }
.weigh .v small { font-size: var(--t-12); font-weight: 600; color: var(--muted); margin-left: 2px; }
.weigh .deduct .v { color: var(--danger-ink); }
.weigh .final { background: var(--primary-soft); }
.weigh .final .v { color: var(--primary-strong); }

/* 7e. Gate badge — a handoff that is blocked, and by what. See MODULES.md §3. */
.gate {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-2); border-radius: var(--r-ctl);
  border: var(--bw) solid var(--warning); background: var(--warning-soft);
  color: var(--warning-ink); font-size: var(--t-13); font-weight: 600;
}
.gate .ico { width: 15px; height: 15px; flex: none; }
.gate.open   { border-color: var(--success); background: var(--success-soft); color: var(--success-ink); }
.gate.hard   { border-color: var(--danger);  background: var(--danger-soft);  color: var(--danger-ink); }

/* 7f. Unit selector — Bhopal / Hosur / Unit-3 / Unit-4 */
.unitsel {
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: var(--h-ctl-sm); padding: 0 var(--s-2) 0 var(--s-3);
  border: var(--rule); border-radius: var(--r-ctl); background: var(--surface-2);
  font-size: var(--t-13); font-weight: 600; color: var(--ink-2);
}
.unitsel .ico { width: 14px; height: 14px; color: var(--muted); }

/* 7g. Persona chip */
.persona { display: inline-flex; align-items: center; gap: var(--s-2); }
.avatar {
  width: 26px; height: 26px; flex: none; border-radius: var(--r-full);
  display: grid; place-items: center; background: var(--primary-soft-2);
  color: var(--primary-strong); font-family: var(--font-display);
  font-size: var(--t-12); font-weight: 700;
}
.avatar.lg { width: 36px; height: 36px; font-size: var(--t-14); }

/* 7h. Figure row — compact ledger figures. Deliberately NOT the hero-metric
   template: no giant number, no gradient, no supporting-stat trio. */
.figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); border: var(--rule); border-radius: var(--r-card); background: var(--surface); overflow: hidden; }
.figs > div { padding: var(--s-3) var(--pad-card); border-right: var(--rule); }
.figs > div:last-child { border-right: 0; }
.figs .v { font-family: var(--font-display); font-size: var(--t-28); font-weight: 600; line-height: 1.05; font-variant-numeric: tabular-nums; margin-top: 2px; }
.figs .d { font-size: var(--t-12); font-weight: 600; margin-top: 3px; }
.figs .d.up { color: var(--success-ink); } .figs .d.dn { color: var(--danger-ink); }
@media (max-width: 760px) { .figs > div { border-right: 0; border-bottom: var(--rule); } }

/* 7i. Utilisation bar — capacity, load fill, yield against standard */
.util { display: flex; align-items: center; gap: var(--s-2); }
.util-bar { flex: 1 1 auto; min-width: 60px; height: 8px; background: var(--surface-3); border-radius: var(--r-ctl); overflow: hidden; }
.util-bar > i { display: block; height: 100%; background: var(--primary); }
.util-bar.warn > i { background: var(--warning); }
.util-bar.over > i { background: var(--danger); }
.util .pc { font-size: var(--t-13); font-weight: 700; font-variant-numeric: tabular-nums; min-width: 38px; text-align: right; }

/* 7j. Lifecycle timeline — the 13-state sales order, the PO, the shipment */
.states { display: flex; flex-wrap: wrap; gap: 2px; }
.states .st {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px var(--s-2); font-size: var(--t-12); font-weight: 600;
  background: var(--surface-2); color: var(--muted);
  border: var(--rule); border-radius: var(--r-ctl);
}
.states .st.done { background: var(--success-soft); color: var(--success-ink); border-color: var(--success); }
.states .st.now  { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }
.states .st.blocked { background: var(--danger-soft); color: var(--danger-ink); border-color: var(--danger); }

/* --------------------------------------------------------------------------
   8. LAYERS — drawer, modal, menu. The only things that carry a shadow,
   because they are the only things that genuinely overlay.
   -------------------------------------------------------------------------- */
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(var(--drawer-w), 92vw);
  z-index: var(--z-layer); background: var(--surface);
  border-left: var(--rule); box-shadow: var(--elev-modal);
  display: flex; flex-direction: column;
  transform: translateX(100%); visibility: hidden;
  transition: transform var(--dur-2) var(--ease-out), visibility 0s linear var(--dur-2);
}
body.layer-open .drawer { transform: none; visibility: visible; transition-delay: 0s; }
body.has-pocbar .drawer { bottom: var(--pocbar-h); }
.drawer-hd { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) var(--s-4); border-bottom: var(--bw-strong) solid var(--line-strong); }
.drawer-bd { padding: var(--s-4); overflow-y: auto; flex: 1 1 auto; }
.drawer-bd > * + * { margin-top: var(--s-4); }
.drawer-ft { padding: var(--s-3) var(--s-4); border-top: var(--rule); background: var(--surface-2); display: flex; gap: var(--s-2); }
.scrim { position: fixed; inset: 0; z-index: calc(var(--z-layer) - 1); background: oklch(0.235 0.022 196 / 0.42); opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease); }
body.layer-open .scrim { opacity: 1; pointer-events: auto; }

.modal { position: fixed; inset: 0; z-index: var(--z-layer); display: grid; place-items: center; padding: var(--s-4); }
.modal-box { width: min(560px, 100%); background: var(--surface); border: var(--rule); border-radius: var(--r-card); box-shadow: var(--elev-modal); }
.menu { min-width: 200px; background: var(--surface); border: var(--rule); border-radius: var(--r-card); box-shadow: var(--elev-pop); padding: var(--s-1); }
.menu button, .menu a { display: flex; align-items: center; gap: var(--s-2); width: 100%; min-height: 32px; padding: 0 var(--s-2); border-radius: var(--r-ctl); font-size: var(--t-14); color: var(--ink-2); text-decoration: none; }
.menu button:hover, .menu a:hover { background: var(--surface-2); color: var(--ink); }
.menu .sep { height: var(--bw); background: var(--line); margin: var(--s-1) 0; }

/* Tabs live in section 12, built as one component. The scaffold's original
   `.tabs a, .tabs button` block was deleted when that landed — two
   implementations of one class is how a style silently wins the wrong way. */

/* --------------------------------------------------------------------------
   9. FEEDBACK AND EMPTY STATES — the unhappy paths are what convince a buyer.
   -------------------------------------------------------------------------- */
.state {
  display: grid; justify-items: center; text-align: center;
  padding: var(--s-8) var(--s-5); color: var(--muted);
}
.state .ico { width: 28px; height: 28px; color: var(--muted-2); margin-bottom: var(--s-3); }
.state h3 { color: var(--ink); margin-bottom: var(--s-1); }
.state p { max-width: 46ch; font-size: var(--t-14); }
.state .btn { margin-top: var(--s-4); }
.state.denied .ico { color: var(--danger); }
.state.error .ico { color: var(--danger); }
.state.offline .ico { color: var(--warning-ink); }

.note {
  display: flex; gap: var(--s-3); padding: var(--s-3);
  border: var(--rule); border-radius: var(--r-card); background: var(--surface-2);
  font-size: var(--t-14); color: var(--ink-2);
}
.note .ico { width: 18px; height: 18px; flex: none; color: var(--muted); }
.note.warn   { background: var(--warning-soft); border-color: var(--warning); color: var(--warning-ink); }
.note.warn .ico { color: var(--warning-ink); }
.note.danger { background: var(--danger-soft); border-color: var(--danger); color: var(--danger-ink); }
.note.danger .ico { color: var(--danger-ink); }
.note.ok     { background: var(--success-soft); border-color: var(--success); color: var(--success-ink); }
.note.ok .ico { color: var(--success-ink); }
.note.info   { background: var(--info-soft); border-color: var(--info); color: var(--info-ink); }
.note.info .ico { color: var(--info-ink); }

/* Skeleton — reserve the space so nothing jumps */
.skel { background: var(--surface-3); border-radius: var(--r-ctl); position: relative; overflow: hidden; }
.skel::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, oklch(1 0 0 / 0.55), transparent);
  animation: shimmer 1.4s infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
.skel-line { height: 10px; margin-bottom: var(--s-2); }
.skel-row { height: var(--h-row); margin-bottom: var(--bw); }

/* Offline / permission strip */
.strip {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-5); font-size: var(--t-13); font-weight: 600;
}
.strip.offline { background: var(--warning-soft); color: var(--warning-ink); border-bottom: var(--bw) solid var(--warning); }
.strip .ico { width: 15px; height: 15px; }

/* --------------------------------------------------------------------------
   10. SHOP-FLOOR VARIANT — gloved hands, arm's length, glare.
   Opt in with .t-lg on a container. Not a separate stylesheet.
   -------------------------------------------------------------------------- */
.t-lg { --h-ctl: 44px; --h-ctl-sm: 38px; --h-row: 48px; --pad-card: var(--s-5); }
.t-lg .btn { font-size: var(--t-16); }
.t-lg table.tbl { font-size: var(--t-16); }
.t-lg .input, .t-lg .select { font-size: var(--t-16); }

/* Persona switcher in the prototype bar. Switching persona changes the rail,
   the launchpad and every reachable workspace — the team-modular demo. */
.poc-persona {
  height: 26px; max-width: 250px; padding: 0 var(--s-2);
  background: var(--drench-2); color: var(--on-drench);
  border: var(--bw) solid var(--drench-line); border-radius: var(--r-ctl);
  font-family: var(--font-body); font-size: var(--t-12); cursor: pointer;
}
.poc-persona:hover { border-color: var(--on-drench-muted); }

/* Charts — hand-drawn inline SVG, series colours from the brand ramp only. */
.chart { display: block; width: 100%; height: auto; overflow: visible; }

/* Launchpad greeting — the page's <h1> is the screen name, so this is styled
   display type rather than a heading level. */
.lp-hi { font-family: var(--font-display); font-size: var(--t-28); font-weight: 600;
  line-height: var(--lh-snug); letter-spacing: var(--tracking-heading); color: var(--on-drench); }

/* Read-only workspace: you can see the screen, you cannot act in it. */
.strip.readonly { background: var(--info-soft); color: var(--info-ink);
  border: var(--bw) solid var(--info); border-radius: var(--r-card); margin-bottom: var(--s-4); }
/* Every control that changes something, not just the two loudest button
   styles — a secondary "Put on hold" changes an order as much as a primary
   "Approve" does. Opening a record to read it is not a change: a row's Open
   is drawn as a primary button, and must stay live. */
.wsbody.is-readonly .btn-pri:not([data-act="tx-open"]):not([data-act="md-open"]):not([data-act="md-review"]),
.wsbody.is-readonly .btn-danger,
.wsbody.is-readonly [data-create],
.wsbody.is-readonly [data-edit],
.wsbody.is-readonly [data-del],
.wsbody.is-readonly [data-act^="tx-"]:not([data-act="tx-open"]),
.wsbody.is-readonly [data-act^="md-"]:not([data-act="md-open"]):not([data-act="md-review"]) {
  opacity: .45; pointer-events: none; }
/* The one exception: an action a document RESERVES to an authority stays live
   for whoever holds that authority, whatever workspace it is read in. A
   supplier invoice is Purchase's document, but the payment is the Financial
   Controller's decision — an approval that only its own team can reach is not
   an approval. */
.wsbody.is-readonly [data-act^="tx-"][data-authority-ok],
.wsbody.is-readonly [data-authority-ok] { opacity: 1; pointer-events: auto; }
.wsbody.is-readonly input:not([type="search"]),
.wsbody.is-readonly select,
.wsbody.is-readonly textarea { pointer-events: none; background: var(--surface-2); }

/* A denied workspace renders no contextual panel, so the content takes its
   column. The explicit grid-column on .wsmain has to move too, or the grid
   creates an implicit third column and leaves a gap where the panel was. */
.app:not(:has(.panelnav)) { grid-template-columns: var(--rail-w) minmax(0, 1fr); }
.app:not(:has(.panelnav)) .wsmain { grid-column: 2; }

/* Person chooser — used on the landing page, the sign-in screen and the
   permission-denied screen, so it belongs here rather than in one page. */
.person { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-3);
  background: var(--surface); border: var(--rule); border-radius: var(--r-card);
  text-decoration: none; color: var(--ink); text-align: left;
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease); }
.person:hover { border-color: var(--primary); background: var(--primary-soft); color: var(--ink); }
.person .ico { margin-left: auto; color: var(--muted); flex: none; }
.person b { display: block; font-size: var(--t-14); }
.person span.r { display: block; font-size: var(--t-12); color: var(--muted); }

/* Overflow counter in the read-only band. */
.rail-item.rail-more { font-family: var(--font-display); font-size: var(--t-13); font-weight: 700; }

/* Permission denied — a signpost, not a dead end. */
.denied { max-width: 620px; }
.denied-hd { display: flex; gap: var(--s-4); align-items: flex-start;
  padding: var(--s-5); background: var(--surface); border: var(--rule); border-radius: var(--r-card); }
.denied-hd .ico { width: 24px; height: 24px; color: var(--danger); flex: none; margin-top: 3px; }
.denied-people { display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: var(--s-2); margin-top: var(--s-2); }

/* Forms — two columns, full-width fields opt in with .fw. */
.formgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4) var(--s-3); }
.formgrid .field.fw { grid-column: 1 / -1; }
/* A field that starts a row, so the one after it — a dimension and its unit —
   sits beside it rather than under it. */
.formgrid .field.row-start { grid-column: 1; }
@media (max-width: 620px) { .formgrid { grid-template-columns: minmax(0, 1fr); } }
.drawer.wide { width: min(620px, 96vw); }
/* A tabbed form: room for the strip and for the line rowsets inside it. */
.drawer.xwide { width: min(820px, 96vw); }
.rowacts {
  display: inline-flex; gap: 2px; white-space: nowrap;
  opacity: 0.45; transition: opacity var(--dur-1) var(--ease);
}
/* A filled button on every row was the heaviest thing on the page and it is
   never what you came to read. These recede rather than disappear: hiding them
   outright leaves a keyboard user tabbing to a control they cannot see. */
tr:hover .rowacts,
tr:focus-within .rowacts,
tr[aria-selected="true"] .rowacts { opacity: 1; }
.rowacts:focus-within { opacity: 1; }
@media (hover: none) { .rowacts { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .rowacts { transition: none; } }
.rowacts .btn-icon { color: var(--muted); }
.rowacts .btn-icon:hover { color: var(--ink); }
.rowacts [data-del]:hover { color: var(--danger-ink); background: var(--danger-soft); }
/* The primary row action is quiet too — it is an affordance, not a call to action. */
.rowacts .btn-pri {
  background: transparent; border-color: var(--line-strong); color: var(--ink-2);
}
.rowacts .btn-pri:hover { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }

/* Filter chips above a register. */
/* The chips scroll in their own track rather than wrapping the whole toolbar
   onto a second and third line. The fade on the right says there is more. */
.chips {
  display: flex; flex-wrap: nowrap; gap: var(--s-1);
  flex: 1 1 auto; min-width: 0;
  overflow-x: auto; scrollbar-width: none;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent);
          mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent);
}
.chips::-webkit-scrollbar { display: none; }
.chips button { flex: 0 0 auto; }
.chips button { display: inline-flex; align-items: center; gap: 5px; min-height: 28px;
  padding: 0 var(--s-3); border: var(--rule); border-radius: var(--r-ctl);
  background: var(--surface); color: var(--ink-2); font-size: var(--t-13); font-weight: 600; }
.chips button:hover { background: var(--surface-2); }
.chips button[aria-pressed="true"] { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.chips button .n { font-variant-numeric: tabular-nums; opacity: .75; }
/* Nothing behind it: still reachable, no longer shouting a zero. */
.chips button.is-empty { color: var(--muted); border-style: dashed; }
.chips button.is-empty[aria-pressed="true"] { color: var(--on-primary); border-style: solid; }

/* A gate inside a table cell stays on one line — the full reason is the title. */
table.tbl .gate { white-space: nowrap; }


/* An access-matrix cell that has been changed from its role default. */
.tag-edited { outline: var(--bw-strong) solid var(--accent-strong); outline-offset: 1px; }


/* A subtotal line inside a reconciliation: ruled above, and it carries weight. */
.dl dt.dl-total, .dl dd.dl-total {
  border-top: var(--bw-strong) solid var(--line-strong, var(--line));
  padding-top: var(--s-2); margin-top: var(--s-1);
  color: var(--ink); font-weight: 600;
}

/* --- Tabs -----------------------------------------------------------------
   One master at a time. The active tab is FILLED, not underlined: on a screen
   this dense a 2px rule is not enough to answer "where am I". The strip sits on
   an inset track so the group reads as one control, and the count travels with
   the label so you can see where the work is before you click. Square corners,
   hairline border, no shadow — the same register as everything else here. */

.tabs {
  display: inline-flex; align-items: stretch; gap: 2px;
  max-width: 100%;
  padding: 3px;
  background: var(--surface-2);
  border: var(--rule);
  border-radius: var(--r-lg);
  overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabwrap { margin-bottom: var(--s-4); }

.tab {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 7px var(--s-4);
  border: var(--bw) solid transparent;
  border-radius: var(--r-card);
  background: transparent;
  font-family: var(--font-display);
  font-size: var(--t-15);
  font-weight: 600;
  letter-spacing: 0.005em;
  text-transform: none;                    /* sentence case reads cleaner here */
  color: var(--ink-2);
  white-space: nowrap;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease);
}
.tab:hover:not([aria-selected="true"]) {
  background: var(--surface);
  border-color: var(--line);
  color: var(--ink);
}
.tab:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 1px; }

.tab[aria-selected="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

/* The count: quiet on an inactive tab, legible on the filled one. */
.tab-n {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 21px; height: 19px; padding: 0 6px;
  border-radius: var(--r-ctl);
  background: var(--surface);
  border: var(--rule);
  font-family: var(--font-body); font-size: var(--t-12);
  font-weight: 500; letter-spacing: 0; text-transform: none;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.tab[aria-selected="true"] .tab-n {
  background: oklch(1 0 0 / 0.18);
  border-color: oklch(1 0 0 / 0.28);
  color: var(--on-primary);
}
.tab .ico { opacity: 0.75; }
.tab[aria-selected="true"] .ico { opacity: 1; }

/* Vertical: ten reference tables read better down the side than in a strip
   that scrolls. Same filled active state, so "where am I" is answered the
   same way in both orientations. */
.tabs-v { display: grid; grid-template-columns: 224px minmax(0, 1fr); gap: var(--s-4); align-items: start; }
/* Without this a wide reference table pushes past its grid track instead of
   scrolling inside it, and the page gains a horizontal scrollbar. */
.tabs-v > .tabpanel { min-width: 0; }
.tabs-v > .tabpanel > * { max-width: 100%; }
.tabs-v .tabs.tabs-side {
  display: flex; flex-direction: column; gap: 2px;
  width: 100%; padding: 3px;
  border-radius: var(--r-lg);
  overflow: visible;
}
.tabs-side .tab {
  width: 100%; justify-content: flex-start;
  padding: 7px var(--s-3);
  text-align: left;
  /* A report name as long as "Order Tracking / Milestone Report" wraps to a
     second line rather than pushing its count out of the strip. */
  white-space: normal; line-height: 1.25;
}
.tabs-side .tab > span:not(.tab-n) { flex: 1 1 auto; min-width: 0; }
.tabs-side .tab-n { margin-left: auto; flex: 0 0 auto; }

@media (max-width: 860px) {
  .tabs-v { grid-template-columns: minmax(0, 1fr); }
  .tabs-v .tabs.tabs-side {
    flex-direction: row; overflow-x: auto; margin-bottom: var(--s-4);
  }
  .tabs-side .tab { width: auto; }
  .tabs-side .tab-n { margin-left: 0; }
}

@media (max-width: 700px) {
  .tab { padding: 7px var(--s-3); font-size: var(--t-14); }
  .tab .ico { display: none; }
}

/* Inside a tab the tab already names the surface, so the panel header carries
   only its actions. */
.panel-hd.no-title { justify-content: flex-end; }

/* A toggle in a form reads its own state in words. "On" as a colour alone is
   not a value a user can check before submitting a master. */
.toggle-row { display: inline-flex; align-items: center; gap: var(--s-3); min-height: var(--h-ctl); }
.toggle-state {
  font-family: var(--font-display); font-size: var(--t-13); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: var(--case-head);
  color: var(--muted); min-width: 2.5em;
}
.toggle input:checked ~ .track ~ .toggle-state,
.toggle-row:has(input:checked) .toggle-state { color: var(--primary-strong); }

/* Multi-select: the document asks for several units on a department, several
   roles on a user. A checkbox group states what is chosen without a dropdown
   that hides it. */
.multi-sm { gap: var(--s-1); }
.multi-sm .multi-opt { padding: 2px var(--s-2); font-size: var(--t-12); }
.multi {
  display: flex; flex-wrap: wrap; gap: var(--s-1);
  padding: var(--s-2); min-height: var(--h-ctl);
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-ctl);
  background: var(--surface);
}
.multi-opt {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  padding: 3px var(--s-2); border: var(--rule); border-radius: var(--r-ctl);
  background: var(--surface-2); font-size: var(--t-13); color: var(--ink-2);
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.multi-opt input { width: 14px; height: 14px; accent-color: var(--primary); cursor: pointer; }
.multi-opt:hover { border-color: var(--muted-2); }
.multi-opt:has(input:checked) {
  background: var(--primary-soft); border-color: var(--primary); color: var(--primary-strong); font-weight: 600;
}
.multi-opt:has(input:disabled) { cursor: not-allowed; opacity: 0.6; }

/* The dropdown that holds several choices. Closed it is the height of every
   other control and reads as what is chosen; open it is a short scrolling list
   of the same checkboxes the open group uses. */
.msdd { position: relative; display: block; min-width: 0; }
.msdd-sum {
  display: flex; align-items: center; gap: var(--s-2); list-style: none; cursor: pointer;
  min-height: var(--h-ctl); padding: 0 var(--s-6) 0 var(--s-3);
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-ctl);
  background-color: var(--surface); color: var(--ink); font-size: var(--t-14);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 14px) 52%, calc(100% - 9px) 52%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.msdd-sum::-webkit-details-marker { display: none; }
.msdd-sum:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.msdd[open] > .msdd-sum { border-color: var(--primary); }
.msdd-val { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msdd-val.is-empty { color: var(--muted); }
.msdd-n {
  flex: none; min-width: 18px; padding: 0 5px; border-radius: 9px; text-align: center;
  background: var(--primary-soft); color: var(--primary-strong);
  font-size: var(--t-12); font-weight: 600; line-height: 18px;
}
.msdd-list {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 2px);
  max-height: 232px; overflow-y: auto; padding: var(--s-1);
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-ctl);
  background: var(--surface); box-shadow: 0 8px 24px rgba(16, 24, 32, 0.14);
}
.msdd-opt {
  display: flex; align-items: center; gap: var(--s-2); cursor: pointer;
  padding: 6px var(--s-2); border-radius: var(--r-ctl); font-size: var(--t-13); color: var(--ink-2);
}
.msdd-opt input { width: 14px; height: 14px; flex: none; accent-color: var(--primary); cursor: pointer; }
.msdd-opt:hover { background: var(--surface-2); }
.msdd-opt:has(input:checked) { color: var(--primary-strong); font-weight: 600; }
.msdd-none { display: block; padding: var(--s-2); }
.msdd.is-off > .msdd-sum { cursor: not-allowed; background-color: var(--surface-2); color: var(--ink-3); }
.msdd-sm > .msdd-sum { min-height: var(--h-ctl-sm); height: var(--h-ctl-sm); font-size: var(--t-13); padding-left: var(--s-2); }

/* A field that does not apply to this transaction: present, legible, inert.
   It wakes when the field it depends on changes. */
.field.is-off { opacity: 0.55; }
.field.is-off .label::after { content: ' — not applicable'; font-weight: 400; color: var(--ink-3); }

/* --- Form tabs: a 27-field master is not one scrolling column ------------- */
/* The strip WRAPS here rather than scrolling. Inside a drawer the scrollbar is
   hidden, so a strip that overflows silently hides its last tabs — and a tab
   nobody can reach is a field that does not exist. */
.formtabs .tabs { margin-bottom: var(--s-4); flex-wrap: wrap; row-gap: 2px; overflow-x: visible; }
.formtabs .ftpane { margin: 0; }

/* --- Child collections: addresses on a customer, contacts, bank units -----
   Each row is a small bounded record, not a table row, because it is edited
   rather than read. */
.rowset { display: block; }
.rowset-row {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-3); margin-bottom: var(--s-2);
  border: var(--rule); border-radius: var(--r-card);
  background: var(--surface-2);
}
.rowset-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s-2); flex: 1 1 auto; min-width: 0;
}
.rf { display: block; min-width: 0; }
.rf .label { display: block; margin-bottom: 3px; }
.rf-wide { grid-column: 1 / -1; }
.rf-s2 { grid-column: span 2; }
.rf-s3 { grid-column: span 3; }
@media (max-width: 720px) { .rf-s2, .rf-s3 { grid-column: 1 / -1; } }
.rf-flag { display: flex; flex-direction: column; gap: 3px; }
.rowset-del { flex: none; margin-top: 18px; color: var(--muted); }
.rowset-del:hover { color: var(--danger-ink); background: var(--danger-soft); }
.rowset-empty { margin: 0 0 var(--s-2); }

/* Supporting documents on a master — a vendor's KYC, a customer's GST
   certificate. Same bounded-row idiom as the other child collections. */
.docset-row {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-3); margin-bottom: var(--s-2);
  border: var(--rule); border-radius: var(--r-card); background: var(--surface-2);
}
.docset-ic { flex: none; margin-top: 20px; color: var(--muted); }
.docset-fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s-2); flex: 1 1 auto; min-width: 0;
}
.docset-fields .rf-wide { grid-column: span 2; }
.docset-row.is-archived { opacity: .7; }

/* --- W1 dashboard: a KPI card is a link, and it says so ------------------- */
.kpigrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: var(--s-3);
}
.kpi {
  position: relative; display: block; text-decoration: none;
  padding: var(--s-4); padding-right: var(--s-5);
  background: var(--surface); border: var(--rule); border-radius: var(--r-card);
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.kpi:hover { border-color: var(--primary); background: var(--primary-soft); }
.kpi:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 2px; }
.kpi-k {
  display: block; font-family: var(--font-display); font-size: var(--t-12); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: var(--case-head); color: var(--muted);
}
.kpi-v {
  display: block; margin: var(--s-2) 0 2px;
  font-family: var(--font-display); font-size: var(--t-28); font-weight: 600;
  line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums;
}
.kpi-v.bad { color: var(--danger-ink); }
.kpi-v.good { color: var(--success-ink); }
.kpi-d { display: block; font-size: var(--t-13); color: var(--muted); }
.kpi-go {
  position: absolute; top: var(--s-4); right: var(--s-3);
  color: var(--muted); opacity: 0; transition: opacity var(--dur-1) var(--ease);
}
.kpi:hover .kpi-go, .kpi:focus-visible .kpi-go { opacity: 1; color: var(--primary-strong); }

/* The setup sequence reads as a numbered order, because it is one. */
.seqlist { margin: 0; padding-left: var(--s-5); }
.seqlist li { margin-bottom: var(--s-2); font-size: var(--t-14); }
.seqlist li span.muted { display: block; }

/* §9.3 — twelve milestones inside a register cell. Same rail, smaller. */
.states-sm { flex-wrap: wrap; gap: 2px; }
.states-sm .st { font-size: 10px; padding: 1px 6px; }

/* --- W3 §11 schedule board: machine lanes by day ------------------------- */
.sb th, .sb td { vertical-align: top; }
.sb .sb-lane { min-width: 170px; }
.sb .sb-cell { min-width: 132px; padding: var(--s-1) var(--s-2); }
.sb .sb-cell.is-closed { background: var(--surface-2); }
.sb .sb-cell.is-down { background: var(--danger-soft); }
.sb .sb-grp td {
  background: var(--surface-2); font-family: var(--font-display); font-size: var(--t-12); font-weight: 600;
  letter-spacing: var(--tracking-label); text-transform: var(--case-head); color: var(--muted);
}
.sb-block {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px; width: 100%;
  margin: 0 0 4px; padding: 4px 6px; text-align: left; cursor: pointer;
  font: inherit; font-size: var(--t-12); color: var(--ink);
  border: 1px solid var(--line); border-left-width: 3px; border-radius: var(--r-ctl);
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.sb-block:hover { filter: brightness(0.97); }
.sb-block:focus-visible { outline: 2px solid var(--accent-strong); outline-offset: 1px; }
.sb-h { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.sb-free { display: block; font-size: var(--t-11); color: var(--muted); }
.sb-key { display: inline-block; width: 12px; height: 12px; border: 1px solid var(--line); border-left-width: 3px; border-radius: 3px; }
.sb-plan { background: var(--info-soft); border-left-color: var(--info); }
.sb-firm { background: var(--primary-soft); border-left-color: var(--primary); }
.sb-run  { background: var(--success-soft); border-left-color: var(--success); }
.sb-held { background: var(--warning-soft); border-left-color: var(--warning); }
.sb-down { background: var(--danger-soft); border-left-color: var(--danger); }
