/* ============================================================
   Elvira Books — styles.css
   Light and dark are both selected, not flipped. The --viz-*
   values are the data-viz reference palette used as documented
   (categorical slots 1–2, blue ordinal ramp) against its own
   light/dark chart surfaces.
   ============================================================ */

/* ---------- Inter — the app's own face (SIL OFL, self-hosted) ----------
   One variable file per script subset covers every weight 100–900.
   font-display: swap shows system text instantly on the very first visit
   and swaps when ready; after that the font lives in the device cache.
   Arabic (and anything else outside these ranges) falls through to the
   system stack below, exactly as before. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- tokens ---------- */
:root {
  color-scheme: light;

  /* Slate — cool professional grays, white cards, blue accent. */
  --surface:      #f7f8fa;
  --surface-2:    #edeff3;
  --page:         #e4e7ec;
  --ink:          #0f172a;
  --ink-2:        #46536b;
  --muted:        #8b95a7;
  --grid:         #e5e8ee;
  --line:         #d5dae2;
  --border:       rgba(15, 23, 42, .09);
  --border-strong:rgba(15, 23, 42, .18);
  --shadow:       0 1px 2px rgba(15,23,42,.05), 0 6px 20px rgba(15,23,42,.06);
  --shadow-lg:    0 10px 32px rgba(15,23,42,.14);

  --accent:       #2563eb;
  --btn-primary:  #232932;
  --accent-ink:   #ffffff;
  --accent-soft:  rgba(37,99,235,.10);

  --good:         #16a34a;
  --warning:      #f59e0b;
  --serious:      #ea701c;
  --critical:     #dc2626;
  --good-text:    #15803d;
  --bad-text:     #a94442;   /* muted brick — legible without shouting */
  --link:         #1a73e8;   /* rule 7b: a hyperlink LOOKS like a hyperlink */

  --viz-1:        #2563eb;
  --viz-2:        #dc2626;
  --viz-3:        #16a34a;
  --viz-ord-1:    #86b6ef;
  --viz-ord-2:    #5598e7;
  --viz-ord-3:    #2a78d6;
  --viz-ord-4:    #1c5cab;
  --viz-ord-5:    #104281;

  --r-sm: 6px;
  --r:    9px;
  --r-lg: 14px;

  --side-w: 214px;
  /* Calibri, chosen 2026-08-11. It belongs to Microsoft and cannot be
     self-hosted, so the stack degrades in deliberate order:
       Calibri  — already on every Windows and Office machine: no download
       Carlito  — the metric-compatible open twin, where a system has it
       Inter    — the self-hosted face, so a Mac, iPad or Android till still
                  gets ONE consistent typeface rather than whatever it likes
     Anything outside those falls through to the platform's own UI face. */
  --font: Calibri, Carlito, 'Inter', system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --surface:      #171b22;
    --surface-2:    #1f242e;
    --page:         #0f1219;
    --ink:          #f4f6fa;
    --ink-2:        #c3cad6;
  --link:         #7ab3f5;
    --muted:        #8b95a7;
    --grid:         #262c38;
    --line:         #333b49;
    --border:       rgba(255,255,255,.09);
    --border-strong:rgba(255,255,255,.20);
    --shadow:       0 1px 2px rgba(0,0,0,.3), 0 6px 20px rgba(0,0,0,.30);
    --shadow-lg:    0 10px 32px rgba(0,0,0,.55);
    --accent:       #60a5fa;
    --btn-primary:  #232932;
    --accent-ink:   #0b1220;
    --accent-soft:  rgba(96,165,250,.16);
    --good-text:    #4ade80;
    --bad-text:     #d38f8f;
    --viz-1:        #60a5fa;
    --viz-2:        #f87171;
    --viz-3:        #4ade80;
    --viz-ord-1:    #184f95;
    --viz-ord-2:    #256abf;
    --viz-ord-3:    #3987e5;
    --viz-ord-4:    #6da7ec;
    --viz-ord-5:    #9ec5f4;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface:      #171b22;
  --surface-2:    #1f242e;
  --page:         #0f1219;
  --ink:          #f4f6fa;
  --ink-2:        #c3cad6;
  --link:         #7ab3f5;
  --muted:        #8b95a7;
  --grid:         #262c38;
  --line:         #333b49;
  --border:       rgba(255,255,255,.09);
  --border-strong:rgba(255,255,255,.20);
  --shadow:       0 1px 2px rgba(0,0,0,.3), 0 6px 20px rgba(0,0,0,.30);
  --shadow-lg:    0 10px 32px rgba(0,0,0,.55);
  --accent:       #60a5fa;
  --btn-primary:  #232932;
  --accent-ink:   #0b1220;
  --accent-soft:  rgba(96,165,250,.16);
  --good-text:    #4ade80;
  --bad-text:     #d38f8f;
  --viz-1:        #60a5fa;
  --viz-2:        #f87171;
  --viz-3:        #4ade80;
  --viz-ord-1:    #184f95;
  --viz-ord-2:    #256abf;
  --viz-ord-3:    #3987e5;
  --viz-ord-4:    #6da7ec;
  --viz-ord-5:    #9ec5f4;
}

/* ---------- base ---------- */
* { box-sizing: border-box; }
/* The browser hides [hidden] with a display rule of the very lowest
   weight, so ANY class that sets display beats it — .banner is display
   block, and a banner set hidden went on showing as an empty box. The
   attribute is used in forty places across the app, so it is settled
   here once rather than found again screen by screen. */
[hidden] { display: none !important; }

/* ---------- scrollbars ----------
   Left to the operating system until now, which on Windows means a wide light
   track with an arrow button at each end. Against the near-black sidebar rail
   that read as a strip of somebody else's software glued down one side of the
   app — and the same bar appeared in every modal, the calculator tape, the
   serial picker and global search.

   ONE RULE FOR ALL OF THEM, mixed from --ink rather than written per surface.
   The sidebar already re-scopes --ink to #f4f6fa, so it takes a light thumb on
   dark automatically while the content area takes a dark thumb on light, from
   these five declarations. That is the mechanism the .sidebar block describes
   about itself: "Everything inside styles itself from these variables, so
   re-scoping them here re-themes the whole rail without touching a single
   child rule."

   Always visible, deliberately. A hover-only thumb is prettier on a laptop and
   invisible on a TOUCHSCREEN, and the shop's till is one — a nav taller than
   the screen with no sign that it continues is exactly what rule 7c is for.

   Styling ::-webkit-scrollbar at all is also what removes those arrow buttons:
   they are only drawn when ::-webkit-scrollbar-button is left to the default.

   The combobox keeps its own — .cmb-list hides the native bar and draws a rail
   that FLOATS over the rows instead of taking a lane, which is right for a
   dropdown. A class selector outranks the * below, so it needs no exception. */
* {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--ink) 22%, transparent) transparent;
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  border-radius: 99px;
  background: color-mix(in srgb, var(--ink) 22%, transparent);
}
::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--ink) 38%, transparent);
}
/* Where two scrollbars meet. Left alone it is a small pale square that reads
   as a chip out of the corner of the panel. */
::-webkit-scrollbar-corner { background: transparent; }

html, body { height: 100%; }
body {
  margin: 0;
  font: 13px/1.45 var(--font);
  color: var(--ink);
  background: var(--page);
  -webkit-font-smoothing: antialiased;
}
body.modal-open { overflow: hidden; }
h1, h2, h3, h4 { margin: 0; font-weight: 640; letter-spacing: -.012em; }
h1 { font-size: 18px; }
h3 { font-size: 13.5px; }
h4 { font-size: 12px; margin: 14px 0 6px; color: var(--ink-2); }
p { margin: 0 0 8px; }
a { color: inherit; }
code { font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
.muted { color: var(--muted); }
.small { font-size: 11.5px; }
.b, .strong { font-weight: 650; }
.grow { flex: 1 1 auto; }
.pad { padding: 12px; }
.hidden { display: none !important; }
.pos, .good-text { color: var(--good-text); }
.neg, .bad-text { color: var(--bad-text); }
.warn-text { color: var(--serious); font-weight: 600; }
.num { font-variant-numeric: tabular-nums; }
.ta-right { text-align: right; }
.ta-center { text-align: center; }
.scroll-x { overflow-x: auto; }

.icn { width: 16px; height: 16px; flex: none; }

/* ---------- layout ---------- */
#app { display: flex; min-height: 100vh; }
.sidebar {
  width: var(--side-w); flex: none;
  display: flex; flex-direction: column;
  position: sticky; top: 12px; height: calc(100vh - 24px);
  z-index: 30;
  /* A floating near-black slate rail, the same in both themes. Everything
     inside styles itself from these variables, so re-scoping them here
     re-themes the whole rail without touching a single child rule. */
  margin: 12px 0 12px 12px;
  border-radius: 18px;
  background: #232932;
  color: var(--ink);
  border: 1px solid rgba(255, 255, 255, .06);
  --ink: #f4f6fa;
  --ink-2: #c3cad6;
  --link:         #7ab3f5;
  --muted: #8b95a7;
  --surface-2: rgba(255, 255, 255, .07);
  --border: rgba(255, 255, 255, .08);
  --border-strong: rgba(255, 255, 255, .22);
  --accent: #60a5fa;
  --accent-ink: #0b1220;
  --accent-soft: rgba(255, 255, 255, .10);
}
/* The active item is a quiet lighter pill, not a coloured one. */
.sidebar .nav-item.on { color: #ffffff; }
.sidebar .nav-item.on .icn { color: #ffffff; }
.main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.view { flex: 1 1 auto; padding: 4px 20px 48px; max-width: 1560px; width: 100%; }

/* brand */
.brand { display: flex; align-items: center; gap: 10px; padding: 16px 14px 12px; }
.brand-mark {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  background: rgba(255, 255, 255, .10); color: #ffffff;
  border: 1px solid rgba(255, 255, 255, .10);
  display: grid; place-items: center;
}
.brand-mark .icn { width: 17px; height: 17px; }
.brand-mark.big { width: 44px; height: 44px; border-radius: 11px; margin-bottom: 12px; }
.brand-mark.big .icn { width: 22px; height: 22px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-text b { font-size: 14.5px; letter-spacing: -.01em; }
.brand-text small { font-size: 9.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .07em; }
/* The wordmark: serif ELVIRA over letterspaced BOOKS. Navy voice on paper,
   sky voice on dark surfaces and on the always-slate sidebar rail. */
.wm-nm { font-family: Georgia, "Times New Roman", serif; font-weight: 700; letter-spacing: .06em; color: #2B4A87; }
.wm-bk { text-transform: uppercase; letter-spacing: .5em; margin-right: -.5em; color: var(--muted); }
.sidebar .wm-nm { color: #9db8ea; }
.side-ver { font-size: 10px; color: var(--muted); text-align: center; opacity: .7; padding: 4px 0 2px; }
.brand-text .wm-nm { font-size: 16px; }
.wm-h1 { display: flex; flex-direction: column; align-items: center; line-height: 1.1; gap: 3px; }
.wm-h1 .wm-nm { font-size: 30px; }
.wm-h1 .wm-bk { font-size: 12px; font-weight: 400; }
:root[data-theme="dark"] .wm-nm { color: #9db8ea; }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .wm-nm { color: #9db8ea; }
}
/* Phone-only: the generic .icon-btn rule sits LATER in the file, so this
   hide must outrank it — .sidebar scoping does that without !important. */
.sidebar .nav-close { display: none; margin-left: auto; }

/* company switcher — lives in the topbar, like every app the user knows */
.co-switch { flex: none; }
.co-btn {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; border-radius: var(--r); cursor: pointer;
  background: transparent; border: 1px solid transparent;
  color: var(--ink); font: inherit; font-size: 13px; font-weight: 600; text-align: left;
  max-width: 220px;
}
.top-bell { position: relative; }
.bell-dot {
  position: absolute; top: 5px; right: 6px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--critical); border: 1.5px solid var(--surface);
}
.co-btn:hover { border-color: var(--border); background: var(--surface-2); }
.co-btn .icn { margin-left: auto; width: 14px; height: 14px; color: var(--muted); }
.co-avatar {
  width: 22px; height: 22px; border-radius: 6px; flex: none;
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center; font-size: 10px; font-weight: 700;
}
.co-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* nav — dense rows; the roomier mock spacing was tried and rolled back */
.nav { flex: 1 1 auto; overflow-y: auto; padding: 2px 6px 10px; }
.nav-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 8px; border-radius: var(--r-sm);
  color: var(--ink-2); text-decoration: none; font-size: 12.5px;
  border: 0; background: none; cursor: pointer; font-family: inherit; text-align: left;
}
.nav-item .icn { width: 15px; height: 15px; }
.nav-item:hover { background: var(--surface-2); color: var(--ink); }
.nav-item.on { background: var(--accent-soft); color: var(--ink); font-weight: 600; }
.nav-item.on .icn { color: var(--accent); }
.nav-item.sub { padding-left: 31px; font-size: 12.5px; }
.nav-caret { margin-left: auto; display: flex; transition: transform .16s; }
.nav-caret .icn { width: 12px; height: 12px; }
.nav-group.open .nav-caret { transform: rotate(180deg); }
.nav-sub { display: none; }
.nav-group.open .nav-sub { display: block; }
.nav-badge {
  margin-left: auto; min-width: 16px; height: 16px; padding: 0 5px;
  /* muted brick on the dark sidebar — present without flashing */
  border-radius: 8px; background: #9a5350; color: #f3e2e1;
  font-size: 10px; font-weight: 650; display: grid; place-items: center;
}
.nav-item.sub .nav-badge { margin-left: auto; }

.side-foot { border-top: 1px solid var(--border); padding: 6px; }
.side-btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 8px; border: 0; background: none; border-radius: var(--r-sm);
  color: var(--ink-2); font: inherit; font-size: 12.5px; cursor: pointer; text-align: left;
}
.side-btn .icn { width: 15px; height: 15px; }
.side-btn:hover { background: var(--surface-2); color: var(--ink); }
.save-state {
  font-size: 11px; color: var(--muted); padding: 4px 10px;
  opacity: 0; transition: opacity .2s;
}
.save-state.on { opacity: 1; }

/* topbar */
.topbar {
  position: sticky; top: 12px; z-index: 20;
  display: flex; align-items: center; gap: 10px;
  margin: 12px 16px 0;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--shadow);
}
/* The rail's two desktop moods: PINNED (always there) and UNPINNED (tucked
   to a sliver at the screen edge; crossing it with the mouse slides it out
   over the page). The pin button in the rail's own header switches moods;
   on phones the drawer behaves as it always has and the pin never shows. */
.nav-open { display: inline-grid; }
.sidebar .nav-pin { display: none; margin-left: auto; color: var(--ink-2); }
.nav-pin.unpinned .icn { transform: rotate(45deg); }
@media (min-width: 861px) {
  .sidebar .nav-pin { display: inline-grid; }
  body.nav-unpinned .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0;
    height: calc(100vh - 24px); margin: 12px 0;
    border-radius: 0 18px 18px 0;
    /* rail is 214px wide — slide all but a 16px sliver off screen
       (plain pixels: calc()+var() proved unreliable in this transform) */
    transform: translateX(-198px);
    transition: transform .18s ease;
    box-shadow: var(--shadow-lg);
    z-index: 90;
  }
  body.nav-unpinned .sidebar:hover,
  body.nav-unpinned .sidebar:focus-within { transform: none; }
  /* A grip at the sliver's waist — the door announces itself. */
  body.nav-unpinned .sidebar::after {
    content: ''; position: absolute; right: 5px; top: 50%;
    width: 5px; height: 46px; border-radius: 99px;
    background: rgba(255, 255, 255, .45);
    transform: translateY(-50%);
    transition: opacity .15s;
  }
  body.nav-unpinned .sidebar:hover::after { opacity: 0; }
  /* And the page steps back from the tucked rail instead of touching it. */
  body.nav-unpinned .main { margin-left: 22px; }
}
.global-search {
  display: flex; align-items: center; gap: 7px;
  min-width: 0; max-width: 360px; flex: 1 1 220px;
  padding: 5px 9px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--border);
  color: var(--muted); font: inherit; font-size: 12.5px; cursor: pointer; text-align: left;
}
.global-search:hover { border-color: var(--border-strong); }
.global-search span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.global-search kbd {
  margin-left: auto; font: 11px/1 var(--font); padding: 3px 6px;
  border: 1px solid var(--border); border-radius: 4px; color: var(--muted);
}

/* ---------- page chrome ---------- */
.page-head {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 0 10px; flex-wrap: wrap;
}
.page-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.page-sub { color: var(--muted); font-size: 12px; margin: 1px 0 0; }
.page-actions { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }
.act-div { width: 1px; background: var(--border); margin: 0 2px; }
.page-body > * + * { margin-top: 12px; }

/* The toolbar is a row of controls, not a panel — no box around it. */
.toolbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 0 10px; margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.toolbar.sub { margin: 0 0 10px; border: 0; padding: 0; }
.inline-lbl { font-size: 11.5px; color: var(--muted); font-weight: 600; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 10px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--border-strong);
  color: var(--ink); font: inherit; font-size: 12.5px; font-weight: 560;
  cursor: pointer; white-space: nowrap; text-decoration: none;
}
.btn .icn { width: 14px; height: 14px; }
.btn:hover { background: var(--surface-2); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
/* Primary actions wear the sidebar's dark grey, not the accent — the accent
   stays for links, highlights and charts. Its own variable, so dark mode can
   lift it enough to read against dark surfaces. */
.btn-primary { background: var(--btn-primary); border-color: var(--btn-primary); color: #c3cad6; }
.btn-primary:hover { filter: brightness(1.18); background: var(--btn-primary); }
.btn-danger { background: var(--critical); border-color: var(--critical); color: #fff; }
.btn-danger:hover { filter: brightness(1.06); background: var(--critical); }
.btn-warn { background: var(--warning); border-color: var(--warning); color: #2a2000; }
/* Confirming a match is the good outcome on that screen, so its button wears
   the good colour rather than the neutral primary. */
.btn-good { background: var(--good); border-color: var(--good); color: #fff; }
.btn-good:hover { filter: brightness(1.06); background: var(--good); }
.btn-good:disabled { filter: none; opacity: .5; }
.btn-sm { padding: 3px 8px; font-size: 12px; }
.btn-sm .icn { width: 13px; height: 13px; }
.btn-lg { padding: 8px 15px; font-size: 13.5px; }
.btn-row { display: flex; gap: 6px; flex-wrap: wrap; }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 26px; height: 26px; border-radius: var(--r-sm);
  border: 0; background: none; color: var(--ink-2); cursor: pointer;
}
.icon-btn:hover { background: var(--surface-2); color: var(--ink); }
.icon-btn .icn { width: 15px; height: 15px; }
.icon-btn.sm { width: 22px; height: 22px; }
.icon-btn.sm .icn { width: 13px; height: 13px; }

.link-btn {
  border: 0; background: none; padding: 0; cursor: pointer;
  color: var(--link); font: inherit; text-align: left;
  display: inline-flex; align-items: center; gap: 5px;
  text-decoration: none;   /* anchors reuse this class — no default underline */
}
.link-btn:hover { color: var(--accent); text-decoration: underline; }
.link-btn.strong { font-weight: 600; }
.link-btn.xs { font-size: 11.5px; color: var(--muted); margin-left: 6px; }

/* ---------- cards ---------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  overflow: hidden;
}
.card + .card { margin-top: 20px; }
.card-head {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-bottom: 1px solid var(--border);
}
.card-head h3 { font-size: 13px; }
.card-sub { font-size: 11.5px; color: var(--muted); margin: 1px 0 0; }
.card-head-acts { margin-left: auto; display: flex; gap: 6px; align-items: center; }
.card-body { padding: 12px; }
.card-body.no-pad { padding: 0; }
.danger-card { border-color: color-mix(in srgb, var(--critical) 40%, var(--border)); }

/* ---------- stats ---------- */
.stat-row { display: grid; gap: 8px; }
.stat-row-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stat-row-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.stat-row-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
/* breadcrumb trail */
.crumbs {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; margin: 8px 0 4px; color: var(--muted);
}
.crumbs a { color: var(--accent); text-decoration: none; font-weight: 560; }
.crumbs a:hover { text-decoration: underline; }
.crumbs span { color: var(--ink-2); font-weight: 550; }
.crumbs i { font-style: normal; color: var(--muted); opacity: .75; font-size: 15px; font-weight: 700; }
.crumb-back {
  display: grid; place-items: center; width: 28px; height: 28px; flex: none;
  border: 1px solid var(--border-strong); border-radius: 8px;
  background: var(--surface); color: var(--ink); cursor: pointer; padding: 0;
}
.crumb-back .icn { width: 15px; height: 15px; }
.crumb-back:hover { background: var(--surface-2); }

.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); padding: 9px 11px; box-shadow: var(--shadow);
}
.stat[data-act] { cursor: pointer; }
.stat[data-act]:hover { border-color: var(--border-strong); }
.stat-top { display: flex; align-items: center; gap: 6px; }
.stat-label {
  font-size: 10.5px; color: var(--muted); letter-spacing: .02em; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The icon is a tinted chip, so the four tiles read at a glance as
   income / spend / result / cash rather than four grey boxes. */
.stat-icn {
  margin-left: auto; display: grid; place-items: center; flex: none;
  width: 28px; height: 28px; border-radius: 9px;
  background: var(--surface-2); color: var(--ink-2);
}
.stat-icn .icn { width: 14px; height: 14px; }
.stat.tone-green .stat-icn { background: rgba(22,163,74,.12); color: #16a34a; }
.stat.tone-red .stat-icn { background: rgba(220,38,38,.10); color: #dc2626; }
.stat.tone-blue .stat-icn { background: var(--accent-soft); color: var(--accent); }
.stat.tone-orange .stat-icn { background: rgba(245,158,11,.14); color: #d97706; }
.stat-spark { margin-top: 8px; }
.stat-spark svg { display: block; width: 100%; height: 26px; }
.stat-value { font-size: 19px; font-weight: 680; letter-spacing: -.02em; margin: 4px 0 1px; }
.stat-foot { font-size: 11px; color: var(--muted); display: flex; align-items: center; gap: 6px; min-height: 0; }
.stat-foot:empty { display: none; }
.stat-delta { display: inline-flex; align-items: center; gap: 1px; font-weight: 620; }
.stat-delta .icn { width: 11px; height: 11px; }
.stat-delta.up { color: var(--good-text); }
.stat-delta.down { color: var(--bad-text); }
.stat.accent { border-color: color-mix(in srgb, var(--accent) 42%, var(--border)); }
.stat.accent .stat-value { color: var(--accent); }
.stat.good .stat-value { color: var(--good-text); }
.stat.bad .stat-value { color: var(--bad-text); }

/* ---------- tables ---------- */
/* A table standing on its own gets the card treatment — the page background
   is grey now, and a transparent table just dissolves into it. Inside a card
   or a dialog the surface is already provided, so it goes back to bare. */
.table-wrap {
  overflow-x: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
}
.card .table-wrap, .modal .table-wrap, .doc-sheet .table-wrap {
  background: none; border: 0; border-radius: 0; box-shadow: none;
}
/* Financial tables read far better as single-line rows. Below this width
   the table scrolls sideways rather than wrapping every cell to three lines.
   Compact tables (inside modals and cards) are exempt. */
.table-wrap > .tbl:not(.compact) { min-width: 840px; }
/* Data grids are TIER TWO type: a notch smaller and tighter than the app
   chrome, because fifty rows are scanned, not read — density wins here. */
.tbl { width: 100%; border-collapse: collapse; font-size: 12px; line-height: 1.35; }
/* Columns are ruled as well as rows. A register runs eight columns wide and
   the eye has to carry one row across all of them; the horizontal rules alone
   said where a row ended but never where a figure's column began. The last
   column takes no rule — the table's own edge is already there. */
.tbl th, .tbl td { border-right: 1px solid var(--grid); }
.tbl th:last-child, .tbl td:last-child { border-right: 0; }
.tbl .small, .tbl .muted.small { font-size: 11px; }
.tbl td.ta-right, .tbl th.ta-right { white-space: nowrap; }
.tbl td:last-child { white-space: nowrap; }
.tbl .link-btn { white-space: nowrap; }
/* Movement schedules: many narrow money columns — nothing may wrap. */
.tbl.mv th, .tbl.mv td { white-space: nowrap; }
.tbl th {
  text-align: left; font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .045em; color: var(--muted);
  padding: 6px 10px; border-bottom: 1px solid var(--line);
  background: var(--surface-2); position: sticky; top: 0; z-index: 1;
  white-space: nowrap;
}
/* .tbl th wins over the bare .ta-right helper on specificity, leaving numeric
   headers left-aligned over right-aligned figures. Re-assert it for headers. */
.tbl th.ta-right { text-align: right; }
.tbl th[data-sort] { cursor: pointer; user-select: none; }
.tbl th[data-sort]:hover { color: var(--ink); }
.sort-arrow { margin-left: 3px; color: var(--accent); }
.tbl td { padding: 5px 10px; border-bottom: 1px solid var(--grid); vertical-align: middle; }
.tbl tbody tr:hover { background: var(--surface-2); }
.tbl tbody tr.no-rows:hover { background: none; }
.tbl tr.no-rows td { padding: 0; border: 0; }
.tbl tfoot td { padding: 7px 10px; border-top: 1px solid var(--line); font-weight: 640; }
/* compact tightens spacing only — sizes come from the shared tier-two type */
.tbl.compact td, .tbl.compact th { padding: 4px 8px; }
.tbl .ta-right { font-variant-numeric: tabular-nums; }
tr.total-row td { border-top: 1px solid var(--line); border-bottom: 2px double var(--ink-2); font-weight: 680; }
tr.grand-row td { font-size: 13.5px; }
tr.subtotal-row td { border-top: 1px solid var(--grid); font-weight: 620; }
tr.section-row td { font-weight: 660; background: var(--surface-2); }
tr.spacer td { height: 7px; border: 0; background: none; }
tr.row-on { background: var(--accent-soft) !important; }
tr.row-dim { opacity: .5; }
.indent-1 { padding-left: 30px !important; }
.indent-2 { padding-left: 50px !important; }
.indent-3 { padding-left: 70px !important; }
.cell-entity { display: flex; align-items: center; gap: 7px; }
/* Keep name columns on one line; the table scrolls if space runs out. */
.tbl .link-btn.strong { white-space: nowrap; }
.acct-name { padding-left: calc(var(--d, 0) * 16px); }
.chk-cell { text-align: center; }
.cleared { color: var(--good-text); font-weight: 700; }

/* ---------- badges & chips ---------- */
.badge {
  display: inline-block; padding: 1px 6px; border-radius: 4px;
  font-size: 10.5px; font-weight: 620; letter-spacing: .01em; white-space: nowrap;
}
.badge-ok { background: color-mix(in srgb, var(--good) 16%, transparent); color: var(--good-text); }
.badge-info { background: color-mix(in srgb, var(--viz-1) 16%, transparent); color: var(--viz-1); }
.badge-warn { background: color-mix(in srgb, var(--warning) 24%, transparent); color: #8a5c00; }
.badge-danger { background: color-mix(in srgb, var(--critical) 16%, transparent); color: var(--bad-text); }
.badge-muted { background: var(--surface-2); color: var(--muted); }
:root[data-theme="dark"] .badge-warn { color: var(--warning); }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .badge-warn { color: var(--warning); }
}
.chip {
  display: inline-block; padding: 0 5px; border-radius: 3px; margin-left: 5px;
  font-size: 9.5px; font-weight: 620; text-transform: uppercase; letter-spacing: .035em;
  background: var(--surface-2); color: var(--muted);
}
.chip-ok { background: color-mix(in srgb, var(--good) 16%, transparent); color: var(--good-text); }
.chip-warn { background: color-mix(in srgb, var(--warning) 26%, transparent); color: #8a5c00; }
.chip-bad { background: color-mix(in srgb, var(--bad-text) 18%, transparent); color: var(--bad-text); }
.chip-info { background: color-mix(in srgb, var(--accent) 13%, transparent); color: var(--accent); }
/* A status cell states two independent facts side by side, so its chips sit in
   a row of their own rather than trailing a sentence. */
.st-cell { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.st-cell .chip { margin-left: 0; }
.avatar {
  width: 22px; height: 22px; border-radius: 5px; flex: none;
  display: grid; place-items: center; font-size: 9.5px; font-weight: 700;
  background: hsl(var(--h, 200) 42% 88%); color: hsl(var(--h, 200) 55% 26%);
}
:root[data-theme="dark"] .avatar { background: hsl(var(--h, 200) 30% 26%); color: hsl(var(--h, 200) 60% 82%); }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .avatar { background: hsl(var(--h,200) 30% 26%); color: hsl(var(--h,200) 60% 82%); }
}

/* ---------- forms ---------- */
.field { display: flex; flex-direction: column; gap: 3px; margin-bottom: 9px; }
.field > label { font-size: 11.5px; font-weight: 600; color: var(--ink-2); }
/* A field the CATEGORY answers. Not disabled-because-broken: disabled
   because somebody already decided, one level up. The label says where it
   came from so the greying reads as an explanation rather than a fault. */
.field.from-category > label::after {
  content: " · from the category";
  font-weight: 400; font-style: italic; color: var(--muted);
}
.req { color: var(--critical); }
.hint { font-size: 11px; color: var(--muted); line-height: 1.35; }
input[type=text], input[type=email], input[type=number], input[type=date],
input[type=search], input[type=password], input[type=url], select, textarea {
  width: 100%; padding: 5px 8px; font: inherit; font-size: 12.5px;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
}
textarea { resize: vertical; }
/* One ring, not two. A 2px outline held one pixel off the field drew a
   second line with a gap of page showing between it and the border. Pulled
   in onto the border, it reads as a single crisp edge — and, sitting inside
   the box, it no longer grows the field and shoves its neighbours in a
   line grid. */
input:focus, select:focus, textarea:focus, .btn:focus-visible, .link-btn:focus-visible {
  outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent);
}
input[readonly] { background: var(--surface-2); color: var(--ink-2); }
input[type=color] { padding: 2px; height: 34px; }
input[type=file] { font-size: 13px; }
select { cursor: pointer; }
.sel-sm, select.sel-sm { width: auto; min-width: 118px; padding: 4px 7px; font-size: 12px; }
/* The input half of the same idea. A bare field in a toolbar inherits
   width:100% from the form-field rule and takes the whole bar to itself,
   pushing whatever follows onto its own line — which is what the As-of date
   was doing. banking.js was already asking for this class; it just was never
   written, so those two date boxes have been full width the whole time. */
.inp-sm, input.inp-sm { width: auto; min-width: 140px; padding: 4px 7px; font-size: 12px; }
.mini { width: 70px !important; padding: 3px 5px; font-size: 12px; }
.form-grid-2, .form-grid-3, .doc-grid {
  display: grid; gap: 0 12px;
}
.form-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.form-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.doc-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.span2 { grid-column: span 2; }
.form-actions { display: flex; gap: 10px; margin-top: 18px; }

/* Freight sits under its own heading inside the line table — what you bought
   above, what it cost to get it here below. */
.lines tr.ln-head-row > td {
  padding: 13px 10px 3px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--muted); border-top: 1px solid var(--border);
}
.lines tr.ln-head-row .icn {
  width: 11px; height: 11px; vertical-align: -1px; margin-right: 5px; opacity: .65;
}
.lines-actions .grow { flex: 1 1 auto; }

/* (an orphaned rule that had lost its selector lived here — it parsed as
   garbage and swallowed the rule after it; removed) */


/* An account that is fixed by the rules rather than chosen. Reads as text, not
   as a disabled control, because there is nothing here to operate. */
.ln-locked {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; color: var(--muted);
  /* Sized and padded like the inputs beside it, so a locked cell sits on
     the same baseline as the editable ones around it. */
  padding: 0 8px; height: 28px; box-sizing: border-box; width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ln-locked .icn { width: 12px; height: 12px; opacity: .6; flex: none; }

/* Marks the line that is freight rather than goods. Small and quiet — it is a
   label on a line, not an alarm. */
.lc-tag {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 4px; padding: 1px 7px 1px 5px; border-radius: 999px;
  font-size: 11px; font-weight: 600; letter-spacing: .01em;
  background: var(--accent-soft); color: var(--accent);
}
.lc-tag.inline { margin-top: 0; vertical-align: 2px; }
.lc-tag .icn { width: 12px; height: 12px; }

.emp-avatar {
  width: 52px; height: 52px; border-radius: 50%; object-fit: cover;
  border: 1px solid var(--grid); flex: none; align-self: center;
}

/* ---------- dashboard logo ---------- */
.dash-logo {
  width: 72px; height: 72px; border-radius: 14px; object-fit: contain;
  background: var(--surface); border: 1px solid var(--grid); padding: 6px;
  flex: none; align-self: center;
}

/* ---------- leave calendar (day / week / month / year) ---------- */
.lv-cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.lv-cal .cal-dow {
  font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .045em;
  color: var(--muted); text-align: center; padding: 2px 0;
}
.cal-day {
  min-height: 72px; border: 1px solid var(--grid); border-radius: 8px;
  padding: 4px 6px; background: var(--surface); overflow: hidden;
}
.lv-week .cal-day { min-height: 120px; }
.cal-day.cal-blank { border-color: transparent; background: transparent; }
.cal-day[data-cal-date], .yc-day[data-cal-date] { cursor: pointer; }
.cal-day[data-cal-date]:hover, .yc-day[data-cal-date]:hover { border-color: var(--accent); }
.yc-day[data-cal-date]:hover { box-shadow: inset 0 0 0 1px var(--accent); }
.cal-day.wknd { background: var(--surface-2); }
.cal-day.hol { background: color-mix(in srgb, var(--good) 14%, var(--surface)); border-color: color-mix(in srgb, var(--good) 40%, transparent); }
.cal-day.today { outline: 2px solid var(--accent); outline-offset: -1px; }
.cal-num { font-size: 11.5px; font-weight: 640; color: var(--muted); }
.cal-day.today .cal-num { color: var(--accent); }
.cal-hol {
  font-size: 10px; line-height: 1.25; color: var(--good-text); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-chip {
  display: block; font-size: 10px; line-height: 1.5; border-radius: 4px;
  padding: 0 5px; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-chip.lv-annual { background: color-mix(in srgb, var(--viz-1) 18%, transparent); color: var(--viz-1); }
.cal-chip.lv-sick { background: color-mix(in srgb, var(--warning) 24%, transparent); color: #8a5c00; }
.cal-chip.lv-unpaid { background: var(--surface-2); color: var(--muted); }
.cal-chip.lv-other { background: color-mix(in srgb, #8b5cf6 18%, transparent); color: #7c3aed; }
:root[data-theme="dark"] .cal-chip.lv-other { color: #a78bfa; }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .cal-chip.lv-other { color: #a78bfa; }
}
.cal-chip.lv-more { background: transparent; color: var(--muted); }
.cal-legend .cal-chip { display: inline-block; margin-top: 0; }
.lv-year {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px;
}
.mini-cal { border: 1px solid var(--grid); border-radius: 10px; padding: 8px 9px; background: var(--surface); }
.mc-name { font-size: 12px; font-weight: 650; margin-bottom: 5px; }
.mc-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.yc-dow {
  font-size: 9px; font-weight: 600; color: var(--muted); text-align: center;
  text-transform: uppercase;
}
.yc-day {
  font-size: 10.5px; text-align: center; line-height: 1.9;
  border-radius: 5px; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.yc-day.yc-blank { visibility: hidden; }
.yc-day.wknd { background: var(--surface-2); color: var(--muted); }
.yc-day.hol { background: color-mix(in srgb, var(--good) 20%, var(--surface)); color: var(--good-text); font-weight: 650; }
.yc-day.lv { box-shadow: inset 0 -2.5px 0 var(--viz-1); }
.yc-day.lv:not(.hol):not(.wknd) { background: color-mix(in srgb, var(--viz-1) 14%, var(--surface)); color: var(--viz-1); font-weight: 650; }
.yc-day.today { outline: 2px solid var(--accent); outline-offset: -1px; font-weight: 700; }
.cal-legend { display: flex; gap: 16px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
.cal-legend span { display: inline-flex; gap: 6px; align-items: center; }
.cal-key {
  display: inline-block; width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--grid);
}
.cal-key.wknd { background: var(--surface-2); }
.cal-key.hol { background: color-mix(in srgb, var(--good) 20%, var(--surface)); border-color: color-mix(in srgb, var(--good) 40%, transparent); }
.cal-key.lv { background: color-mix(in srgb, var(--viz-1) 14%, var(--surface)); box-shadow: inset 0 -2.5px 0 var(--viz-1); }
.cal-key.today { border: 2px solid var(--accent); }
@media (max-width: 1100px) { .lv-year { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 820px) { .lv-year { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .lv-year { grid-template-columns: 1fr; } }

/* Two steps, numbered, because they happen at different moments and telling
   them apart is the whole difficulty of landed cost. */
.lc-steps { margin: 0; padding: 0; list-style: none; counter-reset: lcstep; }
.lc-steps li {
  position: relative; padding: 0 0 0 28px; margin: 0 0 9px;
  font-size: 12.5px; line-height: 1.5; color: var(--muted);
}
.lc-steps li:last-child { margin-bottom: 0; }
.lc-steps li b { color: var(--ink); }
.lc-steps li::before {
  counter-increment: lcstep; content: counter(lcstep);
  position: absolute; left: 0; top: 2px;
  width: 17px; height: 17px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 700;
  background: var(--accent-soft, rgba(0,0,0,.06)); color: var(--accent);
}

/* The facts a dialog is acting on, stated before the controls that act on
   them — read-only, so they are text and not disabled inputs. */
.kv-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 6px 20px; padding-bottom: 12px; margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
}
.kv { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; }
.kv > span { color: var(--muted); }
/* Inside a detail grid the side-by-side pair collides with its neighbours —
   stack the label above its value instead. */
.doc-grid .kv { display: block; }
.doc-grid .kv > span { display: block; margin-bottom: 2px; }
tr.dim > td { opacity: .45; }

.chk, .radio { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13.5px; }
.chk input, .radio input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
.radio-group { display: flex; flex-direction: column; gap: 8px; }
/* Checkboxes that answer one question together — what a contact IS to you
   — read as a row, not as a stack of unrelated switches. */
.chk-row { display: flex; gap: 18px; flex-wrap: wrap; align-items: center; }

.money-input { position: relative; }
.money-input .cur {
  position: absolute; left: 9px; top: 50%; transform: translateY(-50%);
  font-size: 12.5px; color: var(--muted); pointer-events: none;
}
.money-input input { padding-left: 24px; }

.search { position: relative; display: flex; align-items: center; min-width: 210px; flex: 0 1 300px; }
.search .icn { position: absolute; left: 9px; color: var(--muted); pointer-events: none; }
.search input { padding-left: 30px; }
.date-pair { display: inline-flex; align-items: center; gap: 6px; }
.date-pair input { width: 145px; }
.dash { color: var(--muted); }
.period { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ---------- tabs ---------- */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--border); overflow-x: auto; }
.tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; border: 0; background: none; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--muted);
  border-bottom: 2px solid transparent; white-space: nowrap;
}
.tab .icn { width: 14px; height: 14px; }
.tab:hover { color: var(--ink); }
.tab.on { color: var(--ink); font-weight: 620; border-bottom-color: var(--accent); }
.tab-count {
  background: var(--surface-2); border-radius: 8px; padding: 0 5px;
  font-size: 10.5px; font-weight: 640;
}
.tab-body { padding-top: 12px; }
/* Same rhythm inside a tab as the page itself has — the assets register sat
   with its table welded to the tiles because this wrapper swallowed the
   page-level spacing rule. */
.tab-body > * + * { margin-top: 12px; }
.modal-tabs { margin-top: 10px; }

/* ---------- banners & empty ---------- */
/* Block layout, not flex — inline <b>/<code>/<button> inside the message
   must stay part of the sentence rather than becoming flex items. */
.banner {
  display: block; position: relative;
  padding: 8px 11px 8px 32px; border-radius: var(--r);
  font-size: 12.5px; line-height: 1.45; border: 1px solid var(--border);
}
.banner > .icn { position: absolute; left: 10px; top: 9px; width: 15px; height: 15px; }
.banner p:last-child, .banner ul:last-child { margin-bottom: 0; }
.banner-info { background: color-mix(in srgb, var(--viz-1) 9%, var(--surface)); border-color: color-mix(in srgb, var(--viz-1) 30%, transparent); }
.banner-warn { background: color-mix(in srgb, var(--warning) 14%, var(--surface)); border-color: color-mix(in srgb, var(--warning) 40%, transparent); }
.banner-ok { background: color-mix(in srgb, var(--good) 10%, var(--surface)); border-color: color-mix(in srgb, var(--good) 30%, transparent); }

.empty { text-align: center; padding: 30px 18px; }
.empty-icn {
  width: 34px; height: 34px; margin: 0 auto 9px; border-radius: 8px;
  background: var(--surface-2); color: var(--muted); display: grid; place-items: center;
}
.empty-icn .icn { width: 17px; height: 17px; }
.empty h3 { margin-bottom: 3px; }
.empty p { color: var(--muted); max-width: 400px; margin: 0 auto 11px; font-size: 12.5px; }

.err-list { margin: 0; padding-left: 20px; color: var(--bad-text); }
.err-list li { margin-bottom: 5px; }
.err-pre { background: var(--surface-2); padding: 12px; border-radius: var(--r); overflow: auto; font-size: 11.5px; max-height: 240px; }
.confirm-msg { font-size: 14.5px; }



/* ---------- registers ----------
   A list of branches and what is on each. Deliberately not a table: the
   question an owner has is "is the shop's till on?", and a grid of columns
   answered five questions nobody had while burying that one. */
.reg-branch { margin-bottom: 14px; }
.reg-branch:last-child { margin-bottom: 0; }
.reg-branch-name {
  font-weight: 500; font-size: 14px; margin-bottom: 4px;
  padding-bottom: 4px; border-bottom: 1px solid var(--border);
}
.reg-till {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid rgba(128,128,128,.12);
}
.reg-till:last-child { border-bottom: 0; }
.reg-till-what { flex: 1 1 auto; min-width: 0; font-size: 13.5px; }
.reg-mac { font-variant-numeric: tabular-nums; letter-spacing: .04em; color: var(--muted); }
.reg-dot { color: var(--muted); margin: 0 6px; }
.reg-when { font-size: 12px; color: var(--muted); margin-top: 2px; }
/* A till dark since Tuesday looks identical to a working one without this,
   which is the whole reason the line is here. */
.reg-live, .reg-dead {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-inline-end: 6px; vertical-align: middle;
}
.reg-live { background: var(--good); }
.reg-dead { background: var(--critical); }
.reg-cut { flex: none; }
/* ---------- pairing a till ----------
   A screen a cashier looks at once, from across a counter, often while
   reading it aloud down a phone. So: one thing per line, the code big enough
   to read at arm's length, and nothing else competing for attention. */
.pair-wrap {
  /* #app is a flex ROW (the sidebar layout), so this has to claim the width
     itself or the card sits in a column at the left edge. */
  flex: 1 1 auto; width: 100%;
  min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.pair-card {
  width: 100%; max-width: 420px; text-align: center;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 14px; padding: 28px 24px; box-shadow: var(--shadow-lg);
}
.pair-card h1 { font-size: 20px; margin-bottom: 6px; }
.pair-code {
  font-size: 40px; font-weight: 500; letter-spacing: .18em;
  margin: 18px 0 10px; font-variant-numeric: tabular-nums;
  color: var(--text-accent, var(--ink));
}
.pair-qr { display: flex; justify-content: center; margin: 6px 0 10px; }
.pair-qr svg { width: 132px; height: 132px; }
.pair-dev {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 14px 0 4px; padding: 9px 12px;
  background: var(--surface-2); border-radius: var(--r);
}
.pair-dev b { font-variant-numeric: tabular-nums; letter-spacing: .06em; }
/* The install step, for a browser that cannot offer a prompt — iOS hides it
   in the share sheet. Instructions have to look like instructions, not like
   the small print under a button that isn't there. */
.pair-steps {
  margin: 18px 0 4px; padding: 12px 14px;
  background: var(--surface-2); border-radius: var(--r);
  font-size: 14px; line-height: 1.5;
}
.pair-steps p { margin: 0; }

/* ---------- storage alarm ----------
   Not a toast. A toast is a thing that has happened; this is a state the app
   is IN, and it stays on screen for as long as the state lasts. No close
   button, no animation, no fade — deliberately. It sits below the modal layer
   (z 200) so a dialog is never half-covered by it; it is still there when the
   dialog closes, because nothing but a successful save takes it down. */
.storage-alarm {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 190;
  display: flex; align-items: center; gap: 10px;
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
  font-size: 13.5px; line-height: 1.35;
  color: var(--bad-text);
  background: color-mix(in srgb, var(--critical) 18%, var(--surface));
  border-top: 2px solid var(--critical);
  box-shadow: 0 -6px 18px rgb(0 0 0 / .12);
}
.storage-alarm > .icn { width: 17px; height: 17px; flex: none; }
.storage-alarm > div { flex: 1 1 auto; min-width: 0; }
.storage-alarm .btn { flex: none; }
/* Keep the bar off the last row of whatever is on screen — including the
   till, where the bottom row is the one that takes the money. */
body.storage-blocked .view { padding-bottom: 76px; }
body.storage-blocked.pos-only .view,
body.storage-blocked.pos-register .view,
body.storage-blocked.pos-fullscreen .view { padding-bottom: 60px !important; }
/* Toasts stack in the same corner and sat squarely on top of the bar's own
   Back up button — the one control it exists to offer. They move up instead. */
body.storage-blocked #toast-root { bottom: 68px; }

/* ---------- toasts ---------- */
#toast-root {
  position: fixed; right: 18px; bottom: 18px; z-index: 300;
  display: flex; flex-direction: column; gap: 9px; pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 13px; min-width: 250px; max-width: 400px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r); box-shadow: var(--shadow-lg);
  font-size: 13.5px; pointer-events: auto;
  animation: toast-in .2s ease;
}
.toast-out { animation: toast-out .2s ease forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px); } }
/* A result carries its own colour, and it is the SAME green the paid and
   reconciled badges wear — one meaning, one colour. Mixed into the surface
   rather than into transparency, because a toast floats over the page and
   has to stay opaque. */
.toast-success {
  background: color-mix(in srgb, var(--good) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--good) 45%, var(--surface));
  color: var(--good-text);
}
.toast-success .icn, .toast-success .toast-x { color: var(--good-text); }
.toast-error {
  background: color-mix(in srgb, var(--critical) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--critical) 45%, var(--surface));
  color: var(--bad-text);
}
.toast-error .icn, .toast-error .toast-x { color: var(--bad-text); }
.toast-info {
  background: color-mix(in srgb, var(--viz-1) 15%, var(--surface));
  border-color: color-mix(in srgb, var(--viz-1) 45%, var(--surface));
  color: var(--viz-1);
}
.toast-info .icn, .toast-info .toast-x { color: var(--viz-1); }
.toast-x { margin-left: auto; border: 0; background: none; cursor: pointer; color: var(--muted); padding: 0; display: flex; }

/* ---------- modals ---------- */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(11,11,11,.42); backdrop-filter: blur(2px);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 44px 18px; overflow-y: auto;
  animation: fade-in .14s ease;
}
.modal-out { animation: fade-out .14s ease forwards; }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
.modal {
  background: var(--surface); border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg); width: 100%; max-width: 560px;
  animation: modal-in .18s cubic-bezier(.2,.8,.3,1);
  display: flex; flex-direction: column; max-height: calc(100vh - 88px);
}
@keyframes modal-in { from { opacity: 0; transform: translateY(-10px) scale(.99); } }
.modal-sm { max-width: 420px; }
.modal-md { max-width: 640px; }
.modal-lg { max-width: 940px; }
.modal-head { padding: 12px 14px 9px; border-bottom: 1px solid var(--border); position: relative; }
.modal-head h2 { font-size: 15px; padding-right: 30px; }
.modal-sub { font-size: 12px; color: var(--muted); margin: 2px 0 0; }
.modal-close { position: absolute; top: 9px; right: 9px; }
.modal-body { padding: 14px; overflow-y: auto; flex: 1 1 auto; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 7px;
  padding: 10px 14px; border-top: 1px solid var(--border); background: var(--surface-2);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* dropdown menus */
.menu-wrap { position: relative; display: inline-flex; }
.menu {
  position: absolute; top: calc(100% + 5px); right: 0; z-index: 60;
  min-width: 210px; padding: 5px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--r); box-shadow: var(--shadow-lg);
}
.menu-left { right: auto; left: 0; }
.menu-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 7px 10px; border: 0; background: none; border-radius: var(--r-sm);
  font: inherit; font-size: 13px; color: var(--ink); cursor: pointer; text-align: left;
}
.menu-item:hover { background: var(--surface-2); }
.menu-item.danger { color: var(--bad-text); }
.menu-div { height: 1px; background: var(--border); margin: 5px 2px; }

/* ---------- document editor ---------- */
.doc-editor .card + .card { margin-top: 20px; }
.entity-strip {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; margin-top: 2px;
  background: var(--surface-2); border-radius: var(--r);
}
.strip-bal { margin-left: auto; text-align: right; font-size: 11px; color: var(--muted); }
.strip-bal b { display: block; font-size: 13.5px; color: var(--ink); }

.lines-wrap { overflow-x: auto; }
.lines { width: 100%; border-collapse: collapse; min-width: 900px; }
.lines th {
  text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: .045em;
  color: var(--muted); font-weight: 600; padding: 6px 7px;
  border-bottom: 1px solid var(--line); background: var(--surface-2);
}
.lines td { padding: 2px 5px; border-bottom: 1px solid var(--grid); }
/* The grid you type into earns its verticals twice over: they show which cell
   you are tabbing through, and they line the money columns up down the page. */
.lines th, .lines td { border-right: 1px solid var(--grid); }
.lines th:last-child, .lines td:last-child { border-right: 0; }
.lines .ln-no { text-align: center; color: var(--muted); font-size: 11px; }
.lines input, .lines select { padding: 4px 6px; font-size: 12.5px; border-color: transparent; background: transparent; }
.lines input:hover, .lines select:hover { border-color: var(--border); background: var(--surface); }
.lines input:focus, .lines select:focus { background: var(--surface); }
.lines .ln-del { text-align: center; }
.lines-actions { display: flex; gap: 6px; padding: 8px 10px; border-top: 1px solid var(--border); }
.je-totals td { border-top: 1px solid var(--line); padding: 7px 7px; }

.doc-bottom { display: grid; grid-template-columns: 1fr 300px; gap: 14px; margin-top: 12px; }
.doc-notes { min-width: 0; }
.doc-totals {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 11px 13px; box-shadow: var(--shadow); height: fit-content;
}
.totals-tbl { width: 100%; border-collapse: collapse; }
.totals-tbl td { padding: 3px 0; font-size: 12.5px; font-variant-numeric: tabular-nums; }
/* An amount and its currency code are one word — "KD 1,800.000" breaking
   across two lines reads like an error, so the value column never wraps. */
.totals-tbl td:last-child { white-space: nowrap; }
.tot-lbl { color: var(--ink-2); }
.disc-ctl { display: inline-flex; gap: 4px; margin-left: 6px; }
.totals-tbl tr.grand td { border-top: 1px solid var(--line); font-weight: 680; font-size: 14px; padding-top: 7px; }
.totals-tbl tr.due td { font-weight: 680; font-size: 13.5px; color: var(--accent); }
.totals-tbl tr.warn-row td { color: var(--serious); }
.totals-tbl tr.fc-row td { color: var(--muted); font-size: 12.5px; border-top: 1px dashed var(--border); }
.fc-base { display: block; font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

.doc-footer {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 12px; margin-top: 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
}
.doc-footer-info { display: flex; gap: 14px; align-items: center; font-size: 12.5px; color: var(--ink-2); flex-wrap: wrap; }
.doc-footer-acts { margin-left: auto; }

.apply-tbl input { padding: 5px 7px; }

/* ---------- detail layout ---------- */
.detail-grid { display: grid; grid-template-columns: 1fr 290px; gap: 12px; align-items: start; }
.detail-side .card { position: sticky; top: 56px; }
.dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 11px; margin: 0; font-size: 12.5px; }
.dl dt { color: var(--muted); font-size: 11.5px; }
.dl dd { margin: 0; }

/* ---------- dashboard ---------- */
/* Three tracks: the lead chart and the activity feed take two, their side
   cards (bank accounts, P&L summary) take the third — the mock's rhythm. */
.dash-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.dash-grid > .card { margin-top: 0; }
.dash-grid > .span2 { grid-column: span 2; }
/* Customizable dashboard: every section is a widget cell. A widget carries
   its own span, and its inner card fills it. */
.dash-widget { grid-column: span 1; min-width: 0; display: flex; flex-direction: column; }
.dash-widget.span2 { grid-column: span 2; }
.dash-widget.span3 { grid-column: 1 / -1; }
.dash-widget > .card, .dash-widget > section.card { flex: 1; margin-top: 0; }
.dash-widget > .stat-row { flex: 1; }
.dash-editbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--accent-soft); border: 1px solid var(--accent); border-radius: var(--r);
  padding: 8px 12px; margin-bottom: 14px; font-size: 13.5px; }
.dash-editbar > span:first-child { display: inline-flex; align-items: center; gap: 6px; color: var(--ink-2); }
.dash-grid.editing .dash-widget.editable { outline: 1.5px dashed var(--border-strong); outline-offset: 3px;
  border-radius: var(--r); position: relative; cursor: grab; }
.dash-grid.editing .dash-widget.dragging { opacity: .5; }
.dash-wtools { display: flex; align-items: center; gap: 4px; padding: 4px 6px; margin-bottom: 6px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); }
.dash-wtitle { font-size: 12px; font-weight: 600; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.dash-grip { display: inline-flex; color: var(--muted); cursor: grab; }
.dash-add { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; padding-top: 14px;
  border-top: 1px dashed var(--border-strong); }
@media (max-width: 900px) { .dash-widget.span2, .dash-widget.span3 { grid-column: 1 / -1; } }

/* bank accounts card */
.bank-list { list-style: none; margin: 0; padding: 4px 0; }
.bank-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px; border-bottom: 1px solid var(--grid);
}
.bank-row:last-child { border-bottom: 0; }
.bank-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.bank-name {
  min-width: 0; font-size: 12.5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bank-bal { margin-left: auto; text-align: right; font-size: 12.5px; }
.bank-add {
  display: flex; align-items: center; gap: 6px; width: 100%;
  padding: 10px 14px; border: 0; border-top: 1px solid var(--grid);
  background: none; color: var(--accent); font: inherit; font-size: 12.5px;
  font-weight: 600; cursor: pointer;
}
.bank-add .icn { width: 13px; height: 13px; }
.bank-add:hover { background: var(--surface-2); }

/* P&L summary card */
.pnl-summary { margin: 0 0 12px; }
.pnl-summary > div {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--grid); font-size: 13px;
}
.pnl-summary dt { color: var(--ink-2); }
.pnl-summary dd { margin: 0; font-weight: 600; }
.pnl-summary .pnl-net { font-size: 14px; }
.pnl-summary .pnl-net dt { font-weight: 700; color: var(--ink); }
.btn-block { display: flex; justify-content: center; width: 100%; }
.chart-card .card-body { padding: 8px 10px 10px; }
.tasks-card {
  border-color: color-mix(in srgb, var(--bad-text) 40%, var(--border));
  background: color-mix(in srgb, var(--bad-text) 7%, var(--surface));
}
.tasks-card .card-head { background: transparent; border-bottom-color: color-mix(in srgb, var(--bad-text) 22%, transparent); }
.tasks-card.collapsed .card-head { border-bottom: 0; }
.tasks-card .task { border-bottom-color: color-mix(in srgb, var(--bad-text) 14%, transparent); }
.tasks-toggle { cursor: pointer; user-select: none; display: flex; align-items: center; gap: 8px; }
.tasks-chev .icn { transition: transform .15s ease; color: var(--muted); }
.tasks-chev.up .icn { transform: rotate(180deg); }
.task-list { list-style: none; margin: 0; padding: 0; }
.task {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 12px; border-bottom: 1px solid var(--grid);
}
.task:last-child { border-bottom: 0; }
.task-icn { display: flex; color: var(--muted); }
.task-bad .task-icn { color: var(--critical); }
.task-warn .task-icn { color: var(--serious); }
.task-info .task-icn { color: var(--viz-1); }
.task-text { flex: 1 1 auto; font-size: 12.5px; }
.task-icn .icn { width: 15px; height: 15px; }
.quick-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; }
.quick {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 10px 6px; border-radius: var(--r);
  background: var(--surface-2); border: 1px solid transparent;
  color: var(--ink-2); font: inherit; font-size: 11.5px; cursor: pointer;
}
.quick:hover { border-color: var(--accent); color: var(--ink); background: var(--accent-soft); }
.quick .icn { width: 16px; height: 16px; }

/* ---------- charts ---------- */
.viz { width: 100%; height: auto; display: block; overflow: visible; }
.viz-grid { stroke: var(--grid); stroke-width: 1; }
.viz-axis { stroke: var(--line); stroke-width: 1; }
.viz-tick { fill: var(--muted); font: 11px var(--font); }
.viz-cat { fill: var(--ink-2); font: 12px var(--font); }
.viz-val { fill: var(--ink); font: 12px var(--font); font-weight: 620; font-variant-numeric: tabular-nums; }
.viz-bar { transition: opacity .12s; }
.viz-bar:hover { opacity: .82; }
.viz-track { fill: var(--surface-2); }
.viz-line { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.viz-area { opacity: .12; }
.viz-dot { stroke: var(--surface); stroke-width: 2; }
.viz-hot { fill: transparent; }
.viz-hot:hover { fill: var(--ink); opacity: .04; }
.viz-legend { display: flex; gap: 16px; padding: 2px 0 8px; flex-wrap: wrap; }
.viz-key { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-2); }
.viz-key i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.viz-empty { padding: 40px 16px; text-align: center; color: var(--muted); font-size: 13px; }
/* ---------- donut ----------
   Ring on the left, legend on the right; on a narrow card they stack. The
   legend carries the money and the share, because the ring only ranks. */
.viz-donut { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; min-width: 0; }
.viz-donut > .viz { flex: 0 1 180px; min-width: 140px; max-width: 220px; }
.viz-slice { stroke: var(--surface); stroke-width: 1.5; transition: opacity .12s; }
.viz-donut:hover .viz-slice { opacity: .55; }
.viz-donut .viz-slice:hover { opacity: 1; }
.viz-donut-total { fill: var(--ink); font: 700 19px var(--font); font-variant-numeric: tabular-nums; }
.viz-donut-cap { fill: var(--muted); font: 11px var(--font); text-transform: uppercase; letter-spacing: .06em; }
/* min-width:0 all the way down, or the name refuses to shrink, the row grows
   wider than the card, and the percentage is clipped off the right edge. */
.viz-legend { flex: 1 1 170px; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.viz-lg-row { display: flex; align-items: center; gap: 8px; font-size: 12.5px; min-width: 0; }
.viz-lg-dot { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.viz-lg-name { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1 1 auto; min-width: 0; }
.viz-lg-val { flex: none; margin-left: auto; font-weight: 620; font-variant-numeric: tabular-nums; white-space: nowrap; }
.viz-lg-pct { flex: none; color: var(--muted); font-size: 11.5px; width: 42px; text-align: right;
  font-variant-numeric: tabular-nums; }
.viz-tip {
  position: fixed; z-index: 400; pointer-events: none;
  padding: 6px 9px; border-radius: 6px; font-size: 12px; font-weight: 550;
  background: var(--ink); color: var(--page); box-shadow: var(--shadow-lg);
  white-space: nowrap;
}

.pbar { height: 7px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.pbar-fill { height: 100%; background: var(--viz-1); border-radius: 4px; }
.pbar-fill.warn { background: var(--warning); }
.pbar-fill.over { background: var(--critical); }

/* ---------- reports ---------- */
.rpt-index { display: flex; flex-direction: column; gap: 16px; }
.rpt-group h3 { margin-bottom: 8px; }
.rpt-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 8px; }
.rpt-card {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  padding: 10px 11px; border-radius: var(--r);
  background: var(--surface); border: 1px solid var(--border);
  cursor: pointer; font: inherit; box-shadow: var(--shadow);
}
.rpt-card:hover { border-color: var(--accent); }
.rpt-icn { color: var(--accent); display: flex; margin-bottom: 2px; }
.rpt-icn .icn { width: 15px; height: 15px; }
.rpt-name { font-weight: 630; font-size: 12.5px; }
.rpt-blurb { font-size: 11.5px; color: var(--muted); line-height: 1.35; }
.report-surface {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-lg); padding: 12px; box-shadow: var(--shadow);
}
.report-surface > .stat-row { margin-bottom: 12px; }
.rpt-subhead { margin-bottom: 8px; }
.tbl.rpt td { padding: 5px 10px; }
.tbl.rpt-2col td:first-child { width: auto; }
/* A comparative period widens a statement from two columns to five, which is
   more than a narrow screen holds. The table scrolls inside its own box so the
   PAGE never scrolls sideways, and the percentage is set quieter than the
   money beside it — it is context, not a figure anybody keys in. */
.tbl.rpt-cmp th, .tbl.rpt-cmp td { white-space: nowrap; }
.tbl.rpt-cmp td:last-child { font-size: 12px; }
.tbl.gl td { font-size: 13px; padding: 6px 10px; }

/* ---------- banking ----------
   The card grid that lived here died with the accounts overview, which
   lists accounts in a table. Its .bank-name / .bank-bal are still defined
   further up, where the dashboard's bank widget uses them. */
/* ---------- the account's own dashboard ----------
   Activity on the left, the queue waiting on the right; one column once the
   window is too narrow to hold both. */
.ws-dash { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.ws-dash-main { flex: 1 1 520px; min-width: 0; }
.ws-dash-side { flex: 0 1 300px; min-width: 240px; display: flex; flex-direction: column; gap: 12px; }
.ws-h { font-size: 14px; margin: 4px 0 10px; }
.ws-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; margin-bottom: 12px; }
.ws-fact .card-body { padding: 13px 14px; }
.ws-fact-h { display: flex; align-items: center; gap: 7px; font-size: 13.5px; margin-bottom: 9px; }
.ws-fact-h .icn { width: 15px; height: 15px; color: var(--muted); }
.ws-fact-r { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; padding: 3px 0;
  font-variant-numeric: tabular-nums; }
.ws-fact-f { margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--border); font-size: 12.5px; }
.ws-fact-f .icn { width: 14px; height: 14px; margin-right: 4px; vertical-align: -2px; }
.ws-q { display: flex; gap: 11px; align-items: center; padding: 12px 13px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r); }
.ws-q-n { display: inline-flex; align-items: center; justify-content: center; min-width: 42px; height: 34px;
  padding: 0 8px; border-radius: 8px; font-size: 16px; font-weight: 680; font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--critical) 14%, var(--surface)); color: var(--bad-text); }
.ws-q-n.zero { background: var(--surface-2); color: var(--muted); }
.ws-q-l { font-size: 13px; font-weight: 600; }
.ws-recent { list-style: none; margin: 0; padding: 0; }
.ws-recent li { padding: 9px 13px; border-bottom: 1px solid var(--border); }
.ws-recent li:last-child { border-bottom: 0; }
.ws-recent-t { font-size: 12.5px; }

.rec-head {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 10px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r); box-shadow: var(--shadow);
}
.rec-stat { display: flex; flex-direction: column; gap: 1px; }
.rec-stat span { font-size: 10.5px; color: var(--muted); letter-spacing: .02em; font-weight: 600; }
.rec-stat b { font-size: 14.5px; font-variant-numeric: tabular-nums; }
.rec-stat.good b { color: var(--good-text); }
.rec-stat.bad b { color: var(--bad-text); }
.rec-acts { margin-left: auto; display: flex; gap: 9px; }
.reconcile-start { max-width: 560px; }
.dep-total { margin-top: 14px; text-align: right; font-size: 15px; }

/* ---------- budgets ---------- */
.budget-tbl input { width: 84px; padding: 4px 6px; font-size: 12.5px; text-align: right; }
.bud-sub { font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* ---------- fixed assets: barcodes & physical count ---------- */
.barcode { display: block; max-width: 100%; height: auto; }
.asset-barcode {
  background: #fff; border: 1px solid var(--border);
  border-radius: var(--r-sm); padding: 10px;
}
/* Lists sit side by side only when there is genuinely room for two tables. */
.count-lists {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 16px; align-items: start; margin-top: 16px;
}
.count-lists > .card { margin-top: 0; }
.scan-card { border-color: var(--accent); }
.scan-card .card-body { display: grid; grid-template-columns: minmax(260px, 1fr) minmax(260px, 1.4fr); gap: 16px; align-items: end; }
@media (max-width: 720px) { .scan-card .card-body { grid-template-columns: 1fr; } }
.scan-card .scan-feedback { margin-top: 0; }
.scan-label {
  display: block; font-size: 12px; font-weight: 620; color: var(--ink-2); margin-bottom: 6px;
}
.scan-input {
  width: 100%; font-size: 22px !important; padding: 14px 16px !important;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 2px; text-transform: uppercase;
}
.scan-feedback {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px; padding: 14px 16px; border-radius: var(--r);
  border: 1px solid var(--border); min-height: 62px;
}
.scan-feedback .icn { width: 22px; height: 22px; flex: none; }
.scan-ok { background: color-mix(in srgb, var(--good) 12%, var(--surface)); border-color: color-mix(in srgb, var(--good) 40%, transparent); }
.scan-ok .icn { color: var(--good); }
.scan-warn { background: color-mix(in srgb, var(--warning) 16%, var(--surface)); border-color: color-mix(in srgb, var(--warning) 45%, transparent); }
.scan-warn .icn { color: var(--serious); }
.scan-bad { background: color-mix(in srgb, var(--critical) 12%, var(--surface)); border-color: color-mix(in srgb, var(--critical) 40%, transparent); }
.scan-bad .icn { color: var(--critical); }
.scan-idle { background: var(--surface-2); }
.scan-idle .icn { color: var(--muted); }

.lb-list { margin-top: 14px; }
.lb-scroll {
  max-height: 220px; overflow-y: auto; margin-top: 8px;
  border: 1px solid var(--border); border-radius: var(--r-sm); padding: 8px;
}
.lb-row { display: flex; padding: 3px 0; font-size: 13px; }
.lb-preview { margin-top: 14px; }
.lb-sample {
  background: #fff; border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  padding: 12px; max-width: 260px; text-align: center;
}
.lb-sample .lb-name { font-size: 12px; font-weight: 650; color: #111; margin-top: 4px; }

/* ---------- serial numbers ---------- */
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .01em; }
.serial-btn { font-variant-numeric: tabular-nums; gap: 4px; }
.serial-btn.serial-ok { border-color: var(--good); color: var(--good-text); }
.serial-btn.serial-part { border-color: var(--warning); color: var(--serious); }
/* Tracking is off for this product — an offer, not a status, so it stays quiet. */
.serial-off { border-style: dashed; color: var(--muted); font-weight: 400; }
.serial-off:hover { color: var(--ink); border-style: solid; }
.sn-pick { max-height: 300px; overflow-y: auto; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 6px; margin-top: 8px; }
.sn-row { display: flex; padding: 3px 4px; border-radius: 3px; }
.sn-row:hover { background: var(--surface-2); }
.sn-row b { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* ---------- document + sibling list ---------- */
/* The list keeps its own scroll so moving between records never costs you
   your place in the history. */
.doc-split { display: flex; gap: 14px; align-items: flex-start; }
.doc-main { flex: 1 1 auto; min-width: 0; }
.doc-list-pane {
  flex: 0 0 268px; width: 268px; align-self: stretch;
  position: sticky; top: 6px; max-height: calc(100vh - 20px);
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r);
  overflow: hidden;
}
.dl-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.dl-head b { font-size: 12.5px; }
.dl-head .icon-btn { margin-left: auto; }
.dl-search { padding: 8px; border-bottom: 1px solid var(--border); }
.dl-search input { width: 100%; }
.dl-rows { overflow-y: auto; flex: 1 1 auto; }
.dl-row {
  display: block; width: 100%; text-align: left; cursor: pointer;
  border: 0; border-bottom: 1px solid var(--border); border-left: 3px solid transparent;
  background: none; color: inherit; font: inherit; padding: 8px 10px;
}
.dl-row:hover { background: var(--surface-2); }
.dl-row.on { background: var(--accent-soft); border-left-color: var(--accent); }
.dl-top { display: flex; gap: 8px; align-items: baseline; }
.dl-name { font-weight: 600; font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dl-amt { margin-left: auto; font-variant-numeric: tabular-nums; font-size: 12.5px; white-space: nowrap; }
.dl-sub { color: var(--muted); font-size: 11px; margin-top: 1px; }
.dl-status { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; margin-top: 3px; font-weight: 700; color: var(--muted); }
.dl-status.s-overdue { color: var(--bad-text); }
.dl-status.s-paid { color: var(--good-text); }
.dl-status.s-partial { color: var(--serious); }
.pane-reopen { margin-bottom: 8px; }
@media (max-width: 1100px) { .doc-list-pane { display: none; } }

/* The view fills the window. Capping it left a dead band down the right-hand
   side, which read worse than a wide document ever did. The sheet keeps its
   own page width inside, so the printed face still looks like a page. */
.doc-read .card { margin-bottom: 20px; }
/* Facts stay a tidy row rather than spreading themselves to the far edge. */
.doc-read .dd-facts { grid-template-columns: repeat(auto-fit, minmax(120px, max-content)); gap: 12px 28px; }
.doc-read .table-wrap > .tbl { min-width: 0; }

/* The record read as a record — the same facts, laid out for looking up
   rather than for a customer's letterbox. */
.dd-head { display: flex; gap: 30px; justify-content: space-between; align-items: flex-start; margin-bottom: 16px; }
.dd-title { font-size: 21px; font-weight: 700; letter-spacing: -.02em; text-transform: uppercase; }
.dd-status { display: inline-block; margin-top: 8px; padding: 3px 9px; border-radius: 3px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: #fff; background: var(--muted); }
.dd-status.ribbon-ok { background: var(--good); }
.dd-status.ribbon-warn { background: var(--warning); color: #3a2c00; }
.dd-status.ribbon-danger { background: var(--critical); }
.dd-status.ribbon-info { background: var(--viz-1); }
.dd-party { text-align: right; }
.dd-party h4 { margin: 0 0 3px; font-size: 10px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); }
.dd-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px 18px; margin: 4px 0 18px; }
.dd-facts > div { display: flex; flex-direction: column; }
.dd-facts span { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.dd-facts b { font-size: 13.5px; }
.dd-lines tbody tr:hover { background: transparent; }
.dd-totals { margin-left: auto; margin-top: 12px; }
.pdf-toggle { display: flex; justify-content: flex-end; padding: 4px 2px 8px; }

/* The document as it will print — scaled to the pane, never reflowed, so the
   preview cannot quietly disagree with the paper. */
.doc-preview-card { padding: 0; overflow: hidden; }
.doc-preview-wrap { background: var(--surface-2); padding: 18px; overflow-x: auto; }
.doc-sheet {
  position: relative; background: #fff; color: #1c2430;
  max-width: 820px; margin: 0 auto; padding: 34px 40px;
  border: 1px solid var(--border); border-radius: 2px; box-shadow: var(--shadow-lg);
  overflow: hidden;   /* clips the ribbon to the corner, as on paper */
}
.doc-ribbon {
  position: absolute; top: 14px; left: -34px; transform: rotate(-45deg);
  width: 140px; text-align: center; padding: 4px 0;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: #fff; background: var(--muted);
}
.doc-ribbon.ribbon-ok { background: var(--good); }
.doc-ribbon.ribbon-warn { background: var(--warning); color: #3a2c00; }
.doc-ribbon.ribbon-danger { background: var(--critical); }
.doc-ribbon.ribbon-info { background: var(--viz-1); }
/* The sheet is printed output, so it keeps print colours in either theme. */
.doc-sheet table { width: 100%; border-collapse: collapse; margin: 10px 0; }
.doc-sheet th, .doc-sheet td { padding: 7px 9px; text-align: left; border-bottom: 1px solid #e3e7ec; vertical-align: top; }
.doc-sheet th { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: #5a6673; background: #f6f8fa; border-bottom: 1.5px solid #d3d9e0; }
.doc-sheet .muted { color: #6b7684; }
.doc-sheet .doc-head { display: flex; justify-content: space-between; gap: 30px; margin-bottom: 26px; align-items: flex-start; }
.doc-sheet .doc-title { font-size: 30px; font-weight: 700; letter-spacing: -.02em; text-align: right; text-transform: uppercase; color: #111; }
.doc-sheet .doc-title-ar, .print-sheet .doc-title-ar { font-size: 20px; font-weight: 600; letter-spacing: 0; margin-top: 2px; }
.doc-sheet .co-name { font-size: 18px; font-weight: 700; margin-bottom: 3px; }
.doc-sheet .meta { margin-top: 10px; font-size: 12px; }
.doc-sheet .meta div { display: flex; justify-content: flex-end; gap: 14px; }
.doc-sheet .meta .k { color: #6b7684; }
.doc-sheet .addr-row { display: flex; gap: 44px; margin: 18px 0 20px; }
.doc-sheet .addr h4 { margin: 0 0 4px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em; color: #6b7684; font-weight: 600; }
.doc-sheet .totals { margin-left: auto; width: 290px; margin-top: 12px; }
.doc-sheet .totals td { padding: 5px 9px; border: none; }
.doc-sheet .totals tr.grand td { border-top: 2px solid #1c2430; font-weight: 700; font-size: 15px; padding-top: 9px; }
.doc-sheet .totals tr.due td { background: #f3f6f9; font-weight: 700; font-size: 15px; }
.doc-sheet .foot-note { margin-top: 34px; padding-top: 14px; border-top: 1px solid #e3e7ec; font-size: 11.5px; color: #5a6673; white-space: pre-wrap; }
.doc-sheet .logo { max-height: 66px; max-width: 230px; margin-bottom: 8px; }

/* ---------- gross margin on a sales document ---------- */
/* The headline number is the one a salesperson glances at mid-negotiation,
   so it carries the colour and everything else stays quiet. */
.margin-hero { font-size: 20px; font-weight: 650; font-variant-numeric: tabular-nums; }
.margin-hero.good { color: var(--good-text); }
.margin-hero.bad { color: var(--bad-text); }
.margin-card .stat-row { padding: 12px 12px 0; }
.table-wrap > .tbl.margin-tbl { min-width: 620px; }
/* A row of figures, not a row of cards — the header already carries the
   headline, so this just fills in the arithmetic behind it. */
.margin-strip { display: flex; flex-wrap: wrap; gap: 22px; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.mfig { display: flex; flex-direction: column; line-height: 1.25; }
.mfig i { font-style: normal; font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.mfig b { font-size: 14px; font-variant-numeric: tabular-nums; }
.margin-tbl .alt-col { color: var(--ink-2); background: var(--surface-2); }
/* A losing line gets a spine, not a shout — you should find it by scanning,
   without the table turning into a warning sign. */
.margin-tbl tr.verdict-loss td:first-child { box-shadow: inset 3px 0 0 var(--critical); }
.margin-tbl tr.verdict-thin td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.verdict-box { display: flex; flex-direction: column; gap: 8px; padding: 12px; }
.verdict-group { display: flex; gap: 9px; padding: 10px 12px; border-radius: var(--r); background: var(--surface-2); font-size: 12.5px; }
.verdict-group .icn { flex: none; margin-top: 1px; }
.verdict-group.loss { border-left: 3px solid var(--critical); }
.verdict-group.loss > .icn { color: var(--critical); }
.verdict-group.thin { border-left: 3px solid var(--warning); }
.verdict-group.thin > .icn { color: var(--serious); }
.verdict-group.good { border-left: 3px solid var(--good); }
.verdict-group.good > .icn { color: var(--good-text); }
.verdict-list { margin: 6px 0 0; padding-left: 16px; }
.verdict-list li { margin-bottom: 2px; }
.margin-tbl tbody tr:hover { background: transparent; }
.margin-tbl td { padding-top: 7px; padding-bottom: 7px; }

/* ---------- journal panel on a document ---------- */
/* The ledger is the source of truth, so it reads as a record rather than
   another editable surface: quieter head, monospaced figures, no hover. */
.jrnl-card .card-head h3 { font-weight: 600; }
/* Four short columns don't need the 840px the wide list tables ask for. */
.table-wrap > .tbl.jrnl-tbl { min-width: 460px; }
.jrnl-tbl tbody tr:hover { background: transparent; }
.jrnl-tbl td { padding-top: 7px; padding-bottom: 7px; }
.jrnl-tbl .num { font-variant-numeric: tabular-nums; }
.jrnl-tbl .total-row td { border-top: 2px solid var(--text); font-weight: 600; }
.modal .jrnl-card { border: 0; box-shadow: none; margin: 0; }
.modal .jrnl-card .card-head { padding-left: 0; padding-right: 0; }

/* An inactive record still earns its row, just not your attention. */
.row-off td { opacity: .58; }
.pm-tbl th.grp { border-left: 1px solid var(--border); border-bottom: 1px solid var(--border); font-size: 10.5px; letter-spacing: .04em; }
.pm-tbl td.side-off { font-style: italic; }
.pm-tbl tbody td:nth-child(2), .pm-tbl tbody td:nth-child(4),
.pm-tbl thead tr:last-child th:nth-child(1), .pm-tbl thead tr:last-child th:nth-child(3) { border-left: 1px solid var(--border); }

/* ---------- advances and credits ---------- */
.credits-banner { align-items: center; gap: 8px; }
.credits-banner .link-btn { margin-left: auto; white-space: nowrap; }
.apply-foot { display: flex; justify-content: space-between; gap: 12px; padding: 10px 2px 0; font-size: 12.5px; }

/* ---------- stock count sheet ---------- */
.sheet-bar { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.sheet-bar input[type="search"] { min-width: 230px; }
.tbl-count td { vertical-align: middle; }
.tbl-count .ln-count { width: 100%; text-align: right; font-variant-numeric: tabular-nums; }
.tbl-count .ln-note { width: 100%; }
/* A variance is the whole point of the sheet — give it a spine, not a shout. */
.tbl-count tr.has-var td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.ok-tick { color: var(--good-text); }

.warranty-hero { padding: 4px 0; }
.wh-status { display: flex; align-items: center; gap: 8px; font-size: 16px; margin-bottom: 10px; }
.wh-status .icn { width: 20px; height: 20px; }
.warranty-active .wh-status { color: var(--good-text); }
.warranty-expiring .wh-status { color: var(--serious); }
.warranty-expired .wh-status { color: var(--bad-text); }
.warranty-not-started .wh-status { color: var(--muted); }
.wh-dates { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.wh-dates > div { background: var(--surface-2); border-radius: var(--r-sm); padding: 8px 10px; }
.wh-dates span { display: block; font-size: 10.5px; color: var(--muted); }
.wh-dates b { font-size: 13.5px; }

/* ---------- settings ---------- */
.settings-body { max-width: 980px; }
.logo-row { display: flex; gap: 18px; align-items: flex-start; }
.logo-preview {
  width: 190px; height: 92px; border-radius: var(--r);
  border: 1px dashed var(--border-strong); background: var(--surface-2);
  display: grid; place-items: center; overflow: hidden; flex: none;
}
.logo-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
.storage-bar { height: 9px; border-radius: 5px; background: var(--surface-2); overflow: hidden; margin-bottom: 8px; }
.storage-fill { height: 100%; background: var(--accent); }
.count-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 9px; margin-top: 12px; }
.count-tile {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 11px; background: var(--surface-2); border-radius: var(--r-sm); font-size: 12.5px;
}
.count-tile b { font-size: 14px; }
.tmpl-preview { background: var(--surface-2); border-radius: var(--r); padding: 12px; }

/* ---------- global search ---------- */
.gs-input { font-size: 15px !important; padding: 11px 13px !important; }
.gs-results { margin-top: 12px; max-height: 46vh; overflow-y: auto; }
.gs-row {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 9px 11px; border: 0; background: none; border-radius: var(--r-sm);
  font: inherit; text-align: left; cursor: pointer; color: var(--ink);
}
.gs-row:hover { background: var(--surface-2); }
.gs-icn { color: var(--muted); display: flex; }
.gs-main { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.gs-main b { font-size: 13.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gs-main small { font-size: 11.5px; color: var(--muted); }
.gs-kind { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

/* ---------- welcome ---------- */
.welcome { display: grid; place-items: center; min-height: 78vh; padding: 24px 0; }
.welcome-card {
  max-width: 720px; width: 100%; text-align: center;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; padding: 30px 30px 26px;
}
.welcome-card h1 { font-size: 23px; margin-bottom: 6px; }
.lede { color: var(--ink-2); max-width: 500px; margin: 0 auto 20px; font-size: 13.5px; }
.welcome-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 22px; }
.wf {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 11px 8px; background: var(--surface-2); border-radius: var(--r);
}
.wf .icn { width: 17px; height: 17px; color: var(--accent); }
.wf b { font-size: 12px; }
.wf span { font-size: 11px; color: var(--muted); line-height: 1.3; }
.welcome-form { text-align: left; max-width: 620px; margin: 0 auto; }
.welcome-actions { display: flex; gap: 10px; flex-wrap: wrap; margin: 18px 0 14px; justify-content: center; }

/* ---------- loading ---------- */
.loading { display: flex; align-items: center; gap: 10px; padding: 30px; color: var(--muted); justify-content: center; }
.spin {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--grid); border-top-color: var(--accent);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- responsive ---------- */
@media (max-width: 1180px) {
  .stat-row-5 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dash-grid { grid-template-columns: 1fr; }
  .dash-grid > .span2 { grid-column: auto; }
  .doc-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 980px) {
  .stat-row-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .detail-grid { grid-template-columns: 1fr; }
  .detail-side .card { position: static; }
  .doc-bottom { grid-template-columns: 1fr; }
}
@media (max-width: 860px) {
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0;
    transform: translateX(-100%); transition: transform .2s;
    box-shadow: var(--shadow-lg);
  }
  body.nav-shown .sidebar { transform: none; }
  .nav-open, .sidebar .nav-close { display: inline-grid; }
  .sidebar .nav-pin { display: none; }   /* the pin is a desktop tool */
  .view { padding: 16px 14px 60px; }
  .topbar { padding: 10px 14px; }
  .stat-row-3, .stat-row-4, .stat-row-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-grid-2, .form-grid-3, .doc-grid { grid-template-columns: 1fr; }
  .span2 { grid-column: auto; }
  .quick-grid { grid-template-columns: repeat(2, 1fr); }
  .welcome-grid { grid-template-columns: repeat(2, 1fr); }
  .welcome-card { padding: 26px 20px; }
  .page-actions { width: 100%; }
  .global-search kbd { display: none; }
}
@media (max-width: 560px) {
  .stat-row-3, .stat-row-4, .stat-row-5 { grid-template-columns: 1fr; }
  .rec-head { gap: 14px; }
}

/* ---------- print ---------- */
@media print {
  .sidebar, .topbar, .page-actions, .toolbar, #toast-root { display: none !important; }
  .view { padding: 0; }
  .card, .report-surface { box-shadow: none; border: 0; }
  body { background: #fff; }
}

/* forced colors: keep marks distinguishable without colour */
@media (forced-colors: active) {
  .viz-bar, .viz-line, .pbar-fill { forced-color-adjust: none; }
  .btn, .card, .stat { border: 1px solid CanvasText; }
}

/* Numbers in books are typed, not nudged — spinner arrows only invite
   accidental one-cent changes, so every number field goes without them. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* Searchable dropdowns: the select stays the select — opening it shows the
   same plain list a native popup would, with one slim search row on top. */
.cmb-panel {
  position: fixed; z-index: 6000; background: var(--surface);
  border: 1px solid var(--border); border-radius: 6px; overflow: hidden;
  box-shadow: 0 6px 22px rgba(0,0,0,.16);
}
.cmb-q {
  width: 100%; box-sizing: border-box; padding: 5px 10px; font-size: 12.5px;
  border: 0; border-bottom: 1px solid var(--border); border-radius: 0;
  background: var(--surface); color: inherit; outline: none; font: inherit;
}
/* overscroll-behavior: reaching the end of the option list must not scroll
   the page underneath — the panel is pinned to where the field was. */
/* The height is a whole number of rows (12 x 24px), so the list never ends
   on a row sliced through the middle. The scrollbar is slim and its track is
   transparent, so a highlighted row reads as one band to the panel edge
   instead of stopping short against a strip of grey. */
.cmb-list {
  max-height: 288px; overflow: auto; overscroll-behavior: contain;
  scrollbar-width: none;
}
.cmb-list::-webkit-scrollbar { width: 0; height: 0; }
/* The scrollbar the panel draws for itself, floating over the rows rather
   than taking a lane out of them. */
.cmb-rail {
  position: absolute; right: 3px; width: 8px; display: none;
  border-radius: 99px; cursor: default;
}
/* Not --border-strong: that token is already translucent, and dimming it
   further left the thumb at an effective alpha of .10 — invisible. Mixed
   against the ink instead, so it holds up in both themes. */
.cmb-thumb {
  position: absolute; left: 0; width: 100%; border-radius: 99px;
  background: color-mix(in srgb, var(--ink) 26%, transparent);
}
.cmb-panel:hover .cmb-thumb, .cmb-rail:active .cmb-thumb {
  background: color-mix(in srgb, var(--ink) 45%, transparent);
}
/* Two columns: what the thing is called, and the quieter fact about it —
   an account's type, an item's category. The name takes the space and
   truncates; the meta keeps its own width so the column stays readable. */
/* The height is stated, not computed. Left to the content, a row carrying
   a second span at a smaller size grew a fraction of a pixel over its
   neighbours — enough that twelve of them no longer fitted the list exactly
   and the twelfth was left sliced through the middle at the bottom edge. */
.cmb-opt {
  display: flex; align-items: baseline; gap: 14px; cursor: pointer;
  height: 24px; box-sizing: border-box; padding: 0 15px 0 10px;
  font-size: 12.5px; line-height: 24px;
}
.cmb-txt { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmb-meta { flex: none; color: var(--muted); font-size: 11px; font-style: italic; white-space: nowrap; }
.cmb-opt:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
.cmb-opt.on { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.cmb-group { padding: 5px 15px 1px 10px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.cmb-none { padding: 6px 15px 6px 10px; color: var(--muted); font-size: 12.5px; }
.cmb-add {
  height: 24px; box-sizing: border-box; padding: 0 10px;
  border-bottom: 1px solid var(--border); color: var(--accent);
  cursor: pointer; font-weight: 500; font-size: 12.5px; line-height: 23px;
}
.cmb-add:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }

/* Section headers inside the bank match list */
.bm-sec td {
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); background: color-mix(in srgb, var(--accent) 5%, var(--surface));
  padding: 5px 10px !important; border-top: 1px solid var(--border);
}

/* Keyboard highlight inside searchable dropdowns */
.cmb-opt.hi { background: color-mix(in srgb, var(--accent) 22%, transparent); }

/* Every "create new" row in a dropdown wears the same face, whether it is
   the panel's own footer or an option the select brought with it. */
.cmb-opt.cmb-newopt { color: var(--accent); font-weight: 500; border-bottom: 1px solid var(--border); }

/* Native dropdown "create new" options match the panel styling */
option.opt-new { color: #1a73e8; font-weight: 600; }

/* POS full screen: the till is the whole window; the books wait behind one tap. */
/* The brand mark is the BLUE icon everywhere — light mode, dark mode,
   sidebar, sign-in, favicon: one navy face for the whole system. */
:root { --brand-field: #2B4A87; --brand-accent: #9db8ea; }

/* The front door (sign-in / onboarding) stands alone — no sidebar, no
   topbar, nothing to explore until there are books to show. */
body.bare .sidebar, body.bare .topbar { display: none !important; }
body.bare .view { padding: 8px !important; }

body.pos-fullscreen .sidebar, body.pos-fullscreen .topbar { display: none !important; }
body.pos-fullscreen .view { padding: 8px !important; }
/* The till is always its own screen: pos-only applies whenever the route is
   the POS, pos-register makes it device-permanent, pos-fullscreen adds the
   browser's own fullscreen. All three wear the same bare face. */
body.pos-register .sidebar, body.pos-register .topbar,
body.pos-only .sidebar, body.pos-only .topbar { display: none !important; }
body.pos-register .view, body.pos-only .view { padding: 8px !important; }
.pos-sell { height: calc(100vh - 120px); height: calc(100dvh - 120px); }
/* In bare till modes the .view is already the exact visible height (100dvh
   minus its own padding), so the sell screen just fills it — no vh math to
   disagree with iOS. */
body.pos-fullscreen .pos-sell, body.pos-register .pos-sell, body.pos-only .pos-sell {
  height: 100%; min-height: 0;
}
body.pos-fullscreen .main, body.pos-only .main { overflow: hidden; }
/* The till NEVER scrolls and owns every pixel: the window is the till's
   exact size — no body scroll, no books-page width cap. 100dvh (where
   supported) is the ACTUAL visible height — on iPads 100vh lies and the
   bottom row slid under the home-indicator area. The safe-area inset
   keeps the last buttons above the iOS swipe bar.
   The lock rides on pos-only/pos-fullscreen (the ROUTE is the till), not
   pos-register (the DEVICE is a till): a register visiting its satellite
   pages — item requests — must still be able to scroll a long list. */
body.pos-fullscreen, body.pos-only { overflow: hidden; }
body.pos-fullscreen .main, body.pos-only .main {
  height: 100vh; height: 100dvh;
}
body.pos-fullscreen .view, body.pos-only .view {
  max-width: none; min-height: 0; overflow: hidden;
  padding-bottom: max(8px, env(safe-area-inset-bottom)) !important;
}
/* Till home tiles: contents grow with the screen. Small screens keep the
   compact furniture; a tall till screen gets big touch targets. */
.pos-tile-badge { width: 44px; height: 44px; border-radius: 12px; display: flex; align-items: center; justify-content: center; flex: none; }
.pos-tile-icn { display: flex; transform: scale(1.4); }
.pos-tile-label { font-size: 14px; }
/* Only genuinely tall screens (desktop tills) get the big furniture —
   an iPad's 800-ish height needs the compact set to fit all rows. */
@media (min-height: 900px) {
  .pos-home-btn { gap: 10px !important; }
  .pos-tile-badge { width: 70px; height: 70px; border-radius: 16px; }
  .pos-tile-icn { transform: scale(2.1); }
  .pos-tile-label { font-size: 16px; }
  .pos-home-btn .small { font-size: 13px; }
}

/* ============================================================
   Dashboard style: CLARITY — white cards on a cool grey wash,
   one blue, a greeting and a KPI row up top. A per-user choice
   (Dashboard → Style); Classic remains exactly as it was.
   ============================================================ */
.dash-clarity {
  --cl-bg: #F6F7F9; --cl-card: #fff; --cl-line: #E4E7EB;
  --cl-ink: #20262E; --cl-mut: #79828E; --cl-blue: #2F6FB3;
  --cl-up: #1F8A54; --cl-dn: #C24747;
  background: var(--cl-bg);
}
:root[data-theme="dark"] .dash-clarity {
  --cl-bg: var(--bg); --cl-card: var(--surface); --cl-line: var(--border);
  --cl-ink: var(--ink); --cl-mut: var(--muted); --cl-blue: #6FA0D6;
  --cl-up: #4CC38A; --cl-dn: #E57878;
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .dash-clarity {
    --cl-bg: var(--bg); --cl-card: var(--surface); --cl-line: var(--border);
    --cl-ink: var(--ink); --cl-mut: var(--muted); --cl-blue: #6FA0D6;
    --cl-up: #4CC38A; --cl-dn: #E57878;
  }
}
.dash-clarity .page-title { font-size: 17px; font-weight: 650; letter-spacing: -0.01em; }
.dash-clarity, .dash-clarity .dash-grid { font-variant-numeric: tabular-nums; }
.dash-clarity .ckpis {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-bottom: 14px;
}
@media (max-width: 1180px) { .dash-clarity .ckpis { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px) { .dash-clarity .ckpis { grid-template-columns: repeat(2, 1fr); } }
.dash-clarity .ckpi {
  background: var(--cl-card); border: 1px solid var(--cl-line);
  border-radius: 10px; padding: 13px 15px; min-width: 0;
}
.dash-clarity .ckpi .l {
  font-size: 11px; color: var(--cl-mut);
  text-transform: uppercase; letter-spacing: 0.05em; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.dash-clarity .ckpi .v { font-size: 21px; font-weight: 650; margin-top: 3px; color: var(--cl-ink); }
.dash-clarity .ckpi .d { font-size: 11.5px; margin-top: 2px; color: var(--cl-mut); }
.dash-clarity .ckpi .up { color: var(--cl-up); }
.dash-clarity .ckpi .dn { color: var(--cl-dn); }
/* The widgets keep their bones; the skin quiets them to white cards. */
.dash-clarity .card {
  background: var(--cl-card); border: 1px solid var(--cl-line);
  border-radius: 10px; box-shadow: none;
}
.dash-clarity .card-head h3 { font-size: 13px; font-weight: 650; }
.dash-clarity .btn-primary { background: var(--cl-blue); border-color: var(--cl-blue); }

/* Gross-margin widget: donut beside the figures; stacks when narrow. */
.gm-flex { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.gm-donut { width: 96px; height: 96px; flex: none; }
.gm-flex .pnl-summary { flex: 1; min-width: 180px; }

/* Banking Overview: round icon badges + the uncategorized count. */
.bank-ov-icn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%; flex: none;
  background: var(--accent-soft); color: var(--accent);
}
.bank-ov-icn .icn { width: 17px; height: 17px; }
.bank-ov-icn.sm { width: 28px; height: 28px; margin-inline-end: 8px; vertical-align: middle; }
.bank-ov-icn.sm .icn { width: 13px; height: 13px; }
.bank-ov-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 38px; height: 38px; border-radius: 10px; padding: 0 8px;
  background: rgba(217, 119, 6, .14); color: #b45309;
  font-weight: 700; font-size: 15px; font-variant-numeric: tabular-nums;
}

/* Account workspace (the per-account screen) + its slide-in panel. */
.ws-head { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 4px 0 2px; }
.ws-name { font-size: 15.5px; font-weight: 650; color: var(--accent); }
.ws-x { color: #c5221f; }
.ws-amt {
  display: flex; gap: 10px; align-items: center;
  margin: 10px 0 0; padding: 6px 0 14px; border-bottom: 1px solid var(--border);
}
/* The workspace's three views are ONE segmented control, not a second set of
   tabs — the Banking page above already speaks the app's underline-tab
   language, and two tab dialects on one screen read as an accident. */
.ws-tabband {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  border-bottom: 1px solid var(--border); margin: 0 0 4px; padding: 10px 0 12px;
}
/* The band sits on the page ground, not on a card, so the SELECTED segment is
   the raised one — the track is the sunken part. */
.ws-seg {
  display: inline-flex; background: var(--surface-2);
  border: 1px solid var(--border-strong); border-radius: 9px; overflow: hidden;
}
.ws-tab {
  display: flex; gap: 6px; align-items: center;
  background: none; color: var(--ink-2);
  border: 0; border-right: 1px solid var(--border);
  font-size: 12.5px; font-weight: 620; padding: 7px 14px; cursor: pointer;
}
.ws-tab:last-child { border-right: 0; }
.ws-tab:not(.on):hover { color: var(--ink); }
.ws-tab.on { background: var(--surface); color: var(--ink); }
/* The count is work waiting, so it is red — and tinted rather than filled,
   because it rides two different grounds depending on which segment is on. */
.ws-tab .tab-count {
  background: color-mix(in srgb, var(--bad-text) 14%, transparent);
  color: var(--bad-text); font-weight: 700;
}
.ws-multi { display: flex; gap: 8px; align-items: center; }
/* Every filter row in the workspace is this one object, so two rows on two
   tabs cannot drift apart in spacing or wrapping. */
.ws-chiprow { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 12px 0 10px; }

/* A filter chip states which slice you are looking at; it is not a call to
   action, so the selected one is TINTED rather than filled — the same accent
   in the same strength the toasts and status badges use. */
.ws-chip {
  border: 1px solid var(--border); background: none; color: var(--ink-2);
  border-radius: 999px; padding: 4px 13px; font-size: 12px; font-weight: 600; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.ws-chip:hover { border-color: var(--border-strong); color: var(--ink); }
.ws-chip.on {
  background: color-mix(in srgb, var(--accent) 14%, var(--surface));
  border-color: color-mix(in srgb, var(--accent) 45%, var(--surface));
  color: var(--accent);
}
.ws-empty { text-align: center; color: var(--muted); padding: 46px 12px; font-size: 13px; }
.ws-recog {
  display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
  padding: 1px 6px; border-radius: 4px; background: rgba(22,163,74,.14); color: #15803d;
}
.ws-panel {
  position: fixed; top: 0; bottom: 0; inset-inline-end: 0; z-index: 460;
  width: min(560px, 94vw); background: var(--surface);
  border-inline-start: 1px solid var(--border-strong);
  box-shadow: -12px 0 34px rgba(10, 14, 20, .18);
  display: flex; flex-direction: column; overflow: hidden;
}
.ws-panel-tabs { display: flex; gap: 2px; align-items: center; padding: 10px 12px 0; }
.ws-ptab {
  background: none; border: 0; border-bottom: 2px solid transparent; cursor: pointer;
  font-size: 12px; font-weight: 700; letter-spacing: .04em; color: var(--muted); padding: 8px 10px;
}
.ws-ptab.on { color: var(--accent); border-bottom-color: var(--accent); }
.ws-panel-body { flex: 1; overflow-y: auto; padding-bottom: 12px; }
.ws-sec { padding: 12px 16px 6px; font-size: 13px; }
.ws-cand {
  display: flex; gap: 10px; align-items: center; padding: 9px 16px;
  border-bottom: 1px solid var(--grid); font-size: 13px;
}
/* The app's own recommendations, heading included, sit in one tinted block —
   tinted rather than filled, because they are still only suggestions. */
.ws-best {
  background: color-mix(in srgb, var(--good) 9%, transparent);
  border-bottom: 1px solid var(--grid);
}
.ws-best .ws-cand:last-child { border-bottom: 0; }
/* How many the app is recommending is the block's headline number, so it is
   marked in the same good colour instead of trailing the heading as loose text. */
.ws-count {
  display: inline-block; min-width: 22px; padding: 1px 7px; border-radius: 99px;
  background: color-mix(in srgb, var(--good) 22%, transparent); color: var(--good-text);
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; text-align: center;
}
/* Nothing found is not good news — that count stays neutral. */
.ws-count-0 { background: var(--surface-2); color: var(--muted); }
.ws-flt { padding: 8px 16px; border-bottom: 1px solid var(--grid); }
.ws-panel-foot {
  display: flex; gap: 8px; align-items: center; padding: 10px 16px;
  border-top: 1px solid var(--border); background: var(--surface);
}
.ws-cat { padding: 4px 16px; }
.ws-cat-grid { margin: 8px 0; }
.ws-cat-row {
  display: grid; grid-template-columns: 1fr 110px 28px; gap: 6px;
  align-items: center; padding: 5px 0;
}
.ws-cat-row .span2 { grid-column: 1 / -1; }

/* Locked money fields wear the same face as the locked number series:
   dark ground, dimmed, plainly not yours to type in. */
.locked-field, .locked-field:disabled {
  background: var(--surface-2) !important;
  color: var(--ink-2) !important;
  opacity: .75;
  cursor: not-allowed;
}

/* ---------- calculator ----------
   A floating window, above dialogs (you reach for it while one is open)
   but below toasts, so its own confirmations stay readable. */
.calc-panel {
  position: fixed; top: 68px; right: 18px; z-index: 250; width: 268px;
  /* On a short window the tape gives up its height first — the keys must
     never be pushed off the bottom of the screen. */
  max-height: calc(100vh - 88px);
  display: flex; flex-direction: column;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border-strong); border-radius: 16px;
  box-shadow: var(--shadow-lg); outline: none; overflow: hidden;
}
.calc-hidden { display: none; }
.calc-head {
  display: flex; align-items: center; gap: 6px; padding: 7px 8px 7px 11px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  font-size: 12.5px; font-weight: 650; cursor: move; user-select: none;
}
.calc-grip { display: flex; align-items: center; gap: 7px; }
.calc-grip .icn { width: 15px; height: 15px; }
/* The tape shares the panel's own ground; the screen below is the only
   card, so the eye lands on the number. */
.calc-tape { flex: 0 1 118px; min-height: 40px; overflow-y: auto; padding: 6px 0; }
.calc-empty { padding: 8px 12px; margin: 0; }
.calc-tl {
  display: flex; width: 100%; align-items: baseline; gap: 8px;
  padding: 2px 12px; border: 0; background: none; cursor: pointer;
  color: var(--ink-2); font: inherit; font-size: 12px;
}
.calc-tl:hover { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.calc-tl .num { flex: 1; text-align: right; font-variant-numeric: tabular-nums; }
.calc-tl em { width: 42px; font-style: normal; color: var(--muted); font-size: 11px; }
/* The total line is the answer, so it is ruled off like one on paper. */
.calc-tl.tot { color: var(--ink); font-weight: 700; border-top: 1px solid var(--line); margin-top: 2px; }
.calc-screen {
  padding: 8px 12px 10px; margin: 0 10px 2px;
  background: var(--surface-2); border-radius: 12px;
}
.calc-flags { display: flex; gap: 6px; min-height: 14px; }
.calc-flag { font-size: 10px; font-weight: 700; color: var(--accent); letter-spacing: .02em; }
.calc-disp {
  font-size: 24px; font-weight: 650; text-align: right;
  font-variant-numeric: tabular-nums; overflow-x: auto; white-space: nowrap;
}
.calc-disp.bad { font-size: 13px; color: var(--bad-text); }
/* Every key is its own tile with air around it — the keypad reads as keys
   rather than as a ruled grid. */
.calc-pad { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; padding: 6px 10px 10px; }
.calc-k {
  border: 0; border-radius: 10px; background: var(--surface-2); color: var(--ink);
  font: 650 14.5px inherit; padding: 11px 0; cursor: pointer;
}
.calc-k:hover { background: color-mix(in srgb, var(--accent) 12%, var(--surface-2)); }
.calc-k:active { background: color-mix(in srgb, var(--accent) 24%, var(--surface-2)); }
.calc-k.k-fn {
  font-size: 12px; font-weight: 620; color: var(--ink-2);
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
}
.calc-k.k-op { background: color-mix(in srgb, var(--accent) 13%, transparent); color: var(--accent); font-size: 16px; }
.calc-k.k-warn { background: color-mix(in srgb, var(--bad-text) 13%, transparent); color: var(--bad-text); }
.calc-k.k-eq { background: var(--accent); color: #fff; font-size: 16px; }
.calc-k.k-eq:hover { background: var(--accent); filter: brightness(1.08); }
.calc-k.k-void { background: none; cursor: default; }
.calc-foot { display: flex; align-items: center; gap: 8px; padding: 9px 10px; }

/* ---------- the Soft skin ----------
   An option, not a replacement: Settings leaves Classic in place and this
   whole block only applies when the sidebar's Style button says Soft. It is
   paint and nothing else — fill, border and radius. No element moves, no
   layout changes, so a page cannot lay out differently between the two.

   The one thing that needed care: today a GREY box means "you cannot type
   here" — a locked amount on a matched document, a read-only field. This skin
   fills every box grey, which would have taken that meaning away, so the
   locked states are given a mark of their own further down. */
:root[data-skin="soft"] { --r-sm: 8px; --r: 12px; --r-lg: 14px; }

:root[data-skin="soft"] .btn {
  background: var(--surface-2); border-color: transparent; border-radius: 9px;
}
:root[data-skin="soft"] .btn:hover { background: color-mix(in srgb, var(--accent) 12%, var(--surface-2)); }
/* THE PRIMARY BUTTON SITS IN THE PAGE RATHER THAN ON TOP OF IT. A solid
   accent among a row of quiet grey pills was the loudest thing on the screen
   — and the same button is on every toolbar in the app, so it shouted from
   all of them. At 82% the surface behind shows through just enough to settle
   it, and a border at 30% keeps an edge so it still reads as a button rather
   than a coloured patch. Hover comes FORWARD to 92% instead of brightening,
   which is the movement translucency asks for.

   The ink is the accent's own, not white: in dark mode the accent is a pale
   blue, and white on pale blue was barely legible even before it was
   softened. --accent-ink is white on the light theme and near-black on the
   dark one, so the label reads on both. */
:root[data-skin="soft"] .btn-primary {
  background: color-mix(in srgb, var(--accent) 82%, transparent);
  border-color: color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--accent-ink);
}
:root[data-skin="soft"] .btn-primary:hover {
  background: color-mix(in srgb, var(--accent) 92%, transparent);
  filter: none;
}
:root[data-skin="soft"] .btn-danger { background: var(--critical); border-color: var(--critical); color: #fff; }
:root[data-skin="soft"] .btn-warn { background: var(--warning); border-color: var(--warning); }
:root[data-skin="soft"] .btn-good { background: var(--good); border-color: var(--good); color: #fff; }
:root[data-skin="soft"] .btn:disabled { opacity: .55; }

/* Fill, edge and corner only — deliberately NOT padding. A skin selector
   outranks every component rule, so setting padding here quietly wiped the
   room the search box leaves for its magnifier and the money box leaves for
   its currency symbol, and the text slid underneath them. Spacing belongs to
   the component that knows what sits inside its own field. */
:root[data-skin="soft"] input[type=text], :root[data-skin="soft"] input[type=email],
:root[data-skin="soft"] input[type=number], :root[data-skin="soft"] input[type=date],
:root[data-skin="soft"] input[type=search], :root[data-skin="soft"] input[type=password],
:root[data-skin="soft"] input[type=url], :root[data-skin="soft"] select,
:root[data-skin="soft"] textarea {
  background: var(--surface-2); border-color: transparent; border-radius: 8px;
}
/* A document's line grid is a table pretending to be one: its fields are
   transparent and borderless on purpose, so the rows read as rows. Filling
   them would draw a box round every cell. */
:root[data-skin="soft"] .lines input, :root[data-skin="soft"] .lines select {
  background: transparent; border-color: transparent;
}
:root[data-skin="soft"] input[type=color] { background: none; }
/* The focus ring is an OUTLINE, not the border, so losing the border costs a
   keyboard user nothing — but say it here so nobody "tidies" it away. */
:root[data-skin="soft"] input:focus, :root[data-skin="soft"] select:focus,
:root[data-skin="soft"] textarea:focus { border-color: var(--accent); }

/* Grey no longer means "locked", so the locked states say it themselves: a
   dashed edge and the not-allowed cursor, both of which survive any fill. */
:root[data-skin="soft"] input[readonly],
:root[data-skin="soft"] .locked-field,
:root[data-skin="soft"] .locked-field:disabled,
:root[data-skin="soft"] input:disabled,
:root[data-skin="soft"] select:disabled,
:root[data-skin="soft"] textarea:disabled {
  background: color-mix(in srgb, var(--ink) 6%, var(--surface-2)) !important;
  border: 1px dashed var(--border-strong) !important;
  color: var(--ink-2) !important;
}
:root[data-skin="soft"] input[readonly] { cursor: not-allowed; }

:root[data-skin="soft"] .card {
  border-color: transparent;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 8px 24px rgba(15, 23, 42, .06);
}
:root[data-skin="soft"] .banner { border-radius: 12px; }

/* ---- bulk add expenses -------------------------------------------------
   A grid of one-line expenses. Every cell is a control, so the padding
   comes off the cell and goes on the control, and the row height is set
   by what is IN it rather than by table padding fighting input margins. */
.bulk-grid td { padding: 4px 6px; vertical-align: middle; }
.bulk-grid th { white-space: nowrap; }
.bulk-grid .bulk-in,
.bulk-grid select { width: 100%; min-width: 130px; }
.bulk-grid input[type="date"] { min-width: 140px; }
/* Money reads as one control: the currency and the figure sit together,
   laid out rather than left to overflow the cell they share. */
.bulk-money { white-space: nowrap; }
.bulk-money > * { vertical-align: middle; }
.bulk-money .bulk-cur { width: auto; min-width: 0; margin-right: 4px; }
.bulk-money .bulk-cur-fixed { color: var(--muted); margin-right: 6px; font-size: 12px; }
.bulk-grid .bulk-amt {
  width: calc(100% - 52px); min-width: 90px;
  text-align: right; font-variant-numeric: tabular-nums;
}
.bulk-tick, .bulk-drop { text-align: center; width: 44px; }
/* A row that cannot be saved is marked where it sits, with its reason on
   the line underneath — near enough to fix without hunting for it. */
.bulk-grid tr.bulk-bad > td { background: color-mix(in srgb, var(--bad-text) 7%, transparent); }
.bulk-grid tr.bulk-why > td { padding: 0 6px 6px 12px; border-top: 0; }
/* A cell this grid may not change: on screen, plainly, but not a control.
   Hiding it would mean a person could not see what they were leaving be. */
.bulk-held { display: inline-block; padding: 0 2px; font-size: 12.5px; cursor: help; }
.bulk-money .bulk-held { text-align: right; font-variant-numeric: tabular-nums; }
/* The ones a bulk update cannot reach, named inside its dialog. Scrolls
   rather than growing, so a selection of thirty cannot push the button
   off the bottom of the screen. */
.bu-nope {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line);
  max-height: 140px; overflow-y: auto; font-size: 12px;
}
.bu-nope > div { margin-bottom: 3px; }

/* ---------- attachments ----------
   The clip is a fact about a record, so it sits with the record's name and
   never asks for attention: muted until you look for it. */
.att-mark {
  display: inline-flex; align-items: center; gap: 3px;
  margin-inline-start: 6px; color: var(--muted);
  font-size: 11px; font-variant-numeric: tabular-nums; vertical-align: middle;
}
.att-mark .icn { width: 12px; height: 12px; }
.att-mark.att-head { font-size: 12px; }
.att-head .icn { width: 13px; height: 13px; }
/* A drop target nobody can see is not a target. The card lifts while a file
   is over it — the only moment this styling exists. */
[data-att-card] { transition: background .12s, box-shadow .12s; }
[data-att-card].att-over {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 2px var(--accent);
}
[data-att-card].att-over .att-drop { color: var(--accent); font-weight: 600; }

/* The receipt preview in Settings — a slip of paper on the page, so what the
   shop is configuring looks like the thing it will hold. Scrolls rather than
   stretching: a receipt with many lines must not push the form about. */
.rcpt-preview {
  background: #fff;
  color: #000;
  border: 1px solid var(--line, #d9dee5);
  border-radius: 4px;
  padding: 10px 6px;
  max-height: 460px;
  overflow: auto;
  display: flex;
  justify-content: center;
  box-shadow: 0 1px 3px rgba(0,0,0,.12);
}
/* The receipt carries its own print geometry in millimetres; on screen it just
   needs to sit still and be legible. */
.rcpt-preview .rcpt { width: auto !important; max-width: 100%; padding: 0 4px !important; }

/* HOME, on the sell screen — a target under the thumb rather than a word in a
   row of six. Leaving the sale is what a cashier does between customers, all
   day, so it gets the corner a hand is already near on a counter machine.

   Fixed to the viewport, not the cart: a long list of lines must not be able to
   scroll it away, and it is the one control that has to be reachable when the
   screen is full. */
.pos-home-fab {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 60;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 1px solid rgba(128,128,128,.28);
  background: var(--card, #131c2e);
  color: var(--accent, #4a86ff);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0,0,0,.35);
  transition: transform .12s ease, background .12s ease;
}
.pos-home-fab svg { width: 26px; height: 26px; }
.pos-home-fab:hover { background: var(--accent-soft, #1c2b4a); }
/* A press a finger can feel on glass, where there is no cursor to tell you the
   tap landed. */
.pos-home-fab:active { transform: scale(.93); }
.pos-home-fab:focus-visible { outline: 2px solid var(--accent, #4a86ff); outline-offset: 2px; }

/* Out of the way of the pay column on a narrow screen, where 56px in the corner
   would sit on top of the keypad. */
@media (max-width: 760px) {
  .pos-home-fab { width: 48px; height: 48px; right: 12px; bottom: 12px; }
  .pos-home-fab svg { width: 22px; height: 22px; }
}

/* NUMBER FIELDS DO NOT SPIN.

   Two reasons, and the second is the serious one.

   The stepper sits at the right edge of the field, which is exactly where a
   right-aligned amount ends — so on a narrow field it covers the number the
   person is trying to read. Seen on the return dialog, where the quantity
   became an icon.

   And a stepper is a control that changes money by being brushed against. In
   Chrome a focused number input also responds to the mouse WHEEL, so scrolling
   a long form with the cursor resting over an amount silently edits it. In a
   ledger that is not a quirk; it is a wrong figure nobody typed and no screen
   reports. The wheel is refused in ui.js for the same reason. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
