/* Inter — a clean, modern typeface used across professional admin/SaaS
   dashboards (Stripe, Linear, Notion, etc.). Loading it here (rather than
   in every HTML <head>) means one edit upgrades every page's type at once.
   Falls back to the platform's own system font instantly if the request is
   ever slow/blocked, so there's no layout flash or dependency risk. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

:root {
    /* Brand */
    --primary: #c62839;
    --primary-dark: #96202e;
    --primary-light: #fdecee;
    --primary-50: #fbf1f2;

    /* Neutrals. --ink/--ink-2/--ink-3 are the app's fixed dark-navy brand
       chrome (topbar background, login hero, toast) and deliberately do NOT
       change between light/dark mode — they're already dark. --heading is
       the separate, theme-aware token for dark TEXT on a light card (page
       titles, card headers, emphasized figures); it equals --ink in light
       mode (so nothing looks different today) but flips to a light color
       in dark mode so those same headings stay readable on a dark card. */
    --ink: #141b29;
    --ink-2: #1d2635;
    --ink-3: #263042;
    --heading: var(--ink);
    --bg: #f3f4f7;
    --surface: #ffffff;
    --border: #e3e6ec;
    --border-strong: #cfd4dd;
    --text: #202634;
    --muted: #69707f;
    --muted-2: #8b93a3;

    /* Status */
    --success: #1e9d5b;
    --success-light: #e7f8ee;
    --danger: #c53030;
    --danger-light: #fdecea;
    --warning: #b7791f;
    --warning-light: #fdf3e1;

    /* Scale */
    --radius-sm: 7px;
    --radius: 11px;
    --radius-lg: 16px;
    --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.06);
    --shadow-sm: 0 1px 3px rgba(16, 24, 40, 0.07), 0 1px 2px rgba(16, 24, 40, 0.04);
    --shadow: 0 4px 14px rgba(16, 24, 40, 0.08), 0 1px 3px rgba(16, 24, 40, 0.05);
    --shadow-lg: 0 16px 40px rgba(16, 24, 40, 0.16);
    --ease: 160ms cubic-bezier(.4, 0, .2, 1);
    --font: 'Inter', -apple-system, "Segoe UI", "Segoe UI Variable", Roboto, Helvetica, Arial, sans-serif;
}

/* ===== Dark theme — toggled by js/api.js (theme-toggle button in the
   topbar), persisted per browser in localStorage, defaults to light. Every
   page already styles itself entirely through the variables above, so this
   one block is the whole theme: no per-page CSS needed. Brand chrome
   (--ink/--ink-2/--ink-3, the topbar/login/toast) is intentionally left
   alone — see the note above. Printing always forces the light palette
   regardless of this (see the @media print override near the bottom), so
   invoices and reports never come out dark. */
:root[data-theme="dark"] {
    --primary: #e24f5f;
    --primary-dark: #c62839;
    --primary-light: #3a1a1f;
    --primary-50: #2a1418;
    --heading: #eef0f5;
    --bg: #0f1216;
    --surface: #1a1e25;
    --border: #2b303a;
    --border-strong: #3b414d;
    --text: #dde1e8;
    --muted: #98a0b0;
    --muted-2: #767f90;
    --success: #35c07c;
    --success-light: #143324;
    --danger: #ef5a5a;
    --danger-light: #3a1a1a;
    --warning: #f0ad4e;
    --warning-light: #3a2c14;
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.25);
    --shadow: 0 4px 14px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
    --shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.5);
}

* { box-sizing: border-box; }

/* Compact mode: shrinking the root font-size scales every rem-based value
   in the app (headings, table text, input text, badges, etc.) down together
   in one place, instead of hand-tuning dozens of individual rules. Combined
   with the tightened px paddings/margins below (which don't scale off rem),
   this is what lets a typical screen fit without scrolling on both a phone
   and a laptop, rather than just shrinking text while leaving all the
   whitespace around it untouched. */
html { font-size: 13px; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }

/* Safety net: nothing on any page should ever be allowed to push the whole
   document wider than the viewport. Without this, a single too-wide element
   anywhere (a long unbroken line, a fixed-width table, etc.) makes the
   ENTIRE page scroll/zoom out horizontally on a phone — every other element
   on that page then renders shrunk down with blank space beside it, which is
   exactly what "lines getting out" and a narrow floating card look like on a
   real device even though nothing is individually broken. Elements that are
   MEANT to scroll horizontally (like .nav-main's overflow-x safety net, or
   a .card holding a wide table) still do — this only stops the outer page
   itself from doing it by accident. */
html, body { max-width: 100%; overflow-x: hidden; }

body {
    margin: 0;
    font-family: var(--font);
    font-feature-settings: "cv11", "ss01";
    background: var(--bg);
    color: var(--text);
    line-height: 1.35;
    /* Hidden by default so a protected page's full layout (topbar, nav,
       whatever form/table markup is in the HTML) never flashes on screen
       for the instant before requireSession() (js/api.js) finds out the
       visitor isn't actually logged in and sends them to login.html. This
       stylesheet loads before body is parsed, so the browser never paints
       body in its hidden state — revealPage() (js/api.js) sets it back to
       visible with an inline style (which always wins over this rule)
       once we actually know what to show: either a confirmed session, or
       login.html/db-settings.html, which have no session to wait on. */
    visibility: hidden;
}

::selection { background: var(--primary-light); color: var(--primary-dark); }

/* Slim, tasteful scrollbars (WebKit/Blink — no-op elsewhere) */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 20px; border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: var(--muted-2); }

a { color: var(--primary); }

/* ===== Topbar ===== */
.topbar {
    background: linear-gradient(180deg, var(--ink-2), var(--ink));
    color: #fff;
    padding: 6px 14px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
    position: relative;
    z-index: 30;
}
.topbar::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: -3px;
    height: 3px;
    background: linear-gradient(90deg, var(--primary), var(--primary-dark) 65%, transparent);
}
.topbar .brand { font-weight: 700; font-size: 1.08rem; display: flex; align-items: center; gap: 10px; letter-spacing: 0.01em; }
.topbar .brand-text::before {
    content: "";
    display: inline-block;
    width: 8px; height: 8px;
    border-radius: 2px;
    background: var(--primary);
    margin-right: 9px;
    vertical-align: middle;
    box-shadow: 0 0 0 3px rgba(198, 40, 57, 0.25);
}
.topbar .brand-logo { height: 30px; display: none; border-radius: 4px; }
.topbar .brand-logo ~ .brand-text::before { display: none; }
.topbar .user-info { font-size: 0.88rem; display: flex; gap: 12px; align-items: center; color: rgba(255,255,255,0.85); }
.topbar button {
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.22);
    color: #fff;
    padding: 7px 14px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.85rem;
    font-family: inherit;
    transition: background var(--ease), border-color var(--ease);
}
.topbar button:hover { background: rgba(255,255,255,0.16); border-color: rgba(255,255,255,0.4); }
.topbar a.back {
    color: #fff;
    text-decoration: none;
    font-size: 0.85rem;
    border: 1px solid rgba(255,255,255,0.22);
    padding: 7px 14px;
    border-radius: var(--radius-sm);
    transition: background var(--ease), border-color var(--ease);
}
.topbar a.back:hover { background: rgba(255,255,255,0.16); border-color: rgba(255,255,255,0.4); }

/* Top nav bar — Data Entry / Reports / All Branch Reports / Account
   Management / Utility, each a labelled button that drops its own menu,
   rendered by js/nav.js just under the topbar on every page except login.
   This is the classic menu-bar shape MobiSoft itself uses (click a
   top-level item, a list drops down under just that item, floating over
   the page) — see the 2026-09-30 note at the top of nav.js for why the
   brief icon-only/expand-below-the-bar design (2026-09-26) was reverted:
   it read as "which icon is which tab?" instead of a menu. */
.nav-bar {
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    position: relative;
    z-index: 20;
    box-shadow: var(--shadow-xs);
}
.nav-bar .nav-home {
    display: flex;
    align-items: center;
    padding: 6px 9px;
    color: var(--text);
    text-decoration: none;
    font-size: 0.98rem;
    font-weight: 600;
    border-bottom: 2px solid transparent;
    transition: color var(--ease), border-color var(--ease);
    flex-shrink: 0;
    white-space: nowrap;
}
.nav-bar .nav-home:hover, .nav-bar .nav-home.active { color: var(--primary); border-bottom-color: var(--primary); }

/* The button row. Text labels are back, so on a narrow phone five buttons
   plus the branch picker genuinely don't all fit on one line — rather than
   wrap (which read as unpolished) the row scrolls horizontally instead,
   same pattern as any mobile tab bar; a quick swipe reaches the rest. */
.nav-main {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 2px;
    padding: 4px 8px;
    overflow-x: auto;
    scrollbar-width: none;
}
.nav-main::-webkit-scrollbar { display: none; }
.nav-item { flex-shrink: 0; }
.nav-trigger {
    display: flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    padding: 7px 10px;
    cursor: pointer;
    transition: background var(--ease);
    white-space: nowrap;
    line-height: 1;
    font-size: 0.86rem;
    font-weight: 600;
    color: var(--text);
}
.nav-trigger:hover { background: var(--bg); }
/* The currently-OPEN button (not "current page") gets the highlight — see
   the code comment in nav.js for why top-level buttons intentionally never
   light up based on which page you're on: several items are deliberately
   cross-listed under more than one group (e.g. "Cash Book" under both Data
   Entry and Reports), so more than one button would light up "correctly"
   at once by that logic, which reads as a bug rather than a feature. Which
   dropdown is open right now is unambiguous, so that's the only state a
   button reflects. */
.nav-trigger.open { background: var(--primary-light); }
.nav-icon { font-size: 1.05rem; display: block; }
.nav-label { display: block; }
.nav-caret { font-size: 0.65rem; color: var(--muted); }

/* The dropdown itself — a single shared element appended to <body> (see
   nav.js), positioned `fixed` with its top/left set inline from the
   clicked button's own bounding rect. That's JS's job, not CSS's, because
   .nav-main (the scrollable button row) forces its own overflow-y to
   "auto" the moment overflow-x is non-visible — any dropdown positioned
   *inside* it would get silently clipped the instant it extended below
   the row. Living in <body> sidesteps that (and every other ancestor's
   overflow/stacking-context quirks) entirely. Hidden via the `hidden`
   attribute so nav.js can toggle it with a single property. */
.nav-dropdown {
    position: fixed;
    min-width: 220px;
    max-width: min(340px, 92vw);
    max-height: 70vh;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md, 0 6px 20px rgba(0,0,0,0.15));
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 1px;
    animation: nav-drop 120ms ease;
    z-index: 3000; /* body-level now (see comment above) — above ordinary content/modals-adjacent chrome (z-index 20/30), below the autosuggest dropdown (5000) and toasts (9999) it can coexist with */
}
/* `.nav-dropdown` and the browser's own `[hidden] { display: none }` rule
   are EQUAL specificity (one class vs one attribute selector) — without
   this, an author rule always beats the UA stylesheet regardless of
   source order, so the `display: flex` above silently wins and the empty
   panel sits there visible (as a small rounded box pinned to the bottom
   of whichever page it was created on, since a `position: fixed` element
   with no top/left set falls back to its static position — the end of
   <body>, since nav.js appends it there) even while nav.js's `dropdown.
   hidden = true` is correctly set. This selector is one class + one
   attribute, so it outranks the plain `.nav-dropdown` rule above and
   actually hides it. */
.nav-dropdown[hidden] { display: none; }
@keyframes nav-drop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.nav-dd-item {
    display: block;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    color: var(--text);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 500;
    white-space: normal;
    transition: background var(--ease), color var(--ease);
}
.nav-dd-item:hover { background: var(--primary-light); }
.nav-dd-item.active { color: #fff; background: var(--primary); }
.nav-dd-divider { height: 1px; background: var(--border); margin: 5px 4px; flex-shrink: 0; }

.nav-branch { margin-left: auto; display: flex; align-items: center; gap: 6px; flex-shrink: 0; white-space: nowrap; }
.nav-branch label { font-size: 0.78rem; color: var(--muted); font-weight: 600; margin: 0; flex-shrink: 0; }
.nav-branch select { padding: 5px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 0.83rem; background: var(--surface); min-width: 0; max-width: 150px; }
@media (max-width: 420px) {
    .nav-branch label { display: none; }
    .nav-branch select { max-width: 108px; }
    /* Below this width, drop the text label and keep just icon + caret so
       the bar has a fighting chance of showing more than one button before
       the branch picker forces a scroll — the dropdown itself is unaffected. */
    .nav-label { display: none; }
    .nav-trigger { padding: 7px 8px; }
}

.content { max-width: 1120px; margin: 0 auto; padding: 8px 10px 14px; }

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 9px 11px;
    margin-bottom: 6px;
    box-shadow: var(--shadow-sm);
    /* Every data table in the app (reports, accounts, items, ledgers,
       the dashboard's recent-transactions/top-items lists, etc.) is
       rendered as a plain <table> straight inside a .card, with no
       wrapping div of its own. A table's unbreakable numeric cells
       (e.g. "12,795.00") can't wrap the way text can, so on a narrow
       phone screen the table is forced wider than the card — and with
       nowhere else to go, that overflow used to bleed past .content
       and get invisibly clipped by html/body's overflow-x:hidden
       (line ~107), cutting off the right-hand columns (amounts) on
       every tab/report/page. Scoping the scroll to .card itself keeps
       the rest of the page fixed and lets a wide table scroll
       horizontally in place instead, without editing every page's
       markup individually. */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

h1 { font-size: 1.25rem; font-weight: 700; margin: 0 0 6px; color: var(--heading); letter-spacing: -0.015em; }
h2 { font-size: 1rem; font-weight: 600; color: var(--heading); margin: 0 0 6px; }

/* Small colored icon badge dropped in as the first thing inside any <h2> —
   a reusable "pro" card-header treatment (icon in a tinted rounded square
   ahead of the title) meant to replace plain text-only card headers across
   the app a page at a time, starting with the Main Menu dashboard. Shares
   the same --accent-rgb recipe/palette as .stat.accent-* below so a card's
   icon and any stat tiles it relates to can use the same hue. Inline-flex +
   negative vertical-align (rather than making h2 itself a flex container)
   so it drops into any existing <h2>text</h2> markup everywhere in the app
   without risk of changing how any h2 that ISN'T using it lays out. */
.card-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 8px;
    font-size: 0.92rem;
    margin-right: 8px;
    vertical-align: -6px;
    background: rgba(var(--accent-rgb, 198, 40, 57), 0.14);
}
/* Smaller variant for a dense header that isn't a plain h1/h2 — the
   .doc-title "document" pattern (Sales, Purchase, Transfer, vouchers, their
   Returns) sits at 1.05rem with a tight border-bottom, where a full 24px
   badge reads oversized. Same icon, scaled to fit. */
.card-ico.sm { width: 20px; height: 20px; font-size: 0.8rem; vertical-align: -4px; }
.card-ico.accent-blue { --accent-rgb: 42, 111, 219; }
.card-ico.accent-purple { --accent-rgb: 124, 92, 214; }
.card-ico.accent-green { --accent-rgb: 30, 157, 91; }
.card-ico.accent-red { --accent-rgb: 197, 48, 48; }
.card-ico.accent-teal { --accent-rgb: 15, 155, 142; }
.card-ico.accent-navy { --accent-rgb: 26, 60, 94; }
.card-ico.accent-orange { --accent-rgb: 224, 142, 11; }
.card-ico.accent-indigo { --accent-rgb: 74, 78, 201; }

table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
th, td { text-align: left; padding: 5px 7px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; }
tbody tr { transition: background var(--ease); }
tbody tr:hover { background: var(--bg); }
tr.cancelled { opacity: 0.5; text-decoration: line-through; }
.report-row-link { cursor: pointer; }
/* Report result tables (reports.html's table() helper, every report tab):
   zebra striping + right-aligned, tabular-figure amount columns so a table
   full of numbers reads as rows of data rather than one undifferentiated
   grey block — the main "hard to read" complaint about these tables.
   Scoped to .report-table-wrap only, so no other table in the app (Items,
   Accounts, vouchers, …) changes look. */
.report-table-wrap tbody tr:nth-child(even) { background: var(--bg); }
.report-table-wrap tbody tr:hover { background: var(--primary-50); }
.report-table-wrap th.num, .report-table-wrap td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* :root[data-theme="dark"] --primary-50 is already a dark-mode-appropriate
   tint (see the dark theme block above), so the hover rule needs no
   separate dark-mode override here. */
/* Stock Report's grouped/subtotaled layout (Category -> Manufacturer ->
   items -> "Total for ..." -> GRAND TOTAL), matching the shape of the
   MobiSoft reference PDF it was built against — a different structure from
   the flat zebra-striped tables above, so it opts out of that striping and
   gets its own row styling instead. */
.report-table-wrap.rpt-grouped tbody tr:nth-child(even) { background: transparent; }
.rpt-grouped tbody tr td { background: transparent; }
.rpt-grouped .rpt-group-cat td { background: var(--primary-50) !important; border-top: 2px solid var(--border-strong); border-bottom: 1px solid var(--border-strong); font-weight: 700; color: var(--heading); padding-top: 7px; padding-bottom: 7px; }
.rpt-grouped .rpt-group-co td { background: var(--surface) !important; font-weight: 700; padding-left: 18px; border-bottom: 1px dashed var(--border); }
.rpt-grouped tbody tr.pg-row td:first-child { padding-left: 32px; }
.rpt-grouped .rpt-subtotal td { font-weight: 700; border-top: 1px solid var(--border-strong); }
.rpt-grouped .rpt-subtotal-cat td { border-bottom: 2px solid var(--border-strong); }
.rpt-grouped .rpt-grand td { font-weight: 700; border-top: 3px double var(--border-strong); font-size: 1.02em; }
/* Items list only (public/items.html's #rows table, via the .items-table
   class added there): the Code column ("ITM-001") was breaking onto two
   lines on a narrow phone, puffing up row height and page scroll. Only the
   first column (Code) is forced onto one line — every other column still
   shrinks/wraps as it always did. */
.items-table th:first-child, .items-table td:first-child { white-space: nowrap; }
/* That alone wasn't enough on a phone: with 11 columns, even wrapping
   columns still have a minimum width (a header word, a price, a pill, the
   Edit/Deactivate buttons don't break), so the row was still wider than the
   screen and the whole card (search box + Add Item button included) had to
   scroll sideways to reach them — exactly what was reported. Below 640px,
   drop the columns that are least useful at a glance (Company, Amazon SKU,
   Unit, Cost, Wholesale) and keep Code/Name/Sale Price/Stock/Status/Edit —
   that's narrow enough to need no horizontal scroll at all. Nothing is
   lost: every dropped column is still in the Add/Edit popup. Position-based
   (nth-child) rather than a new class per cell, since the column order is
   fixed and this avoids touching items.html's render() for every row. */
@media (max-width: 640px) {
    .items-table th:nth-child(3), .items-table td:nth-child(3),
    .items-table th:nth-child(4), .items-table td:nth-child(4),
    .items-table th:nth-child(5), .items-table td:nth-child(5),
    .items-table th:nth-child(6), .items-table td:nth-child(6),
    .items-table th:nth-child(8), .items-table td:nth-child(8) {
        display: none;
    }
    /* Edit + Deactivate side by side still needed more width than the
       6 remaining columns had to spare. Stacking them (each its own line)
       needs only the wider single word's width instead of both combined. */
    .items-table td:last-child button { display: block; margin: 0 0 2px; }
    /* Even with those two changes, the 6 remaining columns' minimum
       widths (a status pill, "Deactivate", "ITM-001", ...) still added up
       to a few px more than a typical phone's width. Tighter side padding
       and a touch smaller text closes that gap — this table alone, so
       nothing else on the page is affected. */
    .items-table th, .items-table td { padding: 5px 3px; font-size: 0.78rem; }
    /* The Status pill's own padding is generous (built for a roomy desktop
       cell) and was still the widest single thing in its column on a
       360px-ish phone. Only shrink it inside this table/breakpoint. */
    .items-table .mkt-pill { padding: 3px 7px; font-size: 0.7rem; }
}
.imei-clickable-row { cursor: pointer; }
.imei-clickable-row:hover { background: var(--bg); }

.stat-row { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.stat {
    --accent-rgb: 198, 40, 57;
    background: linear-gradient(135deg, rgba(var(--accent-rgb), 0.10) 0%, var(--surface) 60%);
    border: 1px solid var(--border);
    border-left: 3px solid var(--primary);
    border-radius: var(--radius);
    padding: 10px 14px;
    /* flex-grow so each card stretches to fill its row instead of hugging
       its own content width and leaving a bare gap on the right — the
       min-width (via the flex-basis) is what decides how many fit per row
       before wrapping; grow(1) is what makes however many DO fit share the
       full row width evenly, phone width included. */
    flex: 1 1 140px;
    box-shadow: var(--shadow-sm);
}
.stat .label { color: var(--muted); font-size: 0.8rem; font-weight: 600; }
.stat .value { font-size: 1.3rem; font-weight: 700; margin-top: 3px; color: var(--heading); letter-spacing: -0.01em; }
/* Color-coded accents for the Main Menu dashboard's summary cards — each
   figure gets its own hue (a soft tinted background plus a matching left
   border) so the row reads at a glance (blue=sales, purple=purchases,
   green=receivables/money owed to us, red=payables/money we owe,
   teal=cash, navy=bank, orange=this week, indigo=this month) without
   needing to read every label first. --accent-rgb feeds the tinted
   background above; it's a fixed light-mode hue used at low opacity, so a
   slight mismatch with --success/--danger's own dark-mode shade is never
   noticeable in practice. */
.stat.accent-blue { --accent-rgb: 42, 111, 219; border-left-color: #2a6fdb; }
.stat.accent-purple { --accent-rgb: 124, 92, 214; border-left-color: #7c5cd6; }
.stat.accent-green { --accent-rgb: 30, 157, 91; border-left-color: var(--success); }
.stat.accent-red { --accent-rgb: 197, 48, 48; border-left-color: var(--danger); }
.stat.accent-teal { --accent-rgb: 15, 155, 142; border-left-color: #0f9b8e; }
.stat.accent-navy { --accent-rgb: 26, 60, 94; border-left-color: #1a3c5e; }
.stat.accent-orange { --accent-rgb: 224, 142, 11; border-left-color: #e08e0b; }
.stat.accent-indigo { --accent-rgb: 74, 78, 201; border-left-color: #4a4ec9; }
/* Dashboard stat cards are links into the report that explains the figure —
   reset the <a> defaults and add a lift on hover so it reads as clickable
   without looking like a button (still just a card). */
a.stat { display: block; text-decoration: none; cursor: pointer; transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease); }
a.stat:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: var(--primary); }

/* ===== Main Menu dashboard (index.html): summary cards above, then a
   Recent Transactions + Quick Actions/trend row, then the existing
   navigation tile grids unchanged below. ===== */
.dash-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 10px; margin-bottom: 10px; align-items: start; }
.dash-grid.even { grid-template-columns: 1fr 1fr; }
.dash-grid.triple { grid-template-columns: 1fr 1fr 1fr; }
@media (max-width: 760px) { .dash-grid, .dash-grid.even, .dash-grid.triple { grid-template-columns: 1fr; } }
@media (max-width: 1100px) and (min-width: 761px) { .dash-grid.triple { grid-template-columns: 1fr 1fr; } }
.dash-recent-card table { font-size: 0.83rem; }
.dash-side h2:first-child { margin-top: 0; }
/* Quick Actions — a single full-width strip of equal-width buttons right
   under the KPI cards (moved out of the old cramped sidebar column so
   every action is one click away without competing for space with the
   trend chart). */
.dash-quick-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.dash-quick-row .dash-quick-btn { flex: 1 1 150px; justify-content: center; }
.dash-quick-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--text);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 600;
    transition: background var(--ease), border-color var(--ease), transform var(--ease);
}
.dash-quick-btn:hover { background: var(--primary-light); border-color: var(--primary); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.dash-quick-btn .icon { font-size: 0.95rem; }
.dash-trend-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
.dash-tabs { display: flex; gap: 2px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 2px; }
.dash-tab {
    border: none; background: transparent; padding: 4px 10px; font-size: 0.78rem; font-weight: 700;
    color: var(--muted); border-radius: 4px; cursor: pointer; font-family: inherit;
    transition: background var(--ease), color var(--ease);
}
.dash-tab:hover { color: var(--heading); }
.dash-tab.active { background: var(--surface); color: var(--primary-dark); box-shadow: var(--shadow-xs); }
.dash-trend .bar-row { display: flex; align-items: center; gap: 8px; margin: 5px 0; }
.dash-trend .bar-label { flex-shrink: 0; text-align: right; font-size: 0.76rem; color: var(--muted); font-weight: 600; }
.dash-trend .bar-track { flex: 1; background: var(--bg); border-radius: 4px; overflow: hidden; height: 18px; }
.dash-trend .bar-fill { background: linear-gradient(90deg, var(--primary), var(--primary-dark)); height: 100%; display: flex; align-items: center; padding-left: 7px; color: #fff; font-size: 0.72rem; white-space: nowrap; min-width: 2px; border-radius: 4px; }

/* Top Selling Items / Low Stock Alert — compact two-column lists (name,
   right-aligned figure) reusing the app's table look without a full header
   row, since each card only ever shows one kind of figure. */
.dash-mini-list { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.dash-mini-list td { padding: 6px 2px; border-bottom: 1px solid var(--border); }
.dash-mini-list tr:last-child td { border-bottom: none; }
.dash-mini-list .qty { text-align: right; font-weight: 700; color: var(--heading); white-space: nowrap; padding-left: 10px; }
.dash-mini-list .low-stock-row td { color: var(--danger); }
.dash-mini-list .low-stock-row .hint { color: var(--muted); font-weight: 400; }
.dash-mini-empty { color: var(--muted); font-size: 0.85rem; padding: 6px 2px; border-bottom: none !important; }

/* Receivables vs Payables donut — a plain CSS conic-gradient ring (no SVG,
   no charting library), split at the --pct custom property JS sets on the
   element. The inner circle punches the "hole" using the card's own
   background, so it always matches the surrounding surface in both themes. */
.dash-donut-wrap { display: flex; align-items: center; gap: 16px; }
.dash-donut {
    width: 96px; height: 96px; border-radius: 50%; flex-shrink: 0; position: relative;
    background: conic-gradient(var(--success) 0% var(--pct, 50%), var(--danger) var(--pct, 50%) 100%);
}
.dash-donut::after { content: ""; position: absolute; inset: 13px; background: var(--surface); border-radius: 50%; }
.dash-donut-center {
    position: absolute; inset: 13px; display: flex; align-items: center; justify-content: center;
    font-size: 0.68rem; font-weight: 700; color: var(--muted); text-align: center; line-height: 1.2;
}
.dash-donut-legend { font-size: 0.85rem; display: flex; flex-direction: column; gap: 10px; }
.dash-donut-legend .dl-row { display: flex; align-items: center; gap: 7px; }
.dash-donut-legend .dl-dot { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }
.dash-donut-legend .dl-label { color: var(--muted); }
.dash-donut-legend .dl-value { font-weight: 700; color: var(--heading); margin-left: auto; padding-left: 10px; }

form label { display: block; margin: 6px 0 3px; font-size: 0.85rem; color: var(--muted); font-weight: 600; }

/* Base styling for every text-like input, select and textarea in the app —
   not just ones inside a <form> or a .doc-row. The whole Reports screen
   (Sale Report, Stock Report, Price List, SMS to Customers, Quick Lookup,
   and every other report's filter bar) builds its filter rows as plain
   .form-row divs with no <form> wrapper, so those fields fell back to the
   browser's bare native widget — a flat grey dropdown sitting right next to
   a fully styled white one on the very same row. One rule here covers every
   field on every screen, present or future, regardless of what wraps it.
   Checkboxes, radios and file inputs keep their native control. */
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select,
textarea {
    width: 100%;
    padding: 6px 9px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 0.9rem;
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
    transition: border-color var(--ease), box-shadow var(--ease);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-light);
}
input:disabled, input[readonly], select:disabled {
    background: var(--bg);
    color: var(--muted);
}
.form-row { display: flex; gap: 10px; flex-wrap: wrap; }
.form-row > div { flex: 1; min-width: 140px; }
.radio-inline { display: inline-flex; align-items: center; gap: 5px; font-weight: normal; margin-right: 16px; width: auto; }
.radio-inline input { width: auto; }
.doc-check-inline { display: inline-flex; align-items: center; gap: 6px; font-weight: normal; margin-right: 20px; width: auto; }
.doc-check-inline input { width: auto; }
.checkbox-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 6px 16px; margin: 6px 0; }
.checkbox-grid label { display: inline-flex; align-items: center; gap: 6px; font-weight: normal; width: auto; }
.checkbox-grid input { width: auto; }

/* Safety net: any plain, unclassed <button> anywhere in the app still gets
   a consistent look instead of falling back to the browser's bare native
   button style (which is what caused mismatched/misaligned button rows —
   a styled .primary button next to a totally unstyled bare one). Buttons
   that opt into a specific look (.primary/.secondary/.link) are unaffected
   since those rules are more specific and come later in the cascade. */
button {
    font-family: inherit;
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-xs);
    transition: background var(--ease), border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
button:hover { background: var(--bg); border-color: var(--muted-2); box-shadow: var(--shadow-sm); }
button:active { transform: translateY(1px); box-shadow: var(--shadow-xs); }
button:disabled { opacity: 0.4; cursor: not-allowed; transform: none; box-shadow: none; }
button:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
button.link, button.link:hover { background: none; border: none; box-shadow: none; }
button.link:active { transform: none; }
button.primary {
    background: linear-gradient(180deg, var(--primary) 0%, var(--primary-dark) 100%);
    color: #fff;
    border: 1px solid var(--primary-dark);
    padding: 8px 16px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.9rem;
    font-weight: 600;
    margin-top: 10px;
    box-shadow: 0 1px 2px rgba(150, 32, 46, 0.25), var(--shadow-xs);
    transition: background var(--ease), border-color var(--ease), box-shadow var(--ease), transform var(--ease), filter var(--ease);
}
button.primary:hover { filter: brightness(1.06); box-shadow: 0 4px 10px rgba(150, 32, 46, 0.28); }
button.primary:active { transform: translateY(1px); filter: brightness(0.98); }
/* A disabled primary button (e.g. "Save" while browsing a locked, already-
   saved record with Prev/Next) reads as a clean, solid grey rather than a
   washed-out, half-transparent smear of the brand color — the previous
   opacity:0.4 on a red gradient looked broken rather than intentionally
   inactive. */
button.primary:disabled, button.primary:disabled:hover {
    background: var(--border-strong);
    border-color: var(--border-strong);
    color: var(--muted);
    box-shadow: none;
    filter: none;
    opacity: 1;
}
button.secondary {
    background: var(--surface);
    border: 1px solid var(--border-strong);
    color: var(--text);
    padding: 8px 14px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    margin-top: 10px;
    margin-left: 8px;
    font-weight: 600;
    font-size: 0.9rem;
    transition: background var(--ease), border-color var(--ease);
}
button.secondary:hover { background: var(--bg); border-color: var(--muted-2); }
button.link { background: none; border: none; color: var(--primary); cursor: pointer; padding: 0; font-size: 0.85rem; font-weight: 600; }
button.link:hover { color: var(--primary-dark); text-decoration: underline; }
button.link.danger { color: var(--danger); }

.badge { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 0.74rem; font-weight: 700; letter-spacing: 0.02em; }
.badge.role { background: var(--primary-light); color: var(--primary-dark); }

.error {
    color: var(--danger);
    background: var(--danger-light);
    border: 1px solid rgba(197, 48, 48, 0.18);
    border-radius: var(--radius-sm);
    padding: 9px 12px;
    font-size: 0.87rem;
    margin-top: 10px;
}
.success-msg {
    color: var(--success);
    background: var(--success-light);
    border: 1px solid rgba(30, 157, 91, 0.18);
    border-radius: var(--radius-sm);
    padding: 9px 12px;
    font-size: 0.87rem;
    margin-top: 10px;
}
.hint { color: var(--muted); font-size: 0.83rem; margin-top: 5px; }

/* ===== Modal (Serial/IMEI view popup, and anywhere else that needs one) ===== */
.modal-overlay {
    position: fixed; inset: 0; background: rgba(15, 20, 30, 0.55);
    display: flex; align-items: center; justify-content: center;
    z-index: 2000; padding: 20px;
}
.modal-box {
    background: var(--surface, #fff); border-radius: var(--radius, 10px);
    max-width: 520px; width: 100%; max-height: 82vh; overflow-y: auto;
    padding: 14px 16px; box-shadow: 0 18px 50px rgba(0,0,0,0.28);
}
/* Wider variant for a modal that hosts a full multi-column data-entry form
   (Add/Edit Item and similar) rather than a short confirmation/settings box —
   the base 520px is too narrow for a 4-5-column .form-row before it wraps
   into an awkwardly tall single column. */
.modal-box.modal-wide { max-width: 900px; }
.modal-box h3 { margin: 0 0 4px; font-size: 1.05rem; }
.modal-box .modal-close { float: right; background: none; border: none; font-size: 1.3rem; line-height: 1; cursor: pointer; color: var(--muted); }
.modal-box .modal-close:hover { color: var(--ink, #1a1a1a); }
.modal-imei-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 7px 4px; border-bottom: 1px solid var(--border, #e6e6e6); }
.modal-imei-row:last-child { border-bottom: none; }
.modal-imei-row .imei-val { font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 0.92rem; flex: 1; word-break: break-all; }
.modal-imei-row .imei-val input { width: 100%; }
.modal-actions { display: flex; gap: 10px; margin-top: 14px; }

/* ===== Autosuggest (replaces native <input list=""> + <datalist> — see
   js/autosuggest.js for why: native datalist popups are unreliable on
   several mobile browsers, and this is the app's single most-used
   dropdown, so it gets a fully custom, always-visible one instead). ===== */
.autosuggest-box {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 0 0 10px 10px; box-shadow: var(--shadow-lg);
    max-height: 280px; overflow-y: auto; z-index: 5000;
}
.autosuggest-item { padding: 9px 12px; font-size: 0.9rem; cursor: pointer; color: var(--text); }
.autosuggest-item:hover, .autosuggest-item.active { background: var(--primary-50); color: var(--primary-dark); }
.autosuggest-empty { padding: 9px 12px; font-size: 0.87rem; color: var(--muted); }

/* ===== Login ===== */
.login-wrap {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(900px 500px at 15% 10%, rgba(198, 40, 57, 0.16), transparent 60%),
        radial-gradient(900px 600px at 85% 90%, rgba(198, 40, 57, 0.10), transparent 60%),
        linear-gradient(160deg, var(--ink) 0%, #0c111c 100%);
    padding: 24px;
}
.login-box {
    background: var(--surface);
    border: 1px solid rgba(255,255,255,0.06);
    border-radius: var(--radius-lg);
    padding: 26px 26px 22px;
    width: 380px;
    max-width: 100%;
    text-align: center;
    box-shadow: var(--shadow-lg);
}
.login-box img.brand-logo { max-height: 64px; margin-bottom: 14px; display: none; }
.login-box h1 {
    text-align: center;
    font-size: 1.3rem;
    letter-spacing: -0.01em;
    margin-bottom: 4px;
}
.login-box h1.brand-text::before {
    content: "";
    display: block;
    width: 46px; height: 46px;
    margin: 0 auto 14px;
    border-radius: 12px;
    background: linear-gradient(135deg, var(--primary), var(--primary-dark));
    box-shadow: 0 6px 16px rgba(198, 40, 57, 0.35);
}
.login-box img.brand-logo[style*="block"] ~ h1.brand-text::before,
.login-box img.brand-logo:not([style*="display:none"]):not([style*="display: none"]) ~ h1.brand-text::before { display: none; }
.login-box p.tagline { color: var(--muted); font-size: 0.85rem; margin: 0 0 22px; }
.login-box form { text-align: left; }
.login-box button.primary { width: 100%; padding: 11px 20px; font-size: 0.95rem; }
.demo-accounts {
    font-size: 0.78rem;
    color: var(--muted);
    margin-top: 20px;
    line-height: 1.6;
    text-align: left;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
}
.demo-accounts code {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 1px 6px;
    font-size: 0.78rem;
}

/* Main menu — grouped tiles, same structure as a typical mobile-shop POS
   (Invoices / Reports / Management), original layout and styling. */
.menu-group { margin-bottom: 8px; }
.menu-group h2 {
    color: var(--muted);
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    margin: 0 0 6px;
    padding-bottom: 5px;
    border-bottom: 1px solid var(--border);
}
.tile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 6px; }
/* Reports picker (reports.html's "no report chosen yet" screen): each
   category gets its own soft-tinted card and accent color (via --mg-rgb,
   set per .accent-* class — reports.html assigns one of these to every
   .menu-group it renders, cycling through the palette) instead of a bare
   list under a plain grey uppercase label, so the whole picker reads as a
   set of distinct destinations rather than one long undifferentiated wall
   of buttons. */
.report-groups .menu-group {
    --mg-rgb: 198, 40, 57;
    margin-bottom: 16px;
    background: linear-gradient(135deg, rgba(var(--mg-rgb), 0.055) 0%, var(--surface) 55%);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 13px 14px 15px;
}
.report-groups .menu-group:last-child { margin-bottom: 0; }
.report-groups .menu-group.accent-blue { --mg-rgb: 42, 111, 219; }
.report-groups .menu-group.accent-purple { --mg-rgb: 124, 92, 214; }
.report-groups .menu-group.accent-green { --mg-rgb: 30, 157, 91; }
.report-groups .menu-group.accent-red { --mg-rgb: 197, 48, 48; }
.report-groups .menu-group.accent-teal { --mg-rgb: 15, 155, 142; }
.report-groups .menu-group.accent-navy { --mg-rgb: 26, 60, 94; }
.report-groups .menu-group.accent-orange { --mg-rgb: 224, 142, 11; }
/* Scoped to this page only — the shared .tile/.tile-grid sizing (used by the
   home menu too) stays as-is; this grid just reads small with 41 report
   names in it, so it gets its own larger type and wider columns to match. */
.report-groups .menu-group h2 {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 0.86rem;
    color: rgb(var(--mg-rgb));
    border-bottom: none;
    padding-bottom: 0;
    margin-bottom: 11px;
}
.report-groups .menu-group h2 .mg-icon {
    width: 27px;
    height: 27px;
    flex-shrink: 0;
    border-radius: 9px;
    background: rgba(var(--mg-rgb), 0.16);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
}
.report-groups .tile-grid { grid-template-columns: repeat(auto-fill, minmax(138px, 1fr)); gap: 9px; }
.report-groups .tile {
    font-size: 0.95rem;
    padding: 13px 11px 12px;
    border-left: 3px solid rgba(var(--mg-rgb), 0.45);
    font-weight: 600;
}
.report-groups .tile:hover { border-left-color: rgb(var(--mg-rgb)); background: rgba(var(--mg-rgb), 0.06); }
.tile {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 8px 6px 7px;
    text-align: center;
    text-decoration: none;
    color: var(--text);
    font-size: 0.76rem;
    font-weight: 500;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    box-shadow: var(--shadow-xs);
    transition: box-shadow var(--ease), transform var(--ease), border-color var(--ease);
}
.tile:hover { box-shadow: var(--shadow); transform: translateY(-3px); border-color: var(--primary); }
.tile .icon {
    font-size: 0.95rem;
    width: 26px; height: 26px;
    display: flex; align-items: center; justify-content: center;
    background: var(--primary-light);
    border-radius: 11px;
    transition: background var(--ease), transform var(--ease);
}
.tile:hover .icon { background: var(--primary); transform: scale(1.05); }
.tile:hover .icon { filter: none; }

.line-items-table input { padding: 5px 6px; font-size: 0.85rem; }
.line-items-table td { vertical-align: middle; }
.totals-box { max-width: 320px; margin-left: auto; }
.totals-box .row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 0.9rem; }
.totals-box .row.net { font-weight: 700; border-top: 1px solid var(--border); margin-top: 6px; padding-top: 8px; }

/* Browsers strip background colors/images from a print/Save-as-PDF render
   by default (the "Background graphics" checkbox in the print dialog,
   normally off) — without this, every colored element in every printed
   document in the app (the navy INVOICE box, table header shading, the
   report title bar below) silently renders as plain black-on-white even
   though the on-screen CSS clearly sets a color. This is the single fix
   that makes all of those actually print as designed, everywhere, with no
   per-page changes needed. */
@media print {
    * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; color-adjust: exact !important; }
}

/* Printing (invoices, reports, any Ctrl+P / "Download PDF") always uses the
   light palette, even when the screen is in dark mode — re-declares every
   variable dark mode overrides, back to its light value, scoped to the
   dark-mode attribute so this is a no-op when already in light mode. Paper
   doesn't have a "dark mode", and printing a dark page would waste ink and
   look wrong on an invoice a customer keeps. */
@media print {
    :root[data-theme="dark"] {
        --primary: #c62839; --primary-dark: #96202e; --primary-light: #fdecee; --primary-50: #fbf1f2;
        --heading: #141b29; --bg: #f3f4f7; --surface: #ffffff; --border: #e3e6ec; --border-strong: #cfd4dd;
        --text: #202634; --muted: #69707f; --muted-2: #8b93a3;
        --success: #1e9d5b; --success-light: #e7f8ee; --danger: #c53030; --danger-light: #fdecea;
        --warning: #b7791f; --warning-light: #fdf3e1;
    }
}

/* Print page margins only — no CSS-drawn "Page N" footer (removed per
   request: it read as a duplicate/clutter alongside Chrome's own built-in
   print header/footer). Chrome's native "Page 1 of 1" text in the printed
   PDF is NOT this stylesheet — it's the browser's own Print dialog setting
   ("More settings" → uncheck "Headers and footers" before Save as PDF), a
   per-print browser preference no page's CSS can suppress. */
@page {
    margin: 14mm 12mm;
}

/* Report print output — "Generate" shows the report on screen; "Download
   PDF" prints just the report itself (letterhead + filter summary + table)
   via the browser's own Print > Save as PDF, so no server-side PDF library
   is needed. Everything else on the page is hidden for that render only.
   Shares the same navy letterhead look as the Sales/Purchase invoice print
   (see sales.html's #invoice-print .inv-header rules) so every printed
   document in the app reads as one consistent, professional design. */
@media print {
    .topbar, .nav-bar, #filter-card, .no-print { display: none !important; }
    .content { padding: 0; }
    #report-output table { font-size: 11px; }
    body { background: #fff; }
    /* Report pagination (reports.html's table()/wireReportPagers()) only
       ever hides rows on screen with .pg-hide — never removes them — so a
       printed/PDF'd report always includes every row regardless of which
       page was showing when Download PDF was clicked. */
    #report-output tr.pg-hide { display: table-row !important; }
}
.report-print-header { display: none; }
@media print {
    .report-print-header {
        display: block;
        margin-bottom: 12px;
        border-bottom: 3px solid #1a3c5e;
        padding-bottom: 8px;
        font-family: Arial, Helvetica, sans-serif;
        color: #000;
    }
    .report-print-company {
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 14px;
        text-align: center;
        margin-bottom: 8px;
    }
    .report-print-logo { max-height: 58px; max-width: 170px; object-fit: contain; }
    .report-print-company h2 { margin: 0; font-size: 1.5rem; color: #14324a; letter-spacing: 0.3px; }
    .report-print-company p { margin: 2px 0 0; font-size: 0.85rem; }
    .report-print-company .report-print-contact { color: #333; }
    .report-print-header h1 { margin: 0 0 4px; font-size: 1.3rem; text-align: center; }
    .report-print-header .meta { color: #555; font-size: 0.85rem; text-align: center; }
    .report-print-footer {
        display: flex;
        justify-content: flex-end;
        margin-top: 24px;
        font-family: Arial, Helvetica, sans-serif;
        font-size: 11px;
    }
    .report-print-footer .report-print-sign {
        text-align: center;
        border: 1px solid #000;
        min-width: 180px;
        padding: 6px;
    }
    .report-print-footer .report-print-sign-imgs { display: flex; justify-content: center; align-items: flex-end; gap: 10px; min-height: 44px; }
    .report-print-footer .report-print-sign-imgs img { max-height: 44px; max-width: 110px; object-fit: contain; }
    .report-print-footer .report-print-sign-label { font-weight: bold; border-top: 1px solid #000; margin-top: 4px; padding-top: 3px; }
}

/* ===== "Document" form pattern — shared by Purchase, Purchase Return,
   Sales, Sale Return, Transfer, and the voucher pages, matching the
   MobiSoft reference screenshots: always-visible form (no list toggle),
   Ref/Cancelled/Date on top, a party+balance row, an item/line entry box,
   an editable lines table, Unlock/Apply/Total, Remarks+User, a totals
   panel (Freight/Discount/W.H.Tax/Net Total/Cash Paid/Balance), and a
   Save/New/Prev/Next/Print/Export/Close action bar. */
.doc-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 10px 12px;
    margin-bottom: 8px;
    box-shadow: var(--shadow-sm);
}
.doc-title {
    font-size: 1.05rem;
    color: var(--heading);
    margin: 0 0 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
    font-weight: 700;
    letter-spacing: -0.01em;
}
.doc-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 4px; }
.doc-row > div { flex: 1; min-width: 150px; }
.doc-row .grow2 { flex: 2; }
.doc-row .shrink { flex: 0 0 auto; min-width: 0; }
.doc-row label { display: block; font-size: 0.74rem; color: var(--muted); font-weight: 700; margin-bottom: 2px; text-transform: uppercase; letter-spacing: 0.02em; }
.doc-row input, .doc-row select, .doc-row textarea {
    width: 100%; padding: 5px 9px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 0.88rem;
    font-family: inherit; background: var(--surface); color: var(--text);
    transition: border-color var(--ease), box-shadow var(--ease);
}
.doc-row input[readonly], .doc-row input:disabled, .doc-row select:disabled { background: var(--bg); color: var(--muted); }
.doc-check { display: flex; align-items: center; gap: 6px; padding-bottom: 4px; font-size: 0.85rem; font-weight: 600; }
.doc-check input { width: auto; }
.doc-radio-group { display: flex; gap: 14px; align-items: center; padding-bottom: 6px; }
.doc-radio-group label { display: flex; align-items: center; gap: 5px; font-size: 0.85rem; font-weight: 600; margin: 0; }
.doc-radio-group input { width: auto; }

.doc-entry-box { border: 1px dashed var(--border-strong); border-radius: var(--radius); padding: 8px 12px; margin: 5px 0 8px; background: var(--bg); }
.doc-entry-box .doc-row:last-child { margin-bottom: 0; }
.doc-entry-actions { display: flex; gap: 8px; align-items: center; }
.doc-entry-actions button {
    padding: 6px 12px; border-radius: var(--radius-sm); font-size: 0.85rem; font-weight: 600; cursor: pointer;
    border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
    margin: 0; transition: background var(--ease), border-color var(--ease), box-shadow var(--ease);
}
.doc-entry-actions button:hover { background: var(--bg); border-color: var(--muted-2); }
.doc-entry-actions button.primary { background: linear-gradient(180deg, var(--primary) 0%, var(--primary-dark) 100%); border-color: var(--primary-dark); color: #fff; }
.doc-entry-actions button.primary:hover { filter: brightness(1.06); }
.doc-entry-actions button:disabled { opacity: 0.4; cursor: not-allowed; }
.doc-entry-actions button.primary:disabled {
    background: var(--border-strong); border-color: var(--border-strong); color: var(--muted); opacity: 1;
}

.doc-items-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; margin-bottom: 4px; }
.doc-items-table th, .doc-items-table td { padding: 5px 6px; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }
.doc-items-table th { color: var(--muted); font-weight: 700; font-size: 0.73rem; text-transform: uppercase; letter-spacing: 0.03em; background: #fafbfd; }
.doc-items-table tbody tr:hover { background: var(--bg); }
.doc-items-table td.empty { color: var(--muted); text-align: center; padding: 20px; white-space: normal; }
.doc-items-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.doc-items-wrap .doc-items-table { margin-bottom: 0; }
.doc-items-wrap .doc-items-table th:first-child, .doc-items-wrap .doc-items-table td:first-child { padding-left: 12px; }

.doc-items-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin: 6px 0 8px; flex-wrap: wrap; }
.doc-items-foot .doc-total-line { font-weight: 700; font-size: 0.92rem; color: var(--heading); }

.doc-bottom { display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 8px; }
.doc-remarks { flex: 2; min-width: 240px; }
.doc-remarks label { display: block; font-size: 0.74rem; color: var(--muted); font-weight: 700; margin-bottom: 3px; text-transform: uppercase; letter-spacing: 0.02em; }
.doc-remarks textarea { width: 100%; min-height: 44px; padding: 6px 9px; border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 0.88rem; font-family: inherit; resize: vertical; }
.doc-user { margin-top: 5px; font-size: 0.8rem; color: var(--muted); }
/* Two columns instead of one long vertical stack — same fields, same font
   and input sizes, roughly half the panel's height. .row.net (Total after
   Disc., Balance, ...) always spans the full width regardless of where it
   falls in the row order, so it still reads as the panel's own subtotal
   divider rather than getting lost paired up with an ordinary field. */
.doc-totals-panel {
    flex: 1.6; min-width: 300px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius);
    padding: 8px 10px; display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; align-content: start;
}
@media (max-width: 480px) { .doc-totals-panel { grid-template-columns: 1fr; } }
.doc-totals-panel .row { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 3px 0; font-size: 0.86rem; }
.doc-totals-panel .row.net { grid-column: 1 / -1; }
.doc-totals-panel .row label { color: var(--muted); font-weight: 600; margin: 0; white-space: nowrap; }
/* width:115px here needs !important: the global "every input is width:100%"
   reset rule near the top of this file (added to style unclassed report
   filter fields) has higher CSS specificity than this two-class selector —
   three :not() clauses outweigh two classes — so without it, it silently
   won the cascade despite being the earlier, more generic rule. The result
   was this input stretching to ~100% of the row instead of staying a fixed,
   right-aligned amount box, which combined with flex-shrink:0 (not fighting
   any other rule) forced the row wider than the card — the exact "totals
   card with its value cut off at the right edge" bug seen on narrow
   screens, and silently oversized on desktop too. */
.doc-totals-panel .row input { width: 115px !important; flex-shrink: 0; padding: 6px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); text-align: right; background: var(--surface); }
.doc-totals-panel .row.net { font-weight: 700; border-top: 1px solid var(--border-strong); padding-top: 9px; margin-top: 5px; }
.doc-totals-panel .row.net label { color: var(--heading); }
.doc-totals-panel .row.net input { background: var(--primary-light); color: var(--primary-dark); font-weight: 700; border-color: transparent; }

.doc-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; align-items: center; padding-top: 8px; border-top: 1px solid var(--border); }
.doc-actions button, .doc-actions a.btn {
    padding: 6px 12px; border-radius: var(--radius-sm); font-size: 0.85rem; font-weight: 600; cursor: pointer;
    border: 1px solid var(--border-strong); background: var(--surface); color: var(--text); text-decoration: none;
    transition: background var(--ease), border-color var(--ease), box-shadow var(--ease);
}
.doc-actions button:hover, .doc-actions a.btn:hover { background: var(--bg); border-color: var(--muted-2); }
.doc-actions button.primary { background: linear-gradient(180deg, var(--primary) 0%, var(--primary-dark) 100%); border-color: var(--primary-dark); color: #fff; }
.doc-actions button.primary:hover { filter: brightness(1.06); }
.doc-actions button.secondary { background: var(--surface); }
/* The global button.primary/button.secondary rules add a 10px margin-top
   (and button.secondary a margin-left) meant for buttons sitting alone under
   a form. Inside this flex row that pushes just the Save button down out of
   line with its plain siblings (New/Prev/Next/…), so cancel both margins
   here to keep every button in the row vertically centered together. */
.doc-actions button.primary, .doc-actions button.secondary { margin-top: 0; margin-left: 0; }
.doc-actions button:disabled { opacity: 0.4; cursor: not-allowed; }
.doc-actions button.primary:disabled {
    background: var(--border-strong); border-color: var(--border-strong); color: var(--muted); opacity: 1;
}
.doc-actions .spacer { flex: 1; min-width: 8px; }
.doc-import-row { margin-bottom: 10px; }

.doc-unlock-bar { display: flex; align-items: center; gap: 10px; margin: 4px 0 10px; }
.doc-unlock-bar button {
    background: var(--surface);
    color: var(--primary-dark);
    border: 1px solid var(--primary);
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--ease), color var(--ease);
}
.doc-unlock-bar button:hover { background: var(--primary); color: #fff; }
.doc-unlock-bar button.secondary { background: var(--surface); color: var(--text); border: 1px solid var(--border-strong); }
.doc-unlock-bar button.secondary:hover { background: var(--bg); color: var(--text); }


/* Transaction list widget (Purchases-style list-first view) */
.txn-list-controls { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 8px; }
.txn-list-show, .txn-list-search { font-size: 0.85rem; color: var(--muted); font-weight: 600; display: flex; align-items: center; gap: 6px; }
.txn-list-show select { padding: 5px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.txn-list-search input { padding: 5px 9px; border: 1px solid var(--border); border-radius: var(--radius-sm); min-width: 200px; }
.txn-list-table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); }
.txn-list-table { width: 100%; border-collapse: collapse; font-size: 0.83rem; margin-bottom: 0; }
.txn-list-table th, .txn-list-table td { padding: 6px 9px; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }
.txn-list-table th { color: var(--muted); font-weight: 700; font-size: 0.73rem; text-transform: uppercase; letter-spacing: 0.03em; background: #fafbfd; }
.txn-list-table tbody tr:hover { background: var(--bg); }
.txn-list-table td.empty { color: var(--muted); text-align: center; padding: 24px; white-space: normal; }
.txn-list-table tr.cancelled td { color: var(--danger); }
.txn-list-actions { display: flex; gap: 6px; white-space: nowrap; }
.txn-list-actions button {
    width: 28px; height: 26px; border: 1px solid var(--border); background: var(--surface); border-radius: var(--radius-sm);
    cursor: pointer; font-size: 0.88rem; transition: background var(--ease), color var(--ease), border-color var(--ease);
}
.txn-list-actions button:hover { background: var(--primary); color: #fff; border-color: var(--primary); }
.txn-list-footer { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 8px; font-size: 0.8rem; color: var(--muted); }
.txn-list-pagination { display: flex; gap: 4px; flex-wrap: wrap; }
.txn-page-btn { padding: 5px 10px; border: 1px solid var(--border); background: var(--surface); border-radius: var(--radius-sm); cursor: pointer; font-size: 0.8rem; color: var(--text); transition: background var(--ease), color var(--ease); }
.txn-page-btn:hover { background: var(--bg); }
.txn-page-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }
.txn-page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.txn-add-new-bar { margin-bottom: 10px; }
.txn-add-new-bar button {
    background: var(--success); color: #fff; border: 1px solid var(--success); padding: 7px 14px; border-radius: var(--radius-sm);
    font-size: 0.88rem; cursor: pointer; font-weight: 600; box-shadow: var(--shadow-xs); transition: background var(--ease);
}
.txn-add-new-bar button:hover { background: #187a47; }
.cancelled { color: var(--danger); }

/* Friendly toast notifications — replaces the native alert() popup app-wide
   (see js/api.js). Stacks in the bottom-right corner, above everything
   else, and never blocks the page underneath it. */
#gpos-toast-container {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 360px;
    pointer-events: none;
}
.gpos-toast {
    pointer-events: auto;
    background: var(--ink-2);
    color: #fff;
    border-left: 4px solid var(--primary);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
    box-shadow: var(--shadow-lg);
    font-size: 0.86rem;
    line-height: 1.4;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    animation: gpos-toast-in 180ms ease-out;
}
.gpos-toast span { flex: 1; white-space: pre-line; word-break: break-word; }
.gpos-toast-close {
    background: none; border: none; box-shadow: none; color: rgba(255,255,255,0.7);
    font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 0 2px; margin: 0;
}
.gpos-toast-close:hover { color: #fff; background: none; }
.gpos-toast-out { animation: gpos-toast-out 180ms ease-in forwards; }
@keyframes gpos-toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes gpos-toast-out { from { opacity: 1; } to { opacity: 0; transform: translateY(4px); } }
@media print { #gpos-toast-container { display: none !important; } }

/* Settings — a left-hand section nav + one visible card at a time, instead
   of every section stacked into one long scrolling column. Non-admin users
   never see the nav (they only ever get the Change Password card), so this
   only engages for admins. */
.settings-layout { display: flex; align-items: flex-start; gap: 24px; }
.settings-nav {
    flex: 0 0 200px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    position: sticky;
    top: 18px;
}
.settings-nav button {
    text-align: left;
    padding: 10px 14px;
    border: 1px solid transparent;
    background: none;
    box-shadow: none;
    border-radius: var(--radius-sm);
    font-size: 0.87rem;
    font-weight: 600;
    color: var(--text);
    margin: 0;
}
.settings-nav button:hover { background: var(--bg); box-shadow: none; }
.settings-nav button.active { background: var(--primary-light); color: var(--primary-dark); }
.settings-panes { flex: 1; min-width: 0; }
.settings-panes .card { max-width: 760px; }
@media (max-width: 860px) {
    .settings-layout { flex-direction: column; }
    .settings-nav { flex-direction: row; flex-wrap: wrap; position: static; width: 100%; }
}

/* IMEI entry — scan/type one, click Add (or press Enter), it drops into a
   removable chip list. Also accepts a comma/newline-separated paste for
   bulk-adding several IMEIs in one shot. Used on Purchase entry. */
.imei-add-bar { display: flex; gap: 8px; align-items: flex-start; }
.imei-add-bar textarea { flex: 1; min-height: 38px; resize: vertical; }
.imei-add-bar button { flex-shrink: 0; white-space: nowrap; margin: 0; }
.imei-chip-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.imei-chip-list:empty { margin-top: 0; }
.imei-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--primary-50);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 0.82rem;
    font-weight: 600;
    padding: 4px 6px 4px 10px;
    border-radius: 999px;
}
.imei-chip button {
    all: unset;
    cursor: pointer;
    color: var(--muted);
    font-size: 0.75rem;
    line-height: 1;
    padding: 2px 5px;
    border-radius: 50%;
}
.imei-chip button:hover { background: var(--danger-light); color: var(--danger); }
/* Flags an IMEI that isn't the standard 15-digit length — still added (a
   scanner or a supplier list can occasionally be right when the rule of
   thumb isn't), just visibly called out so it gets a second look. */
.imei-chip-warn { background: var(--warning-light); border-color: var(--warning); color: var(--warning); }

/* ===== Marketplace Orders (marketplace-orders.html) — one card per order
   instead of a dense table, so a long error message has room to be laid
   out clearly instead of being crammed into a table cell. ===== */
.mkt-order {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 11px 14px;
    margin-bottom: 9px;
    background: var(--surface);
    box-shadow: var(--shadow-xs);
}
.mkt-order-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; flex-wrap: wrap; }
.mkt-order-main { display: flex; flex-direction: column; gap: 2px; }
.mkt-order-id { font-weight: 700; color: var(--heading); font-size: 0.95rem; }
.mkt-order-meta { color: var(--muted); font-size: 0.8rem; }
.mkt-order-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }

.mkt-pill {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 11px; border-radius: 20px;
    font-size: 0.74rem; font-weight: 700; letter-spacing: 0.02em; white-space: nowrap;
}
.mkt-pill.ok { background: var(--success-light); color: var(--success); }
.mkt-pill.pending { background: var(--bg); color: var(--muted); border: 1px solid var(--border); }
.mkt-pill.unmapped { background: var(--danger-light); color: var(--danger); }
.mkt-pill.stock { background: var(--warning-light); color: var(--warning); }
.mkt-pill.other { background: var(--danger-light); color: var(--danger); }

.mkt-reason {
    margin-top: 9px; padding: 9px 11px;
    border-radius: var(--radius-sm);
    font-size: 0.85rem; line-height: 1.45;
    background: var(--bg); border: 1px solid var(--border);
}
.mkt-reason-title { font-weight: 700; color: var(--heading); display: block; margin-bottom: 2px; }
.mkt-reason code, .code-chip {
    background: var(--surface); border: 1px solid var(--border); border-radius: 4px;
    padding: 1px 6px; font-size: 0.82rem; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    display: inline-block;
}
/* ===== Marketplace SKU Mapping (marketplace-sku-map.html) ===== */
.mkt-map-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mkt-map-arrow { color: var(--muted-2); }
.mkt-reason .mkt-qty { font-weight: 700; }
.mkt-reason .mkt-qty.short { color: var(--danger); }
.mkt-actions { margin-top: 9px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.mkt-actions a.button-link {
    display: inline-flex; align-items: center;
    border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
    padding: 7px 13px; font-size: 0.85rem; font-weight: 600;
    color: var(--text); text-decoration: none; background: var(--surface);
    transition: background var(--ease), border-color var(--ease);
}
.mkt-actions a.button-link:hover { background: var(--bg); border-color: var(--muted-2); }

/* ===== Items screen (items.html) ===== */
.items-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.items-toolbar input { max-width: 280px; }
.items-toolbar button.primary { margin: 0; }
/* Amazon SKU field — set apart from the rest of the Add/Edit Item form
   (a soft tinted panel, not just another .form-row) so it reads as a
   distinct "this is a marketplace link, not part of the catalogue record
   itself" area rather than blending in with Code/Name/Price. */
.sku-section {
    margin-top: 14px;
    padding: 11px 13px 13px;
    border-radius: var(--radius);
    background: rgba(224, 142, 11, 0.055);
    border: 1px solid var(--border);
}
.sku-section h3 {
    display: flex; align-items: center; gap: 8px;
    font-size: 0.85rem; font-weight: 700; color: var(--heading);
    margin: 0 0 8px;
}

/* ===== Marketplace Settings (marketplace-settings.html) — groups the
   long credentials form (left) alongside the shorter behavior/backfill/
   cron cards (right) using the same 2fr/1fr grid the dashboard uses, so a
   wide screen is put to use instead of stacking everything into one long
   scroll with empty space beside it. ===== */
.mkt-settings-side { display: flex; flex-direction: column; gap: 10px; }
