/* ============================================================
   KOHEN Car Aircon & Airconditioning - System UI
   Shared stylesheet
   ============================================================ */

:root {
  color-scheme: light;
  /* Display scale for the whole system: 90%. The layout was designed with
     roomy spacing, and this is the comfortable reading size. Everything that
     measures the screen (vh / vw) divides by this so full-height areas
     still fill the screen. */
  --ui-zoom: 0.9;
  /* Brand */
  --brand-50:  #eef2fc;
  --brand-100: #d0dfef;
  --brand-200: #9fc8e1;
  --brand-400: #5fa8d3;
  --brand-500: #2e7eb0;
  --brand-600: #05449f;
  --brand-700: #05449f;
  /* Blue for text and links (buttons use --brand-600 as a fill). */
  --brand-text: #05449f;

  /* Neutrals */
  /* Text greys, each at least 4.5:1 on white and on --bg (WCAG AA for body
     text) except --ink-300, which is for icons and small hints (4.3:1).
     The old #7a8aa0 / #aab6c6 measured 3.5:1 and 2:1 and read as faded. */
  --ink-900: #0f1b2d;
  --ink-700: #1f2d40;
  --ink-500: #44536a;
  --ink-400: #546378;
  --ink-300: #627188;
  /* Borders read clearly against both the white cards and the --bg page;
     the old #e6ecf3 / #eef2f7 nearly vanished on most screens. */
  --line:    #cfd8e3;
  --line-2:  #e1e7ef;
  --bg:      #f4f7fb;
  --card:    #ffffff;
  /* Subtle fills: table headers, hover rows, tab tracks. */
  --surface-2: #f8fafd;
  --surface-3: #eef2f7;
  --topbar-bg: rgba(244,247,251,.85);

  /* Status */
  /* Status text on its own tinted badge: 4.5:1 or better (the old green
     and amber were under 3:1 on their backgrounds). */
  --ok-bg:#e7f7ee; --ok-fg:#15803d;
  --warn-bg:#fff3e0; --warn-fg:#b45309;
  --bad-bg:#fdeaea; --bad-fg:#b91c1c;
  --ok-line:#bfe8cf; --warn-line:#f5d7a8; --bad-line:#f6caca;
  /* Solid fills behind white text (Delete buttons, active Sold / Removed
     tabs, the bell's count). Same as the text colours in light mode; kept
     separate so dark mode can soften the text without losing this contrast. */
  --ok-solid:#15803d; --bad-solid:#b91c1c;
  --violet-bg:#f3edff; --violet-fg:#7c3aed;

  /* Flatter than before: surfaces are separated by a 1px --line border, with
     the shadow only hinting at elevation instead of carrying it. */
  --shadow-sm: 0 1px 3px rgba(16,27,45,.08);
  --shadow-md: 0 4px 12px rgba(16,27,45,.09);
  --radius: 14px;
  --radius-sm: 10px;
  --radius-pill: 999px;

  --sidebar-w: 248px;

  --font: "Manrope","Plus Jakarta Sans",-apple-system,BlinkMacSystemFont,
          "Segoe UI",sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink-900);
  -webkit-font-smoothing: antialiased;
  font-size: 14px;
  line-height: 1.5;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 20px; }
::-webkit-scrollbar-track { background: transparent; }

/* ============================================================
   LOGIN
   ============================================================ */
.login-wrap {
  min-height: calc(100vh / var(--ui-zoom));
  display: grid;
  place-items: center;
  align-content: center;
  padding: 24px;
  background:
    linear-gradient(135deg, rgba(13,42,92,.35), rgba(31,95,224,.20)),
    url('../img/Login_bg.png') center/cover no-repeat,
    #0b2150;
  position: relative;
  overflow: hidden;
}
.login-card {
  width: 100%;
  max-width: 380px;
  background: var(--card);
  border: 1px solid rgba(255,255,255,.22);
  border-radius: 20px;
  padding: 38px 32px 32px;
  box-shadow: 0 30px 70px rgba(2,12,40,.45);
  position: relative;
  z-index: 1;
  color: var(--ink-900);
}
.login-logo { text-align: center; margin-bottom: 22px; position: relative; z-index: 1; }
.login-logo img { width: 240px; max-width: 70vw; display: block; margin: 0 auto; }
/* In the flow, not absolute: pinned to the corner it sat over the first
   label ("Verification code"), since the card's top padding is shorter than
   the button. The negative margins keep it near the corner; the bottom
   margin pushes the step's fields below it. */
.login-back {
  display: flex; width: fit-content; align-items: center; gap: 3px;
  margin: -16px 0 14px -14px;
  padding: 5px 10px 5px 6px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--card); color: var(--ink-500); font-size: 12px; font-weight: 700;
  transition: background .15s, color .15s, border-color .15s;
}
.login-back svg { width: 15px; height: 15px; }
.login-back:hover { background: var(--brand-50); color: var(--brand-text); border-color: var(--brand-200); }
.login-back:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }
.login-back[hidden] { display: none; }
.login-logo .brand-name { font-size: 26px; letter-spacing: 3px; }
.login-logo .brand-sub { font-size: 9px; letter-spacing: 2px; color:var(--ink-400); margin-top:4px; }
.login-card label {
  display:block; font-size: 12px; color:var(--ink-500); margin: 0 0 6px 2px; font-weight: 600;
}
.login-card .field { margin-bottom: 16px; }
.login-card .field-hint { font-size: 11.5px; color: var(--ink-400); margin-top: 6px; }
.login-card input {
  width: 100%;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-900);
  font-size: 14px;
  outline: none;
  transition: border .15s, background .15s;
}
.login-card input::placeholder { color: var(--ink-300); }
.login-card input:focus { border-color: var(--brand-500); background: var(--card); }

/* 2FA code as six boxes (index.html initOtp). Same border, fill and focus as
   the other login inputs; only the shape and the type size change. */
.otp { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px; }
.login-card .otp-box {
  height: 50px; padding: 0; text-align: center;
  font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums;
  caret-color: var(--brand-500);
}
.login-card .otp-box:focus { box-shadow: 0 0 0 3px var(--brand-50); }
.otp-switch { display: block; margin-top: 10px; }
#mfaDigits[hidden], #mfaRecovery[hidden] { display: none; }

.btn-login {
  width: 100%;
  margin-top: 6px;
  padding: 12px;
  border: 0;
  border-radius: 10px;
  background: linear-gradient(180deg, var(--brand-500), var(--brand-600));
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  letter-spacing: .3px;
  box-shadow: 0 8px 20px rgba(31,95,224,.45);
  transition: transform .08s, box-shadow .15s;
}
.btn-login:hover { box-shadow: 0 10px 26px rgba(31,95,224,.6); }
.btn-login:active { transform: translateY(1px); }
/* "Forgot password?" sits under the password field, on the admin option only.
   The slot stays in the markup; the link inside it is created and destroyed
   (see index.html), so :empty is what collapses the spacing when there is no
   link rather than a second state to keep in sync. */
.login-forgot { margin: -10px 0 16px; text-align: right; }
.login-forgot:empty { display: none; }
.login-forgot .link-btn { font-size: 12px; padding: 0; }
/* "or" rule + the Google-rendered button. The button itself is Google's
   iframe; only the space around it is styled here. */
.login-alt[hidden] { display: none; }
.login-alt-sep {
  display: flex; align-items: center; gap: 10px;
  margin: 16px 0 12px; color: var(--ink-400); font-size: 12px; font-weight: 600;
}
.login-alt-sep::before, .login-alt-sep::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.login-google { display: flex; justify-content: center; min-height: 44px; }
.login-hint {
  margin-top: 18px; text-align:center; font-size: 11.5px; color:#c9d8f5; line-height:1.7;
}
.login-hint b { color:#fff; }
/* Same red as .modal-error and .rr-error elsewhere in the system. The
   previous pale-pink-on-translucent-red was written for a dark card and is
   near-unreadable on the white one this sits in. The alert glyph rides along
   as a background image so the JS can keep toggling display:block. */
.login-error {
  display: none;
  margin-top: 14px;
  padding: 11px 13px 11px 38px;
  border-radius: var(--radius-sm);
  background-color: var(--bad-bg);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23dc2626' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' y1='7.5' x2='12' y2='13'/%3E%3Cline x1='12' y1='16.5' x2='12.01' y2='16.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 13px 11px;
  background-size: 16px 16px;
  border: 1px solid var(--bad-line);
  /* A step darker than --bad-fg: that red on --bad-bg lands at ~4.2:1, just
     under AA for text this size. The icon keeps --bad-fg, which clears the
     3:1 that graphics need. */
  color: var(--bad-fg);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.45;
  text-align: left;
  animation: login-error-in .18s ease-out;
}
@keyframes login-error-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .login-error { animation: none; }
}

/* ============================================================
   APP SHELL
   ============================================================ */
.app { display: flex; min-height: calc(100vh / var(--ui-zoom)); }

.sidebar {
  width: var(--sidebar-w);
  background: var(--brand-600);
  border-right: 1px solid var(--brand-700);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: calc(100vh / var(--ui-zoom));
  flex-shrink: 0;
}
.sb-brand {
  padding: 16px 20px 14px;
  border-bottom: 1px solid rgba(255,255,255,.18);
  display: flex; align-items: center; justify-content: center; gap: 10px;
}
.sb-logo-img { width: 100%; max-width: 147px; display: block; }
.sb-role {
  margin: 14px 16px 6px;
  background: transparent;
  color: #fff;
  border: 1px solid rgba(255,255,255,.4);
  border-radius: 10px;
  padding: 10px 14px;
}
.sb-role .r-title {
  font-weight: 800; font-size: 13px; letter-spacing:.4px;
  text-transform: uppercase;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sb-role .r-sub {
  font-size: 10.5px; opacity: .8;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sb-nav { padding: 8px 12px; overflow-y: auto; flex: 1; }
.sb-link {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px;
  border-radius: 10px;
  color: rgba(255,255,255,.8);
  font-weight: 600;
  font-size: 13px;
  margin-bottom: 2px;
  transition: background .12s, color .12s;
}
.sb-link svg { width: 18px; height: 18px; flex-shrink: 0; }
.sb-link:hover { background: rgba(255,255,255,.1); color: #fff; }
.sb-link.active { background: rgba(255,255,255,.16); color: #fff; box-shadow: none; }

.main { flex: 1; min-width: 0; display:flex; flex-direction:column; }

/* ---------- Mobile navigation ----------
   The sidebar used to be display:none below 760px, which removed every nav
   link on a phone. It now slides in as a drawer instead, holding the same
   links, the same routes and the same role gating — layout.js builds the
   markup once and this only changes where it sits. Hidden on desktop. */
.nav-toggle {
  display: none;
  width: 38px; height: 38px; flex: 0 0 auto;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--card); color: var(--ink-700);
  place-items: center;
  box-shadow: var(--shadow-sm);
}
.nav-toggle svg { width: 19px; height: 19px; }
.nav-toggle:hover { background: var(--brand-50); color: var(--brand-text); border-color: var(--brand-200); }
.nav-scrim {
  display: none; position: fixed; inset: 0; z-index: 65;
  background: rgba(15,27,45,.5);
}
.nav-scrim[hidden] { display: none; }

.topbar {
  display:flex; align-items:center; justify-content:space-between;
  padding: 16px 26px;
  position: sticky; top:0; z-index: 20;
  background: var(--topbar-bg);
  backdrop-filter: blur(8px);
}
/* margin-right:auto rather than the header's space-between deciding it: with
   the nav toggle present there are three children, and space-between alone
   would centre the title instead of keeping it beside the button. */
.page-title { margin-right: auto; min-width: 0; }
.page-title h1 { font-size: 20px; font-weight: 800; letter-spacing:-.2px; }
.page-title p { font-size: 12.5px; color: var(--ink-400); margin-top:2px; }
.user-menu { position: relative; }
.user-chip {
  display:flex; align-items:center; gap:10px;
  background:var(--card); border:1px solid var(--line);
  border-radius: 30px; padding: 5px 14px 5px 6px;
  box-shadow: var(--shadow-sm);
  font: inherit; text-align: left; color: inherit; cursor: pointer;
}
.user-chip .ava {
  width: 30px; height:30px; border-radius:50%;
  background: var(--brand-600); color:#fff; display:grid; place-items:center;
  font-weight: 800; font-size: 12px;
  flex: 0 0 auto;
}
/* min-width:0 lets the truncating children shrink inside the flex chip. */
.user-chip .u-meta { min-width: 0; max-width: 150px; }
.user-chip .u-name {
  font-weight: 700; font-size: 12.5px; line-height:1.1;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-chip .u-sub {
  font-size: 10.5px; color: var(--ink-400);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-chip .chev { color: var(--ink-400); margin-left: 2px; transition: transform .15s; flex: 0 0 auto; }
.user-menu.open .user-chip .chev { transform: rotate(180deg); }

.user-dropdown {
  display:none; position:absolute; top: calc(100% + 8px); right: 0;
  width: 190px; background:var(--card); border:1px solid var(--line);
  border-radius: 12px; padding: 6px; box-shadow: var(--shadow-md); z-index: 30;
}
.user-menu.open .user-dropdown { display:block; }
.ud-item {
  width:100%; display:flex; align-items:center; gap:9px;
  padding: 9px 10px; border-radius: 8px; border:0; background:transparent;
  color: var(--bad-fg); font-weight: 700; font-size: 12.5px; font-family: inherit; cursor:pointer;
}
.ud-item svg { width:16px; height:16px; }
.ud-item:hover { background: var(--bad-bg); }
/* Log Out is a destructive-styled item by default (red); Security is a
   normal action, not a warning, so it gets its own neutral coloring. */
.ud-item.ud-neutral { color: var(--ink-700); }
.ud-item.ud-neutral:hover { background: var(--bg-soft, var(--surface-2)); }

.content { padding: 6px 26px 40px; }

/* ============================================================
   COMPONENTS
   ============================================================ */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.card-pad { padding: 22px 24px; }
.card-head {
  display:flex; align-items:center; justify-content:space-between;
  gap: 10px; flex-wrap: wrap;
  padding: 16px 20px; border-bottom: 1px solid var(--line-2);
}

.card-head h3 { font-size: 14.5px; font-weight: 800; display:flex; align-items:center; gap:8px; }
.card-head .sub { font-size: 11.5px; color: var(--ink-400); }

/* Chart container. Chart.js sizes a canvas from its width/height attributes'
   ratio, so a `height="90"` chart came out ~3.3:1 — about 100px tall on a
   phone, with the axis labels on top of each other. The box sets the height
   instead and the chart fills it; only the sizing changes, never the data.
   The canvas gets no width or height of its own here: Chart.js manages both,
   and overriding them desynchronises the drawing buffer from the element. */
.chart-box { position: relative; width: 100%; height: 300px; }

.grid { display: grid; gap: 20px; }
.cols-4 { grid-template-columns: repeat(4, 1fr); }
.cols-3 { grid-template-columns: repeat(3, 1fr); }
.cols-2 { grid-template-columns: repeat(2, 1fr); }
.span-2 { grid-column: span 2; }

/* Stat cards */
.stat {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px 22px 20px;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
}
.stat .s-label { font-size: 10.5px; letter-spacing:.7px; color: var(--ink-400); font-weight:800; text-transform: uppercase; }
.stat .s-num { font-size: 30px; font-weight: 800; margin: 8px 0 2px; letter-spacing:-1px; }
.stat .s-sub { font-size: 11.5px; color: var(--ink-400); }
.stat .s-ico {
  position: absolute; top: 16px; right: 16px;
  width: 38px; height:38px; border-radius: 11px;
  display:grid; place-items:center;
}
.stat .s-ico svg { width: 19px; height:19px; }
.ic-blue  { background: var(--brand-50); color: var(--brand-text); }
.ic-green { background: var(--ok-bg);  color: var(--ok-fg); }
.ic-red   { background: var(--bad-bg); color: var(--bad-fg); }
.ic-amber { background: var(--warn-bg);color: var(--warn-fg); }

/* Badges */
.badge {
  display: inline-flex; align-items:center; gap:5px;
  font-size: 11px; font-weight: 800; padding: 4px 11px; border-radius: var(--radius-pill);
  white-space: nowrap; text-transform: capitalize;
}
.badge::before { content:""; width:6px; height:6px; border-radius:50%; background: currentColor; }
.b-ok  { background: var(--ok-bg);  color: var(--ok-fg); }
.b-warn{ background: var(--warn-bg);color: var(--warn-fg); }
.b-bad { background: var(--bad-bg); color: var(--bad-fg); }
.b-info{ background: var(--brand-50); color: var(--brand-text); }
.b-soft{ background:var(--surface-3); color: var(--ink-500); }

/* Tables */
.table-wrap { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; }
table.tbl th {
  text-align: left; font-size: 10.5px; letter-spacing:.6px; text-transform: uppercase;
  color: var(--ink-400); font-weight: 800; padding: 12px 16px; border-bottom:1px solid var(--line);
  background:var(--surface-2);
}
table.tbl td { padding: 13px 16px; border-bottom: 1px solid var(--line-2); font-size: 13px; vertical-align: middle; }
table.tbl tr:last-child td { border-bottom: 0; }
table.tbl tbody tr:hover { background: var(--surface-2); }
.t-prod { display:flex; align-items:center; gap:11px; }
.t-prod .t-ico {
  width: 34px; height:34px; border-radius:9px; background: var(--brand-50);
  display:grid; place-items:center; color: var(--brand-text); flex-shrink:0;
}
.t-prod .t-ico svg { width:17px; height:17px; }
.t-prod .t-name { font-weight: 700; }
.t-prod .t-meta { font-size: 11px; color: var(--ink-400); }
.muted { color: var(--ink-400); }
.mono { font-variant-numeric: tabular-nums; }

/* Heading above a group of .stat cards, for pages that show more than one row
   of them and need to say what each row is (AI Forecasting: actuals vs.
   projections). Matches .stat .s-label's treatment so the two read as one
   system rather than as a card and an unrelated title. */
.section-label {
  font-size: 11px; letter-spacing: .7px; font-weight: 800; text-transform: uppercase;
  color: var(--ink-500); margin: 0 0 10px;
}
.section-label + .grid { margin-top: 0; }

/* Row-count select + "View All" button sitting in a .card-head opposite the
   title. Compact so a list panel's header stays one line. */
/* flex-wrap so a search box paired with a segmented filter (Product Stock
   Details) drops to its own line on a narrow screen instead of overflowing
   the card, while the short row-count/View All pairs elsewhere never have
   enough width to trigger it. */
.list-tools { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-left: auto; }
.select-sm { padding: 6px 10px; font-size: 12px; }
.btn-sm { padding: 6px 12px; font-size: 12px; }

/* Wider modal for the "View All" tables — the default .modal is sized for
   forms and would wrap the columns. */
.modal.modal-table { max-width: 760px; }
/* The shared "View All" list (assets/js/list-modal.js): wide enough for its
   6-7 columns to fit without sideways scrolling, with tighter cells. */
.modal.modal-list { max-width: min(1120px, calc(96vw / var(--ui-zoom))); }
.modal-list table.tbl th { padding: 10px 12px; }
.modal-list table.tbl td { padding: 7px 12px; font-size: 12.5px; line-height: 1.4; }
/* The table takes whatever height the screen allows (the dialog is capped at
   the viewport) and scrolls on its own, header pinned, while the title,
   search and page controls stay in view. A short list stays short. */
.modal-list .modal-body { display: flex; flex-direction: column; min-height: 0; overflow: hidden; padding-top: 12px; }
.modal-list .modal-body > .search { flex: 0 0 auto; margin-bottom: 10px !important; }
.modal-list .modal-body > .table-wrap {
  flex: 0 1 auto; min-height: 140px; overflow: auto;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.modal-list table.tbl thead th { position: sticky; top: 0; z-index: 1; background: var(--surface-2); }
.modal-list .modal-head { padding-top: 16px; }
.modal-list .modal-foot { padding: 12px 22px 14px; }
/* Sortable column header inside a .tbl. The caret is always present so the
   header text does not shift when sorting changes. */
table.tbl th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
table.tbl th.sortable:hover { color: var(--brand-text); }
table.tbl th.sortable .caret { opacity: .35; margin-left: 5px; font-size: 10px; }
table.tbl th.sortable[aria-sort="ascending"] .caret,
table.tbl th.sortable[aria-sort="descending"] .caret { opacity: 1; color: var(--brand-text); }

/* Segmented toggle for switching what a chart plots, sized to sit inside a
   .card-head next to the title without changing that row's height. */
.seg {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-pill);
}
.seg button {
  border: 0; background: transparent; cursor: pointer;
  font-family: inherit; font-size: 11.5px; font-weight: 700; color: var(--ink-500);
  padding: 6px 14px; border-radius: var(--radius-pill); white-space: nowrap;
}
.seg button:hover { color: var(--ink-700); }
.seg button[aria-pressed="true"] { background: var(--card); color: var(--brand-text); box-shadow: var(--shadow-sm); }
.seg button:disabled { opacity: .55; cursor: default; }

/* Up/down change indicator under a .stat figure. Direction is set by the
   caller, not by the sign: a rising cost is not good news. */
.s-delta { font-weight: 800; }
.s-delta.up   { color: var(--ok-fg); }
.s-delta.down { color: var(--bad-fg); }
.s-delta.flat { color: var(--ink-400); }

/* Sales Overview "Last Sold" cell: date on top, time under it, so the
   stamp stays readable in the daily, weekly and monthly views alike. */
.sale-stamp { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sale-stamp-date {
  display: block; font-weight: 700; color: var(--ink-900); font-size: 12.5px;
}
.sale-stamp-time {
  display: block; margin-top: 2px; font-weight: 600; font-size: 11.5px;
  color: var(--brand-700);
}
.num-strong { font-weight: 800; }
.row-actions { display:flex; gap: 8px; }
.icon-btn {
  width: 30px; height: 30px; border-radius: 8px; border:1px solid var(--line);
  background:var(--card); display:grid; place-items:center; color: var(--ink-500);
}
.icon-btn svg { width:15px; height:15px; }
.icon-btn:hover { background: var(--brand-50); color: var(--brand-text); border-color: var(--brand-200); }
.icon-btn.danger:hover { background: var(--bad-bg); color: var(--bad-fg); border-color:var(--bad-line); }
/* Permanent delete is the only irreversible row action - it reads as filled
   red at rest, not just on hover, so it never looks like the soft Remove. */
.icon-btn.danger-solid {
  background: var(--bad-solid); color:#fff; border-color: var(--bad-solid);
  box-shadow: 0 2px 5px rgba(220,38,38,.2);
}
.icon-btn.danger-solid:hover { background:var(--bad-solid); color:#fff; border-color:var(--bad-solid); }

/* Toolbar / tabs / search */
.toolbar { display:flex; align-items:center; gap: 12px; flex-wrap: wrap; }
.tabs { display:flex; gap:8px; background:var(--surface-3); padding:4px; border-radius:10px; border: 1px solid var(--line); }
.tab {
  border:0; background:transparent; padding:8px 16px; border-radius:8px;
  font-weight: 700; font-size: 12.5px; color: var(--ink-500);
}
.tab.active { background:var(--card); color: var(--brand-700); box-shadow: var(--shadow-sm); outline: 1px solid var(--line); }

/* Inventory tabs: blue for Active, red for Removed */
.tab[data-tab="active"] { background: var(--brand-50); color: var(--brand-text); border: 1px solid var(--brand-200); }
.tab[data-tab="active"]:hover { background: var(--brand-100); }
.tab[data-tab="active"].active { background: var(--brand-600); color: #fff; border-color: var(--brand-600); }
.tab[data-tab="removed"] { background: var(--bad-bg); color: var(--bad-fg); border: 1px solid var(--bad-line); }
.tab[data-tab="removed"]:hover { background: var(--bad-line); }
.tab[data-tab="removed"].active { background: var(--bad-solid); color: #fff; border-color: var(--bad-solid); }
.search {
  flex:1; min-width: 200px; display:flex; align-items:center; gap:9px;
  background:var(--card); border:1px solid var(--line); border-radius:10px; padding: 9px 13px;
}
.search svg { width:16px; height:16px; color: var(--ink-300); }
.search input { border:0; outline:0; flex:1; font-size: 13px; font-family:inherit; background:transparent; }
/* Compact search for card headers, same height as .select-sm beside it. */
.search.search-sm { padding: 6px 10px; gap: 7px; }
.search.search-sm svg { width: 14px; height: 14px; }
.search.search-sm input { font-size: 12px; min-width: 0; }
.select {
  border:1px solid var(--line); background:var(--card); border-radius:10px; padding:9px 12px;
  font-size: 12.5px; font-weight:600; color: var(--ink-700); font-family:inherit; outline:none;
}
.btn {
  display:inline-flex; align-items:center; gap:8px; border:0; border-radius:10px;
  padding: 9px 16px; font-weight: 700; font-size: 12.5px;
}
.btn svg { width:15px; height:15px; }
.btn-primary { background: var(--brand-600); color:#fff; box-shadow: 0 2px 6px rgba(11,76,144,.18); }
.btn-primary:hover { background: var(--brand-700); }
.btn-ghost { background:var(--card); border:1px solid var(--line); color: var(--ink-500); }
.btn-ghost:hover { background:var(--surface-2); }
.btn-danger { background: var(--bad-solid); color:#fff; box-shadow: 0 2px 6px rgba(220,38,38,.2); }
.btn-danger:hover { background:var(--bad-solid); filter: brightness(1.08); }
.btn:disabled { opacity:.55; cursor: not-allowed; box-shadow:none; }

/* Modal (confirm dialogs) */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(15,27,45,.5);
  backdrop-filter: blur(3px);
  display: grid; place-items: center; padding: 24px;
}
.modal-backdrop[hidden] { display: none; }
.modal {
  width: 100%; max-width: 440px;
  background: var(--card); border-radius: var(--radius);
  box-shadow: 0 30px 70px rgba(2,12,40,.35);
  overflow: hidden;
  /* A tall dialog (recovery codes, sales history, the account form) used to
     run off the top and bottom of a short viewport with no way to reach its
     buttons. The head and foot stay put; only the body scrolls. */
  display: flex;
  flex-direction: column;
  max-height: calc(calc(100vh / var(--ui-zoom)) - 48px);
  max-height: calc(calc(100dvh / var(--ui-zoom)) - 48px);
}
.modal-head, .modal-foot { flex: 0 0 auto; }
.modal-body { flex: 1 1 auto; overflow-y: auto; }
.modal-head { display:flex; gap: 13px; padding: 20px 22px 0; }
.modal-head h3 { font-size: 15.5px; font-weight: 800; }
.modal-head .modal-sub { font-size: 12px; color: var(--ink-400); margin-top: 2px; }
.modal-x {
  margin-left: auto; align-self: flex-start; flex-shrink: 0;
  width: 32px; height: 32px; border-radius: 9px; border: 0;
  display: grid; place-items: center;
  background: transparent; color: var(--ink-400); cursor: pointer;
  transition: background .12s, color .12s;
}
.modal-x svg { width: 18px; height: 18px; }
.modal-x:hover { background: var(--bad-bg); color: var(--bad-fg); }
.modal-ico {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--bad-bg); color: var(--bad-fg);
}
.modal-ico svg { width: 20px; height: 20px; }
.modal-body { padding: 14px 22px 4px; font-size: 13px; color: var(--ink-700); line-height: 1.6; }
.modal-body b { font-weight: 800; color: var(--ink-900); }
.modal-error {
  margin-top: 14px; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--bad-bg); color: var(--bad-fg);
  border: 1px solid var(--bad-line); font-size: 12.5px; font-weight: 600;
}
.modal-error[hidden] { display: none; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 18px 22px 20px;
}

/* Two-factor setup: QR code + manual secret + one-time recovery codes */
.mfa-qr { display:block; margin: 4px auto 14px; width: 176px; height: 176px; border-radius: 10px; border: 1px solid var(--line); }
.mfa-secret {
  display:block; text-align:center; font-size: 13px; letter-spacing: 1px;
  padding: 8px 10px; border-radius: var(--radius-sm); background: var(--bg-soft, var(--surface-2));
  margin-bottom: 14px; word-break: break-all;
}
.recovery-codes {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  margin: 4px 0 14px; padding: 12px; border-radius: var(--radius-sm);
  background: var(--bg-soft, var(--surface-2)); border: 1px solid var(--line);
}
.recovery-codes span { font-size: 13px; text-align:center; padding: 4px 0; }

/* Alert list (low stock, etc.) */
.alert-list { display:flex; flex-direction:column; }
.alert-item {
  display:flex; align-items:center; justify-content:space-between;
  padding: 12px 4px; border-bottom: 1px dashed var(--line);
}
.alert-item:last-child { border-bottom: 0; }
.alert-item .a-name { font-weight: 700; font-size: 13px; }
.alert-item .a-cat { font-size: 11px; color: var(--ink-400); }

/* Insight cards */
.insight {
  border-radius: 12px; padding: 13px 14px; margin-bottom: 10px; font-size: 12.5px;
  border-left: 4px solid;
}
.insight .i-title { font-weight: 800; margin-bottom: 3px; }
.insight.i-up   { background: var(--ok-bg); border-color: var(--ok-fg); }
.insight.i-warn { background: var(--warn-bg); border-color: var(--warn-fg); }
.insight.i-info { background: var(--brand-50); border-color: var(--brand-500); }

/* Restock recommendation */
.restock {
  border:1px solid var(--line); border-radius:12px; padding: 13px 14px; margin-bottom: 10px;
  display:flex; align-items:flex-start; justify-content:space-between; gap: 10px;
}
.restock .r-name { font-weight: 800; font-size: 13px; }
.restock .r-meta { font-size: 11.5px; color: var(--ink-500); margin-top: 3px; }
.restock .r-meta b { color: var(--brand-700); }

/* Ranked lists */
.ranked { display:flex; flex-direction:column; }
.ranked-row {
  display:flex; align-items:center; gap: 12px; padding: 11px 4px;
  border-bottom: 1px solid var(--line-2);
}
.ranked-row:last-child { border-bottom:0; }
.rank-no {
  width:26px; height:26px; border-radius:8px; background: var(--brand-50); color: var(--brand-700);
  display:grid; place-items:center; font-weight:800; font-size:12px; flex-shrink:0;
}
.ranked-row .rk-name { font-weight: 700; font-size: 13px; }
.ranked-row .rk-sub { font-size: 11px; color: var(--ink-400); }
.ranked-row .rk-val { margin-left:auto; font-weight: 800; }

/* Pricing summary cards */
.price-sum { display:flex; align-items:center; justify-content:space-between; }
.price-sum .ps-num { font-size: 22px; font-weight: 800; margin-top:4px; }

/* Chat / assistant */
.chat {
  display:flex; flex-direction:column; height: calc(calc(100vh / var(--ui-zoom)) - 180px); min-height: 460px;
  /* dvh tracks the mobile browser's collapsing address bar; vh does not, so
     the composer sat under it. Desktop is unaffected — the two are equal. */
  height: calc(calc(100dvh / var(--ui-zoom)) - 180px);
}
.chat-head {
  background: var(--brand-600); color:#fff; border-radius: 12px 12px 0 0;
  padding: 14px 18px; display:flex; align-items:center; gap:12px;
}
.chat-head .ch-ico { width:36px;height:36px;border-radius:10px;background:rgba(255,255,255,.2);display:grid;place-items:center; }
.chat-body {
  flex:1; overflow-y:auto; padding: 18px; background:var(--surface-2);
  display:flex; flex-direction:column; gap: 14px;
  border-left:1px solid var(--line); border-right:1px solid var(--line);
}
.msg { display:flex; gap:10px; max-width: 78%; }
.msg .m-ava {
  width:30px;height:30px;border-radius:9px;flex-shrink:0;display:grid;place-items:center;font-size:12px;font-weight:800;
}
.msg.bot .m-ava { background: var(--brand-50); color: var(--brand-text); }
.msg.user { margin-left:auto; flex-direction: row-reverse; }
.msg.user .m-ava { background: var(--ink-700); color:#fff; }
.bubble { padding: 11px 14px; border-radius: 12px; font-size: 13px; line-height:1.55; }
.msg.bot .bubble { background:var(--card); border:1px solid var(--line); border-top-left-radius:3px; }
.msg.user .bubble { background: var(--brand-600); color:#fff; border-top-right-radius:3px; }
.bubble ul { margin: 6px 0 0 18px; }
.bubble b { font-weight: 800; }
.chips { display:flex; gap:8px; flex-wrap:wrap; padding: 10px 18px; background:var(--surface-2); border-left:1px solid var(--line); border-right:1px solid var(--line); }
.chip {
  border:1px solid var(--brand-200); background: var(--brand-50); color: var(--brand-700);
  border-radius: 30px; padding: 6px 14px; font-size: 12px; font-weight: 700;
}
.chip:hover { background: var(--brand-100); }
.chat-input {
  display:flex; gap:10px; padding: 14px 18px;
  border:1px solid var(--line); border-top:0; border-radius: 0 0 12px 12px; background:var(--card);
}
.chat-input input { flex:1; border:1px solid var(--line); border-radius:10px; padding: 11px 14px; outline:none; font-family:inherit; font-size:13px; }
.chat-input input:focus { border-color: var(--brand-400); }

/* Form (add product) */
.form-grid { display:grid; grid-template-columns: 1fr 1fr; gap: 16px 18px; max-width: 640px; }
.form-grid .full { grid-column: 1 / -1; }
.form-field label { display:block; font-size:12px; font-weight:700; color:var(--ink-700); margin-bottom:6px; }
.form-field label .req { color: var(--bad-fg); }
.form-field input, .form-field select, .form-field textarea {
  width:100%; padding: 10px 13px; border:1px solid var(--line); border-radius:10px;
  font-family:inherit; font-size:13px; outline:none; background:var(--card);
}
.form-field input:focus, .form-field select:focus, .form-field textarea:focus { border-color: var(--brand-400); }
/* Required-field validation. The red border holds under focus so the field
   the user was sent to still reads as the one that needs fixing. */
.form-field .is-invalid,
.form-field .is-invalid:focus { border-color: var(--bad-fg); background: var(--bad-bg); }
.field-error {
  display: flex; align-items: center; gap: 6px;
  margin-top: 6px; font-size: 12px; font-weight: 600; color: var(--bad-fg);
}
.field-error::before {
  content: "!"; flex: none;
  width: 15px; height: 15px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--bad-solid); color: #fff; font-size: 10px; font-weight: 800; line-height: 1;
}
.field-error[hidden] { display: none; }

/* ============================================================
   SHOW/HIDE PASSWORD TOGGLE
   Shared by the login card and the account dialogs. The button sits inside
   the field's box, so the input reserves room on the right for it and the
   visible border stays the input's own.
   ============================================================ */
.pw-wrap { position: relative; display: block; }
.pw-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-400);
  transition: color .15s, background .15s;
}
.pw-toggle svg { width: 17px; height: 17px; display: block; }
.pw-toggle svg[hidden] { display: none; }
.pw-toggle:hover { color: var(--brand-text); background: var(--line-2); }
.pw-toggle:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 1px; }

/* Dialog fields: 10px/13px input, ~41px tall. */
.form-field .pw-wrap input { padding-right: 42px; }

/* Login card: taller 12px/14px input, so the button grows to match. */
.login-card .pw-wrap input { padding-right: 46px; }
.login-card .pw-toggle { width: 38px; height: 38px; }
.login-card .pw-toggle svg { width: 18px; height: 18px; }

/* Live password-policy checklist under the account dialogs' password fields.
   Unmet rules read in muted ink with a hollow mark rather than red, so a field
   the admin has not typed in yet does not look like an error. */
.pw-rules { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 3px; font-size: 12px; }
.pw-rules li { display: flex; align-items: center; gap: 7px; color: var(--ink-400); }
.pw-rules li::before {
  content: ""; width: 12px; height: 12px; flex-shrink: 0; box-sizing: border-box;
  border: 1.5px solid var(--ink-300); border-radius: 50%;
}
.pw-rules li.met { color: var(--ok-fg); }
.pw-rules li.met::before {
  border-color: var(--ok-fg);
  background: var(--ok-solid) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 6.2l2 2 4-4.4' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 10px no-repeat;
}

@media (max-width: 420px) {
  /* Comfortable touch target on small screens, kept inside each field's box. */
  .form-field .pw-wrap input { padding-right: 46px; }
  .pw-toggle { width: 38px; height: 38px; }
  .login-card .pw-wrap input { padding-right: 52px; }
  .login-card .pw-toggle { width: 44px; height: 44px; }
}

.dropzone {
  border: 2px dashed var(--line); border-radius: 12px; padding: 26px; text-align:center;
  color: var(--ink-400); background:var(--surface-2);
}
.dropzone svg { width: 30px; height:30px; opacity:.5; }
.dz-preview {
  display:block; max-height: 190px; max-width: 100%; margin: 0 auto 12px;
  border-radius: var(--radius-sm); border: 1px solid var(--line); object-fit: contain;
}
/* display:block above beats the UA [hidden] rule, which left an empty
   broken-image box showing before any image was picked. */
.dz-preview[hidden] { display: none; }
.dz-hint { margin-top: 10px; font-size: 11px; color: var(--ink-300); }
/* Inline notice above the dropzone for a rejected image (wrong type, too big,
   empty) - replaces a browser alert(). White card with a red accent bar so it
   reads as a message about the upload rather than a field turning red. */
.upload-alert {
  display: flex; align-items: flex-start; gap: 9px;
  margin-bottom: 12px;
  padding: 12px 14px;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--bad-fg);
  border-radius: var(--radius-sm);
  color: var(--bad-fg);
  font-size: 13px; line-height: 1.45;
  animation: upload-alert-in .18s ease-out;
}
.upload-alert[hidden] { display: none; }
.upload-alert svg { width: 16px; height: 16px; flex: none; margin-top: 1.5px; color: var(--bad-fg); }
.upload-alert strong { font-weight: 800; }
@keyframes upload-alert-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .upload-alert { animation: none; }
}

/* ============================================================
   INVENTORY - VIEW TOGGLE + CARD (IMAGE) MODE
   Both modes render the same filtered rows; only the markup differs.
   ============================================================ */
.view-toggle {
  display: inline-flex; gap: 4px; padding: 4px;
  background: var(--surface-3); border-radius: var(--radius-sm);
}
.vt-btn {
  width: 32px; height: 30px; border: 0; border-radius: 8px;
  background: transparent; color: var(--ink-500);
  display: grid; place-items: center;
}
.vt-btn svg { width: 16px; height: 16px; }
.vt-btn:hover { color: var(--brand-text); }
.vt-btn.active { background: var(--card); color: var(--brand-700); border: 1px solid var(--line); }

.card-grid {
  display: grid; gap: 20px; padding: 4px 24px 24px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.card-grid[hidden] { display: none; }

.prod-card {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); overflow: hidden; display: flex; flex-direction: column;
}
.prod-card:hover { border-color: var(--brand-200); }
.pc-media { position: relative; aspect-ratio: 4 / 3; background: var(--brand-50); }
.pc-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pc-placeholder {
  width: 100%; height: 100%; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px; color: var(--brand-text);
}
.pc-placeholder svg { width: 34px; height: 34px; opacity: .55; }
.pc-placeholder span {
  font-size: 10.5px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--ink-400);
}
.pc-badge { position: absolute; top: 10px; left: 10px; }

/* Inventory bulk selection: "Select all" sits under the view toggle, and each
   row / card carries its own checkbox. */
.list-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap; margin: 14px 0 4px;
}
.bulk-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-left: auto; }
.bulk-bar[hidden] { display: none; }
.bulk-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.bulk-actions .btn { padding: 7px 12px; font-size: 12px; }
.bulk-count { font-size: 12px; font-weight: 700; color: var(--brand-700); }
.select-all {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer; user-select: none;
  font-size: 12.5px; font-weight: 700; color: var(--ink-700);
  padding: 6px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--card);
}
.select-all input, .row-check { width: 16px; height: 16px; accent-color: var(--brand-600); cursor: pointer; margin: 0; }
.select-all input:disabled { cursor: not-allowed; }
table.tbl .check-col { width: 44px; padding-right: 0; }
table.tbl tr.is-selected td { background: var(--brand-50); }
.pc-top { position: relative; }
.pc-check {
  position: absolute; top: 8px; right: 8px; z-index: 1;
  display: grid; place-items: center; width: 28px; height: 28px; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); border-radius: 8px;
}
.prod-card.is-selected { border-color: var(--brand-600); box-shadow: 0 0 0 2px var(--brand-100); }
.hl-danger { color: var(--bad-fg); font-weight: 800; background: var(--bad-bg); padding: 1px 5px; border-radius: 4px; }
/* Dimmed scrim, not a hidden card: an out-of-stock product still has to be
   readable and editable in this view. */
.pc-scrim {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(15,27,45,.45); color: #fff;
  font-weight: 800; font-size: 12.5px; letter-spacing: 1.4px; text-transform: uppercase;
}
.pc-body { padding: 14px 15px 15px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
.pc-meta {
  font-size: 10.5px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--ink-400);
}
.pc-name { font-size: 13.5px; font-weight: 800; line-height: 1.35; }
.pc-row {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12px; color: var(--ink-400); margin-top: auto;
}
.pc-qty { color: var(--ink-700); }
.pc-qty b { font-weight: 800; }
.pc-actions { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.pc-actions .btn { width: 100%; justify-content: center; }

/* Outline buttons: used by the card actions and the account roster */
.btn-outline {
  background: var(--brand-50); border: 1px solid var(--brand-200); color: var(--brand-text);
}
.btn-outline:hover { background: var(--brand-100); border-color: var(--brand-400); }
.btn-outline-danger {
  background: var(--bad-bg); border: 1px solid var(--bad-line); color: var(--bad-fg);
}
.btn-outline-danger:hover { background: var(--bad-line); border-color: var(--bad-fg); }
.btn-outline:disabled, .btn-outline-danger:disabled { opacity: .45; cursor: not-allowed; }

.empty-state {
  grid-column: 1 / -1; padding: 34px; text-align: center;
  color: var(--ink-400); font-size: 13px;
}

/* progress bar (inventory by category) */
.bar-track { height: 8px; background:var(--surface-3); border-radius: 30px; overflow:hidden; min-width: 110px; }
.bar-fill { height: 100%; background: linear-gradient(90deg,var(--brand-500),var(--brand-600)); border-radius:30px; }

/* ============================================================
   ADMIN MANAGEMENT
   Accounts and access, not day-to-day stock: a roster of account rows
   rather than the dense product grid, on a heavier summary strip.
   ============================================================ */
.admin-summary {
  display: grid; grid-template-columns: repeat(3, 1fr);
  background: var(--brand-600); color: #fff;
  border-radius: var(--radius); overflow: hidden;
}
.as-item { padding: 20px 24px; border-right: 1px solid rgba(255,255,255,.18); }
.as-item:last-child { border-right: 0; }
.as-label {
  font-size: 10.5px; font-weight: 800; letter-spacing: .8px;
  text-transform: uppercase; color: rgba(255,255,255,.72);
}
.as-num { font-size: 30px; font-weight: 800; letter-spacing: -1px; margin: 6px 0 2px; }
.as-sub { font-size: 11.5px; color: rgba(255,255,255,.7); }

.card-head .ch-ic { display: inline-flex; width: 17px; height: 17px; color: var(--brand-text); }
.card-head .ch-ic svg { width: 17px; height: 17px; }

.roster { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }
.roster-row {
  display: grid; align-items: center; gap: 14px;
  grid-template-columns: 44px minmax(160px, 1.4fr) 130px minmax(150px, 1fr) 96px auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px; background: var(--card);
}
.roster-row:hover { border-color: var(--brand-200); }
/* Deactivated accounts stay on the list - the audit trail refers to them - but
   they read as switched off. */
.roster-row.is-off { background: var(--surface-2); }
.roster-row.is-off .rr-ava { background: var(--ink-300); }
.roster-row.is-off .rr-name, .roster-row.is-off .rr-user { color: var(--ink-400); }
.rr-ava {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--brand-600); color: #fff;
  display: grid; place-items: center; font-weight: 800; font-size: 14px;
}
.rr-name { font-weight: 800; font-size: 13.5px; }
.rr-you {
  font-size: 9.5px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase;
  background: var(--brand-50); color: var(--brand-text);
  border-radius: var(--radius-pill); padding: 2px 7px; margin-left: 4px; vertical-align: 1px;
}
.rr-user { font-size: 11.5px; color: var(--ink-400); }
.role-pill {
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 800; padding: 5px 12px; border-radius: var(--radius-pill);
  border: 1px solid transparent; white-space: nowrap;
}
.rp-admin { background: var(--brand-50); color: var(--brand-700); border-color: var(--brand-200); }
.rp-staff { background: var(--surface-3); color: var(--ink-500); border-color: var(--line); }
.rr-seen-label {
  font-size: 10px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--ink-300);
}
.rr-seen-val { font-size: 12px; color: var(--ink-500); }
.rr-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.rr-actions .btn { padding: 7px 12px; font-size: 12px; }
.rr-error {
  grid-column: 1 / -1; margin-top: 4px;
  background: var(--bad-bg); color: var(--bad-fg); border: 1px solid var(--bad-line);
  border-radius: var(--radius-sm); padding: 9px 12px; font-size: 12.5px; font-weight: 600;
}
.rr-error[hidden] { display: none; }
/* Whether an emailed password link went out, above the roster. Green when it
   did, amber when it did not — never red, because the account itself saved. */
.page-note {
  margin: 4px 0 10px; padding: 9px 12px; border-radius: var(--radius-sm);
  background: var(--ok-bg); color: var(--ok-fg); border: 1px solid var(--ok-line);
  font-size: 12.5px; font-weight: 600;
}
.page-note.is-warn { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-line); }
.page-note[hidden] { display: none; }
/* The create dialog's "a link will be emailed" explanation. */
.form-note {
  padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--brand-50); color: var(--ink-700); border: 1px solid var(--brand-100);
  font-size: 12.5px; line-height: 1.5;
}
.form-note[hidden] { display: none; }
.modal-ico.ico-brand { background: var(--brand-50); color: var(--brand-text); }
.form-grid.form-grid-1 { grid-template-columns: 1fr; max-width: none; gap: 14px; }
.form-field[hidden] { display: none; }

/* ============================================================
   SYSTEM AUDIT LOGS
   ============================================================ */
.date-field {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 700; color: var(--ink-500);
}
.date-field input { font-weight: 600; }
.audit-tbl td { vertical-align: top; }
.nowrap { white-space: nowrap; }
.al-kind {
  font-size: 10px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--ink-400);
}
/* overflow-wrap: anywhere lets a name with no spaces (one product was named
   "HELOOOO..." 150 characters long) break onto more lines. Without it that
   single name stretched "What changed?" to 1500px and pushed Action,
   Performed by and Details off the right edge of the table. */
.al-entity { font-weight: 800; font-size: 13px; overflow-wrap: anywhere; max-width: 260px; }
.al-who { font-weight: 800; font-size: 13px; }
.al-role { font-size: 11px; color: var(--ink-400); }
.al-details { max-width: 420px; color: var(--ink-700); overflow-wrap: anywhere; }
.al-who { overflow-wrap: anywhere; }
.link-btn {
  border: 0; background: transparent; padding: 4px 0 0;
  color: var(--brand-text); font-weight: 700; font-size: 12px; font-family: inherit;
}
.link-btn:hover { text-decoration: underline; }
.diff-wrap { margin-top: 8px; }
.diff-wrap[hidden] { display: none; }
.diff-tbl { width: 100%; border-collapse: collapse; background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.diff-tbl th {
  text-align: left; font-size: 10px; letter-spacing: .5px; text-transform: uppercase;
  color: var(--ink-400); font-weight: 800; padding: 7px 10px; border-bottom: 1px solid var(--line);
}
.diff-tbl td { padding: 7px 10px; font-size: 12px; border-bottom: 1px solid var(--line-2); word-break: break-word; }
.diff-tbl tr:last-child td { border-bottom: 0; }
.diff-key { font-weight: 700; color: var(--ink-700); }
.diff-old { color: var(--ink-400); text-decoration: line-through; }
.diff-new { color: var(--ok-fg); font-weight: 700; }
.pager { display: flex; align-items: center; justify-content: space-between; border-top: 1px solid var(--line-2); }
.pager .btn { padding: 7px 14px; }
/* display:flex above would otherwise beat the hidden attribute, leaving an
   empty pager bar under a table that has nothing to page. */
.pager[hidden] { display: none; }

/* ============================================================
   SOLD ITEMS
   Reuses the inventory tabs, cards, modal and stat components; only the
   pieces those did not already have live here.
   ============================================================ */
/* Five stat cards stay in one row on laptops and desktops (the 90% display
   scale leaves room). Narrower screens fall back below (<=1100, <=760). */
.cols-5 { grid-template-columns: repeat(5, 1fr); }

/* Third inventory tab: green, next to blue Active and red Removed */
.tab[data-tab="sold"] { background: var(--ok-bg); color: var(--ok-fg); border: 1px solid var(--ok-line); }
.tab[data-tab="sold"]:hover { background: var(--ok-line); }
.tab[data-tab="sold"].active { background: var(--ok-solid); color: #fff; border-color: var(--ok-solid); }

/* Inventory action toast colours, one per kind of action. */
.tab-fx-add    { color: var(--brand-text); }
.tab-fx-remove { color: var(--bad-fg); }
.tab-fx-sold   { color: var(--ok-fg); }
@keyframes tab-fade { 0%, 80% { opacity: 1; } 100% { opacity: 0; } }

/* Inventory action toast ("Product Added", "5 Marked as Sold"). The
   tab-fx-* class supplies the text colour. */
.inv-toast {
  position: fixed; left: 50%; bottom: 24px; z-index: 60;
  transform: translateX(-50%);
  max-width: calc(calc(100vw / var(--ui-zoom)) - 32px); white-space: nowrap;
  padding: 12px 22px; border-radius: 999px;
  background: var(--card); border: 2px solid currentColor; box-shadow: 0 10px 30px rgba(15, 23, 42, .2);
  font-size: 14px; font-weight: 800; pointer-events: none;
  animation: inv-toast 3.5s ease forwards;
}
@keyframes inv-toast {
  0%       { opacity: 0; transform: translate(-50%, 12px); }
  8%, 85%  { opacity: 1; transform: translate(-50%, 0); }
  100%     { opacity: 0; transform: translate(-50%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .inv-toast { animation: tab-fade 3.5s linear forwards; }
}

.btn-outline-success {
  background: var(--ok-bg); border: 1px solid var(--ok-line); color: var(--ok-fg);
}
.btn-outline-success:hover { background: var(--ok-line); border-color: var(--ok-fg); }
.btn-outline-success:disabled { opacity: .45; cursor: not-allowed; }

/* ============================================================
   AI ASSISTANT (Product Inquiry Assistant)
   Additions to the chat block above: the header controls, the
   thinking indicator, the lookup trace under an answer, and the
   recording state of the mic button.
   ============================================================ */

/* Pushes the header controls to the right of the bot name/subtitle. */
.chat-head .ch-tools { margin-left: auto; display: flex; gap: 8px; }
.chat-head .ch-btn {
  background: rgba(255,255,255,.18); border: 1px solid rgba(255,255,255,.28);
  color: #fff; border-radius: 9px; padding: 6px 11px; font: inherit;
  font-size: 12px; font-weight: 700; cursor: pointer; display: flex;
  align-items: center; gap: 6px;
}
.chat-head .ch-btn:hover { background: rgba(255,255,255,.3); }
.chat-head .ch-btn svg { width: 14px; height: 14px; }
/* Speak-answers is off by default; on, it reads as a pressed control. */
.chat-head .ch-btn[aria-pressed="true"] { background: var(--card); color: var(--brand-700); border-color: var(--card); }

/* Three dots while the model is working. Replaced by the real answer. */
.typing { display: inline-flex; gap: 4px; align-items: center; height: 14px; }
.typing span {
  width: 6px; height: 6px; border-radius: 50%; background: var(--brand-400);
  animation: typing-bounce 1.1s infinite ease-in-out;
}
.typing span:nth-child(2) { animation-delay: .15s; }
.typing span:nth-child(3) { animation-delay: .3s; }
@keyframes typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: .45; }
  30% { transform: translateY(-4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .typing span { animation: none; opacity: .6; }
}

/* "Checked inventory: Compressor" — which lookups produced the answer, so a
   number in the bubble can be traced to the tool call behind it. */
.m-trace {
  margin-top: 7px; padding-top: 7px; border-top: 1px dashed var(--line);
  font-size: 11px; color: var(--ink-500); display: flex; flex-wrap: wrap; gap: 6px;
}
.m-trace .tr {
  background: var(--brand-50); color: var(--brand-700); border-radius: 6px;
  padding: 2px 7px; font-weight: 700;
}
.m-trace .tr.miss { background: var(--warn-bg); color: var(--warn-fg); }

/* An error the user needs to act on (no API key, service down) reads as a
   notice, not as something the assistant "said". */
.msg.bot .bubble.b-error {
  background: var(--bad-bg); border-color: var(--bad-line); color: var(--bad-fg); font-weight: 600;
}

/* Mic actively listening. */
#voiceBtn.listening {
  background: var(--bad-solid); border-color: var(--bad-solid); color: #fff;
  animation: mic-pulse 1.4s infinite;
}
@keyframes mic-pulse { 50% { opacity: .62; } }
@media (prefers-reduced-motion: reduce) { #voiceBtn.listening { animation: none; } }
#voiceBtn:disabled { opacity: .45; cursor: not-allowed; }
.chat-input input:disabled { background: var(--surface-2); cursor: not-allowed; }
.icon-btn.success:hover { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-line); }
.icon-btn:disabled { opacity: .4; cursor: not-allowed; }
.icon-btn:disabled:hover { background:var(--card); color: var(--ink-500); border-color: var(--line); }
.modal-ico.ico-ok { background: var(--ok-bg); color: var(--ok-fg); }

/* Mark as Sold modal: the facts being acted on, then the one input */
.sale-facts {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px 16px;
  padding: 12px 14px; margin-bottom: 14px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--line);
}
.sale-facts .full { grid-column: 1 / -1; }
.sf-label {
  font-size: 10px; font-weight: 800; letter-spacing: .6px;
  text-transform: uppercase; color: var(--ink-400);
}
.sf-val { font-size: 13px; font-weight: 800; color: var(--ink-900); }
.sale-remaining { margin-top: 8px; font-size: 12px; color: var(--ink-500); }
.sale-remaining b { font-weight: 800; }

/* Sold-tab card: lifetime sold figure under the stock line */
.pc-sold { color: var(--ok-fg); font-weight: 700; }

/* Sales history modal */
.modal.modal-wide { max-width: 560px; }
.history-wrap { max-height: 320px; overflow: auto; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.history-wrap table.tbl td { padding: 10px 12px; }
.history-wrap table.tbl th { padding: 9px 12px; position: sticky; top: 0; }

/* Reports: Sales Overview period switcher */
.period-nav { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.period-nav .btn { padding: 7px 12px; }
.period-label { font-weight: 800; font-size: 13px; color: var(--ink-900); min-width: 150px; }
.sales-total td { background: var(--surface-2); border-top: 1px solid var(--line); font-weight: 800; color: var(--ink-900); }

/* misc */
.flex { display:flex; } .between { justify-content:space-between; } .center { align-items:center; }
.gap-8{gap:8px;} .gap-12{gap:12px;} .gap-16{gap:16px;}
.mt-16{margin-top:16px;} .mt-20{margin-top:20px;} .mt-24{margin-top:24px;}
.mb-8{margin-bottom:8px;}
.hi-warn{display:inline-flex;width:18px;height:18px;color:var(--warn-fg);vertical-align:-3px;}
.hi-red {display:inline-flex;width:18px;height:18px;color:var(--bad-fg);vertical-align:-3px;}
.hi-blue{display:inline-flex;width:18px;height:18px;color:var(--brand-text);vertical-align:-3px;}
.link { color: var(--brand-text); font-weight: 700; font-size: 12.5px; }
.link:hover { text-decoration: underline; }
.right { text-align:right; } .tc { text-align:center; }

/* ============================================================
   RESPONSIVE SCALE
   Breakpoints, widest first. Each one only relaxes the layout the previous
   one set — the desktop design above is the baseline and is never rebuilt.

     >=1700   large desktop: cap the content width
     <=1100   small laptop / landscape tablet
     <= 900   portrait tablet: sidebar becomes a drawer
     <= 760   large phone
     <= 620   phone
     <= 420   small phone
   ============================================================ */

/* ---------- Large desktop: stop the content stretching edge to edge ---------- */
@media (min-width: 1700px) {
  .topbar, .content { width: 100%; max-width: 1660px; margin-left: auto; margin-right: auto; }
}

/* ---------- Small laptop / landscape tablet ---------- */
@media (max-width: 1100px) {
  .cols-4 { grid-template-columns: repeat(2,1fr); }
  .cols-5 { grid-template-columns: repeat(2,1fr); }
  .cols-3 { grid-template-columns: 1fr; }
  .span-2 { grid-column: span 1; }

  .roster-row { grid-template-columns: 44px 1fr auto; }
  .roster-row .rr-seen { grid-column: 2 / -1; }
  .roster-row .rr-actions { grid-column: 1 / -1; justify-content: flex-start; }
}

/* ---------- Portrait tablet: the sidebar becomes a drawer ----------
   A 248px fixed rail plus a data table does not fit here, and the tablet is
   exactly where the extra width is worth reclaiming. Every nav link is still
   present — it is one tap away instead of always on screen. */
@media (max-width: 900px) {
  .nav-toggle { display: grid; }
  .sidebar {
    position: fixed; top: 0; left: 0; z-index: 70;
    height: calc(100vh / var(--ui-zoom)); height: calc(100dvh / var(--ui-zoom));
    width: min(var(--sidebar-w), calc(82vw / var(--ui-zoom)));
    transform: translateX(-100%);
    transition: transform .22s ease;
  }
  body.nav-open .sidebar { transform: none; box-shadow: 0 0 40px rgba(2,12,40,.4); }
  body.nav-open .nav-scrim { display: block; }
  body.nav-open { overflow: hidden; }

  /* Two panels side by side leave neither enough room once the page is this
     narrow — a table inside one of them would be the part that suffers. */
  .cols-2 { grid-template-columns: 1fr; }

  .chart-box { height: 260px; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar { transition: none; }
}

/* ---------- Large phone ---------- */
@media (max-width: 760px) {
  .topbar { padding: 12px 14px; gap: 10px; }
  .page-title h1 { font-size: 17px; }
  .page-title p { font-size: 11.5px; }
  .content { padding: 6px 14px 32px; }
  .user-chip .u-meta { max-width: 88px; }

  .sale-facts { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .admin-summary { grid-template-columns: 1fr; }
  .as-item { border-right: 0; border-bottom: 1px solid rgba(255,255,255,.18); }
  .as-item:last-child { border-bottom: 0; }

  /* Keep two product cards per row where they still fit — one giant card per
     screen turns a 30-product catalogue into a very long scroll. */
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; padding: 4px 14px 20px; }

  .card-pad { padding: 16px 14px; }
  .card-head { padding: 14px 14px; }
  .chart-box { height: 230px; }

  /* Tables scroll inside .table-wrap rather than stretching the page. The
     min-width is on the cells, not the table, so a three-column table still
     fits a phone while a seven-column one scrolls — no column is dropped. */
  table.tbl th, table.tbl td { padding: 11px 12px; white-space: nowrap; }
  table.tbl th { min-width: 78px; }
  table.tbl td .t-prod { min-width: 168px; }
  table.tbl td.al-details { max-width: 260px; white-space: normal; }
  table.tbl td .t-name, table.tbl td .t-meta { white-space: normal; }
  .table-wrap { -webkit-overflow-scrolling: touch; }

  /* Comfortable tap targets. */
  .icon-btn { width: 34px; height: 34px; }
  .btn { padding: 10px 16px; }
  .tab { padding: 9px 14px; }

  .toolbar > .search { flex: 1 1 100%; }
  .tabs { flex-wrap: wrap; }

  /* The composer keeps its two buttons on one row under a full-width field
     instead of squeezing all three and pushing Voice off screen. */
  .chat { height: calc(calc(100vh / var(--ui-zoom)) - 150px); height: calc(calc(100dvh / var(--ui-zoom)) - 150px); min-height: 380px; }
  .chat-head { flex-wrap: wrap; }
  .chat-head .ch-tools { margin-left: auto; }
  .msg { max-width: 92%; }
  .chat-input { flex-wrap: wrap; padding: 12px 14px; }
  .chat-input input { flex: 1 1 100%; }
  .chat-input .btn { flex: 1 1 0; justify-content: center; }
  .chips { padding: 10px 14px; }
  .chat-body { padding: 14px; }
}

/* ---------- Phone ---------- */
@media (max-width: 620px) {
  .cols-4, .cols-5, .cols-2 { grid-template-columns: 1fr; }
  .stat { padding: 18px 16px 16px; }
  .stat .s-num { font-size: 26px; }

  /* One account per block: the six-column roster row cannot hold its shape
     at this width without pushing the action buttons off screen. */
  .roster-row { grid-template-columns: 44px 1fr; gap: 10px 12px; padding: 14px; }
  .roster-row .rr-role { grid-column: 2; justify-self: start; }
  .roster-row .rr-seen,
  .roster-row .rr-state { grid-column: 1 / -1; }
  .roster-row .rr-actions { grid-column: 1 / -1; justify-content: flex-start; }
  .rr-actions .btn { flex: 1 1 auto; justify-content: center; }

  .modal-backdrop { padding: 12px; }
  .modal-head { padding: 16px 16px 0; }
  .modal-body { padding: 12px 16px 4px; }
  .modal-foot { padding: 14px 16px 16px; flex-wrap: wrap; }
  .modal-foot .btn { flex: 1 1 auto; justify-content: center; }

  .list-tools { margin-left: 0; }
  .period-label { min-width: 0; }
  .chart-box { height: 210px; }
}

/* ---------- Small phone ---------- */
@media (max-width: 420px) {
  .login-wrap { padding: 14px; }
  .login-card { padding: 28px 20px 24px; border-radius: 16px; }
  .mfa-qr { width: 100%; max-width: 176px; height: auto; aspect-ratio: 1; }
  .card-grid { grid-template-columns: 1fr; }
  .tabs { width: 100%; }
  .tab { flex: 1 1 auto; text-align: center; }
  .select { flex: 1 1 140px; }
}

/* ---------- Sidebar submenu ----------
   "Inventory Reports" expands rather than routing. Colours are the
   sidebar's own tokens (blue panel, white text), matching .sb-link.active
   above — the spec described the sidebar as white-with-blue, which is not
   what this theme is; consistency with the real sidebar wins. */
.sb-group { display: block; }
.sb-parent {
  width: 100%; background: none; border: 0; font: inherit; cursor: pointer;
  text-align: left;
}
.sb-caret {
  margin-left: auto; display: inline-flex; width: 16px; height: 16px;
  transition: transform .18s ease;
}
.sb-caret svg { width: 16px; height: 16px; }
.sb-group.open .sb-caret { transform: rotate(90deg); }

/* Collapsed by grid-row height rather than display:none, so the open/close
   animates and the caret has something to move with. */
.sb-sub {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .18s ease;
}
.sb-group.open .sb-sub { grid-template-rows: 1fr; }
.sb-sub > div { overflow: hidden; }
.sb-sublink {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px 9px 33px; font-size: 12.5px;
  color: rgba(255,255,255,.78); font-weight: 600; text-decoration: none;
  border-radius: 10px; margin-bottom: 2px;
  transition: background .12s, color .12s;
}
.sb-sublink svg { width: 15px; height: 15px; flex-shrink: 0; }
.sb-sublink:hover { background: rgba(255,255,255,.1); color: #fff; }
.sb-sublink.active { background: rgba(255,255,255,.16); color: #fff; font-weight: 700; }

@media (prefers-reduced-motion: reduce) {
  .sb-caret, .sb-sub { transition: none; }
}

/* ---------- Segmented control (report filters) ---------- */
.seg { display: inline-flex; gap: 2px; background: var(--surface-3); border: 1px solid var(--line); padding: 3px; border-radius: var(--radius-pill); }
.seg-btn {
  border: 0; background: none; font: inherit; font-size: 12px; font-weight: 700;
  color: var(--ink-500); padding: 6px 13px; border-radius: var(--radius-pill); cursor: pointer;
}
.seg-btn:hover { color: var(--brand-text); }
.seg-btn.active { background: var(--card); color: var(--brand-text); box-shadow: 0 1px 3px rgba(0,0,0,.10); }
.report-actions { display: inline-flex; gap: 8px; }

/* ---------- Print ----------
   Reports are the only thing in the app anyone prints. Everything
   interactive or navigational is dropped, leaving the report header and
   the tables. */
.print-header { display: none; }
.print-footer { display: none; }

@media print {
  @page { margin: 14mm; }

  /* Kept inside the @page margin band (0/0 = its edges), so it repeats on
     every printed page without needing its own reserved space or fighting
     the page's own content for room. It sits in the same corner the
     browser's own printed URL/date footer would otherwise use, but that
     footer is a print-dialog setting (Chrome/Edge: "More settings" ->
     "Headers and footers") no page CSS can turn off — this is the site's
     own mark alongside it, not a replacement for it. */
  .print-footer {
    display: block; position: fixed; left: 0; bottom: 0;
  }
  .print-footer img {
    display: block; height: 8mm; width: auto; max-width: 46mm;
    /* Grayscale image over a photographic filter: the source mark is flat
       brand blue on white, so this reads as a clean black-and-white print
       rather than a washed-out photo conversion. */
    filter: grayscale(1) contrast(1.4);
  }

  /* The chrome: sidebar, topbar, drawer, and anything a reader cannot
     click on paper. */
  .sidebar, .topbar, .mobile-nav, .report-actions,
  .tabs, .period-nav, .seg, .modal-backdrop, .pager, .period-coverage { display: none !important; }

  body, .app, .main, .content {
    display: block !important; margin: 0 !important; padding: 0 !important;
    background: #fff !important; height: auto !important; overflow: visible !important;
  }

  .print-header { display: block; margin-bottom: 14px; }
  .ph-biz   { font-size: 12px; font-weight: 700; letter-spacing: .4px; }
  .ph-title { font-size: 20px; font-weight: 800; margin-top: 2px; }
  .ph-sub   { font-size: 12px; margin-top: 2px; }
  .ph-meta  { font-size: 10.5px; color: #444; margin-top: 4px; }

  /* Cards keep their numbers but lose the screen styling that wastes ink. */
  .card, .stat { box-shadow: none !important; border: 1px solid #ccc !important; break-inside: avoid; }
  .s-ico { display: none !important; }

  /* The point of a printed report: headers repeat on every page and rows
     are not split down the middle. */
  .table-wrap { overflow: visible !important; max-height: none !important; }
  table.tbl { width: 100%; border-collapse: collapse; }
  table.tbl thead { display: table-header-group; }
  table.tbl tfoot { display: table-footer-group; }
  table.tbl tr { break-inside: avoid; }
  table.tbl th, table.tbl td { border-bottom: 1px solid #ddd; padding: 6px 8px; font-size: 11px; }

  /* Badges are colour on screen; on paper they have to read as text. */
  .badge { border: 1px solid #999; background: none !important; color: #000 !important; }
  .badge::before { display: none; }
}

/* ---------- Stock level bar (Inventory Report, by category) ----------
   Width is the category's share of the largest category, so the column
   reads as a comparison at a glance rather than as another number. */
.lvl-bar {
  width: 100%; max-width: 190px; min-width: 90px; height: 9px;
  background: var(--surface-3); border-radius: var(--radius-pill); overflow: hidden;
}
.lvl-bar > span {
  display: block; height: 100%; border-radius: var(--radius-pill);
  background: var(--brand-600);
}

@media print {
  /* Browsers drop background colour when printing unless told not to, which
     would leave every bar an empty grey track. */
  .lvl-bar, .lvl-bar > span {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  .lvl-bar { border: 1px solid #999; }
}


/* ============================================================
   INVENTORY: pagination and the Inventory Activity panel
   ============================================================ */
.inv-pager { flex-wrap: wrap; gap: 10px; }
.pager-left { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; font-size: 12.5px; }
.pager-size { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; }
.pager-size .select { padding: 5px 8px; font-size: 12.5px; }
.pager-nav { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.pager-nav .btn { padding: 7px 12px; }
.pager-nav .btn:disabled { opacity: .45; cursor: not-allowed; }
.pager-num { min-width: 36px; justify-content: center; }
.pager-gap { color: var(--ink-400); padding: 0 2px; }

/* Activity kinds share one colour each: the pill, the row stripe and icon. */
.k-added    { --k-fg: var(--brand-text); --k-bg: var(--brand-50); }
.k-removed, .k-purged { --k-fg: var(--bad-fg); --k-bg: var(--bad-bg); }
.k-sold     { --k-fg: var(--ok-fg); --k-bg: var(--ok-bg); }
.k-restored { --k-fg: var(--violet-fg); --k-bg: var(--violet-bg); }
.k-updated  { --k-fg: var(--warn-fg); --k-bg: var(--warn-bg); }

.act-today { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; }
.act-today-label { font-size: 11px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase; color: var(--ink-400); margin-right: 4px; }
.act-pill {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 5px 12px; border-radius: var(--radius-pill);
  background: var(--k-bg); color: var(--k-fg); font-size: 12px; font-weight: 700;
}
.act-pill b { font-size: 14px; font-weight: 800; }

.act-filters { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.act-filter {
  padding: 5px 12px; border-radius: var(--radius-pill); cursor: pointer;
  border: 1px solid var(--line); background: var(--card); color: var(--ink-500);
  font: inherit; font-size: 12px; font-weight: 700;
}
.act-filter:hover { background: var(--line-2); }
.act-filter.active { background: var(--brand-600); border-color: var(--brand-600); color: #fff; }
.act-filter:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }

.act-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }.act-item {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); border-left: 4px solid var(--k-fg); background: var(--card);
}
.act-item.is-new { animation: act-new 2.4s ease-out; }
@keyframes act-new { 0%, 40% { background: var(--k-bg); } 100% { background: var(--card); } }
@media (prefers-reduced-motion: reduce) { .act-item.is-new { animation: none; background: var(--k-bg); } }
.act-ico {
  flex: none; display: grid; place-items: center; width: 32px; height: 32px;
  border-radius: 50%; background: var(--k-bg); color: var(--k-fg);
}
.act-ico svg { width: 16px; height: 16px; }
.act-main { flex: 1; min-width: 0; }
.act-text { font-size: 13px; color: var(--ink-700); overflow-wrap: anywhere; }
.act-tag {
  display: inline-block; margin-right: 4px; padding: 1px 8px; border-radius: var(--radius-pill);
  background: var(--k-bg); color: var(--k-fg); font-size: 10.5px; font-weight: 800;
  text-transform: uppercase; letter-spacing: .4px; vertical-align: 1px;
}
.act-meta { font-size: 11.5px; color: var(--ink-400); margin-top: 2px; }
.act-time { flex: none; font-size: 11.5px; font-weight: 700; color: var(--ink-500); white-space: nowrap; }
.act-empty { padding: 18px; text-align: center; font-size: 13px; }

/* ============================================================
   SALES REPORT: coverage line, From / To range form, overall total card
   ============================================================ */
.period-coverage { font-size: 12px; color: var(--ink-500); margin: 0 0 14px; }
.range-field {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 700; color: var(--ink-700);
}
.range-error { font-size: 12px; font-weight: 700; color: var(--bad-fg); }
.range-error[hidden], .period-nav[hidden], .period-nav [hidden] { display: none; }
/* The headline figure: tinted and edged so it reads first. */
.stat.stat-total { background: var(--ok-bg); border-color: var(--ok-line); }
.stat.stat-total .s-num { color: var(--ok-fg); }

/* ============================================================
   PRINTED REPORTS: a formal document, not a screenshot of the app.
   Small type in points, flat black-on-white boxes, a ruled letterhead,
   compact summary figures and dense tables. Comes last so it wins over
   the screen styles and the earlier print rules.
   ============================================================ */
@media print {
  @page {
    size: A4;
    margin: 14mm 12mm 16mm;
    @bottom-right {
      content: "Page " counter(page) " of " counter(pages);
      font-family: Manrope, Arial, sans-serif; font-size: 7.5pt; color: #555;
    }
  }
  html, body { font-size: 9pt; color: #000 !important; }

  /* Screen-only controls: filters, search, pickers, page controls. */
  .list-tools, .search, .report-actions, #ri-asof, .pager,
  .period-coverage, .range-error { display: none !important; }

  /* Letterhead: business, title, period and generated line, ruled off. */
  .print-header {
    margin: 0 0 10pt; padding-bottom: 6pt; border-bottom: 1.5pt solid #000;
  }
  .ph-biz   { font-size: 8pt; font-weight: 700; letter-spacing: .6pt; text-transform: uppercase; color: #333; }
  .ph-title { font-size: 15pt; font-weight: 800; margin-top: 2pt; color: #000; }
  .ph-sub   { font-size: 8.5pt; margin-top: 2pt; color: #000; }
  .ph-meta  { font-size: 7.5pt; color: #444; margin-top: 2pt; }

  /* Summary figures: one compact row of small boxes. */
  .grid.cols-2, .grid.cols-3, .grid.cols-4 {
    display: grid !important; grid-auto-flow: column; grid-auto-columns: 1fr;
    grid-template-columns: none !important; gap: 6pt !important; margin-bottom: 10pt;
  }
  .stat, .stat.stat-total {
    padding: 5pt 8pt !important; border: .75pt solid #888 !important; border-radius: 0 !important;
    background: #fff !important; min-height: 0 !important;
  }
  .stat .s-label { font-size: 6.5pt; letter-spacing: .4pt; color: #444; }
  .stat .s-num, .stat.stat-total .s-num {
    font-size: 12pt !important; margin: 2pt 0 0 !important; letter-spacing: 0; color: #000 !important;
  }
  .stat .s-sub { display: none; }

  /* Sections: a plain heading over a ruled table instead of a rounded card. */
  .card { border: 0 !important; border-radius: 0 !important; break-inside: auto !important; margin-top: 10pt !important; }
  .card-head {
    padding: 0 0 3pt !important; border: 0 !important; border-bottom: .75pt solid #000 !important;
    display: block !important;
  }
  .card-head h3 { font-size: 9.5pt; text-transform: uppercase; letter-spacing: .5pt; color: #000; }
  .card-head .badge, .card-head .sub { display: none !important; }

  table.tbl th {
    font-size: 6.8pt !important; letter-spacing: .3pt; color: #000 !important;
    background: #eee !important; padding: 3pt 5pt !important; border-bottom: .75pt solid #000 !important;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  table.tbl td {
    font-size: 7.8pt !important; padding: 2.5pt 5pt !important; color: #000 !important;
    border-bottom: .5pt solid #ccc !important;
  }
  table.tbl td * { color: #000 !important; }
  table.tbl td .muted { color: #333 !important; }
  table.tbl tbody tr:nth-child(even) td {
    background: #f6f6f6 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  /* Status badges read as plain words on paper. */
  .badge { border: 0 !important; padding: 0 !important; font-size: inherit !important; font-weight: 700 !important; }

  .lvl-bar { height: 5pt; border: .5pt solid #666 !important; border-radius: 0 !important; background: #fff !important; }
  .lvl-bar > span { background: #555 !important; border-radius: 0 !important; }

  /* The logo lives in the letterhead (top right of page 1) rather than as a
     fixed footer, which would print over the last row on every page. The
     business name runs in the bottom margin opposite the page number. */
  .print-footer { display: none !important; }
  .print-header { display: flex !important; align-items: flex-end; justify-content: space-between; gap: 12pt; }
  .ph-logo { display: block !important; height: 14mm; width: auto; max-width: 50mm; filter: grayscale(1) contrast(1.3); }
}
@media print {
  @page {
    @bottom-left {
      content: "KOHEN Car Aircon & Airconditioning Supplies";
      font-family: Manrope, Arial, sans-serif; font-size: 7.5pt; color: #555;
    }
  }
}
.ph-logo { display: none; }

/* Product Stock Details: Current Quantity centred under its heading on paper. */
@media print {
  table.tbl th.col-qty, table.tbl td.col-qty { text-align: center; }
}

/* Row number (#) on report tables: paper only, so a printout can be counted
   and referred to by row. The screen keeps its pager instead. */
.col-num { display: none; }
@media print {
  table.tbl th.col-num, table.tbl td.col-num { display: table-cell; width: 1%; white-space: nowrap; text-align: right; }
}

/* Placeholder text everywhere (search boxes, form fields): readable, still
   lighter than typed text. Browsers' own default is close to 2.5:1. */
input::placeholder, textarea::placeholder { color: var(--ink-300); opacity: 1; }

/* Admin Management: Active / Archived tabs, each with its account count. */
.tab-count {
  display: inline-block; min-width: 20px; margin-left: 6px; padding: 1px 7px;
  border-radius: var(--radius-pill); background: var(--line-2); color: var(--ink-500);
  font-size: 11px; font-weight: 800; text-align: center;
}
.tab.active .tab-count { background: var(--brand-50); color: var(--brand-700); }
/* .btn sets display, which would otherwise beat the hidden attribute. */
.btn[hidden] { display: none; }

/* ============================================================
   NOTIFICATIONS: bell beside the profile name, and its panel.
   ============================================================ */
.topbar-right { display: flex; align-items: center; gap: 12px; }
.notif { position: relative; }
.notif-btn {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); box-shadow: var(--shadow-sm);
  color: var(--ink-700);
}
.notif-btn svg { width: 19px; height: 19px; }
.notif-btn:hover, .notif.open .notif-btn { background: var(--brand-50); color: var(--brand-text); border-color: var(--brand-200); }
.notif-btn:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 2px; }
.notif-count {
  position: absolute; top: -4px; right: -4px; min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: 999px; background: var(--bad-solid); color: #fff; border: 2px solid var(--card);
  font-size: 10.5px; font-weight: 800; line-height: 15px; text-align: center;
}
.notif-count[hidden] { display: none; }
.notif-panel {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 40;
  width: min(380px, calc(calc(100vw / var(--ui-zoom)) - 32px));
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 14px 40px rgba(16,27,45,.16); overflow: hidden;
}
.notif-panel[hidden] { display: none; }
.notif-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; border-bottom: 1px solid var(--line-2); font-size: 14px;
}
.notif-head .link-btn { font-size: 12px; }
.notif-head .link-btn:disabled { color: var(--ink-300); cursor: default; text-decoration: none; }
.notif-list { list-style: none; margin: 0; padding: 4px; max-height: min(430px, calc(60vh / var(--ui-zoom))); overflow-y: auto; }
.notif-item {
  width: 100%; display: flex; align-items: flex-start; gap: 11px; text-align: left;
  padding: 10px 10px; border: 0; border-radius: 10px; background: transparent;
  font: inherit; color: var(--ink-700); cursor: pointer;
}
.notif-item:hover { background: var(--bg); }
.notif-item.is-unread { background: var(--surface-2); }
.notif-item.is-unread:hover { background: var(--brand-50); }
.notif-item:focus-visible { outline: 2px solid var(--brand-500); outline-offset: -2px; }
.notif-ico {
  flex: none; width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
}
.notif-ico svg { width: 15px; height: 15px; }
.tone-warn  { background: var(--warn-bg); color: var(--warn-fg); }
.tone-bad   { background: var(--bad-bg);  color: var(--bad-fg); }
.tone-ok    { background: var(--ok-bg);   color: var(--ok-fg); }
.tone-brand { background: var(--brand-50); color: var(--brand-text); }
.tone-soft  { background: var(--line-2);  color: var(--ink-500); }
.notif-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.notif-msg { font-size: 12.8px; line-height: 1.4; overflow-wrap: anywhere; }
.notif-item.is-unread .notif-msg { font-weight: 700; color: var(--ink-900); }
.notif-time { font-size: 11.5px; color: var(--ink-400); }
.notif-dot { flex: none; width: 8px; height: 8px; margin-top: 6px; border-radius: 50%; background: var(--brand-600); }
.notif-empty {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 30px 16px; text-align: center; font-size: 12.5px; color: var(--ink-400);
}
.notif-empty svg { width: 26px; height: 26px; opacity: .6; }
.notif-foot { padding: 9px 16px; border-top: 1px solid var(--line-2); font-size: 11px; color: var(--ink-400); }
@media print { .notif { display: none !important; } }



/* ============================================================
   DARK THEME
   <html data-theme="dark">, set before first paint by the inline script in
   each page's <head> (choice stored in localStorage "kohen_theme": light,
   dark or system). Every colour above comes from these tokens, so the dark
   theme is this one block. Contrast was kept at the light theme's levels:
   body text 4.5:1 or better on --card and --bg.
   ============================================================ */
:root[data-theme="dark"] {
  color-scheme: dark;
  /* Charcoal dark, modelled on the STI student portal: neutral charcoal
     page and cards (no blue cast), gentle off-white text, and a calm
     teal-blue accent that fills the selected tab / option with white text.
     Every text colour meets 4.5:1 on the cards except --ink-300 (icons,
     small hints, 4.3:1). */

  --brand-50:  #13303d;
  --brand-100: #173a4a;
  --brand-200: #1f5269;
  --brand-400: #3ec3e8;
  --brand-500: #1c95c9;
  /* Muted teal for selected items and fills (softer than the portal's
     #047eaf); --on-brand is the softened white text that sits on it. */
  --brand-600: #2a6680;
  --on-brand: #dfe8ee;
  --brand-700: #3ec3e8;
  --brand-text: #3ec3e8;

  /* Softened about 10% from the portal's #e4e6f0 for longer reading. */
  --ink-900: #d5d8e2;
  --ink-700: #bcc0cc;
  --ink-500: #a9adbb;
  --ink-400: #9498a8;
  --ink-300: #81859a;
  --line:    #30323f;
  --line-2:  #292a35;
  --bg:      #14151b;
  --card:    #22232e;
  --surface-2: #1b1c24;
  --surface-3: #2b2c39;
  --topbar-bg: rgba(20,21,27,.9);

  /* Green and red are soft pastels for text and badges, with deeper solid
     versions for anything that carries white text. */
  --ok-bg:#1d3028;   --ok-fg:#7fd6a3;   --ok-line:#2f5443;   --ok-solid:#2e7d54;
  --warn-bg:#352b17; --warn-fg:#e9b44f; --warn-line:#5f4a22;
  --bad-bg:#3a2429;  --bad-fg:#f08a8f;  --bad-line:#61363d;  --bad-solid:#b4464c;
  --violet-bg:#2a2340; --violet-fg:#c4b5fd;

  --shadow-sm: 0 1px 3px rgba(0,0,0,.30);
  --shadow-md: 0 4px 14px rgba(0,0,0,.40);
}
/* Native form fields follow color-scheme; make sure typed text and the
   field itself use the theme rather than the browser's light defaults. */
:root[data-theme="dark"] input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
:root[data-theme="dark"] select,
:root[data-theme="dark"] textarea {
  background-color: var(--card); color: var(--ink-900); border-color: var(--line);
}
/* Images (product photos, logos) are not inverted; just softened a touch. */
:root[data-theme="dark"] img { filter: brightness(.92); }
:root[data-theme="dark"] .print-footer img, :root[data-theme="dark"] .ph-logo { filter: none; }

/* Printouts are always black on white, whatever the screen theme. */
@media print {
  :root[data-theme="dark"] {
    color-scheme: light;
    --brand-50:#eef2fc; --brand-100:#d0dfef; --brand-200:#9fc8e1; --brand-400:#5fa8d3;
    --brand-500:#2e7eb0; --brand-600:#05449f; --brand-700:#05449f; --brand-text:#05449f;
    --ink-900:#0f1b2d; --ink-700:#1f2d40; --ink-500:#4a5a70; --ink-400:#5c6b80; --ink-300:#6b7a90;
    --line:#cfd8e3; --line-2:#e1e7ef; --bg:#ffffff; --card:#ffffff;
    --surface-2:#f8fafd; --surface-3:#eef2f7;
    --ok-bg:#e7f7ee; --ok-fg:#15803d; --warn-bg:#fff3e0; --warn-fg:#b45309; --bad-bg:#fdeaea; --bad-fg:#b91c1c;
    --ok-solid:#15803d; --bad-solid:#b91c1c;
  }
  :root[data-theme="dark"] img { filter: none; }
}

/* Theme picker in the profile menu. */
.ud-theme { padding: 8px 10px 6px; border-top: 1px solid var(--line-2); margin-top: 4px; }
.ud-theme-label { font-size: 10.5px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; color: var(--ink-400); margin-bottom: 6px; }
.theme-seg { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; padding: 3px; border-radius: 9px; background: var(--surface-3); border: 1px solid var(--line); }
.theme-seg button {
  border: 0; border-radius: 7px; padding: 6px 4px; background: transparent; cursor: pointer;
  font: inherit; font-size: 11.5px; font-weight: 700; color: var(--ink-500);
}
.theme-seg button[aria-pressed="true"] { background: var(--card); color: var(--brand-700); box-shadow: var(--shadow-sm); }
.theme-seg button:focus-visible { outline: 2px solid var(--brand-500); outline-offset: 1px; }
.user-dropdown { width: 220px; }

/* Dark sidebar: charcoal like the portal's top bar, with the current page as
   a teal pill (white text), the same way the portal marks its active tab. */
:root[data-theme="dark"] .sidebar { background: #1b1c24; border-right-color: #292a35; }
:root[data-theme="dark"] .sb-brand { border-bottom-color: #292a35; }
:root[data-theme="dark"] .sb-role { background: #22232e; border-color: #30323f; }
:root[data-theme="dark"] .sb-link { color: var(--ink-700); }
:root[data-theme="dark"] .sb-link:hover { background: #2b2c39; color: var(--ink-900); }
:root[data-theme="dark"] .sb-link.active { background: var(--brand-600); color: var(--on-brand); box-shadow: none; }

/* ============================================================
   DARK THEME: coloured text on the theme's own surface.
   Buttons, badges and the inventory tabs drop their tinted fills in dark
   mode: the background is the card colour and only the text (plus a thin
   matching outline) carries the red / green / amber / blue. Tints read as
   muddy blocks on a dark page; coloured text on dark reads cleanly.
   Solid buttons (Save, Delete Permanently, active tabs) are unchanged.
   ============================================================ */
:root[data-theme="dark"] .btn-outline         { background: var(--card); border-color: var(--brand-200); }
:root[data-theme="dark"] .btn-outline-danger  { background: var(--card); border-color: var(--bad-line); }
:root[data-theme="dark"] .btn-outline-success { background: var(--card); border-color: var(--ok-line); }
:root[data-theme="dark"] .btn-outline:hover         { background: var(--surface-2); border-color: var(--brand-400); }
:root[data-theme="dark"] .btn-outline-danger:hover  { background: var(--surface-2); border-color: var(--bad-fg); }
:root[data-theme="dark"] .btn-outline-success:hover { background: var(--surface-2); border-color: var(--ok-fg); }

:root[data-theme="dark"] .badge { background: var(--card); border: 1px solid var(--line); }
:root[data-theme="dark"] .b-ok   { border-color: var(--ok-line); }
:root[data-theme="dark"] .b-warn { border-color: var(--warn-line); }
:root[data-theme="dark"] .b-bad  { border-color: var(--bad-line); }
:root[data-theme="dark"] .b-info { border-color: var(--brand-200); }

:root[data-theme="dark"] .tab[data-tab="active"]:not(.active),
:root[data-theme="dark"] .tab[data-tab="sold"]:not(.active),
:root[data-theme="dark"] .tab[data-tab="removed"]:not(.active) { background: var(--card); }
:root[data-theme="dark"] .tab[data-tab]:not(.active):hover { background: var(--surface-2); }

:root[data-theme="dark"] .icon-btn.danger:hover,
:root[data-theme="dark"] .icon-btn.success:hover { background: var(--surface-2); }

/* Dark theme, same idea for the blue blocks: Admin Management's summary
   strip and the primary buttons (Create Account, Save, Export...) sit on the
   card colour with light-blue text and a light-blue outline instead of a
   solid blue fill. The primary outline is brighter than .btn-outline's so
   the main action on a page still stands out. */
:root[data-theme="dark"] .admin-summary {
  background: var(--card); color: var(--ink-900); border: 1px solid var(--line);
}
:root[data-theme="dark"] .as-item { border-right-color: var(--line); }
:root[data-theme="dark"] .as-label { color: var(--ink-400); }
:root[data-theme="dark"] .as-num { color: var(--brand-text); }
:root[data-theme="dark"] .as-sub { color: var(--ink-500); }

:root[data-theme="dark"] .btn-primary {
  background: var(--card); color: var(--brand-text);
  border: 1px solid var(--brand-400); box-shadow: none;
}
:root[data-theme="dark"] .btn-primary:hover { background: var(--surface-2); border-color: var(--brand-text); }

/* Dark theme, AI Assistant: the chat header drops its solid blue bar for
   the card colour, with the bot icon and buttons in light blue - the same
   treatment as the other blue blocks. Your own messages become a soft blue
   bubble instead of a bright one. */
:root[data-theme="dark"] .chat-head {
  background: var(--card); color: var(--ink-900);
  border: 1px solid var(--line); border-bottom-color: var(--line-2);
}
:root[data-theme="dark"] .chat-head .ch-ico { background: var(--brand-50); color: var(--brand-text); }
:root[data-theme="dark"] .chat-head .ch-btn {
  background: var(--card); color: var(--brand-text); border-color: var(--brand-400);
}
:root[data-theme="dark"] .chat-head .ch-btn:hover { background: var(--surface-2); border-color: var(--brand-text); }
:root[data-theme="dark"] .chat-head .ch-btn[aria-pressed="true"] {
  background: var(--brand-50); color: var(--brand-text); border-color: var(--brand-text);
}
:root[data-theme="dark"] .msg.user .bubble {
  background: var(--brand-50); color: var(--ink-900); border: 1px solid var(--brand-200);
}
:root[data-theme="dark"] .msg.user .m-ava { background: var(--surface-3); color: var(--ink-900); }
:root[data-theme="dark"] .chip { background: var(--card); color: var(--brand-text); }
:root[data-theme="dark"] .chip:hover { background: var(--surface-2); }


/* ============================================================
   DISPLAY SCALE (90%)
   One page-wide scale, so every size in this file shrinks together.
   Charts get a matching mouse-position correction in data.js.
   ============================================================ */
html { zoom: var(--ui-zoom); }
/* Paper is always actual size. */
@media print { html { zoom: 1; } :root { --ui-zoom: 1; } }


/* Dark theme, selected states the portal way: the chosen tab, page number,
   theme option and filter fill with teal and white text, on a charcoal
   track. Action buttons keep the outlined style. */
:root[data-theme="dark"] .tabs { background: var(--card); border-color: var(--line); }
:root[data-theme="dark"] .tab { color: var(--ink-700); }
:root[data-theme="dark"] .tab.active:not([data-tab="sold"]):not([data-tab="removed"]) {
  background: var(--brand-600); color: var(--on-brand); outline: 0; box-shadow: none;
}
:root[data-theme="dark"] .pager-num.btn-primary,
:root[data-theme="dark"] .act-filter.active {
  background: var(--brand-600); color: var(--on-brand); border-color: var(--brand-600);
}
:root[data-theme="dark"] .theme-seg button[aria-pressed="true"] { background: var(--brand-600); color: var(--on-brand); }
:root[data-theme="dark"] .notif-dot { background: var(--brand-400); }
:root[data-theme="dark"] .notif-item.is-unread { background: #262836; }
/* Product photo area with no photo: neutral charcoal, not a teal wash. */
:root[data-theme="dark"] .pc-media { background: var(--surface-3); }

/* Dark theme, Inventory Activity: words in the system's normal off-white.
   The kind of change still shows at a glance through each item's colour -
   the outline on the Today pills and tags, the icon and the left stripe -
   while the text itself stays one calm colour. */
:root[data-theme="dark"] .act-pill {
  background: var(--card); color: var(--ink-900);
  border: 1px solid color-mix(in srgb, var(--k-fg) 45%, transparent);
}
:root[data-theme="dark"] .act-pill b { color: var(--ink-900); }
:root[data-theme="dark"] .act-tag {
  background: transparent; color: var(--ink-900);
  border: 1px solid color-mix(in srgb, var(--k-fg) 55%, transparent);
}
:root[data-theme="dark"] .act-meta { color: var(--ink-500); }
:root[data-theme="dark"] .act-time { color: var(--ink-500); }

/* Dark theme, segmented pickers (Revenue / Units Sold / Gross Profit and
   similar): no coloured fill. The chosen one is white text on a slightly
   lighter charcoal pill; the others are dimmer grey text. */
:root[data-theme="dark"] .seg button { color: var(--ink-500); }
:root[data-theme="dark"] .seg button:hover { color: var(--ink-900); }
:root[data-theme="dark"] .seg button[aria-pressed="true"] {
  background: #3a3c4c; color: var(--ink-900); box-shadow: none;
}
:root[data-theme="dark"] .seg-btn { color: var(--ink-500); }
:root[data-theme="dark"] .seg-btn.active { background: #3a3c4c; color: var(--ink-900); box-shadow: none; }
:root[data-theme="dark"] .seg-btn:hover { color: var(--ink-900); }

/* Dark theme, Business Insights: the card colour with a coloured left edge,
   off-white heading and softer grey body - the same pattern as Inventory
   Activity, instead of light pastel boxes. */
:root[data-theme="dark"] .insight { background: var(--surface-2); border: 1px solid var(--line); border-left-width: 4px; color: var(--ink-500); }
:root[data-theme="dark"] .insight .i-title { color: var(--ink-900); }
:root[data-theme="dark"] .insight.i-up   { border-left-color: var(--ok-fg); }
:root[data-theme="dark"] .insight.i-warn { border-left-color: var(--warn-fg); }
:root[data-theme="dark"] .insight.i-info { border-left-color: var(--brand-400); }
/* The sidebar's account block is white in light mode; soften it to match. */
:root[data-theme="dark"] .sb-role, :root[data-theme="dark"] .sb-role .r-title { color: var(--ink-900); }
:root[data-theme="dark"] .sb-role .r-sub { color: var(--ink-500); }
/* The white KOHEN logo in the sidebar, softened to the same off-white as the
   dark theme's main text (#d5d8e2 is about 84% of white). */
:root[data-theme="dark"] .sb-logo-img { filter: brightness(.84); }
/* Inventory "Active Products" tab when selected: same soft teal. */
:root[data-theme="dark"] .tab[data-tab="active"].active { background: var(--brand-600); color: var(--on-brand); border-color: var(--brand-600); }

/* ============================================================
   ADD / EDIT PRODUCT window: image and fields side by side, so the whole
   form fits on a laptop screen without scrolling. Stacks again on narrow
   screens.
   ============================================================ */
.modal.modal-product { max-width: 900px; }
.modal-product .modal-body { padding-top: 12px; }
.pm-layout { display: grid; grid-template-columns: 250px 1fr; gap: 20px; align-items: start; }
.pm-image { margin: 0; }
.pm-image .dropzone {
  padding: 16px 14px; min-height: 230px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.pm-image .dz-preview { max-height: 150px; margin-bottom: 10px; }
.pm-fields .form-grid { max-width: none; gap: 12px 14px; }
.modal-product .form-field input, .modal-product .form-field select { padding: 9px 12px; }
.modal-product .form-field label { margin-bottom: 5px; }
@media (max-width: 760px) {
  .pm-layout { grid-template-columns: 1fr; }
  .pm-image .dropzone { min-height: 0; }
}
/* The upload button's icon is a normal button icon, not the big dropzone one. */
.dropzone .btn svg { width: 15px; height: 15px; opacity: 1; }
