/* ══════════════════════════════════════════════════════════════════════════════
   Smart Order — project design language.

   Every token below is a CSS custom property on :root. NOTHING in this file names
   a tenant, and no component ever hardcodes a colour. The values here are the
   Daitalens default palette; the brand resolver in index.html (CP-1006) overwrites
   them inline on <html> from the matched tenants.json row, which wins over this
   stylesheet. If the resolver never runs (fetch failed, file missing) the app still
   renders correctly, in Daitalens blue — that is the point of keeping a full set here.

   Dark mode is a SECOND AXIS, not a second brand: [data-theme="dark"] carries the
   dark values for the same tokens. Tenant x theme = four combinations.

   Token names and hex values are lifted verbatim from the design baseline
   AI_Docs/mocks/SmartOrderFE_Ro.html; the type scale is stepped up, because the mock
   draws inside a ~720px device frame and this is a real window.
   ══════════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── brand tokens: the resolver overwrites every one of these ── */
  --so-primary: #1071B9;
  --so-primary-ink: #0C447C;
  --so-primary-rgb: 16, 113, 185;
  --so-appbar: #03173D;
  --so-appbar-ink: #FFFFFF;
  --so-brandfg: #FFFFFF;
  --so-accent: #4FCAFF;
  --so-side: #F4F6F9;
  --so-line: #E2E8F0;
  --so-line2: #EDF2F7;
  --so-ink: #1A202C;
  --so-body: #4A5568;
  --so-lab: #718096;
  /* The micro-label ink for text sitting on a SELECTED row.
     A selected row is tinted with the tenant's primary, which lifts the surface under the label
     and takes the pairing below the floor: --so-lab measured 4.09:1 on the light selected row
     and 3.91:1 on the dark one. Rather than weakening the tint — the selection affordance is
     doing a job — the label gets one step more ink, rebound onto --so-lab inside `tr.sel` so
     every lab-coloured descendant picks it up without naming them one by one. */
  --so-lab-tint: #5A6778;
  --so-field: #CBD5E0;
  --so-card: #FFFFFF;
  --so-bg: #FFFFFF;
  --so-divider: 3px;
  --so-loginbg: linear-gradient(158deg, #03173D 0%, #0B3A6B 100%);

  /* ── semantic tokens: fixed, never tenant-specific ── */
  --so-ok-bg: #E4F3E9;
  --so-ok-ink: #2C6B45;
  --so-amber-bg: #FBE9C4;
  /* 4.48:1 on its own tint is a near miss, which is the worst kind: it looks deliberate and it
     is still below the floor. Amber carries every advisory chip and count on the app, so this
     is the seventh token fix of the design pass. 5.25:1 on the tint, 6.28:1 on white. */
  --so-amber-ink: #7D5A12;
  --so-red-bg: #FBDCDC;
  --so-red-ink: #A03A3A;
  --so-blue-bg: #E2ECF6;
  --so-blue-ink: #0C447C;

  /* The row action on a list of flagged lines. Neutral on purpose: four of them stacked in the
     tenant's brand colour would out-shout the screen's one real next step. Light mode takes the
     mock's dark button; dark mode a raised surface, because a white button there is louder still. */
  --so-rowbtn: #2E3338;
  --so-rowbtn-ink: #FFFFFF;

  /* The ONE solid call-to-action on a screen, split out from --so-primary because the brand
     colour and a button's background have different jobs. CP-1042: white on --so-primary is
     3.1:1 in light and 2.3:1 in dark on a mid-tone brand colour — below the 4.5:1 body floor,
     and 13.5px/800 is not "large text" under WCAG. The CTA therefore carries its own ink pair,
     which the resolver derives from the tenant's primary (a darkened primary in light, the
     primary itself with warm-dark ink in dark). The ACTIVE NAV PILL deliberately keeps
     white-on-brand: that is the chrome the customer signed off in Alex's mockup, and changing
     it is Alex's call, not this ticket's. */
  --so-cta: #0B4F82;
  --so-cta-hov: #08395E;
  --so-cta-ink: #FFFFFF;

  /* ── derived from --so-primary by the resolver; these are the fallbacks ── */
  --so-hov: rgba(0, 0, 0, .035);
  --so-sel: rgba(16, 113, 185, .10);
  --so-tint: rgba(16, 113, 185, .10);
  --so-ring: rgba(16, 113, 185, .18);

  /* ── shape and type ── */
  --so-shadow: 0 4px 16px rgba(29, 41, 51, .10);
  --so-shadow-lg: 0 14px 40px rgba(0, 0, 0, .22);
  --so-radius: 10px;
  --so-radius-sm: 8px;
  --so-ph-a: rgba(0, 0, 0, .045);
  --so-ph-b: rgba(0, 0, 0, .085);
  --so-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
  --so-sans: 'Inter', 'Inter var', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --so-appbar-h: 56px;
  --so-side-w: 216px;

  /* written by the resolver from the tenant; defaults here keep the app legible without it */
  --so-dropdown: #0B2A55;
  --so-nav-active: #0E4C86;
}

/* First visit only: the resolver has no cached tenant yet, so the shell is held for a moment
   rather than painted in a colour it is about to change. A returning visitor never sees this —
   their brand is on :root before a byte is fetched. Removed by the resolver, and by a timeout
   if the fetch never answers, so this can never strand the page. */
html[data-brand-pending] body { visibility: hidden; }

:root[data-theme="dark"] {
  --so-primary: #4FCAFF;
  --so-primary-ink: #9BD8F7;
  --so-primary-rgb: 79, 202, 255;
  --so-appbar: #0B1220;
  --so-appbar-ink: #FFFFFF;
  --so-brandfg: #FFFFFF;
  --so-accent: #4FCAFF;
  --so-side: #141824;
  /* CP-1042: lifted from .10 so a card keeps a visible edge on the dark canvas — at .10 the
     tiles flattened into the background and the shell lost its structure. */
  --so-line: rgba(255, 255, 255, .14);
  --so-line2: rgba(255, 255, 255, .07);
  --so-ink: #E4E4E7;
  /* CP-1042: the two ink tokens are lifted here as the no-resolver fallback, and DERIVED from
     the tenant's own app bar by the resolver so a warm tenant gets warm micro-labels rather
     than a cold grey on a warm card. --so-lab at #7C8698 measured 4.58:1 on the default dark
     card, and as little as 2.84:1 once a warm tenant's resolver repainted it — every uppercase
     tile label, table header and hint on the app was below the floor. */
  --so-body: #B0B7C3;
  --so-lab: #98A2B4;
  --so-lab-tint: #ADB6C5;
  --so-field: rgba(255, 255, 255, .16);
  --so-card: #1A1D27;
  --so-bg: #12151D;
  --so-loginbg: linear-gradient(158deg, #060B16 0%, #0E2744 100%);

  --so-ok-bg: rgba(72, 187, 120, .16);
  --so-ok-ink: #7ED9A3;
  --so-amber-bg: rgba(214, 158, 46, .18);
  --so-amber-ink: #EFC978;
  --so-red-bg: rgba(252, 129, 129, .16);
  --so-red-ink: #FCA5A5;
  --so-blue-bg: rgba(79, 202, 255, .14);
  --so-blue-ink: #8FD3F4;

  --so-rowbtn: rgba(255, 255, 255, .11);
  --so-rowbtn-ink: #E4E4E7;

  /* In dark the CTA keeps the brand colour and takes warm-DARK ink, because a darkened accent
     on a dark canvas disappears. The resolver recomputes both from the tenant's dark primary. */
  --so-cta: #4FCAFF;
  --so-cta-hov: #7BD8FF;
  --so-cta-ink: #0D2029;

  --so-hov: rgba(255, 255, 255, .05);
  --so-sel: rgba(79, 202, 255, .14);
  --so-tint: rgba(79, 202, 255, .14);
  --so-ring: rgba(79, 202, 255, .28);

  --so-shadow: 0 12px 40px rgba(0, 0, 0, .55);
  --so-shadow-lg: 0 16px 48px rgba(0, 0, 0, .62);
  --so-ph-a: rgba(255, 255, 255, .05);
  --so-ph-b: rgba(255, 255, 255, .10);
}

/* ══ base ══════════════════════════════════════════════════════════════════ */

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

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--so-sans);
  font-size: 14px;
  line-height: 1.5;
  color: var(--so-ink);
  background: var(--so-bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p, ul, ol { margin: 0; }
ul { padding: 0; list-style: none; }

a { color: var(--so-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

button { font-family: inherit; cursor: pointer; }
button[disabled] { cursor: not-allowed; }

:focus-visible {
  outline: 2px solid var(--so-primary);
  outline-offset: 2px;
  border-radius: 4px;
}

/*
  <FocusOnNavigate Selector="h1" /> moves focus to the page heading on every route change, so a
  screen reader announces the new page instead of leaving the reader where the old one ended. Blazor
  makes the heading focusable by giving it tabindex="-1", and Chromium's :focus-visible heuristic
  then paints a ring around the H1 on every single navigation — a keyboard affordance on something
  no keyboard can reach.

  Suppress the ring THERE and nowhere else. tabindex="-1" means the heading is unreachable by Tab, so
  the only thing that can focus it is that component: there is no case where a user put focus here
  and needs to see where it went. Every real control keeps the rule above untouched. The focus
  management itself stays — this is a paint fix, not an accessibility rollback.
*/
h1[tabindex="-1"]:focus,
h1[tabindex="-1"]:focus-visible {
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ══ app shell ═════════════════════════════════════════════════════════════ */

.so-shell { display: flex; flex-direction: column; min-height: 100vh; background: var(--so-bg); }

.so-appbar {
  background: var(--so-appbar);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 20px;
  height: var(--so-appbar-h);
  border-bottom: var(--so-divider) solid var(--so-primary);
  flex: none;
  position: sticky;
  top: 0;
  z-index: 20;
}

.so-brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
.so-brand .mark { height: 28px; width: auto; max-width: 160px; display: block; }
.so-brand .word {
  font-size: 16px; font-weight: 800; letter-spacing: -.01em;
  color: var(--so-brandfg); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.so-brand .dot {
  width: 22px; height: 22px; border-radius: 6px; flex: none;
  background: var(--so-brandfg); display: block;
}

/* ── the tenant's wordmark, per theme (CP-1034) ────────────────────────────────────────────────
   A tenant may supply a second wordmark drawn for a dark surface, because artwork is not
   theme-neutral: ink that reads on a cream bar turns to mud on a dark one. Ro's rule is REAL
   ASSETS, NOT FILTERS — an invert() or brightness() over a logo looks like a filtered logo.

   BOTH are in the markup and the CHOICE IS MADE HERE, off the data-theme attribute the pre-boot
   resolver owns. Deciding it in C# instead would read a brand record captured once at boot, so
   toggling the theme would leave yesterday's logo on screen until the next reload.

   A tenant with no dark variant emits one <img> carrying neither class, and it shows in both.

   The `html[data-theme]` prefix is not decoration, it is arithmetic: `.so-loginbox .logo img`
   below is (0,2,1) and sets `display: block` on this very element, and it comes LATER in the file.
   A bare `[data-theme] img.so-mark-dark` ties at (0,2,1), loses on order, and both wordmarks paint
   side by side on the sign-in card — which is exactly what happened the first time. */
html[data-theme] img.so-mark-dark { display: none; }
html[data-theme="dark"] img.so-mark-light { display: none; }
html[data-theme="dark"] img.so-mark-dark { display: block; }

/* The wordmark failed to load (a bad path, a missing file, a blocked request). The logoText
   fallback is already in the markup, hidden; smartOrderBrand.markFailed swaps the two. A broken
   asset URL costs the tenant its logo, never the whole app bar.

   !important because the slot rules give `.logo .dot` an explicit `display: block`, and the
   attribute has to win over it wherever this component is placed. */
.mark[hidden], .so-mark-fallback[hidden] { display: none !important; }
/* The product name beside the tenant's mark. It takes its ink from the APP BAR, not the page —
   a cream bar and a navy bar need opposite inks and neither can use the page's grey. */
.so-brand.sub {
  font-size: 13px; font-weight: 700; white-space: nowrap;
  color: color-mix(in srgb, var(--so-appbar-ink) 72%, transparent);
  padding-left: 12px; margin-left: 2px;
  border-left: 1px solid color-mix(in srgb, var(--so-appbar-ink) 28%, transparent);
}

.so-appbar-right { display: flex; align-items: center; gap: 10px; margin-left: auto; }

/* the picker and the sign-out button sit ON the app bar, so they take their ink
   from --so-appbar-ink, not the page ink — a cream bar and a navy bar both work. */
.so-sel {
  border: 1px solid color-mix(in srgb, var(--so-appbar-ink) 26%, transparent);
  background: color-mix(in srgb, var(--so-appbar-ink) 8%, transparent);
  color: var(--so-appbar-ink);
  border-radius: var(--so-radius-sm);
  padding: 6px 12px;
  font-size: 13px; font-weight: 700; font-family: inherit;
  display: inline-flex; align-items: center; gap: 8px;
  max-width: 260px;
}
.so-sel:hover { background: color-mix(in srgb, var(--so-appbar-ink) 15%, transparent); }
.so-sel .cv { font-size: 10px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; opacity: .62; flex: none; }
.so-sel .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The native control has to be stripped back, or the browser paints its own white box on the
   app bar — which is unreadable on a dark bar and overlaps whatever sits next to it. The chevron
   is drawn back on, because a picker with no affordance is a label people do not click. */
.so-sel select {
  appearance: none; -webkit-appearance: none;
  background: transparent; border: none; outline: none;
  font: inherit; color: inherit;
  padding: 0 18px 0 0; margin: 0; max-width: 170px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 6px top 52%, right 1px top 52%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.so-sel select:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
/* The dropdown itself is drawn by the OS and cannot inherit the bar's ink, so it is given the
   page's own surface — the one place a menu is guaranteed legible in both themes. */
.so-sel option { color: var(--so-ink); background: var(--so-card); }

.so-logout {
  border: 1px solid color-mix(in srgb, var(--so-appbar-ink) 26%, transparent);
  background: transparent;
  color: color-mix(in srgb, var(--so-appbar-ink) 82%, transparent);
  border-radius: var(--so-radius-sm);
  padding: 6px 13px; font-size: 13px; font-weight: 700;
}
.so-logout:hover { color: var(--so-appbar-ink); background: color-mix(in srgb, var(--so-appbar-ink) 10%, transparent); }

.so-who { font-size: 12.5px; color: color-mix(in srgb, var(--so-appbar-ink) 78%, transparent); white-space: nowrap; }

.so-themebtn {
  border: 1px solid color-mix(in srgb, var(--so-appbar-ink) 26%, transparent);
  background: transparent; color: var(--so-appbar-ink);
  border-radius: var(--so-radius-sm); width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 14px;
}

.so-main { display: flex; flex: 1; min-height: 0; }

.so-side {
  width: var(--so-side-w); flex: none; background: var(--so-side);
  border-right: 1px solid var(--so-line); padding: 14px 12px;
  display: flex; flex-direction: column; gap: 4px;
}

.so-nav {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: var(--so-radius-sm); font-size: 13.5px; font-weight: 700;
  color: var(--so-lab); text-decoration: none;
}
.so-nav:hover { background: var(--so-hov); color: var(--so-ink); text-decoration: none; }
.so-nav .k {
  width: 22px; height: 22px; flex: none; border-radius: 6px;
  background: var(--so-primary); color: #fff; font-size: 11px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
.so-nav.active { background: var(--so-primary); color: #fff; }
.so-nav.active .k { background: #fff; color: var(--so-primary); }

.so-page {
  flex: 1; min-width: 0; padding: 24px 28px;
  display: flex; flex-direction: column; gap: 16px;
}

/* ══ page furniture ════════════════════════════════════════════════════════ */

.so-h1row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.so-h1 { font-size: 24px; font-weight: 800; color: var(--so-ink); letter-spacing: -.015em; }
.so-h2 {
  font-size: 14px; font-weight: 800; color: var(--so-primary);
  padding-bottom: 7px; border-bottom: 3px solid var(--so-primary); display: inline-block;
}
.so-lede { font-size: 14px; color: var(--so-body); max-width: 68ch; line-height: 1.6; }

.so-pill {
  background: var(--so-amber-bg); color: var(--so-amber-ink);
  border-radius: 999px; padding: 4px 12px; font-size: 12px; font-weight: 800;
}
.so-pill.ok { background: var(--so-ok-bg); color: var(--so-ok-ink); }
.so-pill.bad { background: var(--so-red-bg); color: var(--so-red-ink); }
.so-pill.mute { background: var(--so-line2); color: var(--so-lab-tint); }
/* Amber is the base, but a run in flight says so explicitly rather than by omission. */
.so-pill.warn { background: var(--so-amber-bg); color: var(--so-amber-ink); }

.so-btn {
  border: none; border-radius: var(--so-radius-sm); padding: 9px 16px;
  font-size: 13.5px; font-weight: 800; font-family: inherit;
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
}
/* CP-1042: the solid CTA moved off --so-primary onto the CTA pair. Same button everywhere, and
   the one place the brand colour was failing the 4.5:1 floor now clears it in both themes. */
.so-btn.p { background: var(--so-cta); color: var(--so-cta-ink); }
.so-btn.p:hover { background: var(--so-cta-hov); }
.so-btn.o { border: 1px solid var(--so-field); color: var(--so-primary-ink); background: transparent; }
.so-btn.o:hover { background: var(--so-tint); }
.so-btn.g { color: var(--so-lab); background: transparent; }
.so-btn.g:hover { color: var(--so-ink); background: var(--so-hov); }
/* ── disabled is NEUTRAL GREY, never a pale tint of the brand (CP-1045, system rule 9) ──
   `opacity:.45` over the brand fill gave white text on a washed-out brand colour at roughly
   1.7:1. On the sign-in card that is the largest element on the screen, and it reads as a live
   button that failed to paint rather than as "not yet". Grey says "not yet"; the button LIGHTING
   UP is the validation message, and it can only light up if it was dark to begin with.

   Ink is --so-body rather than --so-lab on purpose: it clears 4.5:1 on the grey in both themes
   today, without waiting on the dark-mode label token being warmed elsewhere in the epic. */
.so-btn[disabled] {
  background: var(--so-line2);
  color: var(--so-body);
  border-color: transparent;
  box-shadow: none;
}
/* Hover must not undo it — .so-btn.p:hover is (0,2,0) and would otherwise repaint the brand fill. */
.so-btn[disabled]:hover { background: var(--so-line2); color: var(--so-body); text-decoration: none; }
.so-btn.block { width: 100%; justify-content: center; padding: 11px 16px; font-size: 14px; }

.so-card { border: 1px solid var(--so-line); background: var(--so-card); border-radius: var(--so-radius); padding: 16px 18px; }

.so-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.so-tile { border: 1px solid var(--so-line); background: var(--so-card); border-radius: var(--so-radius); padding: 14px 16px; }
.so-tile .n { font-size: 28px; font-weight: 800; color: var(--so-primary); line-height: 1.05; font-variant-numeric: tabular-nums; }
.so-tile .t { font-size: 11px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--so-lab); margin-top: 6px; }
.so-tile .s { font-size: 12.5px; color: var(--so-body); margin-top: 4px; }

.so-banner {
  display: flex; align-items: flex-start; gap: 11px;
  background: var(--so-ok-bg); color: var(--so-ok-ink);
  border-radius: var(--so-radius); padding: 12px 15px;
  font-size: 13.5px; font-weight: 600; line-height: 1.55;
}
.so-banner.warn { background: var(--so-amber-bg); color: var(--so-amber-ink); }
.so-banner.bad { background: var(--so-red-bg); color: var(--so-red-ink); }
.so-banner.info { background: var(--so-blue-bg); color: var(--so-blue-ink); }
.so-banner .ti { font-size: 16px; flex: none; margin-top: 1px; }

/* the single app-level strip: its dismiss sits hard right and inherits the banner's ink */
.so-appmsg { align-items: center; }
.so-appmsg .so-btn { margin-left: auto; color: inherit; opacity: .78; }
.so-appmsg .so-btn:hover { opacity: 1; background: rgba(0, 0, 0, .06); }

/* the empty state a placeholder route shows: a name, a sentence, never a spinner
   that never resolves and never the word TODO. */
.so-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; color: var(--so-lab); text-align: center; font-size: 14px;
  padding: 56px 16px; border: 1px dashed var(--so-field); border-radius: var(--so-radius);
  background: var(--so-side);
}
.so-empty .ti { font-size: 28px; color: var(--so-primary); }
.so-empty .big { font-size: 16px; font-weight: 800; color: var(--so-ink); }
.so-empty .s { max-width: 46ch; line-height: 1.6; }

.so-skel {
  background: linear-gradient(90deg, var(--so-ph-a), var(--so-ph-b), var(--so-ph-a));
  background-size: 200% 100%; border-radius: 6px; height: 14px;
  animation: so-shimmer 1.4s linear infinite;
}
@keyframes so-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* ══ forms ═════════════════════════════════════════════════════════════════ */

.so-lab { font-size: 11px; font-weight: 800; letter-spacing: .055em; text-transform: uppercase; color: var(--so-lab); margin-bottom: 6px; display: block; }
.so-inp {
  width: 100%; border: 1px solid var(--so-field); border-radius: var(--so-radius-sm);
  padding: 10px 13px; font-size: 14.5px; font-family: inherit;
  color: var(--so-ink); background: var(--so-bg);
}
.so-inp:focus { outline: none; border-color: var(--so-primary); box-shadow: 0 0 0 3px var(--so-ring); }
.so-inp.err { border-color: var(--so-red-ink); background: var(--so-red-bg); }
.so-inp.code { font-family: var(--so-mono); font-size: 22px; letter-spacing: .38em; text-align: center; font-weight: 700; }
.so-hint { font-size: 12px; color: var(--so-lab); margin-top: 6px; line-height: 1.45; }
.so-hint.err { color: var(--so-red-ink); font-weight: 700; }
.so-field + .so-field { margin-top: 14px; }

/* ══ sign in ═══════════════════════════════════════════════════════════════ */

.so-login {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: var(--so-loginbg); padding: 24px;
}
.so-loginbox {
  width: 100%; max-width: 392px; background: var(--so-card);
  border: 1px solid var(--so-line); border-radius: 14px;
  padding: 28px 28px 24px; display: flex; flex-direction: column; gap: 14px;
  box-shadow: var(--so-shadow-lg);
  /* CP-1045: ONE alignment per card. The wordmark, the labels, the inputs, the headline and the
     support line all start on the same left edge — the footer used to be the only centred thing
     in a card of twelve elements, which is two grammars in one box. */
  text-align: left;
}
.so-loginbox .logo { display: flex; align-items: center; gap: 10px; margin-bottom: 2px; }
.so-loginbox .logo img { max-width: 240px; max-height: 48px; width: auto; height: auto; display: block; }
.so-loginbox .logo .word { font-size: 21px; font-weight: 800; letter-spacing: -.02em; color: var(--so-primary); }
.so-loginbox .logo .dot { width: 26px; height: 26px; border-radius: 7px; background: var(--so-primary); flex: none; display: block; }
/* Title step of the scale: 20/800. The eyebrow above it carries the flow, so the headline no
   longer has to also say where you are. */
.so-loginbox .t { font-size: 20px; font-weight: 800; color: var(--so-ink); letter-spacing: -.015em; }
.so-loginbox .s { font-size: 13.5px; color: var(--so-body); line-height: 1.55; margin-top: 6px; }
.so-loginbox .foot { font-size: 12.5px; color: var(--so-lab); line-height: 1.5; }
/* Orange means "act", and the least important line on the screen is not an action. The support
   link keeps its underline so it is still obviously a link without spending the brand colour. */
.so-loginbox .foot a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.so-loginbox .foot a:hover { color: var(--so-ink); }

/*
  CP-1045 — the flow eyebrow. Micro-caps is one of exactly three places the scale allows them
  (page eyebrow, stat label, table header), and this is the page eyebrow.

  The group below it is the heading, not a stack of siblings, so the eyebrow's bottom margin is
  the 8px inside-a-group step rather than the card's 14px between-groups gap.
*/
.so-loginbox .so-step {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--so-lab); margin-bottom: 8px; line-height: 1.4;
}
.so-loginbox .so-step + .t { margin-top: 0; }

/*
  A username is an IDENTIFIER, not a label, so the micro-caps treatment stops at it. Upper-casing
  what a user typed shouts it back at them and, on an email address, makes it harder to read than
  what they just keyed in — the whole reason the name is here is so they can check it at a glance.
  Wrapping is allowed: a long address on a 392px card is honest, a clipped one is a trap.
*/
.so-step .who {
  text-transform: none; letter-spacing: 0; font-size: 12px; font-weight: 700;
  color: var(--so-body); overflow-wrap: anywhere;
}

.so-product { font-size: 13px; font-weight: 700; color: var(--so-lab); letter-spacing: .01em; }

/* ══ a whole-page state — no access (CP-1045) ══════════════════════════════
   Scoped to `.so-state` / `.so-statecard` and used by NoAccess.razor only. Nothing here touches a
   :root token or a shared component rule: the dark-mode token corrections belong to the Overview
   redesign's PR, and two PRs editing the same custom properties is a merge nobody wins.

   No-access was the only screen in the app with no container, so it bled to 1440 and read as an
   unstyled error page. Same card, same hairline, same radius as everywhere else. */
.so-state {
  flex: 1; min-width: 0; background: var(--so-bg);
  display: flex; align-items: center; justify-content: center;
  padding: 48px 26px; min-height: calc(100vh - var(--so-appbar-h));
}
.so-statecard {
  width: 100%; max-width: 620px;
  background: var(--so-card); border: 1px solid var(--so-line);
  border-radius: var(--so-radius); box-shadow: var(--so-shadow);
  padding: 30px 32px;
  /* Spacing rhythm: 14px between groups inside a card, never a flat 16 everywhere. */
  display: flex; flex-direction: column; gap: 14px;
}

/* The icon tile. Direct child, because the info banner inside this card also carries a `.ti`
   and it is a 16px glyph, not a 46px tile. Blue = context, per the chip vocabulary — this state
   is information, not a failure, so it is never red. */
.so-statecard > .ti {
  width: 46px; height: 46px; border-radius: 13px; flex: none;
  background: var(--so-blue-bg); color: var(--so-blue-ink);
  display: inline-flex; align-items: center; justify-content: center;
}
.so-statecard > .ti svg { width: 23px; height: 23px; display: block; }

/* The heading group: 10px inside it, against the card's 14px between groups. Grouping is done
   with SPACE, not rules — a flat gap everywhere is why nothing used to read as belonging to
   anything. */
.so-statehead { display: flex; flex-direction: column; gap: 10px; }

/* Page eyebrow — micro-caps, the same step the sign-in card uses, so identity reads the same
   way in both places a user meets it. Tighter still against its own headline. */
.so-statecard .so-step {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--so-lab); line-height: 1.4; margin-bottom: -2px;
}
/* Title step, not the 24px page-display step: this is a card headline. */
.so-statecard .so-h1 { font-size: 20px; line-height: 1.3; }
.so-statecard .so-lede { max-width: none; }
/* Machine detail, last and quiet — it is the block an administrator pastes, not the instruction. */
.so-statecard .so-mono { line-height: 1.6; padding-top: 2px; }
.so-statecard .so-mono b { color: var(--so-body); }

@media (max-width: 640px) {
  .so-state { padding: 26px 16px; align-items: flex-start; }
  .so-statecard { padding: 22px 18px; }
  .so-statecard .so-h1row { flex-direction: column; align-items: stretch; }
  .so-statecard .so-h1row .so-btn { justify-content: center; }
}

/* ══ tables — the house shape for a homogeneous list surface ════════════════ */

.so-dtbl { border: 1px solid var(--so-line); border-radius: var(--so-radius); background: var(--so-card); overflow: auto; }
.so-dtbl table { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13px; }
.so-dtbl th {
  position: sticky; top: 0; z-index: 2; text-align: left;
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--so-lab); font-weight: 800; padding: 10px 12px;
  background: var(--so-side); border-bottom: 1px solid var(--so-line); white-space: nowrap;
}
.so-dtbl td { padding: 10px 12px; border-bottom: 1px solid var(--so-line2); color: var(--so-body); vertical-align: middle; }
.so-dtbl tbody tr:last-child td { border-bottom: none; }
.so-dtbl td b { color: var(--so-ink); font-weight: 700; }
.so-dtbl td .sub { font-size: 11.5px; color: var(--so-lab); font-weight: 600; }
.so-dtbl th.n, .so-dtbl td.n { text-align: right; font-variant-numeric: tabular-nums; }
.so-dtbl tbody tr:hover td { background: var(--so-hov); }

.so-chip { border-radius: 6px; padding: 4px 10px; font-size: 11.5px; font-weight: 800; display: inline-block; }
.so-chip.a { background: var(--so-amber-bg); color: var(--so-amber-ink); }
.so-chip.b { background: var(--so-red-bg); color: var(--so-red-ink); }
.so-chip.c { background: var(--so-blue-bg); color: var(--so-blue-ink); }
.so-chip.ok { background: var(--so-ok-bg); color: var(--so-ok-ink); }
.so-chip.mute { background: var(--so-line2); color: var(--so-lab-tint); }

.so-mono { font-family: var(--so-mono); font-size: 12.5px; color: var(--so-lab); }

/* ══ settings (E1) — tabs, sentence thresholds, the sticky action bar ══════ */

.so-tabs { display: flex; gap: 22px; border-bottom: 1px solid var(--so-line2); margin: 18px 0 20px; }
.so-tabs button {
  font-family: inherit; font-size: 13.5px; font-weight: 700; color: var(--so-lab);
  background: none; border: none; border-bottom: 3px solid transparent;
  padding: 0 0 9px; margin-bottom: -1px; cursor: pointer;
}
.so-tabs button:hover { color: var(--so-ink); }
.so-tabs button.on { color: var(--so-primary); border-bottom-color: var(--so-primary); }
.so-tabs button:focus-visible { outline: 2px solid var(--so-primary); outline-offset: 3px; border-radius: 4px; }

/* A threshold reads as a sentence with the number IN it, not a bare label over a box.
   A labelled input makes you infer the rule; a sentence states it (UX pass 2, 18 Sep). */
.so-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 28px; }
.so-sent { font-size: 15px; color: var(--so-body); line-height: 2.2; }
.so-field-in {
  border: 1px solid var(--so-field); border-radius: 7px; padding: 6px 10px;
  font-family: inherit; font-size: 15px; font-weight: 800; color: var(--so-ink);
  background: var(--so-bg); font-variant-numeric: tabular-nums;
  display: inline-block; line-height: 1.2; text-align: center; max-width: 7ch;
}
.so-field-in:focus { outline: none; border-color: var(--so-primary); box-shadow: 0 0 0 3px var(--so-ring); }
.so-field-in.dirty { border-color: var(--so-primary); color: var(--so-primary); box-shadow: 0 0 0 2px var(--so-ring); }
.so-field-in.err { border-color: var(--so-red-ink); background: var(--so-red-bg); color: var(--so-red-ink); }
.so-field-in.ro { font-weight: 700; color: var(--so-lab); border-style: dashed; max-width: none; padding: 6px 12px; }

/* Days are toggles, not a comma string — the comma string is only how they travel. */
.so-sched { display: flex; flex-direction: column; gap: 22px; max-width: 520px; }
.so-sched-time { max-width: 180px; }
.so-days { display: flex; gap: 7px; flex-wrap: wrap; }
.so-day {
  font-family: inherit; border: 1px solid var(--so-field); border-radius: 7px; padding: 8px 13px;
  font-size: 13px; font-weight: 700; color: var(--so-lab); background: var(--so-bg); cursor: pointer;
}
.so-day:hover { color: var(--so-ink); }
.so-day.on { background: var(--so-primary); border-color: var(--so-primary); color: #fff; }
.so-day:focus-visible { outline: 2px solid var(--so-primary); outline-offset: 2px; }

/* The exclusions grid: an editable list surface, so it is lighter than the dense .so-dtbl. */
.so-excl { display: flex; flex-direction: column; gap: 14px; }
.so-excl-acts { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* The file input keeps its own focus ring and its own keyboard behaviour — it is just not
   the thing anybody should have to look at. Hiding it with display:none would take it out of
   the tab order too, so it is sized to nothing and clipped instead. */
.so-upload { position: relative; cursor: pointer; }
.so-upload input[type="file"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; font-size: 0;
}
.so-upload:focus-within { outline: 2px solid var(--so-primary); outline-offset: 2px; border-radius: var(--so-radius-sm); }
.so-tbl { border: 1px solid var(--so-line); border-radius: var(--so-radius); overflow: auto; background: var(--so-card); }
.so-tbl table { border-collapse: collapse; width: 100%; font-size: 13.5px; }
.so-tbl th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--so-lab); padding: 10px 12px; border-bottom: 1px solid var(--so-line);
  background: var(--so-side); font-weight: 800;
}
.so-tbl td { padding: 8px 12px; border-bottom: 1px solid var(--so-line2); color: var(--so-body); vertical-align: top; }
.so-tbl tr:last-child td { border-bottom: none; }
.so-tbl td b { color: var(--so-ink); font-weight: 700; }
.so-tbl-empty { color: var(--so-lab); padding: 22px 12px; text-align: center; }
.so-inp.sm { padding: 6px 9px; font-size: 13.5px; width: 100%; }

/* The same paging footer as the orders table, deliberately. */
.so-runs { display: flex; flex-direction: column; gap: 12px; }
.so-pager {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--so-lab); border-top: 1px solid var(--so-line2); padding-top: 10px;
}
.so-pager b { color: var(--so-ink); }
.so-pager-acts { margin-left: auto; display: flex; gap: 6px; align-items: center; }
.so-pgb {
  font-family: inherit; border: 1px solid var(--so-field); border-radius: 6px; padding: 4px 11px;
  font-size: 12.5px; font-weight: 800; color: var(--so-lab); background: var(--so-bg);
  white-space: nowrap; cursor: pointer;
}
.so-pgb.on { background: var(--so-primary); border-color: var(--so-primary); color: #fff; }
.so-pgb[disabled] { opacity: .42; cursor: default; }

/* Sticky, and the dirty state is unmissable: Save is disabled until the form is valid rather
   than error-slapping on click (UX pass 2, note 5). */
.so-stick {
  position: sticky; bottom: 0; z-index: 3; margin-top: 22px;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: var(--so-card); border: 1px solid var(--so-line); border-radius: var(--so-radius);
  padding: 11px 14px; box-shadow: 0 -5px 16px rgba(20, 14, 8, .07);
}
.so-stick .acts { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.so-stick-note { font-size: 12px; color: var(--so-lab); }

/* One decision, centred, with the fear-killing line in it — never a bare "Are you sure?". */
.so-modal {
  position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center;
  background: rgba(10, 14, 20, .48); padding: 20px;
}
.so-modal-box {
  background: var(--so-card); border-radius: var(--so-radius); box-shadow: var(--so-shadow-lg);
  padding: 22px 24px; max-width: 460px; width: 100%; display: flex; flex-direction: column; gap: 12px;
}
.so-modal-t { font-size: 18px; font-weight: 800; color: var(--so-ink); }
.so-modal-s { font-size: 14px; color: var(--so-body); line-height: 1.6; }
.so-modal-acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
/* ══ D1 — the sent-orders table ════════════════════════════════════════════ */

/* The section head above the table: what the list is, and how to use it. */
.so-tblhead { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
/* The table scrolls inside itself so the paging footer stays on screen — a footer you have to
   scroll the page to reach cannot tell you where you are. The header is sticky above it. */
.so-dtbl.fill { max-height: calc(100vh - 310px); min-height: 180px; }
.so-tblhead-note { font-size: 12px; color: var(--so-lab); margin-left: auto; }

/* A row is a button: it hovers, it carries a chevron, and the open one keeps a selected state with
   an accent edge BEHIND the scrim — the list never goes away while the drawer is over it. */
.so-dtbl tbody tr[role="button"] { cursor: pointer; }
/* The tint lifts the surface under the row, so the micro-label ink is rebound for everything
   inside it. Rebinding --so-lab rather than naming `.sub` means a hint, a chip or anything else
   lab-coloured that lands in a selected row later clears the floor without a second fix. */
.so-dtbl tbody tr.sel td { background: var(--so-sel); --so-lab: var(--so-lab-tint); }
.so-dtbl tbody tr.sel td:first-child { box-shadow: inset 3px 0 0 var(--so-primary); }
.so-dtbl tbody tr:focus-visible { outline: 2px solid var(--so-primary); outline-offset: -2px; }
.so-dtbl th.go, .so-dtbl td.go { width: 30px; text-align: right; }
.so-go { color: var(--so-field); font-size: 17px; font-weight: 700; line-height: 1; }
.so-dtbl tbody tr:hover .so-go, .so-dtbl tbody tr.sel .so-go { color: var(--so-primary); }
.so-dtbl tbody tr.skel td { padding: 14px 12px; }
.so-dtbl tbody tr.skel .so-skel { display: block; height: 10px; }

/* Saving is the only green number on the screen, so it reads as the one good thing. */
.saving { color: var(--so-ok-ink); }
.warnink { color: var(--so-amber-ink); }

/* The paging footer itself is shared with settings' run history, above. These are the two things
   the orders footer adds: a wrapping button row, and a real "per page" control. */
.so-pager b { font-variant-numeric: tabular-nums; }
.so-pagerbtns { margin-left: auto; display: flex; gap: 5px; align-items: center; flex-wrap: wrap; }
.so-perpage select {
  font: inherit; font-size: 12px; font-weight: 800; color: var(--so-lab);
  background: var(--so-line2); border: 1px solid transparent; border-radius: 6px;
  padding: 4px 8px; cursor: pointer;
}
.so-perpage select:hover { color: var(--so-ink); }
.so-perpage select:focus-visible { outline: 2px solid var(--so-primary); outline-offset: 2px; }
.so-perpage option { color: var(--so-ink); background: var(--so-card); }
.so-pgb:hover:not([disabled]) { color: var(--so-ink); background: var(--so-hov); }
.so-pgb.off { opacity: .42; cursor: default; }

/* ══ D1 — the detail drawer ════════════════════════════════════════════════ */

.so-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, .26); z-index: 30; border: 0; }
:root[data-theme="dark"] .so-scrim { background: rgba(0, 0, 0, .48); }

/* CP-1036, then CP-1040 — 50vw, floored at 720 and capped at 960. Ro, testing: "still small",
   twice. The FLOOR is what the six-column lines table needs to put Product, Suggested, Ordered,
   Cost, Saving and State each on one line at 1440; the CAP is because a panel wider than that
   stops being a panel over a list and starts being a page, and the list behind it is the whole
   reason this is a drawer. Three steps, widest first.

   The shell scrolls NOTHING itself: it is a flex column of header / body / footer, and the body is
   the one scroll region (dl-design-defaults, rule 2). An action you have to scroll to reach cannot
   be found, which is why the footer is outside the scroll rather than sticky inside it. */
.so-drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: clamp(720px, 50vw, 960px); max-width: 100vw;
  background: var(--so-bg); border-left: 1px solid var(--so-line);
  box-shadow: -10px 0 28px rgba(0, 0, 0, .20); z-index: 31;
  display: flex; flex-direction: column; overflow: hidden;
  animation: so-drawer-in 160ms ease-out;
}

/* Header and footer hold their ground; the body between them is the only thing that moves. */
.so-dwr-head {
  flex: 0 0 auto; padding: 22px 28px 14px; border-bottom: 1px solid var(--so-line2);
  display: flex; flex-direction: column; gap: 6px;
}
.so-dwr-titlerow { display: flex; align-items: center; gap: 10px; }
/* The reference IS the title: it is what the order is called on the phone and in the supplier's
   system. Mono, because every character of it matters when it is read out. */
.so-dwr-title {
  font-family: var(--so-mono); font-size: 19px; font-weight: 700; color: var(--so-ink);
  margin: 0; letter-spacing: -.01em;
}
.so-dwr-meta { font-size: 12.5px; color: var(--so-lab); line-height: 1.5; }
/* 40px of target, per CP-1040. A close button that needs aiming at is a close button people miss. */
.so-dwr-x {
  margin-left: auto; min-width: 40px; min-height: 40px; display: flex; align-items: center;
  justify-content: center; border: 1px solid transparent; background: none; cursor: pointer;
  font-size: 20px; line-height: 1; color: var(--so-lab); border-radius: var(--so-radius-sm);
}
.so-dwr-x:hover { color: var(--so-ink); background: var(--so-line2); }
.so-dwr-x:focus-visible { outline: none; border-color: var(--so-ring); box-shadow: 0 0 0 3px var(--so-ring); }

.so-dwr-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  padding: 18px 28px 22px; display: flex; flex-direction: column; gap: 14px;
}

.so-dwr-foot {
  flex: 0 0 auto; display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap;
  padding: 14px 28px; border-top: 1px solid var(--so-line2); background: var(--so-card);
}
.so-dwr-foot .so-btn { min-height: 40px; }

/* CP-1040 — the four totals as ONE row, not four bordered cards. Four cards read as four things to
   click; this reads as one figure with four parts, which is what it is. Equal cells, label above,
   value large and right-aligned in tabular figures so the numbers line up down the row. */
.so-statrow {
  display: grid; grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--so-line2); border-radius: var(--so-radius-sm); overflow: hidden;
  background: var(--so-card);
}
.so-stat { padding: 11px 14px; border-left: 1px solid var(--so-line2); }
.so-stat:first-child { border-left: none; }
.so-stat .k {
  font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
  color: var(--so-lab); text-align: right;
}
.so-stat .v {
  font-size: 21px; font-weight: 800; color: var(--so-ink); text-align: right;
  font-variant-numeric: tabular-nums; margin-top: 3px; line-height: 1.2;
}
.so-stat .v.good { color: var(--so-ok-ink); }

/* CP-1040 — removed / set aside as a collapsed accordion with its count in the header, the same
   shape as the draft page's "Removed (n)" chip. These lines are a decision already made: worth
   finding, not worth reading past every time the drawer opens. <details> because a native
   disclosure is keyboard-operable and screen-reader-announced without a line of script. */
.so-acc { border: 1px solid var(--so-line2); border-radius: var(--so-radius-sm); }
.so-acc > summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 11px 14px; font-size: 12px; font-weight: 800; color: var(--so-lab);
  text-transform: uppercase; letter-spacing: .05em; min-height: 40px; box-sizing: border-box;
}
.so-acc > summary::-webkit-details-marker { display: none; }
.so-acc > summary::before {
  content: "\25B8"; font-size: 11px; color: var(--so-lab); transition: transform 120ms ease-out;
}
.so-acc[open] > summary::before { transform: rotate(90deg); }
.so-acc > summary:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--so-ring); border-radius: var(--so-radius-sm); }
.so-acc-n {
  margin-left: auto; font-variant-numeric: tabular-nums; background: var(--so-line2);
  color: var(--so-ink); border-radius: 999px; padding: 1px 9px; font-size: 11.5px;
}
.so-acc .so-tbl { border: none; border-top: 1px solid var(--so-line2); border-radius: 0; }

@media (prefers-reduced-motion: reduce) {
  .so-acc > summary::before { transition: none; }
}
:root[data-theme="dark"] .so-drawer { box-shadow: -10px 0 28px rgba(0, 0, 0, .62); }
.so-drawer:focus { outline: none; }

/* Between 1000 and 1279 a 720px panel leaves too little of the list behind it to keep your place,
   which is the whole reason this is a drawer and not a page. */
@media (max-width: 1279px) {
  .so-drawer { width: 560px; }
  .so-dwr-head { padding: 18px 20px 12px; }
  .so-dwr-body { padding: 16px 20px 18px; }
  .so-dwr-foot { padding: 12px 20px; }
  .so-drawer .so-tbl.fixed th { font-size: 9px; padding: 8px 6px; }
  .so-drawer .so-tbl.fixed td { padding: 8px 6px; }
}

/* Below 1000 the panel IS the window: a 560px drawer on a 900px screen is a list you cannot
   read behind a panel you cannot use. The border-left goes with it — there is nothing beside it
   for the rule to separate it from. */
@media (max-width: 999px) {
  .so-drawer { width: 100vw; border-left: none; }
}

@keyframes so-drawer-in { from { transform: translateX(16px); opacity: .6; } to { transform: none; opacity: 1; } }

/* `.so-drawer .dkey` lived here. CP-1046 moved the idempotency key out of the body and into the
   footer as "our ref"; see `.so-dwr-ourref` at the end of this file. */
.so-drawer .so-empty { border: none; background: transparent; }

/* The read-only lines table inside the drawer. It borrows the shared .so-tbl vocabulary defined
   above (settings' exclusions grid owns it) and only tightens what a narrow panel needs — scoped to
   the drawer, so restyling here can never reach across to another screen. */
.so-drawer .so-tbl { border-radius: var(--so-radius-sm); }
.so-drawer .so-tbl table { font-size: 12px; }
.so-drawer .so-tbl th { font-size: 10px; letter-spacing: .05em; padding: 8px 9px; }
.so-drawer .so-tbl td { padding: 8px 9px; vertical-align: middle; }
.so-drawer .so-tbl td b.adj { color: var(--so-primary); }
.so-drawer .so-tbl td .sub { font-size: 11px; color: var(--so-lab); line-height: 1.35; }
.so-drawer .so-tbl td.n { text-align: right; font-variant-numeric: tabular-nums; }
/* CP-1040: a right-aligned column needs a right-aligned heading, or the header reads as a
   different column from the numbers under it. */
.so-drawer .so-tbl th.n { text-align: right; }
.so-tbl.fixed table { table-layout: fixed; }
/* Wrap at spaces, never mid-word: a fixed layout plus `overflow-wrap: anywhere` turns "Suggested"
   into "Sugge / sted" and a flag chip into a five-line tower. Only the item id, which has no spaces
   in it to wrap at, is allowed to break anywhere. */
.so-tbl.fixed td, .so-tbl.fixed th { overflow-wrap: normal; word-break: normal; white-space: normal; }
.so-tbl.fixed th { font-size: 9px; letter-spacing: normal; padding: 8px 5px; }
.so-tbl.fixed td { padding: 8px 5px; }
.so-tbl.fixed td .sub { overflow-wrap: anywhere; }
.so-tbl.fixed .so-chip { padding: 3px 6px; line-height: 1.3; text-align: center; font-size: 10.5px; }
/* CP-1040 — six columns: Product, Suggested, Ordered, Cost, Saving, State, each on ONE line at
   1440. The 9px headings and 5px gutters that came before were what a 480px panel needed; at
   720-960 the drawer's table reads at the same size as every other table in the app. Scoped to the
   drawer so the settings grid that shares .so-tbl.fixed is untouched. */
.so-drawer .so-tbl.fixed th { font-size: 10px; letter-spacing: .05em; padding: 9px 10px; }
.so-drawer .so-tbl.fixed td { padding: 9px 10px; }
.so-drawer .so-tbl.fixed th, .so-drawer .so-tbl.fixed td.n { white-space: nowrap; }
.so-drawer .so-tbl.fixed .so-chip { white-space: nowrap; }
.so-drawer .so-tbl.fixed td .sub { display: block; }

.so-tbl.lines th:nth-child(1) { width: 32%; }
.so-tbl.lines th:nth-child(2) { width: 12%; }
.so-tbl.lines th:nth-child(3) { width: 13%; }
.so-tbl.lines th:nth-child(4) { width: 16%; }
.so-tbl.lines th:nth-child(5) { width: 12%; }
.so-tbl.lines th:nth-child(6) { width: 15%; }
/* Struck through, dimmed, and outside the totals — the override report in plain sight. */
.so-tbl tr.gone td { opacity: .58; }
.so-tbl tr.gone td b { text-decoration: line-through; }
.so-was { font-size: 11px; color: var(--so-primary); font-weight: 700; margin-top: 2px; }

/* ══ B1 · the buying overview — design pass 21 Sep 2026 (CP-1042) ══════════
   Ported from the approved mock, AI_Docs/mocks/overview-redesign-2026-09-21.html.

   The screen's skeleton is fixed across every state — eyebrow + title + run
   status LINE, the peak card, the tiles, the attention list, the run trail —
   so the page never reorganises itself under the user and no state is ever a
   blank canvas. Only the peak card's colour, copy and CTA change.

   These classes are `sox-` prefixed and used by Overview.razor alone. The
   `so-` vocabulary they replaced (.so-rule / .so-rows / .so-row) was also
   Overview-only and went with them; nothing else on the app referenced it. */

/* ── 1 · the header block ──────────────────────────────────────────────── */

.sox-head { display: flex; align-items: flex-start; gap: 20px; flex-wrap: wrap; }
.sox-eyebrow {
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--so-lab);
}
.sox-h1 { font-size: 27px; font-weight: 800; letter-spacing: -.02em; color: var(--so-ink); margin: 4px 0 0; }

/* The last-run status is a LINE, not a pill: a sentence can grow to carry the trigger, the
   line counts and a failure reason, where a fixed-width blob had nowhere to put any of it. */
.sox-runline {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin-top: 9px; font-size: 13.5px; color: var(--so-body);
}
.sox-runline b { color: var(--so-ink); font-weight: 700; }
.sox-dot { width: 8px; height: 8px; border-radius: 999px; flex: none; }
.sox-dot.ok   { background: #3E9B63; box-shadow: 0 0 0 3px rgba(62, 155, 99, .18); }
.sox-dot.warn { background: #D69E2E; box-shadow: 0 0 0 3px rgba(214, 158, 46, .20); }
.sox-dot.bad  { background: #C0504A; box-shadow: 0 0 0 3px rgba(192, 80, 74, .20); }
.sox-dot.mute { background: var(--so-lab); box-shadow: 0 0 0 3px var(--so-hov); }
.sox-sep { color: var(--so-field); }
.sox-runline .sox-ghost { margin-left: 4px; }

/* "Run it again" rides at the end of the status line — present, quiet, exactly where you look
   after reading that the run fired. It is promoted to the solid CTA in one state only: a run
   that failed, which is the one morning where re-running genuinely is the primary action. */
.sox-ghost {
  background: none; border: none; padding: 4px 8px; margin: -4px 0; border-radius: 6px;
  font: 700 13px var(--so-sans); color: var(--so-lab); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
}
.sox-ghost:hover:not([disabled]) { color: var(--so-ink); background: var(--so-hov); }
.sox-ghost:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--so-ring); }
.sox-ghost[disabled] { opacity: .45; cursor: default; }

/* ── 2 · the peak — the decision card ──────────────────────────────────── */

.sox-peak {
  position: relative; display: flex; align-items: center; gap: 28px; flex-wrap: wrap;
  background: var(--so-card); border: 1px solid var(--so-line);
  border-left: 4px solid var(--so-primary);
  border-radius: var(--so-radius); padding: 22px 26px; box-shadow: var(--so-shadow);
}
.sox-peak .body { flex: 1 1 420px; min-width: 0; }
/* --so-primary at 11px is 3.1:1 on white; the ink variant is the readable one. */
.sox-peak .lab {
  font-size: 11px; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--so-primary-ink);
}
.sox-peak .headline {
  font-size: 25px; font-weight: 800; letter-spacing: -.02em; color: var(--so-ink);
  margin-top: 7px; line-height: 1.25; font-variant-numeric: tabular-nums;
}
.sox-peak .support { margin-top: 8px; font-size: 14px; color: var(--so-body); line-height: 1.6; max-width: 62ch; }
.sox-peak .support b { color: var(--so-ink); font-weight: 700; }
.sox-peak .cta { display: flex; flex-direction: column; align-items: flex-end; gap: 9px; flex: none; }
.sox-peak .cta .after { font-size: 12.5px; color: var(--so-lab); font-weight: 600; }
.sox-peak.calm { border-left-color: #3E9B63; }
.sox-peak.calm .lab { color: var(--so-ok-ink); }
.sox-peak.quiet { border-left-color: var(--so-field); }
.sox-peak.quiet .lab { color: var(--so-lab); }
.sox-peak.bad { border-left-color: #C0504A; }
.sox-peak.bad .lab { color: var(--so-red-ink); }

/* ── 3 · stat tiles — one system, three slots ──────────────────────────── */

/* Label / value+unit / consequence, in that order. The VALUE is ink, not brand orange: four
   numbers in the brand colour spend it on things that carry no brand meaning, and the two
   places it genuinely means something (active nav, the CTA) stop reading as special. Meaning
   lives in the small coloured phrase on the consequence line instead. */
.sox-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.sox-tile {
  background: var(--so-card); border: 1px solid var(--so-line); border-radius: var(--so-radius);
  padding: 15px 17px 16px; display: flex; flex-direction: column; min-height: 124px;
}
.sox-tile .t {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--so-lab); display: flex; align-items: center; gap: 7px;
}
.sox-tile .n {
  font-size: 31px; font-weight: 800; line-height: 1.1; letter-spacing: -.02em;
  color: var(--so-ink); font-variant-numeric: tabular-nums; margin-top: 9px;
}
.sox-tile .n .u { font-size: 15px; font-weight: 700; color: var(--so-lab); margin-left: 3px; letter-spacing: 0; }
/* "—" is a real answer and reads as one: label-weight, never a fat orange redaction bar. */
.sox-tile .n.none { color: var(--so-lab); font-weight: 700; }
.sox-tile .d { margin-top: auto; padding-top: 9px; font-size: 12.5px; font-weight: 600; color: var(--so-body); line-height: 1.4; }
.sox-tile .d .c { font-weight: 800; }
.sox-tile .d .c.pos { color: var(--so-ok-ink); }
.sox-tile .d .c.warn { color: var(--so-amber-ink); }
.sox-tile .d .c.bad { color: var(--so-red-ink); }
.sox-tile .bar { margin-top: 10px; height: 5px; border-radius: 999px; background: var(--so-line2); overflow: hidden; }
.sox-tile .bar i { display: block; height: 100%; border-radius: 999px; background: var(--so-amber-ink); }
.sox-tile .bar i.pos { background: #3E9B63; }

/* ── 4 · needs attention ───────────────────────────────────────────────── */

/* Section headings are INK with a count chip. The orange text + 3px orange underline they used
   to carry is the exact treatment `.so-tabs button.on` uses on Settings, so it read as
   clickable — and people click things that look clickable. */
.sox-secthead { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.sox-h2b { font-size: 16px; font-weight: 800; color: var(--so-ink); letter-spacing: -.01em; margin: 0; }
.sox-count {
  font-size: 11.5px; font-weight: 800; border-radius: 999px; padding: 2px 9px;
  background: var(--so-amber-bg); color: var(--so-amber-ink);
}
.sox-count.ok { background: var(--so-ok-bg); color: var(--so-ok-ink); }
.sox-secthead .hint { margin-left: auto; font-size: 12.5px; color: var(--so-lab); font-weight: 600; }

.sox-list {
  background: var(--so-card); border: 1px solid var(--so-line); border-radius: var(--so-radius);
  overflow: hidden;
}
.sox-row {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px;
  border-bottom: 1px solid var(--so-line2); cursor: pointer; width: 100%;
  background: none; border-left: none; border-right: none; border-top: none;
  font-family: inherit; text-align: left; color: inherit;
  transition: background .16s ease;
}
.sox-row:last-child { border-bottom: none; }
.sox-row:hover { background: var(--so-hov); }
.sox-row:hover .so-btn.d { background: var(--so-cta); color: var(--so-cta-ink); }
.sox-row:focus-visible { outline: none; box-shadow: inset 0 0 0 3px var(--so-ring); }

/* Advisory flags are AMBER. Red is kept for things that actually went wrong — the spec calls
   these advisory only, with no acknowledgement gate (confirmed with Matt, 7 Aug 2026), and red
   says "you must fix this" when the flag means "you might want to look". */
.sox-icontile {
  width: 38px; height: 38px; border-radius: 10px; flex: none; display: grid; place-items: center;
  font-size: 17px; font-weight: 800;
}
.sox-icontile.amber { background: var(--so-amber-bg); color: var(--so-amber-ink); }
.sox-icontile.blue  { background: var(--so-blue-bg);  color: var(--so-blue-ink); }
.sox-icontile.mute  { background: var(--so-line2);    color: var(--so-lab); }
.sox-row .nm { flex: 1; min-width: 0; }
.sox-row .nm .top { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.sox-row .nm b { font-size: 14.5px; font-weight: 700; color: var(--so-ink); }
.sox-row .nm .sku { font-family: var(--so-mono); font-size: 11.5px; color: var(--so-lab); }
.sox-row .nm .why { font-size: 13px; color: var(--so-body); margin-top: 3px; line-height: 1.45; }
/* `sox-qty`, not `qty`: `.qty` is already the draft order's quantity STEPPER further down this
   file — a bordered inline-flex box whose `.s` children are its minus/plus buttons. A row here
   that called itself `.qty` inherited that border and that layout, and the cartons and the cost
   came out side by side inside a stray input-looking box. */
.sox-row .sox-qty {
  flex: none; text-align: right; font-variant-numeric: tabular-nums;
  font-size: 13.5px; font-weight: 700; color: var(--so-ink); min-width: 96px;
}
.sox-row .sox-qty .s { display: block; font-size: 11.5px; font-weight: 600; color: var(--so-lab); }

/* The good-news state is the WIN, so it reads like a green light. A dashed box means
   "something is missing here" everywhere else in software, which argued with its own copy. */
.sox-clear {
  display: flex; align-items: center; gap: 16px;
  background: var(--so-card); border: 1px solid var(--so-line); border-left: 4px solid #3E9B63;
  border-radius: var(--so-radius); padding: 18px 20px;
}
.sox-clear .tick {
  width: 40px; height: 40px; border-radius: 12px; flex: none; display: grid; place-items: center;
  background: var(--so-ok-bg); color: var(--so-ok-ink); font-size: 20px; font-weight: 800;
}
.sox-clear .big { font-size: 15px; font-weight: 800; color: var(--so-ink); }
.sox-clear .s { font-size: 13px; color: var(--so-body); margin-top: 3px; line-height: 1.5; }

/* The `sox-trail` / `sox-step` block that used to close this section is gone (Ro, 21 Sep 2026).
   The design pass gave the page a four-step "This run, so far" card so it would end on
   something rather than on empty canvas; tested on the real screen, every step it drew was
   already said above it, so it read as ceremony. The status line and the peak card carry all
   of it, including the vendor's reference. */

/* The row action is dark rather than primary: four of them stacked in the tenant's
   brand colour would out-shout the screen's one real next step. Derived from the
   neutral ink, so it lands on every tenant. */
.so-btn.d { background: var(--so-rowbtn); color: var(--so-rowbtn-ink); }
.so-btn.d:hover { background: color-mix(in srgb, var(--so-rowbtn) 82%, var(--so-ink)); }
.so-btn.big { padding: 13px 22px; font-size: 15px; border-radius: var(--so-radius); }

/* The error state's two exits. */
.so-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ── the run control ──────────────────────────────────────────────────────
   Shared by the overview and the draft page, and deliberately the same shape on both.

   It shipped as a ghost button on the overview's status line and as a button under the draft
   page's preview table — two treatments, two labels, and on a real draft no way to start a run
   from the draft page at all. Ro tested it and asked for one recognisable control: "make sure
   it's recognisable so we can run a new session". It now sits in the header's action area on
   both screens, in every state, at a 40px target, carrying the brand colour either as a solid
   fill or as an outline depending on whether the screen already has a primary. */

.so-runaction { position: relative; flex: none; align-self: flex-start; }
.so-btn-run { min-height: 40px; padding-inline: 18px; }
/* The outlined variant carries the brand colour rather than neutral ink — outlined is about
   emphasis against the page's primary, not about the control being unimportant. */
.so-btn.o.so-btn-run { color: var(--so-primary-ink); border-color: var(--so-primary-ink); }
.so-btn.o.so-btn-run:hover { background: var(--so-tint); }
.so-btn-run .ti { font-size: 15px; line-height: 1; }

/* The confirm. One line, the truth, and two ways out — never a modal for a decision this small. */
.so-confirm {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 20;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  width: max-content; max-width: min(92vw, 460px);
  background: var(--so-card); border: 1px solid var(--so-line);
  border-radius: var(--so-radius); padding: 12px 14px; box-shadow: var(--so-shadow-lg);
}
.so-confirm .q { font-size: 13.5px; font-weight: 600; color: var(--so-ink); line-height: 1.45; flex: 1 1 100%; }
.so-confirm .so-btn { min-height: 36px; }

@media (max-width: 640px) {
  .so-runaction { width: 100%; }
  .so-btn-run { width: 100%; justify-content: center; }
  .so-confirm { right: auto; left: 0; width: 100%; }
}

@media (max-width: 1280px) {
  .sox-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  .sox-peak .cta { align-items: stretch; width: 100%; }
  .sox-peak .cta .after { text-align: center; }
}

@media (max-width: 640px) {
  .sox-tiles { grid-template-columns: minmax(0, 1fr); }
  .sox-row { flex-wrap: wrap; }
  .sox-row .nm { flex-basis: 100%; order: 3; }
  .sox-row .sox-qty { text-align: left; }
}
/* ══ the draft order — UX pass 2, "the draft as a work surface" ═════════════
   Task-first chips, a column diet, one decision per row, sticky totals. Ported from
   the design baseline's UX-pass-2 block, stepped up one type scale: the mock draws
   inside a ~720px device frame and this is a real window. ═══════════════════ */

/* The page's own stack, so a screen can be one root element (and one test id) without losing
   the shell's column rhythm. */
.so-page-stack { display: flex; flex-direction: column; gap: 16px; flex: 1; min-width: 0; }

/* A label a screen reader needs and a sighted user does not — an empty <th> is announced as
   nothing at all, which is how a column of buttons becomes unreachable. */
.so-visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

.so-chips { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

.so-fchip {
  border: 1px solid var(--so-field); border-radius: 999px; padding: 6px 14px;
  font-size: 12.5px; font-weight: 800; color: var(--so-lab); background: var(--so-bg);
  white-space: nowrap; display: inline-flex; align-items: center; gap: 6px;
}
.so-fchip:hover { background: var(--so-hov); color: var(--so-ink); }
.so-fchip[aria-pressed="true"] { background: var(--so-primary); border-color: var(--so-primary); color: #fff; }
/* Amber outline says "this one wants you" while it is NOT the chosen chip; once chosen
   the primary fill wins, because two loud states on one control read as a rendering bug. */
.so-fchip.alert { border-color: var(--so-amber-ink); color: var(--so-amber-ink); }
.so-fchip.alert[aria-pressed="true"] { background: var(--so-primary); border-color: var(--so-primary); color: #fff; }

.so-prog {
  margin-left: auto; font-size: 12px; color: var(--so-lab); display: flex; align-items: center;
  gap: 9px; font-weight: 700; white-space: nowrap;
}
.so-prog .track { width: 96px; height: 6px; border-radius: 3px; background: var(--so-line2); overflow: hidden; }
.so-prog .track i { display: block; height: 100%; background: var(--so-primary); border-radius: 3px; }

/* ── the grid itself ─────────────────────────────────────────────────────── */

.so-dgrid { border: 1px solid var(--so-line); border-radius: var(--so-radius); background: var(--so-card); overflow-y: auto; overflow-x: auto; }
.so-dgrid table { table-layout: fixed; border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13px; }
.so-dgrid th {
  position: sticky; top: 0; z-index: 2; text-align: left; font-size: 10px; text-transform: uppercase;
  letter-spacing: .05em; color: var(--so-lab); font-weight: 800; padding: 9px 12px;
  background: var(--so-side); border-bottom: 1px solid var(--so-line);
}
.so-dgrid th.n { text-align: right; }
.so-dgrid td { padding: 11px 12px; border-bottom: 1px solid var(--so-line2); vertical-align: middle; color: var(--so-body); }
.so-dgrid tbody tr:last-child td { border-bottom: none; }
.so-dgrid tbody tr:hover td { background: var(--so-hov); }
.so-dgrid td b { color: var(--so-ink); font-weight: 700; }
.so-dgrid .sub { font-size: 11px; color: var(--so-lab); line-height: 1.4; margin-top: 3px; }
.so-dgrid td.n { text-align: right; font-variant-numeric: tabular-nums; }
.so-dgrid .u { font-size: 11px; color: var(--so-lab); font-weight: 700; }

/* The flag's colour is the row's left edge: you learn the row wants you before you read it. */
.so-dgrid tr.f-ctn td:first-child { box-shadow: inset 3px 0 0 var(--so-amber-ink); }
.so-dgrid tr.f-hist td:first-child { box-shadow: inset 3px 0 0 var(--so-red-ink); }
.so-dgrid tr.f-low td:first-child { box-shadow: inset 3px 0 0 var(--so-blue-ink); }
/* Reviewed dims, it does NOT disappear — a row that vanishes under you feels like a bug. */
.so-dgrid tr.done td { opacity: .72; }

.rflag {
  font-size: 11px; font-weight: 800; margin-top: 6px; display: inline-block;
  border-radius: 6px; padding: 3px 8px; line-height: 1.3;
}
.rflag.a { background: var(--so-amber-bg); color: var(--so-amber-ink); }
.rflag.b { background: var(--so-red-bg); color: var(--so-red-ink); }
.rflag.c { background: var(--so-blue-bg); color: var(--so-blue-ink); }

.cbar { height: 5px; border-radius: 3px; background: var(--so-line2); margin-top: 6px; overflow: hidden; }
.cbar i { display: block; height: 100%; border-radius: 3px; background: var(--so-primary); }
.cbar.ok i { background: var(--so-ok-ink); }
.cbar.low i { background: var(--so-blue-ink); }

/* ── the one editable control on the row ─────────────────────────────────── */

.qty { display: inline-flex; align-items: stretch; border: 1px solid var(--so-field); border-radius: 8px; overflow: hidden; background: var(--so-bg); }
/* 36px is the floor for a target someone hits 142 times before breakfast. */
.qty .s {
  width: 36px; min-height: 36px; display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 800; color: var(--so-lab); background: var(--so-side);
  border: none; padding: 0;
}
.qty .s:hover:not([disabled]) { color: var(--so-ink); background: var(--so-hov); }
.qty .v {
  width: 58px; min-height: 36px; padding: 6px 4px; text-align: center; font-size: 15px; font-weight: 800;
  color: var(--so-ink); font-variant-numeric: tabular-nums; background: transparent;
  border: none; border-left: 1px solid var(--so-field); border-right: 1px solid var(--so-field);
  font-family: inherit; -moz-appearance: textfield; appearance: textfield;
}
.qty .v::-webkit-outer-spin-button, .qty .v::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty .v:focus { outline: none; }
.qty:focus-within { border-color: var(--so-primary); box-shadow: 0 0 0 3px var(--so-ring); }
.qty.edited { border-color: var(--so-primary); }
.qty.edited .v { color: var(--so-primary); }
.qty .un { display: flex; align-items: center; padding: 0 9px; font-size: 11px; font-weight: 800; color: var(--so-lab); }

.wasline { font-size: 11px; color: var(--so-primary); font-weight: 700; margin-top: 5px; }
.wasline .rs { color: var(--so-lab); text-decoration: underline; font-weight: 700; background: none; border: none; padding: 0; font-size: 11px; font-family: inherit; }
.wasline .rs:hover { color: var(--so-ink); }

.so-rowbtn { background: none; border: none; color: var(--so-lab); font-size: 13px; font-weight: 700; padding: 6px 8px; border-radius: 6px; min-height: 36px; }
.so-rowbtn:hover { color: var(--so-red-ink); background: var(--so-red-bg); }
.so-rowbtn.x:hover { color: var(--so-primary); background: var(--so-tint); }

/* The removal reason: three one-tap chips plus free text, and every one of them optional. */
.so-reasons { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: 8px; }
.so-reasons .so-fchip { padding: 5px 11px; font-size: 11.5px; }
.so-reasons .so-inp { padding: 5px 9px; font-size: 12px; width: 190px; }

/* The row expand: everything that does NOT answer "should I change this number?". */
.so-expand { background: var(--so-side); }
.so-expand .facts { display: flex; gap: 20px; flex-wrap: wrap; font-size: 12px; color: var(--so-body); }
.so-expand .facts > div { display: flex; flex-direction: column; gap: 2px; }
.so-expand .facts .k { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--so-lab); }
.so-expand .facts .v { font-weight: 700; color: var(--so-ink); font-variant-numeric: tabular-nums; }

/* ── the decisions already made, and the one still to make ───────────────── */

.so-toggle {
  display: flex; align-items: center; gap: 10px; font-size: 12.5px; font-weight: 700; color: var(--so-lab);
  background: var(--so-side); border: 1px dashed var(--so-field); border-radius: var(--so-radius-sm); padding: 9px 13px;
}
.so-toggle b { color: var(--so-ink); }
.so-toggle .go { margin-left: auto; color: var(--so-primary-ink); font-weight: 800; white-space: nowrap; background: none; border: none; font-size: 12.5px; font-family: inherit; }
.so-removed-list { display: flex; flex-direction: column; gap: 9px; padding: 11px 13px; border: 1px solid var(--so-line); border-top: none; border-radius: 0 0 var(--so-radius-sm) var(--so-radius-sm); background: var(--so-card); }
.so-removed-list .row { display: flex; align-items: center; gap: 12px; font-size: 12.5px; color: var(--so-body); flex-wrap: wrap; }
.so-removed-list .row b { color: var(--so-ink); }
.so-removed-list .row .why { margin-right: auto; color: var(--so-lab); }

/* The sticky action bar itself is defined once, up with Settings (E1) — it is the same component
   on both screens and a second base rule here would quietly win over it by cascade order. What is
   added below is only what the DRAFT's bar carries that a settings bar does not: four totals. */
:root[data-theme="dark"] .so-stick { box-shadow: 0 -5px 16px rgba(0, 0, 0, .45); }
.so-stick .t { display: flex; gap: 22px; flex-wrap: wrap; }
.so-stick .t .v { font-size: 19px; font-weight: 800; color: var(--so-ink); font-variant-numeric: tabular-nums; line-height: 1.1; }
.so-stick .t .v.good { color: var(--so-ok-ink); }
.so-stick .t .k { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--so-lab); margin-top: 3px; }
.so-stick .acts .left { font-size: 11.5px; color: var(--so-lab); font-weight: 700; }

/* The pager, likewise, is Settings'/Orders' rule — this only adds the draft's right-hand group. */
.so-pager .grow { margin-left: auto; display: flex; gap: 8px; align-items: center; }

.so-kbd { font-family: var(--so-mono); font-size: 11px; font-weight: 700; border: 1px solid var(--so-field); border-radius: 4px; padding: 1px 5px; color: var(--so-lab); background: var(--so-side); }

/* The one irreversible action gets a real dialog — and it is the SAME dialog Settings raises
   before discarding, so it uses .so-modal / .so-modal-box rather than a second one that looks
   almost the same. The only addition is a list, for naming the lines a collision blocked. */
.so-banner ul { display: flex; flex-direction: column; gap: 5px; margin-top: 6px; }

/* ══ C2 — the ending. Peak-End: this is the screen they describe to someone else. ══ */

.so-hero { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; text-align: center; padding: 24px 6px; }
.so-tick { width: 64px; height: 64px; border-radius: 50%; background: var(--so-ok-bg); color: var(--so-ok-ink); display: flex; align-items: center; justify-content: center; font-size: 30px; font-weight: 800; }
.so-tick.warn { background: var(--so-amber-bg); color: var(--so-amber-ink); }
.so-tick.bad { background: var(--so-red-bg); color: var(--so-red-ink); }
/* The headline and the sentence under it are one statement, so they are one block. */
.so-outcome { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.so-hero .big, .so-modal-box.sent .big { font-size: 26px; font-weight: 800; color: var(--so-ink); letter-spacing: -.015em; max-width: 22ch; }
.so-hero .sub, .so-modal-box.sent .sub { font-size: 14.5px; color: var(--so-body); max-width: 52ch; line-height: 1.55; }
/* The reference is the artefact they quote on the phone, so it gets its own block. */
.so-ref { font-family: var(--so-mono); font-size: 18px; font-weight: 700; color: var(--so-primary); background: var(--so-tint); border-radius: var(--so-radius-sm); padding: 9px 18px; }
.so-sum { display: flex; gap: 30px; flex-wrap: wrap; justify-content: center; }
.so-sum div { text-align: center; }
.so-sum .v { font-size: 22px; font-weight: 800; color: var(--so-ink); font-variant-numeric: tabular-nums; }
.so-sum .v.good { color: var(--so-ok-ink); }
.so-sum .k { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--so-lab); margin-top: 3px; }
.so-next { display: flex; gap: 10px; margin-top: 4px; flex-wrap: wrap; justify-content: center; }

/* CP-1038 — the ending as a dialog over the draft. It reuses the C2 vocabulary above (tick,
   outcome, reference, the four numbers) rather than a second set that looks almost the same: the
   moment did not change, only where it happens. Wider than the confirm dialog because the four
   numbers have to sit on one row — wrapped onto two they read as eight. */
.so-modal-box.sent {
  max-width: 560px; align-items: center; text-align: center; gap: 14px;
  padding: 26px 26px 22px; position: relative;
}
.so-modal-box.sent .so-banner { text-align: left; }
/* CP-1040: the dialog's numbers get the drawer's stat row, so the surface that ENDS the send and
   the surface that shows it later read as the same thing. */
.so-modal-box.sent .so-statrow { width: 100%; }
/* The × sits in the corner, small and quiet: it is an escape hatch, not an action, and the action
   is the primary button. */
.so-modal-x {
  position: absolute; top: 10px; right: 12px; border: none; background: none; cursor: pointer;
  font-size: 20px; line-height: 1; padding: 4px 8px; color: var(--so-lab); border-radius: var(--so-radius-sm);
}
.so-modal-x:hover { color: var(--so-ink); background: var(--so-line2); }
.so-modal-acts.sent { justify-content: center; flex-wrap: wrap; margin-top: 2px; width: 100%; }

/* ══ single-column degrade — every screen, per the baseline ════════════════ */

@media (max-width: 860px) {
  :root { --so-side-w: 100%; }
  .so-main { flex-direction: column; }
  .so-side {
    width: 100%; border-right: none; border-bottom: 1px solid var(--so-line);
    flex-direction: row; overflow-x: auto; padding: 10px 12px; gap: 8px;
  }
  .so-nav { white-space: nowrap; }
  .so-page { padding: 18px 16px; }
  .so-appbar { padding: 0 16px; gap: 8px; }
  .so-who { display: none; }
  .so-sel { max-width: 150px; }

  /* The draft grid is six columns of small numbers; below 860px it scrolls inside its own
     card rather than pushing the PAGE sideways — a horizontal page scrollbar is never
     acceptable. The card keeps its own overflow-x, so the page never gains one. */
  .so-dgrid table { table-layout: auto; min-width: 580px; }
  .so-stick .t { gap: 14px; }
  .so-stick .acts .so-btn { flex: 1; justify-content: center; }
  .so-prog { margin-left: 0; width: 100%; }
  .so-hero { padding: 14px 4px; }
  .so-hero .big, .so-modal-box.sent .big { font-size: 21px; }
  .so-sum { gap: 18px; }
  .so-modal-box.sent { padding: 20px 18px 18px; }
  .so-modal-acts.sent .so-btn { flex: 1; justify-content: center; }

  .so-grid2 { grid-template-columns: 1fr; }
  .so-tabs { gap: 14px; overflow-x: auto; }
  .so-stick { flex-direction: column; align-items: stretch; }
  .so-stick .acts { margin-left: 0; }
  /* The drawer is already full-width from 999px down (see the drawer's own block above). What a
     phone needs on top of that is the product column giving ground — the numeric columns are
     already at the width their headings need. */
  .so-tbl.fixed th { font-size: 8.5px; }
  .so-tbl.lines th:nth-child(1) { width: 26%; }
  .so-tbl.lines th:nth-child(2) { width: 13%; }
  .so-tbl.lines th:nth-child(3) { width: 14%; }
  .so-tbl.lines th:nth-child(4) { width: 17%; }
  .so-tbl.lines th:nth-child(5) { width: 14%; }
  .so-tbl.lines th:nth-child(6) { width: 16%; }
  /* Four cells of tabular numbers do not fit across a phone. Two by two keeps them readable
     without either a horizontal scrollbar or a font size nobody can read. */
  .so-statrow { grid-template-columns: repeat(2, 1fr); }
  .so-stat:nth-child(3) { border-left: none; }
  .so-stat:nth-child(n+3) { border-top: 1px solid var(--so-line2); }
  .so-tblhead-note { margin-left: 0; width: 100%; }
  .so-pagerbtns { margin-left: 0; width: 100%; }
}

/* ══ CP-1043 — the approved app redesign, applied to the draft and the two dialogs ═════════
   Ro approved AI_Docs/diagnosis/overview-redesign/app-redesign.html on 21 Sep 2026 13:32.

   Deliberately the LAST block in this file, and deliberately touching no :root token: the Overview
   redesign (CP-1042) owns the token values and is landing dark-mode contrast fixes in them. These
   are component rules only, and every one of them is an override of something earlier in this
   file, so source order is doing the work rather than a specificity arms race. */

/* ── rule 4: one decision card per screen ───────────────────────────────────
   The only 4px left accent in the system, so it cannot be diluted. It names the line that wants a
   look, says why, and carries the one action that goes there. */
.so-decide {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  border: 1px solid var(--so-line); border-left: 4px solid var(--so-primary);
  border-radius: var(--so-radius); background: var(--so-card);
  box-shadow: var(--so-shadow); padding: 16px 18px;
}
.so-decide .body { flex: 1 1 320px; min-width: 0; }
.so-decide .lab {
  font-size: 10.5px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
  color: var(--so-lab);
}
.so-decide .headline {
  font-size: 20px; font-weight: 800; color: var(--so-ink); letter-spacing: -.01em;
  margin-top: 5px; line-height: 1.25;
}
.so-decide .support { font-size: 13.5px; color: var(--so-body); line-height: 1.55; margin-top: 6px; }
.so-decide .support b { color: var(--so-ink); }
.so-decide .cta { display: flex; flex-direction: column; align-items: stretch; gap: 6px; flex: none; }
.so-decide .cta .after { font-size: 11.5px; font-weight: 700; color: var(--so-lab); text-align: center; }
.so-btn.big { padding: 12px 20px; font-size: 14.5px; justify-content: center; }

/* The good outcome is a green light, not an empty dropzone. */
.so-verdict {
  display: flex; align-items: center; gap: 14px;
  border: 1px solid var(--so-line); border-radius: var(--so-radius);
  background: var(--so-card); padding: 14px 16px;
}
.so-verdict .ti {
  width: 40px; height: 40px; border-radius: 12px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--so-ok-bg); color: var(--so-ok-ink); font-size: 20px; font-weight: 800;
}
.so-verdict .t { font-size: 16px; font-weight: 800; color: var(--so-ink); }
.so-verdict .s { font-size: 13px; color: var(--so-body); line-height: 1.5; margin-top: 2px; }

/* ── rule 6: the ONE stat row, on all three surfaces ────────────────────────
   Two additions the draft and the confirm dialog need and the drawer never did: a three-cell
   variant, and a sub-line under a value. */
.so-statrow.three { grid-template-columns: repeat(3, 1fr); }
.so-stat .s {
  font-size: 11px; font-weight: 700; color: var(--so-lab); text-align: right;
  margin-top: 3px; line-height: 1.3;
}

/* ── rule 7: brand colour means "act" ───────────────────────────────────────
   A selected FILTER is a state, not an action. It used to be a solid brand pill, which made it the
   second-loudest thing on the page, competing with Approve. */
.so-fchip[aria-pressed="true"],
.so-fchip.alert[aria-pressed="true"] {
  background: var(--so-line2); border-color: var(--so-field); color: var(--so-ink);
}
.so-fchip[aria-pressed="true"]:hover { background: var(--so-line2); }

/* ── rule 8: red is failed or destructive ONLY ──────────────────────────────
   "Above buying history" is advisory and explicitly never stops an order going, so its row edge
   goes amber with its chip. */
.so-dgrid tr.f-hist td:first-child { box-shadow: inset 3px 0 0 var(--so-amber-ink); }

/* A line the engine deliberately never costed stays visible and says so in place, rather than
   leaving a gap under the chip that hid it. */
.so-dgrid tr.excluded td { opacity: .62; }
.so-dgrid .nameline { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.so-dgrid .nameline b { color: var(--so-ink); font-weight: 700; }
.so-dgrid .sub.why { color: var(--so-body); max-width: 62ch; }

/* ── rule 9: disabled is neutral grey, never a pale tint of the brand ───────
   A washed-out brand button reads as broken, not as "not yet". */
.so-btn.p[disabled], .so-btn.p:disabled {
  background: var(--so-line2); color: var(--so-lab); opacity: 1;
}
.so-btn.p[disabled]:hover, .so-btn.p:disabled:hover { background: var(--so-line2); }

/* ── the sticky bar: the sentence that kills the hesitation sits beside the button ── */
.so-stick .so-stick-note { flex: 1 1 260px; min-width: 0; line-height: 1.45; }

/* ── the two dialogs ────────────────────────────────────────────────────────
   The escape route gets physical distance, not just a lighter colour. */
.so-modal-acts.split { justify-content: space-between; width: 100%; }
.so-modal-box .so-statrow { width: 100%; }

/* The reference is the artefact of the peak — the thing read out on the phone — so it gets its own
   designed block rather than body type inside the explanation. */
.so-modal-box.sent .so-ref {
  font-size: 20px; text-align: center; width: 100%; padding: 12px 18px;
  border: 1px solid var(--so-line); letter-spacing: .02em; box-sizing: border-box;
}

@media (max-width: 860px) {
  /* The four-cell row collapses two-by-two above. A three-cell row has no clean two-by-two, so it
     stacks — the nth-child border rules up there assume exactly four cells. */
  .so-statrow.three { grid-template-columns: 1fr; }
  .so-statrow.three .so-stat { border-left: none; border-top: 1px solid var(--so-line2); }
  .so-statrow.three .so-stat:first-child { border-top: none; }
}

@media (max-width: 720px) {
  .so-decide { align-items: stretch; }
  .so-decide .cta { flex: 1 1 100%; }
  .so-modal-acts.split { flex-wrap: wrap; }
  .so-modal-acts.split .so-btn { flex: 1; justify-content: center; }
}

/* ══ print — the drawer alone ══════════════════════════════════════════════ */

/* Locked decision 10: a print stylesheet only, printing the drawer's contents. No CSV export in
   Phase 1 — a supplier phone call that ends in "can you send that through" is answered by Print. */
@media print {
  .so-appbar, .so-side, .so-scrim, .so-pager, .so-drawer .dclose, #blazor-error-ui { display: none !important; }

  body, .so-shell, .so-main, .so-page { display: block; background: #fff; height: auto; }

  /* With a drawer open, the order IS the document: the list behind it is not what was asked for. */
  .so-page:has(.so-drawer) > *:not(.so-drawer) { display: none !important; }

  .so-drawer {
    position: static; width: auto; max-width: none; inset: auto;
    border: none; box-shadow: none; overflow: visible; padding: 0; animation: none;
  }
  .so-drawer .dtot { margin-top: 24px; }
  .so-tbl, .so-dtbl { border-color: #ccc; }
}

/* ══ Blazor's own furniture ════════════════════════════════════════════════ */

#blazor-error-ui {
  background: var(--so-amber-bg); color: var(--so-amber-ink);
  bottom: 0; display: none; left: 0; padding: 12px 18px; position: fixed;
  width: 100%; z-index: 1000; font-size: 13.5px; font-weight: 700;
  box-shadow: 0 -2px 12px rgba(0, 0, 0, .2);
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: 16px; top: 12px; }

.loading-progress { position: relative; display: block; width: 8rem; height: 8rem; margin: 20vh auto 1rem; }
.loading-progress circle { fill: none; stroke: var(--so-line); stroke-width: .6rem; transform-origin: 50% 50%; transform: rotate(-90deg); }
.loading-progress circle:last-child {
  stroke: var(--so-primary);
  stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 2) 500%;
  transition: stroke-dasharray .05s ease-in-out;
}
.loading-progress-text { position: absolute; text-align: center; font-weight: 700; inset: calc(20vh + 3.25rem) 0 auto 0; color: var(--so-lab); }
.loading-progress-text:after { content: var(--blazor-load-percentage-text, "Loading"); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   CP-1046 — the Orders table and the order drawer, per the app-wide redesign Ro approved on
   21 September 2026 (AI_Docs/diagnosis/overview-redesign/app-redesign.html, screen 6).

   Scoped on purpose. Nothing below redefines a :root token and nothing below reaches a screen
   other than Orders and the drawer: `.so-dtbl.fill` is the orders table alone (settings' run
   history uses bare `.so-dtbl`), `.so-h2.sec` is opt-in, and the rest is under `.so-drawer`.
   The one shared rule is `.so-stat`, which is the point of the pass — the stat row is ONE
   component and the drawer, the list and the sent dialog must not be able to drift apart again.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── the stat row, matched to the mock ───────────────────────────────────────────────────────
   Label and value left-aligned and 24px, as the mock draws it on all three surfaces. Right-
   aligning a label above a left-hand value was the reason the four cells read as four unrelated
   figures instead of one row. The numbers stay tabular so they line up down the row. */
.so-stat { padding: 13px 18px; }
.so-stat .k { font-size: 10.5px; letter-spacing: .09em; text-align: left; }
.so-stat .v { font-size: 24px; text-align: left; margin-top: 5px; line-height: 1.15; letter-spacing: -.02em; }
/* The optional line under a value: "against normal cost", "on this page". It carries the caveat
   that would otherwise make the label above it a lie. */
.so-stat .s { font-size: 12px; color: var(--so-lab); font-weight: 600; margin-top: 3px; }

/* ── section heading: 16px in ink ────────────────────────────────────────────────────────────
   Rule 1 gives the app a Section step it was missing, which is why headings borrowed the tab
   style; rule 7 says orange means "act" and nothing else. Opt-in modifier rather than a change
   to `.so-h2`, because the other screens carrying that class belong to other tickets. */
.so-h2.sec {
  font-size: 16px; font-weight: 800; color: var(--so-ink);
  padding-bottom: 0; border-bottom: none; letter-spacing: -.01em;
}

/* ── the orders table: one density ───────────────────────────────────────────────────────────
   Rule 5 — micro-caps header on the sidebar tint, 14px rows, hairline separators, hover tint,
   numbers right-aligned and tabular, chevron on any row that opens something. The first four
   already held; these are the row padding and the header tracking. */
.so-dtbl.fill th { letter-spacing: .09em; padding: 11px 14px; }
.so-dtbl.fill td { padding: 14px; }
.so-dtbl.fill tbody tr.skel td { padding: 18px 14px; }
/* A stat row now sits above the table, so the scroll box that keeps the pager on screen has more
   chrome above it to allow for. */
.so-dtbl.fill { max-height: calc(100vh - 404px); }

/* The reference cell of an order the supplier has not confirmed. Inert grey, not amber: CP-1046
   moved that doubt into the status chip, and two amber signals for one fact read as two facts. */
.mutedink { color: var(--so-lab); }

/* ── the drawer footer ───────────────────────────────────────────────────────────────────────
   Our own reference on the left as labelled meta, the actions on the right with one of them
   carrying the weight. The key used to sit bare and unlabelled at the bottom of the body, where
   "14-96-6529-1" is indistinguishable from a debug artefact. */
.so-dwr-foot { justify-content: flex-start; align-items: center; }
.so-dwr-foot .acts { margin-left: auto; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.so-dwr-ourref {
  font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
  color: var(--so-lab); display: inline-flex; align-items: baseline; gap: 6px; min-width: 0;
}
.so-dwr-ourref .so-mono { font-size: 12px; text-transform: none; letter-spacing: 0; overflow-wrap: anywhere; }

/* Below 1000px the drawer is full width and the reference would push the actions off the edge,
   so the two stack and the actions keep the full row. */
@media (max-width: 999px) {
  .so-dwr-foot { flex-wrap: wrap; gap: 10px; }
  .so-dwr-foot .acts { margin-left: 0; width: 100%; justify-content: flex-end; }
}
/* ══ CP-1044 — Settings design pass, per the approved app redesign ═════════════════════════════

   Scoped to `.so-settings` on purpose. The same defects (a glyph for an icon, a washed-out brand
   disabled state, orange spent on things that are not actions) exist on sibling screens, and each
   of those screens has its own ticket and its own PR. A global rewrite here would land three
   people's work inside one diff and merge-conflict with all of them, so nothing below can reach a
   screen this ticket does not own. NO :root token is touched — those belong to CP-1042.
   ════════════════════════════════════════════════════════════════════════════════════════════ */

/* A real icon, not a font's best guess. `<span class="ti">i</span>` rendered as a bare, floating
   inverted exclamation mark on Thresholds, Exclusions and Schedule — a dot over a stem with no
   shape around it reads as a missing glyph, because that is what it looks like. */
.so-bi {
  flex: none; width: 18px; height: 18px; border-radius: 999px;
  display: grid; place-items: center; margin-top: 1px;
  background: currentColor; font-size: 11px; font-weight: 800; line-height: 1;
}
.so-bi > span { color: var(--so-card); }

/* ── rule 3 · card grammar: every tab's content lives on a card, like Orders and Draft ── */
.so-settings .so-pane { padding: 0; display: flex; flex-direction: column; }
.so-settings .so-pane > .so-grid2,
.so-settings .so-pane > .so-sched,
.so-settings .so-pane > .so-excl,
.so-settings .so-pane > .so-runs { padding: 18px 20px; }
.so-settings .so-pane > .so-banner { margin: 0 20px 18px; }

/* ── rule 1 · the missing 16/800 section step. Headings stop borrowing the tab style. ── */
.so-pane-head {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 20px; border-bottom: 1px solid var(--so-line2);
}
.so-pane-head .t { font-size: 16px; font-weight: 800; color: var(--so-ink); }
.so-pane-head .r { margin-left: auto; font-size: 12px; font-weight: 700; color: var(--so-lab); }

/* ── rule 2 · spacing rhythm: 22 between sections, 14 inside a group, 10 inside a row ── */
.so-settings .so-grid2 { gap: 22px 28px; }
.so-settings .so-sched { gap: 22px; }
.so-settings .so-excl { gap: 14px; }
.so-settings .so-excl-acts { gap: 10px; }
.so-settings .so-days { gap: 10px; }
.so-settings .so-runs { gap: 14px; }

/* ── rule 7 · orange means "act". A tab is a place, not an action, so its underline is ink. ── */
.so-settings .so-tabs button.on { color: var(--so-ink); border-bottom-color: var(--so-ink); }
.so-settings .so-tabs button:focus-visible { outline-color: var(--so-primary); }

/* Selection is a state, not an action: Mon and Wed were the loudest things on the Schedule tab,
   louder than the Save button they exist to feed. */
.so-settings .so-day { border-radius: 999px; padding: 8px 15px; }
.so-settings .so-day.on {
  background: var(--so-ink); border-color: transparent; color: var(--so-card);
}

/* The page number is a label for where you are, not a button to press. */
.so-settings .so-pgb.on {
  background: var(--so-side); border-color: var(--so-line); color: var(--so-ink);
}

/* ── rule 9 · disabled is neutral grey, never a pale tint of the brand ──
   A 45%-opacity orange fill with white text reads as "click me, I think" and fails 4.5:1 twice
   over. The one control whose whole job is to say "there is nothing to save" now says it. */
.so-settings .so-btn.p[disabled],
.so-settings .so-btn.o[disabled],
.so-settings .so-btn.g[disabled] {
  opacity: 1; cursor: not-allowed;
  background: var(--so-line2); color: var(--so-body); border-color: transparent;
}
.so-settings .so-btn.p[disabled]:hover,
.so-settings .so-btn.o[disabled]:hover,
.so-settings .so-btn.g[disabled]:hover { background: var(--so-line2); color: var(--so-body); }

/* One decision card, one primary: the stick bar is the only place a filled button appears. */
.so-settings .so-stick { gap: 14px; padding: 12px 16px; }
.so-settings .so-stick .acts { gap: 10px; }

/* ── rule 5 · run history joins the one table density ── */
.so-settings .so-dtbl { border: none; border-radius: 0; }
.so-settings .so-dtbl th {
  letter-spacing: .09em; padding: 11px 14px;
}
.so-settings .so-dtbl td { padding: 14px; }
.so-settings .so-dtbl td .sub { font-size: 11.5px; }
.so-settings .so-pager { border-top: none; padding-top: 0; }

/* The exclusions grid sits inside the card now, so it drops its own outer chrome. */
.so-settings .so-pane .so-tbl { border-left: none; border-right: none; border-radius: 0; }
.so-settings .so-pane .so-tbl:first-child { border-top: none; }

/* ── rule 9 · destructive is red-soft and never the brand primary ──
   "Throw them away" is the one irreversible button on this screen. */
.so-settings-modal .so-btn.p { background: var(--so-red-bg); color: var(--so-red-ink); }
.so-settings-modal .so-btn.p:hover { background: var(--so-red-bg); filter: brightness(.96); }

/* Rule 8 moved Draft from a blue chip to a grey one, and grey is `--so-lab` on `--so-line2`,
   which measures 4.22:1 in dark mode — the chip would have been the one thing this pass made
   WORSE. Body ink keeps it reading as inert and clears the floor: 6.68:1 light, 5.87:1 dark. */
.so-settings .so-chip.mute { color: var(--so-body); }
