/* src/styles/redesign.css
 *
 * Full visual design system — sole source of visual truth.
 *
 * The <style> block in index.html is intentionally structure-only
 * (positioning, sizing, animations, scroll behavior, iOS quirks,
 * print-friendly receipt/invoice styling). EVERY visual choice —
 * colors, surfaces, borders, radii, shadows, typography, button
 * looks, card chrome, modal polish, table chrome, KPI strip,
 * bottom nav, drawer — lives here.
 *
 * 2026-05-22 (v=d) — pushed harder per operator feedback. No more
 * cosmetic refinement of legacy tokens. This is the look:
 *   - Inter typeface (Linear/Stripe-class), JetBrains Mono for code
 *   - Deep ink palette with intentional warmth/coolness shifts
 *     between surfaces — cards feel raised rather than just "less dark"
 *   - Brand mark in topbar (colored square + initial)
 *   - Signature accent gradient line under header (2px, visible)
 *   - Cards with subtle top-to-bottom gradient for tactile depth
 *   - KPI tiles get a colored top accent strip per metric type +
 *     32px tabular-figure values
 *   - Status indicators on table row first cell (colored dot)
 *   - Solid filled primary CTA in confident indigo, sharper corners
 *   - Inputs in a flat well with accent border + glow on focus
 *   - Sub-tabs become a true Linear/Stripe tab strip
 *   - Bottom nav: pure iOS — no boxed buttons, accent text active
 *   - Modal becomes bottom sheet on mobile
 *   - Distinctive empty / loading state treatment
 */

/* ═════════════════════════════════════════════════════════════════
 * TOKENS
 * ═════════════════════════════════════════════════════════════════ */
:root {
  /* Type stack — Inter primary, JetBrains Mono for code/IMEI/timestamps.
     Falls back to system fonts if the network blocks Google Fonts. */
  --font-sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;

  /* INK palette — deep, with intentional warmth/coolness between
     surfaces so panels read as actual depth. The page is the coldest
     surface; cards warm slightly toward indigo; modals warmest. */
  --ink-0:  #05070d;   /* page background — deep cold ink */
  --ink-1:  #0b1020;   /* card surface */
  --ink-2:  #131830;   /* nested surfaces / hover / sub-cards */
  --ink-3:  #1d2444;   /* modals, drawer, elevated panels */
  --ink-4:  #2d365c;   /* divider on elevated surfaces */
  --ink-warm:  #0e1126;  /* card top — feels slightly raised */
  --ink-cool:  #090c1c;  /* card bottom — settles down into page */

  /* Hairlines */
  --line-0: rgba(255,255,255,0.05);
  --line-1: rgba(255,255,255,0.10);
  --line-2: rgba(255,255,255,0.16);
  --line-3: rgba(255,255,255,0.26);

  /* Text — Inter renders darker than system fonts, so push contrast */
  --tx-1: #f6f7fc;
  --tx-2: #aab2c8;
  --tx-3: #687087;

  /* Accent — confident indigo. Solid for CTAs. */
  --ac:        #818cf8;
  --ac-solid:  #6366f1;
  --ac-hover:  #818cf8;
  --ac-active: #4f56e8;
  --ac-bg:     rgba(129, 140, 248, 0.16);
  --ac-bg-2:   rgba(129, 140, 248, 0.08);
  --ac-border: rgba(129, 140, 248, 0.60);
  --ac-glow:   0 0 0 3px rgba(129, 140, 248, 0.26);
  /* Legacy alias — a few inline `style='background:var(--accent)'`
   * sites in accounting / pricing-agent emitted before the rename
   * still reference --accent. Map it to our canonical --ac-solid so
   * those progress bars / brand accents pick up the indigo instead
   * of falling back to invisible (var() with no fallback = empty). */
  --accent:    #6366f1;

  /* Secondary accent — used for money, growth, positive trends */
  --pos:        #34d399;
  --pos-solid:  #10b981;
  --pos-bg:     rgba(52, 211, 153, 0.13);
  --pos-border: rgba(52, 211, 153, 0.45);

  /* Status */
  --good:        #4ade80;
  --good-solid:  #22c55e;
  --good-bg:     rgba(74, 222, 128, 0.13);
  --good-border: rgba(74, 222, 128, 0.45);
  --warn:        #fbbf24;
  --warn-solid:  #f59e0b;
  --warn-bg:     rgba(251, 191, 36, 0.13);
  --warn-border: rgba(251, 191, 36, 0.46);
  --bad:         #f87171;
  --bad-solid:   #ef4444;
  --bad-bg:      rgba(248, 113, 113, 0.13);
  --bad-border:  rgba(248, 113, 113, 0.46);

  /* 4pt spacing rhythm */
  --sp-1: 4px;  --sp-2: 8px;   --sp-3: 12px;
  --sp-4: 16px; --sp-5: 20px;  --sp-6: 24px;
  --sp-7: 32px; --sp-8: 40px;  --sp-9: 56px;

  /* Radii — sharper than legacy */
  --r-xs:   4px;
  --r-sm:   6px;
  --r-md:   8px;
  --r-lg:  12px;
  --r-xl:  16px;
  --r-pill: 999px;

  --shadow-1: 0 1px 2px rgba(0,0,0,0.40), 0 6px 16px rgba(0,0,0,0.22);
  --shadow-2: 0 24px 60px rgba(0,0,0,0.60), 0 4px 8px rgba(0,0,0,0.40);
  --shadow-key: 0 0 0 1px rgba(255,255,255,0.04) inset;

  /* Type ramp — pushed up so headings have real presence */
  --fs-2xs: 10px;
  --fs-xs:  11px;
  --fs-sm:  12px;
  --fs-md:  13px;
  --fs-lg:  14px;
  --fs-xl:  16px;
  --fs-2xl: 18px;
  --fs-3xl: 22px;
  --fs-4xl: 28px;
  --fs-5xl: 36px;

  --tx-fast: 100ms cubic-bezier(0.4, 0, 0.2, 1);
  --tx-med:  160ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* ═════════════════════════════════════════════════════════════════
 * GLOBAL CANVAS
 * ═════════════════════════════════════════════════════════════════ */
html, body {
  background: var(--ink-0);
  /* Tell browsers to use dark-mode rendering for native controls
   * (scrollbars, date/time pickers, autofill, number spin buttons,
   * select dropdown menus). One declaration covers them all. */
  color-scheme: dark;
}
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
body {
  color: var(--tx-1);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-feature-settings: "cv11", "ss01", "ss03";
  letter-spacing: -0.005em;
  background:
    radial-gradient(1100px 750px at 6% -12%, rgba(99, 102, 241, 0.10), transparent 55%),
    radial-gradient(800px 600px at 108% 110%, rgba(129, 140, 248, 0.05), transparent 55%),
    var(--ink-0);
}

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

/* Lists inside modal/card bodies need readable color + spacing.
 * Loan-how-it-works modal uses <ul> + <ol> with inline padding/line-
 * height; this just ensures the bullets/numbers and text inherit our
 * design palette instead of browser defaults. */
ul, ol { color: var(--tx-2); }
ul li, ol li { margin-bottom: 4px; }
ul li::marker, ol li::marker { color: var(--tx-3); }
ul li:last-child, ol li:last-child { margin-bottom: 0; }

/* Inline <code> tag — JetBrains Mono + faint surface. Used in
 * settings (e.g. <code>chrome://extensions</code>) + AI tool labels. */
code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  padding: 1px 5px;
  border-radius: var(--r-xs);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--line-1);
  color: var(--tx-1);
}

/* <kbd> already styled above; <samp> + <var> follow the mono pattern */
samp, var {
  font-family: var(--font-mono);
  font-style: normal;
  color: var(--tx-2);
}

/* <pre> blocks (used in #fatal error overlay + audit detail) — block-
 * level mono surface, readable on dark. */
pre {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  background: var(--ink-1);
  border: 1px solid var(--line-1);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  overflow: auto;
  color: var(--tx-2);
  line-height: 1.45;
}

/* Bare <hr> element (different from our `.hr` div divider). Picks up
 * the same hairline tone so it doesn't look like a bright default. */
hr {
  border: 0;
  border-top: 1px solid var(--line-1);
  margin: var(--sp-3) 0;
  height: 0;
}

/* Tabular numerals on data surfaces */
.kpi, .kpi .box, .kpi .v, .mono,
table, th, td,
.docTable, .docTable th, .docTable td,
.docMono, .tag, .badge, .pill,
input[inputmode="decimal"], input[inputmode="numeric"] {
  font-variant-numeric: tabular-nums;
}

::selection { background: var(--ac-bg); color: var(--tx-1); }

.muted { color: var(--tx-3); }
.small { font-size: var(--fs-sm); }
.mono  {
  font-family: var(--font-mono);
  color: var(--tx-2);
  font-size: 0.92em;
  font-weight: 500;
}
.hr {
  height: 1px;
  background: var(--line-1);
  margin: var(--sp-4) 0;
  border: 0;
}

/* ═════════════════════════════════════════════════════════════════
 * SHELL — header (topbar with brand mark + accent line), drawer,
 * bottom nav.
 * ═════════════════════════════════════════════════════════════════ */
header {
  background: var(--ink-0);
  border-bottom: 1px solid var(--line-1);
}
/* Signature element — 2px accent gradient under header, visible
   on every screen. Stronger / more saturated than v-c. */
header::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(99, 102, 241, 0.75) 22%,
    rgba(129, 140, 248, 0.95) 50%,
    rgba(167, 139, 250, 0.75) 78%,
    transparent 100%);
  pointer-events: none;
}

/* Brand mark — colored square with "IE" inside, sits inside .brand.
   CSS only via ::before — no markup change. Visible identity element.
   Uses grid so h1 stacks above .sub while the ::before sits to the
   left spanning both rows. */
.brand {
  display: grid !important;
  grid-template-columns: 32px 1fr;
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: var(--sp-3);
  row-gap: 1px;
}
.brand::before {
  content: "IE";
  grid-column: 1;
  grid-row: 1 / span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px; height: 32px;
  background: linear-gradient(135deg, var(--ac-solid) 0%, #8b5cf6 100%);
  border-radius: var(--r-md);
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: var(--fs-sm);
  color: #fff;
  letter-spacing: -0.02em;
  box-shadow: 0 4px 12px rgba(99, 102, 241, 0.35), var(--shadow-key);
}
.brand h1 {
  grid-column: 2;
  grid-row: 1;
  font-family: var(--font-sans);
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.018em;
  color: var(--tx-1);
  line-height: 1.15;
  margin: 0;
}
.brand .sub {
  grid-column: 2;
  grid-row: 2;
  font-family: var(--font-sans);
  font-size: 10px;
  color: var(--tx-3);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  font-weight: 600;
  line-height: 1.2;
}

/* Hamburger */
.hamburger {
  width: 38px; height: 38px;
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.03);
  border-radius: var(--r-md);
  transition: background var(--tx-fast), border-color var(--tx-fast), transform var(--tx-fast);
}
.hamburger:hover {
  background: rgba(255,255,255,0.06);
  border-color: var(--line-3);
}
.hamburger:focus-visible {
  outline: none;
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
}
.hamburger:active { transform: scale(0.96); }
.drawerClose:focus-visible {
  outline: none;
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
}
.hamburger span {
  background: var(--tx-1);
  border-radius: 2px;
}

/* Drawer */
.drawer {
  background: var(--ink-3);
  border-left: 1px solid var(--line-2);
  box-shadow: var(--shadow-2);
}
.drawerOverlay { background: rgba(5, 7, 13, 0.70); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.drawerTitle {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--tx-1);
}
.drawerClose {
  width: 36px; height: 36px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.04);
  color: var(--tx-2);
}
.drawerClose:hover { background: rgba(255,255,255,0.08); color: var(--tx-1); }

.drawerNav a {
  padding: 10px 12px;
  border-radius: var(--r-md);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--tx-2);
  transition: background var(--tx-fast), color var(--tx-fast);
}
.drawerNav a:hover {
  background: rgba(255,255,255,0.05);
  color: var(--tx-1);
}

.navGroupBtn {
  padding: 10px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.03);
  color: var(--tx-1);
  font-weight: 600;
  font-size: var(--fs-md);
}
.navGroupBtn:hover { background: rgba(255,255,255,0.07); }
.navGroupBtn .chev { opacity: 0.6; }
.navSub a {
  padding: 8px 12px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--tx-3);
}
.navSub a:hover { color: var(--tx-1); background: rgba(255,255,255,0.04); }
.drawerFoot { border-top: 1px solid var(--line-1); }

/* Mobile bottom nav — iOS-style pure tab bar */
.bottomNav {
  background: rgba(5, 7, 13, 0.94);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--line-1);
  box-shadow: none;
}
.bottomNav .navBtn {
  border: 0;
  background: transparent;
  border-radius: var(--r-md);
  color: var(--tx-3);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.02em;
  transition: color var(--tx-fast);
}
.bottomNav .navBtn .ic {
  font-size: 22px;
  filter: grayscale(0.55) opacity(0.65);
  transition: filter var(--tx-fast), transform var(--tx-fast);
}
.bottomNav .navBtn.active {
  background: transparent;
  color: var(--ac);
  border: 0;
  box-shadow: none;
  font-weight: 600;
}
.bottomNav .navBtn.active .ic {
  filter: none;
  transform: translateY(-1px);
}
.bottomNav .navBtn:hover { color: var(--tx-2); }
.bottomNav .navBtn:focus-visible {
  outline: none;
  color: var(--ac);
  background: rgba(99, 102, 241, 0.06);
  border-radius: var(--r-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * CARDS — subtle vertical gradient + hairline. Real depth.
 * ═════════════════════════════════════════════════════════════════ */
.card {
  background: linear-gradient(180deg, var(--ink-warm) 0%, var(--ink-cool) 100%);
  border: 1px solid var(--line-1);
  border-radius: var(--r-lg);
  overflow: clip;
  box-shadow: var(--shadow-key);
}
.card .hd {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line-1);
  background: linear-gradient(180deg, rgba(255,255,255,0.02), transparent);
}
.card .hd h2 {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--tx-1);
}
.card .hd h3 {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.005em;
  margin: 0;
  color: var(--tx-1);
}
.card .bd { padding: var(--sp-4); }

/* ═════════════════════════════════════════════════════════════════
 * KPI STRIP — taller tiles, BIG values (36px), uppercase labels,
 * optional accent strip on top. Most visible Home change.
 * ═════════════════════════════════════════════════════════════════ */
.kpi .box {
  position: relative;
  padding: var(--sp-4) var(--sp-4) var(--sp-3);
  border: 1px solid var(--line-1);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--ink-warm), var(--ink-cool));
  display: flex;
  flex-direction: column-reverse;
  gap: var(--sp-2);
  min-height: 102px;
  transition: border-color var(--tx-fast), transform var(--tx-fast);
  box-shadow: var(--shadow-key);
  overflow: clip;
}
.kpi .box::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--ac-solid), var(--ac));
  opacity: 0.85;
}
/* Cycle through 4 accent colors so any KPI strip length looks intentional */
.kpi .box:nth-child(4n+2)::before { background: linear-gradient(90deg, var(--pos-solid), var(--pos)); }
.kpi .box:nth-child(4n+3)::before { background: linear-gradient(90deg, #8b5cf6, #a78bfa); }
.kpi .box:nth-child(4n+4)::before { background: linear-gradient(90deg, var(--warn-solid), var(--warn)); }
.kpi .box:hover { border-color: var(--line-2); }
.kpi .box .v {
  font-family: var(--font-sans);
  font-size: var(--fs-5xl);          /* 36px */
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.0;
  color: var(--tx-1);
}
.kpi .box .t {
  font-size: var(--fs-2xs);
  color: var(--tx-3);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-weight: 700;
}

/* ═════════════════════════════════════════════════════════════════
 * BUTTONS — sharper corners, more weight, tactile press feedback
 * ═════════════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.04);
  color: var(--tx-1);
  border-radius: var(--r-sm);                  /* 6px — sharper */
  padding: 8px 14px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-md);
  letter-spacing: -0.008em;
  white-space: nowrap;
  transition:
    background var(--tx-fast),
    border-color var(--tx-fast),
    transform 60ms cubic-bezier(0.4, 0, 0.2, 1);
}
.btn:hover  { background: rgba(255,255,255,0.08); border-color: var(--line-3); }
.btn:active { transform: scale(0.97); background: rgba(255,255,255,0.12); }
.btn:focus-visible {
  outline: none;
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
}
.btn:disabled, .btn[disabled] {
  opacity: 0.40;
  cursor: not-allowed;
}

.btn.primary {
  background: linear-gradient(180deg, var(--ac-hover) 0%, var(--ac-solid) 100%);
  border-color: var(--ac-solid);
  color: #ffffff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset, 0 2px 8px rgba(99, 102, 241, 0.30);
}
.btn.primary:hover  {
  background: linear-gradient(180deg, var(--ac), var(--ac-hover));
  border-color: var(--ac-hover);
}
.btn.primary:active {
  background: var(--ac-active);
  border-color: var(--ac-active);
  box-shadow: none;
}

.btn.good {
  background: linear-gradient(180deg, var(--good) 0%, var(--good-solid) 100%);
  border-color: var(--good-solid);
  color: #07140b;
  box-shadow: 0 1px 0 rgba(255,255,255,0.18) inset, 0 2px 8px rgba(34, 197, 94, 0.28);
}
.btn.good:hover  { background: linear-gradient(180deg, #6ee7a0, var(--good)); }

.btn.bad {
  background: linear-gradient(180deg, var(--bad) 0%, var(--bad-solid) 100%);
  border-color: var(--bad-solid);
  color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset, 0 2px 8px rgba(239, 68, 68, 0.30);
}
.btn.bad:hover { background: linear-gradient(180deg, #fb8585, var(--bad)); }

.btn.ghost {
  background: transparent;
  border-color: var(--line-2);
  color: var(--tx-2);
}
.btn.ghost:hover {
  background: rgba(255,255,255,0.03);
  color: var(--tx-1);
}

.btn.tiny {
  padding: 5px 10px;
  font-size: var(--fs-sm);
  border-radius: var(--r-xs);
}

.btn.block { width: 100%; }

/* "Add to Inventory" CTA: confident primary even without .primary class */
#addBtn:not(.primary):not(.good):not(.bad) {
  background: linear-gradient(180deg, var(--ac-hover), var(--ac-solid));
  border-color: var(--ac-solid);
  color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset, 0 2px 8px rgba(99, 102, 241, 0.30);
}
#addBtn:not(.primary):not(.good):not(.bad):hover {
  background: linear-gradient(180deg, var(--ac), var(--ac-hover));
}

/* ═════════════════════════════════════════════════════════════════
 * FORM CONTROLS
 * ═════════════════════════════════════════════════════════════════ */
input, select, textarea,
.field input, .field select, .field textarea {
  background: rgba(0,0,0,0.40);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  padding: 9px 12px;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--tx-1);
  transition: border-color var(--tx-fast), box-shadow var(--tx-fast), background var(--tx-fast);
}
input::placeholder, textarea::placeholder { color: var(--tx-3); }

/* Chrome / Safari autofill — kill the bright yellow background that
 * appears when the browser fills a saved login. With color-scheme:dark
 * on <html> Chrome already adapts on most platforms, but Safari and
 * some Chromium versions still flash yellow on iOS. The accepted
 * cross-browser fix is a heavy inset box-shadow that paints over the
 * background. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
  -webkit-box-shadow: 0 0 0 1000px var(--ink-1) inset !important;
  -webkit-text-fill-color: var(--tx-1) !important;
  caret-color: var(--tx-1);
  transition: background-color 9999s ease-out;
}
input:hover, select:hover, textarea:hover { border-color: var(--line-3); }
input:focus, select:focus, textarea:focus,
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
  background: rgba(0,0,0,0.50);
}
input:disabled, select:disabled, textarea:disabled {
  opacity: 0.50;
  cursor: not-allowed;
}

.field label {
  font-family: var(--font-sans);
  font-size: var(--fs-2xs);
  color: var(--tx-3);
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

/* IMEI/mono inputs */
.mono, input.mono { font-family: var(--font-mono); }

/* Search inputs — pill */
input[type="search"],
#main input[placeholder*="earch" i] {
  border-radius: var(--r-pill);
  padding-left: var(--sp-4);
}

/* ═════════════════════════════════════════════════════════════════
 * TABLES — dense, uppercase headers, alternating row tones,
 * status indicators on first column, monospace IMEI
 * ═════════════════════════════════════════════════════════════════ */
table {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
}
th, td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line-0);
  font-weight: 500;
}
th {
  position: sticky; top: 0; z-index: 1;
  background: var(--ink-2);
  color: var(--tx-3);
  font-weight: 700;
  font-size: var(--fs-2xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--line-2);
}
tbody tr { transition: background var(--tx-fast); }
tbody tr:nth-child(odd) td { background: rgba(255,255,255,0.012); }
tbody tr:hover td { background: rgba(129, 140, 248, 0.045); }

/* Table footer — used for totals row in invoice builder etc. Get a
 * stronger top border + slightly darker surface so totals row reads
 * as a "summary" anchor at the bottom. */
tfoot td {
  background: var(--ink-1);
  border-top: 1px solid var(--line-2);
  border-bottom: 0;
  padding: var(--sp-3) var(--sp-3);
}
tfoot tr:hover td { background: var(--ink-1); }
tbody td.muted[colspan] {
  text-align: center;
  padding: var(--sp-8) var(--sp-4);
  color: var(--tx-3);
  font-size: var(--fs-sm);
}

/* IMEI / mono cells in tables */
tbody td .mono, td.mono, .mono {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.92em;
  color: var(--tx-2);
  letter-spacing: -0.005em;
}

/* Tables keep nowrap (set in index.html on .tableWrap th/td) so the
 * old, dense, at-a-glance look the operator wanted is preserved.
 * .tableWrap has overflow-x:auto so a wide table scrolls INSIDE
 * the card instead of pushing the page horizontally. Previously
 * tried `white-space: normal` on desktop td — that broke
 * "23 - US AT&T Activation Policy" into a 4-line vertical stack
 * and an IMEI into one digit-cluster per line in the Invoice
 * Builder split view. Operator pushed back; reverted. */

/* Inline row-action buttons — tighter */
tbody .btn,
tbody .btn.tiny {
  padding: 4px 8px;
  font-size: var(--fs-xs);
  font-weight: 600;
  border-radius: var(--r-xs);
}
tbody .btn + .btn { margin-left: 2px; }

tbody td .tag,
tbody td .badge {
  font-size: 10px;
  padding: 2px 7px;
}

.tableWrap {
  border: 1px solid var(--line-1);
  border-radius: var(--r-md);
  background: var(--ink-1);
}

@media (max-width: 720px) {
  th, td { padding: 7px 9px; }
  /* Keep row buttons compact on mobile too — operator wants at-a-glance
   * density across many rows. The ⋯ kebab is 32×32 already, which
   * gives the comfortable touch target without bloating every row. */
  tbody .btn,
  tbody .btn.tiny {
    padding: 4px 8px;
    font-size: var(--fs-xs);
  }
}

/* ═════════════════════════════════════════════════════════════════
 * PILLS · TAGS · BADGES · DOT · NOTICE
 * ═════════════════════════════════════════════════════════════════ */
.pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 12px;
  font-size: var(--fs-sm);
  font-weight: 600;
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.04);
  border-radius: var(--r-pill);
  color: var(--tx-1);
}
.dot {
  width: 8px; height: 8px;
  border-radius: var(--r-pill);
  background: var(--good);
  box-shadow: 0 0 0 3px rgba(74, 222, 128, 0.22);
}

.tag, .badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px;
  font-size: var(--fs-xs);
  font-weight: 700;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.04);
  white-space: nowrap;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tx-2);
  line-height: 1.2;
}
.tag.good, .badge.good {
  border-color: var(--good-border);
  background: var(--good-bg);
  color: var(--good);
}
.tag.warn, .badge.warn {
  border-color: var(--warn-border);
  background: var(--warn-bg);
  color: var(--warn);
}
.tag.bad, .badge.bad {
  border-color: var(--bad-border);
  background: var(--bad-bg);
  color: var(--bad);
}
.tag.info, .badge.info {
  border-color: rgba(56, 189, 248, 0.30);
  background: rgba(56, 189, 248, 0.10);
  color: #7dd3fc;
}

.notice {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.03);
  font-size: var(--fs-md);
  line-height: 1.55;
  border-left: 3px solid var(--ac);
}
.notice.good,
.notice.ok { border-color: var(--good-border); background: var(--good-bg); border-left-color: var(--good); }
.notice.bad  { border-color: var(--bad-border);  background: var(--bad-bg);  border-left-color: var(--bad); }
.notice.warn { border-color: var(--warn-border); background: var(--warn-bg); border-left-color: var(--warn); }

/* ═════════════════════════════════════════════════════════════════
 * TOAST
 * ═════════════════════════════════════════════════════════════════ */
.toast {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-2);
  background: var(--ink-3);
  box-shadow: var(--shadow-2);
  font-size: var(--fs-md);
}
.toast .t { font-weight: 700; color: var(--tx-1); letter-spacing: -0.005em; }
.toast .b { font-size: var(--fs-sm); color: var(--tx-3); margin-top: 2px; }

/* ═════════════════════════════════════════════════════════════════
 * MODAL — desktop card / mobile bottom sheet
 * ═════════════════════════════════════════════════════════════════ */
.modalOverlay {
  background: rgba(5, 7, 13, 0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.modal {
  background: var(--ink-3);
  border: 1px solid var(--line-2);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-2);
  padding: var(--sp-4) var(--sp-4) var(--sp-5);
}
.modalHead {
  padding-bottom: var(--sp-3);
  margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line-1);
  gap: var(--sp-3);
}
.modalTitle {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--tx-1);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 480px) {
  .modalTitle { font-size: var(--fs-lg); }
}
.iconBtn {
  width: 32px; height: 32px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.03);
  color: var(--tx-2);
  transition: background var(--tx-fast), color var(--tx-fast);
}
.iconBtn:hover { background: rgba(255,255,255,0.08); color: var(--tx-1); }
.iconBtn:focus-visible {
  outline: none;
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
}

/* Mobile: centered modal (was: bottom sheet). Operator reported the
 * bottom-sheet style hid content under the bottom-nav and made short
 * modals like 'Bulk Purchase Complete' look like a thin strip at the
 * bottom edge. Centering on the viewport with side padding makes the
 * full modal visible regardless of content length. */
@media (max-width: 720px) {
  .modalOverlay {
    align-items: center;
    padding: 16px 12px;
  }
  .modal {
    width: 100%;
    max-width: 100%;
    max-height: calc(100dvh - 32px);
    border-radius: var(--r-xl);
    border: 1px solid var(--line-2);
    padding: var(--sp-4);
  }
  /* No bottom-sheet handle bar in the centered layout. */
  .modal::before { display: none; }
}

/* Scanner */
.scanFrame {
  border-radius: var(--r-lg);
  border: 1px solid var(--line-1);
  background: rgba(0,0,0,0.40);
}
.scanBox {
  border-radius: var(--r-md);
  border: 2px solid rgba(255,255,255,0.85);
  box-shadow: 0 0 0 6px rgba(0,0,0,0.30);
}
.scanLine { background: var(--good); }

.imgPrev {
  border-radius: var(--r-md);
  border: 1px solid var(--line-1);
  background: rgba(0,0,0,0.30);
}
.choiceList .btn {
  padding: 7px 12px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * SUB-TABS — Linear/Stripe-style tab strip with accent underline
 * ═════════════════════════════════════════════════════════════════ */
.segTabs {
  padding: 0;
  margin: 0 0 var(--sp-3) 0;
  gap: 0;
  border-bottom: 1px solid var(--line-1);
}
.segBtn {
  flex: 0 0 auto;
  padding: var(--sp-3) var(--sp-4);
  border-radius: 0;
  border: 0;
  background: transparent;
  color: var(--tx-3);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-md);
  letter-spacing: -0.005em;
  position: relative;
  transition: color var(--tx-fast);
  cursor: pointer;
}
.segBtn:hover { color: var(--tx-2); }
.segBtn.active {
  color: var(--tx-1);
  background: transparent;
  box-shadow: none;
}
.segBtn.active::after {
  content: "";
  position: absolute;
  left: var(--sp-4); right: var(--sp-4);
  bottom: -1px;
  height: 2px;
  background: var(--ac);
  border-radius: 2px 2px 0 0;
}

/* ═════════════════════════════════════════════════════════════════
 * SETTINGS — section cards + collapsible chevron + sticky chip nav
 * ═════════════════════════════════════════════════════════════════ */
.secCard {
  background: linear-gradient(180deg, var(--ink-warm), var(--ink-cool));
  border: 1px solid var(--line-1);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-key);
}
.secHead {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line-1);
  align-items: flex-start;
}
.secHead h3 {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--tx-1);
}
.secSub {
  font-size: var(--fs-sm);
  color: var(--tx-3);
  margin-top: var(--sp-1);
  line-height: 1.45;
}
.secBody { padding: var(--sp-4); }
.secBody .hr { margin: var(--sp-3) 0; background: var(--line-1); }

.secCard.collapsible.collapsed .secHead { border-bottom: 0; }
.secCard.collapsible .secHead::after {
  border-right-color: var(--tx-3);
  border-bottom-color: var(--tx-3);
}

/* Sticky in-page chip nav — settings sections shortcut row.
 * top: 64px so it sits BELOW the .pageHd header (which is sticky
 * at top: 0 with its own ~60px height). */
.settingsNav {
  position: sticky;
  top: 64px;
  z-index: 26;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: var(--sp-2) 0;
  margin: 0 0 var(--sp-3) 0;
  background: linear-gradient(180deg, rgba(11, 16, 32, 0.94), rgba(11, 16, 32, 0.78));
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line-1);
}
.settingsNav .chip {
  padding: 6px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.03);
  color: var(--tx-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--tx-fast), color var(--tx-fast), border-color var(--tx-fast);
}
.settingsNav .chip:hover {
  background: rgba(255,255,255,0.06);
  color: var(--tx-1);
}
.settingsNav .chip.active {
  background: var(--ac-bg);
  border-color: var(--ac-border);
  color: var(--ac);
}
/* Section cards in settings get clear top spacing + an anchor-target
 * offset so the sticky nav doesn't cover the heading on jump. */
.secCard { scroll-margin-top: 80px; }

/* ═════════════════════════════════════════════════════════════════
 * KV LIST
 * ═════════════════════════════════════════════════════════════════ */
.kvItem {
  border: 1px solid var(--line-1);
  background: linear-gradient(180deg, var(--ink-warm), var(--ink-cool));
  border-radius: var(--r-md);
  padding: var(--sp-3);
}
.kvItem .k {
  font-size: var(--fs-2xs);
  color: var(--tx-3);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  margin-bottom: 6px;
}
.kvItem .v {
  font-size: var(--fs-sm);
  white-space: normal;
  word-break: break-word;
  color: var(--tx-1);
}

.statusPanel {
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.03);
  border-radius: var(--r-md);
}
.bulkDetailGrid > div {
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.03);
  border-radius: var(--r-md);
  color: var(--tx-2);    /* lift value text out of the muted tx-3 */
}
.bulkDetailGrid b {
  display: block;
  margin-bottom: 4px;
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--tx-3);    /* label stays in tx-3 — value pops in tx-2 */
}

/* ═════════════════════════════════════════════════════════════════
 * FATAL OVERLAY
 * ═════════════════════════════════════════════════════════════════ */
#fatal {
  background: rgba(5, 7, 13, 0.94);
  backdrop-filter: blur(8px);
}
#fatal .box {
  border: 1px solid var(--line-2);
  background: var(--ink-3);
  border-radius: var(--r-xl);
}
#fatal pre { color: var(--tx-1); }

/* ═════════════════════════════════════════════════════════════════
 * AUTH OVERLAY
 * ═════════════════════════════════════════════════════════════════ */
#authOverlay { background: rgba(5, 7, 13, 0.78); }
#authOverlay .panel {
  background: linear-gradient(180deg, var(--ink-warm), var(--ink-cool));
  border: 1px solid var(--line-2);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-2);
}

/* ═════════════════════════════════════════════════════════════════
 * SCROLLBARS — desktop only
 * ═════════════════════════════════════════════════════════════════ */
@media (pointer: fine) {
  ::-webkit-scrollbar { width: 10px; height: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb {
    background: var(--line-2);
    border-radius: var(--r-pill);
    border: 2px solid transparent;
    background-clip: padding-box;
  }
  ::-webkit-scrollbar-thumb:hover {
    background: var(--line-3);
    background-clip: padding-box;
  }
}

/* ═════════════════════════════════════════════════════════════════
 * FOCUS RINGS
 * ═════════════════════════════════════════════════════════════════ */
button:not(.btn):focus-visible,
[role="button"]:focus-visible,
a:focus-visible {
  outline: none;
  box-shadow: var(--ac-glow);
  border-radius: var(--r-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * MOBILE VISUAL ADJUSTMENTS
 * ═════════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
  .card { border-radius: var(--r-md); }
  .card .hd { padding: var(--sp-3); }
  .card .bd { padding: var(--sp-3); }
  .card .hd h2 { font-size: var(--fs-lg); }

  .kpi .box { padding: var(--sp-3); min-height: 84px; }
  .kpi .box .v { font-size: var(--fs-3xl); }
  .kpi .box .t { font-size: 9px; letter-spacing: 0.10em; }

  .btn { padding: 8px 12px; font-size: var(--fs-sm); }
  .btn.tiny { padding: 4px 8px; font-size: var(--fs-xs); }

  .brand::before { width: 30px; height: 30px; font-size: var(--fs-xs); }
  .brand h1 { font-size: var(--fs-md); }

  .secHead { padding: var(--sp-3); }
  .secHead h3 { font-size: var(--fs-lg); }
  .secBody { padding: var(--sp-3); }

  .segTabs { padding: 0; }
  .segBtn { padding: var(--sp-2) var(--sp-3); font-size: var(--fs-sm); }

  .modal { border-radius: var(--r-lg); }
}
@media (max-width: 480px) {
  .card .hd { padding: var(--sp-2) var(--sp-3); }
  .card .bd { padding: var(--sp-3); }
  .kpi .box { padding: var(--sp-3); min-height: 72px; }
  .kpi .box .v { font-size: var(--fs-2xl); }
  .btn { padding: 7px 10px; }
  .btn.tiny { padding: 4px 7px; font-size: 10px; }
}

/* ═════════════════════════════════════════════════════════════════
 * NATIVE FORM CONTROLS — checkboxes, radios, select dropdown arrow,
 * file inputs. The browser defaults are gray + chunky; replace with
 * confident dark-themed versions. CSS-only.
 * ═════════════════════════════════════════════════════════════════ */

/* Checkbox + radio — fully restyled */
input[type="checkbox"],
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 16px; height: 16px;
  border: 1px solid var(--line-2);
  background: rgba(0,0,0,0.40);
  cursor: pointer;
  margin: 0 6px 0 0;
  position: relative;
  vertical-align: -3px;
  transition: background var(--tx-fast), border-color var(--tx-fast), box-shadow var(--tx-fast);
  flex-shrink: 0;
}
input[type="checkbox"] { border-radius: var(--r-xs); }
input[type="radio"]    { border-radius: var(--r-pill); }

input[type="checkbox"]:hover,
input[type="radio"]:hover {
  border-color: var(--line-3);
  background: rgba(0,0,0,0.30);
}
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: none;
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
}
input[type="checkbox"]:checked,
input[type="radio"]:checked {
  background: var(--ac-solid);
  border-color: var(--ac-solid);
}
input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4px; top: 1px;
  width: 5px; height: 9px;
  border-right: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(45deg);
}
input[type="radio"]:checked::after {
  content: "";
  position: absolute;
  left: 4px; top: 4px;
  width: 6px; height: 6px;
  background: #fff;
  border-radius: var(--r-pill);
}
input[type="checkbox"]:disabled,
input[type="radio"]:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Select dropdown arrow — replace the gray native chevron */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M2 4l4 4 4-4' stroke='%23aab2c8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px;
  background-color: rgba(0,0,0,0.40);
}
select:focus {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M2 4l4 4 4-4' stroke='%23818cf8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
}
select option {
  background: var(--ink-3);
  color: var(--tx-1);
}

/* File input — make the "Choose File" button match the design */
input[type="file"] {
  padding: 6px;
  cursor: pointer;
  font-size: var(--fs-sm);
}
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button {
  margin-right: var(--sp-3);
  padding: 6px 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: rgba(255,255,255,0.05);
  color: var(--tx-1);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background var(--tx-fast);
}
input[type="file"]::file-selector-button:hover,
input[type="file"]::-webkit-file-upload-button:hover {
  background: rgba(255,255,255,0.10);
}

/* Date / datetime / time / month / week inputs — make the native
 * calendar icon visible on the dark surface. WebKit / Chromium puts
 * the icon in `::-webkit-calendar-picker-indicator`. The root-level
 * `color-scheme: dark` makes the picker pop-up dark-themed; this
 * just tweaks the trigger glyph visibility. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="week"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.7;
  filter: invert(0.9);
  transition: opacity var(--tx-fast);
}
input[type="date"]:hover::-webkit-calendar-picker-indicator,
input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator,
input[type="time"]:hover::-webkit-calendar-picker-indicator,
input[type="month"]:hover::-webkit-calendar-picker-indicator,
input[type="week"]:hover::-webkit-calendar-picker-indicator {
  opacity: 1;
}

/* Range / number arrows kept native */

/* Inline checkbox label — used everywhere across forms */
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
  display: inline-flex;
  align-items: center;
  gap: 0;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: HOME (#app)
 * Quick Intake card + Bulk Intake card pattern; KPI strip above.
 * ═════════════════════════════════════════════════════════════════ */

/* The Quick Intake "field row" pattern: tighten gaps and align
   action buttons cleanly at the footer. */
#main > .grid > .card .bd > .row {
  margin-top: var(--sp-1);
}
#main > .grid > .card .bd > .row:first-child {
  margin-top: 0;
}

/* "SickW Lookup" button sits next to Add to Inventory — keep it
   readable but secondary */
#lookupBtn {
  background: rgba(255,255,255,0.04);
  border-color: var(--line-2);
  color: var(--tx-1);
}

/* IMEI lookup output panel: see the dedicated #lookupOut rule below
 * (level coloring respected via .notice.* overrides). */

/* Bulk Intake textarea — distinctive monospace, larger */
textarea[id*="bulk" i],
textarea[id*="Bulk" i],
#bulkPasteText {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.55;
  min-height: 140px;
  letter-spacing: -0.005em;
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: INVENTORY (#inventory)
 * Dense table with status indicators. Inline row actions.
 * ═════════════════════════════════════════════════════════════════ */

/* Status indicator dot on the first cell of inventory rows when
   the row contains a .tag.good — visual cue at a glance. */
#main table tbody tr:has(.tag.good) td:first-child {
  position: relative;
  padding-left: 18px;
}
#main table tbody tr:has(.tag.good) td:first-child::before {
  content: "";
  position: absolute;
  left: 8px; top: 50%;
  transform: translateY(-50%);
  width: 6px; height: 6px;
  background: var(--good);
  border-radius: var(--r-pill);
  box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.20);
}

/* Inventory search input — pill-shaped, fully restyled. Also applies
 * to search inputs inside modals (vendor history, AI memory, etc.)
 * so the search affordance is consistent. */
#main input[placeholder*="earch" i],
.modal input[placeholder*="earch" i] {
  border-radius: var(--r-pill);
  padding-left: 36px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'><circle cx='6' cy='6' r='4.5' stroke='%23687087' stroke-width='1.5' fill='none'/><path d='M9.5 9.5l3 3' stroke='%23687087' stroke-width='1.5' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat;
  background-position: 12px center;
}

/* Edit Device modal — multi-field form grid */
.modal #edImei, .modal #edModel, .modal #edCost {
  font-weight: 500;
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: SALES (#sales)
 * Log Sale card + Invoice Builder.
 * ═════════════════════════════════════════════════════════════════ */

/* Selected device notice when sale is staged */
#main .card .bd .notice {
  border-left: 3px solid var(--ac);
  padding-left: var(--sp-3);
}
#main .card .bd .notice.good { border-left-color: var(--good); }
#main .card .bd .notice.bad  { border-left-color: var(--bad); }
#main .card .bd .notice.warn { border-left-color: var(--warn); }

/* Log Sale CTA — keep prominent green */
#logSaleBtn {
  background: linear-gradient(180deg, var(--good) 0%, var(--good-solid) 100%);
  border-color: var(--good-solid);
  color: #07140b;
  box-shadow: 0 1px 0 rgba(255,255,255,0.18) inset, 0 2px 8px rgba(34, 197, 94, 0.28);
  font-weight: 700;
}
#logSaleBtn:hover {
  background: linear-gradient(180deg, #6ee7a0, var(--good));
}

/* Invoice items table — tighten + numerics right */
#invItemsTbl input.invSalePrice {
  width: 96px;
  text-align: right;
  padding: 6px 10px;
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
}
#invItemsTbl th.num,
#invItemsTbl td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* Invoice totals strip */
#invTotals {
  padding: var(--sp-3) var(--sp-4);
  background: var(--ink-2);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  font-size: var(--fs-md);
  border: 1px solid var(--line-1);
}
#invTotals b {
  font-weight: 700;
  color: var(--tx-1);
}

/* "Fill from buyer" auto-fill row — accent treatment */
#main .row[style*="bdfb"], #main .row > [data-fill-buyer] {
  /* tiny "buyer pill" buttons */
}
.btn[data-fill-buyer] {
  font-size: 11px;
  padding: 4px 9px;
  border-radius: var(--r-xs);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: PURCHASES (#purchases)
 * Simple table view of purchase history.
 * ═════════════════════════════════════════════════════════════════ */
/* Purchases doesn't need special treatment beyond the global table styles. */

/* ═════════════════════════════════════════════════════════════════
 * VIEW: ACCOUNTING + TAX (#accounting / #tax)
 * Sub-tabs + dense data tables + acctFormGrid.
 * ═════════════════════════════════════════════════════════════════ */

.acctFormGrid {
  gap: var(--sp-2) var(--sp-3);
  align-items: end;
}

/* Tax YTD-TOTAL row */
#taxBody tr:last-child td,
#taxBody tr[style*="border-top"] td {
  font-weight: 700;
  background: var(--ink-2);
  border-top: 1px solid var(--line-2);
  color: var(--tx-1);
}

/* Tax page sub-tab content */
#taxSubTabs {
  margin-bottom: var(--sp-3);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: CASH TRACKER (#cashtracker)
 * Cash ledger form + KPI strip.
 * ═════════════════════════════════════════════════════════════════ */
#cashLedgerForm .field input,
#cashLedgerForm .field select {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: STATEMENTS (#statements) + LOAN PACKAGE (#loanpackage)
 * Financial reports with section titles.
 * ═════════════════════════════════════════════════════════════════ */

.stmtSection,
#main .card .bd > h3,
#main .card .bd > h4 {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--tx-1);
  margin: var(--sp-5) 0 var(--sp-2);
  letter-spacing: -0.005em;
}

tr.totalRow,
tr.subtotalRow {
  border-top: 1px solid var(--line-2);
}
tr.totalRow td,
tr.subtotalRow td {
  font-weight: 700;
  background: var(--ink-2);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: VENDORS (#vendors) / BUYERS
 * Lists + edit modals.
 * ═════════════════════════════════════════════════════════════════ */
#main .card .bd table[id*="vendor" i] td:first-child,
#main .card .bd table[id*="buyers" i] td:first-child {
  font-weight: 600;
  color: var(--tx-1);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: PRICING AGENT (#pricingagent)
 * Data-dense page: summary strip + tables + run-report modal.
 * ═════════════════════════════════════════════════════════════════ */

#paSummary {
  margin-bottom: var(--sp-3);
}
#paSummary > .row {
  gap: var(--sp-2);
  flex-wrap: wrap;
}
#paSummary > .row > div {
  padding: var(--sp-2) var(--sp-3) !important;
  background: var(--ink-1) !important;
  border: 1px solid var(--line-1) !important;
  border-radius: var(--r-md) !important;
  min-width: 130px;
}
#paSummary > .row > div > .small.muted {
  font-size: var(--fs-2xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--tx-3);
}
#paSummary > .row > div > div:last-child {
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  color: var(--tx-1);
  margin-top: 2px;
}

/* PA run report modal — standalone, created outside openModal */
#paRunReportModal > .card,
#paDiagModal > .card {
  background: var(--ink-3) !important;
  border: 1px solid var(--line-2) !important;
  border-radius: var(--r-xl) !important;
  box-shadow: var(--shadow-2) !important;
}
/* Pricing-agent preview modal — `#paPreviewModal` is the overlay
 * (dark backdrop). Its FIRST child is the inner card (no `.card`
 * class; built with inline `background:#0b1220` and own border).
 * Restyle the overlay backdrop + the inner card surface. */
#paPreviewModal {
  background: rgba(5, 7, 13, 0.72) !important;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
#paPreviewModal > div {
  background: var(--ink-3) !important;
  border-color: var(--line-2) !important;
  border-radius: var(--r-xl) !important;
  box-shadow: var(--shadow-2) !important;
}
/* paPreview table inside the modal — view-builder hardcodes #0b1220 on
 * sticky `<th>` headers. Override to use design-system surface. */
#paPrevBody table th[style*="background:#0b1220"] {
  background: var(--ink-2) !important;
  color: var(--tx-3) !important;
  border-bottom-color: var(--line-2) !important;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 10px !important;
  font-weight: 700;
}
#paPrevBody table td {
  color: var(--tx-2);
  border-color: var(--line-1) !important;
}
#paPrevBody table tbody tr:hover td {
  background: rgba(99, 102, 241, 0.04);
}
@media (max-width: 720px) {
  #paPreviewModal { align-items: flex-end !important; padding: 0 !important; }
  #paPreviewModal > div {
    width: 100% !important;
    max-width: 100% !important;
    border-radius: var(--r-xl) var(--r-xl) 0 0 !important;
    max-height: 92dvh;
  }
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: BULK INTAKE (#bulkintake)
 * Big textarea + table + warnings strip + action row.
 * ═════════════════════════════════════════════════════════════════ */

.bulkWarnStrip {
  font-size: var(--fs-sm);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-md);
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  border-left: 3px solid var(--warn);
  color: var(--warn);
  margin-bottom: var(--sp-3);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: AUDIT LOG (#audit)
 * Mostly inherits global table styles. Filter inputs at top.
 * ═════════════════════════════════════════════════════════════════ */
#audBody td {
  font-size: var(--fs-sm);
}
#audBody td:nth-child(1) {
  font-family: var(--font-mono);
  color: var(--tx-3);
  white-space: nowrap;
  font-size: var(--fs-xs);
}
/* Audit Detail column (5th col) can be long — let it wrap so users
 * can read full context without scrolling sideways. */
#audBody td:nth-child(5) {
  white-space: normal;
  max-width: 480px;
  color: var(--tx-2);
  line-height: 1.4;
}
/* Type column gets a faint pill-like tone so event types are
 * scannable at a glance. */
#audBody td:nth-child(4) {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--tx-2);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: NOTIFICATIONS (#notifications)
 * Items list with type badges.
 * ═════════════════════════════════════════════════════════════════ */
/* Each notification renders as `.notice` which already supplies its
 * own padding + radius + left-accent border. Don't add a flat
 * border-bottom or override the padding here — let .notice own it. */

/* ═════════════════════════════════════════════════════════════════
 * VIEW: AI ASSISTANT (#aiassistant)
 * Chat-style: messages list + pending panel + suggested prompts.
 * ═════════════════════════════════════════════════════════════════ */

/* Suggested prompts strip — small accent pills */
#aiPrompts .btn,
button[data-ai-prompt] {
  border-radius: var(--r-pill);
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.03);
  color: var(--tx-2);
  font-size: var(--fs-sm);
  padding: 5px 12px;
  font-weight: 500;
}
#aiPrompts .btn:hover,
button[data-ai-prompt]:hover {
  background: var(--ac-bg);
  border-color: var(--ac-border);
  color: var(--ac);
}

/* AI messages chat bubbles
 *
 * The view-builder hardcodes `background: #1e293b` or `#0f172a` via an
 * inline style for each bubble (user vs assistant). To make bubbles
 * match the redesign palette WITHOUT touching the JS, we override the
 * inline rule with a `!important` here. User-bubble background is
 * tinted with our accent; assistant-bubble is the standard ink-1.
 */
#aiMessages > div,
[id^="aiMsg"] {
  border-radius: var(--r-lg) !important;
  padding: var(--sp-3) !important;
  margin-bottom: var(--sp-2);
  border: 1px solid var(--line-1);
  background: var(--ink-1) !important;
}
/* User bubbles: slightly warmer surface so the conversation reads
 * "back-and-forth" without bringing in raw slate-700 from inline. */
#aiMessages > div[style*="#1e293b"],
#aiMessages > div[style*="1e293b"] {
  background: linear-gradient(180deg, rgba(99,102,241,0.10), rgba(99,102,241,0.04)) !important;
  border-color: rgba(99,102,241,0.20);
}
#aiMessages > div[style*="#0f172a"],
#aiMessages > div[style*="0f172a"] {
  background: var(--ink-1) !important;
  border-color: var(--line-1);
}
#aiMessages details summary {
  color: var(--tx-3) !important;
}
/* Our generic details::before chevron is sized for full-size summaries
 * (--fs-lg = 18px). The AI "Tools used" summary uses an inline 11px
 * font, so shrink the chevron to match. */
#aiMessages details > summary::before {
  font-size: 12px;
  margin-right: 4px;
}
#aiMessages details code {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--tx-2);
  padding: 1px 4px;
  background: rgba(255,255,255,0.03);
  border-radius: var(--r-xs);
}

/* AI memory list cards — view-builder uses inline rgba(255,255,255,.04)
 * for the card surface; tighten the look so memory rows read as cards. */
#aimList > div[style*="rgba(255,255,255,.04)"],
#aimList > div[style*="rgba(255,255,255,0.04)"] {
  background: var(--ink-1) !important;
  border-color: var(--line-1) !important;
  border-radius: var(--r-md) !important;
  padding: var(--sp-3) !important;
  margin-bottom: var(--sp-2) !important;
}

/* AI pending-approval panel — view-builder hardcodes `background:#1f2937`
 * for the panel and `background:#0f172a` for the inner pending cards.
 * Override to use our ink palette so the pending area visually belongs
 * with the rest of the drawer. */
#aiPendingPanel > div {
  background: var(--ink-2) !important;
  border-top: 1px solid var(--line-1) !important;
}
#aiPendingPanel > div > .small {
  color: var(--warn) !important;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 10px !important;
}
#aiPendingPanel > div > div[style*="background:#0f172a"] {
  background: var(--ink-1) !important;
  border-color: var(--line-1) !important;
  border-radius: var(--r-md) !important;
}

/* ═════════════════════════════════════════════════════════════════
 * NOTIFICATIONS LIST — clickable items with unread bullet
 *
 * The notifications inbox renders each item as `.notice[data-nid]`
 * with a leading "• " in the title when unread. Treat the whole row
 * as clickable: cursor pointer + hover lift + bolder left rule when
 * unread.
 * ═════════════════════════════════════════════════════════════════ */
#notifList .notice[data-nid] {
  cursor: pointer;
  transition: background var(--tx-fast), border-color var(--tx-fast), transform var(--tx-fast);
}
#notifList .notice[data-nid]:hover {
  background: rgba(99, 102, 241, 0.06);
  border-color: var(--line-2);
}
#notifList .notice[data-nid] b {
  font-weight: 600;
}

/* ═════════════════════════════════════════════════════════════════
 * PRICING AGENT — Run Report standalone modal
 *
 * Built outside of openModal() in inline.js with an inline-styled
 * `position:fixed; background:rgba(0,0,0,.55)` wrapper. Its inner
 * card uses `background:#0b1220`. Override so the modal uses our
 * design system surfaces / blur backdrop.
 * ═════════════════════════════════════════════════════════════════ */
#paRunReportModal,
#paDiagModal {
  background: rgba(5, 7, 13, 0.72) !important;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
#paRunReportModal > .card,
#paDiagModal > .card {
  background: var(--ink-3) !important;
  border: 1px solid var(--line-2) !important;
  border-radius: var(--r-xl) !important;
  box-shadow: var(--shadow-2) !important;
}
#paRunReportModal > .card > .hd,
#paDiagModal > .card > .hd {
  padding: var(--sp-3) var(--sp-4);
  background: transparent;
  border-bottom: 1px solid var(--line-1);
}
#paRunReportModal > .card > .hd b,
#paDiagModal > .card > .hd b {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.015em;
}
#paRunReportModal > .card > .bd,
#paDiagModal > .card > .bd {
  padding: var(--sp-4);
  overflow: auto;
}
#paRunReportModal > .card > .row,
#paDiagModal > .card > .row {
  border-top: 1px solid var(--line-1);
  padding: var(--sp-3) var(--sp-4) !important;
}
/* Mobile: make it a bottom sheet like other modals */
@media (max-width: 720px) {
  #paRunReportModal,
  #paDiagModal { align-items: flex-end !important; }
  #paRunReportModal > .card,
  #paDiagModal > .card {
    width: 100% !important;
    border-radius: var(--r-xl) var(--r-xl) 0 0 !important;
    max-height: 92dvh;
  }
}

/* ═════════════════════════════════════════════════════════════════
 * PRICE SHEET VIEW — embedded iframe surface
 *
 * `#psWrap` ships with `border: 1px solid rgba(255,255,255,.12)` and
 * `background: rgba(0,0,0,.18)` inline. Override to use design tokens.
 * ═════════════════════════════════════════════════════════════════ */
#psWrap {
  border-color: var(--line-1) !important;
  border-radius: var(--r-lg) !important;
  background: var(--ink-1) !important;
  overflow: hidden;
  min-height: 320px;
}
#psWrap iframe {
  border: 0;
  width: 100%;
  height: 70vh;
  display: block;
}
#psWrap > .muted {
  padding: var(--sp-4) var(--sp-5);
  color: var(--tx-3);
}

/* Pricing-agent preview-modal search input — view-builder uses inline
 * #0f172a + rgba(255,255,255,.15). Override to match form-control look. */
#paPrevSearch {
  background: var(--ink-1) !important;
  border: 1px solid var(--line-2) !important;
  color: var(--tx-1) !important;
  border-radius: var(--r-sm) !important;
  font-family: var(--font-sans);
}
#paPrevSearch:focus {
  outline: none;
  border-color: var(--ac-border) !important;
  box-shadow: var(--ac-glow);
}

/* Pricing-agent preview-modal paste textarea — same treatment */
#paPasteArea {
  background: var(--ink-1) !important;
  border: 1px solid var(--line-2) !important;
  color: var(--tx-1) !important;
  border-radius: var(--r-sm) !important;
  font-family: var(--font-mono);
}
#paPasteArea:focus {
  outline: none;
  border-color: var(--ac-border) !important;
  box-shadow: var(--ac-glow);
}
#paPastePanel {
  background: var(--ink-1) !important;
  border: 1px solid var(--line-1) !important;
  border-radius: var(--r-md) !important;
}

/* AI bulk-review inline-styled <select data-blr-cat> + <input> in
 * the memory editor. These use a hardcoded `background:#0f172a;color:#fff`
 * pattern. Override colors but keep the width / font-size from the
 * inline style — they need to fit inside dense table cells. */
select[data-blr-cat],
input[data-blr-cat-custom],
input[data-aa-cap] {
  background: var(--ink-0) !important;
  border-color: var(--line-2) !important;
  color: var(--tx-1) !important;
  border-radius: var(--r-xs) !important;
}
select[data-blr-cat]:focus,
input[data-blr-cat-custom]:focus,
input[data-aa-cap]:focus {
  outline: none;
  border-color: var(--ac-border) !important;
  box-shadow: 0 0 0 2px var(--ac-bg) !important;
}
/* AI bulk-review row hover */
tr[data-blr-id] {
  transition: background var(--tx-fast);
}
tr[data-blr-id]:hover {
  background: rgba(99, 102, 241, 0.04);
}

/* AI history conversation row — the "Open conversation" button gets
 * a hover state so it reads as clickable. Inline `color:#cbd5e1` keeps
 * the dim slate look; we just add a left-rule accent on hover. */
button.link[data-ai-conv] {
  transition: background var(--tx-fast), padding-left var(--tx-fast);
}
button.link[data-ai-conv]:hover {
  background: rgba(99, 102, 241, 0.06) !important;
  color: var(--tx-1) !important;
  padding-left: var(--sp-2) !important;
  border-radius: var(--r-xs);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: TEAM (#team) + TEAM USER (#team-user)
 * Worker permissions list.
 * ═════════════════════════════════════════════════════════════════ */
#teamBody td {
  font-size: var(--fs-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: PRICE SHEET (#pricesheet)
 * XLSX viewer + upload chrome.
 * ═════════════════════════════════════════════════════════════════ */
/* Inherits global card / btn / table styles. */

/* ═════════════════════════════════════════════════════════════════
 * VIEW: SETTINGS — more polish on the specific sub-sections
 * ═════════════════════════════════════════════════════════════════ */

/* Owner-only section visual cue: subtle indigo top hairline so the
   admin sees these are gated. */
.secCard.ownerOnly {
  position: relative;
}
.secCard.ownerOnly::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--ac-solid), transparent);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  opacity: 0.5;
}

/* Settings: nested input field rows align flush */
.secBody .field input,
.secBody .field select,
.secBody .field textarea {
  background: var(--ink-0);
}

/* Boot Timing panel (already exists) — tighten */
#bootTimingSec table th,
#bootTimingSec table td {
  font-size: var(--fs-xs);
}

/* ═════════════════════════════════════════════════════════════════
 * EMPTY STATES — generic polish across views
 * ═════════════════════════════════════════════════════════════════ */

/* Generic "no rows" placeholder pattern */
tbody td.muted[colspan],
tbody tr td[colspan].muted,
.muted-empty {
  text-align: center;
  padding: var(--sp-7) var(--sp-4);
  color: var(--tx-3);
  font-size: var(--fs-sm);
  font-style: italic;
}

/* Loading shimmer placeholder (for any element with .loading class) */
.loading-skeleton {
  background: linear-gradient(90deg,
    var(--ink-1) 0%,
    var(--ink-2) 50%,
    var(--ink-1) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: var(--r-sm);
}
@keyframes shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* ═════════════════════════════════════════════════════════════════
 * KEYBOARD HINT (kbd elements + ⌘K patterns)
 * ═════════════════════════════════════════════════════════════════ */
kbd, .kbd {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  border-radius: var(--r-xs);
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--line-2);
  border-bottom-width: 2px;
  color: var(--tx-2);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}

/* ═════════════════════════════════════════════════════════════════
 * PAGE HEADER — generic component for view-level titles
 * ═════════════════════════════════════════════════════════════════ */
.pageHd {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-4) 0;
}
.pageHd h2 {
  margin: 0;
  font-size: var(--fs-3xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--tx-1);
}
.pageHd .meta {
  color: var(--tx-3);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.10em;
  font-weight: 700;
}

/* ═════════════════════════════════════════════════════════════════
 * FATAL OVERLAY — tighter
 * ═════════════════════════════════════════════════════════════════ */
#fatal h2 {
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 var(--sp-3);
  color: var(--bad);
}

/* ═════════════════════════════════════════════════════════════════
 * RECEIPT ROW (mobile attachment buttons) — keep clean
 * ═════════════════════════════════════════════════════════════════ */
.receiptRow .btn {
  padding: 7px 12px;
  border-radius: var(--r-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * AI TRIGGER — top-bar search button. Match the new design.
 * Pulled from the standalone <style> block in index.html.
 * ═════════════════════════════════════════════════════════════════ */
#aiTrigger {
  background: var(--ink-1);
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  color: var(--tx-2);
  transition: background var(--tx-fast), border-color var(--tx-fast);
}
#aiTrigger:hover {
  background: var(--ink-2);
  border-color: var(--line-3);
}
.aiKbdHint {
  font-size: 10px;
  color: var(--tx-3);
  font-family: var(--font-mono);
}

/* ═════════════════════════════════════════════════════════════════
 * ADDITIONAL VISUAL POLISH
 * ═════════════════════════════════════════════════════════════════ */

/* Smooth out border-radius on nested elements inside tableWrap */
.tableWrap > table { border-radius: var(--r-md); overflow: clip; }

/* Wide-form input groups in modals: tighten the gap */
.modal .field input,
.modal .field select,
.modal .field textarea {
  background: rgba(0,0,0,0.40);
}

/* Action button row at the bottom of cards/modals */
.card .bd > .row:last-child,
.modal > .row:last-child {
  margin-top: var(--sp-4);
}

/* Loading text */
.muted.loading::after {
  content: "...";
  display: inline-block;
  animation: dotpulse 1.2s steps(4, end) infinite;
}
@keyframes dotpulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 1.0; }
}

/* Make sure the icon font + emoji in bottom nav and brand mark
   don't accidentally pick up Inter (which doesn't have emoji glyphs). */
.bottomNav .navBtn .ic,
.docLogo {
  font-family: system-ui, "Apple Color Emoji", "Segoe UI Emoji", sans-serif;
}

/* Ensure the modal body inputs are usable on iOS (16px font prevents zoom) */
@media (max-width: 520px) {
  .modal input, .modal select, .modal textarea {
    font-size: 16px !important;
  }
}

/* Better text rendering on Inter */
* {
  text-rendering: optimizeLegibility;
}

/* ═════════════════════════════════════════════════════════════════
 * AUTH OVERLAY — login / signup / forgot password / 2FA / etc.
 * First thing users see — make it polished.
 * ═════════════════════════════════════════════════════════════════ */
#authOverlay {
  background: radial-gradient(900px 600px at 50% -10%, rgba(99, 102, 241, 0.20), transparent 60%),
              rgba(5, 7, 13, 0.92);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
#authOverlay .panel.card {
  max-width: 440px;
  margin: 80px auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-6);
  background: linear-gradient(180deg, var(--ink-warm), var(--ink-cool));
  border: 1px solid var(--line-2);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-2);
}
#authOverlay .h2 {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--tx-1);
  margin: 0;
}
#authOverlay .small.muted {
  font-size: var(--fs-sm);
  color: var(--tx-3);
  line-height: 1.5;
  margin-top: 2px;
}
#authOverlay .tabs {
  margin: var(--sp-4) 0 var(--sp-3);
  gap: 0;
  border-bottom: 1px solid var(--line-1);
  padding: 0;
}
#authOverlay .tabBtn {
  flex: 1;
  border: 0;
  background: transparent;
  border-radius: 0;
  padding: 10px 12px;
  color: var(--tx-3);
  font-weight: 600;
  font-size: var(--fs-md);
  position: relative;
}
#authOverlay .tabBtn.ghost { /* default "inactive" state */
  background: transparent;
  border: 0;
}
#authOverlay .tabBtn:not(.ghost) {
  color: var(--tx-1);
  background: transparent;
}
#authOverlay .tabBtn:not(.ghost)::after {
  content: "";
  position: absolute;
  left: var(--sp-3); right: var(--sp-3);
  bottom: -1px;
  height: 2px;
  background: var(--ac);
  border-radius: 2px 2px 0 0;
}
#authOverlay label {
  display: block;
  margin: var(--sp-3) 0 var(--sp-1);
  font-size: var(--fs-2xs);
  color: var(--tx-3);
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}
#authOverlay input {
  width: 100%;
  background: var(--ink-0);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  padding: 10px 12px;
}
#authOverlay input:focus {
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
  background: var(--ink-0);
}
#authOverlay .hint {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  margin-top: var(--sp-1);
  opacity: 1;
}
#authOverlay .err {
  margin-top: var(--sp-3);
}
#authOverlay button[type="submit"] {
  background: linear-gradient(180deg, var(--ac-hover) 0%, var(--ac-solid) 100%);
  border-color: var(--ac-solid);
  color: #fff;
  font-weight: 700;
  padding: 9px 18px;
  box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset, 0 2px 8px rgba(99, 102, 241, 0.30);
}
#authOverlay button[type="submit"]:hover {
  background: linear-gradient(180deg, var(--ac), var(--ac-hover));
}
#authOverlay #forgotPwLink {
  color: var(--ac);
  font-weight: 600;
  text-decoration: none;
}
#authOverlay #forgotPwLink:hover {
  color: var(--ac-hover);
  text-decoration: underline;
}

/* ═════════════════════════════════════════════════════════════════
 * DRAWER NAV — active page indicator
 * The drawer doesn't currently mark the active page visually.
 * Make the underlying nav links pick up an accent state via :hover
 * AND for the page they correspond to (via [href^="#X"] for routes
 * that match the current location.hash).
 * ═════════════════════════════════════════════════════════════════ */

/* Drawer link icon space — add subtle hover preview */
.drawer .drawerNav a {
  position: relative;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.drawer .drawerNav a::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 3px; height: 0;
  background: var(--ac);
  border-radius: 0 2px 2px 0;
  transition: height var(--tx-fast);
  transform: translateY(-50%);
}
.drawer .drawerNav a:hover::before { height: 18px; }

/* When the route matches, JS adds .currentRoute class — style it
   even though no current code sets that yet. This is forward-looking
   so the moment a future commit wires it, the style is ready. */
.drawer .drawerNav a.currentRoute {
  color: var(--ac);
  background: var(--ac-bg-2);
}
.drawer .drawerNav a.currentRoute::before { height: 18px; }

/* ═════════════════════════════════════════════════════════════════
 * TOPBAR PILL — Cloud sync pill
 * ═════════════════════════════════════════════════════════════════ */
#topCloudPill {
  background: var(--ink-1);
  border: 1px solid var(--line-1);
  padding: 5px 10px;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--tx-2);
}
#topCloudPill .dot {
  width: 6px; height: 6px;
  box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.18);
}

/* ═════════════════════════════════════════════════════════════════
 * NESTED CARDS / MODALS — prevent double-gradient on cards inside
 * modals (the modal already has its own surface treatment).
 * ═════════════════════════════════════════════════════════════════ */
.modal .card,
.modal > .card,
.drawer .card {
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--line-1);
  box-shadow: none;
}

/* secCard inside a settings page wraps OUTSIDE a card, so leave its
   gradient. But if a future commit puts secCard inside another card,
   neutralize the gradient stack. */
.card .secCard {
  background: rgba(255,255,255,0.02);
  box-shadow: none;
}

/* ═════════════════════════════════════════════════════════════════
 * STRIPES TABLE NUMERIC RIGHT-ALIGNMENT
 * Per Stripe convention, money + counts columns should be right-aligned.
 * The markup mostly uses class="num" or text content like $123.
 * ═════════════════════════════════════════════════════════════════ */
th.num, td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ═════════════════════════════════════════════════════════════════
 * HSCROLL ACTION STRIPS — when actions wrap in a horizontal scroll
 * ═════════════════════════════════════════════════════════════════ */
.hScroll {
  padding: var(--sp-2) 0;
}
.hScroll .btn {
  flex-shrink: 0;
}

/* ═════════════════════════════════════════════════════════════════
 * PRINT MODE — when the operator prints a receipt/invoice/statement.
 * Hide app chrome; show only the .docPaper content.
 * ═════════════════════════════════════════════════════════════════ */
@media print {
  header, .bottomNav, .drawer, .drawerOverlay,
  .toastWrap, #aiTrigger, #aiBgTasks, #fatal,
  .modalOverlay, #aiDrawer, #aiDrawerOverlay,
  #paRunReportModal, #paDiagModal, #paPreviewModal {
    display: none !important;
  }
  body {
    background: #fff !important;
    color: #111 !important;
  }
  .wrap {
    padding: 0 !important;
    max-width: 100% !important;
  }
  .card, .secCard {
    background: #fff !important;
    border: 0 !important;
    box-shadow: none !important;
  }
  .docPaper { box-shadow: none !important; }
}

/* ═════════════════════════════════════════════════════════════════
 * REDUCED MOTION — respect users with motion-sensitivity prefs
 * ═════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  .scanLine { animation: none; }
  .loading-skeleton { animation: none; }
}

/* ═════════════════════════════════════════════════════════════════
 * CARD HOVER LIFT — subtle on interactive cards (those with
 * data-route or onClick handlers). Default cards do NOT lift —
 * they're informational.
 * ═════════════════════════════════════════════════════════════════ */
.card[data-route],
.card.clickable,
a > .card,
button > .card {
  cursor: pointer;
  transition: border-color var(--tx-fast), transform var(--tx-fast);
}
.card[data-route]:hover,
.card.clickable:hover,
a:hover > .card,
button:hover > .card {
  border-color: var(--line-3);
  transform: translateY(-1px);
}

/* ═════════════════════════════════════════════════════════════════
 * TABLE OF SALES (the Sales page invoice picker)
 * ═════════════════════════════════════════════════════════════════ */
#invPickList {
  font-size: var(--fs-sm);
}
#invPickList .invPick {
  width: 16px; height: 16px;
}

/* ═════════════════════════════════════════════════════════════════
 * FEATURE: status row indicator dots in tables.
 * The first <td> of any row containing .tag.bad or .tag.warn gets
 * a color-matched dot. (.good already covered above.)
 * ═════════════════════════════════════════════════════════════════ */
#main table tbody tr:has(.tag.warn) td:first-child,
#main table tbody tr:has(.badge.warn) td:first-child {
  position: relative;
  padding-left: 18px;
}
#main table tbody tr:has(.tag.warn) td:first-child::before,
#main table tbody tr:has(.badge.warn) td:first-child::before {
  content: "";
  position: absolute;
  left: 8px; top: 50%;
  transform: translateY(-50%);
  width: 6px; height: 6px;
  background: var(--warn);
  border-radius: var(--r-pill);
  box-shadow: 0 0 0 2px rgba(251, 191, 36, 0.20);
}
#main table tbody tr:has(.tag.bad) td:first-child,
#main table tbody tr:has(.badge.bad) td:first-child {
  position: relative;
  padding-left: 18px;
}
#main table tbody tr:has(.tag.bad) td:first-child::before,
#main table tbody tr:has(.badge.bad) td:first-child::before {
  content: "";
  position: absolute;
  left: 8px; top: 50%;
  transform: translateY(-50%);
  width: 6px; height: 6px;
  background: var(--bad);
  border-radius: var(--r-pill);
  box-shadow: 0 0 0 2px rgba(248, 113, 113, 0.22);
}

/* ═════════════════════════════════════════════════════════════════
 * MORE BUTTON VARIANTS — .warn, .danger, and the snap- specials
 * ═════════════════════════════════════════════════════════════════ */
.btn.warn {
  background: linear-gradient(180deg, var(--warn) 0%, var(--warn-solid) 100%);
  border-color: var(--warn-solid);
  color: #1a1100;
  box-shadow: 0 1px 0 rgba(255,255,255,0.18) inset, 0 2px 8px rgba(251, 191, 36, 0.28);
  font-weight: 700;
}
.btn.warn:hover {
  background: linear-gradient(180deg, #fcd34d, var(--warn));
}

.btn.danger {
  background: linear-gradient(180deg, var(--bad) 0%, var(--bad-solid) 100%);
  border-color: var(--bad-solid);
  color: #fff;
  box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset, 0 2px 8px rgba(239, 68, 68, 0.30);
}
.btn.danger:hover { background: linear-gradient(180deg, #fb8585, var(--bad)); }

/* ═════════════════════════════════════════════════════════════════
 * BULK MDM STATUS CELL — used inside bulk-intake table for per-
 * device MDM status (Eligible / Checked / On / Off). Pair badge
 * with the row's action button.
 * ═════════════════════════════════════════════════════════════════ */
.bulkMdmBtn {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--line-2);
  color: var(--tx-1);
  font-size: var(--fs-xs);
  font-weight: 600;
  border-radius: var(--r-xs);
  padding: 5px 10px;
}
.bulkMdmBtn:hover {
  background: rgba(255,255,255,0.08);
  border-color: var(--line-3);
}

/* Bulk detail grid (Edit Bulk Item modal) — surface refinement */
.bulkDetailGrid > div {
  background: rgba(0,0,0,0.20);
  border: 1px solid var(--line-1);
}
.bulkDetailGrid > div:hover {
  border-color: var(--line-2);
}

/* ═════════════════════════════════════════════════════════════════
 * INLINE-EDITABLE TABLE CELLS — when a price/cost cell becomes an
 * input field (e.g., invoice line items, statement fix-missing).
 * ═════════════════════════════════════════════════════════════════ */
table input[type="text"],
table input[type="number"],
table input[inputmode="decimal"] {
  padding: 5px 8px;
  font-size: var(--fs-sm);
  border-radius: var(--r-xs);
  background: rgba(0,0,0,0.30);
  border: 1px solid var(--line-1);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
table input:focus {
  border-color: var(--ac-border);
  background: rgba(0,0,0,0.50);
}

/* ═════════════════════════════════════════════════════════════════
 * SNAPSHOT BUTTONS — Cloud Backup
 * snapDownload / snapRestore appear in Settings → Cloud Backup +
 * Snapshots. Keep them small and tidy.
 * ═════════════════════════════════════════════════════════════════ */
.btn.snapDownload {
  font-size: var(--fs-xs);
  padding: 5px 10px;
  border-radius: var(--r-xs);
}
.btn.snapRestore {
  font-size: var(--fs-xs);
  padding: 5px 10px;
  border-radius: var(--r-xs);
  background: var(--warn-bg);
  border-color: var(--warn-border);
  color: var(--warn);
  font-weight: 600;
}
.btn.snapRestore:hover {
  background: rgba(251, 191, 36, 0.20);
  border-color: rgba(251, 191, 36, 0.55);
}

/* ═════════════════════════════════════════════════════════════════
 * AI MEMORY / TOOLS panel
 * The AI page has a memory list + pending tools panel. Refine.
 * ═════════════════════════════════════════════════════════════════ */
#aiMemoryList > div,
#aiToolsList > div {
  padding: var(--sp-3);
  border: 1px solid var(--line-1);
  background: var(--ink-1);
  border-radius: var(--r-md);
  margin-bottom: var(--sp-2);
}

/* ═════════════════════════════════════════════════════════════════
 * PRICING AGENT — table-with-status (results table)
 * Each result row has a status pill in last column. Make the row
 * border-left accent reflect the status.
 * ═════════════════════════════════════════════════════════════════ */
#paResultsTbl tbody tr,
table[id*="paResults" i] tbody tr {
  border-left: 3px solid transparent;
  transition: border-left-color var(--tx-fast), background var(--tx-fast);
}
#paResultsTbl tbody tr:has(.tag.good),
table[id*="paResults" i] tbody tr:has(.badge.good) {
  border-left-color: var(--good);
}
#paResultsTbl tbody tr:has(.tag.warn),
table[id*="paResults" i] tbody tr:has(.badge.warn) {
  border-left-color: var(--warn);
}
#paResultsTbl tbody tr:has(.tag.bad),
table[id*="paResults" i] tbody tr:has(.badge.bad) {
  border-left-color: var(--bad);
}

/* ═════════════════════════════════════════════════════════════════
 * IMEI REPORT MODAL — key/value list with grouped data
 * ═════════════════════════════════════════════════════════════════ */
.modal .kvList { gap: var(--sp-2); }
.modal .kvItem { padding: var(--sp-2) var(--sp-3); }

/* ═════════════════════════════════════════════════════════════════
 * TOAST POSITIONING REFINEMENT
 * The legacy toast was bottom-only; on mobile we move it above the
 * bottom nav so it's not hidden.
 * ═════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .toastWrap {
    bottom: calc(70px + env(safe-area-inset-bottom));
  }
}

/* ═════════════════════════════════════════════════════════════════
 * CARD HEADER WITH ACTION BUTTON
 * Many cards have a header like:
 *   <div class='hd'><h2>Title</h2></div>
 * but some have a header with an action button (refresh, etc.).
 * Make sure those flex correctly.
 * ═════════════════════════════════════════════════════════════════ */
.card .hd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}
.card .hd > div:first-child { flex: 1; min-width: 0; }
.card .hd .btn {
  flex: 0 0 auto;
  padding: 5px 10px;
  font-size: var(--fs-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * NESTED ROWS INSIDE CARDS — better spacing rhythm
 * ═════════════════════════════════════════════════════════════════ */
.card .bd .row + .row { margin-top: var(--sp-3); }
.card .bd .row + .hr,
.card .bd .hr + .row { margin-top: var(--sp-3); }

/* ═════════════════════════════════════════════════════════════════
 * BUYERS TABLE CONTACT CELL — the cell renders a mailto/tel link
 * inside <a class='small'>. Style that link cleanly.
 * ═════════════════════════════════════════════════════════════════ */
table a.small {
  color: var(--ac);
  text-decoration: none;
  font-weight: 500;
}
table a.small:hover {
  color: var(--ac-hover);
  text-decoration: underline;
}

/* ═════════════════════════════════════════════════════════════════
 * IMAGE PREVIEW (scanner photo, receipt attach)
 * ═════════════════════════════════════════════════════════════════ */
.imgPrev {
  display: block;
  border-radius: var(--r-md);
  border: 1px solid var(--line-1);
  background: rgba(0,0,0,0.40);
  overflow: hidden;
}

/* ═════════════════════════════════════════════════════════════════
 * NOTIFICATIONS — empty state has more personality
 * ═════════════════════════════════════════════════════════════════ */
#notifList:empty::before,
#main:has(#notifList:empty) #notifList::before {
  content: "No notifications yet";
  display: block;
  text-align: center;
  padding: var(--sp-8) var(--sp-4);
  color: var(--tx-3);
  font-size: var(--fs-sm);
  font-style: italic;
}

/* ═════════════════════════════════════════════════════════════════
 * AI TRIGGER (top search bar) — keep it confident
 * ═════════════════════════════════════════════════════════════════ */
#aiTrigger {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: var(--fs-sm);
  letter-spacing: -0.005em;
}

/* ═════════════════════════════════════════════════════════════════
 * NICE-TO-HAVE: keyboard focus on table rows (for keyboard nav)
 * ═════════════════════════════════════════════════════════════════ */
tbody tr:focus-within td {
  background: rgba(129, 140, 248, 0.08);
}

/* ═════════════════════════════════════════════════════════════════
 * VENDOR HISTORY MODAL — search + buttons row
 * ═════════════════════════════════════════════════════════════════ */
#vhQ {
  border-radius: var(--r-pill);
  padding-left: var(--sp-4);
}

/* ═════════════════════════════════════════════════════════════════
 * STATEMENT VIEWER — month label / period chrome
 * ═════════════════════════════════════════════════════════════════ */
.stmtMonthLabel,
.stmtPeriod {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--tx-1);
}

/* ═════════════════════════════════════════════════════════════════
 * LOAN PACKAGE — section grouping
 * ═════════════════════════════════════════════════════════════════ */
.loanSection {
  margin-top: var(--sp-5);
}
.loanSection h3,
.loanSection h4 {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.005em;
  margin: 0 0 var(--sp-2);
}

/* ═════════════════════════════════════════════════════════════════
 * BANK CONNECTIONS LIST (Settings → Plaid)
 * ═════════════════════════════════════════════════════════════════ */
#bankConnList > div {
  padding: var(--sp-3);
  border: 1px solid var(--line-1);
  background: var(--ink-1);
  border-radius: var(--r-md);
  margin-bottom: var(--sp-2);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

/* ═════════════════════════════════════════════════════════════════
 * AI SUGGEST META LINE (visible after "Suggest Price" clicks)
 * ═════════════════════════════════════════════════════════════════ */
#suggestMeta {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  font-family: var(--font-mono);
  letter-spacing: -0.005em;
}

/* ═════════════════════════════════════════════════════════════════
 * TAX CENTER — projection mode + period selectors
 * ═════════════════════════════════════════════════════════════════ */
#taxProjMode,
#taxPeriodSel,
#loanPeriodSel,
#loanMonthSel {
  min-width: 140px;
}

/* ═════════════════════════════════════════════════════════════════
 * MINIMUM VIABLE LOADING / ERROR PATTERN
 * Every async card shows a "Loading…" muted line — promote it.
 * ═════════════════════════════════════════════════════════════════ */
tbody tr td.muted:only-child {
  text-align: center;
  padding: var(--sp-6) var(--sp-4);
  color: var(--tx-3);
  font-size: var(--fs-sm);
}

/* ═════════════════════════════════════════════════════════════════
 * BANK TX CATEGORY CHIP — used in accounting reconciliation
 * ═════════════════════════════════════════════════════════════════ */
.bankCatChip {
  display: inline-flex;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--ac-bg-2);
  border: 1px solid var(--ac-border);
  color: var(--ac);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ═════════════════════════════════════════════════════════════════
 * SUMMARY CHIPS (Pricing Agent summary strip)
 * ═════════════════════════════════════════════════════════════════ */
#paSummary div[class*="row"] > div {
  position: relative;
}

/* ═════════════════════════════════════════════════════════════════
 * MOBILE EDGE CASES + REFINEMENTS
 * ═════════════════════════════════════════════════════════════════ */

/* IE brand mark — keep visible on tablets/desktop, but on very
   narrow phones (<360px) we hide it to give the title room.
   28x28 on phones, 32x32 default. */
@media (max-width: 720px) {
  .brand { grid-template-columns: 28px 1fr; column-gap: 8px; }
  .brand::before { width: 28px; height: 28px; font-size: 11px; }
  .brand h1 { font-size: var(--fs-md); }
}
@media (max-width: 360px) {
  .brand { grid-template-columns: 1fr; }
  .brand::before { display: none; }
  .brand h1 { grid-column: 1; }
  .brand .sub { grid-column: 1; }
}

/* Topbar pill chrome on mobile — smaller */
@media (max-width: 720px) {
  #topCloudPill { font-size: var(--fs-xs); padding: 4px 8px; }
  #topCloudPill .dot { width: 5px; height: 5px; }
}

/* Make the title text actually truncate when overflowing instead of
   wrapping awkwardly */
.brand h1 {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* Action row in topbar — make it wrap nicely */
.actions {
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.actions .btn {
  font-size: var(--fs-sm);
  padding: 7px 11px;
}
.actions #topCloudPill { order: -1; }

/* ═════════════════════════════════════════════════════════════════
 * AI TRIGGER (search-bar style) — match the redesign palette
 * The button has inline styles that we need to override carefully.
 * Keep the red "AI" badge as the deliberate brand cue.
 * ═════════════════════════════════════════════════════════════════ */
#aiTrigger {
  background: rgba(11, 16, 32, 0.92) !important;
  border: 1px solid var(--line-2) !important;
  border-radius: var(--r-pill) !important;
  box-shadow: var(--shadow-1) !important;
  color: var(--tx-2) !important;
}
#aiTrigger:hover {
  background: var(--ink-1) !important;
  border-color: var(--line-3) !important;
}
#aiTriggerLabel {
  color: var(--tx-3) !important;
  font-size: var(--fs-sm) !important;
  font-family: var(--font-sans) !important;
}
.aiKbdHint {
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--line-2) !important;
  border-bottom-width: 2px;
  color: var(--tx-2) !important;
  font-family: var(--font-mono) !important;
  font-weight: 600;
  border-radius: var(--r-xs) !important;
  padding: 1px 6px !important;
}

/* ═════════════════════════════════════════════════════════════════
 * AI DRAWER (right-side panel slid in by #aiTrigger)
 * ═════════════════════════════════════════════════════════════════ */
#aiDrawer {
  background: var(--ink-2) !important;
  border-left: 1px solid var(--line-2);
  box-shadow: var(--shadow-2);
  /* Sit above the mobile bottom-nav (z-index 9996) so the textarea
   * at the drawer's bottom isn't hidden behind it. */
  z-index: 9999 !important;
}
/* On mobile (where the .bottomNav is visible), reserve enough space
 * at the bottom of the drawer so the input row clears the nav. The
 * nav is ~60-72px tall (padding + nav button + safe-area).
 * Verified at 390×844 (iPhone 14): textarea bottom landed only 12px
 * above the nav top — too tight for a 375×667 iPhone SE. Bumped to
 * 96px so smaller phones get real clearance too. */
@media (max-width: 899px) {
  #aiDrawer {
    padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)) !important;
  }
}
#aiDrawerOverlay {
  background: rgba(5, 7, 13, 0.70) !important;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  /* Match the drawer's z-index so the overlay covers the bottom nav
   * too — otherwise tapping the nav while the drawer is open dismisses
   * the drawer in an unexpected way. */
  z-index: 9998 !important;
}

/* AI drawer chrome — close button, header, etc. */
#aiDrawer .closeBtn {
  width: 36px; height: 36px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.04);
  color: var(--tx-2);
}
#aiDrawer .closeBtn:hover { background: rgba(255,255,255,0.08); color: var(--tx-1); }

/* Inline-styled subdivisions inside #aiDrawer (header / suggested
 * row / pending panel / preferences row / input row). Each is a
 * direct child <div> with inline border + padding. Override common
 * fragments so they use design-system borders/tx instead of raw
 * white-alpha hex. */
#aiDrawer > div {
  border-color: var(--line-1) !important;
}
#aiDrawer > div[style*="background:rgba(255,255,255,.03)"],
#aiDrawer > div[style*="background:rgba(255,255,255,0.03)"] {
  background: rgba(255, 255, 255, 0.02) !important;
}
#aiDrawer #aiInput {
  background: var(--ink-1) !important;
  border: 1px solid var(--line-2) !important;
  color: var(--tx-1) !important;
  border-radius: var(--r-md) !important;
  font-family: var(--font-sans);
  transition: border-color var(--tx-fast), box-shadow var(--tx-fast);
}
#aiDrawer #aiInput:focus {
  outline: none;
  border-color: var(--ac-border) !important;
  box-shadow: var(--ac-glow);
}
#aiDrawer #aiSuggested {
  color: var(--tx-3) !important;
}
#aiDrawer .btn.tiny {
  padding: 5px 10px;
}

/* AI trigger button (FAB-style on the right edge). */
#aiTrigger .aiKbdHint {
  border-color: var(--line-2) !important;
  color: var(--tx-3) !important;
  background: rgba(255, 255, 255, 0.04);
}

/* ═════════════════════════════════════════════════════════════════
 * BACKGROUND-TASKS PILL (AI bank-label processing, etc.)
 * ═════════════════════════════════════════════════════════════════ */
#aiBgTasks {
  background: var(--ink-2) !important;
  border: 1px solid var(--line-2) !important;
  border-radius: var(--r-lg) !important;
  box-shadow: var(--shadow-1) !important;
  color: var(--tx-1) !important;
  padding: var(--sp-3) !important;
}

/* ═════════════════════════════════════════════════════════════════
 * INVOICE PICKER MODAL — pickup-when-creating-invoice flow
 * ═════════════════════════════════════════════════════════════════ */
#invPickList tr {
  cursor: pointer;
}
#invPickList tr:hover td {
  background: var(--ac-bg-2);
}

/* ═════════════════════════════════════════════════════════════════
 * MORE TABLE REFINEMENTS — first/last column rounded corners
 * ═════════════════════════════════════════════════════════════════ */
.tableWrap > table thead th:first-child { border-top-left-radius: var(--r-sm); }
.tableWrap > table thead th:last-child { border-top-right-radius: var(--r-sm); }

/* ═════════════════════════════════════════════════════════════════
 * CHIP / PILL EXPANSIONS — used in many places
 * ═════════════════════════════════════════════════════════════════ */
.chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  background: rgba(255,255,255,0.04);
  color: var(--tx-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--tx-fast), color var(--tx-fast), border-color var(--tx-fast);
}
.chip:hover {
  background: rgba(255,255,255,0.08);
  color: var(--tx-1);
}
.chip.active {
  background: var(--ac-bg);
  border-color: var(--ac-border);
  color: var(--ac);
}

/* ═════════════════════════════════════════════════════════════════
 * HEADER ACTIONS — make sure desktop fits comfortably
 * ═════════════════════════════════════════════════════════════════ */
@media (min-width: 980px) {
  .actions { gap: var(--sp-2); }
  .actions .btn { padding: 7px 12px; }
}

/* ═════════════════════════════════════════════════════════════════
 * UPDATE TO TABLE HOVER — make it more visible
 * ═════════════════════════════════════════════════════════════════ */
tbody tr:hover td {
  background: rgba(129, 140, 248, 0.06);
  cursor: pointer;
}
/* But not for read-only tables — opt out via class */
table.no-hover tbody tr:hover td {
  background: transparent;
  cursor: auto;
}

/* ═════════════════════════════════════════════════════════════════
 * REFINE THE KPI VALUE FONT — use Inter's tabular numerals at
 * the heavy weight for big presence
 * ═════════════════════════════════════════════════════════════════ */
.kpi .box .v {
  font-family: var(--font-sans);
  font-weight: 700;
  font-feature-settings: "cv11", "ss03", "tnum";
}

/* Money in tables / forms — slightly bolder numbers */
td:has(b),
table b,
.docTotals b {
  font-weight: 600;
}

/* ═════════════════════════════════════════════════════════════════
 * SETTINGS — sub-nav chips on the chip-row (top sticky)
 * ═════════════════════════════════════════════════════════════════ */
.settingsNav .chip {
  padding: 6px 14px;
  font-size: var(--fs-sm);
  font-weight: 600;
}

/* ═════════════════════════════════════════════════════════════════
 * SCROLLING INSIDE MODALS — make scrollbar match
 * ═════════════════════════════════════════════════════════════════ */
.modal {
  scrollbar-width: thin;
  scrollbar-color: var(--line-3) transparent;
}
.modal::-webkit-scrollbar { width: 8px; }
.modal::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border-radius: var(--r-pill);
}
.modal::-webkit-scrollbar-thumb:hover { background: var(--line-3); }

/* ═════════════════════════════════════════════════════════════════
 * FORM HINTS (the .hint class used in auth + settings)
 * ═════════════════════════════════════════════════════════════════ */
.hint {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  margin-top: var(--sp-1);
  line-height: 1.45;
}

/* ═════════════════════════════════════════════════════════════════
 * PROGRESS / SPINNER — used during async operations
 * ═════════════════════════════════════════════════════════════════ */
.spinner {
  display: inline-block;
  width: 14px; height: 14px;
  border: 2px solid var(--line-2);
  border-top-color: var(--ac);
  border-radius: var(--r-pill);
  animation: spin 0.8s linear infinite;
  vertical-align: -2px;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ═════════════════════════════════════════════════════════════════
 * MICRO-FIXES
 * ═════════════════════════════════════════════════════════════════ */

/* The legacy <h2> used font-weight:900 — keep something close to that
   for the modal title which uses .h2 class */
.h2 {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.018em;
  color: var(--tx-1);
  margin: 0;
}

/* The fatal overlay h2 keeps red */
#fatal h2 { color: var(--bad); }

/* Long mono strings (IMEIs) shouldn't break weirdly mid-character */
.mono, td.mono {
  word-break: keep-all;
  overflow-wrap: anywhere;
}

/* No-break for the "Last sync" + similar status lines */
.statusLine, .syncLine {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  white-space: nowrap;
}

/* Subtle gradient text accent for headline numbers (optional class) */
.gradientText {
  background: linear-gradient(135deg, var(--ac), #a78bfa);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* If the field has a "required" indicator class */
.field label[for]::after,
.required-star::after {
  content: "";
}

/* ═════════════════════════════════════════════════════════════════
 * FINAL POLISH PASS — defensive selectors + visual finishing
 * ═════════════════════════════════════════════════════════════════ */

/* CURSOR on table rows should ONLY be pointer when there's a click
   handler or anchor — opt-in via .clickable on the table. The
   blanket cursor:pointer in d5 was too aggressive. */
tbody tr:hover td { cursor: auto; }
tbody tr.clickable,
table.clickable tbody tr,
tbody tr[onclick],
tbody tr[data-route] {
  cursor: pointer;
}
tbody tr.clickable:hover td,
table.clickable tbody tr:hover td,
tbody tr[onclick]:hover td,
tbody tr[data-route]:hover td {
  background: var(--ac-bg-2);
}

/* Card with inline border style (MDM warning, etc.) still gets the
   gradient background but NOT a border conflict — the inline style
   wins for border anyway, but normalize the surface look. */
.card[style*="border:"] {
  background: rgba(255,255,255,0.025);
}

/* Specifically the MDM warning border-2px-solid pattern */
.card[style*="#b00020"],
.card[style*="border:2px solid"] {
  background: linear-gradient(180deg, rgba(248, 113, 113, 0.08), rgba(0,0,0,0)) , var(--ink-1);
}

/* Specific dashboard inventory listing — refine the rows showing
   "On Hand devices · Sold today · etc" pattern */
.dashRow {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line-0);
}
.dashRow:last-child { border-bottom: 0; }

/* ═════════════════════════════════════════════════════════════════
 * LARGER SPACING IN .bd — when card body has multiple sections
 * ═════════════════════════════════════════════════════════════════ */
.card .bd > h3,
.card .bd > h4 {
  margin-top: var(--sp-4);
  margin-bottom: var(--sp-2);
}
.card .bd > h3:first-child,
.card .bd > h4:first-child {
  margin-top: 0;
}

/* ═════════════════════════════════════════════════════════════════
 * STATEMENT TABLE — section labels in left column emphasized
 * ═════════════════════════════════════════════════════════════════ */
table.stmtTable td:first-child,
.stmtTable tbody td:first-child {
  font-weight: 600;
  color: var(--tx-1);
}

/* ═════════════════════════════════════════════════════════════════
 * DETAILS / SUMMARY — collapsible patterns
 * ═════════════════════════════════════════════════════════════════ */
details {
  border: 1px solid var(--line-1);
  background: rgba(255,255,255,0.02);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  margin: var(--sp-2) 0;
}
details[open] {
  background: rgba(255,255,255,0.03);
}
details > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--tx-2);
  list-style: none;
  outline: none;
  padding: var(--sp-1) 0;
}
details > summary::-webkit-details-marker { display: none; }
details > summary::before {
  content: "›";
  display: inline-block;
  margin-right: var(--sp-2);
  color: var(--tx-3);
  transition: transform var(--tx-fast);
  font-size: var(--fs-lg);
  line-height: 1;
}
details[open] > summary::before {
  transform: rotate(90deg);
}
/* Suppress our chevron when the summary is a `.notice` block — the
 * docs.mjs view (Invoice Device Checklist) and some others render
 * their own dropdown arrow in markup. */
details > summary.notice::before { content: none; display: none; }
details > summary.notice { padding: var(--sp-2) var(--sp-3); }

/* ═════════════════════════════════════════════════════════════════
 * NOTICE / ALERT INSIDE CARDS — extra polish
 * ═════════════════════════════════════════════════════════════════ */
.card .bd > .notice {
  margin: var(--sp-3) 0;
}
.card .bd > .notice:first-child { margin-top: 0; }
.card .bd > .notice:last-child { margin-bottom: 0; }

/* ═════════════════════════════════════════════════════════════════
 * IMG / PHOTO CHROME — used in receipt attachments, scanner preview
 * ═════════════════════════════════════════════════════════════════ */
img:not([class*="docLogo"]):not(.brand-img) {
  border-radius: var(--r-xs);
}

/* ═════════════════════════════════════════════════════════════════
 * SUMMARY KEYS in modals (Confirm Bulk Purchase, etc.)
 * ═════════════════════════════════════════════════════════════════ */
.summaryKey {
  font-size: var(--fs-2xs);
  color: var(--tx-3);
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}
.summaryValue {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--tx-1);
}

/* ═════════════════════════════════════════════════════════════════
 * UNIVERSAL CARD GRID GAP REFINEMENTS
 * ═════════════════════════════════════════════════════════════════ */
@media (min-width: 980px) {
  .grid { gap: var(--sp-4); }
}

/* ═════════════════════════════════════════════════════════════════
 * iOS SAFE-AREA INSET TWEAKS
 * ═════════════════════════════════════════════════════════════════ */
@supports (padding: max(0px)) {
  .wrap {
    padding-bottom: max(calc(var(--sp-6) + 64px), env(safe-area-inset-bottom));
  }
}

/* ═════════════════════════════════════════════════════════════════
 * DRAWER NAV — make it visually consistent across both flat links
 * and grouped (collapsible) sections
 * ═════════════════════════════════════════════════════════════════ */
.drawerNav .navSub a {
  padding-left: var(--sp-5);   /* indent sub-items */
}

/* ═════════════════════════════════════════════════════════════════
 * CARD SHADOW LIFT ON FOCUS — interactive cards
 * ═════════════════════════════════════════════════════════════════ */
.card[tabindex]:focus-visible,
.card[role="button"]:focus-visible {
  outline: none;
  border-color: var(--ac-border);
  box-shadow: var(--ac-glow);
}

/* ═════════════════════════════════════════════════════════════════
 * SUBMIT BUTTON DEFAULT IN AUTH/SETTINGS FORMS
 * (forms with no .btn class on the submit button — make them
 * still look reasonable)
 * ═════════════════════════════════════════════════════════════════ */
form button[type="submit"]:not(.btn) {
  background: linear-gradient(180deg, var(--ac-hover) 0%, var(--ac-solid) 100%);
  border: 1px solid var(--ac-solid);
  color: #fff;
  font-weight: 700;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  padding: 9px 16px;
  border-radius: var(--r-sm);
  cursor: pointer;
  box-shadow: 0 1px 0 rgba(255,255,255,0.15) inset, 0 2px 8px rgba(99, 102, 241, 0.30);
}
form button[type="submit"]:not(.btn):hover {
  background: linear-gradient(180deg, var(--ac), var(--ac-hover));
}

/* ═════════════════════════════════════════════════════════════════
 * VIEW: AI CONVERSATION (chat bubble layout)
 * ═════════════════════════════════════════════════════════════════ */
.aiChatMsg {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-1);
  background: var(--ink-1);
  margin-bottom: var(--sp-2);
  font-size: var(--fs-md);
  line-height: 1.55;
}
.aiChatMsg.user {
  background: var(--ac-bg-2);
  border-color: var(--ac-border);
}
.aiChatMsg.assistant {
  background: var(--ink-1);
}

/* ═════════════════════════════════════════════════════════════════
 * NAV CHIP — settings section chip nav (sticky)
 * Already styled above; just ensure scroll snap behavior
 * ═════════════════════════════════════════════════════════════════ */
.settingsNav {
  scroll-snap-type: x proximity;
}
.settingsNav .chip {
  scroll-snap-align: start;
}

/* ═════════════════════════════════════════════════════════════════
 * BUTTON LOADING STATE (for async actions like save)
 * Markup convention: .btn.loading; we just show the spinner +
 * dim the label.
 * ═════════════════════════════════════════════════════════════════ */
.btn.loading {
  pointer-events: none;
  opacity: 0.7;
}
.btn.loading::before {
  content: "";
  display: inline-block;
  width: 12px; height: 12px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: var(--r-pill);
  animation: spin 0.8s linear infinite;
  margin-right: 6px;
  vertical-align: -2px;
  opacity: 0.7;
}

/* ═════════════════════════════════════════════════════════════════
 * FINAL: subtle scroll-margin so anchor jumps inside Settings
 * leave room above the sticky chip nav.
 * ═════════════════════════════════════════════════════════════════ */
.secCard,
[id^="sec"] {
  scroll-margin-top: 120px;
}

/* ═════════════════════════════════════════════════════════════════
 * CARD-WITH-OWNER-ONLY-GATE — visual indicator (owner badge)
 * Mark sections that require owner role with a small accent
 * indicator. Pattern: classnames already use .ownerOnly elsewhere.
 * ═════════════════════════════════════════════════════════════════ */
.ownerOnly .secHead h3::after,
.secCard.ownerOnly .secHead h3::after {
  content: "OWNER";
  display: inline-block;
  margin-left: var(--sp-2);
  padding: 1px 6px;
  border-radius: var(--r-xs);
  background: var(--ac-bg);
  border: 1px solid var(--ac-border);
  color: var(--ac);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  vertical-align: middle;
  text-transform: uppercase;
}

/* ═════════════════════════════════════════════════════════════════
 * REMAINING CLASS PATTERNS (deductions, pricing agent rows)
 * ═════════════════════════════════════════════════════════════════ */

/* Deductions list columns (Deductions page). dedAmt and dedWhy are
 * <input> elements; dedProfit is a <td> text cell. */
input.dedAmt {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: right;
  width: 100px;
  padding: 6px 8px;
}
td.dedProfit, .dedProfit {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: right;
}
input.dedWhy {
  font-size: var(--fs-sm);
  padding: 6px 10px;
  width: 100%;
  min-width: 180px;
}

/* Pricing agent row checkbox cell */
.paRowCheck {
  width: 16px; height: 16px;
}

/* ═════════════════════════════════════════════════════════════════
 * LAYOUT NORMALIZATIONS
 * ═════════════════════════════════════════════════════════════════ */

/* Trailing labels in field rows should not steal width */
label.inline {
  font-size: var(--fs-sm);
  color: var(--tx-2);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
}

/* Generic .label utility class */
.label {
  font-size: var(--fs-2xs);
  color: var(--tx-3);
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

/* ═════════════════════════════════════════════════════════════════
 * UTILITY CLASSES that show up in inline render code
 * ═════════════════════════════════════════════════════════════════ */
.link {
  color: var(--ac);
  text-decoration: none;
  font-weight: 500;
}
.link:hover {
  color: var(--ac-hover);
  text-decoration: underline;
}

/* ═════════════════════════════════════════════════════════════════
 * NOTIFICATION TYPE BADGES (sync / warn / error / info)
 * ═════════════════════════════════════════════════════════════════ */
.notifType {
  display: inline-block;
  padding: 1px 6px;
  border-radius: var(--r-xs);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* ═════════════════════════════════════════════════════════════════
 * KEEP STATE ALIGNED — last micro fixes
 * ═════════════════════════════════════════════════════════════════ */

/* Make the .field's textarea pick up the mono font for code-like input */
.field textarea[data-mono],
textarea.mono {
  font-family: var(--font-mono);
}

/* The "Suggest Price" lookup output panel — base layout only.
 * Level coloring (bad / warn / good) comes from the .notice.<level>
 * classes that the host JS toggles. Don't set border-left-color here
 * because it'd override .notice.bad / .notice.warn left-accent. */
#lookupOut {
  background: var(--ink-1);
  border: 1px solid var(--line-1);
  border-left-width: 3px;
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-4);
  margin-top: var(--sp-3);
}
/* Re-state level coloring at #lookupOut specificity so .notice.bad
 * etc. wins over our base border-left rule. */
#lookupOut.notice { border-left-color: var(--ac); }
#lookupOut.notice.good,
#lookupOut.notice.ok { border-left-color: var(--good); }
#lookupOut.notice.bad { border-left-color: var(--bad); }
#lookupOut.notice.warn { border-left-color: var(--warn); }

/* Suggest meta line (small grey text under Suggest Price) */
#suggestMeta {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--tx-3);
  margin-top: 4px;
}

/* ═════════════════════════════════════════════════════════════════
 * DRAWER NAV — full edge tap area on iOS
 * ═════════════════════════════════════════════════════════════════ */
.drawer .drawerNav a {
  -webkit-tap-highlight-color: transparent;
}

/* ═════════════════════════════════════════════════════════════════
 * BANK TX TABLE / ACCOUNTING — long memo column wraps
 * ═════════════════════════════════════════════════════════════════ */
#acctTxBody td:nth-child(3),
#acctTxBody td.memo {
  white-space: normal;
  max-width: 280px;
  font-size: var(--fs-xs);
  color: var(--tx-2);
}

/* ═════════════════════════════════════════════════════════════════
 * SIGNATURE PAD (vendor master agreement)
 * ═════════════════════════════════════════════════════════════════ */
canvas.signature,
.signaturePad canvas {
  border-radius: var(--r-md);
  border: 1px dashed var(--line-3);
  background: rgba(255,255,255,0.04);
}

/* ═════════════════════════════════════════════════════════════════
 * CASH LEDGER GRID
 * ═════════════════════════════════════════════════════════════════ */
.cashLedgerGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--sp-3);
  align-items: end;
}

/* ═════════════════════════════════════════════════════════════════
 * TAB-STYLE BUTTON GROUP (when buttons are presented as tabs but
 * use .btn class)
 * ═════════════════════════════════════════════════════════════════ */
.tabRow {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--line-1);
}
.tabRow .btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  color: var(--tx-3);
  padding: var(--sp-3) var(--sp-4);
}
.tabRow .btn:hover {
  background: transparent;
  color: var(--tx-2);
}
.tabRow .btn.active,
.tabRow .btn.primary {
  background: transparent;
  border-color: var(--ac);
  color: var(--tx-1);
  box-shadow: none;
}

/* ═════════════════════════════════════════════════════════════════
 * SETTINGS SHELL + SECTIONS GRID
 *
 * The Settings page wraps everything in `.card.settingsShell` and the
 * grid container is `.settingsSections`. Each section is a `.secCard`
 * that may also carry `.span2` to take two columns on desktop.
 * ═════════════════════════════════════════════════════════════════ */

.card.settingsShell {
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
}
.card.settingsShell > .hd {
  background: transparent;
  border: 0;
  padding: var(--sp-4) var(--sp-5) var(--sp-3);
}
.card.settingsShell > .hd h2 {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}
.card.settingsShell > .bd {
  padding: 0 var(--sp-5) var(--sp-5);
}

.settingsSections {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-4);
}
.settingsSections > .secCard.span2 {
  grid-column: 1 / -1;
}
@media (max-width: 900px) {
  .settingsSections {
    grid-template-columns: 1fr;
    gap: var(--sp-3);
  }
  .settingsSections > .secCard.span2 {
    grid-column: 1;
  }
  .card.settingsShell > .hd { padding: var(--sp-3) var(--sp-4) var(--sp-2); }
  .card.settingsShell > .bd { padding: 0 var(--sp-3) var(--sp-3); }
}

/* Generic grid-column-span utility */
.span2 { grid-column: span 2; }

/* ═════════════════════════════════════════════════════════════════
 * BULK INTAKE — action rows + cell containers + modal action rows
 * ═════════════════════════════════════════════════════════════════ */

.bulkActionRow {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.bulkActionRow .btn {
  padding: 4px 8px;
  font-size: var(--fs-xs);
}
.bulkModalActionRow {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}
.bulkModalActionRow .btn {
  padding: 6px 10px;
  font-size: var(--fs-xs);
}
.bulkMdmCell {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 22px;
}

/* ═════════════════════════════════════════════════════════════════
 * STATUS FIELD / STATUS PANEL / STATUS SUB
 *
 * Pattern used inside bulk-intake edit modal: a `.field` flagged with
 * `.statusField` whose body is a `.statusPanel` (badge + small sub).
 * ═════════════════════════════════════════════════════════════════ */

.field.statusField .statusPanel {
  background: var(--ink-1);
  border: 1px solid var(--line-1);
  border-radius: var(--r-md);
  padding: var(--sp-2) var(--sp-3);
  min-height: 38px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
}
.statusSub {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  line-height: 1.3;
}

/* ═════════════════════════════════════════════════════════════════
 * FORM ROW — generic row that wraps a set of `.field`s
 * ═════════════════════════════════════════════════════════════════ */

.row.formRow {
  display: flex;
  gap: var(--sp-3);
  flex-wrap: wrap;
  align-items: flex-end;
}
.row.formRow > .field { flex: 1 1 220px; min-width: 200px; }

/* ═════════════════════════════════════════════════════════════════
 * ACCOUNTING EXPENSE FORM GRID
 *
 * The "Add Expense" form on the Accounting page uses
 * .acctFormGrid (date / amount / category / memo). Memo gets a wider
 * track so the placeholder is readable.
 * ═════════════════════════════════════════════════════════════════ */

.acctFormGrid {
  display: grid;
  grid-template-columns: minmax(140px, 1fr) minmax(120px, 1fr) minmax(160px, 1fr) minmax(220px, 2fr);
  gap: var(--sp-3);
  align-items: end;
}
.acctFormGrid .field.acctMemo {
  /* Memo gets the most flexible slot. */
  min-width: 0;
}
@media (max-width: 760px) {
  .acctFormGrid {
    grid-template-columns: 1fr 1fr;
  }
  .acctFormGrid .field.acctMemo {
    grid-column: 1 / -1;
  }
}
@media (max-width: 420px) {
  .acctFormGrid {
    grid-template-columns: 1fr;
  }
  .acctFormGrid .field.acctMemo {
    grid-column: 1;
  }
}

/* ═════════════════════════════════════════════════════════════════
 * HORIZONTAL SCROLL ROW — used on dense button strips on mobile
 *
 * `.row.hScroll` becomes horizontally-scrollable on small screens so
 * a long line of action buttons doesn't wrap into a 3-row mess.
 * ═════════════════════════════════════════════════════════════════ */

.row.hScroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  scrollbar-color: var(--line-3) transparent;
  padding-bottom: 2px;
  margin-right: calc(-1 * var(--sp-3));
  padding-right: var(--sp-3);
}
.row.hScroll::-webkit-scrollbar { height: 6px; }
.row.hScroll::-webkit-scrollbar-thumb {
  background: var(--line-3);
  border-radius: 999px;
}
.row.hScroll > * { flex: 0 0 auto; }

/* ═════════════════════════════════════════════════════════════════
 * INV REMOVE / SALE SEL — small inline-cell controls
 * ═════════════════════════════════════════════════════════════════ */

.btn.invRemove {
  padding: 3px 8px;
  font-size: 11px;
}
input.saleSel {
  width: 16px;
  height: 16px;
}

/* ═════════════════════════════════════════════════════════════════
 * NUM column right-align inside `.docItems` is already handled by
 * the legacy invoice/receipt block in index.html. Outside the print
 * doc context, plain `.num` should be right-aligned + mono-tabular
 * so totals columns line up.
 * ═════════════════════════════════════════════════════════════════ */

td.num, th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ═════════════════════════════════════════════════════════════════
 * OWNER-ONLY ROW BADGE — when an entire .row, .field, or button is
 * wrapped in .ownerOnly, give it a faint left rule so admins know
 * at a glance this control is privileged.
 * ═════════════════════════════════════════════════════════════════ */

.row.ownerOnly,
.field.ownerOnly,
button.ownerOnly,
.btn.ownerOnly {
  position: relative;
}
.row.ownerOnly::before,
.field.ownerOnly::before {
  content: "";
  position: absolute;
  left: calc(-1 * var(--sp-2));
  top: 4px;
  bottom: 4px;
  width: 2px;
  background: linear-gradient(180deg, var(--ac-solid), #8b5cf6);
  border-radius: 999px;
  opacity: 0.55;
  pointer-events: none;
}

/* ═════════════════════════════════════════════════════════════════
 * SECTION BODY — first-row spacing tweak
 *
 * `.secBody > .row:first-child` shouldn't have a top margin so the
 * card body doesn't get a phantom gap.
 * ═════════════════════════════════════════════════════════════════ */
.secBody > .row:first-child,
.secBody > .field:first-child,
.secBody > .grid:first-child {
  margin-top: 0;
}
.secBody > .row + .row,
.secBody > .field + .field {
  margin-top: var(--sp-2);
}

/* ═════════════════════════════════════════════════════════════════
 * INVENTORY EDIT — `.edActions` row aligns status fields + buttons
 * ═════════════════════════════════════════════════════════════════ */
.row.edActions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  align-items: flex-end;
}
.row.edActions .btn {
  align-self: flex-end;
  height: 38px;
}
.row.edActions .small.muted {
  align-self: center;
  font-size: var(--fs-xs);
}

/* ═════════════════════════════════════════════════════════════════
 * INVENTORY PICKER + MASS-CHOICE CHECKBOXES
 * ═════════════════════════════════════════════════════════════════ */
input.invPick,
input.mcChk {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

/* ═════════════════════════════════════════════════════════════════
 * RECEIPT ATTACHMENT ROW — long file-input row inside a doc form
 * ═════════════════════════════════════════════════════════════════ */
.row.receiptRow {
  background: var(--ink-1);
  border: 1px solid var(--line-1);
  border-radius: var(--r-md);
  padding: var(--sp-3);
  gap: var(--sp-2) var(--sp-3);
}
.row.receiptRow > .field input[type="file"] {
  border-color: var(--line-2);
}

/* ═════════════════════════════════════════════════════════════════
 * DOC TABLES (invoice + receipt structures rendered into doc views)
 *
 * These are LIGHT-themed when printed (see index.html structural CSS),
 * but inside the dark POS view they should match our other tables.
 * ═════════════════════════════════════════════════════════════════ */
.docTable {
  width: 100%;
  border-collapse: collapse;
}
.docTable thead th {
  text-align: left;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--tx-3);
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line-2);
  background: var(--ink-1);
}
.docTable tbody td {
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--line-1);
  font-size: var(--fs-sm);
  vertical-align: middle;
}
.docTable tbody tr:hover {
  background: rgba(99, 102, 241, 0.04);
}
.docTable input,
.docTable select {
  height: 32px;
  padding: 4px 8px;
  font-size: var(--fs-sm);
}
/* Print mode: revert .docTable to the light-themed legacy look.
 * The print stylesheet in index.html already covers the surrounding
 * docPaper / docHeader chrome; this just keeps our dark-theme rules
 * from leaking into the printed page. */
@media print {
  .docTable thead th,
  .docTable tbody td {
    background: #fff;
    color: #111;
    border-color: rgba(0, 0, 0, 0.12);
  }
  .docTable tbody tr:hover { background: transparent; }
}

/* ═════════════════════════════════════════════════════════════════
 * LAYOUT SHELL UTILITIES — 2026-05-26 redesign
 *
 * These primitives drive the new page layouts (Home, Inventory, Bulk
 * Intake, Sales, Accounting, Tax, Settings). They REPLACE the old
 * "vertical stack of .row > .field" pattern that wasted screen space.
 *
 * Pattern names match how callers use them:
 *   .pageHd      — sticky page header (title + primary actions)
 *   .kpiStrip    — sticky horizontal KPI ribbon (replaces .kpi grid)
 *   .subnav      — sticky sub-tab strip under pageHd
 *   .formGrid    — compact CSS Grid for paired fields (replaces .row)
 *   .split       — 2-col split (sidebar + main)
 *   .actionBar   — sticky bottom action toolbar
 *   .overflowMenu— kebab popover for table-row actions
 *   .segFilter   — pill-style segmented filter group
 *   .compactCard — card with tighter padding
 * ═════════════════════════════════════════════════════════════════ */

/* --- Sticky page header --------------------------------------- */
.pageHd {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  margin: 0 0 var(--sp-3) 0;
  background: linear-gradient(180deg, rgba(11, 16, 32, 0.92), rgba(11, 16, 32, 0.78));
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line-1);
}
.pageHd .pageTitle {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.pageHd .pageTitle h1 {
  margin: 0;
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.012em;
  color: var(--tx-1);
}
.pageHd .pageTitle .sub {
  font-size: var(--fs-sm);
  color: var(--tx-3);
}
.pageHd .pageActs {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

/* --- Sticky KPI ribbon ---------------------------------------- */
.kpiStrip {
  position: sticky;
  top: 52px;
  z-index: 25;
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4);
  margin: 0 0 var(--sp-3) 0;
  overflow-x: auto;
  scrollbar-width: thin;
  background: linear-gradient(180deg, rgba(5, 7, 13, 0.86), rgba(5, 7, 13, 0.72));
  backdrop-filter: saturate(140%) blur(8px);
  -webkit-backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--line-0);
  scroll-snap-type: x mandatory;
}
.kpiStrip::-webkit-scrollbar { height: 4px; }
.kpiStrip::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 2px; }
.kpiStrip .kBox {
  flex: 0 0 calc(33.333% - 6px);
  min-width: 0;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--line-1);
  background: linear-gradient(180deg, var(--ink-warm), var(--ink-cool));
  border-radius: var(--r-md);
  box-shadow: var(--shadow-key);
}
@media (max-width: 480px) {
  .kpiStrip .kBox { flex: 0 0 calc(50% - 4px); }
}
.kpiStrip .kBox .v {
  font-family: var(--font-mono);
  font-feature-settings: "tnum", "ss01";
  font-size: var(--fs-2xl);
  font-weight: 700;
  color: var(--tx-1);
  letter-spacing: -0.02em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.kpiStrip .kBox .t {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  /* Allow labels to wrap to 2 lines so words don't get truncated
   * when KPI tiles are narrow (33% / 50% widths on mobile). */
  white-space: normal;
  line-height: 1.25;
  word-break: normal;
  overflow-wrap: break-word;
}
.kpiStrip .kBox.pos .v { color: var(--pos); }
.kpiStrip .kBox.warn .v { color: var(--warn); }
.kpiStrip .kBox.bad .v { color: var(--bad); }
@media (min-width: 980px) {
  .kpiStrip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    overflow: visible;
  }
  .kpiStrip .kBox { min-width: 0; }
}

/* --- Sticky sub-nav (horizontal tab strip under pageHd) ------- */
.subnav {
  position: sticky;
  top: 52px;
  z-index: 24;
  display: flex;
  gap: 2px;
  padding: 0 var(--sp-4);
  margin: 0 0 var(--sp-3) 0;
  overflow-x: auto;
  scrollbar-width: none;
  background: rgba(5, 7, 13, 0.82);
  backdrop-filter: saturate(140%) blur(8px);
  -webkit-backdrop-filter: saturate(140%) blur(8px);
  border-bottom: 1px solid var(--line-1);
}
.subnav::-webkit-scrollbar { display: none; }
.subnav .snBtn {
  flex: 0 0 auto;
  padding: var(--sp-3) var(--sp-3);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--tx-2);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 600;
  cursor: pointer;
  transition: color var(--tx-fast), border-color var(--tx-fast);
}
.subnav .snBtn:hover { color: var(--tx-1); }
.subnav .snBtn.active {
  color: var(--ac);
  border-bottom-color: var(--ac-solid);
}
.subnav .snBtn .badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: var(--fs-2xs);
  background: var(--ac-bg);
  color: var(--ac);
  border-radius: var(--r-pill);
  vertical-align: middle;
}

/* --- Compact form grid (replaces .row of .field) -------------- */
/* The KEY layout primitive. CSS Grid auto-fit means two compact
 * fields fit on a 360px iPhone and four fit on desktop without any
 * media query gymnastics. Override .field's 220px min so we don't
 * fall back to the old wrap-everything-vertical behavior. */
.formGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sp-3);
  align-items: start;
}
.formGrid > .field {
  min-width: 0;
  flex: initial;
}
.formGrid > .field.span2 { grid-column: span 2; }
.formGrid > .field.spanFull { grid-column: 1 / -1; }
@media (min-width: 720px) {
  .formGrid { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
}
@media (min-width: 1100px) {
  .formGrid.tight { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}

/* --- Two-column split layout (sidebar + main) ----------------- */
.split {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-4);
  align-items: start;
}
@media (min-width: 980px) {
  .split { grid-template-columns: minmax(280px, 0.7fr) 1.3fr; }
  .split.right { grid-template-columns: 1.3fr minmax(280px, 0.7fr); }
  .split.even { grid-template-columns: 1fr 1fr; }
  .split.thin { grid-template-columns: minmax(220px, 240px) 1fr; }
}
.split > .splitMain { min-width: 0; }
.split > .splitSide { min-width: 0; }

/* ─────────────────────────────────────────────────────────────────
 * GLOBAL OVERFLOW HARDENING (added 2026-05-28 r53)
 *
 * Goal: no card / modal / drawer / table on PC at 1366–1920px
 * should push content past the viewport with no visible scrollbar.
 * Bulk-fix targets — based on operator-reported overflow spots:
 *
 *   * Long URLs / notes / IMEIs in card bodies can blow out a flex
 *     parent because flex children have implicit min-width:auto.
 *     Force them shrinkable.
 *   * Modal bodies need overflow-wrap so a long string can't push
 *     the modal wider than max-width.
 *   * Card bodies and notice blocks need the same.
 *   * Long words inside .small / .muted / .mono-but-not-cell get
 *     overflow-wrap so they don't escape their container.
 * ───────────────────────────────────────────────────────────────── */
.card, .card > .bd, .modal, #modalBody, .drawer, .notice, .kvList,
.kvItem, .kvItem .v, .formGrid, .formGrid > .field {
  min-width: 0;
}
/* Cell content that's NOT explicitly mono (mono cells stay nowrap so
 * 15-digit IMEIs/serials don't get chopped mid-number). Wraps at
 * spaces only — never mid-word — so the inventory carrier text or
 * vendor names stay readable. */
.modal .kvItem .v:not(.mono),
.notice:not(.mono),
.card .bd > p,
.card .bd > div > .small {
  overflow-wrap: break-word;
}
/* Any container the operator can drop arbitrary text into (notes,
 * descriptions) gets break-word so a 50-character URL or single
 * pasted token can't push the parent wider than the viewport. */
.notes, .desc, [data-overflow-safe="1"] {
  overflow-wrap: anywhere;
  word-break: break-word;
}

/* --- Sticky bottom action bar --------------------------------- */
.actionBar {
  position: sticky;
  bottom: 0;
  z-index: 28;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4);
  margin: var(--sp-3) calc(var(--sp-4) * -1) 0;
  background: linear-gradient(0deg, rgba(11, 16, 32, 0.96), rgba(11, 16, 32, 0.82));
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-top: 1px solid var(--line-1);
}
.actionBar .grow { flex: 1; min-width: 0; }
.actionBar .meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-size: var(--fs-sm);
  color: var(--tx-2);
}
.actionBar .meta .big {
  font-family: var(--font-mono);
  font-feature-settings: "tnum";
  font-size: var(--fs-xl);
  font-weight: 700;
  color: var(--tx-1);
}
/* Lift above bottom nav on mobile */
@media (max-width: 860px) {
  .actionBar { bottom: 60px; }
}

/* --- Overflow menu (kebab popover for row actions) ------------ */
.overflowMenu {
  position: relative;
  display: inline-flex;
}
.overflowMenu > .ovBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--line-1);
  border-radius: var(--r-sm);
  color: var(--tx-2);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.overflowMenu > .ovBtn:hover {
  background: var(--ink-2);
  color: var(--tx-1);
  border-color: var(--line-2);
}
.overflowMenu > .ovPop {
  /* position:fixed so ancestor overflow:auto (sticky table wrappers)
   * doesn't clip the popover. Coordinates are set in JS by
   * src/lib/overflow-menu.mjs at open time. */
  position: fixed;
  top: 0;
  left: 0;
  min-width: 180px;
  display: none;
  flex-direction: column;
  padding: 4px;
  background: var(--ink-3);
  border: 1px solid var(--line-2);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-2);
  z-index: 9999;
}
.overflowMenu.open > .ovPop { display: flex; }
.overflowMenu > .ovPop button {
  text-align: left;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
  color: var(--tx-1);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  cursor: pointer;
}
.overflowMenu > .ovPop button:hover { background: var(--ink-2); }
.overflowMenu > .ovPop button.danger { color: var(--bad); }
.overflowMenu > .ovPop hr {
  border: 0;
  border-top: 1px solid var(--line-1);
  margin: 4px 2px;
}

/* --- Segment filter (pill group) ------------------------------ */
.segFilter {
  display: inline-flex;
  padding: 2px;
  background: var(--ink-2);
  border: 1px solid var(--line-1);
  border-radius: var(--r-pill);
  gap: 0;
}
.segFilter .segOpt {
  padding: 6px 14px;
  background: transparent;
  border: 0;
  border-radius: var(--r-pill);
  color: var(--tx-2);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--tx-fast), color var(--tx-fast);
}
.segFilter .segOpt:hover { color: var(--tx-1); }
.segFilter .segOpt.active {
  background: var(--ac-solid);
  color: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.30);
}

/* --- Compact card (tighter padding) --------------------------- */
.compactCard .bd { padding: var(--sp-3); }
.compactCard .hd { padding: var(--sp-2) var(--sp-3); }

/* --- Search bar (input with icon) ----------------------------- */
.searchBar {
  position: relative;
  flex: 1;
  min-width: 200px;
}
.searchBar input {
  width: 100%;
  padding-left: 36px;
}
.searchBar::before {
  content: "⌕";
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--tx-3);
  font-size: 16px;
  pointer-events: none;
}

/* --- Stacked metric (for KPI inside split sidebar) ------------ */
.metricList {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.metricList .met {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--ink-2);
  border: 1px solid var(--line-1);
  border-radius: var(--r-md);
}
.metricList .met .lbl {
  font-size: var(--fs-sm);
  color: var(--tx-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.metricList .met .val {
  font-family: var(--font-mono);
  font-feature-settings: "tnum";
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--tx-1);
}
.metricList .met.pos .val { color: var(--pos); }
.metricList .met.warn .val { color: var(--warn); }
.metricList .met.bad .val { color: var(--bad); }

/* --- Empty / placeholder cell --------------------------------- */
.tdMuted {
  color: var(--tx-3);
  font-style: italic;
}

/* --- Field hint (helper text below input) --------------------- */
.fieldHint {
  font-size: var(--fs-xs);
  color: var(--tx-3);
  margin-top: 2px;
  line-height: 1.4;
}

/* --- Icon button (square, 32px) ------------------------------- */
.btnIcon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--line-1);
  border-radius: var(--r-sm);
  color: var(--tx-2);
  font-size: 14px;
  cursor: pointer;
}
.btnIcon:hover {
  background: var(--ink-2);
  color: var(--tx-1);
  border-color: var(--line-2);
}

/* --- Card with thin top accent (status color) ----------------- */
.accentTop { position: relative; }
.accentTop::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--ac-solid);
  border-top-left-radius: var(--r-lg);
  border-top-right-radius: var(--r-lg);
}
.accentTop.pos::before { background: var(--pos-solid); }
.accentTop.warn::before { background: var(--warn-solid); }
.accentTop.bad::before { background: var(--bad-solid); }

/* --- Sticky table header (table-as-card) ---------------------- */
/* Sticky table thead — needs the wrapper to be the scroll container,
 * otherwise position:sticky sticks to the page viewport (not the
 * card) AND the table overflows horizontally past the page edge
 * forcing a window-level horizontal scrollbar. Setting overflow:auto
 * here keeps oversized tables contained inside the card region. */
.stickyHead {
  overflow: auto;
}
.stickyHead thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--ink-1);
}

/* Inventory table on Windows laptops (1366×768 is the most common):
 * 10 columns can overflow the viewport. Hide the lower-priority
 * Comp Avg + MDM columns up through 1280px so the table fits there,
 * but show ALL columns on phones too (operator pinch-zooms to read
 * them — they explicitly asked for everything visible). The cutoff
 * is below the mobile range so hide doesn't fire on phones.
 * 720px and narrower → all 10 columns rendered, pinch-zoom to read. */
@media (min-width: 721px) and (max-width: 1280px) {
  .invTable .colCompAvg,
  .invTable .colMdm { display: none; }
}

/* Invoice Builder items table: all 8 columns stay visible at every
 * width — operator wants to see IMEI / Description / Condition /
 * Carrier / Activated / Cost / Sale Price / Remove without anything
 * disappearing. The .tableWrap around the table scrolls horizontally
 * inside its card so a wide table on a narrow split-view never
 * pushes the page or compacts cells into vertical word-stacks. */

/* Mobile body padding only — DON'T touch table widths or cell wrap.
 * Operator wants the full table visible at its natural width so they
 * can pinch-zoom to see all columns. Earlier attempts (cell wrap,
 * column hide, force 100% width) crushed the model column into a
 * vertical word-stack — exactly what they didn't want. The viewport
 * tag explicitly allows pinch-zoom down to minimum-scale=0.25 so
 * even a wide bulk intake table fits within a single pinch out. */
/* (mobile button padding handled above in the ≤720px block; no
 * second override needed) */

/* ─────────────────────────────────────────────────────────────────
 * Scanner modal — escape the bottom-sheet default so the camera
 * viewport gets the full screen height. Operator needs to look at
 * the camera viewfinder, not a 50%-tall bottom drawer.
 * ───────────────────────────────────────────────────────────────── */
.modalOverlay.scannerModal {
  align-items: center !important;
  padding: 0 !important;
}
.modalOverlay.scannerModal .modal {
  width: 100%;
  height: 100dvh;
  max-height: 100dvh;
  border-radius: 0;
  border: 0;
  padding: var(--sp-3) var(--sp-4);
  display: flex;
  flex-direction: column;
}
.modalOverlay.scannerModal .modal::before { display: none; }
.modalOverlay.scannerModal .modalHead {
  flex: 0 0 auto;
  padding-bottom: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.modalOverlay.scannerModal #modalBody {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* The .scanFrame in scanner-modal mode owns its own height (60dvh
 * mobile, capped). Letting it flex-grow caused the box to stretch
 * way past the video's natural size — and since index.html's base
 * rule fixes the video at height:320px, the gap below the video
 * was just dark navy, with the scan-box HUD floating in mid-air.
 * Fixed height + absolutely-positioned video that fills the frame
 * keeps the camera viewport and the HUD glued together. */
.modalOverlay.scannerModal .scanFrame {
  flex: 0 0 auto;
  position: relative;
  width: 100%;
  height: 60dvh;
  max-height: 60dvh;
  overflow: hidden;
  transition: height 180ms ease, max-height 180ms ease;
}
/* When the operator has taken a photo and we're showing the photo
 * preview + detected IMEI buttons, shrink the live camera frame so
 * the results section is visible without scrolling. The class is
 * added by the file-input change handler in inline.js and removed
 * by stopScanner. */
.modalOverlay.scannerModal .scanFrame.photoMode {
  height: 26dvh;
  max-height: 26dvh;
}
@media (min-width: 721px) {
  .modalOverlay.scannerModal .scanFrame.photoMode {
    height: 32dvh;
    max-height: 320px;
  }
}
.modalOverlay.scannerModal .scanFrame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* html5-qrcode mount. The library injects its own <video> + <canvas>
 * + viewfinder overlay inside this div. Without explicit sizing it
 * collapses to content height (whatever its internal viewfinder
 * computes), leaving the scanFrame mostly empty navy below. Force
 * it to fill the frame so the camera + the library's corner-bracket
 * overlay land where the operator expects them. */
.modalOverlay.scannerModal .scanFrame #scanH5 {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.modalOverlay.scannerModal .scanFrame #scanH5 video,
.modalOverlay.scannerModal .scanFrame #scanH5 canvas {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  position: absolute;
  inset: 0;
}
@media (min-width: 721px) {
  .modalOverlay.scannerModal .scanFrame {
    height: 64dvh;
    max-height: 580px;
  }
}
/* Wider screens — keep it a centered roomy modal instead of fully
 * full-screen, so it's not visually overwhelming on a laptop. */
@media (min-width: 721px) {
  .modalOverlay.scannerModal .modal {
    width: min(620px, 96vw);
    height: min(86dvh, 760px);
    max-height: 86dvh;
    border-radius: var(--r-xl);
    border: 1px solid var(--line-2);
  }
}
