/* SME ERP - shared dark navy theme (styled after the reference BankNote app) */

:root {
  --bg: #0a1628;
  --bg-elevated: #0f2038;
  --bg-panel: #132743;
  --bg-panel-alt: #17304f;
  --border: #23405f;
  --border-soft: #1b3450;
  --text: #eaf0f8;
  --text-muted: #9db2cc;
  --text-faint: #6f849f;
  --accent: #4a9de0;
  --accent-strong: #2f7dc2;
  --accent-soft: rgba(74, 157, 224, 0.15);
  --gold: #c9a24b;
  --danger: #d9645a;
  --danger-soft: rgba(217, 100, 90, 0.15);
  --success: #4fae7a;
  --success-soft: rgba(79, 174, 122, 0.15);
  --radius: 10px;
  --shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  font-size: 15px;

  /* ---------- Color Settings (System Settings -> Color Settings) ----------
     Ten user-configurable parts of the screen, named the way they look
     to a user (Page Header, Page Background, Menu Bar, Forms, Pop-up
     Forms, Fields, Lists, List Headers, Buttons, Tabs), each with its own
     background + foreground (text) variable so one part never touches
     another. Defaults reproduce today's look exactly - js/theme.js only
     overrides these on top, never the structural background and text variables above.
     A blank foreground is derived from the background's brightness
     (js/theme.js contrastFg()). When a part is customized js/theme.js adds
     a `theme-<part>` class on <html>; the conditional rules further down
     use it to make that part's secondary text (labels, hints, ghost
     buttons) follow the chosen foreground without altering the default. */
  --theme-page-bg: var(--bg);                      /* Page Background */
  --theme-page-fg: var(--text);
  --theme-form-bg: var(--bg-elevated);            /* Forms (content panels) */
  --theme-form-fg: var(--text);
  --theme-popup-bg: var(--bg-elevated);           /* Pop-up Forms */
  --theme-popup-fg: var(--text);
  --theme-list-bg: transparent;                   /* Lists (table rows) */
  /* --theme-list-fg: deliberately not defined by default - see tbody td */
  --theme-list-header-bg: var(--bg-elevated);   /* List Headers */
  --theme-list-header-fg: var(--text-faint);
  --theme-button-bg: linear-gradient(180deg, var(--accent), var(--accent-strong)); /* Buttons */
  --theme-button-fg: #fff;
  --theme-header-bg: linear-gradient(180deg, #0d1e36, #0a1628); /* Page Header (top bar) */
  --theme-header-fg: var(--text);
  --theme-menubar-bg: var(--bg-elevated);         /* Menu Bar (page-title strip + side menus) */
  --theme-menubar-fg: var(--text);
  --theme-field-bg: var(--bg-panel);              /* Fields (inputs, dropdowns) */
  --theme-field-fg: var(--text);
  --theme-button2-bg: transparent;                /* Secondary Buttons (Back, Cancel, Edit, filters) */
  --theme-button2-fg: var(--text-muted);
  --theme-tab-bg: transparent;           /* Tabs (inactive) */
  /* --theme-tab-fg: deliberately not defined by default - see .tab-btn */
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  padding: 0;
}

/* Test 2, item 6.1: "2 scrolls on the same page is not good." The shell
   (topbar + page + footer) is pinned to exactly the viewport height and
   never scrolls itself; only the .list-area regions inside a page's main
   panel (see below) scroll, so there is always at most one scrollbar
   visible at a time. */
body {
  background: var(--theme-page-bg);
  color: var(--theme-page-fg);
  font-family: "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}

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

/* ---------- Top bar ---------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 7px 24px;
  background: var(--theme-header-bg);
  color: var(--theme-header-fg);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.topbar .brand {
  display: flex;
  align-items: center;
  gap: 10px;
}

.topbar .brand .mark {
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--gold);
  text-transform: uppercase;
  font-size: 0.95rem;
}

/* Company logo, injected by js/api.js's applyBranding() when one has been
   uploaded via System Settings. Sized to sit comfortably next to the
   company name without dominating the header. */
.topbar .brand .brand-logo {
  height: 32px;
  max-width: 160px;
  width: auto;
  object-fit: contain;
  border-radius: 4px;
}

.topbar .brand .sub {
  color: var(--theme-header-fg);
  opacity: 0.7;
  font-size: 0.85rem;
}

.topbar .user-area {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 0.9rem;
  color: var(--theme-header-fg);
  opacity: 0.8;
}

.topbar .user-area strong { color: var(--theme-header-fg); opacity: 1; }

/* Back (Version 3.6): the only button in the Page Header; uses the header's
   text colour so it reads on any header colour. */
.topbar .user-area .header-back { color: var(--theme-header-fg); border-color: currentColor; opacity: 1; min-width: 84px; }

/* ---------- Buttons ---------- */
button, .btn {
  font-family: inherit;
  font-size: 0.92rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
  padding: 9px 16px;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.05s ease;
}

button:hover, .btn:hover { filter: brightness(1.15); }
button:active, .btn:active { transform: translateY(1px); }
button:disabled, .btn:disabled { opacity: 0.45; cursor: not-allowed; filter: none; }

.btn-primary {
  /* "Buttons" (Color Settings) */
  background: var(--theme-button-bg);
  border-color: var(--accent-strong);
  color: var(--theme-button-fg);
  font-weight: 600;
}
.theme-button .btn-primary { border-color: transparent; }

/* "Menus" (Color Settings): the Home page module tiles and the module
   landing pages' menu buttons (a .btn-primary carrying .menu-btn). Only
   the .menu-btn rule is unconditional (its default equals .btn-primary's);
   the module tiles keep their own look until Menus is customized. */
.theme-button .module-btn {
  background: var(--theme-button-bg);
  color: var(--theme-button-fg);
  border-color: transparent;
}

.btn-ghost {
  /* "Secondary Buttons" (Color Settings): Back, Cancel, Edit, filter
     buttons, Sign Out... By default they have no fill of their own, so
     they take on the look of whatever part of the screen they sit on (see
     the region rules below). Once Secondary Buttons is customized, the
     html.theme-button2 rules near the end of this file take over
     everywhere, so they all match regardless of where they sit. */
  background: transparent;
  border-color: var(--border);
  /* Same colour as the text around it (the Form, Pop-up, Page Header,
     list row... it sits on), slightly dimmed - so it's always readable,
     whatever colours are chosen. */
  color: inherit;
  opacity: 0.8;
}
.btn-ghost:hover { opacity: 1; }
/* Once any part of the screen is customized, the outline follows the
   text colour too (the built-in navy outline can vanish on a custom
   background). The default look keeps its subtle navy outline. */
html[class*="theme-"] .btn-ghost { border-color: currentColor; }
/* A filter/toggle button that is currently applied (e.g. Orders list
   Pendings / In Process / Active / All). Uses currentColor so it reads
   as "selected" under any color scheme. */
.btn-ghost.is-selected {
  box-shadow: inset 0 0 0 2px currentColor;
  font-weight: 700;
  opacity: 1;
}

/* Unify the look of buttons (Version 3 feedback): every destructive
   action in the app - Delete, Remove, Decline, and so on - now shares
   this one class, instead of some being plain btn-ghost (no danger
   indication at all until a red confirm dialog appears) and others
   using a one-off inline red style. .btn-deny used to duplicate this
   with a slightly different text color/weight for no real reason - it's
   gone now, .btn-danger is the only destructive style. */
.btn-danger {
  background: linear-gradient(180deg, #e17b72, var(--danger));
  border-color: var(--danger);
  color: #fff;
  font-weight: 600;
}

.btn-allow {
  background: linear-gradient(180deg, #5cc088, var(--success));
  border-color: var(--success);
  color: #06210f;
  font-weight: 600;
}

.btn-sm { padding: 5px 10px; font-size: 0.8rem; border-radius: 6px; }
.btn-icon { width: 34px; height: 34px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }

/* ---------- Layout helpers ---------- */
.page {
  flex: 1;
  min-height: 0; /* let a .panel-main child's own .list-area do the scrolling instead of the page itself */
  display: flex;
  flex-direction: column;
  padding: 8px 24px 6px;
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  gap: 8px;
  /* auto, not hidden: on a normal-height window .panel-main's .list-area
     absorbs all the scrolling on its own, so this never engages and
     there's only ever one visible scrollbar. It's a safety net for a
     short window/low resolution where even the compacted chrome (topbar
     + toolbar panels + footer) doesn't leave the list area's minimum
     height to work with - the page scrolls as a whole rather than
     silently clipping content with no way to reach it. */
  overflow-y: auto;
  overflow-x: hidden;
}

.panel {
  /* "Main Form" (Color Settings). Color is explicit, not inherited from
     body, so a customized General background never bleeds its text color
     into panels that kept their own background. */
  background: var(--theme-form-bg);
  color: var(--theme-form-fg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 10px 14px;
  flex-shrink: 0; /* toolbar/hint/summary panels keep their natural height */
}

/* "Menu Bar" (Color Settings): the page-title strip with the Back
   button, and the side menus on Settings / module landing pages. */
.panel.toolbar, .panel.menu-panel {
  background: var(--theme-menubar-bg);
  color: var(--theme-menubar-fg);
}
.theme-menubar .panel.toolbar .panel-title, .theme-menubar .panel.menu-panel .panel-title { color: inherit; }

/* "Pop-up Forms" (Color Settings): every modal in this app is a
   .modal-backdrop > .modal > .panel - the inner .panel is the surface
   people actually see (it fully covers .modal's own background), so
   that's what --theme-popup-bg/-fg targets. */
.modal .panel {
  background: var(--theme-popup-bg);
  color: var(--theme-popup-fg);
}

/* Secondary text inside a themed region (labels, hints, panel titles,
   "nothing here yet" messages) has fixed muted colors that go
   low-contrast against a light custom background. When a region is
   customized (js/theme.js adds the theme-<region> class on <html>), they
   follow that region's foreground instead. Scoped to the class so the
   default look is unchanged. (Secondary buttons need no rule here - they
   always take the colour of the text around them; see .btn-ghost.) */
.theme-form .panel label, .theme-form .panel .hint, .theme-form .panel .panel-title,
.theme-popup .modal .panel label, .theme-popup .modal .panel .hint, .theme-popup .modal .panel .panel-title {
  color: inherit;
}
.theme-form .panel .hint, .theme-popup .modal .panel .hint { opacity: 0.75; }
.theme-form .panel .empty-state, .theme-popup .modal .panel .empty-state { color: inherit; opacity: 0.7; }
/* Row hover on a custom list color: darken slightly instead of jumping
   to the dark --bg-panel. */
.theme-list tbody tr.clickable:hover { background: transparent; filter: brightness(0.93); }
/* ...and on a custom Form / Pop-up colour (rows showing that colour
   through), a light shade instead of the built-in dark navy. */
.theme-form .panel tbody tr.clickable:hover,
.theme-popup .modal .panel tbody tr.clickable:hover { background: rgba(0, 0, 0, 0.06); }

/* The one panel per page that holds the main scrolling list/table - it
   fills whatever vertical space is left after the other (flex-shrink:0)
   panels on the page, and its .list-area child is the ONLY thing that
   scrolls (see .list-area below). Test 2, item 6.1/6.3: "Apply this
   concept to all pages" / "fit everything on one page without outer
   scrolling." */
.panel-main {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.panel-title {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-faint);
  margin: 0 0 10px;
}

.row { display: flex; gap: 14px; }
.row.wrap { flex-wrap: wrap; }
.grow { flex: 1; }

/* ---------- Forms ---------- */
label {
  display: block;
  font-size: 0.7rem;
  color: var(--text-muted);
  margin-bottom: 3px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

input[type="text"], input[type="password"], input[type="date"], input[type="time"], input[type="number"], select, textarea {
  width: 100%;
  background: var(--theme-field-bg); /* "Fields" (Color Settings) */
  border: 1px solid var(--border);
  color: var(--theme-field-fg);
  border-radius: 7px;
  padding: 5px 10px;
  font-size: 0.9rem;
  font-family: inherit;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ---------- Color Settings: swatch + hex text field pairs ---------- */
input.color-swatch[type="color"] {
  width: 46px;
  height: 34px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--bg-panel);
  cursor: pointer;
}
input.color-swatch[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
input.color-swatch[type="color"]::-webkit-color-swatch { border: none; border-radius: 4px; }
input.color-hex[type="text"] { text-transform: uppercase; }
input.color-hex[type="text"]::placeholder { text-transform: none; }

/* Tightened again (was 14px, then 10px) - still not cramped at this
   size, and every px here is one you don't get back on Order Details,
   where several of these rows stack above Order Contents. */
.field { margin-bottom: 7px; }
.field-inline { display: flex; align-items: center; gap: 8px; }

.hint { color: var(--text-faint); font-size: 0.78rem; margin-top: 4px; }
.error-text { color: var(--danger); font-size: 0.85rem; min-height: 1.2em; }

/* ---------- Pills (branch tags) ---------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--bg-panel-alt);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 8px 6px 14px;
  font-size: 0.85rem;
  color: var(--text);
}

.pill .x {
  cursor: pointer;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--danger-soft);
  color: var(--danger);
  font-size: 0.75rem;
  line-height: 1;
}

.pill .x:hover { filter: brightness(1.3); }

.pill-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; min-height: 34px; }

/* ---------- Tables ---------- */
table { width: 100%; border-collapse: collapse; font-size: 0.88rem; background: var(--theme-list-bg); }

/* Test 2, item 8: all amount/quantity figures should always be
   right-aligned - applied to the <td> (or a header <th class="num">
   to match) wherever a JS renderer marks a numeric cell. Tabular
   (fixed-width) figures keep the digits themselves lined up too,
   not just the cell edge. */
.num {
  text-align: right !important;
  font-variant-numeric: tabular-nums;
}

thead th {
  text-align: left;
  color: var(--theme-list-header-fg);
  text-transform: uppercase;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  padding: 5px 10px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--theme-list-header-bg);
}

/* Modification Request: "Align the column heading alignment with the
   alignment of the column content" - a header reuses the same .num class
   as its column's <td> cells, so numeric columns right-align their
   heading too instead of always sitting left like every text column. */
thead th.num { text-align: right; }

/* Modification Request: "allow user to resize the column" - the drag
   handle enableColumnResize() (js/api.js) adds to every header but the
   last. th needs a positioning context for it; thead th's own
   position:sticky above already establishes one, so no extra rule is
   needed for that part. */
.col-resize-handle {
  /* Sits wholly INSIDE its own header cell, at the right edge. It used to
     straddle the border (right:-3px), but the next header paints over that
     outer half, so grabbing the line dead-centre often missed it. */
  position: absolute;
  top: 0;
  right: 0;
  width: 8px;
  height: 100%;
  cursor: col-resize;
  user-select: none;
  touch-action: none;
  z-index: 1;
}
.col-resize-handle:hover,
.col-resize-handle:active {
  background: var(--accent);
  opacity: 0.5;
}

/* Modification Request: "allow users to change the sorting-order of the
   columns" - a clickable header (see makeSortableHeader() in js/api.js)
   gets a pointer cursor and a small arrow showing the active sort
   column/direction. */
thead th.sortable {
  cursor: pointer;
  user-select: none;
}
thead th.sortable:hover { color: var(--text-muted); }
thead th.sortable::after {
  content: "";
  display: inline-block;
  width: 0.7em;
  margin-left: 2px;
}
thead th.sortable.sort-asc::after { content: "\25B2"; }
thead th.sortable.sort-desc::after { content: "\25BC"; }

/* Tightened again ("row heights ... still too tall") - was 11px/12px,
   then 6px/10px. */
tbody td {
  padding: 4px 10px;
  border-bottom: 1px solid var(--border-soft);
  /* Lists have no fill of their own by default, so rows show whatever
     they sit on (a Form, a Pop-up). Their text must then follow that
     same part's text colour - hence "inherit" unless Lists is customized
     (js/theme.js only defines --theme-list-fg when it is). */
  color: var(--theme-list-fg, inherit);
  font-size: 0.86rem;
}

tbody tr { transition: background 0.1s ease; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover { background: var(--bg-panel); }

.scroll-area {
  overflow-y: auto;
  /* Modification Request: resizable columns can now push a table wider
     than its panel - scroll horizontally inside this box instead of
     overflowing the page (the Incoterm page already did this by hand
     with an inline style for its always-wide table; this makes it the
     default everywhere so growing a column never breaks layout). */
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
}

/* The confined, single scrollbar for a page's main list - lives inside
   a .panel-main (see above) and takes over whatever space the panel has
   instead of a hardcoded max-height, so the page itself never needs a
   second, outer scrollbar. Sits directly on .panel-main with no extra
   border/background of its own (the panel already has both). */
.list-area {
  flex: 1;
  /* Follow-up fix: 60px let this shrink to little more than a sliver -
     one row, easily read as "the list is missing" - before the .page
     fallback scroll (see above) ever got a chance to kick in, because
     flexbox starves a min-height:0/low-min-height child before it lets
     its ancestor overflow. 140px guarantees a handful of usable rows;
     below that, .page scrolls as a whole instead of the list quietly
     disappearing. */
  min-height: 140px;
  overflow-y: auto;
  /* Modification Request: same reasoning as .scroll-area above - lets a
     column-resized table scroll sideways in its own box. */
  overflow-x: auto;
}

/* ---------- Status badges ---------- */
.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
}

.badge-active { background: var(--success-soft); color: var(--success); }
.badge-inactive { background: var(--danger-soft); color: var(--danger); }
.badge-allow { background: var(--success-soft); color: var(--success); }
.badge-deny { background: var(--danger-soft); color: var(--danger); }
.badge-power { background: rgba(201, 162, 75, 0.18); color: var(--gold); }

/* ---------- Module grid (Home Page) ---------- */
.welcome {
  text-align: center;
  margin: 6px 0 8px;
}

.welcome h1 { font-size: 1.4rem; margin: 0 0 4px; color: var(--text); }
.welcome p { color: var(--text-muted); margin: 0; }

.module-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-top: 10px;
}

@media (max-width: 640px) {
  .module-grid { grid-template-columns: 1fr; }
}

.module-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 22px 18px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: linear-gradient(180deg, var(--bg-panel-alt), var(--bg-panel));
  color: var(--text);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  transition: filter 0.15s ease, border-color 0.15s ease;
}

.module-btn:hover:not(.disabled) {
  filter: brightness(1.15);
  border-color: var(--accent);
}

.module-btn.disabled {
  color: var(--text-faint);
  cursor: not-allowed;
  opacity: 0.55;
}

.module-btn .tag {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  background: rgba(255,255,255,0.08);
  padding: 2px 7px;
  border-radius: 999px;
}

/* ---------- Login ---------- */
.login-wrap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-card {
  width: 340px;
  /* The Sign In box is a Form like any other. */
  background: var(--theme-form-bg);
  color: var(--theme-form-fg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 30px 28px;
}

.login-card .mark {
  color: var(--gold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  font-size: 0.95rem;
  margin-bottom: 4px;
}

.login-card .brand-logo {
  display: block;
  height: 44px;
  max-width: 100%;
  object-fit: contain;
  margin: 0 0 10px;
}

.login-card h1 { font-size: 1.15rem; margin: 0 0 20px; color: var(--text); }

/* ---------- Page footer (screen name + build tag) ----------
   Test 2, item 6.3: these were "position:fixed" floating overlays in
   the page's bottom corners, which could sit on top of real content
   (the Incoterm screenshot showed the build tag overlapping the table)
   - "I suggest we make a page footer." Now a normal-flow strip pinned
   to the bottom of the viewport by the body/.page flex layout (see
   body/.page above), so it never overlaps content and never needs to
   float over anything. .screen-tag (left) and .build-tag (right) keep
   their own names/classes for the id-per-screen convention (spec 2.1)
   and the honest-stale-cache purpose of the build tag, but are now
   plain inline elements laid out by .page-footer instead of each
   separately fixed-positioning itself. */
/* Version 3.6: the footer is a full-width strip in the Page Header's
   colours (same width, same "Page Header" colour setting), with the
   screen name on the left, who is signed in in the middle and the build
   on the right. */
.page-footer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 5px 24px;
  width: 100%;
  box-sizing: border-box;
  background: var(--theme-header-bg);
  color: var(--theme-header-fg);
  border-top: 1px solid var(--border);
}

.screen-tag,
.build-tag {
  font-size: 0.7rem;
  color: inherit;
  opacity: 0.75;
  letter-spacing: 0.03em;
  background: transparent;
  border: 1px solid rgba(128, 128, 128, 0.5);
  padding: 2px 9px;
  border-radius: 6px;
  white-space: nowrap;
}

.page-footer .footer-user {
  flex: 1;
  text-align: center;
  font-size: 0.85rem;
  opacity: 0.85;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.page-footer .footer-user strong { opacity: 1; }

/* Main Menu: Exit (sign out and close the app) under the module tiles. */
.home-exit { display: flex; justify-content: center; margin-top: 22px; }
.home-exit .btn-danger { min-width: 220px; padding: 10px 18px; font-weight: 600; }

/* ---------- Toolbar (fixed, non-scrollable top section) ---------- */
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.toolbar .actions { display: flex; gap: 10px; }

/* ---------- Modal (User Details Form opens as an overlay) ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(4, 9, 18, 0.65);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  overflow-y: auto;
  padding: 40px 16px;
  z-index: 100;
}

.modal {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  width: 100%;
  max-width: 1080px;
}

/* ---------- User Details Form: basic info (left) + branches (right) ---------- */
.details-grid {
  display: flex;
  gap: 24px;
  align-items: stretch;
}

.details-left {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.details-right {
  flex: 0 0 300px;
  background: var(--bg-panel-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px;
  display: flex;
  flex-direction: column;
}

.details-right .pill-row { flex: 1; align-content: flex-start; }

@media (max-width: 760px) {
  .details-grid { flex-direction: column; }
  .details-right { flex: 0 0 auto; }
}

.toast {
  position: fixed;
  top: 18px;
  right: 18px;
  background: var(--bg-panel-alt);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 12px 18px;
  border-radius: 8px;
  box-shadow: var(--shadow);
  z-index: 200;
  font-size: 0.88rem;
}

.toast.success { border-color: var(--success); color: var(--success); }
.toast.error { border-color: var(--danger); color: var(--danger); }

.empty-state {
  text-align: center;
  color: var(--text-faint);
  padding: 30px;
  font-size: 0.9rem;
}

/* .build-tag itself is defined above, alongside .screen-tag, as part of
   .page-footer - kept as a plain, static marker baked directly into
   each page's HTML (not set by JavaScript) so that even a stale,
   browser-cached copy of a page still shows an honest (old) build
   string instead of silently looking current. If what's on screen
   doesn't match the build just delivered, that's proof the browser is
   serving a cached/older copy of this exact file, not a bug in the app
   itself. */

/* ---------- Combobox (searchable / type-to-filter dropdown) ---------- */
.combo-wrap { position: relative; }

.combo-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 240px;
  overflow-y: auto;
  background: var(--bg-panel);
  border: 1px solid var(--accent);
  border-radius: 8px;
  box-shadow: var(--shadow);
  z-index: 60;
}

.combo-option {
  padding: 8px 12px;
  font-size: 0.88rem;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.combo-option:hover, .combo-option.active { background: var(--accent-soft); }

.combo-empty {
  padding: 8px 12px;
  font-size: 0.85rem;
  color: var(--text-faint);
}

/* ---------- Tabs (Order Details page) ----------
   Follow-up fix: now sits on the SAME row as the action buttons (see
   .order-header-frozen below) instead of on its own row underneath them,
   so no border-bottom/margin-bottom of its own - the active tab's own
   2px accent underline (.tab-btn.active) is enough of an indicator
   without a full-width rule under the whole group. */
.tabs-bar {
  display: flex;
  gap: 4px;
}

.tab-btn {
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  padding: 7px 14px;
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.9rem;
}

.tab-btn:hover { filter: none; color: var(--text); }
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }

/* "Inactive Tabs" (Color Settings) - applies to the Order Details tab
   strip and the Settings page's left-hand sub-menu (.settings-nav-btn,
   which shares .tab-btn). Active tab keeps the accent look. */
.tab-btn:not(.active) {
  background: var(--theme-tab-bg);
  /* Same reasoning as list rows: with no fill of their own by default,
     inactive tabs take the text colour of what they sit on (dimmed),
     unless Tabs is customized. */
  color: var(--theme-tab-fg, inherit);
}
html:not(.theme-tab) .tab-btn:not(.active) { opacity: 0.7; }
html:not(.theme-tab) .tab-btn:not(.active):hover { opacity: 1; }
.theme-tab .tab-btn:not(.active) { border-radius: 8px; }
.theme-tab .tab-btn:not(.active):hover { color: var(--theme-tab-fg); filter: brightness(0.92); }

/* Settings page left-hand sub-menu - reuses .tab-btn's look & feel but
   laid out as a vertical sidebar instead of a horizontal tab strip. */
.settings-nav-btn {
  border: 1px solid transparent;
  border-bottom: 1px solid transparent;
  border-radius: 8px;
  padding: 10px 12px;
  width: 100%;
}
.settings-nav-btn.active {
  background: var(--accent-soft);
  border-color: var(--border);
}

/* A subform's "add new line" input row - given a slightly different
   background than the list below it, per your Version 1 test feedback,
   so it visually reads as "entry area" vs. "the list". */
.subform-input-row {
  background: var(--bg-panel-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px;
  margin-bottom: 8px;
}
/* With a customized Forms colour, the entry strip becomes a slightly
   darker shade of that same colour (so its labels, which follow the
   Forms text colour, stay readable) instead of staying dark navy. */
.theme-form .subform-input-row,
.theme-form .details-right {
  background: rgba(0, 0, 0, 0.06);
  border-color: rgba(0, 0, 0, 0.12);
}

/* Test 2, item 6.1/6.2: the Order Contents / Payment Ledger Total row is
   pinned to the bottom of its .list-area's own scroll viewport (not the
   page), so it's always visible without scrolling down to the end of a
   long list. Solid background is required for sticky cells - otherwise
   scrolled-past rows would show through underneath them. */
.totals-row td {
  font-weight: 700;
  border-top: 2px solid var(--border);
  background: var(--bg-panel);
  position: sticky;
  bottom: 0;
}

/* Order Details page: action buttons + tabs merged into one panel that
   stays pinned to the top of the window while the tab content below it
   scrolls, per your feedback ("merge and freeze"). The title line that
   used to sit above the buttons is gone (redundant), and the tabs now
   share the same row as the buttons instead of a row of their own -
   together that's one whole row's height reclaimed for Order Contents
   below, which is what was leaving it squeezed almost to nothing at a
   normal (non-fullscreen) browser window height. */
.order-header-frozen {
  position: sticky;
  top: 0;
  z-index: 15;
  margin-bottom: 0;
  padding: 10px 16px;
}

/* Each Order Details tab panel (Details / Payment / Log) - a flex column
   so its own list-area can flex-fill the rest of the tab and be the one
   thing that scrolls, matching the .panel-main/.list-area pattern used
   everywhere else. display:flex here is the fallback the tab-switching
   JS lands on when it clears the inline "display:none" on the active
   tab (element.style.display = ""). */
.order-tab {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1;
}

/* An inline status dropdown on an existing Order Log row (Power User
   only - matches the same edit permission as Payment Ledger rows). */
.log-status-select {
  background: var(--bg-panel-alt);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 0.85rem;
}

/* Inline editable cells on the Pricing & Transfer tab (Phase 3.1) - each
   Order Contents row is edited directly in the list, since that tab has
   no separate "+ Add" row to stage values in first. */
.table-inline-input {
  width: 100%;
  min-width: 90px;
  background: var(--bg-panel-alt);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 6px;
  font-size: 0.85rem;
  box-sizing: border-box;
}

/* ---------- Print (Order / Payment Order printable views) ----------
   Applied inside the dedicated print window opened by window.print()
   helpers - light background, since almost nobody prints a dark page. */
.print-doc {
  font-family: "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif;
  color: #111;
  background: #fff;
  padding: 30px 36px;
  max-width: 800px;
  margin: 0 auto;
}

.print-doc h1 { font-size: 1.3rem; margin: 0 0 4px; }
.print-doc h2 { font-size: 1rem; margin: 22px 0 8px; border-bottom: 1px solid #ccc; padding-bottom: 4px; }
.print-doc table { width: 100%; border-collapse: collapse; font-size: 0.85rem; margin-top: 6px; }
.print-doc th, .print-doc td { border: 1px solid #ccc; padding: 6px 8px; text-align: left; }
.print-doc th { background: #f2f2f2; }
.print-doc .meta { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 20px; margin-bottom: 10px; font-size: 0.9rem; }
.print-doc .signature-line { margin-top: 60px; border-top: 1px solid #333; width: 260px; padding-top: 6px; font-size: 0.85rem; }

/* Muted secondary text (stat labels on the module menus, report hints);
   follows the Main Form foreground when that region is customized. */
.muted { color: var(--text-muted); }
.theme-form .panel .muted, .theme-menubar .panel.menu-panel .muted { color: inherit; opacity: 0.75; }
/* Text sitting directly on the General background (Home welcome heading)
   follows its foreground when that region is customized. */
.theme-page .welcome h1 { color: var(--theme-page-fg); }
.theme-page .welcome p { color: var(--theme-page-fg); opacity: 0.75; }

/* "Secondary Buttons" (Color Settings), once customized: every .btn-ghost
   in the app takes this one look, wherever it sits, so Back / Cancel /
   Edit / filter buttons all match. !important is needed only to outrank
   .btn-ghost's default of following the text colour of the part of the
   screen it sits on. The Exit button in the Page
   Header keeps its red warning look on purpose. */
html.theme-button2 .btn-ghost:not(#exitBtn) {
  background: var(--theme-button2-bg) !important;
  color: var(--theme-button2-fg) !important;
  border-color: var(--theme-button2-fg) !important;
  opacity: 1 !important;
}


/* ---- Color Settings: boxes and bands that have a fixed dark fill by
   default. Each takes on the colours of the part it belongs to once that
   part is customized, so its text (which follows the same part) stays
   readable. With nothing customized, all of these look exactly as before. */
.theme-form .panel .scroll-area { background: transparent; }
.theme-popup .modal .panel .scroll-area { background: transparent; }
/* Totals row at the bottom of a list mirrors the List Headers band. */
html[class*="theme-"] .totals-row td {
  background: var(--theme-list-header-bg);
  color: var(--theme-list-header-fg);
}
/* Search-as-you-type dropdowns and in-list inputs are Fields. */
.theme-field .combo-list { background: var(--theme-field-bg); }
.theme-field .combo-option { color: var(--theme-field-fg); }
.theme-field .table-inline-input, .theme-field .log-status-select {
  background: var(--theme-field-bg);
  color: var(--theme-field-fg);
}

/* ---- Color Settings: elements with a fixed accent colour of their own.
   Readable on the built-in dark look, but not on every custom colour, so
   once the relevant part is customized they switch to something that
   reads on any background. */
/* Company name in the Page Header / on the Sign In box: follows the text
   colour of the part it sits on (the gold only suits the dark header). */
.theme-header .topbar .brand .mark { color: var(--theme-header-fg); }
.theme-form .login-card .mark { color: inherit; }
/* Sign In heading and field labels follow the Forms text colour. */
.theme-form .login-card h1, .theme-form .login-card label { color: inherit; }

/* Active tab / selected side-menu item: the accent blue text can go
   low-contrast on a light colour - use the surrounding text colour, bold,
   keeping the blue underline / highlight as the "selected" marker. */
html[class*="theme-"] .tab-btn.active { color: inherit; font-weight: 700; opacity: 1; }
/* Status badges (Active, Pending, Approved, Power...): pale-tint fills
   with coloured text suit the dark look only. Once any colour is
   customized they become solid, darker fills with white text, which read
   on any background. */
html[class*="theme-"] .badge-active,
html[class*="theme-"] .badge-allow { background: #2e7d50; color: #fff; }
html[class*="theme-"] .badge-inactive,
html[class*="theme-"] .badge-deny { background: #b3402f; color: #fff; }
html[class*="theme-"] .badge-power { background: #8a6a1f; color: #fff; }

/* ---- Version 3.5: product images (js/sku_images.js) ----
   A square box of --thumb pixels. The picture sits on white (product
   photos usually have a white background) and keeps its proportions;
   SKUs without an image show a dashed placeholder in the surrounding
   text colour, so it suits any colour scheme. */
.sku-thumb {
  --thumb: 40px;
  width: var(--thumb);
  height: var(--thumb);
  flex: 0 0 auto;
  display: inline-block;
  vertical-align: middle;
  object-fit: contain;
  background: #fff;
  border: 1px solid rgba(128, 128, 128, 0.35);
  border-radius: 6px;
  box-sizing: border-box;
}
img.sku-thumb { cursor: zoom-in; }
.sku-thumb.ph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px dashed currentColor;
  opacity: 0.4;
  color: inherit;
}
.sku-thumb.ph svg { width: 55%; height: 55%; }
td.thumb-cell, th.thumb-cell { width: 56px; padding-top: 4px; padding-bottom: 4px; text-align: center; }
.sku-with-thumb { display: inline-flex; align-items: center; gap: 10px; }
.sku-lightbox { align-items: center; z-index: 2000; }
.sku-lightbox-panel { width: auto; max-width: 92vw; }
.sku-lightbox .lb-img {
  display: block;
  max-width: min(88vw, 1000px);
  max-height: 74vh;
  min-width: 200px;
  object-fit: contain;
  background: #fff;
  border-radius: 8px;
}
.sku-lightbox .lb-caption { font-weight: 600; }

/* Links inside lists (e.g. a customer number on Opening Balance Approval):
   the accent blue is low-contrast on light custom colours - use the
   list's text colour, underlined. */
html[class*="theme-"] .list-area a { color: inherit; text-decoration: underline; }
.small.self-appr { font-style: italic; font-weight: 600; }

/* Version 4.2: shared status pill for pending/open items */
.badge-pending { background: rgba(201,162,75,.2); color: var(--gold); }
html[class*="theme-"] .badge-pending { background: #8a6a1f; color: #fff; }
.small { font-size: .8rem; }
