/* Hornback IMS V4 — Design tokens (source of truth for colors, fonts, spacing, motion).
   ─────────────────────────────────────────────────────────────────────────────────────
   2026-05-23 — Industrial design-port (Batch 1): cool steel ink ramp + factory-saturated
   orange + warm "blueprint paper" canvas + three-font system (Antonio display / Hanken
   Grotesk UI / JetBrains Mono codes). The earlier Poppins / warm-slate tokens are gone.
   See Claude DB/RULES-V4.md U-rules section and the design-mockups/vendors-industrial.html
   reference for the visual direction this implements. */

:root {
  /* ── Brand identity (Hornback) — factory-saturated orange ramp ── */
  --brand-orange:        #F97316;            /* primary brand · #F97316 same as before, just confirming */
  --brand-orange-hover:  #EA580C;            /* darker on hover, was #EA6C0A */
  --brand-orange-soft:   #FFEDD5;            /* tinted bg for soft accents */
  --orange-100:          #FFEDD5;            /* alias for mockup parity */
  --orange-50:           #FFF7ED;            /* lightest tint (badges, hover bg) */

  /* ── Ink (cool steel ramp) — replaces warm slate. Subtle cool shift across all surfaces. ── */
  --ink-950: #0A0F14;                        /* deepest — topbar, bulk-action bar */
  --ink-900: #11181F;                        /* primary text on light, dark sidebar */
  --ink-800: #1B232C;                        /* secondary dark surface */
  --ink-700: #303A45;                        /* body text strong */
  --ink-600: #4A5663;                        /* body text */
  --ink-500: #6A7686;                        /* meta text, labels */
  --ink-400: #8E99A8;                        /* placeholder, muted */
  --ink-300: #B5BDC8;                        /* borders, dividers */
  --ink-200: #D6DCE3;                        /* subtle borders */
  --ink-150: #E4E8ED;                        /* hover bg, header alt */
  --ink-100: #EEF1F4;                        /* row stripe, thead bg */
  --ink-50:  #F6F8FA;                        /* lightest gray surface */

  /* ── Surfaces — warm off-white "blueprint paper" canvas ── */
  --paper:   #FBFAF7;                        /* warm off-white — replaces pure white */
  --canvas:  #F2EFEA;                        /* slight warm cream — main bg */

  /* ── Brand purple (Sub-Assemblies section accent) ── */
  --brand-purple:      #6D28D9;
  --brand-purple-soft: #EDE9FE;

  /* ── Industrial blue (primary action) ── */
  --accent:        #1E40AF;
  --accent-hover:  #1E3A8A;
  --accent-pressed:#172E6E;
  --accent-soft:   #DBEAFE;
  --accent-ring:   rgba(30, 64, 175, .25);

  /* ── Status semantics ── */
  --success:      #15803D; --success-soft: #DCFCE7;
  --warning:      #B45309; --warning-soft: #FEF3C7;
  --danger:       #B91C1C; --danger-soft:  #FEE2E2;
  --danger-ring:  rgba(185, 28, 28, .25);
  --info:         #1E40AF; --info-soft:    #DBEAFE;
  --purple:       #7E22CE; --purple-soft:  #FDF4FF;   /* expenses / HR accent */

  /* ── On-dark variants (for use on navy/dark hero bands) ── */
  --brand-orange-300: #FB923C;  /* orange on dark */
  --info-300:         #60A5FA;  /* blue on dark */
  --danger-300:       #F87171;  /* red on dark */
  --success-300:      #34D399;  /* green on dark */
  --warning-300:      #FDE68A;  /* amber on dark */

  /* ── Extended accent palette ── */
  --info-light:    #3B82F6;   /* lighter info-blue (stat tiles on white) */
  --sky:           #0EA5E9;   /* sky-blue (sub-asm / inward stats) */
  --pink:          #EC4899;   /* hot-pink (paint/consumables stats) */
  --fuchsia:       #BE185D;   /* fuchsia (paint-stage production) */
  --fab-accent:    #9A3412;   /* fabrication dark-orange */
  --danger-dark:   #7F1D1D;   /* critical severity — darkest red */
  --warning-light: #F59E0B;   /* amber mid-tone (lighter than --warning) */

  /* ── Convenience aliases (short form used by HR pages + newer components) ── */
  --border:   var(--ink-300);       /* border-default shorthand */
  --bg-alt:   var(--ink-50);        /* alternate surface (row stripe, card fill) */
  --bg-page:  var(--paper);         /* page / panel background */

  /* ── Pill palettes ── */
  --pill-paint-bg:   #FEE2E2; --pill-paint-fg:   #991B1B;
  --pill-parts-bg:   #DBEAFE; --pill-parts-fg:   #1E40AF;
  --pill-cons-bg:    #FEF3C7; --pill-cons-fg:    #92400E;
  --pill-service-bg: #EDE9FE; --pill-service-fg: #5B21B6;
  --pill-mixed-bg:   #D1FAE5; --pill-mixed-fg:   #065F46;
  --pill-deleted-bg: #FECACA; --pill-deleted-fg: #7F1D1D;

  /* ── Typography — three-font industrial system (Batch 1 port, 2026-05-23) ── */
  --font-display: 'Antonio', 'Hanken Grotesk', system-ui, sans-serif;        /* condensed display: page titles, brand mark */
  --font-ui:      'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;  /* body, controls, labels */
  --font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Consolas, monospace;  /* codes, IDs, meta-caps labels, tabular numbers */
  --fs-2xs: 10px; --fs-xs: 11px; --fs-sm: 12px; --fs-13: 13px;
  --fs-base: 14px; --fs-md: 16px; --fs-lg: 20px; --fs-xl: 24px; --fs-2xl: 30px;
  --fs-display: 56px;                        /* page-title display size (Antonio) */
  --fw-regular: 400; --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700;
  --lh-tight: 1.1; --lh-snug: 1.25; --lh-base: 1.45; --lh-relaxed: 1.6;
  --ls-tight: -0.02em; --ls-snug: -0.005em;
  --ls-wide: 0.04em;  --ls-wider: 0.06em; --ls-widest: 0.08em;
  --ls-mono-caps: 0.14em;                    /* meta-caps tracking (mono labels, eyebrows) */

  /* ── Spacing (8px base) ── */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
  --space-12: 48px; --space-16: 64px;

  /* ── Radius ──
     Industrial port direction (Batch 1, 2026-05-23): sharp corners across the board.
     The old --r-* tokens stay for backward compatibility while later batches restyle the
     specific components (buttons, pills, cards, modals). --radius-sharp is the target
     for everything except inherently-circular UI (avatars, color swatches). */
  --radius-sharp: 0;
  --r-sm: 4px; --r-md: 6px; --r-lg: 8px; --r-xl: 12px;
  --r-pill: 10px; --r-full: 9999px;

  /* ── Elevation ── */
  --shadow-sm: 0 1px 2px rgba(15,23,42,.06);
  --shadow-md: 0 4px 8px rgba(15,23,42,.08);
  --shadow-lg: 0 10px 25px rgba(15,23,42,.10);
  --shadow-xl: 0 20px 50px rgba(15,23,42,.18);
  --shadow-panel: -8px 0 24px rgba(15,23,42,.12);

  /* ── Layout ── */
  --topbar-h: 44px;
  --toolbar-h: 64px;
  --sidebar-w: 220px;
  --sidebar-w-collapsed: 74px;   /* widened for the icon + small label collapsed rail (2026-06-15) */
  --panel-w: 560px;
  --row-h: 36px;
  --field-h: 36px;
  --btn-h: 32px;

  /* ── Motion ── */
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur-fast: 120ms; --dur-base: 180ms; --dur-slow: 280ms;

  /* ── Z-index ── */
  --z-toolbar: 10; --z-sidebar: 20; --z-topbar: 30;
  --z-panel: 40; --z-modal-overlay: 50; --z-modal: 51;
  --z-toast: 60; --z-dropdown: 45;
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 0ms; --dur-base: 0ms; --dur-slow: 0ms; }
}

/* ===== Global resets + base typography ===== */

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  letter-spacing: var(--ls-snug);
  color: var(--ink-800);
  background: var(--canvas);
  line-height: var(--lh-base);
  font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
}

code, .num, input[type="number"], input[inputmode="numeric"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

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

h1 { font-size: var(--fs-xl); letter-spacing: var(--ls-tight); margin: 0 0 var(--space-4); font-weight: var(--fw-bold); }
h2 { font-size: var(--fs-lg); letter-spacing: var(--ls-tight); font-weight: var(--fw-semibold); margin: 0; }
h3 { font-size: var(--fs-md); font-weight: var(--fw-semibold); margin: 0 0 var(--space-2); }
h4 { font-size: var(--fs-base); font-weight: var(--fw-semibold); margin: 0 0 var(--space-2); }

/* ===== App shell (sidebar + topbar layout) ===== */
.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-areas:
    "sidebar topbar"
    "sidebar main";
  min-height: 100vh;
}

/* ── Topbar ── */
/* MR-3 2026-05-29 — nav progress bar (Vercel-style). Sits as the very first
   element of .app-shell at top: 0 / z-index: max so it paints above the topbar.
   .is-loading triggers a 600ms left→right sweep. Animation auto-clears via JS
   (app.js initNavProgress / startNavProgress) when the new page mounts. */
.nav-progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--brand-orange) 30%,
    var(--brand-orange) 70%,
    transparent 100%);
  transform: translateX(-100%);
  opacity: 0;
  pointer-events: none;
  z-index: 9999;
  transition: opacity 120ms ease;
}
.nav-progress-bar.is-loading {
  opacity: 1;
  animation: hb-nav-progress-sweep 600ms cubic-bezier(.4,0,.2,1) forwards;
}
@keyframes hb-nav-progress-sweep {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(20%); }
  100% { transform: translateX(100%); }
}

/* Topbar — dark ink-950 background. The original industrial-port treatment
   (orange border-bottom + dashed "factory tape" ::after stripe) was overridden
   by v32-theme.css (2026-06-03 V3.2 visual port). Both dead overrides removed
   in M3 Batch J · 2026-06-09 — v32-theme now provides the only border-bottom
   (faint hairline) and there's no ::after stripe at all. */
.app-topbar {
  grid-area: topbar;
  background: var(--ink-950);
  color: var(--paper);
  border-top: none;
  padding: 0 var(--space-6);
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
}
.topbar-left { display: flex; align-items: center; gap: var(--space-3); flex: 1 1 auto; min-width: 0; }

/* Brand mark — Antonio condensed display font, uppercase, wide tracking — the topbar's
   signature character moment. White on the dark topbar, orange on hover. */
a.brand-mark, .brand-mark {
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  font-size: 18px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--paper);
  text-decoration: none;
  cursor: pointer;
}
a.brand-mark:hover { color: var(--brand-orange); text-decoration: none; }
/* ENV badge — factory mono-caps tag next to brand mark. Saturated orange against the
   topbar's ink — instantly tells the operator which environment they're in. Sharp corners
   to match the industrial port direction. */
.env-badge {
  background: var(--brand-orange);
  color: var(--ink-950);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: var(--fw-bold);
  padding: 2px 7px;
  border-radius: var(--radius-sharp);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-sm);
}
.user-name { font-weight: var(--fw-semibold); color: var(--ink-900); }
.user-role {
  background: var(--ink-100);
  color: var(--ink-700);
  padding: 2px var(--space-2);
  border-radius: var(--r-pill);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
}
.logout-btn, .login-link {
  background: var(--ink-100);
  color: var(--ink-700);
  border: 1px solid var(--ink-200);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--r-md);
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  font-family: inherit;
}
.logout-btn:hover, .login-link:hover {
  background: var(--ink-200);
  color: var(--ink-900);
  text-decoration: none;
}
.login-link { background: var(--accent); color: var(--paper); border-color: var(--accent); }
.login-link:hover { background: var(--accent-hover); color: var(--paper); }

/* ── Sidebar ── */
.app-sidebar {
  grid-area: sidebar;
  background: var(--ink-900);
  color: var(--ink-300);
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: var(--z-sidebar);
  display: flex;                      /* Rule U26 — flex column so toggle pins to bottom */
  flex-direction: column;
  min-height: 0;
}
.sidebar-nav {
  padding: var(--space-4) 0;
  flex: 1 1 auto;                     /* Rule U26 — nav takes all space, toggle stays at bottom */
  overflow-y: auto;
  min-height: 0;
}
.nav-group { margin-bottom: var(--space-5); }
/* Nav group label — Batch 2: JetBrains Mono caps with wider tracking. Reads as factory
   wayfinding ("MASTER DATA", "ACTIVITY", "ADMIN") instead of soft web section headings. */
.nav-group-label {
  padding: 0 var(--space-4);
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: var(--fw-regular);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: var(--space-2);
}
/* Batch 2.5 · 2026-06-08 — sidebar groups are now <details>/<summary>. Style the summary
   to look like the static label, with a subtle ▸/▾ disclosure indicator. cursor:pointer +
   no native arrow (we use ::before for our own ▸/▾). */
summary.nav-group-label {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
summary.nav-group-label::-webkit-details-marker { display: none; }
summary.nav-group-label::before {
  content: "▸";
  font-size: 10px;
  color: var(--ink-500);
  transition: transform 120ms ease;
  display: inline-block;
}
details[open] > summary.nav-group-label::before { transform: rotate(90deg); }
summary.nav-group-label:hover { color: var(--ink-100); }
.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-13);
  color: var(--ink-300);
  cursor: pointer;
  border-left: 3px solid transparent;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.nav-item:hover {
  background: var(--ink-800);
  color: var(--paper);
  text-decoration: none;
}
.nav-item.active {
  background: var(--ink-800);
  color: var(--paper);
  border-left-color: var(--brand-orange);
  font-weight: var(--fw-semibold);
}
.nav-icon { width: 18px; text-align: center; flex-shrink: 0; }
/* Batch 6 · 2026-06-13 — a nested child nav item (e.g. Factory expenses under Expenses). */
.nav-item-sub { padding-left: calc(var(--space-4) * 2); font-size: var(--fs-12); }
.nav-item-disabled {
  color: var(--ink-500);
  cursor: not-allowed;
  opacity: .7;
}
.nav-item-disabled:hover {
  background: transparent;
  color: var(--ink-500);
}
/* SOON pill — Batch 2: factory wayfinding tag in mono caps. Sharp corners, ink-700 bg
   on ink-400 text — sits inside the dark sidebar without the soft-pill SaaS look. */
.nav-soon {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 8px;
  background: var(--ink-700);
  padding: 1px 5px;
  border-radius: var(--radius-sharp);
  color: var(--ink-400);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* ── Main content area ── */
.app-main {
  grid-area: main;
  position: relative;          /* anchor for the ::before dot grid (Batch 3) */
  padding: var(--space-6);
  overflow-x: auto;
  /* No max-width — operator-grade, full-width tables */
}
/* Blueprint dot grid — Batch 3 industrial port (2026-05-23). Subtle factory-floor
   texture across the main canvas. 4% opacity dots on a 20px lattice, behind all
   content. pointer-events:none so it never blocks clicks. Tune opacity in the rgba()
   if too prominent (try 0.025) or invisible (try 0.06) on a given monitor. */
.app-main::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle, rgba(0, 0, 0, 0.04) 1px, transparent 1px);
  background-size: 20px 20px;
  pointer-events: none;
  z-index: 0;
}
/* z-index removed — it was creating a stacking context that trapped position:fixed
   dropdowns (z=45) behind the sticky topbar (z=30). Content still above the dot layer
   (::before at z=0) because positioned auto-z elements paint after explicit z=0 elements. */
.app-main > * { position: relative; }

/* ── Collapsed sidebar (toggle from topbar) ── */
.app-shell.sidebar-collapsed {
  grid-template-columns: var(--sidebar-w-collapsed) 1fr;
}
.app-shell.sidebar-collapsed .nav-label,
.app-shell.sidebar-collapsed .nav-group-label,
.app-shell.sidebar-collapsed .nav-soon {
  display: none;
}
.app-shell.sidebar-collapsed .nav-item {
  justify-content: center;
  padding: var(--space-3) 0;
  gap: 0;
}
.app-shell.sidebar-collapsed .nav-icon {
  font-size: 18px;
}
.app-shell.sidebar-collapsed .nav-group {
  margin-bottom: var(--space-2);
  border-top: 1px solid var(--ink-800);
  padding-top: var(--space-2);
}
.app-shell.sidebar-collapsed .nav-group:first-child {
  border-top: none;
  padding-top: 0;
}

/* ===== Login page ===== */
/* Login shell — Batch 6 industrial port. Dark ink-950 background with a subtle
   blueprint dot grid. The login card becomes a sharp-cornered paper panel with
   Antonio uppercase title + 4px orange anchor strip on its top edge. */
.login-shell {
  min-height: 100vh;
  background: var(--ink-950);
  background-image: radial-gradient(circle, rgba(255,255,255,0.04) 1px, transparent 1px);
  background-size: 24px 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.login-card {
  position: relative;
  background: var(--paper);
  padding: 36px 32px 32px;
  border-radius: var(--radius-sharp);
  border-top: 4px solid var(--brand-orange);
  box-shadow: 0 24px 60px rgba(0,0,0,.5);
  width: 100%;
  max-width: 380px;
}
.login-card h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-950);
  line-height: 1;
}
.login-card .subtitle {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.15em;
  color: var(--ink-500);
  text-transform: uppercase;
  margin: 8px 0 28px;
}
.login-card label {
  display: block;
  margin-top: var(--space-4);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  font-weight: var(--fw-medium);
  color: var(--ink-700);
  text-transform: uppercase;
}
/* Login card field — Batch 5 industrial chrome. Sharp corners + orange focus. */
.login-card .field {
  width: 100%;
  padding: 9px 12px;
  min-height: 40px;
  margin-top: 4px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sharp);
  font-size: 14px;
  background: var(--paper);
  transition: border-color var(--dur-fast);
}
.login-card .field:focus {
  outline: none;
  border-color: var(--brand-orange);
  box-shadow: 0 0 0 3px rgba(245,133,10,.2);
}
.login-card .validation-message { color: var(--danger); font-size: 12px; margin-top: 4px; }
.login-btn {
  margin-top: 24px;
  width: 100%;
  padding: 12px;
  min-height: 40px;
  background: var(--ink-950);
  color: var(--paper);
  border: 1px solid var(--ink-950);
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  border-radius: 6px;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.login-btn:hover { background: var(--brand-orange); border-color: var(--brand-orange); color: var(--ink-950); }
.login-btn:focus-visible { outline: 3px solid var(--brand-orange); outline-offset: 2px; }
.alert-error {
  background: var(--danger-soft);
  color: var(--danger);
  padding: 10px 14px;
  border-radius: 6px;
  border-left: 4px solid var(--danger);
  font-size: 13px;
  margin-bottom: 12px;
}

/* ===== Welcome / Home page ===== */
/* Home page — Batch 6 industrial port (2026-05-23). Status-board greeting + sharp
   quick-card tiles with mono-caps eyebrow + Antonio title + orange-anchor on hover.
   Mirrors the page-toolbar anchor-bar pattern but for an entry-page context. */
.welcome {
  position: relative;
  padding-left: 16px;
}
.welcome::before {
  content: "";
  position: absolute;
  left: 0; top: 4px; bottom: 4px;
  width: 4px;
  background: var(--brand-orange);
}
.welcome h1 {
  font-family: var(--font-display);
  font-size: 56px;
  font-weight: var(--fw-bold);
  line-height: 0.95;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--ink-950);
  margin: 0 0 8px;
}
.welcome .role-line {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--ink-500);
  text-transform: uppercase;
  margin-bottom: 32px;
}
.welcome .role-line strong { color: var(--ink-900); font-weight: var(--fw-medium); }
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 14px;
  margin: 24px 0;
}
.quick-card {
  position: relative;
  background: var(--paper);
  padding: 20px 22px 22px;
  border-radius: var(--radius-sharp);
  border: 1px solid var(--ink-200);
  color: var(--ink-900);
  text-decoration: none;
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.quick-card::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: transparent;
  transition: background var(--dur-fast);
}
.quick-card:hover {
  border-color: var(--ink-600);
  background: var(--paper);
  text-decoration: none;
}
.quick-card:hover::before { background: var(--brand-orange); }
.quick-card h3 {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-950);
  margin: 0 0 4px;
}
.quick-card p {
  font-family: var(--font-ui);
  color: var(--ink-500);
  font-size: 13px;
  margin: 0;
}
.hint {
  color: var(--ink-500);
  font-size: 12px;
  font-style: italic;
  font-family: var(--font-ui);
}

/* ===== Tables =====
   Batch C8 follow-up (2026-05-24) — NO horizontal scroll. All columns squeeze into the visible
   width via auto layout + ellipsis truncation (Rule U35). When too many columns are visible to
   read comfortably, the operator hides some via the ⚙ gear (Rule U21). This matches the ngrok
   behavior the user preferred and eliminates "columns hidden behind the right edge" on localhost.
   - overflow-x: hidden     — no scrollbar; columns shrink to fit
   - overflow-y: auto + max-height — vertical scroll inside the wrap so sticky thead (U34) engages
*/
.table-wrap {
  background: #fff;
  border-radius: 8px;
  /* overflow-x: auto (revised 2026-05-23) — scrollbar appears ONLY when the table
     overflows the wrap. At normal widths no scrollbar. At narrow viewports (DevTools
     open, small laptop) or after a user-resize wider than fits, scroll appears so the
     operator can see all columns. Sticky thead (U34) + sticky gear (right:0) both
     continue to anchor to .table-wrap during both axis scrolls. */
  overflow-x: auto;
  overflow-y: auto;
  max-height: calc(100vh - 250px);
  border: 1px solid #e5e7eb;
  max-width: 100%;
}
.data-table {
  /* Width strategy (revised 2026-05-23):
     - min-width:100% — table fills the wrap at minimum so it doesn't look stranded at wide viewports.
     - No max width — table grows when columns need more room (narrow viewport with 14+ visible
       columns, OR user explicitly resized a column wider than fits).
     - .table-wrap has overflow-x:auto — scrollbar appears when the table exceeds wrap.
     - The earlier "min-width:max-content" (removed Batch C8) was too aggressive: forced scroll
       at wide viewports too. min-width:100% gives the same comfortable default without the
       always-scroll side effect.
     - U35 ellipsis on <td> + U39 on <th> still applies — within each visible column, content
       truncates cleanly. */
  min-width: 100%;
  border-collapse: separate; /* sticky thead needs separate borders so the bottom border travels with the sticky row, not the first scrolled row */
  border-spacing: 0;
  font-size: 13px;
  table-layout: auto;
}
.data-table th { white-space: nowrap; }   /* prevents header labels from wrapping into 2 lines, keeping column widths predictable */

/* Uniform row height + ellipsis on overflow (Rule U35 candidate — see below).
   Without this, long emails / addresses / GST numbers wrap to a second line and the row
   grows taller, breaking visual rhythm. Now: every cell is single-line, overflow truncates
   with "…", and a tooltip (via the existing `title` attribute on most cells) shows full text. */
.data-table td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 320px;                /* cap any single cell — operator can resize a column wider via the U24 drag handle */
  height: 44px;                    /* fixed row height — every row exactly the same */
  vertical-align: middle;
}
/* The Name cell holds a pill alongside text; let it be a bit wider before truncating */
.data-table td:has(strong) { max-width: 360px; }
/* Actions column (last td in a data-table row) — strip horizontal padding so the
   40px btn-icon (min-width set by v32-theme.css) fits inside a narrow column.
   .data-table td normally has padding:9px 10px; the 10px×2 eats all content space.
   Right padding is kept at 12px so content never hugs the scrollbar track (founder feedback 2026-06-22). */
.data-table td:last-child { padding-left: 2px; padding-right: 12px; overflow: visible; }
/* When the last-child actually contains a btn-icon / action button, center it */
.data-table td:last-child:has(.btn-icon) { padding-left: 0; padding-right: 0; text-align: center; }

/* Rule U39 — header cells truncate the same way data cells do, so a long header
   like "GST Number" never overflows its column box and slides under the sticky
   gear column on the right. Excludes .col-settings-th (the fixed-width gear cell
   has no text content to ellipsis). Mirror of U35 onto <th>. */
.data-table th:not(.col-settings-th) {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 320px;
}

/* ───── Rule U34 — sticky table header ─────
   When the user scrolls vertically, column headers stay pinned to the top so the operator
   always knows which column holds which data. The sticky context is .table-wrap (NOT the
   page viewport — the wrap has overflow-y:auto + overflow-x:auto since 2026-05-23, so it's
   the nearest scrolling ancestor on both axes). top:0 sticks the row to the wrap's top edge
   during vertical scroll. Right:0 on the gear column (further down) sticks it to the wrap's
   right edge during horizontal scroll. Both anchors work simultaneously. */
/* Sticky thead — Batch 4 industrial chrome (2026-05-23). Cool ink-100 background,
   2px ink-400 bottom rule, JetBrains Mono caps headers with wide tracking. Reads as
   a factory data-board header instead of soft web th. */
.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--ink-100);
  border-bottom: 2px solid var(--ink-400);
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: var(--fw-bold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-700);
  /* No box-shadow on the bottom — the 2px ink-400 border carries that visual weight */
  box-shadow: none;
  user-select: none;
}
/* Sort-active header — white bg with a 2px orange underline + darker text. Factory
   underline replaces the previous accent-indigo color. */
.data-table thead th.sort-active {
  background: var(--paper);
  color: var(--ink-950);
  box-shadow: inset 0 -2px 0 var(--brand-orange);
}
.data-table thead th.sort-active .sort-arrow { color: var(--brand-orange); font-weight: 800; }
/* MR-2g: every sortable header carries a faint ⇅ placeholder so the column is
   clearly clickable even before the user has sorted it. Active column overrides
   the placeholder with ▲ / ▼ + brand-orange. */
.data-table thead th.sortable .sort-arrow {
  margin-left: 4px;
  color: var(--ink-400);
  font-size: 11px;
  opacity: 0.7;
}
/* Sortable hover — subtle ink-150 background, full text color */
.data-table thead th.sortable:hover {
  background: var(--ink-150);
  color: var(--ink-950);
}
.data-table thead th.sortable:hover .sort-arrow { color: var(--ink-700); opacity: 1; }

/* The gear column is sticky in BOTH axes (right + top) — needs the higher z-index so it
   sits ABOVE both the regular thead row and the regular sticky right column.
   The 1px left border + stronger box-shadow (Rule U39, 2026-05-23) give the gear's left
   edge a clean visual boundary so adjacent column text reads as "ends here with …" rather
   than "fades out under something". Without these, headers/cells that ellipsis at the
   column edge look like they're being clipped by the gear. */
.col-settings-th,
.col-settings-td {
  position: sticky;
  right: 0;
  width: 40px;
  min-width: 40px;
  border-left: 1px solid var(--ink-200);
  box-shadow: -4px 0 6px rgba(0,0,0,.08);
}
/* .data-table thead th.col-settings-th (higher specificity than .data-table thead th)
   wins box-shadow override so the gear column gets the leftward shadow + 1px border,
   not just thead th's default bottom shadow. Combined value preserves the thead bottom
   shadow + adds the gear's left boundary. */
.data-table thead th.col-settings-th {
  background: var(--ink-100);
  z-index: 5;   /* top-right corner — above thead's z:3 + body cells' z:2 */
  box-shadow: -4px 0 6px rgba(0,0,0,.08);  /* only the leftward shadow — bottom border carries the thead-bottom visual now */
}
.col-settings-td {
  background: #fff;
  z-index: 2;
}
.data-table tr:hover .col-settings-td { background: var(--ink-50); }
.data-table tr.row-selected .col-settings-td { background: var(--accent-soft); }
/* Generic .data-table th — Batch 4 industrial chrome. The thead th rule above already
   handles the sticky/mono-caps/border treatment; this rule sets padding + alignment
   for both thead and any non-sticky th cells (e.g. inside detail panel summary tables). */
.data-table th {
  background: var(--ink-100);
  text-align: left;
  padding: 9px 10px;
  white-space: nowrap;
}
.data-table td {
  padding: 9px 10px;
  border-bottom: 1px solid var(--ink-100);
}
.data-table tbody tr { transition: background var(--dur-fast) var(--ease-out); }
.data-table tbody tr:hover { background: var(--ink-50); }
.data-table tbody tr.row-selected { background: var(--orange-50); }
.data-table tbody tr.row-selected td.col-settings-td { background: var(--orange-50); }

.empty-state {
  padding: 40px 24px;
  text-align: center;
  background: #fff;
  border-radius: 8px;
  border: 1px dashed #e5e7eb;
}
.empty-state p:first-child { font-size: 16px; color: #6b7280; margin: 0 0 8px; }
.empty-state button { margin-top: 12px; }

/* ===== Page toolbar (top of list pages) ===== */
/* Page toolbar — Batch 2 of industrial port. The signature page-identity moment.
   A 4px wide orange anchor bar runs the full height of the header on the left,
   the title flips to Antonio uppercase at 48px, the subtitle becomes JetBrains
   Mono caps. Every list page gets the same treatment automatically (Vendors,
   Users, ZohoSync, future Items / SOs / POs / Production Log). */
.page-toolbar {
  position: relative;
  /* z-index removed — fixed-position dropdowns are now in the root stacking context
     (after removing z-index:1 from .app-main > *), so no stacking trap here. */
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding-left: 16px;            /* room for the orange anchor bar */
  gap: 16px;
  flex-wrap: wrap;
}
/* Filter / tab bar — a stacking context above the table scroll body so the TableFilterDropdown
   menu is never buried behind sticky-thead transforms or table rows. Founder 2026-07-06: was
   z-index:100 which beat the sticky topbar (z 30), so the profile popup dropped BEHIND this bar
   on list pages. Pinned just below the topbar — still far above the table body (max z 5). */
.page-filter-bar { position: relative; z-index: calc(var(--z-topbar) - 5); }

/* Full-bleed list page wrapper — Master Data Refinement MR-1 (2026-05-29).
   Opt-in class for list pages (Items / Consumables / SKUs / Sub-Assemblies)
   that want to fill the viewport corner-to-corner without app-main's padding
   eating into the visible area. Founder feedback: "still not coverning full page".
   Pattern matches the .zsync-shell margin-negate trick shipped overnight. */
.fullbleed-page {
  margin: calc(var(--space-6) * -1);
  /* MR-3 2026-05-29 — bottom padding bumped from space-4 → space-6 so the last
     row of content (sub-asm cards, table rows, BOM sections) doesn't kiss the
     viewport bottom edge. Standing rule: every full-bleed page leaves visible
     breathing room below content. If a page hosts an inner scroll container
     (.table-wrap / .cmp-frame), the container itself ALSO needs padding-bottom
     so its last row sits above the page's padding line. */
  padding: var(--space-4) var(--space-5) var(--space-6);
  /* MR-2k 2026-05-29 — fixed `height` (was `min-height`) so inner scroll
     containers like .cmp-frame and .table-wrap actually contain. With
     `min-height` the page could expand to fit content and the BROWSER
     scrolled instead of the inner pane — making the sticky thead
     scroll away and the horizontal scrollbar invisible until the bottom
     of the page. Founder feedback. */
  height: calc(100vh - 44px);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* MR-3 2026-05-29 — any flat content area that doesn't have its own scroll
   wrapper (SubAssemblies .sa-tab-body, future similar) still needs a guaranteed
   gap above the page bottom. Lets the page itself scroll if content overflows
   and never clips the last row. */
.fullbleed-page .sa-tab-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: var(--space-6);
}
/* v32-theme.css applies background:#f8fafc !important to all .sa-tab-body details > summary.
   Painted-Frames family-group headers (Folding, ZorQ, UniByk…) used to show a full purple
   background but founder prefers just an orange text accent on the normal row background.
   This rule wins the !important specificity race via the attribute selector. */
.sa-tab-body details > summary[style*="brand-purple"] {
  background: #f8fafc !important;
  color: var(--brand-orange) !important;
  font-weight: 700 !important;
}
/* 2026-05-30 — Production Log / Daily Report / Frame Activity have no inner
   scroll container (no .table-wrap / .cmp-frame / .sa-tab-body), so wrap their
   content in .page-scroll-body to give the body itself a scroll axis. Without
   this the .fullbleed-page's overflow:hidden silently clips long content. */
.fullbleed-page .page-scroll-body {
  flex: 1;
  min-height: 0;
  /* 2026-06-15 — min-width:0 lets this flex child be constrained to the page width instead of
     stretching to a wide table's intrinsic width. Without it, a wide .table-wrap inside expands this
     body past the viewport and the table-wrap's own overflow-x:auto never engages (no scrollbar).
     Pairs with the per-column min-widths on the dispatch-log table. */
  min-width: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-bottom: var(--space-6);
}
/* 2026-06-15 — when the body wraps a single wide table (Dispatch Log), make the .table-wrap FILL the
   body and be the one scroll container, so its horizontal scrollbar sits at the VISIBLE bottom edge
   instead of below the nested-scroll fold (founder: "horizontal scroll not visible" even though the
   table was overflowing). Scoped via the --table modifier so flat-content pages are unaffected. */
.page-scroll-body--table { display: flex; flex-direction: column; }
.page-scroll-body--table > .table-wrap {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  max-height: none;
}
/* Make the horizontal scrollbar unmistakable on the wide table. */
.page-scroll-body--table > .table-wrap::-webkit-scrollbar { height: 13px; }
.page-scroll-body--table > .table-wrap::-webkit-scrollbar-thumb { background: #94a3b8; }
.page-scroll-body--table > .table-wrap::-webkit-scrollbar-thumb:hover { background: #64748b; }

/* MR-3 2026-05-29 — SKU detail view 2-column layout.
   Founder feedback: "BOM matrix section is usually lengthier in vertical space
   in comparison to other sections — better we put that on one side like right
   side". Left column = small facts (Pricing, Sub-Asms used, Frames used, Misc).
   Right column = BOM matrix (the only section that grows with row count).
   Below 1200px we collapse to single-column so the panel still works on narrow
   viewports. */
.sku-view-body .sku-view-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
}
@media (min-width: 1200px) {
  .sku-view-body .sku-view-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    align-items: start;
  }
}
.sku-view-body .sku-view-col { min-width: 0; }
.sku-view-body .sku-view-col .form-section,
.sku-view-body .sku-view-col .view-section { margin-bottom: var(--space-5); }
.sku-view-body .sku-view-col .form-section:last-child,
.sku-view-body .sku-view-col .view-section:last-child { margin-bottom: 0; }
/* MR-3c 2026-05-29 — extra bottom buffer on BOTH columns so the last row of
   either side (Misc textarea on the left, last BOM row on the right) keeps
   a comfortable gap from the page bottom rather than tucking under it. */
.sku-view-body .sku-view-col-left,
.sku-view-body .sku-view-col-right { padding-bottom: var(--space-7); }
.fullbleed-page > .page-toolbar {
  margin-bottom: var(--space-4);
}
.fullbleed-page > .vendors-shell {
  flex: 1;
  min-height: 0;
}
/* MR-2f founder fix: when a list-pane sits in a fullbleed-page, its .table-wrap
   should grow to fill the remaining viewport height instead of capping at
   calc(100vh - 250px). Without this the table looks like it occupies ~60% of
   the screen with empty space below — exactly the founder report. */
.fullbleed-page .list-pane {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.fullbleed-page .list-pane > .table-wrap {
  flex: 1;
  min-height: 0;
  max-height: none;
}
.fullbleed-page .list-pane > .pagination-bar {
  flex-shrink: 0;
}
/* MR-StickyHeader · 2026-06-06 — same shape but for pages whose .table-wrap is a
   DIRECT child of .fullbleed-page (no .list-pane wrapper). PurchaseOrders main list
   view is structured this way. Without flex:1 + min-height:0, the wrap doesn't fill
   the remaining vertical space — the page document scrolls instead, and Rule U34's
   sticky thead never engages (because its scroll context becomes the body, not the
   wrap). Founder report 2026-06-06: top column header didn't pin while scrolling
   the PO list. */
.fullbleed-page > .table-wrap {
  flex: 1;
  min-height: 0;
  max-height: none;
}

/* ===========================================================
   SKU Compare Matrix (/skus/compare) — MR-2j 2026-05-29
   Parts × SKUs Excel-style grid with frozen header row + frozen
   first column. Both axes scroll inside .cmp-frame; the corner
   stays glued at top-left.
   =========================================================== */
.cmp-frame {
  flex: 1;
  min-height: 0;
  overflow: auto;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: 0;
  position: relative;
}
.cmp-table {
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
  table-layout: fixed;
}
/* Headers — sticky to the top edge */
.cmp-table thead th {
  position: sticky;
  top: 0;
  background: var(--ink-100);
  color: var(--ink-800);
  border-bottom: 2px solid var(--brand-orange);
  border-right: 1px solid var(--ink-200);
  z-index: 3;
  height: 80px;
  padding: 6px;
  text-align: center;
}
/* MR-3b 2026-05-29 — narrower SKU header (72 → 56px) so more columns fit on
   screen. Vertical text means the cell only needs to be wide enough to clear
   the family separator + a comfortable click target. */
.cmp-sku-head { width: 56px; min-width: 56px; padding: 6px 2px; }
.cmp-sku-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--ink-900);
  height: 116px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  margin: 0 auto;
}

/* Per-family colour grouping. Each .cmp-sku-head AND .cmp-cell carries a hashed
   `fam-c0`..`fam-c5` class so columns sharing a family prefix (JAX, M1, M1S, SNP,
   Vyp, UniByk, …) render in matching colour bands.

   Founder MR-3 2026-05-29: removed the per-cell top-border (it drew a coloured
   line on the first cell of every row × every family band, making the grid look
   noisy). Replaced with a single thick vertical separator on the family-first
   column — clean industrial group boundary, no extra horizontal lines. */
.cmp-sku-head.fam-c0, .cmp-cell.fam-c0 { background: #fff7ed; }
.cmp-sku-head.fam-c1, .cmp-cell.fam-c1 { background: #fdf4ff; }
.cmp-sku-head.fam-c2, .cmp-cell.fam-c2 { background: #eff6ff; }
.cmp-sku-head.fam-c3, .cmp-cell.fam-c3 { background: #ecfdf5; }
.cmp-sku-head.fam-c4, .cmp-cell.fam-c4 { background: #fef3c7; }
.cmp-sku-head.fam-c5, .cmp-cell.fam-c5 { background: #fce7f3; }
/* Family boundary: thick vertical bar on the first column of each family. */
.cmp-sku-head.fam-first { border-left: 3px solid var(--ink-700); }
.cmp-cell.fam-first      { border-left: 3px solid var(--ink-700); }
/* Dirty cell colour still wins for clarity */
.cmp-cell.cmp-cell-dirty { background: #fed7aa !important; }
.cmp-cell.cmp-cell-set:not(.cmp-cell-dirty) { background: var(--accent-soft); }
/* Frozen left column — Part name + code */
.cmp-part-cell {
  position: sticky;
  left: 0;
  background: var(--paper);
  border-right: 2px solid var(--brand-orange);
  border-bottom: 1px solid var(--ink-100);
  z-index: 2;
  width: 240px;
  min-width: 240px;
  padding: 6px 10px;
  vertical-align: middle;
}
.cmp-part-name { font-weight: 600; color: var(--ink-900); font-size: 13px; line-height: 1.2; }
.cmp-part-code { font-size: 11px; color: var(--ink-500); font-family: var(--font-mono); margin-top: 2px; }
/* Frozen corner — sits at the intersection of frozen row + frozen column. Higher z-index than
   both so neither slides over it during scroll. */
.cmp-corner-cell {
  position: sticky;
  top: 0; left: 0;
  background: var(--ink-150);
  border-right: 2px solid var(--brand-orange);
  border-bottom: 2px solid var(--brand-orange);
  z-index: 5;
  width: 240px;
  min-width: 240px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 11px;
  text-align: left;
  padding: 6px 10px;
}
/* Data cells — qty values */
.cmp-cell {
  width: 56px;
  min-width: 56px;
  height: 38px;
  text-align: center;
  border-right: 1px solid var(--ink-100);
  border-bottom: 1px solid var(--ink-100);
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--ink-700);
  background: var(--paper);
}
.cmp-cell-set { background: var(--accent-soft); color: var(--ink-900); font-weight: 600; }
.cmp-cell-dirty { background: var(--brand-orange-soft, #fed7aa); color: var(--ink-950); }
/* Inline editor inside a cell */
.cmp-cell-input {
  width: 100%;
  height: 100%;
  border: none;
  background: transparent;
  text-align: center;
  font: inherit;
  color: inherit;
  padding: 0 4px;
  outline: none;
}
.cmp-cell-input:focus { background: #fff; box-shadow: inset 0 0 0 2px var(--brand-orange); }
/* Category banner row spanning the whole row */
.cmp-cat-row td.cmp-cat-cell {
  position: sticky;
  left: 0;
  background: var(--ink-50);
  color: var(--brand-orange);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-bottom: 1px solid var(--ink-200);
  border-top: 1px solid var(--ink-200);
}
.page-toolbar::before {
  content: "";
  position: absolute;
  left: 0; top: 4px; bottom: 4px;
  width: 4px;
  background: var(--brand-orange);
}
.toolbar-left h1 {
  font-family: var(--font-display);
  font-size: 48px;
  font-weight: var(--fw-bold);
  line-height: 0.95;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--ink-950);
  margin: 0;
}
.toolbar-left .subtitle {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.12em;
  color: var(--ink-500);
  text-transform: uppercase;
  margin: 6px 0 0;
}
.toolbar-actions { display: flex; gap: var(--space-2); align-items: center; }

/* Page-stats — Batch 3 industrial port (2026-05-23). KPI tiles aligned right of the
   page title. Each tile is a stacked label-above-value pair: tiny mono caps label,
   large display-font tabular-nums value. Reusable across every list page (Vendors
   today; Users + ZohoSync + future entities wire up in later per-page passes).
   Use .accent on .page-stat-value for orange (warns / important state). Use the
   nested <span class="unit"> for small grey suffix like "of 75 vendors". */
.page-stats {
  display: flex;
  gap: 28px;
  align-items: flex-end;
  margin-left: auto;           /* push toward the right side, next to actions */
  padding-right: 16px;
  flex-wrap: wrap;             /* graceful wrap when toolbar runs out of room */
}
.page-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.page-stat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.15em;
  color: var(--ink-500);
  text-transform: uppercase;
  font-weight: var(--fw-medium);
}
.page-stat-value {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: var(--fw-semibold);
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.page-stat-value .unit {
  color: var(--ink-500);
  font-weight: var(--fw-regular);
  font-family: var(--font-ui);
  font-size: 12px;
  margin-left: 4px;
  letter-spacing: 0;
  text-transform: none;
}
.page-stat-value.accent { color: var(--brand-orange); }
/* ===== Rich search bar (Rule U20) ===== */
.search-wrap { position: relative; width: 340px; }
.search-input-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
.search-icon {
  position: static;
  flex-shrink: 0;
  font-size: 14px;
  color: #9ca3af;
  pointer-events: none;
}
.search-box {
  flex: 1;
  min-width: 0;
  padding: 8px 36px 8px 12px;     /* icon is an outside sibling now; right clears the ✕ */
  border: 1px solid #d1d5db;
  border-radius: 6px;
  font-size: 14px;
  width: 100%;
  background: #fff;
}
.search-box:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37,99,235,.15); }
.search-clear {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: #e5e7eb;
  border: none;
  color: #6b7280;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  font-size: 11px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}
.search-clear:hover { background: #d1d5db; color: #1f2937; }

.search-suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: #fff;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  box-shadow: 0 10px 25px rgba(0,0,0,.10);
  z-index: 50;
  max-height: 320px;
  overflow-y: auto;
}
.search-suggestion {
  padding: 8px 12px;
  border-bottom: 1px solid #f3f4f6;
  cursor: pointer;
  user-select: none;
}
.search-suggestion:last-child { border-bottom: none; }
.search-suggestion.highlighted { background: #eff6ff; }
.search-suggestion:hover { background: #eff6ff; }
.suggestion-name { font-size: 14px; color: #1f2937; display: flex; align-items: center; gap: var(--space-2); }
.suggestion-meta { font-size: 12px; color: #6b7280; margin-top: var(--space-1); display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.search-suggestion-more {
  padding: var(--space-2) 12px;
  font-size: 11px;
  color: #6b7280;
  background: #f9fafb;
  border-top: 1px solid #e5e7eb;
  text-align: center;
  font-style: italic;
}

/* ===== Buttons — Batch 5 industrial chrome (2026-05-23) =====
   Sharp corners across the board. Three tiers:
   - .btn-primary: ink-950 background with brand-orange on hover — "execute" button.
     Mono caps label for factory operator-console feel.
   - .btn-secondary: white surface with ink-300 border, ink-700 text — supporting actions.
   - .btn-danger: saturated red — destructive (delete, hard-remove).
   Disabled state is opacity-only — no visual reshape. */
.btn-primary, .btn-secondary, .btn-danger, .action-btn-primary, .action-btn-secondary {
  /* M3 audit 2026-06-14 — bumped to ~40dp (was ~35px): padding 8→10px vertical + an explicit
     min-height floor so text-only buttons can't fall under the M3 40dp common-button height.
     inline-flex centres the label so the taller box doesn't push text to the top. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 38px;
  padding: 9px 16px;
  border-radius: var(--radius-sharp);
  border: 1px solid transparent;
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.04em;
  transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.btn-primary {
  background: var(--ink-950);
  color: var(--paper);
  border-color: var(--ink-950);
}
.btn-primary:hover:not([disabled]) {
  background: var(--brand-orange);
  border-color: var(--brand-orange);
  color: var(--ink-950);
}
.btn-primary[disabled] { opacity: .5; cursor: not-allowed; }
.btn-secondary {
  background: var(--paper);
  color: var(--ink-800);
  border-color: var(--ink-300);
}
.btn-secondary:hover:not([disabled]) {
  background: var(--ink-50);
  border-color: var(--ink-600);
  color: var(--ink-950);
}
.btn-secondary[disabled] { opacity: .5; cursor: not-allowed; }
/* action-btn-* aliases — same visual as btn-primary / btn-secondary; used in StockLedger + modals */
.action-btn-primary { background: var(--ink-950); color: var(--paper); border-color: var(--ink-950); }
.action-btn-primary:hover:not([disabled]) { background: var(--brand-orange); border-color: var(--brand-orange); color: var(--ink-950); }
.action-btn-primary[disabled] { opacity: .5; cursor: not-allowed; }
.action-btn-secondary { background: var(--paper); color: var(--ink-800); border-color: var(--ink-300); }
.action-btn-secondary:hover:not([disabled]) { background: var(--ink-50); border-color: var(--ink-600); color: var(--ink-950); }
.action-btn-secondary[disabled] { opacity: .5; cursor: not-allowed; }
.btn-danger {
  background: var(--danger);
  color: var(--paper);
  border-color: var(--danger);
}
.btn-danger:hover { background: #991B1B; border-color: #991B1B; }
/* Ghost/outline variant — transparent bg, danger-coloured border + text, fills on hover. */
.btn-danger-ghost {
  background: transparent;
  color: var(--danger);
  border: 1px solid var(--danger);
  border-radius: var(--radius-md, 8px);
  padding: var(--space-2) var(--space-4);
  font: inherit;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.btn-danger-ghost:hover { background: var(--danger); color: var(--paper); }
.btn-danger-ghost:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }
.btn-danger-ghost:disabled { opacity: .45; filter: grayscale(45%); cursor: not-allowed; }
/* .btn-sm — compact modifier for table row actions (reduces padding so button fits in narrow columns).
   Works as an additive class on top of .btn-primary / .btn-secondary / .btn-danger. */
.btn-sm {
  padding: 4px 10px !important;
  min-height: 28px !important;
  font-size: 11px !important;
}
.btn-icon {
  background: none;
  border: 1px solid transparent;
  color: var(--ink-600);
  font-size: 16px;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--radius-sharp);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.btn-icon:hover { background: var(--ink-100); color: var(--ink-950); border-color: var(--ink-200); }

/* ===== Clickable rows + sort headers ===== */
.clickable-rows tbody tr { cursor: pointer; }
.clickable-rows tbody tr:hover { background: #eff6ff; }
.clickable-rows tbody tr.row-selected { background: #dbeafe; }
.sortable { cursor: pointer; user-select: none; }
.sortable:hover { background: #e5e7eb; }
.data-table code { background: #f3f4f6; padding: 1px 6px; border-radius: 3px; font-size: 12px; }
.data-table .muted { color: #9ca3af; }

/* ===== Pills (status / type chips) ===== */
/* Pill — Batch 4 industrial chrome (2026-05-23). Sharp corners, JetBrains Mono caps
   with letter-spacing, slightly tighter padding. Each .pill-* variant below sets the
   factory-saturated bg + fg colors (the base here is the neutral grey fallback). */
.pill {
  display: inline-block;
  padding: 3px 8px;
  border-radius: var(--radius-sharp);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--ink-150);
  color: var(--ink-700);
  line-height: 1.4;
}
.pill-paint     { background: #fee2e2; color: #991b1b; }
.pill-parts     { background: #dbeafe; color: #1e40af; }
.pill-consumable { background: #fef3c7; color: #92400e; }
.pill-service   { background: #ede9fe; color: #5b21b6; }
.pill-mixed     { background: #d1fae5; color: #065f46; }
/* MR-D8a — Frame Activity stage pills (Fab / Paint / Fg) */
.pill-fab       { background: #ffedd5; color: #9a3412; }
.pill-fg        { background: #dbeafe; color: #1e40af; }

/* VendorCategory pills (Local / Domestic / Overseas) — distinct palette from VendorType */
.pill-category-local    { background: #ccfbf1; color: #115e59; }  /* teal — close-by, fast */
.pill-category-domestic { background: #fef9c3; color: #854d0e; }  /* amber — interstate */
.pill-category-overseas { background: #e0e7ff; color: #3730a3; }  /* indigo — imported */

/* ===== Side panel ===== */
.side-panel-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.3);
  z-index: 100;
}
.side-panel {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 100%;
  max-width: 560px;
  background: var(--paper);
  z-index: 101;
  display: flex;
  flex-direction: column;
  min-height: 0;            /* Rule U25 — flex column needs this so overflow children behave */
  overflow: hidden;         /* contain the body's scroll */
  box-shadow: var(--shadow-panel);
  animation: slideIn .15s ease-out;
}
@@keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }
.side-panel-header {
  /* Rule U25 — flex-anchored, NOT position:sticky.
     Sticky was making the header escape the panel during scroll. */
  flex-shrink: 0;
  width: 100%;
  margin: 0;
  box-sizing: border-box;
  background: var(--paper);
  border-bottom: 1px solid var(--ink-200);
  padding: var(--space-4) var(--space-6);
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  position: relative;
  z-index: 2;
}
.side-panel-header h2 { margin: 0; font-size: 18px; }
.side-panel-header .subtitle { color: #6b7280; font-size: 12px; margin: 2px 0 0; }
.side-panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px 24px;
}
.side-panel-footer {
  position: sticky;
  bottom: 0;
  background: #fff;
  border-top: 1px solid #e5e7eb;
  padding: 12px 24px;
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  z-index: 2;
}

/* ===== View grid (read-only view mode) ===== */
.view-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 24px; }
.view-grid .kv { display: flex; flex-direction: column; gap: 2px; }
.view-grid .kv.kv-wide { grid-column: 1 / -1; }
.view-grid .kv label { font-size: 11px; color: #6b7280; text-transform: uppercase; letter-spacing: .5px; font-weight: 600; }
.view-grid .kv > div { font-size: 14px; color: #1f2937; }
.view-grid .multiline { white-space: pre-wrap; }

/* ===== Forms ===== */
.form-section { margin-bottom: 24px; }
.form-section h3 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: #6b7280;
  font-weight: 600;
  border-bottom: 1px solid #e5e7eb;
  padding-bottom: 4px;
  margin-bottom: 12px;
}
/* legacy .form-section label rule — superseded by .form-field label (form-grid layout) */
.form-section > label {
  display: block;
  margin-top: var(--space-3);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--ink-700);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}
/* Form inputs — Batch 5 industrial chrome. Sharp corners, orange focus (no blue glow). */
.form-section .field {
  width: 100%;
  padding: 8px 12px;
  margin-top: 4px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sharp);
  font-size: 13px;
  font-family: inherit;
  background: var(--paper);
  color: var(--ink-900);
  transition: border-color var(--dur-fast);
}
.form-section .field:focus {
  outline: none;
  border-color: var(--brand-orange);
  box-shadow: none;            /* no glow — clean industrial focus */
}
.form-section .field.invalid, .form-section .field.modified.invalid { border-color: var(--danger); }
.form-row-inline { display: flex; gap: 20px; margin-top: 12px; flex-wrap: wrap; }
.checkbox-row { display: flex; align-items: center; gap: 6px; font-weight: normal !important; margin-top: 0 !important; cursor: pointer; }
.required { color: #dc2626; margin-left: 2px; }
.hint-inline { color: #9ca3af; font-weight: normal; font-size: 11px; }
.validation-message { color: #dc2626; font-size: 12px; margin-top: 4px; display: block; }

/* ===== Modal (confirmations) ===== */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.5);
  z-index: 200;
}
/* Rule U9 — modal header pattern: h3 + ✕ button on the right, used by Compare Matrix
   review + discard modals (and any other modal that wants U9 compliance). */
.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.modal-header h3 { margin: 0; }
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: #fff;
  border-radius: 8px;
  padding: 24px;
  max-width: 440px;
  width: 90%;
  z-index: 201;
  box-shadow: 0 20px 50px rgba(0,0,0,.3);
}
.modal h3 { margin: 0 0 12px; font-size: 18px; }
/* Wider modal for tables (sync preview, diff modal) */
.modal-wide { max-width: 820px; }
.modal p { margin: 8px 0; font-size: 14px; line-height: 1.5; }
.modal-footer { display: flex; gap: 8px; justify-content: flex-end; margin-top: 20px; }

.loading-state { padding: 40px; text-align: center; color: #6b7280; }

/* ===== Toast notifications (Rule U6) ===== */
.toast {
  position: fixed;
  top: 80px;
  right: 24px;
  z-index: 300;
  padding: 12px 20px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  box-shadow: 0 10px 25px rgba(0,0,0,.15);
  animation: toastIn .2s ease-out;
  max-width: 400px;
}
.toast-success { background: #10b981; color: #fff; }
.toast-error   { background: #dc2626; color: #fff; }
.toast-info    { background: #3b82f6; color: #fff; }
@@keyframes toastIn {
  from { transform: translateX(120%); opacity: 0; }
  to   { transform: translateX(0);    opacity: 1; }
}

/* ===== Deleted row styling ===== */
.row-deleted { opacity: 0.6; background: #fef2f2 !important; }
.row-deleted:hover { background: #fee2e2 !important; }
.row-deleted code { text-decoration: line-through; }
.pill-deleted { background: #fee2e2; color: #991b1b; margin-left: 6px; }
/* Parts BOM shortfall row (dispatch planner) */
.row-shortage { background: #fef2f2; }
.row-shortage:hover { background: #fee2e2; }

/* Toggle button "on" state */
.toggle-on { background: #fef3c7 !important; color: #92400e !important; }
.toggle-on:hover { background: #fde68a !important; }

/* Danger modal (permanent delete) */
.modal-danger { border: 2px solid #dc2626; }
.modal-danger h3 { color: #dc2626; }

/* Phone country + digits side-by-side — country narrow, digits wide */
.phone-row {
  display: flex;
  gap: var(--space-2);
  margin-top: 4px;
  min-width: 0;        /* Rule U25 — allow children to shrink within parent */
  width: 100%;
}
.phone-row .field-country {
  width: 110px;        /* compact: just "+91 IN" — was 200px */
  flex: 0 0 110px;
  margin-top: 0 !important;
}
.phone-row .field-phone {
  flex: 1 1 auto;
  min-width: 0;
  margin-top: 0 !important;
}

/* ===== Generic dropdown / popover (Rule U22 — standard visual for ALL dropdowns) ===== */
.dropdown-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-dropdown);
}
.dropdown-card {
  position: fixed;
  background: var(--paper);
  border: 1px solid var(--ink-300);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  z-index: calc(var(--z-dropdown) + 1);
  font-size: var(--fs-13);
  animation: dropdownIn var(--dur-base) var(--ease-out);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-height: 70vh;
}
@keyframes dropdownIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.dropdown-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--ink-200);
  flex-shrink: 0;
}
.dropdown-header h4 {
  margin: 0;
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
}
.dropdown-body {
  padding: var(--space-2) 0;
  overflow-y: auto;
  flex: 1 1 auto;
}
.dropdown-footer {
  display: flex;
  gap: var(--space-2);
  justify-content: space-between;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--ink-200);
  flex-shrink: 0;
}

/* ===== Column customizer (Rule U21) — uses .dropdown-card chrome =====
   NOTE: Width is set ONCE at line ~450 (.col-settings-th, .col-settings-td) to 40px.
   The duplicate width:36px rule that used to live here was removed 2026-05-23 — it
   conflicted with the 40px min-width and produced a visually inconsistent boundary
   that contributed to the "header sliding under gear" clipping bug. */
.col-settings-th {
  text-align: center;
  padding: 0 !important;
}
.col-settings-btn {
  background: transparent;
  border: none;
  color: var(--ink-500);
  font-size: 14px;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: var(--r-sm);
}
.col-settings-btn:hover {
  background: var(--ink-200);
  color: var(--ink-900);
}
.col-settings-dropdown {
  top: 180px;
  right: 32px;
  width: 320px;
}
.col-settings-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  user-select: none;
}
.col-settings-row:hover { background: var(--ink-100); }
.col-settings-check {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 1;
  cursor: pointer;
}
.col-settings-check input[type=checkbox] { cursor: pointer; }
.col-settings-check input[type=checkbox]:disabled { cursor: not-allowed; }
.col-settings-label { flex: 1; }
.col-settings-lock { color: var(--ink-400); font-size: 12px; }
.drag-handle {
  cursor: grab;
  user-select: none;
  color: var(--ink-400);
  padding: 0 var(--space-2);
  font-size: 14px;
  font-weight: bold;
  letter-spacing: -3px;
  line-height: 1;
  flex-shrink: 0;
}
.col-settings-row:hover .drag-handle { color: var(--ink-700); }
.col-settings-row[draggable=true] { cursor: default; }
.col-settings-row[draggable=true]:active,
.col-settings-row[draggable=true]:active .drag-handle { cursor: grabbing; }
.col-settings-row.drag-source { opacity: 0.4; }
.col-settings-row.drag-over {
  background: var(--accent-soft);
  box-shadow: inset 0 2px 0 var(--accent);
}

/* ===== Section bars — used in BOTH view mode (.view-section) and edit mode (.form-section) ===== */
.view-section, .form-section {
  margin-bottom: var(--space-5);
}
.view-section:last-child, .form-section:last-child { margin-bottom: 0; }
.section-bar {
  background: var(--ink-100);
  color: var(--ink-700);
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-widest);
  text-transform: uppercase;
  border-left: 3px solid var(--brand-orange);
  margin: 0 calc(-1 * var(--space-6)) var(--space-3);
}
.section-bar-danger {
  background: var(--danger-soft);
  color: var(--danger);
  border-left-color: var(--danger);
}
.view-section-danger .view-grid { background: var(--danger-soft); padding: var(--space-3); border-radius: var(--r-md); }
.notes-block {
  background: var(--ink-50);
  padding: var(--space-3);
  border-radius: var(--r-md);
  border-left: 2px solid var(--ink-300);
}

/* ===== No spurious typing cursor (Rule U23) — caret-color: transparent except on real inputs ===== */
body, .app-shell, .app-main, .side-panel, .data-table, .data-table th, .data-table td,
.view-section, .view-grid, .kv, .section-bar, .form-section, .form-grid, .form-field {
  caret-color: transparent;
}
input, textarea, [contenteditable="true"] {
  caret-color: auto;
}

/* Suppress focus rings on clickable table cells (mouse-only operators) */
.data-table th, .data-table tr, .data-table td {
  outline: none;
}
.data-table th:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* ===== Edit-mode form grid (Rule U23 — same 2-col layout as view mode) ===== */
.form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3) var(--space-5);
  align-items: end; /* Batch D1b fix: bottom-align inputs so a label that wraps (hint/edit-button) doesn't push its input below the others on the same row */
}
/* 3-column variant — use when three short fields should sit on one row
   (Vendors Classification: Type / Category / Currency). form-field-wide
   still spans full width because grid-column: 1 / -1 works in any-column grid. */
.form-grid-3col {
  grid-template-columns: 1fr 1fr 1fr;
}
.form-field {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.form-field-wide {
  grid-column: 1 / -1;
}
.form-field label {
  display: block;
  margin: 0 0 var(--space-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--ink-700);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
}
.form-field .field, .form-field .phone-row {
  width: 100%;
}
.form-checkboxes {
  display: flex;
  gap: var(--space-5);
  padding-top: var(--space-2);
}

/* Section view-grid — 2-col compact layout (Rule U23 space economy) */
.view-section .view-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3) var(--space-5);
}
.view-section .view-grid .kv {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.view-section .view-grid .kv-wide {
  grid-column: 1 / -1;
}
.view-section .view-grid .kv label {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
  font-weight: var(--fw-semibold);
  color: var(--ink-500);
}
.view-section .view-grid .kv > div {
  font-size: var(--fs-13);
  color: var(--ink-900);
  word-break: break-word;
}
.view-section .view-grid .multiline {
  white-space: pre-wrap;
}

/* Edit-mode form-section: drop the legacy h3 styling (now uses .section-bar div instead) */
.form-section h3 { display: none; }   /* belt-and-braces in case any stray h3 remains */

/* ===== Right-panel: form wraps header so Save can be in the header ===== */
.side-panel-form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* ===== Column resize handles (Rule U24) =====
   MR-V32-ColResizeViz · 2026-06-03 — handle now shows a subtle 1px guide line at rest
   instead of being fully transparent. Founder complaint: "SKU table resizing feature
   is not done yet" — actually wired + working, but invisible to discover. */
.col-resize-handle {
  position: absolute;
  top: 25%;
  right: 0;
  bottom: 25%;
  width: 8px;
  cursor: col-resize;
  user-select: none;
  z-index: 10;
  background: transparent;
  border-right: 2px solid var(--ink-300);
  opacity: 0.55;
  transition: opacity var(--dur-fast), border-color var(--dur-fast);
}
.data-table thead th:hover .col-resize-handle {
  opacity: 1;
  border-right-color: var(--brand-orange);
}
.col-resize-handle:hover,
.col-resize-handle:active {
  border-right-color: var(--brand-orange);
  border-right-width: 3px;
  opacity: 1;
}
.data-table th {
  position: relative;
}
.side-panel-header { align-items: flex-start; }
.header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-shrink: 0;
}
.header-save-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  font-family: inherit;
  margin-right: var(--space-1);
  height: 32px;
  background: var(--brand-orange);
  color: var(--paper);
  border: 1px solid var(--brand-orange);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.header-save-btn:hover:not([disabled]) {
  background: var(--brand-orange-hover);
  border-color: var(--brand-orange-hover);
}
.header-save-btn[disabled] {
  background: var(--ink-200);
  color: var(--ink-500);
  border-color: var(--ink-200);
  cursor: not-allowed;
}
.header-save-btn svg { flex-shrink: 0; }
.icon-action-btn {
  background: transparent;
  border: 1px solid var(--ink-200);
  color: var(--ink-700);
  width: 32px;
  height: 32px;
  border-radius: var(--r-md);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 14px;
  line-height: 1;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.icon-action-btn:hover {
  background: var(--ink-100);
  color: var(--ink-900);
  border-color: var(--ink-300);
}
.icon-action-btn svg { display: block; }   /* prevent baseline gap */

/* Color-coded action icons (Rule U23 — action buttons get semantic color) */
.icon-action-btn.action-edit { color: var(--accent); border-color: var(--accent-soft); }
.icon-action-btn.action-edit:hover { background: var(--accent-soft); color: var(--accent-hover); border-color: var(--accent); }

.icon-action-btn.action-delete { color: var(--danger); border-color: var(--danger-soft); }
.icon-action-btn.action-delete:hover { background: var(--danger-soft); color: var(--danger); border-color: var(--danger); }

.icon-action-btn.action-perm-delete { color: var(--danger); background: var(--danger-soft); border-color: var(--danger); }
.icon-action-btn.action-perm-delete:hover { background: var(--danger); color: var(--paper); }

.icon-action-btn.action-restore { color: var(--success); border-color: var(--success-soft); }
.icon-action-btn.action-restore:hover { background: var(--success-soft); color: var(--success); border-color: var(--success); }

/* ===== Side panel body — generous bottom padding, no horizontal scroll (Rule U23 + U25) ===== */
.side-panel-body {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;                                       /* Rule U25 — no horizontal scroll inside panels, ever */
  padding: var(--space-5) var(--space-6) var(--space-8);
  min-height: 0;
  width: 100%;
  box-sizing: border-box;
}

/* Every direct child of the body respects its container width */
.side-panel-body > *,
.side-panel-body .form-section,
.side-panel-body .form-grid,
.side-panel-body .view-section,
.side-panel-body .view-grid {
  max-width: 100%;
  box-sizing: border-box;
}
.side-panel-body input,
.side-panel-body textarea,
.side-panel-body select,
.side-panel-body .field {
  max-width: 100%;
  box-sizing: border-box;
}

/* ===== Sort arrow orange highlight + active column emphasis ===== */
.data-table th.sort-active { background: var(--brand-orange-soft); }
.data-table th.sort-active { color: var(--ink-900); font-weight: var(--fw-semibold); }
.sort-arrow {
  color: var(--brand-orange);
  font-weight: bold;
  margin-left: 4px;
  font-size: 11px;
  vertical-align: middle;
}

/* ===== Address-cell truncation (Rule U17 doesn't apply to display, just entry) ===== */
.address-cell {
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink-700);
  font-size: var(--fs-sm);
}
.email-cell {
  max-width: 200px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.phone-cell {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
}

/* Topbar already has the orange identity stripe; main button colors updated to use accent var */
/* Older .btn-primary override removed in Batch 5 — the industrial styling now lives
   in the canonical rule at line ~785. (Was: accent-blue bg / accent-hover. Now: ink-950
   bg with orange hover.) */
.search-box:focus { outline: none; border-color: var(--brand-orange); box-shadow: none; }

/* ============================================================================
   BATCH A — Zoho-style redesign foundation
   ============================================================================ */

/* ===== Rule U26 — Sidebar collapse toggle at the BOTTOM =====
   40×40 button pushed to the bottom of the sidebar flex column via margin-top:auto.
   Centered in the icon rail in both expanded and collapsed states. */
.sidebar-toggle {
  flex-shrink: 0;
  align-self: center;
  margin-top: auto;
  margin-bottom: var(--space-3);
  background: transparent;
  border: 1px solid var(--ink-700);
  color: var(--ink-400);
  width: 40px;
  height: 40px;
  border-radius: var(--r-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.sidebar-toggle:hover {
  background: var(--ink-800);
  color: var(--paper);
  border-color: var(--ink-500);
}
.sidebar-toggle:focus-visible {
  outline: 3px solid var(--brand-orange);
  outline-offset: 2px;
}
.sidebar-toggle .toggle-arrow {
  transition: transform var(--dur-base) var(--ease-out);
}
/* Arrow points LEFT when expanded (click to collapse).
   When collapsed, rotate 180deg so it points RIGHT (click to expand). */
.app-shell.sidebar-collapsed .sidebar-toggle .toggle-arrow {
  transform: rotate(180deg);
}

/* ===== Rule U27 — Topbar right-side global controls ===== */
.topbar-right { position: relative; }     /* anchor for absolutely-positioned dropdowns */

/* Topbar icons — Batch 2: light-on-dark inversion since the topbar is now ink-950.
   Light ink-300 stroke at rest, white on hover with ink-800 background. */
.topbar-icon-btn {
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink-300);
  width: 40px;
  height: 40px;
  border-radius: var(--r-full);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.topbar-icon-btn:hover {
  background: var(--ink-800);
  color: var(--paper);
}
.topbar-icon-btn:focus-visible {
  outline: 3px solid var(--brand-orange);
  outline-offset: 2px;
}
.topbar-icon-btn svg { display: block; }

/* User avatar circle — first initial in brand orange. Batch 2: text flipped to ink-950
   for higher contrast on the saturated orange (was white — looked muddy). */
.user-avatar {
  background: var(--brand-orange);
  color: var(--ink-950);
  width: 34px;
  height: 34px;
  border-radius: var(--r-full);
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  letter-spacing: 0;
  cursor: pointer;
  padding: 0;
  transition: background var(--dur-fast), box-shadow var(--dur-fast);
}
.user-avatar:hover {
  background: var(--brand-orange-hover);
}
.user-avatar:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--brand-orange-soft);
}
.user-avatar.lg {
  width: 44px;
  height: 44px;
  font-size: var(--fs-md);
  cursor: default;
}

/* ===== Topbar dropdown (profile, notifications) — Rule U22 chrome reused ===== */
.topbar-dropdown {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 280px;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  z-index: calc(var(--z-topbar) + 5);
  display: none;
  flex-direction: column;
  max-height: 70vh;
  overflow: hidden;
  animation: dropdownIn var(--dur-base) var(--ease-out);
}
.topbar-dropdown.open {
  display: flex;
}
.topbar-dropdown .dropdown-header {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--ink-200);
  background: var(--ink-50);
}
.topbar-dropdown .dropdown-header h4 {
  margin: 0;
  font-size: var(--fs-13);
  font-weight: var(--fw-semibold);
  color: var(--ink-900);
}
.topbar-dropdown .dropdown-body {
  padding: var(--space-2) 0;
  overflow-y: auto;
}
.dropdown-empty {
  padding: var(--space-4);
  color: var(--ink-500);
  font-size: var(--fs-sm);
  text-align: center;
  margin: 0;
}

/* Notifications dropdown — slightly wider */
.notif-dropdown { min-width: 320px; }

/* Profile dropdown header — large avatar + name/email/role */
.profile-dropdown { min-width: 280px; }
.profile-dropdown-header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-bottom: 1px solid var(--ink-200);
  background: var(--ink-50);
}
.profile-info { min-width: 0; flex: 1; }
.profile-name {
  font-weight: var(--fw-semibold);
  font-size: var(--fs-base);
  color: var(--ink-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.profile-email {
  font-size: var(--fs-sm);
  color: var(--ink-500);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.profile-role {
  font-size: var(--fs-2xs);
  color: var(--ink-700);
  background: var(--ink-200);
  display: inline-block;
  padding: 1px var(--space-2);
  border-radius: var(--r-pill);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  margin-top: 2px;
}

/* Dropdown items + dividers (reusable inside topbar + list-page menus + More menu) */
.dropdown-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  font-size: var(--fs-13);
  color: var(--ink-800);
  background: transparent;
  border: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.dropdown-item:hover {
  background: var(--ink-100);
  color: var(--ink-900);
  text-decoration: none;
}
.dropdown-item-danger {
  color: var(--danger);
}
.dropdown-item-danger:hover {
  background: var(--danger-soft);
  color: var(--danger);
}
.dropdown-divider {
  height: 1px;
  background: var(--ink-200);
  border: none;
  margin: var(--space-1) 0;
}
.dropdown-logout-form {
  margin: 0;
  padding: 0;
}

/* ===== Rule U28 — List-page three-dot (⋯) menu ===== */
.list-menu-wrap {
  position: relative;
  display: inline-block;
}
.list-menu-btn {
  background: transparent;
  border: 1px solid var(--ink-200);
  color: var(--ink-700);
  width: 36px;
  height: 36px;
  border-radius: var(--r-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.list-menu-btn:hover {
  background: var(--ink-100);
  color: var(--ink-900);
}
.list-menu-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 200px;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  z-index: var(--z-dropdown);
  padding: var(--space-1) 0;
  animation: dropdownIn var(--dur-base) var(--ease-out);
}

/* ===== Rule U32 — Detail-view header "More ▼" dropdown ===== */
.more-menu-wrap {
  position: relative;
  display: inline-block;
}
.more-menu-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  height: 32px;
  padding: 0 var(--space-3);
  background: transparent;
  border: 1px solid var(--ink-200);
  color: var(--ink-700);
  border-radius: var(--r-md);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.more-menu-btn:hover {
  background: var(--ink-100);
  color: var(--ink-900);
  border-color: var(--ink-300);
}
.more-menu-caret {
  font-size: 10px;
  margin-left: 2px;
  line-height: 1;
}
.more-menu-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 220px;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  z-index: var(--z-dropdown);
  padding: var(--space-1) 0;
  animation: dropdownIn var(--dur-base) var(--ease-out);
}

/* More menu lives inside .side-panel (z:101) — its overlay + dropdown must clear that.
   Without this, clicks inside the panel body wouldn't reach the overlay → menu wouldn't close. */
.more-menu-wrap > .dropdown-overlay { z-index: 102; }
.more-menu-wrap > .more-menu-dropdown { z-index: 103; }

/* ============================================================================
   BATCH B — Zoho-style layout shift (U29 + U30 + U31 + detail tabs)
   Replaces the right-side overlay panel with: list-rail + main-detail + full-screen-edit
   ============================================================================ */

/* ===== Rule U30 — List-to-detail collapse layout =====
   .vendors-shell switches between two modes via .with-detail class on the wrapper. */
.vendors-shell {
  display: flex;
  gap: var(--space-4);
  /* MR-Items-3 2026-06-02 — was not flex-growing inside .fullbleed-page, so the page-toolbar
     pushed it past the bottom + overflow:hidden clipped the last rows. flex:1 makes it claim
     the remaining vertical space; min-height:0 lets children shrink properly. */
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}

/* Mode 1 — no selection: list fills the whole main area (default state) */
.vendors-shell .list-pane {
  flex: 1 1 100%;
  min-width: 0;           /* prevent table-overflow from pushing past container */
}
.vendors-shell .detail-pane {
  display: none;
}

/* Mode 2 — vendor selected: list collapses to 300px rail, detail takes the rest */
.vendors-shell.with-detail .list-pane {
  flex: 0 0 300px;
  min-width: 300px;
  max-width: 300px;
}

/* Shared detail-pane chrome — applies to BOTH .with-detail and .with-edit so the
   pane is visible in either mode (this was the "edit mode black screen" bug). */
.vendors-shell.with-detail .detail-pane,
.vendors-shell.with-edit .detail-pane {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  overflow: hidden;        /* contain the detail/edit body scroll */
  /* MR-Items-3 2026-06-02 — removed `min-height: calc(100vh - topbar-h - space-12)` which
     ignored the page-toolbar + entity-tabs height above. With min-height: 0 the pane
     shrinks to fit available space and the body's overflow-y: auto scrolls properly. */
  min-height: 0;
}

/* Mode 3 — edit mode keeps the list rail visible (MR-2h founder override of original Rule U31).
   Founder direction 2026-05-29: "let's keep the left sidebar of the all the list and edit mode
   keep on the section of the size which is similar to the view view size. So in a user can see
   what's the other items already in the left pane as well." Rail stays as 300px; the edit pane
   takes the remaining width — same layout as view mode. Dirty-exit guard handles row-clicks
   on the rail (TryOpenView routes through TryExit so unsaved edits prompt before switching). */
.vendors-shell.with-edit .list-pane {
  flex: 0 0 300px;
  min-width: 300px;
  max-width: 300px;
}
.vendors-shell.with-edit .detail-pane {
  flex: 1 1 auto;
}

/* ===== List rail (narrow vendor list while detail is open) ===== */
.list-rail {
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* MR-Items-3 2026-06-02 — was `height: calc(100vh - topbar - space-12)` which exceeded
     the actual available space (page-toolbar + tabs ate into it) and pushed the rail past
     the viewport. With vendors-shell now flex-growing inside fullbleed-page, the rail just
     needs to fill its parent's height. */
  height: 100%;
}
.list-rail-header {
  flex-shrink: 0;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--ink-200);
  background: var(--ink-50);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
  color: var(--ink-700);
}
.list-rail-body {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
}
/* MR-3b 2026-05-29 — family group header inside the narrow rail (sub-asm, SKU
   rails get the same treatment as the full-list grouping). Sticky to the top
   of the scroll so the operator always sees which group the visible items
   belong to. */
.list-rail-group-header {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--ink-100);
  color: var(--ink-700);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 6px var(--space-4);
  border-top: 1px solid var(--ink-200);
  border-bottom: 1px solid var(--ink-200);
  border-left: 3px solid var(--brand-orange);
}
.list-rail-group-header:first-child { border-top: none; }
.list-rail-item {
  display: block;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--ink-100);
  cursor: pointer;
  background: var(--paper);
  border-left: 3px solid transparent;
  transition: background var(--dur-fast), border-left-color var(--dur-fast);
}
.list-rail-item:hover {
  background: var(--ink-50);
  text-decoration: none;
}
.list-rail-item.active {
  background: var(--accent-soft);
  border-left-color: var(--accent);
}
.list-rail-item .rail-name {
  font-weight: var(--fw-semibold);
  font-size: var(--fs-13);
  color: var(--ink-900);
  display: block;
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.list-rail-item .rail-code {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-500);
}
.list-rail-item.rail-deleted .rail-name {
  text-decoration: line-through;
  color: var(--ink-500);
}
/* Rail-item with photo thumbnail (Consumables, optionally Items) */
.list-rail-item:has(.rail-thumb), .list-rail-item:has(.rail-thumb-placeholder) {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.list-rail-item .rail-thumb {
  width: 32px;
  height: 32px;
  border-radius: 4px;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid var(--ink-200);
}
.list-rail-item .rail-thumb-placeholder {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  background: var(--ink-100);
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  border: 1px solid var(--ink-150, var(--ink-200));
}
.list-rail-item .rail-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.list-rail-back {
  display: flex;
  width: 100%;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  color: var(--ink-700);
  font-size: var(--fs-sm);
  font-family: inherit;
  cursor: pointer;
  margin-bottom: var(--space-3);
  transition: background var(--dur-fast);
}
.list-rail-back:hover {
  background: var(--ink-100);
  color: var(--ink-900);
}

/* ===== Detail pane (replaces the old side panel — lives in the main area) ===== */
.detail-pane-header {
  flex-shrink: 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--ink-200);
  background: var(--paper);
}
.detail-pane-header h2 {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  color: var(--ink-900);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}
.detail-pane-header .subtitle {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
  color: var(--ink-500);
}
.detail-pane-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  /* MR-Items-2 2026-06-02 — founder feedback: bottom content was getting cropped against
     the pane edge in both view + edit modes. Bumped bottom from space-8 to space-12 +
     added scroll-padding-bottom so the last form-field scrolls into a comfortable
     position instead of being flush with the viewport bottom. */
  padding: var(--space-5) var(--space-6) var(--space-12);
  scroll-padding-bottom: var(--space-8);
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}

/* ===== Detail-view tabs (Rule: every entity detail can have multiple tabs) ===== */
.detail-tabs {
  flex-shrink: 0;
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--ink-200);
  padding: 0 var(--space-6);
  background: var(--paper);
}
.detail-tab {
  background: transparent;
  border: none;
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--ink-500);
  cursor: pointer;
  font-family: inherit;
  border-bottom: 2px solid transparent;
  transition: color var(--dur-fast), border-bottom-color var(--dur-fast);
  margin-bottom: -1px;     /* overlap the parent border */
}
.detail-tab:hover {
  color: var(--ink-900);
}
.detail-tab.active {
  color: var(--brand-orange);
  border-bottom-color: var(--brand-orange);
  font-weight: var(--fw-semibold);
}
.detail-tab-content {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-5) var(--space-6) var(--space-8);
  min-width: 0;
}

/* ===== Full-screen edit (Rule U31) =====
   Same chrome as detail pane, but takes full main-area width. */
.edit-pane-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--ink-200);
  background: var(--paper);
}
.edit-pane-header h2 {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
}
.edit-pane-header .header-actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}
.edit-pane-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--space-5) var(--space-8) var(--space-8);
  min-width: 0;
}

/* MR-D7 2026-05-30 — founder hit "scroll not working in Sub-Assemblies edit mode".
   Root cause: <EditForm> renders a <form>, which becomes the SOLE child of
   .detail-pane (a flex column). The form has no flex layout so the inner
   .edit-pane-header + .edit-pane-body lose their flex behaviour and
   overflow-y:auto on the body never bounds. This class restores the chain:
   detail-pane → form → header + body, body scrolls inside the bounded form. */
.edit-pane-form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}
/* Edit grid wider in full-screen mode — use 3 cols on wide screens for space efficiency */
@media (min-width: 1200px) {
  .edit-pane-body .form-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
  .edit-pane-body .form-field-wide {
    grid-column: 1 / -1;
  }
  .edit-pane-body .view-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
  .edit-pane-body .view-grid .kv-wide {
    grid-column: 1 / -1;
  }
}

/* ===== Rule U29 — Topbar contextual search ===== */
/* Left-anchored next to the brand mark (Rajkumar's pref — Zoho-style placement). */
.topbar-search-wrap {
  flex: 0 0 320px;
  max-width: 320px;
  margin-left: var(--space-4);
}
.topbar-search {
  position: relative;          /* anchors the suggestions dropdown + the ✕ clear */
  width: 100%;
  display: flex;               /* icon + input are flex SIBLINGS now — the icon can never overlap the text */
  align-items: center;
  gap: var(--space-2);
}
.topbar-search-icon {
  position: static;            /* was absolute-over-the-input (emoji-width dependent → overlapped) */
  flex-shrink: 0;
  font-size: 14px;
  color: var(--ink-400);
  pointer-events: none;
}
/* Topbar search input — Batch 2 dark theme. Sits inside the ink-950 topbar so the input
   itself goes ink-800 with ink-700 border + white text. Orange focus ring replaces the
   accent-blue one. Sharp corners, factory feel. */
.topbar-search-input {
  flex: 1;
  min-width: 0;
  height: 32px;
  padding: 0 var(--space-8) 0 var(--space-3);        /* icon is an outside sibling now; right clears the ✕ */
  border: 1px solid var(--ink-700);
  border-radius: var(--radius-sharp);
  font-size: var(--fs-sm);
  font-family: inherit;
  background: var(--ink-800);
  color: var(--paper);
}
.topbar-search-input::placeholder {
  color: var(--ink-400);
}
.topbar-search-input:focus {
  outline: none;
  background: var(--ink-800);
  border-color: var(--brand-orange);
  box-shadow: none;              /* tight industrial focus — color change only, no glow */
}
.topbar-search-clear {
  position: absolute;
  right: var(--space-2);
  top: 50%;
  transform: translateY(-50%);
  background: var(--ink-300);
  border: none;
  color: var(--ink-800);
  width: 24px;
  height: 24px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: var(--fw-bold);
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  z-index: 2;                    /* sit above the input's text content */
  transition: background var(--dur-fast), color var(--dur-fast);
}
.topbar-search-clear:hover {
  background: var(--danger);
  color: var(--paper);
}
/* ===== History tab (audit log table) ===== */
.history-table {
  font-size: var(--fs-sm);
}
.history-table th { background: var(--ink-50); }
.pill-history-create  { background: var(--success-soft); color: var(--success); }
.pill-history-update  { background: var(--accent-soft);  color: var(--accent); }
.pill-history-delete  { background: var(--danger-soft);  color: var(--danger); }
.pill-history-restore { background: var(--warning-soft); color: var(--warning); }
.history-diff {
  background: var(--ink-50);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--ink-300);
  margin-top: var(--space-2);
  border-radius: var(--r-sm);
}
.history-diff pre {
  margin: 4px 0 0;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-700);
  white-space: pre-wrap;
  word-break: break-all;
}

/* ===== Friendly field-by-field history diff (HistoryDiff.razor) ===== */
.diff-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
}
.diff-table th {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  background: var(--ink-50);
  border-bottom: 1px solid var(--ink-200);
  font-weight: var(--fw-semibold);
  color: var(--ink-700);
}
.diff-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--ink-100);
  vertical-align: top;
  color: var(--ink-900);
}
.diff-table .diff-before {
  background: var(--danger-soft);
  color: var(--ink-700);
  text-decoration: line-through;
  text-decoration-color: rgba(185, 28, 28, .4);
}
.diff-table .diff-after {
  background: var(--success-soft);
  color: var(--ink-900);
  font-weight: var(--fw-medium);
}

.topbar-search-suggestions {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  z-index: calc(var(--z-topbar) + 5);
  max-height: 360px;
  overflow-y: auto;
  animation: dropdownIn var(--dur-base) var(--ease-out);
}

/* ===================================================================
   Zoho Link Manager (/zoho-sync) — Batch C5
   Two-pane: Local · IMS (left) vs Zoho · Mirror (right)
   =================================================================== */
.zsync-shell {
  display: flex;
  flex-direction: column;
  /* Topbar = 44px. We negate the .app-main padding (var(--space-6) on all sides)
     so the panes truly fill the viewport corner-to-corner — D2.5 founder feedback
     2026-05-28: "still not coverning full page its only in half page". */
  margin: calc(var(--space-6) * -1);
  padding: var(--space-3);
  height: calc(100vh - 44px);
  gap: 12px;
  box-sizing: border-box;
}
.zsync-header {
  position: relative;            /* anchor for orange anchor bar (Batch 6) */
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  padding: 8px 4px 12px 20px;   /* room for orange anchor bar on left */
  gap: 16px;
  border-bottom: 1px solid var(--ink-200);
  padding-bottom: 8px;
}
/* ZohoSync header — Batch 6: same Antonio uppercase + orange anchor bar pattern as
   .page-toolbar. The .zsync-header markup pre-dates the .page-toolbar convention so it
   needs its own selectors; visual result is identical. */
.zsync-header::before {
  content: "";
  position: absolute;
  left: 0; top: 8px; bottom: 12px;
  width: 4px;
  background: var(--brand-orange);
}
.zsync-header h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: var(--fw-bold);
  line-height: 0.95;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--ink-950);
}
.zsync-header .subtitle {
  margin: 6px 0 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  color: var(--ink-500);
  text-transform: uppercase;
  font-weight: var(--fw-medium);
}
.zsync-header .subtitle strong { color: var(--ink-900); font-weight: var(--fw-semibold); }
.zsync-header-right .hint {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-400);
}

/* ───── Tabs (Items / Consumables / SKUs / Vendors / Prices) ───── */
.zsync-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--ink-200);
  padding: 0 4px;
}
.zsync-tab {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: none;
  background: transparent;
  color: var(--ink-700);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  border-radius: var(--r-md) var(--r-md) 0 0;
  border-bottom: 2px solid transparent;
  transition: all var(--dur-base) var(--ease-out);
}
.zsync-tab:hover:not(.disabled):not(.active) {
  background: var(--ink-100);
}
/* Active tab — Batch 7 industrial polish (2026-05-23). Brand-orange underline replaces
   the previous accent-blue. Matches the table sort-active treatment. Sharp + mono.  */
.zsync-tab.active {
  color: var(--ink-950);
  border-bottom-color: var(--brand-orange);
  background: var(--paper);
  box-shadow: inset 0 -2px 0 var(--brand-orange);
  font-weight: var(--fw-semibold);
}
.zsync-tab.disabled {
  color: var(--ink-400);
  cursor: not-allowed;
}
.zsync-tab-icon {
  font-size: 16px;
}
.zsync-tab-count {
  margin-left: 6px;
  font-weight: 500;
  font-size: 12px;
  background: var(--paper);
  border: 1px solid var(--ink-300);
  padding: 1px 8px;
  border-radius: 10px;
  color: var(--ink-700);
}
.zsync-tab-soon {
  margin-left: 6px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  background: var(--ink-200);
  color: var(--ink-500);
  padding: 1px 6px;
  border-radius: 6px;
}

/* ───── Two-pane body ───── */
.zsync-panes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr;          /* fixes pane collapse — without this, panes are content-height */
  gap: 12px;
  flex: 1;
  min-height: 0;
  min-width: 0;
}
.zsync-pane {
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  min-height: 0;                     /* lets the inner list shrink/scroll instead of overflowing */
  min-width: 0;
  overflow: hidden;
}
.zsync-pane-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--ink-200);
  background: var(--ink-50);
}
.zsync-pane-header strong {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-900);
}
.zsync-pane-icon {
  margin-right: 6px;
}
.zsync-pane-count {
  margin-left: 10px;
  font-size: 12px;
  color: var(--ink-500);
}
.zsync-pane-search {
  padding: 10px 14px 6px 14px;
}
.zsync-search-wrap {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.zsync-search-input {
  flex: 1;
  min-width: 0;
  padding: 9px 36px 9px 12px;   /* icon is an outside sibling now; right clears the ✕ */
  font-size: 13px;
  border: 1px solid var(--ink-300);
  border-radius: var(--r-md);
  background: var(--paper);
  color: var(--ink-900);
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
}
.zsync-search-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
.zsync-search-icon {
  position: static;
  flex-shrink: 0;
  font-size: 13px;
  color: var(--ink-400);
  pointer-events: none;
}
.zsync-search-clear {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
  background: var(--ink-200);
  border: none;
  color: var(--ink-700);
  width: 22px;
  height: 22px;
  border-radius: 50%;
  font-size: 11px;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.zsync-search-clear:hover { background: var(--ink-300); }

/* Bulk-action row above each list — sticky so it stays visible while scrolling.
   Keeps the TableFilterDropdown menu above the table body. Founder 2026-07-06: dropped from
   z-index:100 to just below the topbar so the profile popup no longer hides behind this row. */
.zsync-bulk-row {
  position: sticky;
  top: 0;
  z-index: calc(var(--z-topbar) - 5);
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 500;
  border-bottom: 1px solid var(--ink-200);
  background: var(--ink-50);
  box-shadow: 0 1px 2px rgba(0,0,0,.04);
}
.zsync-bulk-row.has-selection {
  background: var(--accent-soft);
  border-bottom-color: var(--accent);
  color: var(--ink-900);
  font-weight: 600;
}
.zsync-bulk-check {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--ink-700);
  cursor: pointer;
  user-select: none;
}
.zsync-bulk-check input[type="checkbox"] {
  width: 18px;
  height: 18px;
  cursor: pointer;
  accent-color: var(--accent);
}
.zsync-link-btn {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 2px 4px;
  text-decoration: underline;
}
.zsync-link-btn:hover { color: var(--accent-hover); }

/* Per-row checkbox */
.zsync-row-check {
  width: 18px;
  height: 18px;
  cursor: pointer;
  flex-shrink: 0;
  accent-color: var(--accent);
}
.zsync-row-check-disabled {
  width: 18px;
  height: 18px;
  border-radius: 3px;
  background: var(--ink-100);
  border: 1px solid var(--ink-200);
}
.zsync-row-selected {
  background: #E0EBFE !important;   /* deeper than accent-soft so selection reads */
}
.zsync-row-selected::before {
  background: var(--accent);         /* 3px accent bar on the left edge */
}
.zsync-row-selected:hover {
  background: #D5E2FC !important;
}
.zsync-pane-header-actions {
  display: flex;
  gap: 6px;
  align-items: center;
}

/* PicklistManager header: title + ✕ close button on the right (Rule U9 / Part 4 polish) */
.picklist-modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

/* ───── PicklistManager table (Rule U36 + U37) ─────
   - Compact: no horizontal scroll needed
   - Sticky Actions column (right edge) so ✎ 🔄 ⏸ 🗑 buttons are always reachable
   - Sticky thead inside the modal scroll context */
.picklist-table-wrap {
  overflow: auto;
  max-height: 380px;
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  background: var(--paper);
}
.picklist-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
  table-layout: fixed;          /* honor the per-column widths below */
}
.picklist-table th,
.picklist-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--ink-100);
  vertical-align: middle;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.picklist-table thead th {
  position: sticky;
  top: 0;
  background: #f3f4f6;
  font-weight: 600;
  color: var(--ink-700);
  z-index: 2;
  box-shadow: 0 1px 0 var(--ink-200);
}
.picklist-table .col-value   { width: 30%; }
.picklist-table .col-label   { width: 38%; }
.picklist-table .col-usage   { width: 14%; text-align: right; }
.picklist-table .col-actions { width: 18%; text-align: right; white-space: nowrap; }
/* Sticky right-edge Actions column (U37 — action buttons always reachable, no scroll required) */
.picklist-table td.col-actions,
.picklist-table th.col-actions {
  position: sticky;
  right: 0;
  background: var(--paper);
  box-shadow: -2px 0 4px rgba(0,0,0,.04);
  z-index: 1;
}
.picklist-table th.col-actions { background: #f3f4f6; z-index: 3; }
.picklist-table tr:hover td.col-actions { background: var(--ink-50); }
.picklist-table tr.row-inactive { opacity: .55; }
.field-inline { padding: 4px 8px; font-size: 13px; }
.btn-icon {
  /* M3 audit 2026-06-14 — was 26×26px (far under M3's 40dp icon-button box / 48dp touch target).
     Bumped to 34×34px: a much larger, reliable hit area that still fits the 44px data-table rows.
     (Standalone icon buttons outside dense tables could go to the full 40px if needed.) */
  background: transparent;
  border: 1px solid transparent;
  width: 34px;
  height: 34px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-700);
}
.btn-icon:hover:not(:disabled) { background: var(--ink-100); border-color: var(--ink-300); }
.btn-icon:disabled { color: var(--ink-300); cursor: not-allowed; }

/* M3 audit 2026-06-14 — `.btn-sm` was USED across pages (Dispatch Log, Factory Expenses, etc.) but
   never DEFINED, so those buttons silently fell back to the base size. Define a real M3 "small"
   (~32dp / extra-small): a touch denser than the 38dp default but still comfortably tappable. */
.btn-sm {
  min-height: 32px;
  padding: 6px 12px;
  font-size: 12px;
}

/* Rule U36 — tiny inline icon button (e.g. ✎ next to a form-field label to open PicklistManager) */
.btn-link-tiny {
  background: transparent;
  border: none;
  color: var(--ink-500);
  font-size: 12px;
  cursor: pointer;
  padding: 1px 4px;
  margin-left: 4px;
  border-radius: 4px;
}
.btn-link-tiny:hover { background: var(--ink-100); color: var(--accent); }

/* Pill fallback for lookup values without a defined .pill-* CSS class (U36) */
.pill-neutral {
  background: var(--ink-200);
  color: var(--ink-700);
}

/* Generic pill colors for the U36 color picker (PicklistManager). When an admin adds a
   new lookup value, they pick one of these 8 swatches; the chosen class is stored in
   Lookup.pill_class and applied wherever the value renders as a pill. Hue/value pairs
   chosen for clear contrast on both light and dark text without screaming. */
.pill-color-orange { background: #fed7aa; color: #9a3412; }
.pill-color-blue   { background: #dbeafe; color: #1e40af; }
.pill-color-green  { background: #d1fae5; color: #065f46; }
.pill-color-purple { background: #ede9fe; color: #5b21b6; }
.pill-color-red    { background: #fee2e2; color: #991b1b; }
.pill-color-yellow { background: #fef3c7; color: #92400e; }
.pill-color-teal   { background: #ccfbf1; color: #115e59; }
.pill-color-gray   { background: var(--ink-200); color: var(--ink-700); }

/* Swatch grid in the PicklistManager Add form — small circular swatches the admin
   clicks to pick a color. Selected one gets a 2px ring. */
.swatch-grid {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
}
.swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
  transition: transform var(--dur-fast);
}
.swatch:hover { transform: scale(1.1); }
.swatch.swatch-selected { border-color: var(--ink-900); }
.swatch-clear {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px dashed var(--ink-400);
  background: transparent;
  color: var(--ink-500);
  font-size: 11px;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Small icon-only danger button (per-row Unlink) */
.btn-icon-danger {
  background: transparent;
  border: 1px solid transparent;
  color: var(--danger);
  width: 26px;
  height: 26px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all var(--dur-base) var(--ease-out);
}
.btn-icon-danger:hover {
  background: var(--danger-soft);
  border-color: var(--danger);
}
.zsync-chip-row {
  display: flex;
  gap: 6px;
  padding: 0 12px 8px 12px;
  flex-wrap: wrap;
}
.zsync-chip {
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 600;
  background: var(--paper);
  border: 1px solid var(--ink-300);
  color: var(--ink-700);
  border-radius: 999px;
  cursor: pointer;
  transition: all var(--dur-base) var(--ease-out);
}
.zsync-chip:hover {
  background: var(--ink-100);
}
.zsync-chip.active {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}

/* ───── Row list (virtualized) ───── */
.zsync-pane-list {
  flex: 1;
  min-height: 200px;                 /* fallback so Virtualize always has a viewport, even if flex math fails */
  overflow-y: auto;
  background: var(--paper);
  /* Rule U34 — sticky header context for the list itself. The pane header + chips + bulk row
     are siblings ABOVE this scroll container (not inside it), so they stay visible naturally
     when the user scrolls the list. No extra sticky needed inside the list. */
}
.zsync-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 18px;
  border-bottom: 1px solid var(--ink-100);
  gap: 14px;
  min-height: 64px;
  position: relative;
  transition: background-color 120ms var(--ease-out);
}
.zsync-row::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: transparent;
  transition: background 120ms var(--ease-out);
}
.zsync-row:hover {
  background: var(--ink-50);
}
.zsync-row-remote { min-height: 72px; }
.zsync-row-remote {
  background: linear-gradient(to right, transparent 0%, var(--info-soft) 100%);
  background-size: 0% 100%;
  background-repeat: no-repeat;
}
.zsync-row-zoho-deleted {
  opacity: .55;
  text-decoration: line-through;
}
.zsync-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.zsync-row-name {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.zsync-row-name strong {
  font-size: 14px;
  color: var(--ink-900);
}
.zsync-row-code {
  font-size: 11px;
  background: var(--ink-100);
  color: var(--ink-700);
  padding: 1px 6px;
  border-radius: 4px;
  font-family: var(--font-mono, monospace);
}
.zsync-row-type {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  background: var(--ink-200);
  color: var(--ink-700);
  padding: 1px 6px;
  border-radius: 6px;
}
.zsync-row-gst {
  font-size: 11px;
  color: var(--ink-500);
  font-family: var(--font-mono, monospace);
}
.zsync-row-meta {
  display: flex;
  gap: 10px;
  font-size: 12px;
  color: var(--ink-500);
  flex-wrap: wrap;
}
.zsync-row-cat {
  font-size: 11px;
  background: var(--accent-soft);
  color: var(--accent);
  padding: 1px 6px;
  border-radius: 4px;
  font-weight: 600;
}
.zsync-row-zid {
  font-family: var(--font-mono, monospace);
  font-size: 10px;
  color: var(--ink-400);
}
.zsync-row-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Status pills in Zoho-sync panes — Batch 7 industrial polish. Match the new base
   .pill conventions (mono caps + sharp corners + 0.06em tracking). */
.pill-linked {
  background: var(--success-soft);
  color: var(--success);
  padding: 3px 8px;
  border-radius: var(--radius-sharp);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.pill-unlinked {
  background: var(--warning-soft);
  color: var(--warning);
  padding: 3px 8px;
  border-radius: var(--radius-sharp);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.pill-zohoonly {
  background: var(--info-soft);
  color: var(--info);
  padding: 3px 8px;
  border-radius: var(--radius-sharp);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: var(--fw-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ───── Empty + "coming soon" placeholders ───── */
.zsync-empty {
  padding: 32px 16px;
  text-align: center;
  color: var(--ink-500);
}
.zsync-empty p { margin: 4px 0; }
.zsync-coming-soon {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.zsync-coming-card {
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-lg);
  padding: 48px 64px;
  text-align: center;
  max-width: 540px;
}
.zsync-coming-card h2 {
  font-size: 22px;
  margin-bottom: 8px;
  color: var(--ink-700);
}
.zsync-coming-card p {
  margin: 4px 0;
  color: var(--ink-500);
}

/* Small button sizes for the panes */
.btn-xs {
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.5;
  border-radius: 6px;
  min-height: 28px;
}
.btn-sm {
  padding: 6px 16px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 6px;
  min-height: 32px;
}

/* Confirm-modal row preview list */
.zsync-confirm-preview {
  margin: 12px 0 4px 0;
  padding: 10px 14px;
  background: var(--ink-50);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  font-size: 13px;
  max-height: 220px;
  overflow-y: auto;
}
.zsync-confirm-preview ul {
  margin: 0;
  padding-left: 18px;
}
.zsync-confirm-preview li {
  padding: 2px 0;
  color: var(--ink-700);
}
.zsync-confirm-preview .more-line {
  margin-top: 6px;
  color: var(--ink-500);
  font-style: italic;
}

/* Rows-per-page selector (Rule U33 — applies to every list/table page) */
.rpp-wrap {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--ink-700);
}
.rpp-select {
  padding: 3px 8px;
  font-size: 12px;
  border: 1px solid var(--ink-300);
  border-radius: 6px;
  background: var(--paper);
  color: var(--ink-900);
  cursor: pointer;
}
.rpp-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-ring);
}
.pagination-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  font-size: 13px;
  border-top: 1px solid var(--ink-200);
  background: var(--ink-50);
  /* MR-2k 2026-05-29 founder: "pagination should stick to the bottom… users
     can see how many pages or items it's showing as of now instead of at
     the end of the scroll." When the parent .fullbleed-page provides a
     fixed-height stacking layout, this flex-shrink:0 + sticky bottom keeps
     the pagination chrome anchored to the viewport bottom even during table
     vertical scroll. */
  position: sticky;
  bottom: 0;
  z-index: 8;
  flex-shrink: 0;
}
.pagination-controls {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.pagination-btn {
  padding: 4px 10px;
  font-size: 12px;
  border: 1px solid var(--ink-300);
  background: var(--paper);
  color: var(--ink-700);
  border-radius: 4px;
  cursor: pointer;
  min-width: 32px;
}
.pagination-btn:hover:not(:disabled) {
  background: var(--ink-100);
  border-color: var(--ink-400);
}
.pagination-btn:disabled {
  color: var(--ink-300);
  cursor: not-allowed;
}
.pagination-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}

/* MR-Items-1 2026-06-02 — per-section tabs (List + Anomalies). Sits between page-toolbar and
   the content table. Same look pattern as the SubAssemblies page's 3-tab strip but slimmer
   because Items only has 2 tabs. */
.entity-tabs {
  display: flex;
  gap: 0;
  margin: 0 var(--space-4) 0;
  border-bottom: 1px solid var(--ink-200);
  background: transparent;
}
.entity-tab {
  appearance: none;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 18px 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-500);
  cursor: pointer;
  transition: color var(--dur-fast), border-color var(--dur-fast);
  margin-bottom: -1px;
}
.entity-tab:hover { color: var(--ink-700); }
.entity-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* MR-Items-1 — Sub-Assembly row appearing inside the Items list. Faded tint + slightly
   muted text so the eye picks the bicycle-parts (Item rows) up first. Click anywhere
   in the row deep-links to /sub-assemblies?focus={id}. */
.data-table tbody tr.row-subasm {
  background: var(--ink-50);
}
.data-table tbody tr.row-subasm:hover {
  background: var(--ink-100);
}
.data-table tbody tr.row-subasm td {
  color: var(--ink-700);
}
.badge-subasm {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  background: #ede9fe;
  color: #5b21b6;
  border-radius: 10px;
  vertical-align: middle;
}

/* MR-Items-1 — Anomalies tab: severity stat tiles + table pills. Four severity bands:
   high (red), medium (amber), low (slate-grey), info (blue). */
.anomaly-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin: 12px var(--space-4);
}
.anomaly-stat {
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-left: 4px solid var(--ink-300);
  border-radius: var(--r-md);
  padding: 12px 16px;
}
.anomaly-stat-count {
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--ink-900);
}
.anomaly-stat-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-top: 2px;
}
.anomaly-stat-high   { border-left-color: #dc2626; }
.anomaly-stat-medium { border-left-color: #d97706; }
.anomaly-stat-low    { border-left-color: #64748b; }
.anomaly-stat-info   { border-left-color: #2563eb; }

.anomaly-pill {
  display: inline-block;
  padding: 2px 10px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  border-radius: 10px;
}
.anomaly-pill-high   { background: #fee2e2; color: #991b1b; }
.anomaly-pill-medium { background: #fed7aa; color: #9a3412; }
.anomaly-pill-low    { background: #e2e8f0; color: #475569; }
.anomaly-pill-info   { background: #dbeafe; color: #1e40af; }

/* MR-Items-2 2026-06-02 — per-rule sectioned anomaly layout. Each rule gets its own
   collapsible <details> block with severity pill + label + count in the summary bar. */
.anomaly-sections {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 12px var(--space-4) 20px;
}
.anomaly-section {
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-left: 4px solid var(--ink-300);
  border-radius: var(--r-md);
  overflow: hidden;
}
.anomaly-section-high   { border-left-color: #dc2626; }
.anomaly-section-medium { border-left-color: #d97706; }
.anomaly-section-low    { border-left-color: #64748b; }
.anomaly-section-info   { border-left-color: #2563eb; }
.anomaly-section-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  user-select: none;
  background: var(--ink-50);
  transition: background var(--dur-fast);
}
.anomaly-section-summary::-webkit-details-marker { display: none; }
.anomaly-section-summary:hover { background: var(--ink-100); }
.anomaly-section-label {
  flex: 1;
  font-weight: 600;
  color: var(--ink-900);
}
.anomaly-section-count {
  background: var(--ink-200);
  color: var(--ink-700);
  font-weight: 700;
  font-size: 11px;
  padding: 2px 10px;
  border-radius: 10px;
  min-width: 28px;
  text-align: center;
}
.anomaly-section-caret {
  font-size: 12px;
  color: var(--ink-500);
  transition: transform var(--dur-fast);
}
.anomaly-section[open] .anomaly-section-caret { transform: rotate(180deg); }
.anomaly-section .table-wrap {
  border-top: 1px solid var(--ink-200);
  margin: 0;
  border-radius: 0;
}
.anomaly-section .data-table { margin: 0; }

/* MR-Items-5c 2026-06-02 — horizontal tab strip for the Anomalies sub-tab (founder ask:
   browser-tab style switcher across the top, one tab per rule, severity in brackets). */
.anomaly-tab-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin: 12px var(--space-4) 0;
  padding: 0;
  border-bottom: 1px solid var(--ink-200);
}
.anomaly-tab {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 9px 16px;
  font-size: 12.5px;
  font-weight: 600;
  font-family: inherit;
  background: var(--ink-50);
  border: 1px solid var(--ink-200);
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  margin-bottom: -1px;
  cursor: pointer;
  color: var(--ink-600);
  border-top: 3px solid var(--ink-300);
  transition: background var(--dur-fast), color var(--dur-fast);
}
.anomaly-tab:hover {
  background: var(--paper);
  color: var(--ink-900);
}
.anomaly-tab.active {
  background: var(--paper);
  color: var(--ink-900);
  position: relative;
  z-index: 1;
}
/* Severity stripe on top edge: muted by default, saturated when active. */
.anomaly-tab-high          { border-top-color: rgba(220, 38, 38, 0.35); }
.anomaly-tab-high.active   { border-top-color: #dc2626; }
.anomaly-tab-medium        { border-top-color: rgba(217, 119, 6, 0.35); }
.anomaly-tab-medium.active { border-top-color: #d97706; }
.anomaly-tab-low           { border-top-color: rgba(100, 116, 139, 0.35); }
.anomaly-tab-low.active    { border-top-color: #64748b; }
.anomaly-tab-info          { border-top-color: rgba(37, 99, 235, 0.35); }
.anomaly-tab-info.active   { border-top-color: #2563eb; }
.anomaly-tab-label { font-weight: 600; }
.anomaly-tab-meta {
  font-weight: 400;
  font-size: 11px;
  color: var(--ink-500);
  letter-spacing: 0.2px;
}
.anomaly-tab.active .anomaly-tab-meta { color: var(--ink-700); }

/* MR-Items-6 2026-06-02 — Price tab: bulk action bar + status pills + delta colours +
   applied tag. Sits below the anomaly-tab styles since it shares the same .data-table chrome. */
.price-bulk-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  margin: 12px var(--space-4) 0;
  background: var(--ink-50);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  font-size: 13px;
}
.price-select-all {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  font-weight: 600;
  color: var(--ink-700);
}
.price-bulk-spacer { flex: 1; }
.price-status-pill {
  display: inline-block;
  padding: 2px 10px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  border-radius: 10px;
}
.price-status-billed    { background: #d1fae5; color: #065f46; }
.price-status-open      { background: #fed7aa; color: #9a3412; }
.price-status-closed    { background: #e2e8f0; color: #475569; }
.price-status-cancelled { background: #fee2e2; color: #991b1b; }
.price-status-other     { background: var(--ink-200); color: var(--ink-700); }
.price-up   { color: #dc2626; font-weight: 600; }
.price-down { color: #2563eb; font-weight: 600; }
.btn-applied-tag {
  appearance: none;
  border: 1px solid #bbf7d0;
  background: #f0fdf4;
  color: #065f46;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 6px;
  font-size: 12px;
  cursor: default;
  opacity: 0.85;
}

/* MR-Items-7 — clickable PO ref on the Price tab opens a popup modal with PO details. */
.po-ref-link {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dashed var(--accent);
  cursor: pointer;
}
.po-ref-link:hover {
  color: var(--ink-900);
  border-bottom-style: solid;
}

/* MR-Logistics-3 · 2026-06-02 — searchable PO picker (replaces the big check-table inside
   the combined add-event modal). Chip strip + dropdown + search input. */
.po-picker-wrap { position: relative; }
.po-chip-strip {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.po-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 14px;
  padding: 3px 8px;
  font-size: 12px;
  color: var(--ink-700, #3f3f46);
}
.po-chip code { font-family: var(--font-mono); font-weight: 600; }
.po-chip-x {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--ink-500, #6b7280);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
}
.po-chip-x:hover { color: var(--danger, #dc2626); }
.po-search-input { width: 100%; }
.po-search-dropdown {
  /* Code review · 2026-06-08 — taller dropdown (was 280px). Founder feedback:
     "window is too small to show all POs, and I have to scroll it down". */
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 30;
  background: #fff;
  border: 1px solid var(--border, #d4d4d8);
  border-radius: 6px;
  max-height: 480px;
  overflow-y: auto;
  margin-top: 2px;
  box-shadow: 0 6px 18px rgba(0,0,0,.08);
}
.po-search-row {
  appearance: none;
  border: none;
  background: #fff;
  display: grid;
  grid-template-columns: 140px 1fr 110px 90px auto;
  gap: 8px;
  align-items: center;
  width: 100%;
  padding: 8px 10px;
  font-size: 12px;
  text-align: left;
  cursor: pointer;
  border-bottom: 1px solid #f3f4f6;
}
.po-search-row:hover:not(:disabled) { background: #f9fafb; }
.po-search-row:disabled { color: var(--ink-500, #6b7280); cursor: default; }
.po-search-row code { font-family: var(--font-mono); }
.po-search-vendor { font-weight: 500; }
.po-search-row.is-selected { background: #f3f4f6; }

/* Freight-line detection banner + pill. */
.freight-banner {
  background: #fef3c7;
  border: 1px solid #fcd34d;
  color: #92400e;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 12px;
  line-height: 1.5;
}
.pill.pill-warn {
  background: #fef3c7;
  color: #92400e;
  border: 1px solid #fcd34d;
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 8px;
  text-transform: uppercase;
  letter-spacing: .3px;
  font-weight: 600;
}

/* MR-Items-Phase5+ · 2026-06-02 — colour swatch column on the PicklistManager main table.
   Swatch is a clickable button (admin-only) that opens a small palette popover for reassign. */
.swatch-btn {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  border: 1px solid var(--border, #d4d4d8);
  cursor: pointer;
  padding: 0;
  background: var(--swatch-bg, #e5e7eb);
  font-size: 11px;
  line-height: 20px;
  text-align: center;
  vertical-align: middle;
}
.swatch-btn:disabled { cursor: default; opacity: .8; }
.swatch-btn.swatch-empty {
  background: repeating-linear-gradient(45deg, #fff, #fff 3px, #e5e7eb 3px, #e5e7eb 6px);
  border-style: dashed;
}
.swatch-btn.pill-color-orange { background: #fed7aa; border-color: #f97316; }
.swatch-btn.pill-color-red    { background: #fecaca; border-color: #ef4444; }
.swatch-btn.pill-color-yellow { background: #fef08a; border-color: #eab308; }
.swatch-btn.pill-color-green  { background: #bbf7d0; border-color: #22c55e; }
.swatch-btn.pill-color-teal   { background: #99f6e4; border-color: #14b8a6; }
.swatch-btn.pill-color-blue   { background: #bfdbfe; border-color: #3b82f6; }
.swatch-btn.pill-color-purple { background: #ddd6fe; border-color: #8b5cf6; }
.swatch-btn.pill-color-gray   { background: #e5e7eb; border-color: #6b7280; }
.pill-picker-popover {
  position: absolute;
  top: 30px;
  left: 50%;
  transform: translateX(-50%);
  background: #fff;
  border: 1px solid var(--border, #d4d4d8);
  border-radius: 6px;
  padding: var(--space-2);
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
  width: 220px;
  box-shadow: 0 6px 20px rgba(0,0,0,.08);
  z-index: 50;
}

/* MR-Items-Phase5+ · 2026-06-02 — info button next to Computed WAC for the breakdown popover. */
.wac-info-btn {
  appearance: none;
  border: 1px solid var(--border, #d4d4d8);
  background: #fff;
  color: var(--accent, #3b82f6);
  width: 18px;
  height: 18px;
  border-radius: 50%;
  font-size: 11px;
  line-height: 1;
  margin-left: 4px;
  cursor: pointer;
  padding: 0;
  vertical-align: middle;
}
.wac-info-btn:hover { background: var(--accent, #3b82f6); color: #fff; }
.wac-info-btn:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }

/* MR-Logistics · 2026-06-02 — Add Event modal form layout. Two-column grid with
   .field-full spanning both. Labels above inputs, consistent gap.  */
.logistics-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 16px;
  margin: 14px 0 4px;
}
.logistics-form .field-full { grid-column: 1 / -1; }
.logistics-form label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-700, #3f3f46);
  margin-bottom: 4px;
  letter-spacing: .2px;
}
.logistics-form .field {
  width: 100%;
  padding: 7px 10px;
  border: 1px solid var(--border, #d4d4d8);
  border-radius: 6px;
  background: #fff;
  font-size: 13px;
  font-family: inherit;
  box-sizing: border-box;
}
.logistics-form .field:focus {
  outline: none;
  border-color: var(--accent, #3b82f6);
  box-shadow: 0 0 0 2px rgba(59,130,246,.15);
}
.logistics-form textarea.field { resize: vertical; min-height: 56px; }
.logistics-form .field-hint {
  font-size: 11px;
  color: var(--ink-500, #6b7280);
  margin-top: 4px;
}
.logistics-form .modal-actions {
  grid-column: 1 / -1;
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--border, #e5e7eb);
}

/* MR-Items-Phase5 — Apply button on the Price tab. All three states (Apply / Applied /
   No history) share a fixed width + icon-label layout so the column reads consistently. */
.price-apply-btn {
  width: 120px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 10px;
  font-size: 12px;
  white-space: nowrap;
}
.price-apply-btn .apply-icon {
  font-size: 13px;
  line-height: 1;
}

/* MR-Items-6 — PicklistManager near-duplicate detector banner + group list. */
.dup-banner {
  margin: 0 0 10px 0;
}
.dup-banner-toggle {
  appearance: none;
  border: 1px solid #fde68a;
  background: #fef3c7;
  color: #92400e;
  font-weight: 600;
  padding: var(--space-2) var(--space-3);
  border-radius: 6px;
  font-size: 12.5px;
  cursor: pointer;
  width: 100%;
  text-align: left;
}
.dup-banner-toggle:hover { background: #fef9e2; }
.dup-group-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0 0 12px 0;
}
.dup-group {
  background: var(--ink-50);
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  padding: 10px 14px;
}
.dup-group-header {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--ink-500);
  margin-bottom: var(--space-2);
}
.dup-group-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 8px;
}
.dup-variant-row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  cursor: pointer;
}
.dup-group-actions {
  display: flex;
  gap: 8px;
}

/* MR-Items-5 2026-06-02 — Item image upload + view-mode hero. */
.item-image-hero {
  display: block;
  max-width: 320px;
  max-height: 240px;
  width: auto;
  height: auto;
  object-fit: contain;
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  background: var(--ink-50);
}
.item-image-editor {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.item-image-editor .preview-thumb {
  display: block;
  max-width: 200px;
  max-height: 200px;
  width: auto;
  height: auto;
  object-fit: contain;
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md);
  background: var(--ink-50);
}

/* MR-Items-5b 2026-06-02 — Items list thumbnail column (so operators can scan which items
   have images at a glance) + view-mode click-to-zoom lightbox. */
.item-list-thumb {
  display: block;
  width: 36px;
  height: 36px;
  object-fit: cover;
  border: 1px solid var(--ink-200);
  border-radius: 4px;
  background: var(--ink-50);
  margin: 0 auto;
}
.item-image-hero { cursor: zoom-in; }
.item-image-hero:hover { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18); }

.image-lightbox-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.86);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10000;
  padding: 40px;
  cursor: zoom-out;
  animation: lightbox-fade-in 0.15s ease-out;
}
@keyframes lightbox-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.image-lightbox-img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
  cursor: default;
  background: #1a1a1a;
}
.image-lightbox-close {
  position: absolute;
  top: 20px;
  right: 24px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.15);
  color: white;
  font-size: 22px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--dur-fast);
}
.image-lightbox-close:hover {
  background: rgba(255, 255, 255, 0.28);
}

/* MR-Items-2 2026-06-02 — LookupSelect (reusable Lookup-backed <select> with inline +Add). */
.lookup-select-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.lookup-add-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  padding: var(--space-2) var(--space-2);
  background: var(--ink-50);
  border: 1px dashed var(--ink-300);
  border-radius: var(--r-md);
}
.lookup-add-row .field {
  flex: 1;
  min-width: 0;
}

/* MR-WAC-Consistency · 2026-06-03 — Founder Rule 15 deep-link flash. Applied for ~2s
   to a table row that was scrolled into view from another tab/page so the operator's
   eye lands on it. Amber double-ring matches the V3.2 reference pattern. */
.flash-amber {
  box-shadow: 0 0 0 4px #fbbf24, 0 0 0 6px rgba(251,191,36,.4) !important;
  transition: box-shadow .25s ease-out;
}

/* MR-V32-ProdLog · 2026-06-03 — UI polish on Production Log (Frame Activity) page. */
.badge-soon {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 7px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--ink-100);
  color: var(--ink-500);
  border-radius: var(--r-sm, 4px);
  border: 1px solid var(--ink-200);
  vertical-align: middle;
}
.prod-log-day-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 14px;
}
.prod-log-date-chip {
  display: inline-flex;
  align-items: stretch;
  background: #fff;
  border: 1px solid var(--ink-200);
  border-radius: var(--r-md, 6px);
  overflow: hidden;
  box-shadow: 0 1px 0 rgba(15, 23, 42, 0.04);
}
.prod-log-date-chip .seg-btn.day-step {
  border: none;
  border-radius: 0;
  background: var(--ink-50);
  color: var(--ink-600);
  padding: 6px 10px;
  font-size: 12px;
}
.prod-log-date-chip .seg-btn.day-step:hover {
  background: var(--ink-100);
}
.prod-log-date-chip .date-input {
  border: none;
  border-radius: 0;
  width: 150px;
  padding: 6px 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-900);
  background: #fff;
  text-align: center;
  border-left: 1px solid var(--ink-200);
  border-right: 1px solid var(--ink-200);
}
.prod-log-date-chip .date-input:focus {
  outline: none;
  background: var(--brand-orange-50, #fff7ed);
}
.prod-log-date-chip .seg-btn.day-today {
  border: none;
  border-radius: 0;
  background: #fff;
  padding: 6px 12px;
  font-weight: 600;
  border-left: 1px solid var(--ink-200);
}
.prod-log-date-chip .seg-btn.day-today.active {
  background: var(--brand-orange, #f97316);
  color: #fff;
}

/* ===== HR / shared-component utilities (MR-HR-CSS · 2026-06-23) =====
   Classes used by the HR module (Employees, PayRuns, Leave, Reimbursements)
   and new dashboard pages (ProductionDashboard) that were not yet in the
   global sheet. Defined here once so they stay consistent across pages. */

/* ── form-control (Bootstrap-compatible alias → matches app's .field style) ── */
.form-control {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-sharp);
  font-size: 13px;
  font-family: inherit;
  background: var(--paper);
  color: var(--ink-900);
  transition: border-color var(--dur-fast);
  min-height: 36px;           /* standard input size — Rule from memory (asked 10+ times) */
  box-sizing: border-box;
}
.form-control:focus {
  outline: none;
  border-color: var(--brand-orange);
}
.form-control.invalid, .form-control:invalid.modified { border-color: var(--danger); }
.form-control[disabled], .form-control:disabled { opacity: .55; cursor: not-allowed; }
select.form-control { cursor: pointer; }
textarea.form-control { resize: vertical; min-height: 72px; }

/* ── KPI tile card (dashboard / pay-run summary rows) ── */
.kpi-card {
  background: var(--paper);
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-sharp);
  padding: 14px 16px;
}
.kpi-label {
  font-size: 11px;
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-500);
  margin-bottom: 4px;
}
.kpi-value {
  font-size: 22px;
  font-weight: var(--fw-bold);
  color: var(--ink-900);
  line-height: 1.2;
}
.kpi-sub {
  font-size: 12px;
  color: var(--ink-400);
  margin-top: 2px;
}

/* ── status-chip (semantic inline badge — shared across HR + sub-asm tables) ── */
.status-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-sharp);
  font-size: 10px;
  font-weight: var(--fw-semibold);
  font-family: var(--font-mono);
  letter-spacing: .05em;
  text-transform: uppercase;
  background: var(--ink-150);
  color: var(--ink-700);
  line-height: 1.5;
  white-space: nowrap;
}
.status-chip.success { background: var(--success-soft); color: var(--success); }
.status-chip.warning { background: var(--warning-soft); color: var(--warning); }
.status-chip.danger  { background: var(--danger-soft);  color: var(--danger);  }
.status-chip.info    { background: var(--info-soft);    color: var(--info);    }

/* ── dp-header / dp-body (detail-panel chrome used by HR pages) ── */
.dp-header {
  flex-shrink: 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--ink-200);
  background: var(--paper);
}
.dp-header h2, .dp-header h3 {
  margin: 0;
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  color: var(--ink-900);
}
.dp-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overflow-x: hidden;
}

/* ── list-detail-layout generic (HR list+panel pattern) ── */
.list-detail-layout {
  display: flex;
  gap: 0;
  height: calc(100vh - var(--topbar-h, 56px));
  overflow: hidden;
}
.list-detail-layout .list-pane {
  flex-shrink: 0;
  overflow-y: auto;
  border-right: 1px solid var(--ink-200);
}
.list-detail-layout .detail-pane {
  flex: 1 1 auto;
  overflow-y: auto;
  display: none;
}
.list-detail-layout .detail-pane.open {
  display: flex;
  flex-direction: column;
}

/* ── info-banner (payroll / leave informational notice) ── */
.info-banner {
  background: var(--info-soft);
  border: 1px solid var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sharp);
  padding: 10px 14px;
  font-size: 13px;
  color: var(--ink-700);
}

/* ── empty-cell (zero-state table cell) ── */
td.empty-cell {
  text-align: center;
  color: var(--ink-400);
  padding: 20px;
  font-size: 13px;
}
