:root {
  --green: #0F5132;
  --green-dark: #0A3B24;
  --green-light: #E8F3EC;
  --gold: #B8860B;
  --amber: #B8860B;
  --amber-light: #FBF2DD;
  --amber-ink: #7A5605;   /* amber for text — --amber itself is too light to read on paper/amber-light */
  --red: #B3261E;
  --red-light: #FBE9E7;
  --ink: #201E1B;
  /* Design rule (going forward, app-wide): no gray/muted text color anywhere
     — light gray reads poorly in bright daylight, which is how this app is
     mostly used. --ink-soft used to be a genuinely lighter gray-brown
     (a gray-brown) for "less important" text (meta lines, axis labels, timestamps);
     it's now the same deep near-black as --ink itself. Every "soft"/muted
     text style in the app inherits this automatically since they all read
     the variable rather than a hardcoded color — visual hierarchy for that
     text now comes from size/weight/letter-spacing, not from being lighter. */
  --ink-soft: #201E1B;
  --paper: #EFE8D8;
  --card: #FFFFFF;
  --line: #E7E2DC;
  --radius: 15px;
  --radius-sm: 10px;
  --radius-lg: 20px;
  --shadow-sm: 0 1px 2px rgba(32,30,27,0.05), 0 1px 1px rgba(32,30,27,0.04);
  --shadow-md: 0 6px 20px rgba(15,81,50,0.09), 0 2px 6px rgba(32,30,27,0.05);
  --shadow-lg: 0 16px 40px rgba(15,81,50,0.16);
  --sidebar-w: 200px; /* desktop menu: the phone drawer, docked (Kodi-style rows) */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  /* Dashboard data colors — validated for colorblind-safety with the
     dataviz skill's palette checker (lightness band, chroma floor, CVD
     separation, contrast). Distinct from the brand chrome colors above
     (--green/--amber/--red), which stay reserved for nav/buttons/badges
     everywhere else in the app and never carry chart/data meaning. */
  --d-sales: #008300;       --d-sales-light: #E3F3E3;
  --d-blue: #4D7AB3;        --d-blue-light: #E7EEF6;   /* Top sellers bars */
  --d-violet: #6F5FA0;      --d-violet-light: #ECE8F7;  /* Rush hours bars */
  --d-orange: #eb6834;      --d-orange-light: #FDEBE3;  /* Stock value */
  --d-magenta: #e87ba4;     --d-magenta-light: #FCEAF1; /* Supplier debt */
  --d-critical: #d03b3b;    --d-serious: #ec835a;    --d-warning: #fab219;    --d-good: #0ca30c;
  --d-ctx-warm: #BE8F87;    /* de-emphasis "cost of goods" segment, closer to red per feedback */
  --d-gridline: #E7E2DC;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--paper); color: var(--ink); }
body { -webkit-font-smoothing: antialiased; padding-bottom: env(safe-area-inset-bottom); }
#app { min-height: 100vh; display: flex; flex-direction: column; }

button { font: inherit; cursor: pointer; }
input, select, textarea { font: inherit; }

/* A small reusable badge: the "H" mark on a rounded green square, matching
   the app icon (icons/icon-512.png). Used on the topbar, the sidebar, the
   loading screen and every auth screen so the brand has one consistent
   mark instead of plain unstyled "Pharma" text. */
.brand-badge {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(155deg, var(--green), var(--green-dark));
  color: #fff; border-radius: 30%; box-shadow: var(--shadow-sm);
  font-weight: 800; line-height: 1;
}
.ic-svg { display: block; }

/* ---------------------------------------------------------------------- */
/* TOPBAR — on a phone this is the brand bar (green, holds the identity).  */
/* On desktop the brand moves into the sidebar instead (see below), so     */
/* the topbar becomes a slim, quiet utility strip: just the current        */
/* pharmacy name and account controls, not a second copy of the logo.      */
/* ---------------------------------------------------------------------- */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; background: var(--green); color: #fff;
  position: sticky; top: 0; z-index: 10; box-shadow: var(--shadow-sm);
  /* In the Android app the page runs edge-to-edge, so the phone's clock and
     battery sit on top of the page. This padding keeps the green bar's
     content below them (and the green behind them). 0 in a normal browser. */
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  padding-left: max(16px, env(safe-area-inset-left, 0px));
  padding-right: max(16px, env(safe-area-inset-right, 0px));
}
.topbar-id { display: flex; align-items: center; gap: 10px; }
.topbar-id .brand-badge { background: rgba(255,255,255,0.14); box-shadow: none; }
.topbar .brand { font-weight: 700; font-size: 17px; letter-spacing: 0.2px; line-height: 1.2; }
.topbar .sub { font-size: 12px; opacity: 0.85; margin-top: 1px; }
.topbar button { background: rgba(255,255,255,0.15); color: #fff; border: none; border-radius: 10px; padding: 8px 12px; transition: background 0.15s; }
.topbar button:hover { background: rgba(255,255,255,0.25); }

.content { flex: 1; padding: 16px; padding-bottom: 90px; max-width: 720px; margin: 0 auto; width: 100%; }

/* ---------------------------------------------------------------------- */
/* NAV — a bottom tab bar on a phone, the same element becomes the full   */
/* left sidebar on desktop (see the min-width:860px block below). Brand   */
/* and account blocks are written into it too, but stay hidden until      */
/* the desktop layout has room for them.                                  */
/* ---------------------------------------------------------------------- */
.navbar {
  position: fixed; bottom: 0; left: 0; right: 0; background: linear-gradient(165deg, var(--green) 0%, var(--green-dark) 100%);
  display: flex; z-index: 10;
  padding-bottom: env(safe-area-inset-bottom);
}
.navbar-brand, .navbar-foot { display: none; }
.navbar button {
  flex: 1; background: none; border: none; padding: 9px 4px 8px; color: rgba(255,255,255,0.62);
  display: flex; flex-direction: column; align-items: center; gap: 4px; font-size: 10.5px; font-weight: 600;
}
.navbar button .ic {
  display: flex; padding: 4px 14px; border-radius: 999px; transition: background 0.15s, color 0.15s;
}
.navbar button.active { color: #fff; }
.navbar button.active .ic { background: var(--amber); color: #241A03; }

/* Item 31: the left/right colored-accent border pattern, ported over from
   ShuleTop's .stat/.hub-tile tiles (src/styles/main.css) — a thin 1px
   border all around plus a thicker 4px accent specifically on the left and
   right edges, colored to match the tile's own hue. The base rule reserves
   transparent 4px left/right borders so nothing shifts in width when a
   .t-* (or dash-pill/dash-*) color class later recolors them. */
.card {
  background: var(--card); border: 1px solid var(--line); border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-radius: var(--radius); padding: 14px; margin-bottom: 12px; box-shadow: var(--shadow-sm);
}
.kpi-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.kpi {
  background: var(--card); border: 1px solid var(--line); border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow-sm);
}
.kpi .label { font-size: 12px; color: var(--ink-soft); font-weight: 600; }
.kpi .value { font-size: 23px; font-weight: 800; margin-top: 5px; font-variant-numeric: tabular-nums; letter-spacing: -0.2px; }

/* Expiry Reports drill-down: the summary KPI tiles are now real <button>
   elements (clicking one opens that category's full list), so they need
   the same text-align/width/cursor reset .report-tile below already uses
   to undo default button centering and auto-width, plus a matching hover
   lift so it's visually obvious they're clickable. */
.kpi-clickable { text-align: left; width: 100%; cursor: pointer; font: inherit; color: inherit; transition: box-shadow 0.15s, transform 0.15s; }
.kpi-clickable:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }

/* Item 30 (tile color sketch, approved): every summary tile across the app
   (drug detail, Reports, Suppliers, Expenses) now uses a light tint from
   the same palette as the Dashboard's Sales/Stock value/Profit pills,
   instead of plain white or the old bold solid-color "good/bad/warn"
   treatment. Color is chosen by what the number means, not per-screen:
   sales/green = money in or a healthy state, orange = stock & goods
   movement, violet = a neutral count, red = money out/owed, amber =
   needs attention, neutral gray = zero/not applicable. Item 31 adds the
   matching accent border color on top (border-color recolors all four
   sides at once, so the 1px top/bottom and the 4px left/right both pick up
   the same hue in one declaration — same trick ShuleTop's CSS uses). */
.kpi.t-sales   { background: var(--d-sales-light); border-color: var(--d-sales); }
.kpi.t-sales .label { color: var(--d-sales); }
.kpi.t-orange  { background: var(--d-orange-light); border-color: var(--d-orange); }
.kpi.t-orange .label { color: var(--d-orange); }
.kpi.t-violet  { background: var(--d-violet-light); border-color: var(--d-violet); }
.kpi.t-violet .label { color: var(--d-violet); }
.kpi.t-magenta { background: var(--d-magenta-light); border-color: var(--d-magenta); }
.kpi.t-magenta .label { color: var(--d-magenta); }
.kpi.t-green   { background: var(--green-light); border-color: var(--green); }
.kpi.t-green .label { color: var(--green); }
.kpi.t-amber   { background: var(--amber-light); border-color: var(--amber); }
.kpi.t-amber .label { color: #8a6408; }
.kpi.t-red     { background: var(--red-light); border-color: var(--red); }
.kpi.t-red .label { color: var(--red); }
.kpi.t-red .value { color: var(--red); }
.kpi.t-neutral { background: #F1EEEA; border-color: var(--line); }
.kpi.t-neutral .label { color: var(--ink-soft); }

/* Item 32: the Reports hub — a grid of tinted, accent-bordered tiles (same
   .t-* tint tokens and border-accent trick as .kpi, items 30/31) instead of
   a flat list, one per report sub-module. */
.reports-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 640px) { .reports-grid { grid-template-columns: 1fr 1fr; } }
.report-tile {
  display: flex; align-items: flex-start; gap: 14px; text-align: left; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow-sm); width: 100%;
  transition: box-shadow 0.15s, transform 0.15s; font: inherit; color: inherit;
}
.report-tile:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.report-tile .r-ico {
  width: 44px; height: 44px; border-radius: 12px; background: #fff;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.report-tile .r-title { font-weight: 700; font-size: 15px; color: var(--ink); }
.report-tile .r-desc { font-size: 12.5px; color: var(--ink-soft); margin-top: 3px; }
.report-tile.t-sales   { background: var(--d-sales-light); border-color: var(--d-sales); }
.report-tile.t-sales .r-ico   { color: var(--d-sales); }
.report-tile.t-orange  { background: var(--d-orange-light); border-color: var(--d-orange); }
.report-tile.t-orange .r-ico  { color: var(--d-orange); }
.report-tile.t-violet  { background: var(--d-violet-light); border-color: var(--d-violet); }
.report-tile.t-violet .r-ico  { color: var(--d-violet); }
.report-tile.t-amber   { background: var(--amber-light); border-color: var(--amber); }
.report-tile.t-amber .r-ico   { color: #8a6408; }
.report-tile.t-red     { background: var(--red-light); border-color: var(--red); }
.report-tile.t-red .r-ico     { color: var(--red); }

h1, h2, h3 { margin: 0 0 10px; }
h2 { font-size: 16px; }
.section-title { font-size: 13px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--ink-soft); margin: 18px 0 8px; font-weight: 600; }

.list-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 0; border-bottom: 1px solid var(--line); gap: 10px;
}
.list-row:last-child { border-bottom: none; }
.list-row .name { font-weight: 600; }
.list-row .meta { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.list-row .right { text-align: right; white-space: nowrap; }

/* A small round initial badge, colour-coded by status (good/warn/bad),
   used in front of a list row's name (drug rows, first on the Stock tab)
   instead of leaving every row as plain text with nothing to scan by eye. */
.row-avatar {
  width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700; background: var(--green-light); color: var(--green);
}
.row-avatar.warn { background: var(--amber-light); color: var(--amber-ink); }
.row-avatar.bad { background: var(--red-light); color: var(--red); }

.badge { display: inline-block; font-size: 11px; padding: 3px 9px; border-radius: 999px; font-weight: 700; }
.badge.bad { background: var(--red-light); color: var(--red); }
.badge.warn { background: var(--amber-light); color: var(--amber-ink); }
.badge.good { background: var(--green-light); color: var(--green); }
.badge.muted { background: #EFEDEA; color: var(--ink-soft); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: none; border-radius: 12px; padding: 12px 16px; font-weight: 600; width: 100%;
  transition: filter 0.12s, transform 0.05s, background 0.12s;
}
.btn.primary { background: var(--green); color: #fff; box-shadow: 0 3px 10px rgba(15,81,50,0.28); }
.btn.secondary { background: var(--green-light); color: var(--green); }
.btn.ghost { background: #EFEDEA; color: var(--ink); }
.btn.danger { background: var(--red-light); color: var(--red); }
.btn.small { width: auto; padding: 8px 12px; font-size: 13px; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn:not(:disabled):hover { filter: brightness(1.06); }
.btn:not(:disabled):active { transform: scale(0.98); }

.field { margin-bottom: 12px; }
.field label { display: block; font-size: 13px; color: var(--ink-soft); margin-bottom: 5px; }
.field input, .field select, .field textarea {
  width: 100%; padding: 11px 12px; border: 1px solid var(--line); border-radius: 10px; background: #fff;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--green); box-shadow: 0 0 0 3px var(--green-light);
}
.field .hint { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
/* Password box with a show/hide eye (js/core.js pwEye, admin.js wirePwEyes) */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 44px; }
.pw-eye { position: absolute; top: 0; right: 0; bottom: 0; width: 42px; display: grid; place-items: center; background: none; border: 0; padding: 0; cursor: pointer; color: var(--green); border-radius: 0 10px 10px 0; }
.pw-eye:focus-visible { outline: 2px solid var(--green); outline-offset: -2px; }
.row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.row-2 > *, .row-3 > * { min-width: 0; }
.field input, .field select, .field textarea { min-width: 0; }
.row-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; }

/* Same border color every card/kpi/tile in the app already uses, plus their
   shadow — the 1px var(--line) border alone barely reads on this input's
   near-white background (especially inside a white sheet), so on its own it
   looked like the filter bar had no border at all next to the tiles around
   it. */
.searchbox input { width: 100%; padding: 11px 14px; border-radius: 999px; border: 1px solid var(--line); background: #fff; box-shadow: var(--shadow-sm); }

.fab {
  position: fixed; right: 16px; bottom: 78px; z-index: 11;
  background: var(--green); color: #fff; border: none; border-radius: 999px;
  width: 54px; height: 54px; box-shadow: var(--shadow-lg);
  display: flex; align-items: center; justify-content: center;
}

.mask { position: fixed; inset: 0; background: rgba(20,18,16,0.5); display: flex; align-items: flex-end; z-index: 50; }
.sheet { background: #fff; width: 100%; max-height: 88vh; overflow-y: auto; border-radius: 18px 18px 0 0; padding: 18px 16px 24px; }
@media (min-width: 640px) {
  .mask { align-items: center; justify-content: center; }
  .sheet { max-width: 480px; border-radius: 18px; box-shadow: var(--shadow-lg); }
}
.sheet-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
.sheet-head h2 { margin: 0; }
.sheet-head button { background: none; border: none; color: var(--ink-soft); display: flex; padding: 4px; border-radius: 8px; }
.sheet-head button:hover { background: #F1EFEC; }

.cart-line { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px dashed var(--line); }
.cart-line .qty-ctrl { display: flex; align-items: center; gap: 8px; }
.qty-ctrl button { width: 28px; height: 28px; border-radius: 8px; border: 1px solid var(--line); background: #fff; }

.empty { text-align: center; padding: 40px 16px; color: var(--ink-soft); }
.toast { position: fixed; left: 50%; top: calc(18px + env(safe-area-inset-top, 0px)); transform: translateX(-50%); background: var(--ink); color: #fff; padding: 10px 16px; border-radius: 10px; font-size: 14px; z-index: 100; opacity: 0.97; box-shadow: var(--shadow-md); }
.toast.bad { background: var(--red); }
.toast.good { background: var(--green); }

/* ---------------------------------------------------------------------- */
/* AUTH — a proper split layout on desktop (green brand panel with floating */
/* stat cards + form) instead of a tiny centered card in a sea of empty     */
/* page; on mobile the same panel collapses into a curved-gradient hero     */
/* above the form, with a trust line near the bottom. Sketched against      */
/* Kodi's own login/signup screens and approved before being wired up.      */
/* ---------------------------------------------------------------------- */
/* position:relative + min-height so auth-bg-fill (below) and the pinned
   trust line both anchor to the FULL screen, not to whichever child happens
   to be tallest. dvh (with the vh fallback first for older browsers) tracks
   the real visible viewport on mobile, same technique used elsewhere in
   this app's own mobile-viewport handling. */
/* z-index:0 (not just position:relative) is what actually matters here —
   without it .auth-wrap never forms its own stacking context, so the
   z-index:-1 background below escapes upward and paints behind the PAGE's
   own background instead of behind just auth-wrap's in-flow content, which
   is what made the whole green fill invisible the first time this was
   wired up. */
.auth-wrap { position: relative; z-index: 0; min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; padding-bottom: 74px; }
/* One continuous green background behind auth-brand AND auth-form-col, so
   the hero text, the floating card and the trust line all read as ONE green
   screen — matching the approved sketch — instead of auth-brand's own green
   box ending right after its text and the card floating in a separately
   colored section below it. Desktop (900px query below) turns this off and
   lets auth-brand paint its own green instead, since desktop is a genuine
   two-color split (green left / paper right), not one continuous screen. */
.auth-bg-fill {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(160deg, #17945C 0%, var(--green) 55%, var(--green-dark) 100%);
}
.auth-brand { position: relative; padding: calc(40px + env(safe-area-inset-top, 0px)) 24px 8px; text-align: center; color: #fff; }
.auth-brand-top { position: relative; z-index: 1; }
.auth-brand .brand-badge { margin: 0 auto 16px; background: #fff; color: var(--green); box-shadow: none; }
.auth-form-col { flex: 1; display: flex; align-items: center; justify-content: center; padding: 8px 20px 0; }
.auth-card { width: 100%; max-width: 380px; }
/* The sign-in card itself: a soft tint instead of plain white, per direct
   feedback — reuses --green-light rather than a new one-off color. */
.auth-form-col .card { background: var(--green-light); }
/* auth-toggle sits below the card, on the continuous green fill on mobile
   (see auth-bg-fill above) — so it needs light/white text there. Desktop
   resets it back to dark-on-beige, since auth-form-col is plain paper
   background there instead (see the 900px query below). */
.auth-toggle { text-align: center; margin-top: 14px; font-size: 13px; color: rgba(255,255,255,0.85); }
.auth-toggle a { color: #fff; font-weight: 700; text-decoration: underline; }
.error-text { color: var(--red); font-size: 13px; margin-top: 6px; }
.tiny { font-size: 12px; color: var(--ink-soft); }
.spacer { height: 8px; }

/* Simple one-off screens (startup error, password recovery): centered card,
   no split panel — there's nothing to browse, just one thing to do. */
.auth-wrap-simple { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; }
.auth-wrap-simple .auth-card { text-align: center; }
.auth-wrap-simple .brand-badge { margin: 0 auto 10px; }
.auth-wrap-simple .mark { font-size: 22px; font-weight: 800; color: var(--green); }
.auth-wrap-simple .tag { font-size: 13px; color: var(--ink-soft); margin-top: 2px; }
.auth-wrap-simple .card { text-align: left; }

/* A row of auxiliary action buttons (Sync/Import/Excel/Print — secondary
   to the page's one primary action) as a single bordered, dividered strip
   instead of separate boxes that wrap unevenly when a label runs long. */
.toolbar-row { display: flex; align-items: stretch; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.toolbar-row .btn { width: auto; flex: 1 1 auto; min-width: 0; white-space: nowrap; }
.toolbar-segment {
  display: flex; align-items: stretch; background: #fff; border: 1px solid var(--line);
  border-radius: 12px; overflow: hidden; flex-wrap: wrap;
}
.toolbar-segment .btn {
  width: auto; flex: 1 1 auto; white-space: nowrap; background: transparent; color: var(--ink);
  border-radius: 0; border-right: 1px solid var(--line);
}
.toolbar-segment .btn:last-child { border-right: none; }
.toolbar-segment .btn:hover { background: #F5F2EA; }
.toolbar-primary { flex-shrink: 0; width: auto; }
/* Pushes the Excel/Print segment (or any trailing toolbar item) to the
   right edge of its .toolbar-row, leaving any primary/left-hand actions
   in place — an auto left-margin absorbs all remaining row width, so it
   works whether it's the only child or has siblings before/after it. */
.toolbar-end { margin-left: auto; }
.inline-notice {
  display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 700;
  color: var(--amber-ink); margin-bottom: 12px;
}
.inline-notice a { color: inherit; text-decoration: none; }

/* ---------------------------------------------------------------------- */
/* DESKTOP LAYOUT — the bottom tab bar becomes a full-height branded       */
/* sidebar (dark green, gold active state), and the topbar becomes a      */
/* slim white utility strip beside it rather than a second brand bar.     */
/* ---------------------------------------------------------------------- */
@media (min-width: 860px) {
  .topbar {
    margin-left: var(--sidebar-w); padding-left: 28px; padding-right: 28px;
    background: #fff; color: var(--ink); box-shadow: none; border-bottom: 1px solid var(--line);
  }
  .topbar-id .brand-badge, .topbar .brand { display: none; }
  .topbar .sub { color: var(--ink); font-size: 14px; font-weight: 700; opacity: 1; }
  .topbar button { background: var(--green-light); color: var(--green); font-weight: 600; }
  .topbar button:hover { background: #DCEEE2; }

  .navbar {
    top: 0; bottom: 0; left: 0; right: auto; width: var(--sidebar-w);
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    padding: 18px 10px; gap: 2px; box-shadow: 4px 0 20px rgba(10,59,36,0.12);
  }
  .navbar-brand {
    display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 0 4px; margin-bottom: 22px; text-align: center;
  }
  .navbar-brand .brand-badge { width: 32px; height: 32px; font-size: 15px; background: #fff; color: var(--green); }
  .navbar-brand .word { font-size: 14px; font-weight: 800; color: #fff; letter-spacing: 0.2px; }
  /* A narrower column (halved from 264px per feedback) has no room for an
     icon beside a full-width label without wrapping or overflow — icon
     stacked above a small label reads cleanly at this width and still shows
     the full word, just vertically instead of side by side. */
  .navbar button {
    flex: none; flex-direction: column; justify-content: center; gap: 4px;
    padding: 9px 4px; font-size: 10.5px; font-weight: 700; border-radius: 12px;
    line-height: 1.15; text-align: center;
  }
  .navbar button .ic { padding: 0; background: none !important; color: inherit !important; }
  .navbar button .ic-svg { width: 18px; height: 18px; }
  .navbar button.active { background: var(--amber); color: #241A03; box-shadow: 0 4px 12px rgba(184,134,11,0.35); }
  .navbar-spacer { flex-grow: 1; }
  .navbar-foot {
    display: flex; flex-direction: column; gap: 2px; background: rgba(255,255,255,0.09);
    border-radius: 16px; padding: 14px 16px; margin-top: 10px;
  }
  .navbar-foot .who { font-size: 13.5px; font-weight: 700; color: #fff; }
  .navbar-foot .role { font-size: 12px; color: rgba(255,255,255,0.62); }

  /* FIX (PHARMA_PROJECT_STATUS.md item 29 — desktop right-margin bug): the base .content rule below is written
     for mobile, where "width:100%; margin:0 auto" is correct (no sidebar,
     just center a capped column). On desktop, only margin-left got
     overridden here (to clear the fixed sidebar) while width stayed a
     literal 100% of the FULL #app width and margin-right stayed the base
     rule's inherited "auto" — so the box was 100%-of-full-width-wide,
     shifted right by the sidebar, and every last pixel of the resulting
     overflow got absorbed into margin-right as one large empty gap on the
     right instead of the content actually using that space. Fixed by
     sizing width explicitly against the space actually left after the
     sidebar (calc, not 100%) and zeroing margin-right instead of
     inheriting auto. max-width raised from 900 to 1200 so wide desktop
     monitors show more (inventory rows, dashboard cards) instead of
     capping unnecessarily narrow. */
  .content { margin-left: var(--sidebar-w); margin-right: 0; width: calc(100% - var(--sidebar-w)); max-width: 1200px; padding: 24px 32px 60px; }
  .kpi-grid { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
}

/* ---------------------------------------------------------------------- */
/* DASHBOARD — redesigned dashboard: real date-range filter, an axis'd    */
/* sales trend + rush-hours chart, capped/click-through lists, and fixed  */
/* card sizes so a brand-new pharmacy with zero data sees clean           */
/* placeholders instead of a layout that jumps once real data arrives.    */
/* ---------------------------------------------------------------------- */
/* Item 33 (mobile dashboard redesign, approved via sketch): the urgent
   alerts strip from the first sketch — out-of-stock/soonest-expiry, tap
   through to Inventory. */
.dash-alert {
  display: flex; align-items: center; gap: 10px; background: var(--red-light); border: 1px solid #f3c7c2;
  border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; font-size: 12.5px; font-weight: 600;
  color: #8a2a22; cursor: pointer;
}
.dash-alert svg { flex-shrink: 0; }

/* Item 27/33: Sell + Restock side by side, then the live "is this drug in
   stock?" search below (was Sell + search sharing one row). */
.dash-actions { display: flex; gap: 8px; margin-bottom: 10px; }
.dash-actions .btn { width: auto; flex: 1; }
.dash-quick-search { position: relative; margin-bottom: 12px; }
/* Colored to match the tinted-tile treatment below (Sales/Stock
   value/Debt owed) rather than a neutral gray border — violet since this
   search is a neutral lookup, not tied to money in/out or stock value, the
   same meaning --d-violet already carries for Rush hours' bars. */
.dash-quick-search input {
  width: 100%; padding: 11px 14px; border-radius: 999px; border: 2px solid var(--d-violet); background: var(--d-violet-light);
}
.dash-quick-search input::placeholder { color: var(--d-violet); opacity: 0.75; }
.dash-quick-results {
  display: none; position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 5;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); max-height: 320px; overflow-y: auto; padding: 4px 14px;
}
.dash-quick-results.open { display: block; }
.dash-quick-result-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--line); cursor: pointer;
}
.dash-quick-result-row:last-child { border-bottom: none; }
.dash-quick-result-row:hover { background: #FAF9F7; }
.dash-quick-result-row.empty { color: var(--ink-soft); cursor: default; justify-content: center; }
.dash-quick-result-row.empty:hover { background: none; }
.dash-quick-result-row .name { font-weight: 600; }
.dash-quick-result-row .meta { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.dash-quick-result-row .right { display: flex; align-items: center; white-space: nowrap; }

/* Item 33: was plain underlined text tabs with a redundant period label —
   now a rounded segmented pill control (also reused as-is by Expenses'
   own date filter, so that gets the same polish for free), plus a
   calendar button opening a real custom-range picker. .dash-period-label
   stays defined for Expenses, which still uses it; the dashboard itself
   no longer renders it. */
.dash-filter-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.dash-tabs { flex: 1; display: flex; gap: 2px; background: #F1EEEA; border-radius: 999px; padding: 3px; flex-wrap: wrap; }
.dash-tab {
  flex: 1; background: none; border: none; padding: 7px 6px; font-size: 12px; font-family: inherit;
  color: var(--ink-soft); font-weight: 700; border-radius: 999px; cursor: pointer; white-space: nowrap;
}
.dash-tab.active { background: #fff; color: var(--ink); box-shadow: 0 1px 3px rgba(0,0,0,0.12); }
.dash-period-label { font-size: 12px; color: var(--ink-soft); padding-bottom: 10px; }
.dash-cal-btn {
  flex: none; width: 32px; height: 32px; border-radius: 50%; border: none; background: #F1EEEA;
  color: var(--ink-soft); display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.dash-cal-btn.active { background: var(--green); color: #fff; }
.dash-custom-label { font-size: 11.5px; color: var(--ink-soft); font-weight: 600; margin: -4px 0 10px; }

.dash-row { display: flex; flex-direction: column; gap: 16px; align-items: stretch; margin-bottom: 16px; }
@media (min-width: 860px) { .dash-row { flex-direction: row; } }
/* .dash-row's align-items:stretch already gives Top sellers/Expiring soon's
   .dash-col wrappers equal height on desktop (row layout) — but a wrapper
   being taller doesn't make the .card living inside it any taller, since
   .card is only ever as tall as its own content. Making .dash-col a column
   flex box and letting its one .card child grow (flex:1) is what actually
   carries that equal height down to the visible bordered box, so the two
   cards' borders line up bottom-to-bottom instead of whichever has fewer
   rows/no "View all" link stopping short. No effect on mobile's stacked
   layout, where each .dash-col's height is only ever its own content's. */
.dash-col { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.dash-col > .card { flex: 1; }

/* Item 33: the Sales graph card is solo now (Rush hours dropped from this
   layout), so it's no longer height-matched to a sibling — content decides
   its height instead of a fixed 300px that used to leave a lot of empty
   space under a short chart. Card header is now .dash-card-head (compact,
   shared with Stock health/Top sellers/Expiring soon below) instead of
   the old centered section-title + big headline + centered chip row. */
.dash-graph-card { display: flex; flex-direction: column; }
/* Item 30/31's tinted-tile + accent-border treatment (light tint fill,
   solid-colored border — same mechanism as .kpi.t-*, .dash-stat), now
   reused on the plain white cards too so every card on the dashboard reads
   as one consistent, clearly-bordered family instead of some tiles being
   colorful and others fading into the page. Colors follow the app's
   existing meaning convention: green = sales/money in, orange = stock,
   blue = a neutral ranking (matches the Top sellers bars' own blue),
   red = needs urgent attention. */
.dash-graph-card.t-sales { background: var(--d-sales-light); border-color: var(--d-sales); }
.dash-list-card.t-orange { background: var(--d-orange-light); border-color: var(--d-orange); }
.dash-list-card.t-blue { background: var(--d-blue-light); border-color: var(--d-blue); }
.dash-list-card.t-red { background: var(--red-light); border-color: var(--red); }
.dash-graph-head { text-align: center; }
.dash-graph-headline { font-size: 28px; font-weight: 800; color: var(--ink); margin-top: 4px; }
.dash-graph-chip-row { margin-top: 6px; display: flex; justify-content: flex-start; }
/* Item 30: a chip that filled with the card's own light tint would
   disappear into it — chips are a solid white pill with a hairline ring
   instead, which stays legible on any card color (and on the plain white
   cards item 33 introduced). */
.dash-chip { display: inline-flex; align-items: center; gap: 3px; font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px; background: #fff; box-shadow: 0 0 0 1px rgba(32,30,27,0.08); }
.dash-chip.up { color: var(--d-sales); }
.dash-chip.down { color: var(--d-critical); }
.dash-chart-wrap { margin-top: 10px; }
.dash-chart-wrap svg { display: block; }
.dash-axis-label-row { display: flex; margin-top: 6px; }
.dash-axis-label { flex: 1; text-align: center; font-size: 10.5px; color: var(--ink-soft); font-weight: 600; }

/* Item 33: a compact label/value header row shared by the sales graph card,
   Stock health, Top sellers and Expiring soon — replaces the old centered
   .section-title used on each, which took up more vertical space than the
   number it introduced needed. */
.dash-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 2px; }
.dash-card-head .t { font-size: 11.5px; font-weight: 800; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.3px; }
.dash-card-head .v { font-size: 17px; font-weight: 800; color: var(--ink); }

/* Item 33: replaces the old single-file dash-pill-row — a 2-up grid on
   phone (Sales+Profit, then Stock value+Debt owed), 4-up on desktop. Same
   item-30/31 tinted-tile + accent-border treatment as before, just no
   colored dot, and grid instead of flex so pairing is exact regardless of
   content width. */
.dash-stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px; }
@media (min-width: 860px) { .dash-stat-grid { grid-template-columns: repeat(4, 1fr); } }
.dash-stat { border: 1px solid transparent; border-left: 4px solid transparent; border-right: 4px solid transparent; border-radius: var(--radius); padding: 12px 14px; }
.dash-stat .lab { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .3px; }
.dash-stat .val { font-size: 16px; font-weight: 800; color: var(--ink); margin-top: 3px; }
.dash-stat .sub { font-size: 10px; font-weight: 700; color: var(--ink-soft); margin-top: 2px; }

/* Item 33: no more fixed min-height — the old 268px was tuned for a
   two-column desktop pairing and, once cards mostly run 3-4 rows deep on
   phone, just left a lot of dead space below "View all". Cards now hug
   their own content at any width. */
.dash-list-card { }
.dash-bar-row { display: flex; align-items: center; gap: 10px; margin-top: 11px; }
.dash-bar-row.placeholder { opacity: 0.4; }
.dash-bar-label { width: 150px; min-width: 0; font-size: 12px; color: var(--ink); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-bar-meta { font-size: 10px; color: var(--ink-soft); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-bar-track { flex: 1; background: var(--line); border-radius: 5px; height: 7px; overflow: hidden; }
.dash-bar-fill { height: 100%; border-radius: 5px; }
.dash-bar-value { width: 58px; text-align: right; font-size: 11px; font-weight: 700; color: var(--ink); flex-shrink: 0; }
.dash-refetching { opacity: .45; transition: opacity .15s; pointer-events: none; }
.dash-bar-status { width: 52px; text-align: right; font-size: 10px; font-weight: 700; flex-shrink: 0; }
.dash-view-all { display: block; width: 100%; margin-top: 12px; padding: 8px; background: none; border: none; border-top: 1px dashed var(--line); font-size: 12px; font-weight: 700; color: var(--green); text-align: center; cursor: pointer; font-family: inherit; }

/* Item 33: was a wrapping flex row (three items could drop to a second
   line at phone width); a fixed 3-column grid keeps Out/Low/Healthy on
   one row always, and shorter labels ("Out 18" not "Out of stock (18)")
   are what make that fit comfortably. */
.dash-health-legend { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; margin-top: 8px; }
.dash-health-legend .sw { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-health-legend .dot { width: 7px; height: 7px; border-radius: 2px; flex-shrink: 0; }

.dash-profit-legend { display: flex; gap: 18px; margin-top: 10px; align-items: baseline; flex-wrap: wrap; }
.dash-profit-legend .sw { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink); }
.dash-profit-legend .dot { width: 8px; height: 8px; border-radius: 2px; }
.dash-profit-margin { font-size: 11px; color: var(--ink-soft); font-weight: 700; }

/* ---------------------------------------------------------------------- */
/* PRINT — reports and receipts print on their own, with a business       */
/* letterhead, independent of whatever screen is currently open.          */
/* ---------------------------------------------------------------------- */
.print-only { display: none; }
@media print {
  body * { visibility: hidden; }
  #printArea, #printArea * { visibility: visible; }
  #printArea {
    display: block; position: absolute; top: 0; left: 0; width: 100%;
    padding: 0; color: #000; background: #fff;
  }
  .print-letterhead { text-align: center; margin-bottom: 18px; border-bottom: 2px solid #000; padding-bottom: 10px; }
  .print-letterhead .pname { font-size: 20px; font-weight: 800; }
  .print-letterhead .pmeta { font-size: 12px; margin-top: 3px; }
  .print-title { font-size: 15px; font-weight: 700; margin: 10px 0; }
  .print-table { width: 100%; border-collapse: collapse; font-size: 12px; }
  .print-table th, .print-table td { border: 1px solid #999; padding: 5px 7px; text-align: left; }
  .print-table th { background: #eee; }
  .print-footer { margin-top: 16px; font-size: 11px; color: #000; }
}

/* ---------------------------------------------------------------------- */
/* UI polish pass (Oct 2026)                                               */
/* ---------------------------------------------------------------------- */
/* Cart lines: price line was rendering at full body size, same as the name */
.cart-line .name { font-weight: 600; }
.cart-line .meta { font-size: 12px; margin-top: 2px; }

/* Sell: checkout bar (replaces the round floating cart button) */
.cart-bar {
  position: fixed; left: 12px; right: 12px; bottom: calc(72px + env(safe-area-inset-bottom)); z-index: 11;
  display: flex; align-items: center; gap: 12px; padding: 12px 16px; border: none; border-radius: 14px;
  background: var(--green); color: #fff; box-shadow: var(--shadow-lg); font-size: 14px; font-weight: 700; text-align: left;
}
.cart-bar .cb-ic { position: relative; display: flex; }
.cart-bar .cb-n {
  position: absolute; top: -8px; right: -11px; min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px;
  background: var(--amber); color: #241A03; font-size: 11px; display: flex; align-items: center; justify-content: center;
}
.cart-bar .cb-txt { flex: 1; margin-left: 6px; font-variant-numeric: tabular-nums; }
.cart-bar .cb-go { background: rgba(255,255,255,0.16); border-radius: 10px; padding: 6px 10px; white-space: nowrap; }
.content.has-cart-bar { padding-bottom: 160px; }

/* Reports: date range + Excel/Print on one header row */
.report-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.report-head .dash-tabs { flex: 1 1 260px; max-width: 460px; }
.report-head .toolbar-segment { margin-left: auto; }
.report-head .toolbar-segment .btn { padding: 9px 14px; font-size: 13.5px; }

/* Drug detail: batch rows — title + stock badge on one line, actions in an even grid */
.batch-row { padding: 12px 0; border-bottom: 1px solid var(--line); }
.batch-row:last-child { border-bottom: none; }
.batch-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.batch-head .name { font-weight: 600; }
.batch-row .meta { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.batch-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 6px; margin-top: 8px; }
.batch-actions .btn { width: 100%; }

/* Dashboard "Expiring soon" status words in readable ink, not the light bar fill colours */
.dash-bar-status.critical { color: var(--red); }
.dash-bar-status.serious { color: #A93E14; }
.dash-bar-status.warning { color: var(--amber-ink); }

/* Status dropdowns inside list rows (insurance claims) — match the app's inputs instead of the browser default */
.list-row select {
  font: inherit; font-size: 13px; font-weight: 600; color: var(--ink); background: #fff;
  border: 1px solid var(--line); border-radius: 10px; padding: 6px 8px; box-shadow: var(--shadow-sm);
}

/* "Forgot password?" was the browser's default blue underline */
.auth-form-col .tiny a, .auth-card .tiny a { color: var(--green); font-weight: 700; text-decoration: none; }
.auth-form-col .tiny a:hover, .auth-card .tiny a:hover { text-decoration: underline; }
@media (min-width: 860px) {
  .cart-bar { left: auto; right: 32px; bottom: 24px; width: 380px; }
  .content.has-cart-bar { padding-bottom: 110px; }
}

/* ---------------------------------------------------------------------- */
/* PHONE MENU DRAWER — ported from Kodi (app/style.css, "Top-left menu     */
/* drawer"), which is David's own project; the geometry, timing curve and  */
/* drawn scrollbar are copied as-is, repainted in Pharma's green/gold.     */
/*                                                                         */
/* Why it exists: the phone bottom bar can only carry about five thumb-    */
/* sized targets, and Pharma has seven destinations plus five report sub-  */
/* screens. Kodi solved exactly this — a short bottom bar for the hot      */
/* paths, and a hamburger drawer holding every module.                     */
/*                                                                         */
/* Phone only. Pharma's desktop sidebar (the min-width:860px block above)  */
/* already shows every destination, so the hamburger, the scrim and the    */
/* drawer are all hidden there. 860px — not Kodi's 900px — because that is */
/* where Pharma's sidebar already appears; using 900 would leave 860-899px */
/* showing the sidebar AND the phone bars at the same time.                */
/*                                                                         */
/* The panel is inset from the top bar and the tab bar rather than running */
/* the full height: on a phone both bars stay visible and tappable while   */
/* the menu is open, so there is always a way out that is not the scrim.   */
/* --ph-topbar-h/--ph-tabbar-h are the two measurements the insets are     */
/* built from — change those, not the calc()s.                             */
/* ---------------------------------------------------------------------- */
:root { --ph-topbar-h: 60px; --ph-tabbar-h: 62px; --ph-safe-top: env(safe-area-inset-top, 0px); }

/* Below .mask (z-index 50) on purpose: opening a sheet from a drawer row  */
/* must cover the drawer, not slide under it.                              */
.navscrim {
  position: fixed; inset: 0; background: rgba(14,22,19,0.45);
  opacity: 0; visibility: hidden; transition: opacity 0.25s; z-index: 44;
}
body.nav-open .navscrim { opacity: 1; visibility: visible; }

.navdrawer {
  position: fixed; left: 0; z-index: 45;
  top: calc(var(--ph-topbar-h) + 5px + var(--ph-safe-top));
  bottom: calc(var(--ph-tabbar-h) + 6px + env(safe-area-inset-bottom));
  width: 172px; max-width: 70%; overflow: hidden;
  background: linear-gradient(180deg, var(--green) 0%, var(--green-dark) 100%);
  color: #DCEBE8; display: flex; flex-direction: column;
  transform: translateX(-100%);
  transition: transform 0.24s cubic-bezier(0.4, 0.01, 0.2, 1);
  box-shadow: 0 14px 38px -10px rgba(0,0,0,0.55);
}
body.nav-open .navdrawer { transform: none; }

/* The scrollbar is DRAWN (.nd-sb), not the browser's own. On a phone the
   native one is an overlay — it fades in while a finger is moving and is
   invisible the rest of the time, so there is nothing on screen to say the
   list continues, which is the one thing this menu most needs to show. */
.nd-navwrap { position: relative; flex: 1 1 0; min-height: 0; display: flex; }
/* Every row is only as wide as the widest label, so the active-row pill is a
   short pill rather than a band across the whole drawer. */
.nd-nav {
  display: grid; grid-template-columns: max-content; grid-auto-rows: max-content;
  justify-content: start; align-content: start;
  flex: 1 1 0; min-width: 0; overflow-y: auto; padding: 8px 17px 8px 6px;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; -ms-overflow-style: none;
}
.nd-nav::-webkit-scrollbar { display: none; }
.nd-sb {
  position: absolute; top: 34px; bottom: 34px; right: 4px; width: 9px; border-radius: 5px;
  background: rgba(255,255,255,0.12); opacity: 0; transition: opacity 0.2s; pointer-events: none;
}
.nd-sb.on { opacity: 1; }
/* Arrow caps drawn with borders rather than glyphs, so they stay crisp at any
   pixel density. Decorative: the list is scrolled by swiping it. */
.nd-sb::before, .nd-sb::after {
  content: ''; position: absolute; left: 50%; transform: translateX(-50%);
  width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent;
}
.nd-sb::before { bottom: 100%; margin-bottom: 5px; border-bottom: 6px solid #FFFFFF; }
.nd-sb::after { top: 100%; margin-top: 5px; border-top: 6px solid #FFFFFF; }
.nd-sb-th {
  position: absolute; left: 0; right: 0; top: 0; height: 30px; min-height: 24px;
  border-radius: 5px; background: #FFFFFF;
}
/* Mouse/trackpad: the drawn bar can be dragged and the track clicked, so it
   gets a little more width and reacts to hover. Not applied on touch. */
@media (hover: hover) and (pointer: fine) {
  .nd-sb { pointer-events: auto; cursor: pointer; width: 10px; transition: opacity 0.2s, background 0.15s; }
  .nd-sb:hover { background: rgba(255,255,255,0.2); }
  .nd-sb-th { cursor: grab; transition: background 0.15s; }
  .nd-sb-th:hover { background: var(--green-light); }
  .nd-sb-th.drag { cursor: grabbing; background: #CFEBDD; }
}
/* No-gray-text rule: these two are the drawer's quietest text, and they are
   still a readable light green rather than a gray. */
.nd-grp {
  font-size: 9px; letter-spacing: 0.09em; text-transform: uppercase;
  color: #A8C9B8; padding: 10px 9px 4px; font-weight: 700;
}
.nd-row {
  display: flex; align-items: center; gap: 9px; padding: 8px 9px; border-radius: 8px;
  color: #DCEBE8; font-size: 12.5px; font-weight: 600; width: 100%;
  background: none; border: 0; cursor: pointer; text-align: left; font-family: inherit;
}
.nd-row:active { background: rgba(255,255,255,0.08); }
.nd-chip {
  width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center;
  font-size: 14px; line-height: 1; flex: none;
  background: linear-gradient(160deg, rgba(255,255,255,0.32), rgba(255,255,255,0.04));
  box-shadow: 0 2px 4px rgba(0,0,0,0.35), inset 0 1px rgba(255,255,255,0.45), inset 0 -1px 2px rgba(0,0,0,0.3);
}
.nd-lab { flex: 1; min-width: 0; line-height: 1.2; white-space: normal; overflow-wrap: anywhere; }
/* Gold, matching the active tab in the bottom bar and the desktop sidebar,
   rather than Kodi's green-on-green. */
.nd-row.active {
  background: var(--amber); color: #241A03;
  outline: 2px dashed rgba(255,255,255,0.75); outline-offset: -2px;
}
.nd-head {
  flex: 0 0 auto; padding: 11px 13px; border-bottom: 1px solid rgba(255,255,255,0.1);
  font-size: 10px; color: #CFE3D7; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
}
.nd-foot {
  flex: 0 0 auto; padding: 11px 13px; border-top: 1px solid rgba(255,255,255,0.1);
  font-size: 10px; color: #CFE3D7;
}
/* The hamburger gets its own solid colour rather than the topbar's shared
   translucent white wash, which reads as a gray smudge on the green bar —
   the same reasoning (and the same fix) as Kodi's #btnNavMenu. */
.topbar .burgerbtn {
  background: var(--green-dark); color: #fff; border-radius: 50%;
  width: 34px; height: 34px; padding: 0; display: grid; place-items: center; flex: none;
}
.topbar .burgerbtn:hover { background: #072C1B; }
.topbar-left { display: flex; align-items: center; gap: 10px; min-width: 0; }

/* Destinations that stay on the desktop sidebar but move into the drawer on a
   phone, so the bottom bar keeps five thumb-sized targets. Declared here as
   the mobile-first base rule and switched back on inside the 860px block
   below — scoped as ".navbar button.nav-desktop-extra" (not the bare class)
   so it reliably beats ".navbar button" on specificity. */
.navbar button.nav-desktop-extra { display: none; }

/* Desktop-only parts of the menu: hidden on a phone. */
.nd-brand, .nd-who { display: none; }

/* ---------------------------------------------------------------------- */
/* DESKTOP MENU (860px+) — the phone's menu drawer, docked open down the  */
/* left edge (Kodi style): logo and pharmacy name, small CAPITAL group    */
/* headings, an emoji tile then the name on every row. The old icon bar   */
/* (.navbar) is no longer shown here.                                     */
/* ---------------------------------------------------------------------- */
@media (min-width: 860px) {
  .navscrim, .navbar, .topbar .burgerbtn { display: none; }
  .navdrawer {
    top: 0; bottom: 0; left: 0; width: var(--sidebar-w); max-width: none; z-index: 40;
    transform: none; visibility: visible; border-radius: 0; transition: none;
    background: var(--green-dark); box-shadow: 4px 0 20px rgba(10,59,36,0.14);
  }
  .nd-brand {
    display: flex; align-items: center; gap: 9px; flex: 0 0 auto;
    padding: 14px 12px 12px; border-bottom: 1px solid rgba(255,255,255,0.12);
  }
  .nd-bname {
    font-size: 13.5px; font-weight: 800; color: #fff; line-height: 1.2; min-width: 0;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .nd-head { border-bottom: 0; padding: 12px 14px 0; font-size: 10px; color: #A8C9B8; }
  .nd-nav { grid-template-columns: 1fr; padding: 2px 16px 8px 8px; }
  .nd-grp { padding: 12px 8px 4px; font-size: 10px; }
  .nd-row {
    gap: 10px; padding: 5px 8px; font-size: 13px; border-radius: 9px;
    border-left: 3px solid transparent; transition: background 0.12s;
  }
  .nd-row:hover { background: rgba(255,255,255,0.08); }
  .nd-chip { width: 28px; height: 28px; font-size: 15px; border-radius: 8px; }
  /* Selected: a soft lighter panel, a gold bar on its edge and a gold tile —
     the same marking Kodi uses, in Pharma's gold. */
  .nd-row.active {
    background: rgba(255,255,255,0.12); color: #fff; outline: 0; border-left-color: #E8A317;
  }
  .nd-row.active .nd-chip {
    background: linear-gradient(160deg, #F6C95A, #D4920F);
    box-shadow: 0 2px 4px rgba(0,0,0,0.4), inset 0 1px rgba(255,255,255,0.6), inset 0 -1px 2px rgba(80,50,0,0.4);
  }
  .nd-foot { padding: 9px 14px; line-height: 1.5; }
  .nd-who { display: block; color: #fff; font-weight: 700; font-size: 11.5px; }
}

/* ---------------------------------------------------------------------- */
/* AUTH, phone — the "dispensing label" sign-in (approved sketch): green  */
/* aurora, hospital-cross mark, emoji benefit row, and the form as a      */
/* cream label card (header strip, perforated edge, gold stamped button). */
/* Same ids/handlers as desktop; everything below applies under 860px     */
/* only, so the desktop split layout is untouched. The label chrome       */
/* (.auth-lfoot) lives inside #authBody, which is           */
/* display:contents here so `order` can sandwich the card between them.   */
/* ---------------------------------------------------------------------- */
.auth-hero, .auth-lfoot, .auth-title { display: none; }
.auth-pre { display: none; }
.auth-toggle b { font-weight: 700; }
.auth-forgot { text-align: center; margin-top: 10px; }
.auth-forgot a { color: var(--green); font-weight: 600; }

@media (max-width: 859px) {
  .auth-hero { display: block; }
  /* "Daylight" background: cream paper, a curved green header that holds the logo,
     and a gold heartbeat line across its top. A second heartbeat line runs along
     the bottom of the screen. The header is .auth-brand itself, so it always
     wraps the logo/tag/benefit row however tall the phone is. */
  .auth-wrap { justify-content: flex-start; padding-bottom: 76px; }
  @media (max-height: 640px) { .auth-wrap { padding-bottom: 14px; } }
  .auth-bg-fill { background: var(--paper); }
  .auth-wrap::after {
    content: ''; position: absolute; left: 0; right: 0; bottom: 14px; height: 56px; pointer-events: none;
    background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20390%2060'%20preserveAspectRatio='none'%3E%3Cpath%20d='M0%2030%20H96%20L108%2030%20L116%2016%20L126%2048%20L136%2024%20L144%2030%20H238%20L250%2030%20L258%208%20L270%2052%20L278%2030%20H390'%20fill='none'%20stroke='%230F5132'%20stroke-opacity='0.55'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") 0 0 / 100% 56px no-repeat;
  }
  .auth-brand {
    position: relative; z-index: 1; padding: clamp(60px, 9vh, 96px) 18px 30px;
    background: radial-gradient(circle at 92% 0%, rgba(184,134,11,0.5) 0%, transparent 42%),
                linear-gradient(170deg, #17945C 0%, var(--green) 55%, var(--green-dark) 100%);
    border-radius: 0 0 50% 50% / 0 0 64px 64px; box-shadow: 0 12px 30px -12px rgba(10,59,36,0.6);
  }
  .auth-brand::before {
    content: ''; position: absolute; left: 0; right: 0; top: 10px; height: 60px; pointer-events: none;
    background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20390%2060'%20preserveAspectRatio='none'%3E%3Cpath%20d='M0%2034%20H120%20L134%2034%20L142%2012%20L154%2052%20L164%2022%20L172%2034%20H250%20L262%2034%20L270%2018%20L280%2046%20L288%2034%20H390'%20fill='none'%20stroke='%23E7C76A'%20stroke-opacity='0.7'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") 0 0 / 100% 60px no-repeat;
  }
  .auth-hero-mark {
    width: 76px; height: 76px; margin: 0 auto 12px; border-radius: 22px; display: grid; place-items: center;
    background: linear-gradient(160deg, #D7332B, #A61E17);
    box-shadow: 0 0 0 3px rgba(255,255,255,0.9), 0 12px 26px rgba(0,0,0,0.42);
  }
  .auth-hero-mark svg { width: 52px; height: 52px; display: block; }
  .auth-hero-word { margin: 0; font-size: 34px; font-weight: 900; letter-spacing: -0.045em; line-height: 1; color: #fff; }
  .auth-hero-tag {
    margin: 5px 0 0; font-size: 11px; font-weight: 600; letter-spacing: 0.2em;
    text-transform: uppercase; color: #E7C76A;
  }
  .auth-feats { display: flex; justify-content: center; gap: 6px; margin: 14px 0 0; }
  .auth-feat { width: 74px; text-align: center; font-size: 10.5px; font-weight: 600; line-height: 1.2; color: #F3EEE0; }
  /* glass 3D chip: same recipe as Kodi's sign-in feature chips and menu icons */
  .auth-feat i {
    display: grid; place-items: center; width: 44px; height: 44px; margin: 0 auto 5px; border-radius: 12px;
    font-style: normal; font-size: 21px; line-height: 1;
    border: 1px solid rgba(255,255,255,0.35);
    background: linear-gradient(160deg, rgba(255,255,255,0.34), rgba(255,255,255,0.05));
    box-shadow: 0 3px 6px rgba(0,0,0,0.35), inset 0 1px rgba(255,255,255,0.5), inset 0 -1px 3px rgba(0,0,0,0.3);
  }
  /* benefit row: log-in screen only, and only when there is room */
  .auth-wrap:not([data-mode="login"]) .auth-feats { display: none; }
  @media (max-height: 640px) { .auth-feats { display: none; } }

  .auth-form-col { flex: 0 0 auto; position: relative; z-index: 2; margin-top: -18px; padding: 0 18px 22px; align-items: flex-start; }
  .auth-card { max-width: 420px; margin: 0 auto; display: flex; flex-direction: column; }
  #authBody { display: contents; }

  #authBody > .card {
    order: 2; position: relative; margin: 0; background: #FBF7EC; border: 0; border-radius: 4px;
    padding: 16px 22px 12px 22px; box-shadow: 0 14px 30px -10px rgba(0,0,0,0.55);
    display: flex; flex-direction: column;
  }
  /* perforated edges down both sides of the card, inset from the top and bottom */
  #authBody > .card::before, #authBody > .card::after {
    content: ''; position: absolute; top: 12px; bottom: 12px; width: 2px;
    background: repeating-linear-gradient(to bottom, #B9AE93 0 4px, transparent 4px 9px);
  }
  #authBody > .card::before { left: 9px; }
  #authBody > .card::after { right: 9px; }
  .auth-title { display: block; margin: 0 0 13px; font-size: 17px; font-weight: 800; color: #201E1B; letter-spacing: -0.015em; }
  #authBody .field { margin-bottom: 11px; }
  #authBody .field label {
    font: 600 9px/1.2 ui-monospace, "SF Mono", Menlo, Consolas, monospace; letter-spacing: 0.13em;
    text-transform: uppercase; color: #4A4139; margin-bottom: 4px;
  }
  #authBody .field input {
    padding: 8px 11px; border: 1.5px solid #D6CEB9; border-radius: 3px; background: #fff; color: #201E1B;
  }
  #authBody .field input:focus { border-color: #0F5132; box-shadow: inset 0 0 0 1px #0F5132; }
  #authBody .tiny { color: #201E1B; }
  #authBody .field input::placeholder { color: var(--green-dark); opacity: 0.6; }
  /* short phones: shrink the mark and spacing so log-in still fits without scrolling */
  @media (max-height: 640px) {
    .auth-hero-mark { width: 58px; height: 58px; margin-bottom: 8px; border-radius: 17px; }
    .auth-hero-mark svg { width: 40px; height: 40px; }
    .auth-brand { padding: 16px 18px 22px; }
    .auth-brand::before, .auth-wrap::after { display: none; } /* no room for the heartbeat lines */
    .auth-hero-word { font-size: 30px; }
    .auth-title { margin-bottom: 9px; }
    #authBody .field { margin-bottom: 8px; }
  }
  #authBody .btn.primary {
    order: 2; height: 44px; border-radius: 3px; padding: 0 12px; color: #241A03;
    background: linear-gradient(160deg, #D9AE3A, #A9790A); box-shadow: 0 6px 16px rgba(169,121,10,0.42);
    font-size: 12.5px; font-weight: 800; letter-spacing: 0.09em; text-transform: uppercase;
  }
  /* "Forgot password?" sits above the stamp, right-aligned (same markup order as desktop) */
  #authBody .auth-forgot { order: 1; text-align: right; margin: -2px 0 12px; }
  #authBody .auth-forgot a { color: #7A5605; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
  #authBody .btn.primary + .tiny { margin-top: 0; }

  .auth-lfoot {
    display: flex; order: 3; justify-content: space-between; margin-top: 12px;
    font: 500 8.5px/1.2 ui-monospace, "SF Mono", Menlo, Consolas, monospace; letter-spacing: 0.1em;
    text-transform: uppercase; color: #4A4139;
  }

  .auth-toggle { order: 4; display: grid; gap: 8px; margin-top: 15px; }
  .auth-toggle a {
    display: block; padding: 10px; border-radius: 3px; text-align: center; font-size: 12.5px; font-weight: 600;
    color: #201E1B; background: rgba(255,255,255,0.55); border: 1.5px solid var(--green); text-decoration: none;
  }
  .auth-toggle a b { color: var(--green); font-weight: 800; }
  .auth-pre { display: inline; }
  .auth-sep { display: none; }
}

/* critical:start - the few rules the loading screen needs. index.html carries an identical copy inline so the screen draws before this file arrives; tests/critical-css.test.js fails if the two drift apart. */
html,body{margin:0}
.loadscreen{box-sizing:border-box;min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;text-align:center;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:radial-gradient(circle at 18% 0%,#1C7A52 0%,transparent 55%),linear-gradient(180deg,#0F5132 0%,#09291B 100%)}
.loadscreen-mark{width:76px;height:76px;border-radius:22px;background:#B3261E;display:grid;place-items:center;box-shadow:0 0 0 4px #fff,0 12px 26px rgba(0,0,0,.35)}
.loadscreen-mark svg{width:46px;height:46px}
.loadscreen-word{margin:0;font-size:30px;font-weight:900;letter-spacing:-.04em;line-height:1}
.loadscreen-ecg{width:200px;height:34px;overflow:visible}
.loadscreen-ecg path{stroke-dasharray:260;stroke-dashoffset:260;animation:lsBeat 1.6s ease-in-out infinite}
.loadscreen-tag{margin:0;font-size:11px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;color:#E7C76A}
@keyframes lsBeat{0%{stroke-dashoffset:260;opacity:1}60%{stroke-dashoffset:0;opacity:1}100%{stroke-dashoffset:0;opacity:0}}
@media (prefers-reduced-motion:reduce){.loadscreen-ecg path{animation:none;stroke-dashoffset:0}}
/* critical:end */

/* ---------------------------------------------------------------------- */
/* PHONE BOTTOM BAR — glass 3D chips, the same look as the menu drawer's  */
/* (.nd-chip). The flat line icon (.ic) stays for the desktop sidebar;    */
/* the chip (.ic3d) is for phones only. The active tab's chip turns gold  */
/* and lifts a little.                                                    */
/* ---------------------------------------------------------------------- */
.navbar button .ic3d { display: none; }
@media (max-width: 859px) {
  .navbar button { padding: 8px 4px 7px; gap: 3px; color: #DCEBE8; }
  .navbar button.active { color: #fff; }
  .navbar button .ic { display: none; }
  .navbar button .ic3d {
    display: grid; place-items: center; width: 30px; height: 30px; border-radius: 9px;
    font-size: 16px; line-height: 1;
    background: linear-gradient(160deg, rgba(255,255,255,0.34), rgba(255,255,255,0.04));
    box-shadow: 0 3px 6px rgba(0,0,0,0.4), inset 0 1px rgba(255,255,255,0.5), inset 0 -2px 3px rgba(0,0,0,0.3);
    transition: transform 0.15s, background 0.15s;
  }
  .navbar button.active .ic3d {
    background: linear-gradient(160deg, #F0CF78, #B8860B);
    box-shadow: 0 4px 9px rgba(0,0,0,0.45), inset 0 1px rgba(255,255,255,0.7), inset 0 -2px 3px rgba(80,50,0,0.45);
    transform: translateY(-2px);
  }
}

/* ---------------------------------------------------------------------- */
/* LOADING PLACEHOLDERS — shapes (no text) that shimmer while the         */
/* dashboard numbers arrive, instead of a "Loading…" line.                */
/* ---------------------------------------------------------------------- */
.skel {
  display: block; border-radius: 8px; background: #E4DCC8;
  background-image: linear-gradient(90deg, #E4DCC8 0%, #F4EEDF 50%, #E4DCC8 100%);
  background-size: 200% 100%; animation: skelShimmer 1.4s linear infinite;
}
@keyframes skelShimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.skel-card { background: var(--card); border-radius: var(--radius); padding: 14px; box-shadow: var(--shadow-sm); margin-bottom: 12px; }
.skel-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; }
.skel-grid .skel-card { margin-bottom: 0; }
@media (min-width: 860px) { .skel-grid { grid-template-columns: repeat(4, 1fr); } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* Thin bar across the top of the dashboard while older numbers are on screen
   and fresh ones are loading. */
.updating-bar { height: 3px; border-radius: 3px; background: var(--green-light); overflow: hidden; margin: -4px 0 10px; position: relative; }
.updating-bar::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 35%; border-radius: 3px; background: var(--green);
  animation: updSlide 1.1s ease-in-out infinite;
}
@keyframes updSlide { 0% { left: -35%; } 100% { left: 100%; } }
@media (prefers-reduced-motion: reduce) { .updating-bar::after { animation: none; width: 100%; opacity: .5; } }

/* ---------------------------------------------------------------------- */
/* 2026-10-29: customers & credit, refills, SMS, controlled drugs,         */
/* stock take. Reuses the existing cards, KPI tiles, badges and sheets;    */
/* only what those did not already cover is here.                          */
/* ---------------------------------------------------------------------- */
.dash-alert.amber { background: var(--amber-light); border-color: #ecd9a0; color: var(--amber-ink); }
.dash-alert.green { background: var(--green-light); border-color: #b9dcc8; color: var(--green); }
.list-row > div:first-child { min-width: 0; }
.field textarea { resize: vertical; line-height: 1.4; }
.stcount {
  padding: 9px 10px; border: 1px solid var(--line); border-radius: 10px; background: #fff; text-align: right;
}
.stcount:focus { outline: none; border-color: var(--green); box-shadow: 0 0 0 3px var(--green-light); }
.list-row .meta.wrap { white-space: normal; }
.kpi-grid > .kpi { min-width: 0; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------- */
/* Phone sign-in is one fixed screen: it never scrolls up and down. The   */
/* log-in page is locked to the visible screen height and its spacing     */
/* shrinks in steps on shorter phones (and under the Android status bar)  */
/* so the form and both links always fit. Sign-up and the other steps     */
/* have more fields, so they may still scroll when they must.             */
/* ---------------------------------------------------------------------- */
@media (max-width: 859px) {
  html:has(.auth-wrap[data-mode="login"]),
  html:has(.auth-wrap[data-mode="login"]) body { overflow: hidden; overscroll-behavior: none; }
  html:has(.auth-wrap[data-mode="login"]) body { padding-bottom: 0; }
  .auth-wrap[data-mode="login"] { height: 100vh; height: 100dvh; min-height: 0; overflow: hidden; }
  .auth-wrap[data-mode="login"] .auth-brand { padding-top: calc(clamp(24px, 7vh, 80px) + env(safe-area-inset-top, 0px)); }
}
@media (max-width: 859px) and (max-height: 820px) {
  .auth-wrap[data-mode="login"] { padding-bottom: 40px; }
  .auth-wrap[data-mode="login"] .auth-brand { padding-bottom: 24px; }
  .auth-wrap[data-mode="login"] .auth-hero-mark { width: 64px; height: 64px; margin-bottom: 8px; border-radius: 19px; }
  .auth-wrap[data-mode="login"] .auth-hero-mark svg { width: 44px; height: 44px; }
  .auth-wrap[data-mode="login"] .auth-feats { margin-top: 10px; }
  .auth-wrap[data-mode="login"] .auth-feat i { width: 38px; height: 38px; font-size: 18px; margin-bottom: 3px; }
  .auth-wrap[data-mode="login"] .auth-title { margin-bottom: 9px; }
  .auth-wrap[data-mode="login"] #authBody .field { margin-bottom: 8px; }
  .auth-wrap[data-mode="login"] .auth-toggle { margin-top: 10px; gap: 6px; }
  .auth-wrap[data-mode="login"] .auth-toggle a { padding: 8px; }
}
@media (max-width: 859px) and (max-height: 720px) {
  .auth-wrap[data-mode="login"] .auth-feats { display: none; }
  .auth-wrap[data-mode="login"] .auth-brand { padding-bottom: 22px; }
}
@media (max-width: 859px) and (max-height: 620px) {
  .auth-wrap[data-mode="login"] { padding-bottom: 10px; }
  .auth-wrap[data-mode="login"] .auth-wrap::after, .auth-wrap[data-mode="login"]::after { display: none; }
  .auth-wrap[data-mode="login"] .auth-brand { padding-top: calc(14px + env(safe-area-inset-top, 0px)); padding-bottom: 20px; }
  .auth-wrap[data-mode="login"] .auth-hero-mark { width: 50px; height: 50px; margin-bottom: 6px; border-radius: 15px; }
  .auth-wrap[data-mode="login"] .auth-hero-mark svg { width: 34px; height: 34px; }
  .auth-wrap[data-mode="login"] .auth-hero-word { font-size: 26px; }
  .auth-wrap[data-mode="login"] .auth-lfoot { margin-top: 8px; }
}
/* Landscape or very short screens: let the page scroll rather than cut the form. */
@media (max-width: 859px) and (max-height: 520px) {
  html:has(.auth-wrap[data-mode="login"]), html:has(.auth-wrap[data-mode="login"]) body { overflow: auto; }
  .auth-wrap[data-mode="login"] { height: auto; min-height: 100vh; overflow: visible; }
}

/* ---------------------------------------------------------------------- */
/* In-app pop-ups (replace the browser's own "<site> says" boxes) and the */
/* "Please wait, loading…" cover shown while a screen opens.               */
/* ---------------------------------------------------------------------- */
.dlg-mask {
  position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center;
  padding: 20px; background: rgba(20,18,16,0.55);
  padding-top: calc(20px + env(safe-area-inset-top, 0px)); padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
}
.dlg {
  width: 100%; max-width: 380px; background: #FBF7EC; border: 2px solid var(--green); border-radius: 16px;
  padding: 20px 18px 16px; box-shadow: var(--shadow-lg); animation: dlgIn 0.14s ease-out;
}
@keyframes dlgIn { from { transform: scale(0.96); opacity: 0; } to { transform: none; opacity: 1; } }
.dlg-title { margin: 0 0 8px; font-size: 18px; font-weight: 800; color: var(--ink); letter-spacing: -0.01em; }
.dlg-msg { margin: 0 0 14px; font-size: 14.5px; line-height: 1.45; color: var(--ink); }
.dlg-input {
  width: 100%; margin: 0 0 14px; padding: 11px 12px; font: inherit; font-size: 15px; color: var(--ink);
  background: #fff; border: 1.5px solid var(--green); border-radius: 10px;
}
.dlg-input:focus { outline: none; box-shadow: 0 0 0 3px var(--green-light); }
.dlg-actions { display: flex; gap: 10px; }
.dlg-actions .btn { flex: 1 1 0; min-width: 0; }
.dlg-actions .btn.danger { background: var(--red); color: #fff; }

.loadveil { position: fixed; inset: 0; z-index: 90; background: transparent; cursor: progress; }
.loadveil-pill {
  position: absolute; left: 50%; top: calc(76px + env(safe-area-inset-top, 0px)); transform: translateX(-50%);
  display: none; align-items: center; gap: 10px; padding: 10px 18px; border-radius: 999px; white-space: nowrap;
  background: var(--green); color: #fff; font-size: 14px; font-weight: 700; box-shadow: var(--shadow-lg);
}
.loadveil.show .loadveil-pill { display: flex; }
.loadveil-spin {
  width: 16px; height: 16px; border-radius: 50%; border: 2.5px solid rgba(255,255,255,0.35); border-top-color: #fff;
  animation: loadSpin 0.8s linear infinite;
}
@keyframes loadSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .loadveil-spin { animation-duration: 2.4s; } .dlg { animation: none; } }

/* Sell: search box + checkout bar */
.searchbox input[type="search"] { -webkit-appearance: none; appearance: none; }
.searchbox input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
/* The cart bar is the one thing on Sell that must be noticed, so it is blue
   with white text instead of the green used by everything else. */
.cart-bar {
  background: linear-gradient(160deg, #2F72D6 0%, #1B4FA3 100%); color: #fff;
  border: 2px solid #12397D; box-shadow: 0 10px 26px rgba(18,57,125,0.45);
}
.cart-bar .cb-n { background: #fff; color: #12397D; }
.cart-bar .cb-go { background: #fff; color: #12397D; }

/* Every pop-up floats in the middle of the screen: it keeps a gap from the
   screen edges (all four sides) instead of sitting flat against the bottom, and
   has rounded corners all the way round. (The slide-out menu is unchanged.) */
.mask {
  align-items: center; justify-content: center;
  padding: 12px; padding-top: calc(12px + env(safe-area-inset-top, 0px));
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  padding-left: max(12px, env(safe-area-inset-left, 0px)); padding-right: max(12px, env(safe-area-inset-right, 0px));
}
.sheet {
  border-radius: 20px; border: 1.5px solid var(--green); box-shadow: var(--shadow-lg);
  max-height: 100%; min-height: 0;
}

/* Stock Valuation: each drug is a name + value line and a quantity / cost / price line that
   stays on ONE line (it takes the whole row width and shrinks a little on narrow phones). */
.val-row { padding: 12px 0; border-bottom: 1px solid var(--line); }
.val-row:last-child { border-bottom: none; }
.val-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.val-top .name { font-weight: 600; min-width: 0; }
.val-top .right { white-space: nowrap; }
.val-meta {
  margin-top: 3px; font-size: clamp(10px, 3.1vw, 12px); color: var(--ink-soft);
  white-space: nowrap; overflow-x: auto; scrollbar-width: none;
}
.val-meta::-webkit-scrollbar { display: none; }

/* ---------------------------------------------------------------------- */
/* AUTH, desktop (860px and up) — the same "dispensing label" sign-in as   */
/* the phone, as a split screen: green hero on the left (cross mark,       */
/* "Pharma", "Know your stock", four glass feature chips, gold heartbeat   */
/* line), the cream label card on the right with the two links under it.   */
/* Applies to every sign-in step (log in, sign up, staff, reset).          */
/* ---------------------------------------------------------------------- */
@media (min-width: 860px) {
  .auth-wrap { flex-direction: row; min-height: 100vh; min-height: 100dvh; padding-bottom: 0; background: var(--paper); }
  .auth-bg-fill { display: none; }
  .auth-brand {
    flex: 0 0 47%; box-sizing: border-box; position: relative; display: flex; flex-direction: column;
    align-items: center; justify-content: center; padding: 40px 48px; text-align: center; overflow: hidden;
    background: radial-gradient(circle at 18% 0%, #1C7A52 0%, transparent 55%), linear-gradient(180deg, #0F5132 0%, #09291B 100%);
  }
  .auth-brand::before {
    content: ''; position: absolute; left: 0; right: 0; top: 34px; height: 60px; pointer-events: none;
    background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20390%2060'%20preserveAspectRatio='none'%3E%3Cpath%20d='M0%2034%20H120%20L134%2034%20L142%2012%20L154%2052%20L164%2022%20L172%2034%20H250%20L262%2034%20L270%2018%20L280%2046%20L288%2034%20H390'%20fill='none'%20stroke='%23E7C76A'%20stroke-opacity='0.7'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") 0 0 / 100% 60px no-repeat;
  }
  .auth-brand-top { width: 100%; position: relative; z-index: 1; }
  .auth-hero { display: block; }
  .auth-hero-mark {
    width: 112px; height: 112px; margin: 0 auto 18px; border-radius: 32px; display: grid; place-items: center;
    background: linear-gradient(160deg, #D7332B, #A61E17);
    box-shadow: 0 0 0 5px #fff, 0 16px 34px rgba(0,0,0,0.4);
  }
  .auth-hero-mark svg { width: 68px; height: 68px; display: block; }
  .auth-hero-word { margin: 0; font-size: 64px; font-weight: 900; letter-spacing: -0.045em; line-height: 1; color: #fff; }
  .auth-hero-tag { margin: 12px 0 0; font-size: 14px; font-weight: 700; letter-spacing: 0.22em; text-transform: uppercase; color: #E7C76A; }
  .auth-feats { display: grid; grid-template-columns: repeat(2, max-content); justify-content: center; gap: 22px 56px; margin: 38px 0 0; }
  .auth-feat { display: flex; align-items: center; gap: 14px; width: auto; text-align: left; font-size: 16px; font-weight: 700; line-height: 1.2; color: #fff; }
  .auth-feat i {
    display: grid; place-items: center; flex: none; width: 56px; height: 56px; margin: 0; border-radius: 16px;
    font-style: normal; font-size: 26px; line-height: 1; border: 1px solid rgba(255,255,255,0.35);
    background: linear-gradient(160deg, rgba(255,255,255,0.34), rgba(255,255,255,0.05));
    box-shadow: 0 5px 10px rgba(0,0,0,0.4), inset 0 1px rgba(255,255,255,0.5), inset 0 -2px 4px rgba(0,0,0,0.3);
  }

  .auth-form-col {
    flex: 1; min-width: 0; position: relative; display: flex; align-items: center; justify-content: center;
    padding: 40px 40px 100px; background: var(--paper);
  }
  .auth-form-col::after {
    content: ''; position: absolute; left: 0; right: 0; bottom: 26px; height: 56px; pointer-events: none;
    background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20390%2060'%20preserveAspectRatio='none'%3E%3Cpath%20d='M0%2030%20H96%20L108%2030%20L116%2016%20L126%2048%20L136%2024%20L144%2030%20H238%20L250%2030%20L258%208%20L270%2052%20L278%2030%20H390'%20fill='none'%20stroke='%230F5132'%20stroke-opacity='0.55'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") 0 0 / 100% 56px no-repeat;
  }
  .auth-card { width: 440px; max-width: 100%; margin: 0; display: flex; flex-direction: column; position: relative; z-index: 1; }
  #authBody { display: contents; }

  #authBody > .card {
    order: 2; position: relative; margin: 0; background: #FBF7EC; border: 0; border-radius: 6px;
    padding: 28px 38px 20px; box-shadow: 0 14px 34px -12px rgba(32,30,27,0.4), 0 2px 6px rgba(32,30,27,0.08);
    display: flex; flex-direction: column;
  }
  #authBody > .card::before, #authBody > .card::after {
    content: ''; position: absolute; top: 16px; bottom: 16px; width: 2px;
    background: repeating-linear-gradient(to bottom, #B9AE93 0 4px, transparent 4px 9px);
  }
  #authBody > .card::before { left: 12px; }
  #authBody > .card::after { right: 12px; }
  .auth-title { display: block; margin: 0 0 18px; font-size: 24px; font-weight: 800; color: #201E1B; letter-spacing: -0.015em; }
  #authBody .field { margin-bottom: 16px; }
  #authBody .field label {
    font: 700 11px/1.2 ui-monospace, "SF Mono", Menlo, Consolas, monospace; letter-spacing: 0.12em;
    text-transform: uppercase; color: #201E1B; margin-bottom: 6px;
  }
  #authBody .field input { padding: 11px 14px; font-size: 17px; border: 1.5px solid #D6CEB9; border-radius: 6px; background: #fff; color: #201E1B; }
  #authBody .field input:focus { border-color: #0F5132; box-shadow: inset 0 0 0 1px #0F5132; }
  #authBody .tiny { color: #201E1B; }
  #authBody .field input::placeholder { color: var(--green-dark); opacity: 0.6; }
  #authBody .btn.primary {
    order: 2; height: 52px; border-radius: 6px; padding: 0 12px; color: #241A03;
    background: linear-gradient(180deg, #D8AE3A, #B8860B); box-shadow: 0 6px 14px rgba(184,134,11,0.35);
    font-size: 15px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase;
  }
  #authBody .auth-forgot { order: 1; text-align: right; margin: -2px 0 14px; }
  #authBody .auth-forgot a { color: #7A5605; font-size: 14px; font-weight: 800; text-decoration: underline; text-underline-offset: 3px; }
  #authBody .btn.primary + .tiny { margin-top: 0; }
  .auth-lfoot {
    display: flex; order: 3; justify-content: space-between; margin-top: 14px;
    font: 600 10px/1.2 ui-monospace, "SF Mono", Menlo, Consolas, monospace; letter-spacing: 0.1em;
    text-transform: uppercase; color: #201E1B;
  }
  .auth-toggle { order: 4; display: grid; gap: 12px; margin-top: 14px; }
  .auth-toggle a {
    display: block; padding: 13px; border-radius: 3px; text-align: center; font-size: 15px; font-weight: 600;
    color: #201E1B; background: rgba(255,255,255,0.55); border: 1.5px solid var(--green); text-decoration: none;
  }
  .auth-toggle a:hover { background: #fff; }
  .auth-toggle a b { color: var(--green); font-weight: 800; }
  .auth-pre { display: inline; }
  .auth-sep { display: none; }
}
