/* ============================================================================
   taliscon-stock.css — Taliscon Stock (Surgical Holdings) blue design language.
   Change log (append-only; DD/MM/YYYY<tab>Initials<tab>what):
   14/06/2026  CM  Grid Select column as a .tgl toggle (Stock Registry, VB6 parity): centre the switch in
                   .sel-cell + a touch-friendly tap target (.sel-cell .tgl padding) in the coarse-pointer block.
   14/06/2026  CM  Sortable-grid header styling (.sortable-grid thead th): clickable cursor + hover +
                   asc/desc arrow indicator for the shared client-side column sort (tspSortableGrid).
   14/06/2026  CM  Modal required-field pill styling (.req-modal-wrap / .required-popover.req-up):
                   anchors the self-wiring tspModalRequired pill left of the modal footer buttons and
                   opens its popover UPWARD so it is not clipped off the bottom of the modal (header-
                   fallback variant .on-head opens downward). Reuses the existing .required-pill /
                   .required-popover visuals.
   14/06/2026  CM  Stock Registry "collapsed panels" UAT fix: pinned the registry's direct-child
                   .form-section panels (Search criteria + Display) to flex:none. They are direct flex
                   children of .content.single (display:flex;flex-direction:column) and, lacking an
                   explicit flex rule, defaulted to flex:0 1 auto — so once the toolbar + 2 sections +
                   grid-card exceeded the viewport, the flex algorithm SHRANK the sections and their
                   own overflow:hidden CLIPPED the bodies, leaving only the header bars ("collapsed"
                   look). The grid-card already takes the remaining space (flex:1 1 auto). Mirrors the
                   Worksheet/Registry inline .form-section{flex:0 0 auto} fix + the flex:none already
                   applied to the .reg-toolbar/.action-bar siblings.
   14/06/2026  CM  VIEW-mode required suppression: a [data-req-suppress] subtree (e.g. a line editor in
                   read-only / VIEW mode) now shows NO required indication — the faded-red [data-required]
                   left edge is restored to the normal 1px border and the * markers are hidden. Pairs
                   with the taliscon-stock.js painter (clears .req-invalid/.req-valid) so the whole
                   required UX is dormant until the user starts a New / Modify. Fixes "we're locked but
                   the fields still show the red left border / required" on SO Items.
   13/06/2026  CM  TABLET / TOUCH pass (warehouse-floor iPad usability): added a single comprehensive
                   @media (hover:none) and (pointer:coarse) block at the END of this file (search
                   "TABLET / TOUCH TARGET PASS") that lifts standalone tap targets to the 44px WCAG
                   minimum (.btn / .icon-circle / .row-kebab incl. the bottom-card kebab / .modal-x /
                   banner help+theme+user+signout), enlarges grid checkboxes + their cells, grows in-cell
                   editors 28px->40px, stacks modal-foot buttons full-width, and fattens kebab menu items.
                   Uses min-width/min-height so it clamps UP over the existing fixed width/height rules
                   (incl. the more-specific .bc-kebab .row-kebab) without a specificity fight. Additive
                   only — desktop (fine-pointer) is untouched.
   31/05/2026  CM  Required-field system polish for the shared tspRequired engine: (a) restyled the
                   canonical .required-pill into a proper, readable TOOLBAR pill (danger-soft fill +
                   solid border, nowrap, a touch wider) so "N required" / green "All required complete"
                   read clearly — every StockPortal pill sits in a page toolbar, never the banner, so
                   the old translucent-white-on-white look was the "pill looks odd" report; (b) added
                   .req-group-invalid for required checkbox SETs ([data-required-group]). The three
                   field states (.req / [data-required] left edge / .req-invalid / .req-valid) were
                   already present and are unchanged.
   29/05/2026  CM  Goods-In fixes batch: (a) shared app-modal styling (.modal-window.modal-sm +
                   .app-modal-body) for the new appAlert/appConfirm helper — compact, inherits the
                   responsive full-screen breakpoints; (b) items-table inline-input restyle so the
                   Receive-now qty + Line-comment fields match the app-standard .field-group input
                   look (border/radius/focus-ring/readonly/required-invalid). See the rules near the
                   .modal-confirm block.
   28/05/2026  CM  Sales Order Control fixes batch:
                   FIX 3 — portrait/narrow (<=900px) vertical-scroll fix: the so-control
                           shell now lays its single-column reflow out at intrinsic height
                           (so-main + dual-grid + grid sections release overflow:hidden) so
                           the page scrolls as one document on iPad portrait / phones.
                           Landscape (>900px) keeps the 3-column internal-scroller layout.
                   FIX 4 — dark-mode selected-row contrast: extended the dark .is-selected
                           text override to the muted subtitle/comment, the <strong> customer
                           code and the gridcell-check dots, which previously stayed at their
                           dark base colour on the --sel fill and were hard to read.
   29/05/2026  CM  System-wide mobile document-scroll: under a touch/mobile + narrow/short
                   media-query list ((hover:none)+(pointer:coarse) OR max-width:900px OR
                   max-height:680px — the OR covers devtools emulation + small/short windows),
                   the whole .app/.app.module shell now DOCUMENT-scrolls instead of clipping.
                   html/body scroll; .app/.app.module -> min-height:auto + overflow:visible;
                   the inner scrollers (.content/.content.single/.content.so-control/.so-main/
                   .app-main/.form-pane(-grid)/.dual-grid/.grid-section/.gs-body/.stock-area +
                   the items editor side-panel chain) release overflow:hidden and their fixed/
                   flex (1fr / calc-vh) heights so the page flows + scrolls as one document.
                   Desktop (hover-capable, wide, tall) layout is untouched.
   29/05/2026  CM  Mobile-scroll: also release the relocated SO Items supplier grid
                   (.supplier-area, the full-width table under the Product card — caps at
                   230px/overflow:auto on desktop) so it flows into the single document scroll too.
   29/05/2026  CM  FIX (TASK E) — SO Items product-search dropdown scroll regression: the mobile
                   document-scroll media-query converts every editor ancestor (.editor-panel etc.)
                   to overflow:visible / document-scroll, which stripped the clipping/scroll context
                   the position:absolute .autocomplete-list relied on, so a touch drag over the
                   suggestions scrolled the PAGE not the list. Re-assert the list's OWN bounded
                   max-height:260px + overflow-y:auto inside the media query (high enough specificity
                   to win) with overscroll-behavior:contain so the gesture no longer chains to the
                   document. Desktop dropdown scroll (base .autocomplete-list rule) is unchanged.
   29/05/2026  CM  Breadcrumb trail: added .breadcrumb-bar / .breadcrumb styles (Talisman blue
                   links — --brand with #005A9E light / #4CC2FF dark literal fallbacks per
                   CLAUDE.md, muted-ink current crumb, chevron separators). The bar is a thin
                   flex:0 0 auto divider strip placed as the first child of .app-main, so it
                   costs no grid edits and flows naturally into the mobile document-scroll
                   (it is NOT in the overflow-releasing media-query list — a fixed-height
                   strip needs no release). overflow-x:auto + white-space:nowrap keep the
                   deepest (4-crumb) trail from wrapping on narrow widths.
   29/05/2026  CM  [#3] SO Items product-search dropdown scroll — root-cause fix: moved the
                   scroll-chaining containment (overscroll-behavior:contain + touch-action:pan-y
                   + -webkit-overflow-scrolling:touch, overflow:auto -> overflow-y:auto) onto the
                   BASE .autocomplete-list rule (~line 1434). The earlier fix lived only inside
                   the mobile media query, which a normal desktop browser never enters, so the
                   wheel/touch gesture chained to the page. The base rule now contains it on
                   desktop AND touch in one place (the media-query duplicate is now redundant but
                   left in place — harmless). Also released the new ~5-row line-grid height floor
                   inside that media query so it flows in the mobile document scroll.
   29/05/2026  CM  SO Control (+ shared browse layouts) horizontal-overflow fix — landscape
                   phones/tablets at ~932x430 (and narrower) sit BETWEEN the desktop layout
                   and the touch-only fixes, so the search toolbar, status tab strip and data
                   grids ran off the right edge unreachably. The three overflow fixes lived only
                   in the @media (hover:none)+(pointer:coarse) block (so a 932px mouse window got
                   none of them, and a 932px phone got too little). Added WIDTH-driven equivalents
                   under a new @media (max-width:1024px) block (+ a max-width:560px single-column
                   step): (1) .reg-toolbar .search-box flex-wraps to 50% with fluid date inputs
                   (beats inline width:130px) and #btnNewOrder unpins (beats inline margin-left:auto)
                   so it wraps; (2) .workflow-strip becomes a single-row nowrap horizontal scroller;
                   (3) .gs-body keeps a horizontal scroller (overflow-x:auto !important) and the
                   bottom table swaps to the card view by width. ALSO split .gs-body out of the
                   document-scroll overflow:visible group so landscape (<=680 tall) releases only
                   the VERTICAL clip (overflow-y:visible) and keeps overflow-x:auto — otherwise it
                   stripped the new horizontal grid scroller. Desktop (>=1025px wide) is untouched.
   29/05/2026  CM  App-wide form-consistency pass (CSS half): (1) GENERALISED the in-grid/in-table/
                   in-modal input styling — extended the original Goods-In .items-table td input look
                   to ALSO cover .data-grid td and .sub-table td and to include <select>/<textarea>,
                   so every inline editor inside a line-item table, browse grid or modal table (e.g.
                   the PO "Receipt Supplier Invoice" modal's per-line Unit Price / VAT% inputs in
                   #poRiLines + its Postage/Packing tfoot inputs) inherits the app-standard border/
                   radius/focus-ring/readonly/disabled/.req-invalid + [data-required] left-border
                   WITHOUT per-view inline styles. Added in-cell select chevron, .numeric/.mono in-cell
                   helpers and .w-56/.w-64/.w-80/.w-96 width utilities. A
                   :not([type=checkbox]):not([type=radio]):not([type=hidden]) guard keeps row-select
                   checkboxes (.reg-sel/.proc-sel) + hidden fields at native size — no browse-grid
                   regression. (2) Base .field-group: added a :disabled state (mirrors [readonly]) so
                   permission-gated selects/inputs (e.g. Goods-In Shipment Rating) are on-theme.
                   (3) Required components robustness/responsive: generic .req asterisk (so the
                   `<span class="req">*</span>` marker styles outside a .field-group label too), a
                   <=520px viewport cap on .required-popover (was a fixed 460px panel that ran off a
                   phone edge) + body max-height clamp, and a coarse-pointer min-height on
                   .required-pill. Existing toggles/breadcrumb/autocomplete/mobile-scroll/SO-responsive/
                   modal rules untouched.
   29/05/2026  CM  SHARED UI foundation (3 parts, all at the END of the file under the
                   "SHARED UI FOUNDATION" banner):
                   (1) appMenu component styling — .app-action-menu (the viewport-aware popover) +
                       .app-menu-head / .app-menu-item (primary|danger|warn|is-disabled) /
                       .app-menu-divider, and the <=560px BOTTOM ACTION-SHEET variant
                       (.app-action-menu.as-sheet + .app-action-sheet-backdrop). Light + dark, built
                       from the same panel/line/brand tokens + shadow-lg as the legacy .row-ctx-menu it
                       generalises; the popover carries overflow-y:auto so a tall list scrolls inside
                       its JS-set max-height instead of clipping off the viewport top.
                   (2) App-wide status PILLS — generalised the SO Control pill family into reusable
                       .pill (base) + .pill-row (a horizontally-SCROLLING flex strip with
                       -webkit-overflow-scrolling for pill overflow) + intent variants (.pill-brand/
                       -ok/-warn/-danger/-grey/-purple) and the lifecycle .pill-s-<LETTER> set (aliases
                       of the existing .so-status.s-* colours). The legacy .status-pill / .so-status /
                       .workflow-strip rules are untouched — these are additive app-wide names.
                   (3) Dark-mode DATE INPUTS — added color-scheme:light to :root and color-scheme:dark
                       to :root[data-theme="dark"] (natively re-themes the native picker chrome +
                       placeholder), pinned ::-webkit-datetime-edit text to var(--ink) with placeholder
                       segments at var(--ink-4), and re-tinted the ::-webkit-calendar-picker-indicator
                       in dark mode (filter:invert, mirroring the select-chevron light/dark precedent)
                       so the calendar glyph reads on the dark field. Colour/appearance only — the
                       existing responsive width rule + box styling on date inputs are untouched.
   29/05/2026  CM  PO Control SO-Control-alignment pass: added the SELECTABLE pill-strip helpers
                   (.pill-row.pill-strip + .pill.pill-select with .ps-dot/.ps-count/.active + the
                   trailing .pill-state chip) so PO Control's status SELECTOR can be a horizontal
                   scrolling strip of the app-wide .pill/.pill-status pills (the SO Control
                   workflow-strip role) instead of the vertical .status-rail sidebar. Scoped to
                   .pill-select so static .pill badges are unaffected; reuses the existing
                   .so-control / .so-main / .dual-grid / .gs-* classes (no new layout classes) so
                   the shared responsive releases apply to PO Control for free.
   30/05/2026  CM  Shared LOADING OVERLAY — added .app-loading-overlay (a semi-transparent scrim
                   positioned over the .app-main / .content host, full-screen fallback) + a CSS
                   .app-loading-spinner ring, themed from the existing --panel/--brand/--line tokens
                   (works light + dark). Driven by window.loadingOverlay in taliscon-stock.js; shown
                   during slow navigational grid/page loads so a tab-switch delay gives visible
                   feedback. Sits at z-index 120 (above content/breadcrumb, below the modal scrim
                   z-150 and toasts z-300). See the rules at the end of this file.
   30/05/2026  CM  App-wide GRID CELL TRUNCATION — added the reusable .cell-clip utility (a td/th
                   that single-line truncates with an ellipsis: max-width:0 + white-space:nowrap +
                   overflow:hidden + text-overflow:ellipsis; callers may add an explicit inline
                   max-width). Paired with a ZERO-markup delegated cellTitle handler in
                   taliscon-stock.js that, on hover/focus of any clipped TD/TH in table.data-grid /
                   table.items-table, lazily sets title=full-text so the native tooltip shows the
                   whole value. Theme-agnostic. See the rule at the very end of this file.
   ============================================================================ */
:root[data-theme="light"], :root {
  --brand:#1565C4; --brand-deep:#0D4A9E; --brand-darker:#093776;
  --brand-soft:#E7F0FB; --brand-softer:#F4F8FD;
  --ink:#14202E; --ink-2:#2B3849; --ink-3:#566478; --ink-4:#8A96A8;
  --line:#E1E7EF; --line-2:#D0D8E3; --line-strong:#B4BECE;
  --bg:#F3F6FA; --panel:#FFFFFF; --panel-2:#FAFBFD; --panel-3:#EFF3F8;
  /* Selected row — warm yellow, per the mockup. --sel is the strong
     selected fill; --row-hover is a pale tint of the same warm family
     so hover feels like a softer version of selected. */
  --sel:#FFEDB5; --sel-border:#E8B923; --sel-text-dark:#7B5A0E; --row-hover:#FFF8E1;
  --ok:#1E7F3F; --ok-soft:#E5F4EB;
  --warn:#B7791F; --warn-soft:#FCF3E1;
  --danger:#C0392B; --danger-soft:#F7E2DF;
  --banner-bg:#F7E2DF; --banner-text:#B22F22; --banner-border:#EFCAC4;
  --purple:#6D28D9; --purple-soft:#EDE9FE;
  --shadow-sm:0 1px 2px rgba(13,74,158,.05),0 1px 1px rgba(13,74,158,.04);
  --shadow-md:0 6px 16px rgba(13,74,158,.08),0 2px 4px rgba(13,74,158,.05);
  --shadow-lg:0 18px 50px rgba(13,74,158,.16),0 6px 16px rgba(13,74,158,.10);
  --shadow-modal:0 32px 64px rgba(8,30,60,.32),0 12px 32px rgba(8,30,60,.16);
  --r-sm:4px; --r-md:6px; --r-lg:10px;
  --font-ui:'Manrope',-apple-system,'Segoe UI',sans-serif;
  /* 14/06/2026 CM — codes/refs/catalogue numbers were 'DM Mono', which read as an "odd font". Point
     --font-mono at the same Manrope stack as the UI/number fonts so every code matches the rest of the
     app for clarity. The grids that need digit alignment already apply tabular-nums, so columns stay
     aligned without a true monospace face. (Hard-coded 'DM Mono' in the PDF signature block is left.) */
  --font-mono:'Manrope',-apple-system,'Segoe UI',sans-serif;
  --font-num:'Manrope',-apple-system,'Segoe UI',sans-serif;
  --yellow-stripe:#F2C200;
  /* 29/05/2026  CM  Tell the UA to render native control chrome (date pickers, scrollbars,
     placeholder text) in the LIGHT palette — paired with the dark override below. */
  color-scheme:light;
}
:root[data-theme="dark"] {
  --brand:#4D8FE8; --brand-deep:#6AA3ED; --brand-darker:#1E3E73;
  --brand-soft:#1B2A47; --brand-softer:#141B2C;
  --ink:#E8EDF5; --ink-2:#C4CDDB; --ink-3:#8896AE; --ink-4:#5C6A82;
  --line:#2A3142; --line-2:#353D52; --line-strong:#4A5370;
  --bg:#0E1421; --panel:#181E2E; --panel-2:#1E2435; --panel-3:#242B3E;
  /* Dark mode keeps the warm-yellow row family — --sel is the strong
     warm-brown selected fill; --row-hover is a subtler warm tint that
     sits between panel and sel, so hover feels like a quiet preview of
     selected rather than a cool-blue jump. */
  --sel:#4A3A18; --sel-border:#C99818; --sel-text-dark:#FFDD7A; --row-hover:#2A2418;
  --ok:#3FB565; --ok-soft:rgba(63,181,101,.16);
  --warn:#E4A84F; --warn-soft:rgba(228,168,79,.16);
  --danger:#E67364; --danger-soft:rgba(230,115,100,.18);
  --banner-bg:rgba(230,115,100,.18); --banner-text:#E67364; --banner-border:rgba(230,115,100,.34);
  --purple:#C4B5FD; --purple-soft:rgba(196,181,253,.18);
  --shadow-sm:0 1px 2px rgba(0,0,0,.45);
  --shadow-md:0 6px 16px rgba(0,0,0,.4);
  --shadow-lg:0 18px 50px rgba(0,0,0,.55);
  --shadow-modal:0 32px 64px rgba(0,0,0,.7),0 12px 32px rgba(0,0,0,.45);
  /* 29/05/2026  CM  Native control chrome (date picker, placeholder, scrollbars) follows dark. */
  color-scheme:dark;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden}
/* Opt-in scroll mode for content-heavy pages (Help, future docs, long reports).
   Views set ViewBag.HtmlClass = "scrollable" in _Layout to enable. Releases
   the app-shell's fixed-viewport rules so the browser scrollbar handles
   overflow naturally — internal scrollers like .grid-wrap / .form-main are
   unaffected because they only exist on pages that DON'T set scrollable. */
html.scrollable,
html.scrollable body{height:auto;overflow:auto}
html.scrollable .app{height:auto;min-height:calc(100vh - 40px);overflow:visible}
html.scrollable .content{overflow:visible}
body{font-family:var(--font-ui);font-size:13px;color:var(--ink);
  background:
    radial-gradient(1400px 700px at 10% -10%, #DCE7F5 0%, transparent 60%),
    radial-gradient(1000px 500px at 100% 0%, #E5EEF9 0%, transparent 55%),
    var(--bg);
  padding:20px;-webkit-font-smoothing:antialiased;letter-spacing:-0.003em;font-feature-settings:"ss01","cv11"}
[data-theme="dark"] body{
  background:
    radial-gradient(1400px 700px at 10% -10%, rgba(30,55,105,.3) 0%, transparent 60%),
    radial-gradient(1000px 500px at 100% 0%, rgba(20,40,80,.3) 0%, transparent 55%),
    var(--bg);
}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
input,select,textarea{font:inherit;color:inherit}
/* Default theme-aware background for input controls that aren't styled by
   a more specific rule (eg inputs inside table cells, modal bodies, or
   inline strips). :where() keeps the selector specificity at 0,0,1 so
   any .field-group rule still wins where it applies. Checkbox/radio
   excluded — accent-color handles their dark-mode appearance. */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="file"])),
select,
textarea{background-color:var(--panel)}
[data-theme="dark"] input:where(:not([type="checkbox"]):not([type="radio"]):not([type="file"])),
[data-theme="dark"] select,
[data-theme="dark"] textarea{background-color:var(--panel-2)}
svg{display:block}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:5px}
::-webkit-scrollbar-thumb:hover{background:var(--ink-4)}

/* ============ App shell — centred card on the body backdrop ============ */
/* No max-width — this is a utility stock app, full-width helps wide grids
   and side-by-side form sections breathe. The soft-blue radial backdrop on
   <body> still shows in the 20px padding gutter so the "card on backdrop"
   idiom still reads. */
.app{display:grid;grid-template-rows:36px auto 1fr;height:calc(100vh - 40px);max-width:1565px;margin:0 auto;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);box-shadow:var(--shadow-md);overflow:hidden}
/* Module shell — titlebar / banner / (nav-rail | content) */
.app.module{grid-template-rows:36px auto 1fr;grid-template-columns:auto 1fr}
.app.module > .titlebar,
.app.module > .banner{grid-column:1 / -1}
.app.module > .nav-rail{grid-row:3;grid-column:1}
.app.module > .content{grid-row:3;grid-column:2}
/* Web port: _Layout renders every page inside .app-main, the single grid child of
   .app.module. The page's own .content.* (e.g. .content.so-control / .content.single)
   lives INSIDE this host and stretches to fill it. Keeping the host class != "content"
   avoids the ".app.module > .content" 3-column grid collapsing a page into 240px. */
.app.module > .app-main{grid-row:3;grid-column:2;min-width:0;min-height:0;overflow:hidden;display:flex;flex-direction:column}
.app.module > .app-main > .content{flex:1 1 auto;min-height:0}

/* Breadcrumb trail — sits as the FIRST child of .app-main, between .banner and the page
   content. A thin divider strip, not a panel. flex:0 0 auto so it costs only its own
   height and the content area (flex:1 1 auto) absorbs the rest — zero grid edits. Links in
   Talisman blue (--brand, with #005A9E light / #4CC2FF dark literal fallbacks per CLAUDE.md);
   current crumb in muted ink. overflow-x:auto + white-space:nowrap stop the deepest trail
   wrapping on narrow widths. On mobile the .app-main releases overflow:hidden and document-
   scrolls; this fixed-height strip just flows at the top, so it needs no media-query release. */
.breadcrumb-bar{flex:0 0 auto;background:var(--panel);border-bottom:1px solid var(--line);
  padding:7px 28px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.breadcrumb{display:flex;align-items:center;gap:6px;margin:0;padding:0;list-style:none;
  font-size:12.5px;line-height:1.2;white-space:nowrap}
.breadcrumb .crumb a{color:var(--brand,#005A9E);text-decoration:none;font-weight:600;
  padding:2px 4px;border-radius:4px;transition:background .15s,color .15s}
.breadcrumb .crumb a:hover{background:color-mix(in srgb,var(--brand,#005A9E) 12%,transparent);
  text-decoration:underline}
.breadcrumb .crumb.current span{color:var(--ink-3,#6b7280);font-weight:600}
.breadcrumb .crumb-sep{display:inline-flex;align-items:center;color:var(--ink-3,#9aa3af)}
.breadcrumb .crumb-sep svg{width:13px;height:13px}
[data-theme="dark"] .breadcrumb .crumb a{color:var(--brand,#4CC2FF)}
@media (max-width:560px){ .breadcrumb-bar{padding:6px 16px} .breadcrumb{font-size:12px} }

/* Titlebar */
.titlebar{display:flex;align-items:center;justify-content:space-between;padding:0 14px;background:linear-gradient(180deg,var(--brand-darker) 0%,#0A2F66 100%);color:#E8EEF6;font-size:12px;letter-spacing:0.02em}
[data-theme="dark"] .titlebar{background:linear-gradient(180deg,#0B1424 0%,#050B17 100%)}
.tb-left{display:flex;align-items:center;gap:10px}
.tb-icon{width:18px;height:18px;border-radius:3px;background:#fff;display:grid;place-items:center;color:var(--brand-deep);font-weight:800;font-size:10px}
.tb-title{font-weight:600;letter-spacing:.01em}
.tb-controls{display:flex;gap:8px}
.tb-controls span{width:12px;height:12px;border-radius:50%;background:#32496A;display:inline-block}
.tb-controls span:last-child{background:var(--brand)}

/* Banner — canonical SH banner gradient with yellow stripe */
.banner{display:flex;align-items:center;justify-content:space-between;padding:14px 28px 12px;background:linear-gradient(180deg,var(--brand) 0%,var(--brand-deep) 100%);color:#fff;position:relative;z-index:50}
[data-theme="dark"] .banner{background:linear-gradient(180deg,#1E4380 0%,#0F2855 100%)}
.banner::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;background:linear-gradient(90deg,var(--yellow-stripe) 0%,var(--yellow-stripe) 160px,transparent 160px)}
.brand{display:flex;align-items:center;gap:14px}
.brand-logo{width:38px;height:38px;border-radius:8px;background:#fff;display:grid;place-items:center;color:var(--brand-deep);font-weight:800;font-size:18px;letter-spacing:-0.02em;box-shadow:0 2px 6px rgba(0,0,0,.15)}
.brand-mark{font-weight:800;font-size:20px;letter-spacing:-0.015em;color:#fff;line-height:1}
.brand-mark .light{font-weight:400;color:#C5D7EE}
[data-theme="dark"] .brand-mark .light{color:#8FA8D1}
.brand-sub{font-size:10px;text-transform:uppercase;letter-spacing:0.18em;color:rgba(255,255,255,.75);margin-top:4px;font-weight:600}
[data-theme="dark"] .brand-sub{color:rgba(255,255,255,.65)}

/* Subbar — Log / Form switcher in its own strip below banner */
.subbar{display:flex;align-items:stretch;gap:0;background:var(--panel);border-bottom:1px solid var(--line);padding:0 22px}
.page-tabs{display:flex;gap:2px;align-items:stretch}
.page-tab{display:inline-flex;align-items:center;gap:7px;padding:11px 18px;font-size:12.5px;font-weight:600;color:var(--ink-3);border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;letter-spacing:-0.003em;transition:color .15s,border-color .15s}
.page-tab:hover{color:var(--ink)}
.page-tab.active{color:var(--brand);border-bottom-color:var(--brand);font-weight:700}
.page-tab svg{width:14px;height:14px}
.page-tab .count{font-size:10.5px;font-weight:700;padding:1px 7px;background:var(--panel-3);color:var(--ink-3);border-radius:9px;font-variant-numeric:tabular-nums}
.page-tab.active .count{background:var(--brand-soft);color:var(--brand-deep)}

.banner-meta{display:flex;align-items:center;gap:10px}

/* Required pill on banner */
.required-popover-wrap{position:relative}
.required-pill{display:inline-flex;align-items:center;gap:7px;padding:6px 14px;border-radius:14px;background:var(--danger-soft);border:1px solid var(--danger);color:var(--danger);font-size:12.5px;font-weight:700;cursor:pointer;letter-spacing:-0.003em;white-space:nowrap;min-height:30px}
.required-pill:hover{filter:brightness(.97)}
.required-pill svg{width:13px;height:13px;flex-shrink:0}
.required-pill .num{font-variant-numeric:tabular-nums}
.required-pill.clean{background:var(--ok-soft);border-color:var(--ok);color:var(--ok);cursor:default}
/* Required checkbox SET ([data-required-group]) flagged empty by the tspRequired engine. */
[data-required-group="true"].req-group-invalid{outline:1px dashed var(--danger);outline-offset:4px;border-radius:var(--r-sm)}

/* Theme toggle */
.theme-toggle{width:32px;height:32px;border-radius:999px;border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.14);color:#fff;display:inline-flex;align-items:center;justify-content:center;transition:background .2s,transform .2s;backdrop-filter:blur(4px)}
.theme-toggle:hover{background:rgba(255,255,255,.24);transform:scale(1.05)}
.theme-toggle svg{width:16px;height:16px}
.theme-toggle .sun{display:none}
[data-theme="dark"] .theme-toggle .sun{display:block}
[data-theme="dark"] .theme-toggle .moon{display:none}

/* User chip */
.user-chip{display:inline-flex;align-items:center;gap:8px;padding:4px 12px 4px 4px;border-radius:18px;background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);font-size:12px;font-weight:600;color:#fff;backdrop-filter:blur(4px)}
.user-chip .avatar{width:24px;height:24px;border-radius:50%;background:#fff;color:var(--brand-deep);display:grid;place-items:center;font-size:10.5px;font-weight:800}

/* Content */
.content{overflow:hidden;display:flex;flex-direction:column}
.tab-pane{display:none;height:100%}
.tab-pane.active{display:flex;flex-direction:column}

/* ============ Log toolbar ============ */
.log-toolbar{display:flex;align-items:center;gap:10px;padding:12px 18px;background:var(--panel);border-bottom:1px solid var(--line);flex-wrap:wrap}
.search-box{display:flex;align-items:center;gap:8px;flex:1;max-width:380px;height:32px;padding:0 12px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-sm);transition:border-color .15s,box-shadow .15s}
.search-box:focus-within{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.search-box svg{width:14px;height:14px;color:var(--ink-4);flex-shrink:0}
.search-box input{flex:1;height:100%;border:none;outline:none;background:transparent;font-size:12.5px;color:var(--ink)}

.chip-row{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.chip{display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 12px;background:var(--panel);border:1px solid var(--line-2);border-radius:14px;font-size:12px;font-weight:600;color:var(--ink-3);transition:all .12s;letter-spacing:-0.003em}
.chip:hover{background:var(--panel-3);color:var(--ink)}
.chip.active{background:var(--brand-soft);color:var(--brand-deep);border-color:var(--brand-soft)}
.chip .chip-count{font-variant-numeric:tabular-nums;font-size:10.5px;padding:1px 6px;border-radius:8px;background:var(--panel-3);color:var(--ink-3);font-weight:700}
.chip.active .chip-count{background:var(--brand);color:#fff}

.tb-divider{width:1px;height:20px;background:var(--line);margin:0 2px}

/* Buttons */
.btn{height:32px;padding:0 14px;border-radius:var(--r-md);font-size:12.5px;font-weight:600;display:inline-flex;align-items:center;gap:7px;white-space:nowrap;transition:background .14s,border-color .14s,color .14s;border:1px solid transparent;letter-spacing:-0.003em;text-decoration:none}
a.btn,a.btn:hover,a.btn:focus,a.btn:active,a.btn:visited{text-decoration:none}
a.icon-circle,a.icon-circle:hover,a.icon-circle:focus,a.icon-circle:visited{text-decoration:none}
a.chip,a.chip:hover,a.chip:focus,a.chip:visited{text-decoration:none}
.scar-ref a,.scar-ref a:hover,.scar-ref a:focus,.scar-ref a:visited{text-decoration:none}
a.page-tab,a.page-tab:hover,a.page-tab:focus,a.page-tab:visited{text-decoration:none}

/* ===== validation extras (live alongside the canonical .required-pill) ===== */
.field-grid input.is-invalid,.field-grid select.is-invalid,.field-grid textarea.is-invalid,
input.is-invalid,select.is-invalid,textarea.is-invalid{
  border-color:var(--danger) !important;
  background:var(--danger-soft) !important;
}
.field-grid input.is-invalid:focus,.field-grid select.is-invalid:focus,.field-grid textarea.is-invalid:focus{
  outline:none;box-shadow:0 0 0 3px rgba(192,57,43,.18);
}
.required-popover-body{padding:8px 0;max-height:320px;overflow:auto}
.required-popover-body .req-row{display:flex;align-items:center;gap:10px;padding:7px 14px;cursor:pointer;font-size:12.5px}
.required-popover-body .req-row:hover{background:var(--brand-softer);color:var(--brand-deep)}
.required-popover-body .req-row .num{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--danger-soft);color:var(--danger);font-size:11px;font-weight:800;font-variant-numeric:tabular-nums}
.required-popover-body .req-row .lbl{font-weight:600;color:var(--ink)}
.required-popover-body .req-empty{padding:14px;text-align:center;color:var(--ok);font-weight:600;font-size:12.5px}
.required-popover-header{display:flex;align-items:center;gap:10px;padding:12px 14px;background:var(--banner-bg);color:var(--banner-text);border-bottom:1px solid var(--banner-border);font-size:12.5px;font-weight:600}
.required-popover-header svg{width:14px;height:14px;flex-shrink:0}
.required-popover-header .msg{flex:1}
.required-popover-header .close-btn{background:transparent;border:none;cursor:pointer;color:var(--banner-text);padding:2px;display:grid;place-items:center;border-radius:3px}
.required-popover-header .close-btn:hover{background:rgba(0,0,0,.06)}
.required-popover-header .close-btn svg{width:12px;height:12px}
.required-popover-footer{display:flex;justify-content:space-between;padding:8px 14px;background:var(--panel-3);border-top:1px solid var(--line);font-size:10.5px;color:var(--ink-3)}

@keyframes reqPillShake { 0%,100%{transform:none} 25%{transform:translateX(-3px)} 75%{transform:translateX(3px)} }
.required-pill.shake{animation:reqPillShake .35s ease-in-out 2}

/* ===== Pills sized up ~2px (padding + font) so they read better in
       audit / activity / registry. Overrides the canonical 11px/3-9 padding. ===== */
.status-pill{font-size:13px;padding:5px 12px;gap:7px}
.status-pill > .dot{width:7px;height:7px}

/* Purple pill variant (used for ACTIVITY rows in the audit Kind column). */
.status-pill.purple{background:var(--purple-soft);color:var(--purple)}

/* ===== Audit / activity "Who" cell — initials avatar + name ===== */
.who-cell{display:inline-flex;align-items:center;gap:9px;min-width:0}
.who-cell .who-name{font-weight:600;color:var(--ink);letter-spacing:-0.003em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.audit-av{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:28px;height:28px;padding:0 8px;border-radius:14px;
  background:var(--brand);color:#fff;font-size:11px;font-weight:800;
  letter-spacing:0.04em;flex-shrink:0;line-height:1;font-variant-numeric:tabular-nums;
  box-shadow:0 1px 2px rgba(13,74,158,.18);
}
.audit-av.brand  {background:var(--brand);   color:#fff}
.audit-av.purple {background:var(--purple);  color:#fff}
.audit-av.ok     {background:var(--ok);      color:#fff}
.audit-av.warn   {background:var(--warn);    color:#fff}
.audit-av.danger {background:var(--danger);  color:#fff}
.audit-av.sys    {background:var(--panel-3); color:var(--ink-3); border:1px solid var(--line); box-shadow:none}
.audit-av.sys svg{width:14px;height:14px}

[data-theme="dark"] .audit-av{box-shadow:0 1px 2px rgba(0,0,0,.4)}
[data-theme="dark"] .audit-av.sys{background:var(--panel-2);color:var(--ink-3);border-color:var(--line-2)}

/* Timeline grid: let the avatar column grow with the initials width. */
.tl-item{grid-template-columns:auto 1fr !important;align-items:start}

/* Bump audit-kind pill to match the +2px size on .status-pill so the two
   columns look proportional. Canonical mockup style otherwise. */
.audit-kind{font-size:12px;padding:4px 10px;border-radius:10px;letter-spacing:0.08em;display:inline-flex;align-items:center;gap:6px;text-transform:uppercase;font-weight:700;line-height:1.4;white-space:nowrap}
.audit-kind::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block;flex-shrink:0}

/* Force the colour on each variant (high specificity so nothing wins over). */
.audit-kind.audit-kind-workflow{background:var(--brand-soft) !important;color:var(--brand-deep) !important}
.audit-kind.audit-kind-activity{background:var(--purple-soft) !important;color:var(--purple) !important}
.audit-kind.audit-kind-system  {background:var(--panel-3)   !important;color:var(--ink-3)      !important;border:1px solid var(--line)}

/* ===== Semantic status-pill variants — the canonical CSS only ships
       intent-specific names (.awaiting, .effectiveness, .closed, etc.).
       Our DB pill_colour column stores semantic tokens, so add those too. ===== */
.status-pill.brand   {background:var(--brand-soft); color:var(--brand-deep)}
.status-pill.ok      {background:var(--ok-soft);    color:var(--ok)}
.status-pill.warn    {background:var(--warn-soft);  color:var(--warn)}
.status-pill.danger  {background:var(--danger-soft);color:var(--danger)}
.status-pill.sel     {background:var(--sel);        color:var(--sel-text-dark)}
.status-pill.grey    {background:var(--panel-3);    color:var(--ink-3); border:1px solid var(--line)}
.status-pill.grey::before{background:var(--ink-4)}

/* Friendly colour palette exposed by the Definitions colour picker.
   Soft-bg + darker-text pattern matches the rest of the pill set.
   "red/orange/green/blue" map onto the same visual as danger/warn/ok/brand
   so adding a "red" pill looks identical to the legacy "danger" pill —
   we keep both rules so historical Pill_Colour values keep rendering. */
.status-pill.red          {background:var(--danger-soft);color:var(--danger)}
.status-pill.light-red    {background:#FEE2E2;            color:#B91C1C}
.status-pill.dark-red     {background:#DC2626;            color:#FFFFFF}
.status-pill.orange       {background:var(--warn-soft);  color:var(--warn)}
.status-pill.yellow       {background:#FEF3C7;            color:#92400E}
.status-pill.green        {background:var(--ok-soft);    color:var(--ok)}
.status-pill.blue         {background:var(--brand-soft); color:var(--brand-deep)}
.status-pill.light-blue   {background:#DBEAFE;            color:#1D4ED8}
.status-pill.dark-blue    {background:#1E3A8A;            color:#FFFFFF}
.status-pill.pink         {background:#FCE7F3;            color:#BE185D}
.status-pill.none         {background:transparent;        color:var(--ink-4); border:1px dashed var(--line-strong)}
.status-pill.none::before {background:var(--ink-4)}

/* Our pills wrap a <span class="dot"> rather than using ::before — hide ::before
   when we're providing our own dot to avoid the double-dot. */
.status-pill > .dot{width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block}
.status-pill:has(> .dot)::before{display:none}

/* ===== User menu — force solid background (parent .user-chip has translucent
       background + backdrop-filter which bleeds through the dropdown) ===== */
.user-menu{background:#FFFFFF !important;backdrop-filter:none !important;-webkit-backdrop-filter:none !important}
.user-menu .um-header{background:#FFFFFF}
.user-menu .um-item{background:#FFFFFF}
.user-menu .um-item:hover{background:var(--brand-soft)}
.user-menu .um-item.danger:hover{background:var(--danger-soft)}
[data-theme="dark"] .user-menu{background:var(--panel) !important}
[data-theme="dark"] .user-menu .um-header,
[data-theme="dark"] .user-menu .um-item{background:var(--panel)}
[data-theme="dark"] .user-menu .um-item:hover{background:var(--brand-soft)}
[data-theme="dark"] .user-menu .um-item.danger:hover{background:var(--danger-soft)}

/* ===== Workflow colour tuning to match SCAR mockup ===== */
/* Pending step names stay bold/ink-coloured (visual distinction is the dot, not the text). */
.workflow li.pending .step-name{color:var(--ink);font-weight:700}
.workflow li.pending .step-meta{color:var(--ink-4)}
.workflow li.active .step-name{color:var(--ink);font-weight:700}
.workflow li.active .step-meta{color:var(--ink-3)}
.workflow li.done .step-name{color:var(--ink-3);font-weight:600}
.workflow li.done .step-meta{color:var(--ink-4)}
.workflow li.blocked .step-name{color:var(--ink);font-weight:700}
.workflow li.blocked .step-meta{color:var(--warn);font-weight:600}
.btn svg{width:14px;height:14px;flex-shrink:0}
.btn-primary{background:var(--brand);color:#fff}
.btn-primary:hover{background:var(--brand-deep)}
.btn-secondary{background:var(--panel);border-color:var(--line-2);color:var(--ink)}
.btn-secondary:hover{background:var(--panel-3);border-color:var(--line-strong)}
.btn-ghost{background:transparent;border-color:var(--brand);color:var(--brand-deep)}
.btn-ghost:hover{background:var(--brand-soft)}
.btn-danger{background:var(--danger);color:#fff}
.btn-danger:hover{filter:brightness(0.92)}
.btn:disabled{opacity:0.55;cursor:not-allowed}

.icon-circle{width:32px;height:32px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;color:var(--ink-3);background:transparent;transition:background .12s,color .12s;flex-shrink:0}
.icon-circle:hover{background:var(--panel-3);color:var(--ink)}
.icon-circle svg{width:16px;height:16px}

/* ============ Data grid ============ */
.grid-wrap{flex:1;overflow:auto;background:var(--panel);margin:12px 18px 18px;border:1px solid var(--line);border-radius:var(--r-md);box-shadow:var(--shadow-sm)}
table.data-grid{width:100%;border-collapse:collapse;font-size:12.5px}
table.data-grid thead th{position:sticky;top:0;z-index:2;text-align:left;padding:9px 14px;background:var(--brand-softer);border-bottom:1px solid var(--line);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--brand-deep);white-space:nowrap}
table.data-grid thead th.sortable{cursor:pointer;user-select:none;transition:background .12s,color .12s}
table.data-grid thead th.sortable:hover{background:var(--brand-soft);color:var(--brand-deep)}
table.data-grid thead th.sortable .sort-arrow{display:inline-block;margin-left:5px;font-size:9px;opacity:0.32;line-height:1;vertical-align:middle;transition:opacity .12s,transform .12s;font-feature-settings:"tnum" 1}
table.data-grid thead th.sortable:hover .sort-arrow{opacity:0.65}
table.data-grid thead th.sortable.sort-asc .sort-arrow,
table.data-grid thead th.sortable.sort-desc .sort-arrow{opacity:1;color:var(--brand)}
table.data-grid thead th.sortable.sort-asc .sort-arrow::before{content:"\25B2"}
table.data-grid thead th.sortable.sort-desc .sort-arrow::before{content:"\25BC"}
table.data-grid thead th.sortable:not(.sort-asc):not(.sort-desc) .sort-arrow::before{content:"\21C5"}
table.data-grid tbody tr{border-bottom:1px solid var(--line);transition:background .1s;cursor:pointer}
/* Hover + selected are deliberately warm-yellow per the mockup palette
   (see top of mockup-reference.js: "brand #1565C4 + warm-yellow sel").
   --row-hover is a pale tint of the same family as --sel so hovering and
   selecting feel like the same visual gesture at different intensities. */
table.data-grid tbody tr:hover:not(.is-selected){background:var(--row-hover)}
table.data-grid tbody tr.is-selected{background:var(--sel)}
table.data-grid tbody tr.is-selected td{border-bottom-color:var(--sel-border)}
table.data-grid tbody tr.is-selected td:first-child{box-shadow:inset 3px 0 0 var(--brand)}
/* Dark-mode warm-yellow selected text (canonical SH override).
   FIX 4 (28/05/2026 CM): the previous override only recoloured the plain td +
   num/scar-ref/mono/dim cells, so SECONDARY text inside a selected row — the muted
   customer-name subtitle / comment (.muted = --ink-4), the <strong> customer code, and
   the Urgent/Modified/Postage dots (td.gridcell-check, which sets its own --ink-4 /
   --ok colour) — stayed at their dark base colour and were barely legible on the
   dark-brown --sel fill (the contrast the user reported). Force ALL text inside a
   selected row to the readable warm-cream ink, with the brighter gold reserved for the
   numeric/ref/strong emphasis cells. Light mode is untouched (its selected text reads
   fine against the pale-gold --sel). */
[data-theme="dark"] table.data-grid tbody tr.is-selected,
[data-theme="dark"] table.data-grid tbody tr.is-selected td,
[data-theme="dark"] table.data-grid tbody tr.is-selected td .muted,
[data-theme="dark"] table.data-grid tbody tr.is-selected td .clip,
[data-theme="dark"] table.data-grid tbody tr.is-selected td span{color:#F9E7B8}
[data-theme="dark"] table.data-grid tbody tr.is-selected td.num,
[data-theme="dark"] table.data-grid tbody tr.is-selected td.scar-ref,
[data-theme="dark"] table.data-grid tbody tr.is-selected td strong{color:#FFDD7A}
[data-theme="dark"] table.data-grid tbody tr.is-selected td.mono{color:#F9E7B8}
[data-theme="dark"] table.data-grid tbody tr.is-selected td.dim{color:#D6BD7B}
/* The Urgent/Modified/Postage check cells colour themselves via .yes (--ok) / .no
   (--ink-4); both lose contrast on the selection fill, so override them to the same
   warm-cream so the dot/glyph stays visible when the row is selected. */
[data-theme="dark"] table.data-grid tbody tr.is-selected td.gridcell-check,
[data-theme="dark"] table.data-grid tbody tr.is-selected td.gridcell-check.yes,
[data-theme="dark"] table.data-grid tbody tr.is-selected td.gridcell-check.no{color:#FFDD7A}
table.data-grid tbody td{padding:7px 14px;vertical-align:middle;color:var(--ink-2)}
/* 14/06/2026	CM	tfoot cells had NO padding rule (only `tbody td` set 7px 14px), so totals /
   Postage-Packing footer rows fell back to the browser default ~0 padding and read as cramped +
   mis-aligned with the columns above. Match the tbody horizontal padding (footer inputs now line
   up under their headers), add a little vertical room, and a divider to separate the totals row. */
table.data-grid tfoot td{padding:10px 14px;vertical-align:middle;color:var(--ink-2);border-top:1px solid var(--line-strong)}
table.data-grid tbody td.mono{font-family:var(--font-mono);font-size:11.5px;font-variant-numeric:tabular-nums;letter-spacing:-0.02em;white-space:nowrap;color:var(--ink)}
table.data-grid tbody td.dim{color:var(--ink-3)}
table.data-grid tbody td.num{font-family:var(--font-num);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;text-align:right;font-weight:500;color:var(--ink)}
table.data-grid tbody td.actions{text-align:right;white-space:nowrap}
table.data-grid tbody td.actions .icon-circle{width:26px;height:26px}
table.data-grid tbody td.actions .icon-circle svg{width:13px;height:13px}
table.data-grid tbody td .clip{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;max-width:360px;line-height:1.35}

/* SO-style ref in first column */
table.data-grid tbody td.scar-ref{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--brand);letter-spacing:-0.02em}

/* Thumb column */
.thumb-cell{padding:5px 8px !important;width:46px}
.thumb-mini{width:34px;height:34px;border-radius:var(--r-sm);overflow:hidden;background:var(--panel-3);border:1px solid var(--line);display:grid;place-items:center;position:relative;transition:transform .1s,box-shadow .1s}
.thumb-mini:hover{transform:scale(1.4) translateX(8px);box-shadow:var(--shadow-lg);z-index:5;position:relative}
.thumb-mini.empty{color:var(--ink-4)}
.thumb-mini.empty svg{width:14px;height:14px}
.thumb-mini svg.photo-svg{width:100%;height:100%}
.thumb-mini .multi-badge{position:absolute;bottom:-2px;right:-2px;min-width:14px;height:14px;border-radius:7px;background:var(--brand);color:#fff;font-size:9px;font-weight:700;display:grid;place-items:center;padding:0 3px;border:1.5px solid var(--panel);font-variant-numeric:tabular-nums}

/* Status pills */
.status-pill{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:11px;font-size:11px;font-weight:700;letter-spacing:0.02em;white-space:nowrap}
.status-pill::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor}
.status-pill.awaiting{background:var(--warn-soft);color:var(--warn)}
.status-pill.effectiveness{background:var(--brand-soft);color:var(--brand-deep)}
.status-pill.closed{background:var(--ok-soft);color:var(--ok)}
.status-pill.unsat{background:var(--danger-soft);color:var(--danger)}
.status-pill.draft{background:var(--panel-3);color:var(--ink-3);border:1px solid var(--line)}
.status-pill.draft::before{background:var(--ink-4)}

/* Complaint type chip */
.ctype-chip{display:inline-flex;align-items:center;padding:2px 8px;border-radius:10px;font-size:10.5px;font-weight:700;white-space:nowrap;background:var(--panel-3);border:1px solid var(--line);color:var(--ink-3);letter-spacing:0.01em}
.ctype-chip[data-t="Incorrect Part"]{background:var(--brand-soft);color:var(--brand-deep);border-color:transparent}
.ctype-chip[data-t="Incorrect Material"]{background:var(--brand-soft);color:var(--brand-deep);border-color:transparent}
.ctype-chip[data-t="Mechanical Defect"]{background:var(--danger-soft);color:var(--danger);border-color:transparent}
.ctype-chip[data-t="Dimensional Issue"]{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.ctype-chip[data-t="Damage"]{background:var(--danger-soft);color:var(--danger);border-color:transparent}
.ctype-chip[data-t="Cosmetic Defect"]{background:var(--ok-soft);color:var(--ok);border-color:transparent}

/* ============ Form pane ============ */
.form-pane-grid{display:grid;grid-template-columns:1fr 320px;gap:0;height:100%;overflow:hidden}
.form-main{overflow:auto;padding:16px 22px 28px}
.form-side{background:var(--panel-2);border-left:1px solid var(--line);overflow:auto;padding:16px}
.form-header{display:flex;align-items:center;gap:14px;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--line);flex-wrap:wrap}
.form-header h1{font-size:17px;font-weight:700;display:flex;align-items:center;gap:10px;flex-wrap:wrap;letter-spacing:-0.01em}
.form-header .scar-id{font-family:var(--font-mono);font-size:13.5px;font-weight:700;color:var(--brand);padding:3px 9px;background:var(--brand-soft);border-radius:var(--r-sm);letter-spacing:-0.02em}
.form-header-actions{margin-left:auto;display:flex;gap:8px}

/* Cards */
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-md);margin-bottom:12px;overflow:hidden;box-shadow:var(--shadow-sm)}
.card-head{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--brand-softer);border-bottom:1px solid var(--line);font-size:11px;font-weight:700;color:var(--brand-deep);text-transform:uppercase;letter-spacing:0.1em}
.card-head .card-icon{width:20px;height:20px;border-radius:var(--r-sm);background:var(--brand-soft);color:var(--brand-deep);display:grid;place-items:center}
.card-head .card-icon svg{width:12px;height:12px}
.card-head .card-counter{margin-left:auto;font-size:10.5px;color:var(--ink-4);font-weight:600;font-variant-numeric:tabular-nums;text-transform:none;letter-spacing:0}
.card-body{padding:14px 16px 16px}

/* Form grid */
.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 16px}
.field-grid.cols-3{grid-template-columns:1fr 1fr 1fr}
.field-grid .span-2{grid-column:span 2}
.field-grid .span-3{grid-column:1 / -1}
/* Field-group rhythm: 7px label-to-input internal gap, 22px between
   stacked field-groups (set on the parent grid below) so vertical rhythm
   reads as a consistent step rather than label-creeping-into-previous-input. */
.field-group{display:flex;flex-direction:column;gap:7px}
.field-group label{display:block;font-size:10.5px;font-weight:700;color:var(--ink-3);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:0}
.field-group label .req{color:var(--brand);margin-left:3px;font-weight:700}
.field-group label .hint{color:var(--ink-4);font-weight:400;text-transform:none;letter-spacing:0;margin-left:6px;font-size:10px}
.field-group input,.field-group select,.field-group textarea{width:100%;height:32px;padding:0 11px;border:1px solid var(--line-2);border-radius:var(--r-sm);background-color:var(--panel);font-size:12.5px;color:var(--ink);outline:none;transition:border-color .15s,box-shadow .15s;font-family:var(--font-ui)}
/* 14/06/2026 CM — multi-line text boxes are a minimum of 6 lines tall app-wide (was ~3-4 / 72px).
   ~6 lines = 6 x (12.5px x 1.45) + 16px vertical padding ~= 125px -> 132px. resize:vertical still
   lets the user grow them. A few textareas carry a smaller inline min-height; normalised below. */
.field-group textarea{height:auto;padding:8px 11px;min-height:132px;resize:vertical;line-height:1.45}
.field-group input:focus,.field-group select:focus,.field-group textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.field-group input[readonly],.field-group textarea[readonly]{background:var(--panel-3);color:var(--ink-3);cursor:not-allowed}
/* 29/05/2026  CM  Disabled state for the base field-group controls (selects/inputs that are
   permission-gated with `disabled`, e.g. Goods-In Shipment Rating) — mirror the readonly look so a
   disabled control is visibly inert + on-theme instead of the native greyed OS box. */
.field-group input:disabled,.field-group select:disabled,.field-group textarea:disabled{background:var(--panel-3);color:var(--ink-4);cursor:not-allowed;opacity:.75}
[data-theme="dark"] .field-group input,[data-theme="dark"] .field-group select,[data-theme="dark"] .field-group textarea{background-color:var(--panel-2)}
.field-group input.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums;letter-spacing:-0.02em}
.field-group input.numeric{font-family:var(--font-num);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;font-weight:500}
.field-group input[data-required="true"],.field-group select[data-required="true"],.field-group textarea[data-required="true"]{border-left-width:3px;border-left-color:rgba(192,57,43,0.32)}
[data-theme="dark"] .field-group input[data-required="true"],[data-theme="dark"] .field-group select[data-required="true"],[data-theme="dark"] .field-group textarea[data-required="true"]{border-left-color:rgba(230,115,100,0.45)}
.field-group input.req-invalid,.field-group textarea.req-invalid{border-color:var(--danger)!important;border-width:2px!important;border-left-width:4px!important;background-color:rgba(192,57,43,0.06)!important}
[data-theme="dark"] .field-group input.req-invalid,[data-theme="dark"] .field-group textarea.req-invalid{background-color:rgba(230,115,100,0.1)!important}
.field-group select.req-invalid{border-color:var(--danger)!important;border-width:2px!important;border-left-width:4px!important;background-color:rgba(192,57,43,0.05)!important}
.field-group input.req-valid,.field-group select.req-valid,.field-group textarea.req-valid{border-left-color:var(--ok);border-left-width:3px}
/* 14/06/2026  CM  A [data-req-suppress] subtree (a line editor in VIEW / read-only mode) shows NO
   required indication: restore the [data-required]/.req-valid left edge to the normal 1px border and
   hide the * markers. The JS painter clears .req-invalid/.req-valid in the same subtree and
   getRequiredFields()/collect() skip it, so the required UX is fully dormant until New / Modify. */
[data-req-suppress] input[data-required="true"],
[data-req-suppress] select[data-required="true"],
[data-req-suppress] textarea[data-required="true"]{border-left-width:1px!important;border-left-color:var(--line-2)!important}
[data-req-suppress] .req{display:none!important}
.field-group select{appearance:none;padding-right:28px;background-repeat:no-repeat;background-position:right 10px center;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235A6472' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}
[data-theme="dark"] .field-group select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238896AE' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}

@keyframes highlightFlash{0%{box-shadow:0 0 0 0 var(--brand);background:var(--panel)}25%,75%{box-shadow:0 0 0 4px var(--brand-soft);background:var(--brand-soft)}100%{box-shadow:0 0 0 0 var(--brand);background:var(--panel)}}
.highlight-flash{animation:highlightFlash 1.6s ease}

/* ============ Workflow side rail ============ */
.side-title{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.1em;color:var(--ink-3);margin-bottom:10px;display:flex;align-items:center;gap:6px}
.workflow{list-style:none;position:relative}
.workflow::before{content:'';position:absolute;left:11px;top:12px;bottom:12px;width:2px;background:var(--line)}
.workflow li{position:relative;padding:0 0 14px 32px;font-size:12.5px}
.workflow li .dot{position:absolute;left:4px;top:2px;width:16px;height:16px;border-radius:50%;background:var(--panel);border:2px solid var(--line-strong);display:grid;place-items:center;z-index:1}
.workflow li.done .dot{background:var(--ok);border-color:var(--ok);color:#fff}
.workflow li.done .dot svg{width:9px;height:9px;color:#fff}
.workflow li.active .dot{background:var(--brand);border-color:var(--brand)}
.workflow li.active .dot::after{content:'';position:absolute;inset:-4px;border-radius:50%;background:var(--brand-soft);z-index:-1}
.workflow li.blocked .dot{background:var(--yellow-stripe);border-color:var(--warn);color:#1B1B1B}
.workflow li.blocked .dot svg{width:9px;height:9px;color:#1B1B1B}
.workflow li .step-name{font-weight:700;color:var(--ink);letter-spacing:-0.003em}
.workflow li.pending .step-name{color:var(--ink-4);font-weight:500}
.workflow li .step-meta{font-size:11px;color:var(--ink-3);margin-top:2px}
.workflow li.blocked .step-meta{color:var(--warn);font-weight:600}

/* Transition gate */
.gate{margin-top:8px;padding:10px 12px;background:var(--banner-bg);border:1px solid var(--banner-border);border-radius:var(--r-md);font-size:11.5px;color:var(--banner-text);display:flex;flex-direction:column;gap:6px}
.gate.ok{background:var(--ok-soft);border-color:transparent;color:var(--ok)}
.gate-head{font-weight:700;display:flex;align-items:center;gap:6px}
.gate-head svg{width:13px;height:13px}
.gate ul{list-style:none;padding-left:18px}
.gate ul li{position:relative;line-height:1.6}
.gate ul li::before{content:'';position:absolute;left:-12px;top:7px;width:5px;height:5px;border-radius:50%;background:currentColor;opacity:0.7}
.gate-action{margin-top:4px;display:flex;gap:6px;flex-wrap:wrap}
.gate-action .btn{height:28px;padding:0 11px;font-size:11.5px;border-radius:var(--r-sm)}

/* ============ Evidence card ============ */
.evidence-pair{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:14px}
.ev-tile{position:relative;background:var(--panel-3);border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;aspect-ratio:1/1;display:flex;flex-direction:column}
.ev-tile.empty{border:1.5px dashed var(--line-strong);background:transparent;cursor:pointer;transition:border-color .12s,background .12s}
.ev-tile.empty:hover,.ev-tile.empty.dragover{border-color:var(--brand);background:var(--brand-soft)}
.ev-tile .ev-img{flex:1;display:grid;place-items:center;background:#0d1b2a;overflow:hidden;cursor:zoom-in;position:relative}
[data-theme="light"] .ev-tile .ev-img{background:#E5EDF7}
.ev-tile .ev-img svg.photo-svg,.ev-tile .ev-img img{width:100%;height:100%;object-fit:cover}
.ev-tile-label{position:absolute;top:8px;left:8px;padding:3px 9px;border-radius:11px;background:rgba(0,0,0,0.7);color:#fff;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:0.08em;backdrop-filter:blur(4px);z-index:2}
.ev-tile-label.before{background:rgba(13,74,158,0.92)}
.ev-tile-label.after{background:rgba(192,57,43,0.92)}
.ev-tile-meta{display:flex;align-items:center;justify-content:space-between;padding:7px 10px;background:var(--panel);border-top:1px solid var(--line);font-size:11.5px;gap:6px}
.ev-tile-meta .nm{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600;color:var(--ink)}
.ev-tile-meta .sub{color:var(--ink-4);font-size:10.5px;font-variant-numeric:tabular-nums;white-space:nowrap}
.ev-tile-actions{position:absolute;top:8px;right:8px;display:flex;gap:4px;opacity:0;transition:opacity .12s;z-index:3}
.ev-tile:hover .ev-tile-actions{opacity:1}
.ev-tile-actions button{width:26px;height:26px;border-radius:var(--r-sm);background:rgba(0,0,0,0.7);color:#fff;display:grid;place-items:center;backdrop-filter:blur(4px)}
.ev-tile-actions button svg{width:13px;height:13px}
.ev-tile-actions button:hover{background:rgba(0,0,0,0.9)}
.ev-tile.empty .ev-img{cursor:pointer;background:transparent;color:var(--ink-3);text-align:center;padding:14px}
.ev-tile.empty .ev-img svg{width:30px;height:30px;color:var(--ink-4);margin-bottom:8px}
.ev-tile.empty .ev-img .empty-label{font-size:11.5px;font-weight:700;color:var(--ink-2)}
.ev-tile.empty .ev-img .empty-hint{font-size:10.5px;color:var(--ink-4);margin-top:2px}

/* Other evidence strip */
.ev-strip-wrap{margin-top:6px}
.ev-strip-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.ev-strip-head .lbl{font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--ink-3)}
.ev-strip-head .ct{font-size:10.5px;color:var(--ink-4);font-variant-numeric:tabular-nums}
.ev-strip{display:flex;gap:10px;overflow-x:auto;padding:2px 2px 8px;scroll-snap-type:x mandatory}
.ev-strip::-webkit-scrollbar{height:8px}
.ev-strip-tile{flex:0 0 100px;width:100px;height:100px;border-radius:var(--r-sm);overflow:hidden;background:var(--panel-3);border:1px solid var(--line);position:relative;cursor:zoom-in;scroll-snap-align:start}
.ev-strip-tile svg.photo-svg,.ev-strip-tile img{width:100%;height:100%;object-fit:cover}
.ev-strip-tile .pdf-pill{position:absolute;top:4px;left:4px;padding:1px 5px;border-radius:3px;background:rgba(13,74,158,0.92);color:#fff;font-size:9px;font-weight:800;text-transform:uppercase;letter-spacing:0.04em}
.ev-strip-tile .actions{position:absolute;top:4px;right:4px;display:flex;gap:3px;opacity:0;transition:opacity .12s}
.ev-strip-tile:hover .actions{opacity:1}
.ev-strip-tile .actions button{width:22px;height:22px;border-radius:var(--r-sm);background:rgba(0,0,0,0.7);color:#fff;display:grid;place-items:center}
.ev-strip-tile .actions button svg{width:11px;height:11px}
.ev-strip-tile .cap{position:absolute;bottom:0;left:0;right:0;padding:3px 6px;background:linear-gradient(180deg,transparent,rgba(0,0,0,0.78));color:#fff;font-size:10px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:500}
.ev-add-tile{flex:0 0 100px;width:100px;height:100px;border-radius:var(--r-sm);border:1.5px dashed var(--line-strong);background:transparent;color:var(--ink-3);display:grid;place-items:center;text-align:center;font-size:11px;cursor:pointer;transition:all .12s}
.ev-add-tile:hover,.ev-add-tile.dragover{border-color:var(--brand);color:var(--brand-deep);background:var(--brand-soft)}
.ev-add-tile svg{width:18px;height:18px;margin-bottom:4px}
.ev-add-tile .lbl{font-weight:700}

.evidence-card.dragover{outline:2px dashed var(--brand);outline-offset:-4px;background:var(--brand-soft)}
.evidence-status{display:flex;align-items:center;gap:7px;margin-top:10px;padding:8px 12px;background:var(--panel-3);border:1px solid var(--line);border-radius:var(--r-sm);font-size:11.5px;color:var(--ink-3)}
.evidence-status svg{width:13px;height:13px;flex-shrink:0}
.evidence-status.ok{color:var(--ok);background:var(--ok-soft);border-color:transparent}
.evidence-status.warn{color:var(--banner-text);background:var(--banner-bg);border-color:var(--banner-border)}

/* ============ Comments timeline ============ */
.timeline{display:flex;flex-direction:column;gap:10px;margin-top:6px}
.tl-item{display:grid;grid-template-columns:30px 1fr;gap:10px}
.tl-item .av{width:30px;height:30px;border-radius:50%;background:var(--brand);color:#fff;display:grid;place-items:center;font-size:11px;font-weight:800;letter-spacing:-0.02em}
.tl-item .av.sys{background:var(--panel-3);color:var(--ink-3);border:1px solid var(--line)}
.tl-item .av.sys svg{width:14px;height:14px}
.tl-item .av.SS{background:var(--brand)}
.tl-item .av.SN{background:var(--purple)}
.tl-item .av.MO{background:var(--ok)}
.tl-item .av.JW{background:var(--warn);color:#fff}
[data-theme="dark"] .tl-item .av.SS{background:var(--brand);color:#000}
[data-theme="dark"] .tl-item .av.SN{background:var(--purple);color:#000}
[data-theme="dark"] .tl-item .av.MO{background:var(--ok);color:#000}
[data-theme="dark"] .tl-item .av.JW{background:var(--warn);color:#000}
.tl-item .bubble{background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-md);padding:9px 11px;font-size:12.5px}
[data-theme="dark"] .tl-item .bubble{background:var(--panel-3)}
.tl-item .who-time{display:flex;justify-content:space-between;gap:8px;margin-bottom:4px;font-size:11px}
.tl-item .who-time .who{font-weight:700;color:var(--ink)}
.tl-item .who-time .when{color:var(--ink-4);font-variant-numeric:tabular-nums}
.tl-item .msg{color:var(--ink-2);line-height:1.45;white-space:pre-wrap}
.tl-empty{padding:18px;text-align:center;color:var(--ink-4);font-size:12px;background:var(--panel-3);border-radius:var(--r-md);border:1px dashed var(--line-strong)}

.composer{margin-top:12px;padding:10px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--panel)}
.composer textarea{width:100%;border:none;outline:none;background:transparent;font-size:12.5px;line-height:1.45;resize:none;font-family:var(--font-ui);color:var(--ink);min-height:48px}
.composer-actions{display:flex;justify-content:space-between;align-items:center;margin-top:8px;padding-top:8px;border-top:1px solid var(--line);gap:8px}
.composer-actions .left{font-size:11px;color:var(--ink-4)}
.composer-actions .left strong{color:var(--ink-3)}
.composer-actions .btn{height:28px;font-size:11.5px;padding:0 12px;border-radius:var(--r-sm)}

/* Required popover */
.required-popover{position:absolute;top:calc(100% + 8px);right:0;width:460px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-md);box-shadow:var(--shadow-lg);z-index:80;opacity:0;pointer-events:none;transform:translateY(-6px);transition:opacity .14s,transform .14s;color:var(--ink);overflow:hidden}
.required-popover.open{opacity:1;pointer-events:auto;transform:none}
.required-popover-header{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;background:var(--banner-bg);border-bottom:1px solid var(--banner-border);color:var(--banner-text)}
.required-popover-header svg{width:14px;height:14px;flex-shrink:0;margin-top:2px}
.required-popover-header .msg{flex:1;font-size:13px;font-weight:700;line-height:1.35}
.required-popover-header .close-btn{width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:50%;color:var(--banner-text)}
.required-popover-header .close-btn:hover{background:rgba(0,0,0,0.08)}
.required-popover-header .close-btn svg{width:12px;height:12px;margin:0}
.required-popover-body{padding:12px 14px 4px;max-height:380px;overflow-y:auto}
/* 14/06/2026 CM — MODAL required-field pill (tspModalRequired). The wrap anchors the popover;
   in a modal footer it sits left of the buttons and the popover opens UPWARD (.req-up) so it is
   not clipped off the bottom of the modal. The header-fallback variant (.on-head) opens downward. */
.req-modal-wrap{position:relative;display:inline-flex}
.modal-foot .req-modal-wrap{margin-right:auto}
.req-modal-wrap.on-head{margin-left:8px}
.req-modal-wrap .required-popover{width:min(420px,calc(100vw - 32px))}
.req-modal-wrap .required-popover.req-up{top:auto;bottom:calc(100% + 8px);left:0;right:auto;transform:translateY(6px)}
.req-modal-wrap .required-popover.req-up.open{transform:none}
.req-modal-wrap.on-head .required-popover{top:calc(100% + 8px);bottom:auto;left:0;right:auto}
.pill-section-label{font-size:10px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:var(--ink-4);margin:4px 0 8px}
.required-row{display:grid;grid-template-columns:auto 1fr auto;gap:12px;align-items:center;padding:8px;margin:0 -8px 2px;border-radius:var(--r-sm);cursor:pointer}
.required-row:hover{background:var(--panel-3)}
.required-row .name{font-size:13px;font-weight:700;color:var(--ink)}
.required-row .helper{font-size:11.5px;color:var(--ink-4);margin-top:1px}
.required-row .chevron svg{width:12px;height:12px;color:var(--ink-4)}
.required-popover-footer{display:flex;justify-content:space-between;align-items:center;padding:10px 14px;background:var(--panel-2);border-top:1px solid var(--line);font-size:11px;color:var(--ink-3)}
.cat-pill{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9px;font-size:9.5px;font-weight:700;letter-spacing:0.06em;min-width:76px;justify-content:center}
.cat-pill.detail{background:var(--brand-soft);color:var(--brand-deep)}
.cat-pill.issue{background:var(--ok-soft);color:var(--ok)}
.cat-pill.disp{background:var(--warn-soft);color:var(--warn)}
.cat-pill.evidence{background:var(--purple-soft);color:var(--purple)}

/* 29/05/2026  CM  Required-component ROBUSTNESS + RESPONSIVE pass (CSS-only, no markup change).
   ------------------------------------------------------------------------------------------
   (a) Generic .req asterisk — the canonical `<span class="req">*</span>` marker was only styled
       inside `.field-group label .req` (line 540). Forms now place the same marker on labels that
       are NOT inside a .field-group (modal/table-header labels, the SO lifecycle child screens),
       so give .req a base look (brand colour, slight left gap) that the field-group rule still
       overrides where it applies. Keeps the marker visible + on-brand everywhere. */
.req{color:var(--brand);margin-left:3px;font-weight:700}
[data-theme="dark"] .req{color:var(--brand-deep)}
/*  (b) Required popover responsive cap — the popover is a fixed 460px panel anchored right:0 inside
       the banner. On phones (<=480px the banner-meta wraps) a 460px panel runs off the left edge.
       Cap it to the viewport with a small gutter and let the body scroll; desktop (>=521px) keeps
       the 460px design. width:min() is widely supported; max-width is the safety net. */
@media (max-width: 520px){
  .required-popover{width:min(460px, calc(100vw - 24px));max-width:calc(100vw - 24px);left:auto;right:0}
  .required-popover-body{max-height:min(380px, 60vh)}
}
/*  (c) Touch targets — on coarse pointers the pill is a primary action; give it a comfortable hit
       height without changing its desktop look. */
@media (hover: none) and (pointer: coarse){
  .required-pill{min-height:32px;padding:6px 12px}
}

/* ============ Lightbox ============ */
.lightbox-overlay{position:fixed;inset:0;background:rgba(8,30,60,0.88);display:none;z-index:200;align-items:center;justify-content:center;backdrop-filter:blur(8px)}
.lightbox-overlay.open{display:flex}
.lightbox-stage{max-width:90vw;max-height:88vh;background:var(--panel);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column;box-shadow:var(--shadow-modal)}
.lightbox-img{background:#000;display:grid;place-items:center;min-width:560px;min-height:400px;max-height:70vh}
.lightbox-img svg,.lightbox-img img{max-width:100%;max-height:70vh;object-fit:contain}
.lightbox-meta{padding:12px 16px;display:flex;align-items:center;gap:12px;border-top:1px solid var(--line);background:var(--panel);color:var(--ink)}
.lightbox-meta .kind-select{height:30px;padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--panel);font-size:12px;color:var(--ink)}
.lightbox-meta .caption-in{flex:1;height:30px;padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--panel);font-size:12px;color:var(--ink);outline:none}
.lightbox-meta .caption-in:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.lightbox-meta .meta-text{font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.lightbox-close{position:absolute;top:16px;right:18px;width:38px;height:38px;border-radius:50%;background:rgba(255,255,255,0.18);color:#fff;display:grid;place-items:center;cursor:pointer;backdrop-filter:blur(6px);transition:background .12s}
.lightbox-close:hover{background:rgba(255,255,255,0.32)}
.lightbox-close svg{width:18px;height:18px}
.lightbox-nav{position:absolute;top:50%;transform:translateY(-50%);width:46px;height:46px;border-radius:50%;background:rgba(255,255,255,0.18);color:#fff;display:grid;place-items:center;cursor:pointer;backdrop-filter:blur(6px);transition:background .12s}
.lightbox-nav:hover{background:rgba(255,255,255,0.32)}
.lightbox-nav.prev{left:24px}
.lightbox-nav.next{right:24px}
.lightbox-nav svg{width:20px;height:20px}

/* ============ PDF preview modal ============ */
.modal-overlay{position:fixed;inset:0;background:rgba(8,30,60,.45);display:none;z-index:150;align-items:center;justify-content:center;backdrop-filter:blur(2px)}
/* Modal stacking — "child" modals that open in response to actions on a
   parent modal must layer above their parent. Tiers:
     history           → 150  (base registry-level surface)
     compare           → 170  (opened from inside history)
     audit             → 180  (can open from history-row kebab, so above history)
     compose / pdf     → 190  (top tier — pdf can open from form, registry
                                 row context menu, OR history row kebab) */
.modal-overlay#compareModal{z-index:170}
.modal-overlay#auditModal{z-index:180}
.modal-overlay#composeModal,
.modal-overlay#pdfModal{z-index:190}
.modal-overlay.open{display:flex}
.modal-window{background:var(--panel);border-radius:var(--r-lg);box-shadow:var(--shadow-modal);width:880px;max-width:95vw;max-height:92vh;display:flex;flex-direction:column;overflow:hidden;border:1px solid var(--line-2)}
.modal-head{display:flex;align-items:center;gap:14px;padding:13px 18px;background:linear-gradient(180deg,var(--brand) 0%,var(--brand-deep) 100%);color:#fff}
.modal-head .ic{width:32px;height:32px;border-radius:var(--r-sm);background:rgba(255,255,255,0.18);color:#fff;display:grid;place-items:center}
.modal-head .ic svg{width:16px;height:16px}
.modal-head .titles h2{font-size:14px;font-weight:700;margin-bottom:1px;letter-spacing:-0.01em}
.modal-head .titles .sub{font-size:11px;opacity:.85}
.modal-head .titles .sub code{font-family:var(--font-mono);font-size:10.5px;background:rgba(255,255,255,.12);padding:1px 5px;border-radius:3px}
.modal-head .modal-x{margin-left:auto;width:32px;height:32px;border-radius:var(--r-sm);display:grid;place-items:center;color:#fff;cursor:pointer;background:rgba(255,255,255,.12)}
.modal-head .modal-x:hover{background:rgba(255,255,255,.22)}
.modal-head .modal-x svg{width:14px;height:14px}
.modal-body{flex:1;overflow:auto;padding:0;background:var(--bg)}
.modal-foot{padding:12px 18px;border-top:1px solid var(--line);background:var(--panel-2);display:flex;align-items:center;gap:8px;justify-content:flex-end}
.modal-foot .left{margin-right:auto;font-size:11.5px;color:var(--ink-3);display:flex;align-items:center;gap:8px}
.modal-foot .left svg{width:13px;height:13px;color:var(--ok)}
.modal-foot .left code{font-family:var(--font-mono);font-size:10.5px;background:var(--panel-3);padding:1px 5px;border-radius:3px;color:var(--ink-2)}

/* ============ PDF sheet visual ============
   Hard-coded brand colours (the PDF is a printed sheet — always on white,
   regardless of the page theme). The Surgical Holdings brand palette is
   used inline so toggling theme doesn't repaint the sheet. */
.pdf-sheet{width:760px;max-width:95%;margin:24px auto;background:#fff;color:#14202E;
  font-family:'Manrope','Segoe UI',sans-serif;padding:0 0 28px;
  box-shadow:0 4px 24px rgba(13,74,158,.22),0 1px 4px rgba(13,74,158,.10);
  border-radius:4px;font-size:11.5px;line-height:1.5;overflow:hidden;
  letter-spacing:-0.003em;font-feature-settings:"ss01","cv11"}
[data-theme="dark"] .pdf-sheet{background:#FFFFFF;color:#14202E}

/* Brand-gradient header band */
.pdf-band{position:relative;display:flex;align-items:center;justify-content:space-between;
  padding:18px 32px 16px;background:linear-gradient(180deg,#1565C4 0%,#0D4A9E 100%);color:#fff}
.pdf-band::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
  background:linear-gradient(90deg,#F2C200 0%,#F2C200 160px,transparent 160px)}
.pdf-band-left{display:flex;flex-direction:column;gap:4px;min-width:0}
.pdf-band-mark{font-size:22px;font-weight:800;letter-spacing:-0.018em;line-height:1;color:#fff}
.pdf-band-mark span{font-weight:400;color:#C5D7EE}
.pdf-band-sub{font-size:10px;text-transform:uppercase;letter-spacing:0.18em;
  color:rgba(255,255,255,.78);font-weight:600;margin-top:2px}
.pdf-band-right{text-align:right;flex-shrink:0;margin-left:24px}
.pdf-band-reflabel{font-size:9.5px;text-transform:uppercase;letter-spacing:0.16em;
  color:rgba(255,255,255,.70);font-weight:700}
.pdf-band-ref{font-family:'DM Mono',ui-monospace,monospace;font-size:18px;font-weight:700;
  color:#fff;letter-spacing:-0.01em;margin-top:1px}
.pdf-band-date{font-size:10.5px;color:rgba(255,255,255,.78);margin-top:3px;font-weight:500;
  font-variant-numeric:tabular-nums}

/* Meta strip under band */
.pdf-meta-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;
  background:#D0D8E3;border-bottom:1px solid #D0D8E3}
.pdf-meta-strip > div{background:#FAFBFD;padding:7px 14px;display:flex;flex-direction:column;gap:1px}
.pdf-meta-strip .lbl{font-size:9px;text-transform:uppercase;letter-spacing:0.14em;
  color:#8A96A8;font-weight:700}
.pdf-meta-strip .val{font-size:11.5px;color:#14202E;font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* Content padding wrapper — all body sections after meta strip sit in this margin */
.pdf-sheet > .pdf-table,
.pdf-sheet > .pdf-section-hd,
.pdf-sheet > .pdf-tick-grid,
.pdf-sheet > .pdf-cell-issue,
.pdf-sheet > .pdf-photos-row,
.pdf-sheet > .pdf-disp,
.pdf-sheet > .pdf-sig{margin-left:32px;margin-right:32px;width:auto}

.pdf-table{border-collapse:collapse;margin-top:18px;margin-bottom:6px;background:#fff}
.pdf-table th,.pdf-table td{border:1px solid #D0D8E3;padding:7px 10px;vertical-align:top;
  font-size:11.5px;color:#14202E}
.pdf-table th{background:#E7F0FB;text-align:left;font-weight:700;width:170px;
  font-size:10px;letter-spacing:0.08em;text-transform:uppercase;color:#0D4A9E}
.pdf-table td{font-variant-numeric:tabular-nums}

.pdf-section-hd{background:#093776;color:#fff;padding:6px 12px;
  font-size:10.5px;font-weight:700;letter-spacing:0.10em;text-transform:uppercase;
  margin-top:14px}

.pdf-cell-issue{min-height:54px;padding:9px 12px;border:1px solid #D0D8E3;border-top:none;
  font-size:11.5px;line-height:1.55;color:#2B3849;background:#fff}

.pdf-tick-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:0;
  border:1px solid #D0D8E3;border-top:none;background:#fff}
.pdf-tick{display:flex;align-items:center;gap:7px;padding:7px 11px;
  border-right:1px solid #E1E7EF;border-bottom:1px solid #E1E7EF;
  font-size:11px;color:#2B3849}
.pdf-tick:nth-child(3n){border-right:none}
.pdf-tick .box{width:14px;height:14px;border:1.5px solid #0D4A9E;border-radius:2px;
  display:grid;place-items:center;flex-shrink:0;background:#fff}
.pdf-tick.checked{color:#0D4A9E;font-weight:700}
.pdf-tick.checked .box{background:#093776;border-color:#093776;color:#fff}
.pdf-tick.checked .box svg{width:9px;height:9px;color:#fff;stroke-width:3.5}

.pdf-photos-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:12px;
  border:1px solid #D0D8E3;border-top:none;background:#F4F8FD}
.pdf-photo{aspect-ratio:1/1;background:#0F2855;border:1px solid #0D4A9E;border-radius:3px;
  overflow:hidden;display:grid;place-items:center;position:relative}
.pdf-photo svg.photo-svg,.pdf-photo img{width:100%;height:100%;object-fit:cover}
.pdf-photo .caption{position:absolute;bottom:0;left:0;right:0;padding:4px 8px;
  font-family:'Manrope',sans-serif;font-size:9.5px;
  background:rgba(13,74,158,.92);color:#fff;
  border-top:1px solid rgba(255,255,255,.15);
  text-align:center;font-weight:700;letter-spacing:0.06em;text-transform:uppercase}
.pdf-photo-empty{background:#fff !important;color:#8A96A8;font-family:'Manrope',sans-serif;
  border:1px dashed #B4BECE !important;font-size:11px;font-weight:600;text-align:center}

.pdf-disp{padding:10px 12px;border:1px solid #D0D8E3;border-top:none;
  font-size:11.5px;color:#2B3849;background:#fff;line-height:1.55}
.pdf-disp strong{font-weight:700;display:inline-block;min-width:140px;color:#0D4A9E}

.pdf-sig{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:16px;padding:12px 14px;
  border:1px solid #D0D8E3;background:#FAFBFD;border-radius:4px}
.pdf-sig .col strong{display:block;font-size:9.5px;letter-spacing:0.10em;text-transform:uppercase;
  color:#8A96A8;margin-bottom:4px;font-weight:700}
.pdf-sig .col .v{font-family:'Brush Script MT',cursive;font-size:19px;color:#1565C4;
  border-bottom:1px solid #B4BECE;padding-bottom:5px}
.pdf-sig .col .v.mono{font-family:'DM Mono',ui-monospace,monospace;font-size:13px;
  color:#093776;font-style:normal;letter-spacing:-0.01em}
.pdf-sig .col .sub{font-size:9.5px;color:#566478;margin-top:3px;font-weight:500}

/* ============ Compose email modal ============ */
.compose-window{width:680px}
.modal-body.compose-body{padding:16px 20px;background:var(--panel)}
.compose-form{display:flex;flex-direction:column;gap:12px}
.compose-field{display:flex;flex-direction:column;gap:4px}
.compose-field label{font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--ink-3);font-weight:700}
.compose-field label .hint{font-size:10px;color:var(--ink-4);font-weight:400;text-transform:none;letter-spacing:0;margin-left:6px}
.compose-input{height:32px;padding:0 11px;border:1px solid var(--line-2);border-radius:var(--r-sm);background-color:var(--panel);font-size:12.5px;color:var(--ink);font-family:var(--font-ui);outline:none;transition:border-color .15s,box-shadow .15s;width:100%}
[data-theme="dark"] .compose-input{background-color:var(--panel-2)}
.compose-input:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.compose-textarea{height:auto;min-height:200px;padding:10px 11px;resize:vertical;line-height:1.55;font-family:var(--font-ui);white-space:pre-wrap}
.compose-attach-chip{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;background:var(--brand-soft);border:1px solid var(--brand-soft);border-left:3px solid var(--brand);border-radius:var(--r-sm);color:var(--brand-deep);font-size:12px;align-self:flex-start;max-width:100%}
.compose-attach-chip .ic{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
.compose-attach-chip .ic svg{width:14px;height:14px;color:var(--brand-deep)}
.compose-attach-chip strong{font-weight:700;color:var(--brand-deep);font-family:var(--font-mono);letter-spacing:-0.02em;font-size:12px}
.compose-attach-chip .sub{color:var(--brand-deep);opacity:.78;font-weight:500}

/* ============ Audit / History modal ============ */
.log-window{width:1180px;max-width:calc(100vw - 48px)}
.history-window{width:calc(100vw - 48px);max-width:1620px;height:calc(100vh - 48px)}
.history-window .modal-body{flex:1}
/* History grid mirrors the registry grid; the first three columns
   (Saved / By / Action) are snapshot-metadata so we give them a soft
   panel-2 background to visually separate them from the SCAR columns. */
table.history-grid tbody td.history-meta{background:var(--panel-2);color:var(--ink-2)}
table.history-grid tbody tr:hover td.history-meta{background:var(--row-hover)}
table.history-grid tbody td.history-saved{font-family:var(--font-num);font-variant-numeric:tabular-nums;font-weight:500;color:var(--ink)}
table.history-grid tbody td.history-by .who-cell{font-weight:500;color:var(--ink-2)}
/* Checkbox column inside the history grid */
table.history-grid thead th:first-child,
table.history-grid tbody td.history-select{width:38px;text-align:center;padding:6px 8px}
table.history-grid tbody td.history-select{background:var(--panel-2)}
table.history-grid tbody tr.row-selected td.history-meta,
table.history-grid tbody tr.row-selected td.history-select{background:var(--sel)}
table.history-grid tbody tr.row-selected td:first-child{box-shadow:inset 3px 0 0 var(--brand)}
[data-theme="dark"] table.history-grid tbody tr.row-selected td.history-meta,
[data-theme="dark"] table.history-grid tbody tr.row-selected td.history-select{color:#F9E7B8}

/* Tiny checkbox used inside the history grid */
.chk-mini{display:inline-flex;align-items:center;cursor:pointer;user-select:none}
.chk-mini input{display:none}
.chk-mini .chk-mini-box{width:15px;height:15px;border:1px solid var(--line-strong);border-radius:3px;background:var(--panel);display:grid;place-items:center;transition:all .1s}
.chk-mini:hover .chk-mini-box{border-color:var(--ink-2)}
.chk-mini input:checked + .chk-mini-box{background:var(--brand);border-color:var(--brand)}
.chk-mini input:checked + .chk-mini-box::after{content:'';width:7px;height:3.5px;border-left:1.5px solid #fff;border-bottom:1.5px solid #fff;transform:rotate(-45deg) translate(0.5px,-1px)}

/* Compare button — appears in the history toolbar */
.compare-btn{height:28px;font-size:11.5px;padding:0 10px;display:inline-flex;align-items:center;gap:6px}
.compare-btn:disabled{opacity:.55;cursor:not-allowed;color:var(--ink-3);border-color:var(--line-2)}
.compare-btn .compare-count{font-size:10px;font-weight:700;padding:1px 6px;border-radius:8px;background:var(--brand-soft);color:var(--brand-deep);letter-spacing:0;font-variant-numeric:tabular-nums}
.compare-btn:disabled .compare-count{background:var(--panel-3);color:var(--ink-4)}

/* ============ History compare modal ============ */
.compare-window{width:calc(100vw - 64px);max-width:1100px;height:auto;max-height:calc(100vh - 64px)}
.modal-body.compare-body{padding:16px 20px;background:var(--panel);display:flex;flex-direction:column;gap:14px;overflow:auto}

.compare-snapshot-heads{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.compare-snap-card{border:1px solid var(--line);border-radius:var(--r-md);background:var(--panel-2);padding:10px 14px;display:flex;flex-direction:column;gap:4px}
.compare-snap-card.snap-a{border-left:3px solid var(--danger)}
.compare-snap-card.snap-b{border-left:3px solid var(--ok)}
.compare-snap-card .snap-card-label{font-size:9.5px;text-transform:uppercase;letter-spacing:0.14em;color:var(--ink-4);font-weight:700}
.compare-snap-card .snap-card-meta{font-size:13px;color:var(--ink);font-weight:600;display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.compare-snap-card .snap-card-meta .when{font-family:var(--font-num);font-variant-numeric:tabular-nums;color:var(--ink)}
.compare-snap-card .snap-card-meta .who{color:var(--ink-2);font-weight:500}

.compare-toolbar{display:flex;align-items:center;gap:14px;padding:8px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.compare-toolbar .chk{font-size:12.5px;color:var(--ink-2);font-weight:500}

.compare-table-wrap{border:1px solid var(--line);border-radius:var(--r-md);overflow:auto;background:var(--panel);flex:1;min-height:240px;max-height:calc(100vh - 380px)}
table.compare-table{width:100%;border-collapse:collapse;font-size:12.5px;table-layout:fixed}
table.compare-table thead th{position:sticky;top:0;z-index:2;background:var(--brand-softer);padding:9px 12px;border-bottom:1px solid var(--line);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:var(--brand-deep);text-align:left;white-space:nowrap}
table.compare-table thead th.field-col{width:220px}
table.compare-table thead th.snap-col-a,
table.compare-table thead th.snap-col-b{width:calc((100% - 220px) / 2)}
table.compare-table tbody tr{border-bottom:1px solid var(--line)}
table.compare-table tbody td{padding:8px 12px;vertical-align:top;color:var(--ink-2);line-height:1.5;word-break:break-word}
table.compare-table tbody td.compare-field-label{font-size:10.5px;text-transform:uppercase;letter-spacing:0.08em;color:var(--ink-3);font-weight:700;background:var(--panel-2);white-space:nowrap}
table.compare-table tbody td.compare-val.mono{font-family:var(--font-mono);font-size:11.5px;letter-spacing:-0.02em}
table.compare-table tbody tr.compare-changed td.compare-field-label{color:var(--ink);font-weight:800;background:var(--brand-softer)}
table.compare-table tbody tr.compare-changed td.compare-val-a{background:var(--danger-soft);color:var(--danger);position:relative}
table.compare-table tbody tr.compare-changed td.compare-val-b{background:var(--ok-soft);color:var(--ok);font-weight:600;position:relative}
[data-theme="dark"] table.compare-table tbody tr.compare-changed td.compare-val-a{background:rgba(230,115,100,.18);color:#FFB4A8}
[data-theme="dark"] table.compare-table tbody tr.compare-changed td.compare-val-b{background:rgba(63,181,101,.18);color:#9CE5B4}
.compare-empty{color:var(--ink-4);font-style:italic;font-weight:400}
.compare-action-pill{display:inline-flex;align-items:center;padding:2px 7px;border-radius:9px;font-size:10px;font-weight:700;letter-spacing:0.04em;background:var(--panel-3);color:var(--ink-3);text-transform:lowercase}
.modal-body.log-body{padding:0;background:var(--bg);display:flex;flex-direction:column}
.modal-head .ref-chip{display:inline-block;margin-left:10px;padding:2px 9px;border-radius:5px;background:rgba(255,255,255,.18);font-family:var(--font-mono);font-size:12px;font-weight:700;color:#fff;letter-spacing:-0.01em;vertical-align:middle}
.log-toolbar-mini{display:flex;align-items:center;gap:10px;padding:12px 18px;border-bottom:1px solid var(--line);background:var(--panel)}
.log-toolbar-mini .search-box{flex:0 1 380px;max-width:380px}
.log-toolbar-mini .chip{height:28px}
.log-count{font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums;font-weight:600}
.log-table-wrap{flex:1;overflow:auto;background:var(--panel)}
table.log-table{width:100%;border-collapse:collapse;font-size:12.5px}
table.log-table thead th{position:sticky;top:0;z-index:2;text-align:left;padding:9px 14px;background:var(--brand-softer);border-bottom:1px solid var(--line);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--brand-deep);white-space:nowrap}
table.log-table thead th.num-col{text-align:right}
table.log-table tbody tr{border-bottom:1px solid var(--line);transition:background .1s}
table.log-table tbody tr:hover{background:var(--row-hover)}
table.log-table tbody td{padding:8px 14px;vertical-align:middle;color:var(--ink-2);line-height:1.4}
table.log-table tbody td.audit-when,
table.log-table tbody td.audit-num{font-family:var(--font-num);font-variant-numeric:tabular-nums;color:var(--ink);font-weight:500}
table.log-table tbody td.audit-num{text-align:right}
table.log-table tbody td.mono-ref{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--brand);letter-spacing:-0.02em;cursor:pointer}
table.log-table tbody td.mono-ref:hover{text-decoration:underline}
table.log-table tbody td .who-cell{display:inline-flex;align-items:center;gap:7px}
.av-mini{width:22px;height:22px;border-radius:50%;display:inline-grid;place-items:center;font-size:9.5px;font-weight:800;letter-spacing:-0.02em;color:#fff;flex-shrink:0}
.av-mini.av-SS{background:var(--brand)}
.av-mini.av-SN{background:var(--purple)}
.av-mini.av-MO{background:var(--ok)}
.av-mini.av-JW{background:var(--warn);color:#fff}
.av-mini.av-sys{background:var(--panel-3);color:var(--ink-3);border:1px solid var(--line)}
.av-mini.av-sys svg{width:11px;height:11px}
.audit-kind{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9px;font-size:10px;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;line-height:1.4}
.audit-kind.audit-kind-workflow{background:var(--brand-soft);color:var(--brand-deep)}
.audit-kind.audit-kind-activity{background:var(--purple-soft);color:var(--purple)}
.audit-kind.audit-kind-system{background:var(--panel-3);color:var(--ink-3)}
.audit-step{font-weight:600;color:var(--ink)}
.log-empty{padding:28px 18px !important;text-align:center;color:var(--ink-4);font-size:12.5px;background:var(--panel-3)}
.history-action{display:inline-flex;align-items:center;padding:2px 8px;border-radius:9px;font-size:10.5px;font-weight:700;letter-spacing:0.04em;background:var(--panel-3);color:var(--ink-3);border:1px solid var(--line)}
.history-action.history-created{background:var(--brand-soft);color:var(--brand-deep);border-color:transparent}
.history-action.history-sent{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.history-action.history-response{background:var(--purple-soft);color:var(--purple);border-color:transparent}
.history-action.history-closed{background:var(--ok-soft);color:var(--ok);border-color:transparent}
.history-action.history-unsat{background:var(--danger-soft);color:var(--danger);border-color:transparent}
.history-action.history-evidence{background:var(--panel-3);color:var(--ink-3)}
.history-status-mini{font-size:11px;font-weight:600;color:var(--ink-2)}

/* Inline new-SCAR ribbon */
.draft-ribbon{display:flex;align-items:center;gap:10px;padding:9px 13px;margin-bottom:12px;background:var(--brand-soft);border:1px solid var(--brand-soft);border-left:3px solid var(--brand);border-radius:var(--r-sm);color:var(--brand-deep);font-size:12px}
.draft-ribbon svg{width:14px;height:14px;flex-shrink:0}
.draft-ribbon strong{font-weight:700;color:var(--brand-deep)}

/* Hidden file input */
.hidden-input{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}

/* Toast */
.toast{position:fixed;bottom:48px;left:50%;transform:translateX(-50%) translateY(20px);padding:11px 18px;background:#093776;color:#fff;border-radius:var(--r-md);font-size:12.5px;box-shadow:var(--shadow-lg);opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;z-index:300;display:flex;align-items:center;gap:8px;font-weight:600;letter-spacing:-0.003em}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.toast svg{width:14px;height:14px;color:#4ADE80}
[data-theme="dark"] .toast{background:#000;border:1px solid var(--line)}

/* ============ Auth gating ============ */
.app[data-auth="out"] .banner-meta > .required-popover-wrap,
.app[data-auth="out"] .banner-meta > .user-chip,
.app[data-auth="out"] .subbar{display:none}
.app[data-auth="in"] #login-pane{display:none}
.required-popover-wrap[data-show="false"]{display:none}

/* ============ Login screen ============ */
.login-pane{display:flex;align-items:center;justify-content:center;padding:36px 22px;overflow:auto;background:var(--bg)}
.login-card{width:100%;max-width:420px;background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--shadow-md);padding:32px 30px;display:flex;flex-direction:column;gap:18px}
.login-card .login-brand{display:flex;flex-direction:column;align-items:center;gap:10px;padding-bottom:18px;border-bottom:1px solid var(--line)}
.login-card .login-brand .logo{width:48px;height:48px;border-radius:10px;background:linear-gradient(180deg,var(--brand) 0%,var(--brand-deep) 100%);color:#fff;display:grid;place-items:center;font-weight:800;font-size:20px;letter-spacing:-0.02em;box-shadow:0 4px 12px rgba(13,74,158,.22)}
.login-card .login-brand .mark{font-weight:800;font-size:22px;letter-spacing:-0.015em;color:var(--ink);line-height:1}
.login-card .login-brand .mark .light{font-weight:400;color:var(--brand-deep)}
[data-theme="dark"] .login-card .login-brand .mark .light{color:var(--brand)}
.login-card .login-brand .sub{font-size:10.5px;text-transform:uppercase;letter-spacing:0.16em;color:var(--ink-3);font-weight:700}
.login-card h2{font-size:15px;font-weight:700;color:var(--ink);letter-spacing:-0.01em;margin:0}
.login-card .login-field{display:flex;flex-direction:column;gap:4px}
.login-card .login-field label{font-size:10.5px;font-weight:700;color:var(--ink-3);text-transform:uppercase;letter-spacing:0.08em}
.login-card .login-field input{height:36px;padding:0 12px;border:1px solid var(--line-2);border-radius:var(--r-sm);background-color:var(--panel);font-size:13px;color:var(--ink);outline:none;transition:border-color .15s,box-shadow .15s;font-family:var(--font-ui)}
[data-theme="dark"] .login-card .login-field input{background-color:var(--panel-2)}
.login-card .login-field input:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.login-card .login-row{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:11.5px}
.login-card .login-row label{display:inline-flex;align-items:center;gap:6px;color:var(--ink-3);cursor:pointer}
.login-card .login-row label input{accent-color:var(--brand)}
.login-card .login-row a{color:var(--brand);font-weight:600;text-decoration:none;cursor:pointer}
.login-card .login-row a:hover{text-decoration:underline}
.login-card .login-submit{height:38px;background:var(--brand);color:#fff;border:none;border-radius:var(--r-md);font-size:13px;font-weight:700;cursor:pointer;letter-spacing:-0.003em;transition:background .14s;display:inline-flex;align-items:center;justify-content:center;gap:8px}
.login-card .login-submit:hover{background:var(--brand-deep)}
.login-card .login-submit svg{width:14px;height:14px}
.login-card .login-foot{display:flex;justify-content:space-between;align-items:center;padding-top:10px;border-top:1px solid var(--line);font-size:10.5px;color:var(--ink-4)}
.login-card .login-foot .chip{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;background:var(--ok-soft);border-radius:999px;color:var(--ok);font-weight:600}
.login-card .login-foot .chip .dot{width:5px;height:5px;border-radius:50%;background:currentColor}
.login-card .quick-users{display:flex;flex-direction:column;gap:4px}
.login-card .quick-users-label{font-size:10px;text-transform:uppercase;letter-spacing:0.1em;color:var(--ink-4);font-weight:700;margin-top:6px}
.login-card .quick-user-btn{display:flex;align-items:center;gap:9px;padding:7px 9px;background:var(--panel-2);border:1px solid var(--line);border-radius:var(--r-sm);font-size:12px;color:var(--ink-2);cursor:pointer;text-align:left;transition:border-color .14s,background .14s}
.login-card .quick-user-btn:hover{border-color:var(--brand);background:var(--brand-soft);color:var(--brand-deep)}
.login-card .quick-user-btn .av{width:24px;height:24px;border-radius:50%;display:grid;place-items:center;font-size:10px;font-weight:800;color:#fff;flex-shrink:0}
.login-card .quick-user-btn .av.SS{background:var(--brand)}
.login-card .quick-user-btn .av.SN{background:var(--purple);color:#fff}
.login-card .quick-user-btn .av.MO{background:var(--ok)}
.login-card .quick-user-btn .av.JW{background:var(--warn);color:#fff}
.login-card .quick-user-btn .role{margin-left:auto;font-size:10px;color:var(--ink-4);font-weight:600}

/* ============ Context menu ============ */
.context-menu{position:fixed;min-width:220px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-md);box-shadow:var(--shadow-lg);padding:4px;z-index:250;display:none}
.context-menu.open{display:block;animation:cmFade .12s ease-out}
@keyframes cmFade{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:translateY(0)}}
.cm-header{padding:8px 10px 6px;font-size:10.5px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.08em;font-family:var(--font-mono)}
.cm-item{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:var(--r-sm);font-size:13px;color:var(--ink);cursor:pointer;letter-spacing:-0.003em}
.cm-item:hover{background:var(--brand-soft);color:var(--brand-deep)}
.cm-item svg{width:14px;height:14px;color:var(--ink-3)}
.cm-item:hover svg{color:var(--brand-deep)}
.cm-item.danger{color:var(--danger)}
.cm-item.danger svg{color:var(--danger)}
.cm-item.danger:hover{background:var(--danger-soft);color:var(--danger)}
.cm-item.disabled{color:var(--ink-4);cursor:not-allowed}
.cm-item.disabled svg{color:var(--ink-4)}
.cm-item.disabled:hover{background:transparent;color:var(--ink-4)}
.cm-item .shortcut{margin-left:auto;font-size:10.5px;color:var(--ink-4);font-family:var(--font-mono)}
.cm-divider{height:1px;background:var(--line);margin:4px 0}

/* Kebab button in last column */
.row-kebab{width:28px;height:28px;border-radius:var(--r-sm);display:inline-flex;align-items:center;justify-content:center;color:var(--ink-3);background:transparent;transition:background .12s,color .12s}
.row-kebab:hover,.row-kebab.open{background:var(--brand-soft);color:var(--brand-deep)}
.row-kebab svg{width:14px;height:14px}

/* ============ Paging ============ */
.paging-bar{display:flex;align-items:center;gap:14px;padding:8px 18px;background:var(--panel-2);border-top:1px solid var(--line);border-bottom:1px solid var(--line);font-size:11.5px;color:var(--ink-3);flex-wrap:wrap}
.paging-bar .left,.paging-bar .right{display:flex;align-items:center;gap:8px}
.paging-bar .right{margin-left:auto}
.paging-bar .summary{font-variant-numeric:tabular-nums}
.paging-bar .summary strong{color:var(--ink);font-weight:700}
.paging-bar .pp-select{height:26px;padding:0 24px 0 9px;border:1px solid var(--line-2);border-radius:var(--r-sm);background-color:var(--panel);font-size:11.5px;color:var(--ink);cursor:pointer;appearance:none;background-repeat:no-repeat;background-position:right 7px center;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235A6472' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}
[data-theme="dark"] .paging-bar .pp-select{background-color:var(--panel-2);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238896AE' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}
.page-btn{min-width:28px;height:28px;padding:0 8px;border:1px solid var(--line-2);background-color:var(--panel);color:var(--ink-2);border-radius:var(--r-sm);font-size:11.5px;font-weight:600;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;font-variant-numeric:tabular-nums;transition:background .12s,border-color .12s,color .12s}
.page-btn:hover{background:var(--brand-soft);border-color:var(--brand-soft);color:var(--brand-deep)}
.page-btn.active{background:var(--brand);border-color:var(--brand);color:#fff}
.page-btn.active:hover{background:var(--brand-deep);border-color:var(--brand-deep)}
.page-btn:disabled{opacity:0.4;cursor:not-allowed}
.page-btn:disabled:hover{background-color:var(--panel);border-color:var(--line-2);color:var(--ink-2)}
.page-btn svg{width:13px;height:13px}
.page-ellipsis{color:var(--ink-4);padding:0 4px;font-variant-numeric:tabular-nums}
[data-theme="dark"] .page-btn{background-color:var(--panel-2)}

/* User chip popover (sign-out) */
.user-chip{cursor:pointer;position:relative}
.user-menu{position:absolute;top:calc(100% + 8px);right:0;width:200px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-md);box-shadow:var(--shadow-lg);z-index:80;opacity:0;pointer-events:none;transform:translateY(-6px);transition:opacity .14s,transform .14s;color:var(--ink);overflow:hidden;padding:4px}
.user-menu.open{opacity:1;pointer-events:auto;transform:none}
.user-menu .um-header{padding:9px 10px 7px;border-bottom:1px solid var(--line);margin-bottom:4px}
.user-menu .um-name{font-size:13px;font-weight:700;color:var(--ink);letter-spacing:-0.005em}
.user-menu .um-role{font-size:11px;color:var(--ink-3);margin-top:1px}
.user-menu .um-item{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:var(--r-sm);font-size:12.5px;color:var(--ink-2);cursor:pointer;letter-spacing:-0.003em}
.user-menu .um-item:hover{background:var(--brand-soft);color:var(--brand-deep)}
.user-menu .um-item svg{width:13px;height:13px}
.user-menu .um-item.danger:hover{background:var(--danger-soft);color:var(--danger)}
.user-menu .um-item.danger svg{color:var(--danger)}

/* ============================================================
   Responsive — desktop + tablet
   ------------------------------------------------------------
   Breakpoints (matched to iPad Air / iPad / iPad mini / Surface):
     ≤1280px  small desktop / 12.9" iPad Pro landscape
     ≤1100px  tablet landscape — tighten paddings, narrow form rail
     ≤960px   tablet portrait — stack form rail below main, 2-col grids
     ≤720px   small tablet portrait — single-col forms, near-fullscreen modals
   Data grids always horizontally scroll (no good way to fold 14 columns
   into a smaller width and keep them honest).
   ============================================================ */

@media (max-width: 1280px){
  body{padding:16px}
  .app{height:calc(100vh - 32px)}
  .form-main{padding:14px 18px 24px}
  .form-side{padding:14px}
}

@media (max-width: 1100px){
  body{padding:14px}
  .app{height:calc(100vh - 28px)}
  .form-pane-grid{grid-template-columns:1fr 280px}
  .banner{padding:12px 22px 10px}
  .banner-meta{gap:8px}
  .log-toolbar{padding:10px 14px;gap:8px}
  .brand-sub{font-size:9.5px;letter-spacing:0.14em}
}

@media (max-width: 960px){
  body{padding:10px}
  .app{height:calc(100vh - 20px);border-radius:8px}
  .titlebar{padding:0 12px}
  .banner{padding:10px 16px 8px}
  .brand-logo{width:34px;height:34px;font-size:16px}
  .brand-mark{font-size:18px}
  .banner-meta{flex-wrap:wrap;justify-content:flex-end;gap:8px}

  /* Stack form side rail below main — the rail's 320/280px doesn't pay
     for itself once the main column is narrower than ~520px. */
  .form-pane-grid{grid-template-columns:1fr;height:100%;overflow:auto}
  .form-main{overflow:visible;padding:14px 16px 16px}
  .form-side{border-left:none;border-top:1px solid var(--line);overflow:visible;padding:16px 16px 24px}

  /* Tighter form grids — 3-col collapses to 2 */
  .field-grid.cols-3{grid-template-columns:1fr 1fr;gap:10px 14px}
  .field-grid{gap:10px 14px}

  /* Log toolbar wraps cleanly; search box grows to fill its row */
  .log-toolbar{padding:10px 12px;gap:8px}
  .search-box{flex:1 1 220px;max-width:none}
  .chip-row{order:5;width:100%}

  /* User-chip collapses to just the avatar circle */
  .user-chip{padding:3px;border-radius:50%;gap:0}
  #userName{display:none}
}

@media (max-width: 720px){
  body{padding:6px}
  .app{height:calc(100vh - 12px);border-radius:6px}

  /* Single-column form fields + evidence */
  .field-grid,
  .field-grid.cols-3{grid-template-columns:1fr}
  .field-grid .span-2,
  .field-grid .span-3{grid-column:1 / -1}
  .evidence-pair{grid-template-columns:1fr}

  /* Form header — wrap title above actions */
  .form-header h1{font-size:14px;flex:1 1 100%}
  .form-header-actions{flex:1 1 100%;justify-content:flex-end;flex-wrap:wrap;gap:6px}
  .form-header-actions .btn{height:30px;padding:0 11px;font-size:11.5px}

  /* Near-fullscreen modals on small tablets */
  .modal-window{width:100vw;max-width:100vw;max-height:100vh;border-radius:0}
  .compose-window,
  .history-window,
  .compare-window,
  .log-window{width:100vw;max-width:100vw;height:100vh;max-height:100vh;border-radius:0}

  .grid-wrap{margin:8px 10px 10px}
  .paging-bar{padding:7px 10px;font-size:10.5px}

  /* Hide the brand sub-text — too long to fit alongside the brand mark */
  .brand-sub{display:none}
}

/* Touch device polish — fatter tap targets, never hide affordances behind
   :hover (since touch has no hover). */
@media (hover: none) and (pointer: coarse){
  .btn{min-height:34px}
  .icon-circle{width:36px;height:36px}
  .row-kebab{width:32px;height:32px}
  .chk-mini .chk-mini-box{width:18px;height:18px}
  .ev-tile-actions{opacity:1}
  .ev-strip-tile .actions{opacity:1}
  .thumb-mini:hover{transform:none;box-shadow:none}
}

/* Native print stylesheet — we open dedicated print windows for the
   history / compare exports, so the only thing left to do here is hide
   the app chrome if someone hits Ctrl+P on the main page. */
@media print {
  body{padding:0;background:#fff}
  .app{box-shadow:none;border:none;height:auto;max-width:none}
  .titlebar,.subbar,.log-toolbar,.paging-bar{display:none}
  .modal-overlay{display:none !important}
}


/* ============================================================
   Taliscon Stock — additions on top of the SCAR baseline
   ----------------------------------------------------------
   Everything below is new to this portal. It introduces:
     - the LEFT primary navigation rail (modules)
     - the INNER status filter sidebar (sales-order status split)
     - the bottom action toolbar (status-aware action buttons)
     - the summary strip (order-totals row)
     - sales-order status pill variants (O/P/I/C/D/X/R)
     - the line-items editor (frm_SO_Item_Update port)
     - the registry right-rail detail panel
   ============================================================ */

/* ============ Primary nav rail ============
   The rail has FOUR addressable states driven by two independent classes:
   - default (no class)        → pinned + expanded   · 220px wide, in grid flow
   - .collapsed                → pinned + collapsed  ·  64px wide, icon-only
   - .unpinned                 → unpinned + expanded · floats over content,
                                                       autohides off-canvas,
                                                       slides in on hover
   - .collapsed.unpinned       → unpinned + collapsed·  shows narrow strip
                                                       on edge, expands on
                                                       hover. */
.nav-rail{width:220px;background:var(--panel-2);border-right:1px solid var(--line);display:flex;flex-direction:column;overflow:hidden;transition:width .18s,transform .18s,box-shadow .18s}

/* The parent grid reads --nav-w so when rail collapses, content reflows. */
.app.module{--nav-w:220px;position:relative;grid-template-columns:var(--nav-w) 1fr}
.app.module:has(.nav-rail.collapsed){--nav-w:64px}
.app.module:has(.nav-rail.unpinned){--nav-w:12px}  /* tiny edge strip remains as hover trigger */
.app.module > .nav-rail{width:auto}                /* width comes from grid column now */

/* Collapsed: hide text, show icons only */
.nav-rail.collapsed .nav-head,
.nav-rail.collapsed .nav-foot,
.nav-rail.collapsed .nav-item > span:not(.nav-count),
.nav-rail.collapsed .nav-item .nav-count,
.nav-rail.collapsed .nav-divider{display:none}
.nav-rail.collapsed a.nav-item{justify-content:center;padding:11px 0}
.nav-rail.collapsed a.nav-item svg{width:18px;height:18px}

/* Unpinned: float over content; autohide off-canvas; slide in on hover or
   when the rail-header is :focus-within (so keyboard users can tab in). */
.nav-rail.unpinned{position:absolute;top:0;bottom:0;left:0;width:220px;z-index:60;box-shadow:var(--shadow-lg);transform:translateX(calc(-100% + 12px))}
.nav-rail.unpinned.collapsed{width:64px;transform:translateX(calc(-100% + 12px))}
.nav-rail.unpinned:hover,
.nav-rail.unpinned:focus-within{transform:translateX(0)}

/* Rail header — toolbar at top of the sidebar with pin + collapse buttons */
.rail-header{display:flex;align-items:center;gap:2px;padding:6px 8px;border-bottom:1px solid var(--line);min-height:34px;flex:none}
.rail-header .rh-title{flex:1;font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.14em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rail-header button{width:26px;height:26px;border-radius:var(--r-sm);display:inline-grid;place-items:center;color:var(--ink-3);background:transparent;cursor:pointer;transition:background .12s,color .12s;flex-shrink:0}
.rail-header button:hover{background:var(--panel-3);color:var(--ink)}
.rail-header button svg{width:13px;height:13px}
.rail-header button.active{background:var(--brand-soft);color:var(--brand-deep)}
.rail-header button.active svg{stroke-width:2.4}
/* Collapsed: hide the title text, keep just the icons centred */
.nav-rail.collapsed .rail-header{padding:6px 4px;justify-content:center}
.nav-rail.collapsed .rail-header .rh-title{display:none}
.nav-rail.collapsed .rail-header .rh-unpin{display:none}  /* hide pin when collapsed; saves space */

.nav-rail .nav-head{padding:14px 16px 8px;font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.14em}
.nav-rail ul{list-style:none;padding:0 8px;margin:0;display:flex;flex-direction:column;gap:1px}
.nav-rail a.nav-item{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:var(--r-md);font-size:13px;font-weight:600;color:var(--ink-2);letter-spacing:-0.003em;cursor:pointer;transition:background .12s,color .12s,box-shadow .12s;text-decoration:none;position:relative}
.nav-rail a.nav-item svg{width:16px;height:16px;color:var(--ink-3);flex-shrink:0;transition:color .12s}
.nav-rail a.nav-item:hover{background:var(--brand-soft);color:var(--brand-deep)}
.nav-rail a.nav-item:hover svg{color:var(--brand-deep)}
.nav-rail a.nav-item.active{background:var(--brand-soft);color:var(--brand-deep);font-weight:700;box-shadow:inset 3px 0 0 var(--brand)}
.nav-rail a.nav-item.active svg{color:var(--brand);stroke-width:2.4}
.nav-rail a.nav-item .nav-count{margin-left:auto;font-size:10.5px;font-weight:700;padding:1px 7px;border-radius:9px;background:var(--panel-3);color:var(--ink-3);font-variant-numeric:tabular-nums}
.nav-rail a.nav-item.active .nav-count{background:var(--brand);color:#fff}
.nav-rail .nav-divider{height:1px;background:var(--line);margin:10px 14px 6px}
.nav-rail .nav-foot{margin-top:auto;padding:12px 16px;border-top:1px solid var(--line);font-size:11px;color:var(--ink-4);display:flex;flex-direction:column;gap:3px}
.nav-rail .nav-foot strong{color:var(--ink-3);font-weight:700}

/* ============ Content area (module screens) ============ */
.app.module > .content{display:grid;grid-template-columns:240px 1fr 320px;grid-template-rows:auto 1fr auto;overflow:hidden}
.content > .status-rail{grid-row:1 / span 3;grid-column:1;background:var(--panel);border-right:1px solid var(--line);overflow:auto}
.content > .reg-toolbar{grid-row:1;grid-column:2 / span 2;border-bottom:1px solid var(--line);background:var(--panel)}
.content > .reg-grid{grid-row:2;grid-column:2;overflow:hidden;background:var(--panel);display:flex;flex-direction:column}
.content > .detail-rail{grid-row:2;grid-column:3;background:var(--panel-2);border-left:1px solid var(--line);overflow:auto;padding:14px 16px}
.content > .action-bar{grid-row:3;grid-column:2 / span 2;background:var(--panel-2);border-top:1px solid var(--line);padding:9px 16px;display:flex;flex-wrap:wrap;align-items:center;gap:7px}

/* Single-column content (forms, dialogs — no status rail or right rail).
   Uses flexbox column so the scrolling middle pane always fills available
   height regardless of how many auto-height siblings (toolbar, summary
   strip, inline tabs) sit above or below it. Override is on a more-specific
   selector than the parent .app.module > .content grid rule so it wins at
   every breakpoint — the earlier grid version was less specific and the
   media-query rules below were leaking the 3-column grid onto form pages
   (content squashed into the leftmost 240px column). */
.app.module > .content.single{display:flex;flex-direction:column;overflow:hidden}
.content.single > .reg-toolbar,
.content.single > .summary-strip,
.content.single > .inline-tabs,
.content.single > .pdf-tabs,
.content.single > .action-bar{flex:none}
/* 14/06/2026  CM  Stock Registry "collapsed panels" fix: a .form-section that is a DIRECT child of the
   single-column flex host (the Stock Registry Search-criteria + Display panels sit there, not inside a
   .form-pane scroller) must NOT be shrinkable. Without this it inherits flex:0 1 auto, so when the
   toolbar + sections + grid-card overflow the viewport the flex algorithm shrinks the sections and the
   .form-section's own overflow:hidden clips the body — only the header bar shows. Pin it to its natural
   height; the grid-card (flex:1 1 auto) absorbs the remaining space. */
.content.single > .form-section{flex:none}
.content.single > .form-pane,
.content.single > .reg-grid{flex:1 1 auto;min-height:0;overflow:auto}
/* 02/06/2026  CM  GLOBAL UI RULE (mobile reachability): NO bottom toolbars anywhere. On every
   single-column screen the .action-bar floats to the TOP — just under the header — via flex order
   (header -2, action bar -1, everything else default 0 in DOM order). The form-pane stays the flex:1
   scroller below it. Border flips top->bottom so it reads as a top strip. One rule relocates all
   ~25 form/sub-screen action bars; no per-view edits. See reference_global_ui_rules memory. */
.content.single > .reg-toolbar{order:-2}
.content.single > .action-bar{order:-1;border-top:none;border-bottom:1px solid var(--line)}
/* 02/06/2026  CM  GLOBAL UI RULE cont. — some create/edit screens (Quote/Create, SalesOrder/Create)
   wrap their body in a <form> directly under .content.single, so the bar is
   .content.single > form > .action-bar and the rule above can't reach it. Mirror the flex column +
   top-float onto any such form: the form becomes the flex:1 child, its .form-pane is the bounded
   scroller, and its .action-bar floats to the top strip via order. (:has limits this to forms that
   actually contain an action bar — same pattern already used for .form-section-body:has(>items-table).) */
.content.single > form:has(> .action-bar){display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden}
.content.single > form:has(> .action-bar) > .form-pane,
.content.single > form:has(> .action-bar) > .reg-grid{flex:1 1 auto;min-height:0;overflow:auto}
.content.single > form > .action-bar{order:-1;flex:none;border-top:none;border-bottom:1px solid var(--line)}
/* items-grid-wrap manages its own internal scroll on the items-grid-scroll
   child, so the wrap itself must NOT scroll (otherwise the editor panel
   below the table scrolls instead of staying pinned). */
.content.single > .items-grid-wrap{flex:1 1 auto;min-height:0}
/* 01/06/2026  CM  Grid-card panels — a bordered card wrapping a scrollable .grid-wrap as a flex child of
   .content.single. Several registry worklists use this shape (Goods In / Product / Stock Registry /
   Stock Ticket / Worksheet / Endoscope). The card MUST flex as a column so its inner .grid-wrap gets a
   bounded height and SCROLLS — otherwise it is content-sized and the grid + pager are CLIPPED with no
   scrollbar once rows overflow (was a per-screen bug; now fixed for the whole class). */
.grid-card,.st-grid-block,.er-grid-card{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}
/* 01/06/2026  CM  Wide editable .items-table grids must scroll HORIZONTALLY on a narrow window — their
   .form-section-body is otherwise overflow:visible and just clips/squishes the columns. (Browse
   .data-grid tables already scroll via .grid-wrap's overflow:auto, so they are unaffected.) */
.form-section-body:has(> table.items-table){overflow-x:auto}

/* ============ Status filter rail ============ */
.status-rail .sr-head{padding:14px 16px 8px;font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.14em}
.status-rail ul{list-style:none;padding:0 8px;margin:0;display:flex;flex-direction:column;gap:1px}
.status-rail a.sr-item{display:flex;align-items:center;gap:10px;padding:8px 11px;border-radius:var(--r-md);font-size:12.5px;font-weight:600;color:var(--ink-2);text-decoration:none;cursor:pointer;transition:background .12s,color .12s}
.status-rail a.sr-item:hover{background:var(--panel-3);color:var(--ink)}
.status-rail a.sr-item .sr-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--ink-4)}
.status-rail a.sr-item .sr-count{margin-left:auto;font-size:10.5px;font-weight:700;padding:1px 7px;border-radius:9px;background:var(--panel-3);color:var(--ink-3);font-variant-numeric:tabular-nums}
.status-rail a.sr-item.active{background:var(--brand-soft);color:var(--brand-deep);font-weight:700}
.status-rail a.sr-item.active .sr-count{background:var(--brand);color:#fff}

/* Status colour swatches for the dot-prefixed rail items */
.sr-dot.dot-open{background:var(--brand)}
.sr-dot.dot-pending{background:var(--warn)}
.sr-dot.dot-invoiced{background:var(--purple)}
.sr-dot.dot-dispatched{background:#0EA5E9}
.sr-dot.dot-complete{background:var(--ok)}
.sr-dot.dot-cancelled{background:var(--danger)}
.sr-dot.dot-return{background:var(--ink-4)}
.sr-dot.dot-all{background:var(--brand-deep)}

/* ============ Registry toolbar ============ */
.reg-toolbar{padding:10px 16px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.reg-toolbar .title{font-size:14px;font-weight:700;color:var(--ink);letter-spacing:-0.005em;display:flex;align-items:center;gap:9px}
.reg-toolbar .title .count{font-size:11px;color:var(--ink-3);font-weight:600;padding:2px 8px;background:var(--panel-3);border-radius:9px;font-variant-numeric:tabular-nums}
.reg-toolbar .spacer{flex:1}
.reg-toolbar .search-box{flex:0 1 320px;max-width:340px}

/* ============ Registry grid wrapper (no margin — fills content) ============ */
.reg-grid table.data-grid{border-collapse:collapse}
.reg-grid .grid-wrap{flex:1;margin:0;border:none;border-radius:0;box-shadow:none}
.reg-grid .paging-bar{margin:0;border-left:none;border-right:none}

/* ============ Sales-order status pills (semantic letter codes) ============ */
.so-status{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:11px;font-size:11px;font-weight:700;letter-spacing:0.04em;white-space:nowrap;text-transform:uppercase}
.so-status::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block}
.so-status.s-O{background:var(--brand-soft);color:var(--brand-deep)}
.so-status.s-P{background:var(--warn-soft);color:var(--warn)}
.so-status.s-I{background:var(--purple-soft);color:var(--purple)}
.so-status.s-D{background:#DBEAFE;color:#0369A1}
.so-status.s-C{background:var(--ok-soft);color:var(--ok)}
.so-status.s-X{background:var(--danger-soft);color:var(--danger)}
.so-status.s-R{background:var(--panel-3);color:var(--ink-3);border:1px solid var(--line)}
.so-status.s-R::before{background:var(--ink-4)}
[data-theme="dark"] .so-status.s-D{background:rgba(56,128,255,.22);color:#7AB6FF}

/* ============ Right detail rail (selected SO summary) ============ */
.detail-rail .dr-head{padding-bottom:10px;margin-bottom:12px;border-bottom:1px solid var(--line)}
.detail-rail .dr-ref{font-family:var(--font-mono);font-size:14px;font-weight:700;color:var(--brand);letter-spacing:-0.02em}
.detail-rail .dr-cust{font-size:13px;color:var(--ink);font-weight:700;margin-top:2px;letter-spacing:-0.005em}
.detail-rail .dr-sub{font-size:11.5px;color:var(--ink-3);margin-top:2px}
.detail-rail .dr-section{margin-bottom:14px}
.detail-rail .dr-section h4{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.14em;margin-bottom:6px}
.detail-rail .dr-kv{display:grid;grid-template-columns:1fr auto;gap:5px 10px;font-size:12px;color:var(--ink-2)}
.detail-rail .dr-kv .k{color:var(--ink-3);font-weight:600}
.detail-rail .dr-kv .v{text-align:right;font-variant-numeric:tabular-nums;font-weight:600;color:var(--ink)}
.detail-rail .dr-kv .v.mono{font-family:var(--font-mono);letter-spacing:-0.02em}
.detail-rail .dr-totals{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-md);padding:10px 12px;display:flex;flex-direction:column;gap:5px}
.detail-rail .dr-totals .row{display:flex;justify-content:space-between;font-size:12.5px;color:var(--ink-2);font-variant-numeric:tabular-nums}
.detail-rail .dr-totals .row.gross{font-size:15px;font-weight:800;color:var(--ink);border-top:1px solid var(--line);padding-top:6px;margin-top:2px;letter-spacing:-0.005em}
.detail-rail .dr-flags{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
.detail-rail .dr-flag{display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:9px;font-size:10.5px;font-weight:700;letter-spacing:0.04em;background:var(--panel-3);color:var(--ink-3);border:1px solid var(--line)}
.detail-rail .dr-flag.urgent{background:#FDE7E1;color:var(--danger);border-color:transparent}
.detail-rail .dr-flag.zero-rated{background:var(--purple-soft);color:var(--purple);border-color:transparent}
.detail-rail .dr-flag.archived{background:var(--ok-soft);color:var(--ok);border-color:transparent}
[data-theme="dark"] .detail-rail .dr-flag.urgent{background:rgba(230,115,100,.22);color:#FFB4A8}

/* Action-sidebar variant — the right rail behaves as the primary action
   panel on the Sales Order Control registry. Groups of full-width buttons
   stacked vertically with section labels. Replaces the bottom action bar
   on that screen (vertical stack scales better on tablet and shows more
   actions at once without the toolbar wrapping). */
.detail-rail .ar-group-label{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.14em;margin:14px 0 6px;display:flex;align-items:center;gap:7px}
.detail-rail .ar-group-label::after{content:'';flex:1;height:1px;background:var(--line)}
.detail-rail .ar-group-label.danger{color:var(--danger)}
.detail-rail .ar-btn-stack{display:flex;flex-direction:column;gap:5px}
.detail-rail .ar-btn-stack .btn{justify-content:flex-start;width:100%;height:34px;padding:0 12px;font-size:12.5px;text-align:left}
.detail-rail .ar-btn-stack .btn svg{width:14px;height:14px;flex-shrink:0}
.detail-rail .ar-btn-stack .btn.btn-danger-soft{background:var(--danger-soft);color:var(--danger);border-color:transparent}
.detail-rail .ar-btn-stack .btn.btn-danger-soft:hover{background:var(--danger);color:#fff}

/* Empty-state inside the right rail */
.detail-rail .dr-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;height:100%;padding:40px 14px;color:var(--ink-4)}
.detail-rail .dr-empty svg{width:36px;height:36px;color:var(--ink-4);margin-bottom:10px}
.detail-rail .dr-empty .ttl{font-size:13px;font-weight:700;color:var(--ink-3);margin-bottom:3px}
.detail-rail .dr-empty .msg{font-size:11.5px;line-height:1.5}

/* ============ Action toolbar at bottom of registry ============ */
.action-bar .ab-group{display:flex;align-items:center;gap:6px}
.action-bar .ab-divider{width:1px;height:24px;background:var(--line);margin:0 4px}
.action-bar .ab-label{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.12em;margin-right:4px}
.action-bar .ab-spacer{flex:1}
.action-bar .btn{height:30px;padding:0 11px;font-size:12px}
.action-bar .btn svg{width:13px;height:13px}

/* ============ Summary strip (form headers) ============ */
.summary-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);border-bottom:1px solid var(--line)}
.summary-strip > div{background:var(--panel-2);padding:11px 16px;display:flex;flex-direction:column;gap:2px}
.summary-strip .ss-lbl{font-size:10px;text-transform:uppercase;letter-spacing:0.14em;color:var(--ink-4);font-weight:700}
.summary-strip .ss-val{font-size:14px;color:var(--ink);font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-0.005em}
.summary-strip .ss-val.mono{font-family:var(--font-mono);font-weight:700;color:var(--brand)}
.summary-strip .ss-val.sm{font-size:13px}
.summary-strip .ss-sub{font-size:10.5px;color:var(--ink-3);font-weight:500;margin-top:1px}

/* ============ Form pane with extra padding for full screens ============ */
.form-pane{padding:18px 22px 24px;overflow:auto;background:var(--bg)}
/* Form-grid primitives — usable anywhere, not just inside .form-pane.
   The earlier .form-pane-prefixed selectors meant grids inside the items
   editor (which uses .editor-panel, not .form-pane) had NO grid styling
   applied — fields stacked vertically and row gap was 0. */
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:22px 20px}
.form-grid.cols-3{grid-template-columns:1fr 1fr 1fr}
.form-grid .span-2{grid-column:span 2}
.form-grid .span-all{grid-column:1 / -1}
/* Form-section primitives — usable anywhere, not just inside .form-pane.
   The earlier .form-pane-prefixed selectors meant that when the same
   markup was used inside the items-editor panel (not wrapped in
   .form-pane) the form-section-head SVG icons rendered at the SVG default
   300x150px instead of 14x14 — those were the giant chevrons spilling
   down the items page. */
.form-section{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-md);margin-bottom:14px;box-shadow:var(--shadow-sm);overflow:hidden}
.form-section-head{padding:10px 16px;background:var(--brand-softer);border-bottom:1px solid var(--line);font-size:11px;font-weight:700;color:var(--brand-deep);text-transform:uppercase;letter-spacing:0.1em;display:flex;align-items:center;gap:9px}
.form-section-head svg{width:14px;height:14px;color:var(--brand-deep);flex-shrink:0}
.form-section-head .hd-spacer{flex:1}
.form-section-head .hd-action{font-size:11px;font-weight:600;color:var(--brand-deep);text-transform:none;letter-spacing:-0.003em;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:var(--r-sm)}
.form-section-head .hd-action:hover{background:var(--brand-soft)}
.form-section-body{padding:14px 16px}
/* Safety net — any inline SVG inside the items editor or its child sections
   always defaults to 14×14 so a missing local rule never leaks a default-
   sized SVG into the layout. Specific size rules above still win. */
.items-grid-wrap svg{width:14px;height:14px}
.items-grid-wrap .sub-table svg,
.items-grid-wrap .btn svg,
.items-grid-wrap .icon-circle svg,
.items-grid-wrap .form-section-head svg{width:auto;height:auto}
.items-grid-wrap .btn svg{width:14px;height:14px}
.items-grid-wrap .icon-circle svg{width:13px;height:13px}
.items-grid-wrap .form-section-head svg{width:14px;height:14px}

/* Inline cluster of inputs (eg. quantity + selling-price + discount) */
.form-row{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:22px 14px}
.form-row.cols-2{grid-template-columns:1fr 1fr}
.form-row.cols-3{grid-template-columns:1fr 1fr 1fr}
.form-row.cols-5{grid-template-columns:repeat(5,1fr)}

/* ============ Line-items editor (frm_SO_Item_Update) ============ */
.items-table{width:100%;border-collapse:collapse;font-size:12.5px;background:var(--panel)}
.items-table thead th{position:sticky;top:0;z-index:2;text-align:left;padding:9px 12px;background:var(--brand-softer);border-bottom:1px solid var(--line);font-size:10.5px;font-weight:700;text-transform:uppercase;letter-spacing:0.07em;color:var(--brand-deep);white-space:nowrap}
.items-table thead th.num{text-align:right}
.items-table tbody tr{border-bottom:1px solid var(--line);cursor:pointer;transition:background .1s}
.items-table tbody tr:hover:not(.is-selected){background:var(--row-hover)}
.items-table tbody tr.is-selected{background:var(--sel)}
.items-table tbody tr.is-selected td{border-bottom-color:var(--sel-border)}
.items-table tbody tr.is-selected td:first-child{box-shadow:inset 3px 0 0 var(--brand)}
.items-table tbody td{padding:7px 12px;vertical-align:middle;color:var(--ink-2)}
.items-table tbody td.mono{font-family:var(--font-mono);font-size:11.5px;font-variant-numeric:tabular-nums;letter-spacing:-0.02em;color:var(--ink);white-space:nowrap}
.items-table tbody td.num{font-variant-numeric:tabular-nums;text-align:right;font-weight:500;color:var(--ink)}
.items-table tbody td.qty{font-weight:600}
.items-table tbody td.cell-line{font-weight:600;color:var(--ink-3);font-variant-numeric:tabular-nums;width:42px;text-align:center}
.items-table tbody td.cell-actions{text-align:right;white-space:nowrap}
.items-table tbody td.cell-actions .icon-circle{width:26px;height:26px}
.items-table tbody td.cell-actions .icon-circle svg{width:13px;height:13px}

.qty-pill{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:11px;background:var(--panel-3);font-size:11.5px;font-weight:700;color:var(--ink-2);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.qty-pill.short{background:var(--warn-soft);color:var(--warn)}
.qty-pill.ok{background:var(--ok-soft);color:var(--ok)}
.qty-pill.none{background:var(--danger-soft);color:var(--danger)}

/* ============ Autocomplete dropdown ============
   Used by the editor's Product Search box. List sits absolute-positioned
   below the input, with hover/keyboard focus on each suggestion. */
.autocomplete{position:relative}
/* 29/05/2026  CM  [#3] Dropdown-scroll containment moved onto the BASE rule (was only inside the
   mobile media query at ~line 1989, which desktop never enters). The list already has a bounded
   max-height + its own overflow, so it IS the scroll container; the page-scroll leak was pure
   scroll-chaining (default overscroll-behavior:auto chains the wheel/touch delta to the document
   when the list reaches its boundary OR is too short to scroll). overscroll-behavior:contain stops
   that chaining everywhere (desktop wheel + touch); touch-action:pan-y lets the list own vertical
   drags; -webkit-overflow-scrolling:touch gives iOS/iPad momentum. */
.autocomplete-list{position:absolute;top:calc(100% + 2px);left:0;right:0;z-index:20;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-sm);box-shadow:var(--shadow-md);max-height:260px;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;touch-action:pan-y;display:none}
.autocomplete-list.open{display:block}
.autocomplete-item{display:grid;grid-template-columns:auto 1fr auto auto;gap:10px;align-items:center;padding:8px 12px;cursor:pointer;border-bottom:1px solid var(--line);font-size:12.5px;color:var(--ink-2)}
.autocomplete-item:last-child{border-bottom:none}
.autocomplete-item:hover,.autocomplete-item.active{background:var(--brand-soft);color:var(--brand-deep)}
.autocomplete-item .ai-code{font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--brand);letter-spacing:-0.02em;background:var(--brand-soft);padding:1px 6px;border-radius:3px}
.autocomplete-item .ai-name{font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.autocomplete-item .ai-group{font-size:10.5px;font-weight:600;color:var(--ink-3);padding:1px 7px;background:var(--panel-3);border-radius:9px;letter-spacing:0.02em}
.autocomplete-item .ai-stock{font-size:11px;font-variant-numeric:tabular-nums;color:var(--ink-3);font-weight:600}
.autocomplete-item:hover .ai-code,
.autocomplete-item.active .ai-code{background:var(--brand);color:#fff}
.autocomplete-empty{padding:14px;text-align:center;color:var(--ink-4);font-size:12px}

/* ============ Computed totals display block ============
   Read-only summary for Nett / VAT / Gross / Discounted unit / Cost. NOT
   editable — these are derived from Qty × Selling Price × Discount × VAT
   rate so showing them as inputs reads like "I can override the maths"
   which is wrong. Block is intentionally calm + monospace so it reads as
   a derived calculation, not a form field. */
.calc-block{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden}
.calc-block > div{background:var(--panel-2);padding:9px 12px;display:flex;flex-direction:column;gap:2px;min-width:0}
.calc-block .cb-lbl{font-size:9.5px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.12em}
.calc-block .cb-val{font-size:14px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;letter-spacing:-0.005em}
.calc-block .cb-val.gross{color:var(--brand-deep);font-size:15px}
.calc-block .cb-val.muted{color:var(--ink-3);font-weight:600;font-size:13px}
.calc-block .cb-sub{font-size:10.5px;color:var(--ink-4);font-weight:500}
/* Pinned variant — sits between the edit toolbar and the scrolling editor
   pane, always visible while the form below scrolls. Strip the rounded card
   look so it reads as part of the toolbar chrome. */
.calc-block.pinned{flex:none;border:none;border-radius:0;border-bottom:1px solid var(--line);margin:0;background:var(--line)}

/* ============ Items table — limit to ~6 visible rows then scroll =========
   38px row + 36px header + 1px borders × n. The container (.items-grid-scroll
   inside the editor) gets a max-height applied via the items.html inline
   style so this rule just nudges the row sizing for visual rhythm. */
.items-table tbody tr{height:38px}

/* Totals strip below the items table */
.totals-strip{display:flex;justify-content:flex-end;gap:24px;padding:12px 16px;background:var(--panel-2);border-top:1px solid var(--line);border-bottom:1px solid var(--line);font-size:13px;color:var(--ink-2)}
.totals-strip .t-block{display:flex;flex-direction:column;align-items:flex-end;gap:1px}
.totals-strip .t-lbl{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.14em}
.totals-strip .t-val{font-variant-numeric:tabular-nums;font-weight:700;color:var(--ink);font-size:14px}
.totals-strip .t-val.gross{font-size:16px;color:var(--brand-deep)}

/* ============ Catalog-code badge inside cells ============ */
.cat-code{font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--brand);letter-spacing:-0.02em;background:var(--brand-soft);padding:2px 6px;border-radius:var(--r-sm)}

/* ============ Sub-table for sub-items / supplier rows ============ */
.sub-table{width:100%;border-collapse:collapse;font-size:11.5px;background:var(--panel-2)}
.sub-table thead th{padding:6px 11px;background:var(--panel-3);font-size:9.5px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.1em;border-bottom:1px solid var(--line);text-align:left}
.sub-table tbody td{padding:6px 11px;border-bottom:1px solid var(--line);color:var(--ink-2)}
.sub-table tbody td.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums;letter-spacing:-0.02em;color:var(--ink)}
.sub-table tbody td.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:500;color:var(--ink)}

/* ============ Module-screen tabs (inline within a form) ============ */
.inline-tabs{display:flex;gap:4px;padding:0 16px;border-bottom:1px solid var(--line);background:var(--panel);margin-bottom:14px}
.inline-tabs .tab{padding:10px 14px;font-size:12px;font-weight:600;color:var(--ink-3);border-bottom:2px solid transparent;margin-bottom:-1px;cursor:pointer;letter-spacing:-0.003em;transition:color .15s,border-color .15s;display:inline-flex;align-items:center;gap:7px}
.inline-tabs .tab:hover{color:var(--ink)}
.inline-tabs .tab.active{color:var(--brand);border-bottom-color:var(--brand);font-weight:700}
.inline-tabs .tab svg{width:14px;height:14px}

/* ============ Banner — Taliscon Stock variants ============ */
/* Reuse the banner styles from SCAR but allow a wider brand sub for the
   long product-area context labels ("Sales Order Management" etc.) */
.brand-sub{white-space:nowrap}

/* Module chips in banner (Customer / Date / ...) */
.banner-chips{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
.banner-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 11px;border-radius:14px;background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.22);color:#fff;font-size:11.5px;font-weight:600;backdrop-filter:blur(4px)}
.banner-chip strong{font-weight:800}
.banner-chip code{font-family:var(--font-mono);font-size:11.5px;letter-spacing:-0.01em;background:rgba(255,255,255,.18);padding:1px 6px;border-radius:3px;color:#fff;font-weight:700}

/* ============ Index / portal landing tile ============ */
.portal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px;padding:24px}
.portal-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-md);padding:16px 18px;display:flex;flex-direction:column;gap:8px;text-decoration:none;color:inherit;transition:all .14s;cursor:pointer;box-shadow:var(--shadow-sm)}
.portal-card:hover{border-color:var(--brand);box-shadow:var(--shadow-md);transform:translateY(-1px)}
.portal-card .pc-icon{width:38px;height:38px;border-radius:var(--r-md);background:var(--brand-soft);color:var(--brand-deep);display:grid;place-items:center;margin-bottom:6px}
.portal-card .pc-icon svg{width:18px;height:18px}
.portal-card .pc-ttl{font-size:14px;font-weight:700;color:var(--ink);letter-spacing:-0.005em}
.portal-card .pc-sub{font-size:11.5px;color:var(--ink-3);line-height:1.45}
.portal-card .pc-tag{margin-top:auto;font-size:10px;font-weight:700;color:var(--brand-deep);text-transform:uppercase;letter-spacing:0.1em}

/* Portal section heading */
.portal-section{padding:16px 24px 8px}
.portal-section h2{font-size:13px;font-weight:700;color:var(--ink-3);text-transform:uppercase;letter-spacing:0.12em;display:flex;align-items:center;gap:9px}
.portal-section h2::after{content:'';flex:1;height:1px;background:var(--line)}
.portal-section .sub{font-size:11.5px;color:var(--ink-4);margin-top:3px}

/* ============ Stock-area split layout ============
   Used by stock-registry and stock-detail. Wraps the main content area
   in a 2-column grid (main + right action sidebar) inside .content.single.
   Below 960px the sidebar drops to a full-width strip at the bottom. */
.stock-area{display:grid;grid-template-columns:1fr 300px;flex:1 1 auto;min-height:0;overflow:hidden}
.stock-area > .stock-main{overflow:auto;min-width:0;display:flex;flex-direction:column}
.stock-area > .detail-rail{background:var(--panel-2);border-left:1px solid var(--line);overflow:auto;padding:14px 16px}
@media (max-width: 1100px){.stock-area{grid-template-columns:1fr 260px}}
@media (max-width: 960px){
  .stock-area{grid-template-columns:1fr;grid-template-rows:1fr auto}
  .stock-area > .detail-rail{border-left:none;border-top:1px solid var(--line);padding:10px 14px;max-height:none}
  .stock-area > .detail-rail .ar-btn-stack{flex-direction:row;flex-wrap:wrap;gap:6px}
  .stock-area > .detail-rail .ar-btn-stack .btn{width:auto}
}

/* ============ Option pill — toggle-checkbox replacement ============
   Used on stock-registry's Display section. Click toggles .active.
   Circle indicator on the left fills with brand colour + check icon. */
.opt-pill{display:inline-flex;align-items:center;gap:8px;height:32px;padding:0 14px;background:var(--panel);border:1px solid var(--line-2);border-radius:16px;font-size:12.5px;font-weight:600;color:var(--ink-3);cursor:pointer;transition:background .12s,color .12s,border-color .12s;letter-spacing:-0.003em;font-family:inherit}
.opt-pill:hover{background:var(--panel-3);color:var(--ink);border-color:var(--line-strong)}
.opt-pill .pill-check{width:16px;height:16px;border-radius:50%;border:1.5px solid var(--line-strong);display:inline-grid;place-items:center;background:transparent;transition:background .12s,border-color .12s;flex-shrink:0}
.opt-pill .pill-check svg{width:9px;height:9px;color:transparent;stroke-width:3.5;transition:color .12s}
.opt-pill.active{background:var(--brand-soft);color:var(--brand-deep);border-color:transparent}
.opt-pill.active .pill-check{background:var(--brand);border-color:var(--brand)}
.opt-pill.active .pill-check svg{color:#fff}
.opt-connector{color:var(--ink-4);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.14em;align-self:center;padding:0 2px}

/* ============ Mobile + Tablet — full-viewport, no card chrome ============
   Triggered by `(hover: none) and (pointer: coarse)` — the standard CSS
   touchscreen detection. True on:
     - all phones (iOS / Android)
     - all tablets in ANY orientation (iPad portrait 820 + landscape 1180,
       iPad Pro 12.9" 1024/1366, etc.)
     - Chrome DevTools mobile emulation (honoured by the device toolbar)
   False on a narrow desktop window (mouse-driven), so a half-screen browser
   window doesn't accidentally drop the card chrome. This is the reliable
   CSS-only equivalent of UA sniffing without the unreliability. */
@media (hover: none) and (pointer: coarse){
  body{padding:0 !important;background:var(--bg) !important}
  [data-theme="dark"] body{background:var(--bg) !important}
  .app,.app.module{height:100vh !important;height:100dvh !important;width:100%;max-width:none;margin:0;border:none !important;border-radius:0 !important;box-shadow:none !important}
  html.scrollable .app{min-height:100vh !important;min-height:100dvh !important}
  /* Drop the tiny window-control dots on phones — they're decorative */
  .titlebar .tb-controls{display:none}
  /* Banner: collapse the brand sub-line; chips wrap onto their own row */
  .banner{padding:8px 12px;flex-wrap:wrap;gap:8px;min-height:auto}
  .brand-sub{display:none}
  .brand-mark{font-size:16px}
  .banner-meta{gap:6px}
  /* Reg-toolbar wraps tightly */
  .reg-toolbar{padding:8px 10px;gap:8px}
  .reg-toolbar .search-box{flex:1 1 calc(50% - 4px);max-width:none}
  /* Workflow tabs scroll horizontally instead of wrapping (saves vertical) */
  .workflow-strip{flex-wrap:nowrap;overflow-x:auto;padding:7px 10px;-webkit-overflow-scrolling:touch}
  .workflow-tab{flex-shrink:0}
  /* Grids: allow horizontal scroll if the content is wider than the phone */
  .dual-grid .grid-section .gs-body{overflow:auto;-webkit-overflow-scrolling:touch}
  /* Modal windows fit the screen rather than floating */
  .modal-window{width:95vw !important;max-height:90vh}
  /* grid_Bottom swap: hide the wide line-items table and reveal the
     expandable card list rendered in parallel by loadBottom(). */
  .gs-bottom #gridBottom{display:none}
  .gs-bottom .bottom-cards{display:flex}
}

/* ============ grid_Bottom expandable-row list (tablet / mobile) ============
   Rendered by loadBottom() alongside #gridBottom. Hidden on desktop; shown
   on tablet/mobile via the (hover: none) and (pointer: coarse) media query.
   Keeps the key columns (Qty / Gross / Fulfil / Process) aligned like a table,
   tucking the rest into an expandable detail strip. Cells gated by
   availability carry .bc-avail-cell and only show once Query Available runs. */
.bottom-cards{display:none;flex-direction:column;background:var(--panel)}

/* Column-label strip + each row share the same grid so columns line up.
   Tracks: chevron | title | qty | gross | (fulfil) | (process) | kebab.
   The fulfil + process tracks only appear once availability is checked. */
.bc-colhead,.bc-header{display:grid;grid-template-columns:20px minmax(0,1fr) 38px 72px 30px;align-items:center;gap:10px;padding:9px 12px}
.bottom-cards.avail-on .bc-colhead,
.bottom-cards.avail-on .bc-header{grid-template-columns:20px minmax(0,1fr) 38px 72px 66px 48px 30px}

.bc-colhead{border-bottom:1px solid var(--line);background:var(--panel-2)}
.bc-colhead span{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.1em}
.bc-colhead .bc-ch-cat{grid-column:1 / span 2}
.bc-colhead .bc-ch-qty,.bc-colhead .bc-ch-gross{text-align:right}
.bc-colhead .bc-ch-fulfil,.bc-colhead .bc-ch-process{text-align:center}

.bottom-card{border-bottom:1px solid var(--line)}
.bc-header{cursor:pointer;-webkit-tap-highlight-color:transparent}
.bottom-card.expanded{background:var(--brand-soft)}
.bc-chevron{width:13px;height:13px;color:var(--ink-3);transition:transform .15s;justify-self:center}
.bottom-card.expanded .bc-chevron{transform:rotate(90deg);color:var(--brand)}
.bc-title{min-width:0;display:flex;flex-direction:column;gap:1px}
.bc-cat{font-family:var(--font-mono);font-size:13.5px;font-weight:700;color:var(--ink);letter-spacing:-0.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bottom-card.expanded .bc-cat{color:var(--brand-deep)}
.bc-prod{font-size:11.5px;font-weight:500;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bc-qty,.bc-gross{font-size:13px;font-weight:700;color:var(--ink);text-align:right;font-variant-numeric:tabular-nums}
.bc-fulfil,.bc-process,.bc-kebab{display:flex;justify-content:center;align-items:center}
.bc-pill{font-size:10.5px;padding:2px 8px;white-space:nowrap}
.bc-kebab .row-kebab{width:26px;height:26px}

/* Availability-gated cells: hidden until the cards container gets .avail-on. */
.bc-avail-cell{display:none}
.bottom-cards.avail-on .bc-avail-cell{display:flex}
.bottom-cards.avail-on .bc-colhead .bc-avail-cell{display:block}

/* Expanded detail strip — auto-fits as a single row on tablets, wraps on phones. */
.bc-body{display:none;padding:0 12px 12px}
.bottom-card.expanded .bc-body{display:block}
.bc-detail{display:grid;grid-template-columns:repeat(auto-fit,minmax(70px,1fr));gap:10px 14px;padding:10px 0 2px;border-top:1px dashed var(--line)}
.bc-cell{display:flex;flex-direction:column;gap:2px;min-width:0}
.bc-detail .bc-avail-cell{display:none}
.bottom-cards.avail-on .bc-detail .bc-avail-cell{display:flex}
.bc-lbl{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.1em}
.bc-val{font-size:13px;font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}
.bc-val.bad{color:var(--danger)}
.bc-val.warn{color:var(--warn)}

/* Even smaller (phones): one toggle at a time scrolls horizontally,
   data-grid font drops slightly, and the row-kebab cell narrows. */
@media (max-width: 480px){
  .reg-toolbar .title .count{display:none}
  .reg-toolbar .chip-row{order:99;flex-basis:100%;justify-content:flex-start}
  table.data-grid th,table.data-grid td{padding:8px 8px;font-size:11.5px}
  .scar-ref{font-size:11px}
  .row-kebab{width:30px;height:30px}
  td.row-actions,th.row-actions{padding-right:6px}
  .row-ctx-menu{min-width:200px}
}

/* ============ Sales Order Control — dual-grid + tab-rail layout ============
   Maps directly to VB6 frm_SO_Control. The status-rail becomes a 7-tab
   workflow rail (one entry per VB6 SSTab page). The middle column stacks
   grid_TOP (master list, 7 column-sets) above grid_Bottom (line items of the
   selected row). 29/05/2026 CM: the right-hand detail/action rail was REMOVED —
   so-main now fills the full width. Per-tab + form-level actions live in the row
   kebabs; the Tab-4 Batch group sits in the grid_TOP header, UN-PROCESS Items in
   the grid_Bottom header, and New Order in the reg-toolbar (hard-right). */
/* Specificity bumped to `.app.module > .content.so-control` AND !important on
   the display/flex declarations so it wins over the registry 3-col grid rule
   at line 1146 PLUS the responsive media-queries at lines 989/1609 which
   reflow `.content > .status-rail` and `.content > .detail-rail` to span
   full width on smaller screens. Without that defence the panels stack
   vertically (status-rail at top, detail-rail at bottom) instead of forming
   the three-column workflow layout. */
.app.module > .content.so-control{display:flex !important;overflow:hidden;grid-template-columns:none !important;grid-template-rows:none !important}
.app.module > .content.so-control > .status-rail{flex:0 0 240px !important;background:var(--panel);border-right:1px solid var(--line) !important;border-bottom:none !important;overflow:auto;display:flex;flex-direction:column;grid-row:auto !important;grid-column:auto !important;max-height:none}
.app.module > .content.so-control > .status-rail ul{flex-direction:column !important;flex-wrap:nowrap !important;padding:0 8px !important}
.app.module > .content.so-control > .status-rail .sr-head{display:block !important}
/* 29/05/2026 CM: detail rail removed — so-main now fills the full width of the
   so-control flex row (its flex:1 1 auto + no sibling aside means it reflows to
   100%). The former `> .detail-rail` basis rules were deleted. */
.app.module > .content.so-control > .so-main{flex:1 1 auto;display:flex;flex-direction:column;min-width:0;background:var(--panel);overflow:hidden}
/* gs-head action toolbars (Tab-4 Batch group in grid_TOP, UN-PROCESS Items in
   grid_Bottom) — relocated from the removed rail. Keep buttons inline + compact. */
.gs-head .gs-head-actions{display:flex;align-items:center;gap:6px}
.gs-head .gs-batch-group{display:flex;align-items:center;gap:6px}
.gs-head .ar-btn-stack{display:inline-flex;align-items:center;gap:6px}
.gs-head .ar-group-label{font-size:10px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.12em}
.gs-head .ar-group-label::after{content:none}

/* Customer heading strip — replaces VB6 panel_Heading. Red customer name in
   serif evoking the original Times New Roman 13.5 + Customer Details button. */
.customer-banner{display:flex;align-items:center;gap:14px;padding:9px 18px;background:var(--brand-softer);border-bottom:1px solid var(--line);flex-wrap:wrap}
.customer-banner .cb-label{font-size:10.5px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.16em}
.customer-banner .cb-name{font-family:Georgia,'Times New Roman',serif;font-size:17px;font-weight:700;color:var(--brand-deep);letter-spacing:-0.005em}
.customer-banner .cb-meta{font-size:11.5px;color:var(--ink-3);font-weight:600}
.customer-banner .cb-spacer{flex:1}
/* Email + Archive pill toggles. Originally scoped to .customer-banner; now
   top-level so they work in the reg-toolbar (and anywhere else) without the
   icons falling back to default 24px size. */
.email-toggle,
.archived-toggle{display:inline-flex;align-items:center;gap:6px;padding:5px 10px;border-radius:14px;font-size:11.5px;font-weight:700;cursor:pointer;transition:background .12s,color .12s,border-color .12s;white-space:nowrap;font-family:inherit;line-height:1}
.email-toggle{background:#E8FAE8;color:#0E6B2F;border:1px solid #B7E2BD}
.email-toggle:hover{background:#D5F3D8}
.email-toggle.off{background:var(--panel-3);color:var(--ink-4);border-color:var(--line-2)}
.email-toggle svg{width:13px !important;height:13px !important;flex-shrink:0}
.archived-toggle{background:var(--panel);color:var(--ink-3);border:1px solid var(--line-2)}
.archived-toggle:hover{background:var(--panel-3);color:var(--ink)}
.archived-toggle.active{background:var(--ok-soft);color:var(--ok);border-color:transparent}
.archived-toggle svg{width:13px !important;height:13px !important;flex-shrink:0}

[data-theme="dark"] .email-toggle{background:#142A1A;color:#5AC974;border-color:#1F3D26}
[data-theme="dark"] .archived-toggle{background:var(--panel-3)}

/* Horizontal workflow toggle strip — sits below the reg-toolbar (under the
   search-boxes / date-chips row). Toggles match the .chip pattern: 28px
   tall, brand-soft active state, dot + label + count badge. No step number. */
.workflow-strip{display:flex;gap:6px;padding:8px 16px;background:var(--panel);border-bottom:1px solid var(--line);overflow-x:auto;align-items:center;flex-wrap:wrap;flex-shrink:0}
.workflow-tab{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 12px;border-radius:14px;background:var(--panel);border:1px solid var(--line-2);font-size:12px;font-weight:600;color:var(--ink-3);cursor:pointer;white-space:nowrap;transition:all .12s;font-family:inherit;letter-spacing:-0.003em}
.workflow-tab:hover{background:var(--panel-3);color:var(--ink)}
.workflow-tab.active{background:var(--brand-soft);color:var(--brand-deep);border-color:var(--brand-soft)}
.workflow-tab .wt-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
.workflow-tab .wt-count{font-variant-numeric:tabular-nums;font-size:10.5px;padding:1px 6px;border-radius:8px;background:var(--panel-3);color:var(--ink-3);font-weight:700;min-width:18px;text-align:center}
.workflow-tab.active .wt-count{background:var(--brand);color:#fff}
/* 12/06/2026 CM — status-TONED workflow tabs (per CM: the PO Control coloured status pills are the
   house look; every status strip matches them now). Tone letters reuse the .pill-s-* palette:
   O brand-blue, P amber, I purple, D light-blue, C green, X red, R grey. The ACTIVE tab flips to
   the brand tint exactly like the PO pills (.pill-select.active), so selection stays unmistakable. */
.workflow-tab.wt-O{background:var(--brand-soft);color:var(--brand-deep)}
.workflow-tab.wt-P{background:var(--warn-soft);color:var(--warn)}
.workflow-tab.wt-I{background:var(--purple-soft);color:var(--purple)}
.workflow-tab.wt-D{background:#DBEAFE;color:#0369A1}
.workflow-tab.wt-C{background:var(--ok-soft);color:var(--ok)}
.workflow-tab.wt-X{background:var(--danger-soft);color:var(--danger)}
.workflow-tab.wt-R{background:var(--panel-3);color:var(--ink-3)}
[data-theme="dark"] .workflow-tab.wt-D{background:rgba(56,128,255,.22);color:#7AB6FF}
.workflow-tab[class*="wt-"].active{background:var(--brand-soft);color:var(--brand-deep);border-color:var(--brand-soft)}
.workflow-tab[class*="wt-"].active .wt-count{background:var(--brand);color:#fff}
.workflow-state{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--ink-3);padding:5px 10px;border-radius:11px;background:var(--panel);border:1px solid var(--line-2);margin-left:auto}
.workflow-state.ok{background:var(--ok-soft);color:var(--ok);border-color:transparent}
.workflow-state.warn{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.workflow-state svg{width:11px;height:11px}

/* The 7 workflow tabs (left rail). Same .sr-item structure but the dot
   palette now maps 1:1 to VB6 SSTab indexes. */
.status-rail .sr-tabnum{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;font-size:9.5px;font-weight:800;background:var(--panel-3);color:var(--ink-4);flex-shrink:0;font-variant-numeric:tabular-nums}
.status-rail a.sr-item.active .sr-tabnum{background:rgba(255,255,255,.6);color:var(--brand-deep)}
.sr-dot.dot-so-pending{background:var(--warn)}
.sr-dot.dot-so-processed{background:#0EA5E9}
.sr-dot.dot-so-complete{background:var(--ok)}
.sr-dot.dot-open-cons{background:var(--brand)}
.sr-dot.dot-inv-pending{background:#D97706}
.sr-dot.dot-inv-sent{background:var(--purple)}
.sr-dot.dot-inv-complete{background:var(--ok)}

/* Dual grid — grid_TOP above grid_Bottom. Both scrollable; thin divider
   between them. The top grid takes ~46% of the vertical space; the bottom
   grid grows. */
.dual-grid{flex:1 1 auto;display:flex;flex-direction:column;min-height:0;overflow:hidden}
.dual-grid .grid-section{display:flex;flex-direction:column;min-height:0;background:var(--panel)}
.dual-grid .grid-section.gs-top{flex:0 1 46%;border-bottom:6px solid var(--bg)}
.dual-grid .grid-section.gs-bottom{flex:1 1 54%}
.dual-grid .grid-section .gs-head{padding:7px 16px 6px;background:var(--panel-2);border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;font-size:10.5px;font-weight:700;color:var(--brand-deep);text-transform:uppercase;letter-spacing:0.12em;flex-shrink:0}
.dual-grid .grid-section .gs-head .gs-spacer{flex:1}
.dual-grid .grid-section .gs-head .gs-meta{font-size:11px;color:var(--ink-3);font-weight:600;text-transform:none;letter-spacing:-0.003em}
.dual-grid .grid-section .gs-body{flex:1 1 auto;min-height:0;overflow:auto;background:var(--panel)}
.dual-grid table.data-grid{border-collapse:collapse;width:100%}

/* Per-tab column visibility — one <thead> + <tbody> set per tab, swapped via
   `data-tab` attribute. Currently-active tab gets `.is-active`; others hide. */
.tab-cols{display:none}
.tab-cols.is-active{display:table-row-group}
thead.tab-cols.is-active{display:table-header-group}

/* 28/05/2026  CM  TASK 2 — Customer column width on the INVOICE tabs (3 Open
   Consignments, 4 I-Pending, 5 I-Sent, 6 I-Complete). On this DB the customer
   CODE == the customer NAME, so the full name renders in the cell's <strong> and,
   with auto table-layout, a long name (e.g. "52 ALDERLEY ROAD DIAGNOSTIC &
   SURGICAL CENTRE") was squeezed into ~1/8 of the row and wrapped over 3 lines.
   The .so-cust-cell class is on the Customer # <th>/<td> of tabs 3-6 ONLY (the
   SO tabs 0-2 keep their existing sized "Customer #" column untouched), so this
   rule is scoped to those tabs. min-width reserves enough room for the name to
   sit on ~1-2 lines; the <strong> name is clamped to 2 lines with the full value
   still available via the cell's title= tooltip. */
table.data-grid th.so-cust-cell,
table.data-grid td.so-cust-cell{min-width:240px;max-width:300px}
table.data-grid td.so-cust-cell strong{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;line-height:1.3}

/* 13/06/2026  CM  Open Consignments (tab 3, per CM) has only 7 columns, so there is spare width the
   other tabs spend on extra columns. Let tab 3's customer column run wider (long names sit on one line
   instead of wrapping, matching the roomier feel of the I-Sent tab) and give its Comment column a
   comfortable minimum rather than the leftover sliver. Scoped to tab 3 so tabs 4-6 keep 240-300. */
table.data-grid .tab-cols[data-tab="3"] th.so-cust-cell,
table.data-grid .tab-cols[data-tab="3"] td.so-cust-cell{min-width:300px;max-width:460px}
table.data-grid .tab-cols[data-tab="3"] th:nth-child(6),
table.data-grid .tab-cols[data-tab="3"] td:nth-child(6){min-width:220px}

/* 13/06/2026  CM  Pager controls (jump-to-page + rows-per-page), app-wide. Every grid pager carries the
   same .pager-jump / .pager-size groups; style them to match the app inputs and float them to the right
   of the Prev / "Showing…" / Next group so the pager reads cleanly (per CM: the default looked off). */
.pager-jump,
/* 14/06/2026 CM — registry pagers (.grid-pager: #stPager / #regPager / etc.) had NO display rule, so
   when the JS revealed them (style.display='') they fell back to block and the controls wrapped onto
   separate lines (Prev/Next, then page+Go, then rows). Pin them to a single horizontal flex row that
   scrolls if ever too narrow, instead of stacking vertically. */
.grid-pager{display:flex;flex-wrap:nowrap;align-items:center;gap:10px;overflow-x:auto}
/* 14/06/2026 CM — SO Items / Quote Items TOP grid (.items-grid-scroll) has its own vertical scrollbar
   that sat flush against the page (.app-main) scrollbar. Inset it slightly so the two scrollbars don't
   touch (clearer which is which). margin-right isn't set inline on this class, so this applies. */
.items-grid-scroll{margin-right:8px}
.pager-size{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;color:var(--muted,#64748b);white-space:nowrap}
.pager-jump{margin-left:auto}
.pager-jump input,
.pager-size select{height:26px;border:1px solid var(--line,#d7dde5);border-radius:6px;background:var(--panel,#fff);color:var(--ink,#1f2937);font-size:11.5px;padding:0 6px;line-height:24px}
.pager-jump input{width:52px;text-align:right}
.pager-size select{cursor:pointer;padding-right:4px}
[data-theme="dark"] .pager-jump input,
[data-theme="dark"] .pager-size select{background:var(--panel-2,#1e2530);border-color:var(--line,#33404f);color:var(--ink,#e5e9ef)}

/* 14/06/2026 CM — client-side sortable grid (tspSortableGrid): clickable column headers with an
   asc/desc arrow indicator. The checkbox/select, .row-actions and .no-sort headers stay inert. */
.sortable-grid thead th:not(.row-actions):not(.no-sort){cursor:pointer;user-select:none}
.sortable-grid thead th:not(.row-actions):not(.no-sort):hover{color:var(--brand)}
.sortable-grid thead th.sort-asc::after{content:" \25B2";font-size:9px;opacity:.75}
.sortable-grid thead th.sort-desc::after{content:" \25BC";font-size:9px;opacity:.75}
.sortable-grid thead th.sel-cell,.sortable-grid thead th input{cursor:default}

/* CANCELLED ! banner — VB6 panel_Cancelled. Pinned to the top of the grid
   area when the selected row's status is X. */
.cancelled-banner{display:none;align-items:center;justify-content:center;gap:10px;padding:7px 14px;background:var(--danger);color:#fff;font-size:13px;font-weight:800;letter-spacing:0.08em;text-transform:uppercase;animation:cancelled-pulse 1.6s ease-in-out infinite}
.cancelled-banner.show{display:flex}
.cancelled-banner svg{width:16px;height:16px}
@keyframes cancelled-pulse{
  0%,100%{background:var(--danger)}
  50%{background:#A0291E}
}

/* Sort indicator on grid_TOP column headers. Click toggles ASC ↔ DESC; colour
   flips from default (panel) to brand-blue (ASC) to brand-red (DESC) per the
   VB6 LastOrderBy / ColumnSortedColour mechanism. */
.data-grid th.sort-asc{color:var(--brand-deep)}
.data-grid th.sort-desc{color:var(--danger)}
.data-grid th[data-sortable]{cursor:pointer;user-select:none}
.data-grid th[data-sortable]:hover{background:var(--brand-softer)}
.data-grid th[data-sortable] .sa{display:inline-block;width:9px;color:currentColor;font-size:9px;margin-left:4px;opacity:.9}

/* "Tab actions" group flips per tab. Wrapped in a `.tab-actions` container that
   swaps its inner `<div data-tab="N">` on tab change. 29/05/2026 CM: the detail
   rail was removed; the surviving per-tab group is the Tab-4 Batch group now in the
   grid_TOP header, so these rules are rail-independent (no `.detail-rail` ancestor). */
.tab-actions > [data-tab]{display:none}
.tab-actions > [data-tab].is-active{display:block}
.gs-head .tab-actions > [data-tab].is-active{display:flex;align-items:center;gap:6px}
.btn[disabled],
.btn.is-disabled{opacity:.45;pointer-events:none;cursor:not-allowed}

/* Hidden helper rows used by the "Cross_Ref" / Modified-Invoice / Postage
   columns — keep tabular-nums alignment & checkbox dot. */
td.gridcell-check{text-align:center;font-weight:700}
td.gridcell-check.yes{color:var(--ok)}
td.gridcell-check.no{color:var(--ink-4)}
td.gridcell-check.bad{color:var(--danger)}

/* Inline row switch — used in grid_Bottom Process column (replaces ☑/☐).
   Compact iOS-style pill, 32x18, animated knob, brand fill when ON. */
.row-switch{position:relative;display:inline-block;width:32px;height:18px;border-radius:999px;border:none;padding:0;background:var(--line-strong);cursor:pointer;transition:background .15s ease;vertical-align:middle}
.row-switch::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s ease}
.row-switch.on{background:var(--brand)}
.row-switch.on::after{transform:translateX(14px)}
.row-switch:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.row-switch.is-disabled{opacity:.4;cursor:not-allowed}

/* Toggle skin for REAL <input type=checkbox> data fields — visually identical to
   .row-switch above (same 32x18 pill, 14px knob, brand fill when ON) but driven
   by the input's :checked state so the element keeps its id/name/value/checked
   binding and native form POST. Markup:
     <label class="tgl"><input type="checkbox" ...><span class="tgl-track"></span></label>
   The real <input> is visually hidden but stays focusable & serialisable; the
   <span class="tgl-track"> is the pill. Pair with a sibling text label as needed. */
.tgl{position:relative;display:inline-flex;align-items:center;cursor:pointer}
.tgl input{position:absolute;opacity:0;width:32px;height:18px;margin:0;cursor:pointer}
.tgl .tgl-track{position:relative;display:inline-block;width:32px;height:18px;border-radius:999px;background:var(--line-strong);transition:background .15s ease;vertical-align:middle;flex:0 0 auto}
.tgl .tgl-track::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);transition:transform .15s ease}
.tgl input:checked + .tgl-track{background:var(--brand)}
.tgl input:checked + .tgl-track::after{transform:translateX(14px)}
.tgl input:focus-visible + .tgl-track{outline:2px solid var(--brand);outline-offset:2px}
.tgl input:disabled + .tgl-track{opacity:.4;cursor:not-allowed}
.tgl input:disabled{cursor:not-allowed}
/* 14/06/2026 CM — grid Select column rendered as a .tgl toggle (Stock Registry, VB6 parity): centre the
   switch in its cell so it reads as a tidy column of toggles. */
.sel-cell{text-align:center}
.sel-cell .tgl{justify-content:center}

/* ============ Product area (Define / Suppliers / Groups) ============
   29/05/2026  CM  Factor the long inline .tgl override (gap/font-weight/no-caps/ink-2 colour) used
   ~6× across the Product editor screens into one class so toggle alignment stays consistent; the
   .tgl-cell wrapper sits a labelless toggle on the field-grid baseline (spacer label keeps rhythm).
   TIDY-C: the Classification toggles now align to the VAT/Location inputs above them. */
.tgl-inline{gap:8px;font-weight:500;text-transform:none;letter-spacing:0;color:var(--ink-2);font-size:13px;height:32px}
.field-group.tgl-cell{justify-content:flex-end}
.field-group.tgl-cell > label:first-child{visibility:hidden} /* spacer label keeps the baseline */

/* STYLE-D: selects that sit OUTSIDE a .field-group (eg. the Products-list toolbar "All groups"
   filter) get the app standard select look — mirrors .field-group select (line 542 + chevron 555/556)
   so it matches the rest of the app instead of the native OS dropdown. */
select.app-select{appearance:none;height:32px;padding:0 28px 0 11px;border:1px solid var(--line-2);border-radius:var(--r-sm);background-color:var(--panel);font-size:12.5px;color:var(--ink);font-family:var(--font-ui);outline:none;transition:border-color .15s,box-shadow .15s;background-repeat:no-repeat;background-position:right 10px center;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235A6472' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}
select.app-select:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
[data-theme="dark"] select.app-select{background-color:var(--panel-2);background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238896AE' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}

/* GRID-E: Define Product Groups grid — show ~10 rows then scroll (38px row × 10 + ~36px sticky
   header ≈ 416px). Sticky thead (line 1439) keeps the header pinned; overflow-y:auto only kicks in
   past 10 rows and reflows naturally on narrow/short screens (mirrors .autocomplete-list at 1471). */
.grp-grid-scroll{max-height:420px;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch}

/* Per-row action column — appears in the last column of both grid_TOP and
   grid_Bottom. Each row gets a horizontal stack of icon-only buttons whose
   contents flip per active tab (grid_TOP) or per line context (grid_Bottom).
   Buttons are 26px square, colour-coded by intent (primary blue / neutral
   grey / danger red), with the action name in the title attribute. */
td.row-actions,th.row-actions{width:1%;white-space:nowrap;text-align:right;padding-right:10px}
/* Row kebab — single 3-dot button per row that opens the global context menu */
.row-kebab{display:inline-grid;place-items:center;width:26px;height:26px;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--ink-3);cursor:pointer;transition:background .12s,color .12s,border-color .12s;padding:0}
.row-kebab:hover{background:var(--brand-soft);color:var(--brand-deep);border-color:transparent}
.row-kebab.open{background:var(--brand);color:#fff;border-color:transparent}
.row-kebab svg{width:14px;height:14px}

/* Floating context menu — single instance, positioned on the fly next to the
   kebab that triggered it. Each item is icon + label + (optional) accent. */
.row-ctx-menu{position:fixed;z-index:220;min-width:220px;background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-md);box-shadow:var(--shadow-lg);padding:5px;display:none;font-family:var(--font-ui)}
.row-ctx-menu.open{display:block;animation:rcm-in .12s ease-out}
@keyframes rcm-in{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
.row-ctx-menu .rcm-head{padding:7px 10px 5px;font-size:10.5px;font-weight:700;color:var(--ink-4);text-transform:uppercase;letter-spacing:0.12em;border-bottom:1px solid var(--line);margin-bottom:4px;display:flex;align-items:center;gap:8px}
.row-ctx-menu .rcm-head .ref{font-family:var(--font-mono);color:var(--brand);font-size:11.5px;letter-spacing:-0.02em}
.row-ctx-menu .rcm-item{display:flex;align-items:center;gap:9px;padding:8px 11px;font-size:12.5px;color:var(--ink-2);cursor:pointer;border-radius:5px;font-weight:600;border:none;background:transparent;width:100%;text-align:left;line-height:1.2}
.row-ctx-menu .rcm-item:hover{background:var(--brand-soft);color:var(--brand-deep)}
.row-ctx-menu .rcm-item svg{width:14px;height:14px;flex-shrink:0;color:currentColor}
.row-ctx-menu .rcm-item.primary{color:var(--brand-deep)}
.row-ctx-menu .rcm-item.primary:hover{background:var(--brand);color:#fff}
.row-ctx-menu .rcm-item.danger{color:var(--danger)}
.row-ctx-menu .rcm-item.danger:hover{background:var(--danger);color:#fff}
.row-ctx-menu .rcm-item.warn{color:var(--warn)}
.row-ctx-menu .rcm-item.warn:hover{background:var(--warn);color:#fff}
.row-ctx-menu .rcm-item.is-disabled{opacity:.4;pointer-events:none}
.row-ctx-menu .rcm-divider{height:1px;background:var(--line);margin:5px 0}

/* Y/N confirmation modal — share with sales-order-cancel. Already styled by
   .modal-overlay / .modal-window; the additional class .modal-confirm just
   pins the icon colour. */
.modal-confirm .modal-head .ic{background:var(--warn-soft);color:var(--warn)}
.modal-confirm.modal-info .modal-head .ic{background:var(--brand-soft);color:var(--brand)}
.modal-confirm.modal-danger .modal-head .ic{background:var(--danger-soft);color:var(--danger)}

/* 29/05/2026  CM  Shared app modal (appAlert / appConfirm in taliscon-stock.js) — a compact dialog
   variant of the standard .modal-window. Most styling is inherited from .modal-window/.modal-head/
   .modal-body/.modal-foot + the .modal-confirm icon-colour variants; this just adds the small width
   and readable body padding. The responsive breakpoints already full-screen .modal-window, so the
   app modal is responsive (desktop/tablet/phone) for free. */
.modal-window.modal-sm{width:440px}
.app-modal .modal-body.app-modal-body{flex:0 0 auto;padding:18px 20px;background:var(--panel)}
.app-modal .app-modal-body p{font-size:13.5px;line-height:1.5;color:var(--ink-2);margin:0}
.app-modal .modal-head .titles h2{font-size:14px}

/* 29/05/2026  CM  Goods-In receive form — items-table inline inputs (Receive-now qty + Line-comment)
   restyled to the app-standard input look (mirrors .field-group input tokens: --line-2 border,
   --r-sm radius, brand focus ring, readonly + required-invalid states), replacing the ad-hoc inline
   widths. Scoped to the receive table cells so the wider browse data-grids are untouched. */
/* 29/05/2026  CM  GENERALISED in-grid / in-table / in-modal input styling — extended the original
   Goods-In `.items-table td input` look to ALSO cover `.data-grid td` and `.sub-table td` and to
   include <select> + <textarea>, so EVERY inline editor inside a line-item table, browse data-grid
   or modal table (e.g. the PO "Receipt Supplier Invoice" modal's per-line Unit Price / VAT% inputs
   in #poRiLines, and its Postage/Packing tfoot inputs) inherits the app-standard border / radius /
   focus-ring / readonly / disabled / .req-invalid states WITHOUT each view shipping inline styles.
   View agents only need the right shared table class (.items-table | .data-grid | .sub-table) +
   the .req-invalid / numeric / text-right helper classes — no new per-view CSS. The browse grids
   that show plain text cells are untouched (the rule only matches cells that actually contain a
   form control). A :not([type=checkbox]):not([type=radio]):not([type=hidden]) guard keeps row-select
   checkboxes (e.g. .data-grid .reg-sel / .proc-sel) + hidden fields at their native size. */
.items-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.items-table td select,.items-table td textarea,
.data-grid td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.data-grid td select,.data-grid td textarea,
.sub-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.sub-table td select,.sub-table td textarea{width:100%;height:28px;padding:0 9px;border:1px solid var(--line-2);border-radius:var(--r-sm);background-color:var(--panel);font-size:12.5px;color:var(--ink);outline:none;transition:border-color .15s,box-shadow .15s;font-family:var(--font-ui)}
.items-table td textarea,.data-grid td textarea,.sub-table td textarea{height:auto;min-height:48px;padding:6px 9px;resize:vertical;line-height:1.4}
.items-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]):focus,.items-table td select:focus,.items-table td textarea:focus,
.data-grid td input:not([type=checkbox]):not([type=radio]):not([type=hidden]):focus,.data-grid td select:focus,.data-grid td textarea:focus,
.sub-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]):focus,.sub-table td select:focus,.sub-table td textarea:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
.items-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden])[readonly],.items-table td textarea[readonly],
.data-grid td input:not([type=checkbox]):not([type=radio]):not([type=hidden])[readonly],.data-grid td textarea[readonly],
.sub-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden])[readonly],.sub-table td textarea[readonly]{background:var(--panel-3);color:var(--ink-3);cursor:not-allowed}
.items-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]):disabled,.items-table td select:disabled,.items-table td textarea:disabled,
.data-grid td input:not([type=checkbox]):not([type=radio]):not([type=hidden]):disabled,.data-grid td select:disabled,.data-grid td textarea:disabled,
.sub-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]):disabled,.sub-table td select:disabled,.sub-table td textarea:disabled{background:var(--panel-3);color:var(--ink-4);cursor:not-allowed;opacity:.75}
[data-theme="dark"] .items-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),[data-theme="dark"] .items-table td select,[data-theme="dark"] .items-table td textarea,
[data-theme="dark"] .data-grid td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),[data-theme="dark"] .data-grid td select,[data-theme="dark"] .data-grid td textarea,
[data-theme="dark"] .sub-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),[data-theme="dark"] .sub-table td select,[data-theme="dark"] .sub-table td textarea{background-color:var(--panel-2)}
/* In-cell <select> chevron — mirror the .field-group select look (line 555/556) so it doesn't fall
   back to the native OS dropdown inside a grid/table. */
.items-table td select,.data-grid td select,.sub-table td select{appearance:none;padding-right:26px;background-repeat:no-repeat;background-position:right 9px center;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235A6472' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}
[data-theme="dark"] .items-table td select,[data-theme="dark"] .data-grid td select,[data-theme="dark"] .sub-table td select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238896AE' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E")}
/* Required-invalid (empty mandatory) state — same red-ring treatment the .field-group inputs use,
   available to ANY in-cell control via the shared .req-invalid class (so view agents reuse the one
   class, not a per-grid override). */
.items-table td input.req-invalid,.items-table td select.req-invalid,.items-table td textarea.req-invalid,
.data-grid td input.req-invalid,.data-grid td select.req-invalid,.data-grid td textarea.req-invalid,
.sub-table td input.req-invalid,.sub-table td select.req-invalid,.sub-table td textarea.req-invalid{border-color:var(--danger)!important;border-width:2px!important;background-color:rgba(192,57,43,0.06)!important}
[data-theme="dark"] .items-table td input.req-invalid,[data-theme="dark"] .items-table td select.req-invalid,[data-theme="dark"] .items-table td textarea.req-invalid,
[data-theme="dark"] .data-grid td input.req-invalid,[data-theme="dark"] .data-grid td select.req-invalid,[data-theme="dark"] .data-grid td textarea.req-invalid,
[data-theme="dark"] .sub-table td input.req-invalid,[data-theme="dark"] .sub-table td select.req-invalid,[data-theme="dark"] .sub-table td textarea.req-invalid{background-color:rgba(230,115,100,0.1)!important}
/* Required left-border for in-cell controls flagged [data-required] — matches the .field-group cue
   (line 549/550) so the mandatory hint is consistent in grids too. */
.items-table td input[data-required="true"],.items-table td select[data-required="true"],.items-table td textarea[data-required="true"],
.data-grid td input[data-required="true"],.data-grid td select[data-required="true"],.data-grid td textarea[data-required="true"],
.sub-table td input[data-required="true"],.sub-table td select[data-required="true"],.sub-table td textarea[data-required="true"]{border-left-width:3px;border-left-color:rgba(192,57,43,0.32)}
[data-theme="dark"] .items-table td input[data-required="true"],[data-theme="dark"] .items-table td select[data-required="true"],[data-theme="dark"] .items-table td textarea[data-required="true"],
[data-theme="dark"] .data-grid td input[data-required="true"],[data-theme="dark"] .data-grid td select[data-required="true"],[data-theme="dark"] .data-grid td textarea[data-required="true"],
[data-theme="dark"] .sub-table td input[data-required="true"],[data-theme="dark"] .sub-table td select[data-required="true"],[data-theme="dark"] .sub-table td textarea[data-required="true"]{border-left-color:rgba(230,115,100,0.45)}
/* Generic right-aligned numeric in-cell input — replaces ad-hoc inline `style="width:64px;text-align:right"`
   on the PO invoice-receipt Unit Price / VAT% / Postage inputs. Pair with an explicit width utility
   (.w-64 / .w-80 / .w-96) or a column width; defaults to fill the cell. */
.items-table td input.numeric,.data-grid td input.numeric,.sub-table td input.numeric{text-align:right;font-family:var(--font-num);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;font-weight:500}
.items-table td input.mono,.data-grid td input.mono,.sub-table td input.mono{font-family:var(--font-mono);font-variant-numeric:tabular-nums;letter-spacing:-0.02em}
/* Goods-In specific in-cell helpers (unchanged behaviour — kept for the receive table). */
.items-table td input.qty-in{width:96px;text-align:right;font-family:var(--font-num);font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1;font-weight:500}
.items-table td input.line-comment{min-width:140px}
/* Compact width utilities for narrow in-cell numeric editors (PO invoice-receipt grid etc.) so the
   view doesn't need inline widths. */
.items-table td input.w-56,.data-grid td input.w-56,.sub-table td input.w-56{width:56px}
.items-table td input.w-64,.data-grid td input.w-64,.sub-table td input.w-64{width:64px}
.items-table td input.w-80,.data-grid td input.w-80,.sub-table td input.w-80{width:80px}
.items-table td input.w-96,.data-grid td input.w-96,.sub-table td input.w-96{width:96px}

@media (max-width: 1280px){
  .app.module > .content.so-control > .status-rail{flex-basis:220px}
  .app.module > .content.so-control > .detail-rail{flex-basis:300px}
}
@media (max-width: 1100px){
  .app.module > .content.so-control > .status-rail{flex-basis:210px}
  .app.module > .content.so-control > .detail-rail{flex-basis:280px}
}
@media (max-width: 900px){
  .app.module > .content.so-control{flex-direction:column;overflow:auto}
  .app.module > .content.so-control > .status-rail,
  .app.module > .content.so-control > .detail-rail{flex:none;border-right:none;border-bottom:1px solid var(--line)}
  .app.module > .content.so-control > .detail-rail{border-left:none;border-top:1px solid var(--line)}
  /* FIX 3 (28/05/2026 CM): portrait/narrow vertical-scroll fix. When the so-control
     reflows to a single column the page must scroll as ONE document — the desktop
     idiom of two independently-scrolling grids inside an overflow:hidden shell clips
     on a short/narrow portrait viewport (iPad mini 768, phones). Releasing the
     overflow:hidden on the so-main + dual-grid chain (and giving each grid section an
     intrinsic min-height instead of a flex proportion) lets content lay out at its
     natural height so the .content.so-control scroll container (overflow:auto above)
     produces a single page scrollbar. Landscape (>900px) is unaffected — it keeps the
     3-column layout with the internal grid scrollers. */
  .app.module > .content.so-control > .so-main{flex:none;overflow:visible}
  .app.module > .content.so-control .dual-grid{flex:none;overflow:visible}
  .dual-grid .grid-section.gs-top,
  .dual-grid .grid-section.gs-bottom{flex:none;min-height:260px;overflow:visible}
  .dual-grid .grid-section .gs-body{overflow:visible}
}

/* ============================================================================
   29/05/2026  CM  SO CONTROL (+ shared browse) RESPONSIVE OVERFLOW FIX
   ----------------------------------------------------------------------------
   WIDTH-driven equivalents of the touch-only fixes in the
   @media (hover:none) and (pointer:coarse) block (~line 1590). A landscape phone
   / tablet at ~932x430 is WIDER than every old SO breakpoint (900/720/480) yet
   needs the toolbar/tab/grid reflow; a 932px mouse/DevTools window never fires
   the touch query at all. 1024px is the tablet-landscape boundary — safely below
   the desktop 3-grid assumption and above the reported 932px viewport, so it
   covers both without regressing desktop (>=1025px matches none of these). */
@media (max-width: 1024px){
  /* (1) Search toolbar — fluid 2-up wrap; fluid date inputs (beats the inline
         width:130px on #searchFrom/#searchTo); unpin New Order (beats the inline
         margin-left:auto) so it wraps onto its own row instead of forcing width. */
  .reg-toolbar{gap:8px}
  .reg-toolbar .search-box{flex:1 1 calc(50% - 4px);max-width:none}
  .reg-toolbar .search-box input[type="date"]{width:100% !important}
  .reg-toolbar #btnNewOrder{margin-left:0 !important}
  /* (2) Status tab strip — single-row horizontal scroller (not multi-row wrap),
         pills hold their width and the strip scrolls inside .so-main (min-width:0). */
  .workflow-strip{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch}
  .workflow-tab{flex-shrink:0}
  /* (3) Data grids — keep a horizontal scroller even when the document-scroll
         block (below) releases the vertical clip; swap the wide bottom table for
         its parallel card view by WIDTH (previously touch-query only). */
  .dual-grid .grid-section .gs-body{overflow-x:auto !important;-webkit-overflow-scrolling:touch}
  .gs-bottom #gridBottom{display:none}
  .gs-bottom .bottom-cards{display:flex}
}
@media (max-width: 560px){
  /* Single-column search boxes once 50% would be too tight. */
  .reg-toolbar .search-box{flex:1 1 100%}
}

/* ============ Helper utilities ============ */
.muted{color:var(--ink-4)}
.mono-inline{font-family:var(--font-mono);font-size:0.94em;letter-spacing:-0.02em}
.h-spacer{flex:1}
.req-asterisk{color:var(--danger);font-weight:800;margin-left:2px}
.text-right{text-align:right}
.text-num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}

/* ============ Responsive — sidebar collapse for tablets ============ */
@media (max-width: 1280px){
  .nav-rail{width:200px}
  .app.module > .content{grid-template-columns:220px 1fr 300px}
  .summary-strip{grid-template-columns:repeat(4,1fr)}
}
@media (max-width: 1100px){
  .nav-rail{width:64px}
  .nav-rail .nav-head,
  .nav-rail .nav-item span,
  .nav-rail .nav-foot,
  .nav-rail .nav-item .nav-count{display:none}
  .nav-rail a.nav-item{justify-content:center;padding:11px}
  .nav-rail a.nav-item svg{width:18px;height:18px}
  .app.module > .content{grid-template-columns:210px 1fr 280px}
  .form-grid,
  .form-grid.cols-3{grid-template-columns:1fr 1fr}
  .form-row,
  .form-row.cols-5{grid-template-columns:1fr 1fr}
}
@media (max-width: 960px){
  .nav-rail{width:60px}
  /* Move detail-rail (action panel) below the grid as a horizontal-wrap
     button bar — keeps actions reachable on portrait tablet without
     squeezing the data grid below ~480px wide. 5 rows because we now
     have toolbar / status-chip-row / main / detail-rail / (optional) action-bar. */
  .app.module > .content{grid-template-columns:60px 1fr;grid-template-rows:auto auto 1fr auto auto}
  .app.module > .nav-rail{grid-row:3;grid-column:1}
  .content > .status-rail{grid-row:2;grid-column:1 / -1;border-right:none;border-bottom:1px solid var(--line);max-height:none}
  .content > .status-rail .sr-head{display:none}
  .content > .status-rail ul{flex-direction:row;flex-wrap:wrap;padding:8px 10px;gap:5px}
  .content > .status-rail a.sr-item{padding:6px 10px;font-size:12px}
  .content > .reg-toolbar{grid-row:1;grid-column:1}
  .content > .reg-grid{grid-row:3;grid-column:1}
  .content > .detail-rail{grid-row:4;grid-column:1 / -1;border-left:none;border-top:1px solid var(--line);padding:10px 14px;max-height:none;overflow:visible}
  .content > .detail-rail .dr-head{margin-bottom:8px;padding-bottom:8px}
  .content > .detail-rail .ar-group-label{margin:8px 0 4px}
  .content > .detail-rail .ar-btn-stack{flex-direction:row;flex-wrap:wrap;gap:6px}
  .content > .detail-rail .ar-btn-stack .btn{width:auto}
  .content > .action-bar{grid-row:5;grid-column:1}
  .summary-strip{grid-template-columns:repeat(2,1fr)}
}
@media (max-width: 720px){
  .summary-strip{grid-template-columns:1fr}
  .form-grid,
  .form-grid.cols-3,
  .form-row,
  .form-row.cols-2,
  .form-row.cols-3,
  .form-row.cols-5{grid-template-columns:1fr}
}

/* ============================================================================
   SYSTEM-WIDE MOBILE DOCUMENT-SCROLL  (29/05/2026 CM)
   ----------------------------------------------------------------------------
   PROBLEM: the desktop idiom is a fixed-height card shell
   (html,body{height:100%;overflow:hidden} + .app{height:calc(100vh - 40px);
   overflow:hidden}) where ONLY the inner grids scroll. On a phone / tablet /
   small or short window that traps content: the shell can't grow past the
   viewport, the outer overflow:hidden swallows the rest, and large stacked
   forms (SO Items editor, Sales-Order Control single-column reflow, stock
   detail) become partly unreachable because no single scrollbar owns the page.

   FIX: on touch/mobile OR a narrow OR a short viewport, turn the WHOLE shell
   into a normal document-scroll page — html/body scroll, .app/.app.module grow
   to content height with overflow:visible, and every inner scroller listed in
   the brief releases its overflow:hidden + fixed/flex (1fr / calc-vh / %) height
   so the page lays out at its natural height and the browser's own scrollbar
   handles it as ONE document.

   TRIGGER — the comma list is a logical OR:
     (hover:none) and (pointer:coarse)  → real phones + tablets (any orientation)
     (max-width: 900px)                 → narrow windows + DevTools device emulation
     (max-height: 680px)                → short windows / landscape phones where the
                                          fixed-vh shell would clip vertically
   The desktop (hover-capable, wide AND tall) layout matches none of these and is
   left EXACTLY as-is.

   `!important` is used deliberately:
     - to beat the earlier touch rule at line ~1512
       (.app,.app.module{height:100vh !important}),
     - to beat the source-order-later page-scoped <style> rules in
       Views/SalesOrder/Items.cshtml (.items-grid-wrap / .items-grid-main /
       .editor-panel / .items-side, which load after this file in <head>),
     - and to beat the `.app.module > .content.so-control` !important block above.
   ============================================================================ */
@media (hover: none) and (pointer: coarse),
       (max-width: 900px),
       (max-height: 680px){

  /* ---- 1. Make the document itself the scroll container ---- */
  html,
  html body{height:auto !important;min-height:100%;overflow:visible !important;overflow-y:auto !important}
  /* Honour the opt-in scrollable pages here too (they were height:auto already). */
  html.scrollable,
  html.scrollable body{height:auto !important;overflow:visible !important;overflow-y:auto !important}

  /* ---- 2. The shell grows with content instead of pinning to the viewport ---- */
  .app,
  .app.module{height:auto !important;min-height:0 !important;overflow:visible !important}
  html.scrollable .app{min-height:0 !important;overflow:visible !important}

  /* ---- 3. Release the inner scrollers + fixed/flex heights so everything
            flows into the single document scroll. flex:none drops the
            1fr / 46% / 54% proportional heights; overflow:visible drops the
            internal scrollbars; height/min-height auto drops the calc(100%)
            and 100% pins. ---- */
  .content,
  .app.module > .content,
  .content.single,
  .app.module > .content.single,
  .app.module > .app-main,
  .app.module > .app-main > .content,
  .so-main,
  .form-pane,
  .stock-area,
  .dual-grid,
  .dual-grid .grid-section,
  .dual-grid .grid-section.gs-top,
  .dual-grid .grid-section.gs-bottom,
  .stock-area > .stock-main{
    flex:none !important;
    /* 02/06/2026  CM  MOBILE FIX (wide grids clipped + unreachable horizontally): also reset the flex
       min-width:auto floor and cap width to the parent. Without these a wide table's intrinsic
       min-content width (e.g. SO Control's ~1981px 12-column grid) propagates UP the flex chain
       (.gs-body → .grid-section → .dual-grid → .so-main), blowing every ancestor out to ~1981px so the
       grid was clipped at the viewport edge with NO horizontal scroll to reach it. min-width:0 +
       max-width:100% force each container back to the viewport width so the .gs-body scroller below
       actually engages. Verified at 375px: so-main 1981px→361px, table scrolls inside .gs-body. */
    min-width:0 !important;
    max-width:100% !important;
    min-height:0 !important;
    height:auto !important;
    overflow:visible !important;
  }

  /* 29/05/2026  CM  .gs-body removed from the group above: under this document-scroll
     query (esp. landscape phones at max-height:680) the wide top grid has NO card-view
     fallback, so a full overflow:visible would strip its horizontal scroller and let the
     12-column table run off the page unreachably. Release the VERTICAL clip only and KEEP
     a horizontal scroller, so the page document-scrolls vertically while each grid scrolls
     its own overflow horizontally. */
  .dual-grid .grid-section .gs-body{
    flex:none !important;
    /* 02/06/2026  CM  cap to viewport + reset min-width so the wide table overflows THIS scroller
       (overflow-x:auto) instead of expanding it — pairs with the min-width:0/max-width:100% added to
       the ancestor chain above. */
    min-width:0 !important;
    max-width:100% !important;
    min-height:0 !important;
    height:auto !important;
    overflow-y:visible !important;
    overflow-x:auto !important;
    -webkit-overflow-scrolling:touch;
  }

  /* form-pane-grid: stop the fixed 100% height + internal scroll, single column. */
  .form-pane-grid{height:auto !important;overflow:visible !important;grid-template-columns:1fr !important}
  .form-main,
  .form-side{overflow:visible !important}

  /* Sales-Order Control (high-specificity !important block above) — drop the
     row-flex layout to a vertical document flow. The detail rail was removed
     (29/05/2026) so only status-rail + so-main remain. */
  .app.module > .content.so-control{display:flex !important;flex-direction:column !important;overflow:visible !important;height:auto !important;min-height:0 !important}
  .app.module > .content.so-control > .status-rail{flex:none !important;max-height:none !important;overflow:visible !important;border-right:none !important;border-bottom:1px solid var(--line) !important}
  .app.module > .content.so-control > .so-main{flex:none !important;overflow:visible !important;height:auto !important;min-height:0 !important}

  /* stock-area: stack main over detail rail, both flow naturally. */
  .stock-area{display:flex !important;flex-direction:column !important}
  .stock-area > .detail-rail{overflow:visible !important;max-height:none !important;border-left:none !important;border-top:1px solid var(--line) !important}

  /* ---- 4. SO Items editor side-panel chain (page-scoped <style> loads AFTER
            this file, hence !important). Collapse the 2-col grid to a single
            flowing column, release the editor/grid overflow:hidden, and pull
            the side panel (SUPPLIERS table + Line Documents + Line Audit) back
            INTO the flow as a full-width block so its content is reachable
            instead of clipped / display:none. ---- */
  .items-grid-wrap{display:block !important;height:auto !important;min-height:0 !important;overflow:visible !important}
  .items-grid-main{overflow:visible !important;min-height:0 !important}
  /* 29/05/2026  CM  [#2] also release the new fixed/min-height (~5-row) line-grid floor set in
     Items.cshtml so the grid flows into the single document scroll on narrow/touch instead of
     staying pinned to 232px. */
  .items-grid-scroll{height:auto !important;min-height:0 !important;max-height:none !important;overflow:visible !important}
  .editor-panel{overflow:visible !important;min-height:0 !important;height:auto !important}
  /* The relocated supplier grid (full-width table under the Product card) caps at 230px /
     overflow:auto on desktop — release it so it flows into the single document scroll too. */
  .supplier-area{max-height:none !important;overflow:visible !important}
  /* 29/05/2026  CM  FIX (E — dropdown scroll regression): the rules above convert every
     editor ancestor (.editor-panel etc.) to overflow:visible / document-scroll, which strips
     the clipping/scroll context the position:absolute product-search autocomplete list relied
     on — so on a short/narrow/touch viewport a drag over the suggestions scrolled the PAGE
     instead of the list. Re-assert the list's OWN bounded scroll with enough specificity to win
     under this media query, and overscroll-behavior:contain so a touch/wheel gesture that
     reaches the list's top/bottom does NOT chain to the document. The list keeps its absolute
     positioning so it overlays content rather than re-flowing inline. */
  .editor-panel .autocomplete-list,
  .autocomplete .autocomplete-list{
    max-height:260px !important;
    overflow-y:auto !important;
    overscroll-behavior:contain;
    -webkit-overflow-scrolling:touch;
  }
  .items-side{display:block !important;position:static !important;width:auto !important;transform:none !important;
              overflow:visible !important;border-left:none !important;border-top:1px solid var(--line) !important;box-shadow:none !important}
  .items-side.collapsed > .si-body,
  .items-side.unpinned{display:block !important;position:static !important;width:auto !important;transform:none !important;box-shadow:none !important}
}

/* ============================================================================
   SHARED UI FOUNDATION  (29/05/2026 CM)
   ----------------------------------------------------------------------------
   (1) appMenu action-menu (popover + bottom-sheet), (2) app-wide pills,
   (3) dark-mode date inputs. All additive — the legacy .row-ctx-menu /
   .row-kebab / .status-pill / .so-status / .workflow-strip rules are left
   in place; these are the generalised, app-wide successors.
   ============================================================================ */

/* ---- (1) Shared action-menu — viewport-aware popover (JS: appMenu in
            taliscon-stock.js). Built from the same panel/line/brand tokens +
            shadow-lg as the .row-ctx-menu it generalises. overflow-y:auto so a
            list taller than its JS-set max-height scrolls INTERNALLY instead of
            clipping off the viewport top (the old menu's missing guard). ---- */
.app-action-menu{
  position:fixed;z-index:260;min-width:220px;max-width:min(340px, calc(100vw - 16px));
  background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-md);
  box-shadow:var(--shadow-lg);padding:5px;display:none;font-family:var(--font-ui);
  overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
}
.app-action-menu.open{display:block;animation:appmenu-in .12s ease-out}
@keyframes appmenu-in{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
.app-action-menu .app-menu-head{
  padding:7px 10px 5px;font-size:10.5px;font-weight:700;color:var(--ink-4);
  text-transform:uppercase;letter-spacing:0.12em;border-bottom:1px solid var(--line);
  margin-bottom:4px;display:flex;align-items:center;justify-content:space-between;gap:8px;
}
.app-action-menu .app-menu-head .ref{font-family:var(--font-mono);color:var(--brand);font-size:11.5px;letter-spacing:-0.02em;text-transform:none}
.app-action-menu .app-menu-item{
  display:flex;align-items:center;gap:9px;padding:8px 11px;font-size:12.5px;color:var(--ink-2);
  cursor:pointer;border-radius:5px;font-weight:600;border:none;background:transparent;width:100%;
  text-align:left;line-height:1.2;
}
.app-action-menu .app-menu-item:hover,
.app-action-menu .app-menu-item:focus-visible{background:var(--brand-soft);color:var(--brand-deep);outline:none}
.app-action-menu .app-menu-item svg{width:14px;height:14px;flex-shrink:0;color:currentColor}
.app-action-menu .app-menu-item.primary{color:var(--brand-deep)}
.app-action-menu .app-menu-item.primary:hover,
.app-action-menu .app-menu-item.primary:focus-visible{background:var(--brand);color:#fff}
.app-action-menu .app-menu-item.danger{color:var(--danger)}
.app-action-menu .app-menu-item.danger:hover,
.app-action-menu .app-menu-item.danger:focus-visible{background:var(--danger);color:#fff}
.app-action-menu .app-menu-item.warn{color:var(--warn)}
.app-action-menu .app-menu-item.warn:hover,
.app-action-menu .app-menu-item.warn:focus-visible{background:var(--warn);color:#fff}
.app-action-menu .app-menu-item.is-disabled,
.app-action-menu .app-menu-item:disabled{opacity:.4;pointer-events:none}
.app-action-menu .app-menu-divider{height:1px;background:var(--line);margin:5px 0}

/* Bottom action-sheet variant (<=560px, set by appMenu when matchMedia hits). The same singleton
   element drops its anchored position and docks to the bottom edge full-width, over a backdrop. */
.app-action-sheet-backdrop{position:fixed;inset:0;z-index:255;background:rgba(8,30,60,.45);display:none}
.app-action-sheet-backdrop.open{display:block}
[data-theme="dark"] .app-action-sheet-backdrop{background:rgba(0,0,0,.6)}
.app-action-menu.as-sheet{
  position:fixed;left:0;right:0;bottom:0;top:auto;width:100%;min-width:0;max-width:none;
  max-height:70vh;border-radius:var(--r-lg) var(--r-lg) 0 0;border-left:none;border-right:none;border-bottom:none;
  padding:8px 8px calc(8px + env(safe-area-inset-bottom));box-shadow:0 -18px 50px rgba(8,30,60,.30);
  animation:appsheet-in .18s ease-out;
}
@keyframes appsheet-in{from{transform:translateY(100%)}to{transform:translateY(0)}}
.app-action-menu.as-sheet::before{content:'';display:block;width:36px;height:4px;border-radius:2px;background:var(--line-strong);margin:2px auto 8px}
.app-action-menu.as-sheet .app-menu-head{justify-content:center;border-bottom:1px solid var(--line);padding-bottom:8px}
.app-action-menu.as-sheet .app-menu-item{padding:13px 14px;font-size:14px;border-radius:var(--r-md)}
.app-action-menu.as-sheet .app-menu-item svg{width:17px;height:17px}
[data-theme="dark"] .app-action-menu.as-sheet{box-shadow:0 -18px 50px rgba(0,0,0,.6)}

/* ---- (2) App-wide status PILLS — the SO Control pill family generalised into
            reusable names. .pill = the canonical badge; .pill-row = a horizontally
            SCROLLING flex strip so a row of pills overflows-scroll instead of
            wrapping/clipping. Intent + lifecycle variants reuse the same tokens as
            the legacy .status-pill / .so-status (which stay in place). ---- */
.pill{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:11px;font-size:11px;font-weight:700;letter-spacing:0.02em;white-space:nowrap;background:var(--panel-3);color:var(--ink-3)}
.pill::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0}
.pill > .dot{width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block;flex-shrink:0}
.pill:has(> .dot)::before{display:none}
/* Intent variants (semantic, theme-token driven). */
.pill.pill-brand {background:var(--brand-soft); color:var(--brand-deep)}
.pill.pill-ok    {background:var(--ok-soft);    color:var(--ok)}
.pill.pill-warn  {background:var(--warn-soft);  color:var(--warn)}
.pill.pill-danger{background:var(--danger-soft);color:var(--danger)}
.pill.pill-purple{background:var(--purple-soft);color:var(--purple)}
.pill.pill-grey  {background:var(--panel-3);    color:var(--ink-3);border:1px solid var(--line)}
.pill.pill-grey::before{background:var(--ink-4)}
.pill.pill-none  {background:transparent;color:var(--ink-4);border:1px dashed var(--line-strong)}
.pill.pill-none::before{background:var(--ink-4)}
/* Lifecycle status variants — uppercase, mapped 1:1 to the .so-status.s-<LETTER>
   palette so a migrated form can use either name and get the same colour. */
.pill.pill-status{text-transform:uppercase;letter-spacing:0.04em}
.pill.pill-s-O{background:var(--brand-soft); color:var(--brand-deep)}
.pill.pill-s-P{background:var(--warn-soft);  color:var(--warn)}
.pill.pill-s-I{background:var(--purple-soft);color:var(--purple)}
.pill.pill-s-D{background:#DBEAFE;           color:#0369A1}
.pill.pill-s-C{background:var(--ok-soft);    color:var(--ok)}
.pill.pill-s-X{background:var(--danger-soft);color:var(--danger)}
.pill.pill-s-R{background:var(--panel-3);    color:var(--ink-3);border:1px solid var(--line)}
.pill.pill-s-R::before{background:var(--ink-4)}
[data-theme="dark"] .pill.pill-s-D{background:rgba(56,128,255,.22);color:#7AB6FF}
/* Horizontally-scrolling pill strip — a row of pills that scrolls on overflow
   (the SO Control workflow-strip behaviour, available app-wide for any pill row). */
.pill-row{display:flex;align-items:center;gap:6px;overflow-x:auto;flex-wrap:nowrap;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;scrollbar-width:thin}
.pill-row > *{flex-shrink:0}
.pill-row::-webkit-scrollbar{height:6px}
.pill-row::-webkit-scrollbar-thumb{background:var(--line-strong);border-radius:3px}
/* 29/05/2026  CM  Selectable pill strip — a .pill-row used as a STATUS SELECTOR
   (the SO Control workflow-strip role, re-expressed with the app-wide .pill family).
   .pill-select tags a clickable toggle pill (button) inside such a strip: it keeps
   the .pill / .pill-status / .pill-s-<LETTER> palette but adds button affordances
   (taller hit target, hover, an .active selected state, and a trailing count badge).
   Scoped to .pill-select so static .pill badges elsewhere are unaffected. Used by
   PO Control's status strip (Views/PurchaseOrder/Index.cshtml). */
.pill-row.pill-strip{padding:8px 16px;background:var(--panel);border-bottom:1px solid var(--line);flex-shrink:0}
.pill.pill-select{height:28px;padding:0 12px;border-radius:14px;cursor:pointer;font-family:inherit;border:1px solid var(--line-2);transition:background .12s,color .12s,border-color .12s;text-transform:none;letter-spacing:-0.003em;font-size:12px}
.pill.pill-select::before{display:none}
.pill.pill-select:hover{background:var(--panel-3);color:var(--ink)}
.pill.pill-select .ps-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--ink-4)}
.pill.pill-select .ps-count{font-variant-numeric:tabular-nums;font-size:10.5px;padding:1px 6px;border-radius:8px;background:var(--panel-3);color:var(--ink-3);font-weight:700;min-width:18px;text-align:center;margin-left:2px}
.pill.pill-select.active{background:var(--brand-soft);color:var(--brand-deep);border-color:var(--brand-soft)}
.pill.pill-select.active .ps-count{background:var(--brand);color:#fff}
.pill-strip .pill-state{display:inline-flex;align-items:center;gap:6px;font-size:11px;font-weight:600;color:var(--ink-3);padding:5px 10px;border-radius:11px;background:var(--panel);border:1px solid var(--line-2);margin-left:auto;white-space:nowrap}
.pill-strip .pill-state svg{width:11px;height:11px;flex-shrink:0}
.pill-strip .pill-state.active{background:var(--ok-soft);color:var(--ok);border-color:transparent}

/* ---- (3) Dark-mode DATE INPUTS — color-scheme (on :root, above) does the heavy
            lifting (re-themes the placeholder + native picker chrome). Here we pin
            the segment text to theme ink, fade the placeholder segments, and re-tint
            the calendar-picker glyph so it reads on the dark field (mirroring the
            select-chevron light/dark precedent). Colour/appearance ONLY — width,
            border, height come from the existing .search-box / .field-group / generic
            input rules, which are untouched. ---- */
input[type="date"]::-webkit-datetime-edit{color:var(--ink)}
input[type="date"]::-webkit-datetime-edit-text{color:var(--ink-3)}
input[type="date"]::-webkit-datetime-edit-month-field,
input[type="date"]::-webkit-datetime-edit-day-field,
input[type="date"]::-webkit-datetime-edit-year-field{color:var(--ink)}
/* Empty (placeholder) segments read as muted ink in both themes. */
input[type="date"]:in-range::-webkit-datetime-edit-year-field[aria-valuetext="blank"],
input[type="date"]::-webkit-datetime-edit-month-field[aria-valuetext="blank"],
input[type="date"]::-webkit-datetime-edit-day-field[aria-valuetext="blank"],
input[type="date"]::-webkit-datetime-edit-year-field[aria-valuetext="blank"]{color:var(--ink-4)}
[data-theme="dark"] input[type="date"]::-webkit-datetime-edit{color:var(--ink)}
[data-theme="dark"] input[type="date"]::-webkit-datetime-edit-text{color:var(--ink-3)}
/* The calendar dropdown glyph renders as a dark UA icon by default — invert it in dark mode so it
   reads on the dark field (filter:invert mirrors the paging .pp-select chevron light/dark swap). */
[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator{filter:invert(1) brightness(1.7)}
input[type="date"]::-webkit-calendar-picker-indicator{cursor:pointer;opacity:.7;transition:opacity .12s}
input[type="date"]::-webkit-calendar-picker-indicator:hover{opacity:1}

/* ============================================================================
   30/05/2026  CM  SHARED loading overlay (.app-loading-overlay) — see the JS
   module window.loadingOverlay in taliscon-stock.js. Absolute-positioned over
   the main content host (.app-main / .content); .full-screen pins it to the
   viewport when the host falls back to <body>. A semi-transparent scrim built
   from the panel token (so it works in light + dark) with a centred CSS spinner
   ring + "Loading…" label. Hidden by default; .show fades it in. z-index 120
   keeps it above content/breadcrumb (z-50/80) but below the modal scrim (z-150)
   and toasts (z-300) so a load that resolves into a modal layers correctly.
   ============================================================================ */
.app-loading-overlay{
  position:absolute;inset:0;z-index:120;display:flex;align-items:center;justify-content:center;
  background:color-mix(in srgb,var(--panel) 62%,transparent);
  backdrop-filter:blur(1.5px);
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .15s ease;
}
.app-loading-overlay.show{opacity:1;visibility:visible;pointer-events:auto}
.app-loading-overlay.full-screen{position:fixed}
.app-loading-box{
  display:flex;flex-direction:column;align-items:center;gap:12px;
  padding:18px 26px;border-radius:var(--r-lg);
  background:var(--panel);border:1px solid var(--line-2);box-shadow:var(--shadow-lg);
}
.app-loading-spinner{
  width:34px;height:34px;border-radius:50%;
  border:3px solid var(--line-2);border-top-color:var(--brand);
  animation:app-spin .7s linear infinite;
}
.app-loading-label{
  font-size:12.5px;font-weight:600;color:var(--ink-2);letter-spacing:-0.003em;
}
@keyframes app-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .app-loading-spinner{animation-duration:1.4s}
}

/* ============================================================================
   30/05/2026  CM  App-wide GRID CELL TRUNCATION utility (.cell-clip) — drop it
   on a <td>/<th> to make that cell truncate its overflow with an ellipsis on a
   single line. max-width:0 lets a table cell actually shrink below its content
   width (table-layout default sizes to content otherwise), so the cell takes
   only its fair share of the row and ellipsises the rest; a caller may set an
   explicit max-width inline (style="max-width:240px") to cap how wide it grows.
   Theme-agnostic (colour/font untouched — purely overflow geometry). The FULL
   text is surfaced on hover via the delegated cellTitle handler in
   taliscon-stock.js, which lazily sets title=textContent only when the cell is
   actually clipped — so this utility needs ZERO extra per-cell markup.
   ============================================================================ */
.cell-clip{max-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ============================================================================
   TABLET / TOUCH TARGET PASS  (13/06/2026 CM)
   ----------------------------------------------------------------------------
   The portal runs on iPad / iPad-mini on the warehouse + shop floor. Two touch
   media blocks already exist higher up: ~line 1280 (modest 32-36px tap polish)
   and ~line 1740 (layout reflow + the bottom-card swap). This block sits LAST so
   it wins the cascade, and lifts the remaining interactive controls to the 44px
   WCAG-AAA minimum touch target.

   Why min-width/min-height (not width/height): several controls carry a fixed
   width/height from a MORE specific selector (e.g. `.bc-kebab .row-kebab{26px}`).
   A generic `.row-kebab{width:44px}` would lose that specificity fight, but
   `min-width:44px` is a DIFFERENT property that simply clamps the computed size
   UP to 44px regardless of which rule set `width` — so we win without chasing
   every specific selector. Desktop (fine pointer) never matches this block.
   ============================================================================ */
@media (hover: none) and (pointer: coarse){
  /* --- Standalone buttons / icon affordances --- */
  .btn{min-height:44px}
  .icon-circle{min-width:44px;min-height:44px}
  .row-kebab{min-width:44px;min-height:44px}      /* also clamps .bc-kebab .row-kebab (26px) up */
  .modal-head .modal-x{min-width:44px;min-height:44px}
  /* The tablet SO bottom-card kebab sits in a FIXED 30px grid track — widen it to 44px in BOTH
     layouts so the enlarged kebab above doesn't overflow into the gross/process column. */
  .bc-colhead,.bc-header{grid-template-columns:20px minmax(0,1fr) 38px 72px 44px}
  .bottom-cards.avail-on .bc-colhead,
  .bottom-cards.avail-on .bc-header{grid-template-columns:20px minmax(0,1fr) 38px 72px 66px 48px 44px}

  /* --- Banner controls (help / theme toggle / user chip / sign out) --- */
  .help-btn,.signout-btn,.theme-toggle{min-height:44px}
  .theme-toggle{min-width:44px}
  .user-chip{min-height:44px}

  /* --- Grid row-select checkboxes: enlarge the box AND its cell so the whole
         cell is an easy tap, not just the 16px native control. --- */
  .sel-cell{min-width:44px}
  .data-grid td.sel-cell,.items-table td.sel-cell{padding-top:6px;padding-bottom:6px}
  .reg-sel,.so-sel,.proc-sel,.sel-cell input[type=checkbox]{width:22px;height:22px;cursor:pointer}
  /* 14/06/2026 CM — the Select toggle's hidden input can't grow the tap target; pad the .tgl label
     (the real click target) so the whole switch stays an easy fingertip hit on touch. */
  .sel-cell .tgl{padding:6px}

  /* --- In-cell editors: 28px is too small for a fingertip; grow to 40px. The
         textarea floor (48px) higher up already clears the bar. --- */
  .items-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.items-table td select,
  .data-grid td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.data-grid td select,
  .sub-table td input:not([type=checkbox]):not([type=radio]):not([type=hidden]),.sub-table td select{height:40px}

  /* --- Kebab / action-menu items: fatten the rows so neighbours aren't mis-tapped. --- */
  .app-action-menu .app-menu-item{min-height:44px;padding:11px 14px}

  /* --- Modal footer: bigger tap targets, side-by-side preserved on the roomy
         iPad widths (the modal is ~95vw, plenty of room for two buttons). --- */
  .modal-foot .btn{min-height:46px}
}

/* On a genuinely NARROW touch screen (phone / iPad split-view) the right-aligned
   button pair gets cramped, so there we stack them full-width with the hint above. */
@media (hover: none) and (pointer: coarse) and (max-width: 640px){
  .modal-foot{flex-direction:column;align-items:stretch;gap:10px}
  .modal-foot .btn{width:100%}
  .modal-foot .left{margin-right:0;justify-content:center}
}
