:root {
  --green: #2f8f8b;
  --green-dark: #1f6b68;
  --green-light: #e8f5f5;
  --ink: #1d2b2b;
  --muted: #6b7d7d;
  --line: #e2e8e7;
  --bg: #f4f7f6;
  /* The workspace canvas alone sits darker than the rest of the app: its white windows float ON it,
     so a softer backdrop stops a screen full of white panels from glaring. */
  --ws-bg: #b5bdbb;
  --card: #ffffff;
  /* Form controls. These were hardcoded white in every rule that styled them, so in dark mode the
     themed text colour landed on a white box and whatever you typed went invisible. Anything you
     type INTO belongs on --field-bg; a menu or panel you only read from belongs on --card. */
  --field-bg: #ffffff;
  --field-fg: #1d2b2b;
  --field-ph: #94a6a5;       /* placeholder text */
  /* Label colour for anything sitting ON a green fill. Dark mode lifts the green so it reads against
     a dark page, and that same lift leaves a white label on a green button at 2.4:1, under the 3:1
     floor. A light fill wants a dark label, so this flips while the fill stays bright. Hue-proof:
     the accent picker rotates hue only, so the fill keeps its lightness whatever colour is picked. */
  --on-green: #ffffff;
  /* Label for anything on a --green FILL. Distinct from --on-green, which is solved against
     --green-dark (the band): the fill is lighter, so the two do not always agree. */
  --on-accent: #081312;
  --tint-amber: #fdf3d7;   /* pale fills behind status pills */
  --tint-red: #fdeaea;
  --tint-gray: #eef1f0;
  --danger: #c0392b;
  --amber: #b8860b;
  --radius: 10px;
  --shadow: 0 1px 3px rgba(0,0,0,.06), 0 4px 16px rgba(0,0,0,.04);
  --title-bar: #dfe9e7;      /* workspace window title bar */
  --th-bg: #f7fafa;          /* table headers and list headers */
  --green-line: #bfe3e0;     /* the hairline on green-tinted pills */
  --toast-bg: #1d2b2b;
  --toast-fg: #ffffff;
  color-scheme: light;
}

/* Dark theme. Same variables, different values, so everything already written as var(--x)
   follows without being touched. The green is lifted from #2f8f8b to #4bbdb8: the brand green
   is tuned for white behind it and goes muddy on a dark surface, failing contrast on exactly
   the things that matter most (buttons, active nav, totals).
   Set on <html> by the inline script in index.html so it applies before first paint. */
:root[data-theme="dark"] {
  --green: #4bbdb8;
  --green-dark: #3aa09d;
  --green-light: #162828;
  --ink: #e6efee;
  --muted: #93a8a8;
  --line: #2a393a;
  --bg: #121818;
  --ws-bg: #0d1112;
  --card: #1a2222;
  /* A touch under --card so a field still reads as a well you type into, but lifted off pure black
     (was #0f1516, which read as harsh black boxes on the darker forms). */
  --field-bg: #232e2d;
  --field-fg: #e6efee;
  --field-ph: #7d9091;
  --on-green: #081312;
  --on-accent: #081312;
  --tint-amber: #3a2f14;
  --tint-red: #3d1f1c;
  --tint-gray: #232c2c;
  --danger: #ef8479;
  --amber: #e8c37a;
  --shadow: 0 1px 3px rgba(0,0,0,.5), 0 4px 16px rgba(0,0,0,.35);
  --title-bar: #202b2b;
  --th-bg: #161c1d;
  --green-line: #2c4c4a;
  --toast-bg: #2c3a3b;
  --toast-fg: #e6efee;
  color-scheme: dark;
}
* { box-sizing: border-box; }
/* The browser's own [hidden] rule is display:none at the LOWEST specificity, so any of the 200+
   class rules in here that set display (".rs-drop { display: flex }", ".settings-item { display:
   flex }" ...) silently beats it, and an element given the hidden attribute stays on screen.
   That has now produced two separate bugs - a dead settings card, and a file chooser shown on a
   screen that had already fetched the file. One rule ends the class of bug; !important is
   deliberate, because outranking every class rule is exactly the point. */
[hidden] { display: none !important; }
html, body { margin: 0; height: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink); background: var(--bg); font-size: 14px;
}
.hidden { display: none !important; }
button { font-family: inherit; cursor: pointer; }

/* Every text control gets a themed background by default, so a control that is added later, or that
   never had a rule of its own, cannot go invisible in dark mode. Plain element selectors on purpose:
   any class rule outranks these, so the specific styling below still wins.
   Checkbox, radio, range and colour are left alone - the browser paints those itself and a
   background flattens them into grey squares. */
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),
textarea, select {
  background: var(--field-bg); color: var(--field-fg);
}
input::placeholder, textarea::placeholder { color: var(--field-ph); }

/* ---------- Login ---------- */
.login-wrap {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--green) 0%, var(--green-dark) 100%);
}
.login-card {
  background: var(--card); padding: 36px 34px; border-radius: 16px; width: 340px;
  box-shadow: 0 20px 60px rgba(0,0,0,.25); display: flex; flex-direction: column;
}
.login-card .brand { text-align: center; margin-bottom: 18px; }
.login-card .leaf { font-size: 40px; }
.login-card h1 { font-size: 20px; margin: 8px 0 2px; }
.login-card .brand p { margin: 0; color: var(--muted); font-size: 13px; }
.login-card label { font-size: 12px; color: var(--muted); margin: 12px 0 4px; font-weight: 600; }
.login-card input {
  padding: 11px 12px; border: 1px solid var(--line); border-radius: 8px; font-size: 14px;
}
.login-card input:focus { outline: 2px solid var(--green); border-color: var(--green); }
.login-card button {
  margin-top: 20px; background: var(--green); color: var(--on-green); border: 0; padding: 12px;
  border-radius: 8px; font-size: 15px; font-weight: 600;
}
.login-card button:hover { background: var(--green-dark); }
/* text-style links inside the login card (Forgot password / Back to sign in) */
.login-card button.link-btn {
  margin-top: 10px; background: none; color: var(--green); padding: 4px;
  font-size: 13px; font-weight: 600; text-decoration: underline; width: auto;
}
.login-card button.link-btn:hover { background: none; color: var(--green-dark); }
.error { color: var(--danger); font-size: 13px; margin-top: 12px; text-align: center; min-height: 16px; }

/* ---------- Shell ---------- */
#app { display: flex; min-height: 100vh; }
.sidebar {
  width: 230px; background: color-mix(in srgb, var(--green) 18%, #0d1112); color: #cfe0de;
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
}
.side-brand {
  display: flex; align-items: center; gap: 10px; padding: 20px 18px; font-weight: 700;
  font-size: 16px; line-height: 1.1; border-bottom: 1px solid rgba(255,255,255,.08);
}
.side-brand small { color: #8fb7b4; font-weight: 500; }
.side-brand .leaf { font-size: 24px; }
/* The company you are working in, under the wordmark. Settings, books and WhatsApp credentials
   are all per company, so having it permanently on screen stops you editing the wrong one. */
.side-brand-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.side-brand-name { font-size: 16px; font-weight: 700; line-height: 1.15; }
.side-co {
  font-size: 11.5px; font-weight: 600; color: #8fb7b4; line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* min-height:0 lets this flex child actually shrink and scroll instead of pushing
   the Subscription link + footer off the bottom when the menu (e.g. many email
   accounts) grows taller than the screen. */
#nav { flex: 1; min-height: 0; overflow-y: auto; padding: 10px 0; }
/* slim, unobtrusive scrollbar on the dark sidebar */
#nav::-webkit-scrollbar { width: 7px; }
#nav::-webkit-scrollbar-thumb { background: rgba(255,255,255,.14); border-radius: 4px; }
#nav::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.24); }
#nav a {
  display: flex; align-items: center; gap: 11px; padding: 11px 20px; color: #b9cdcb;
  text-decoration: none; font-size: 14px; font-weight: 500; border-left: 3px solid transparent;
}
#nav a:hover { background: rgba(255,255,255,.05); color: #fff; }
#nav a.active { background: color-mix(in srgb, var(--green) 22%, transparent); color: #fff; border-left-color: var(--green); }
#nav a .ic { width: 20px; text-align: center; font-size: 16px; }
/* Follows the accent rather than WhatsApp's own green: the badge counts messages from any
   messenger, and a fixed #25d3bd on a violet or indigo sidebar looked like a stray. --on-green is
   the label colour measured against the accent, so the count stays readable on every one. */
.nav-badge {
  margin-left: auto; margin-right: 2px; background: var(--green); color: var(--on-accent);
  border-radius: 12px; min-width: 24px; height: 22px; padding: 0 9px;
  font-size: 11.5px; font-weight: 700; display: inline-flex;
  align-items: center; justify-content: center;
  animation: navBadgePulse 1.7s ease-out infinite;
}
.nav-badge.upd { background: var(--amber, #b8860b); }
/* The Messenger "New Message" badge is text (not a number) - smaller + more compact. */
#wa-nav-badge { font-size: 9px; height: 18px; padding: 0 7px; letter-spacing: .2px; }
/* Wave only, no scale. A count that grows and shrinks is harder to read at a glance than one
   that holds still, and the ring on its own already carries the "something arrived" signal. */
@keyframes navBadgePulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}
/* respect users who prefer no motion */
@media (prefers-reduced-motion: reduce) { .nav-badge { animation: none; } }
.wa-upd {
  padding: 14px 16px; border-radius: 12px;
  background: var(--card); border: 1px solid var(--line); box-shadow: var(--shadow);
  font-size: 13px; color: var(--muted);
}
.wa-upd-title {
  font-size: 12.5px; letter-spacing: .01em;
  color: var(--muted); font-weight: 700; margin-bottom: 8px;
}
.wa-upd-row { display: flex; justify-content: space-between; gap: 8px; margin: 3px 0; }
.wa-upd-row span { color: var(--muted); }
.wa-upd-row b { color: var(--ink); font-weight: 650; text-align: right; }
.wa-upd-flag { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); font-weight: 600; }
.wa-upd-flag.ok { color: var(--green); }
.wa-upd-flag.has { color: var(--amber); }
.wa-upd-flag small { display: block; font-weight: 400; color: var(--muted); margin-top: 2px; }
/* clickable variant (an update is available) */
button.wa-upd-flag {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  border-top: 1px solid var(--line); border-radius: 0; cursor: pointer;
  font: inherit; font-size: 13px; line-height: 1.35; padding: 10px 0 0; color: var(--amber);
}
button.wa-upd-flag.has:hover { color: var(--green-dark); }
button.wa-upd-flag.has:hover small { color: var(--muted); }
.wa-upd-check {
  display: block; width: 100%; margin-top: 10px; background: none; border: 0;
  color: var(--green); cursor: pointer; font: inherit; font-size: 12px;
  text-decoration: underline; text-align: left; padding: 0;
}
.wa-upd-check:hover { color: var(--green-dark); }
/* Settings two-column layout: cards on the left, update panel on the right. */
.settings-layout { display: flex; gap: 26px; align-items: flex-start; flex-wrap: wrap; }
.settings-side { width: 420px; flex-shrink: 0; display: flex; flex-direction: column; gap: 14px; }
/* Raised from 1180: the wider side needs more room beside the 560px list before it has to wrap
   under it, or the two columns get cramped at mid widths. */
@media (max-width: 1260px){ .settings-side { width: 100%; max-width: 560px; } }
/* busy dialog */
.wa-upd-modal { text-align: center; padding: 6px 4px 2px; }
.wa-upd-spin {
  width: 34px; height: 34px; margin: 4px auto 14px; border-radius: 50%;
  border: 3px solid #e3ecec; border-top-color: var(--green);
  animation: waUpdSpin .9s linear infinite;
}
@keyframes waUpdSpin { to { transform: rotate(360deg); } }
.wa-upd-modal #wa-upd-msg { font-weight: 600; margin: 0 0 8px; }
.wa-upd-modal #wa-upd-msg.err { color: var(--danger); }
.wa-upd-modal .wa-upd-note { font-size: 12.5px; color: #6b7a7a; margin: 0; }
@media (prefers-reduced-motion: reduce) { .wa-upd-spin { animation: none; } }
/* Drag handle on the sidebar's right edge - grab and drag left/right to resize.
   The sidebar is position:sticky (a positioning context), so this pins to its edge. */
.side-resize {
  position: absolute; top: 0; right: -3px; width: 6px; height: 100%;
  cursor: col-resize; z-index: 30; touch-action: none;
}
.side-resize::after {                 /* thin line that lights up on hover/drag */
  content: ""; position: absolute; top: 0; right: 3px; width: 2px; height: 100%;
  background: transparent; transition: background .15s;
}
.side-resize:hover::after, .side-resize.dragging::after { background: var(--green); }
.sidebar.collapsed .side-resize { display: none; }   /* no resizing while collapsed to icons */

.side-foot { padding: 16px 20px; border-top: 1px solid rgba(255,255,255,.08); font-size: 13px; }
/* "Administrator" and the build number share a line; the row owns the spacing now. */
.side-foot-who { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.side-foot #whoami { color: #8fb7b4; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-btn { background: none; border: 0; color: #cfe0de; padding: 0; text-decoration: underline; font-size: 13px; }
/* The sidebar is dark in BOTH themes, so this row keeps its own light-on-dark colours. */
.side-foot-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.accent-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; }
.accent-sw { height: 58px; border-radius: 10px; border: 2px solid transparent; cursor: pointer;
  display: flex; align-items: flex-end; justify-content: center; padding: 6px; position: relative;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }
.accent-sw span { font-size: 11.5px; font-weight: 700; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.4); }
.accent-sw.on { border-color: var(--ink); }
.accent-sw.on:after { content: "\2713"; position: absolute; top: 6px; right: 8px; color: #fff;
  font-size: 14px; font-weight: 700; text-shadow: 0 1px 2px rgba(0,0,0,.4); }
.theme-toggle { flex: none; width: 46px; height: 26px; border-radius: 999px; cursor: pointer;
  background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.18); position: relative;
  padding: 0; transition: background .16s; }
.theme-toggle:hover { background: rgba(255,255,255,.22); }
.theme-toggle:before { content: "\2600"; position: absolute; top: 1px; left: 1px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--card); color: #b8860b; font-size: 13px; line-height: 22px;
  text-align: center; transition: transform .16s; }
:root[data-theme="dark"] .theme-toggle { background: rgba(75,189,184,.28); border-color: rgba(75,189,184,.4); }
:root[data-theme="dark"] .theme-toggle:before { content: "\1F319"; transform: translateX(20px);
  background: #0d1112; color: #e8c37a; }

main { flex: 1; min-width: 0; padding: 26px 32px; }  /* full window width; zoom out (Ctrl+-) to fit more */

/* ---------- Finance home (QuickBooks-style workflow canvas) ---------- */
/* Wrap rather than crush. These are three fixed-ish columns inside a window the user resizes, so
   the viewport media queries below cannot see it getting narrow - a 968px window inside a 1440px
   screen still counts as "desktop". Without a floor on the tile column, widening the balances
   column squeezed it to 239px and the paired tiles (Quotations / Sales Orders) silently stacked. */
.fin-wrap { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.fin-main { flex: 1; display: flex; flex-direction: column; gap: 22px; min-width: 300px; }
.fin-side { width: 300px; display: flex; flex-direction: column; gap: 22px; }
.fin-sec { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 22px 20px 14px; position: relative; }
.fin-chip { position: absolute; top: -10px; left: 16px; background: var(--green-light); color: var(--green-dark);
  font-size: 10.5px; font-weight: 800; letter-spacing: 1px; padding: 3px 12px; border-radius: 10px; border: 1px solid var(--line); }
.fin-row { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin: 6px 0; }
.fin-col { display: flex; flex-direction: column; align-items: stretch; gap: 4px; }
.fin-col .fin-item { flex-direction: row; justify-content: flex-start; min-width: 0; padding: 10px 12px; }
.fin-item { display: flex; flex-direction: column; align-items: center; gap: 8px; background: none;
  border: 1px solid transparent; border-radius: 10px; padding: 12px 14px; min-width: 104px;
  cursor: pointer; font-size: 12.5px; font-weight: 600; color: var(--ink); position: relative; }
.fin-item:hover { background: var(--bg); border-color: var(--line); }
.fin-ic { display: inline-flex; }
.fin-ic svg { width: 38px; height: 38px; }
.fin-col .fin-ic svg { width: 28px; height: 28px; }
.fin-soon { position: absolute; top: 5px; right: 6px; font-size: 8.5px; font-weight: 800; letter-spacing: .5px;
  color: #b8860b; background: #fdf6e3; border: 1px solid #ecd9a0; padding: 1px 5px; border-radius: 8px; }
.fin-col .fin-soon { position: static; order: 2; margin-left: auto; }
/* Count pill on a workspace tile (open bills waiting to be paid). Amber: something is waiting,
   nothing is wrong. Hidden at zero rather than showing a 0. */
/* Dark ink, not white: --amber is a deep gold in light mode but a pale one in dark, and white
   text vanishes on the pale version. Dark ink reads on both. */
/* Waves like the other counts. The drop shadow has to be repeated in every keyframe: box-shadow is
   one property, so animating the ring would otherwise drop the shadow the pill sits on. */
.fin-count { position: absolute; top: 5px; right: 6px; min-width: 19px; height: 19px; padding: 0 6px;
  border-radius: 10px; background: var(--amber); color: #2b1f04; font-size: 10.5px; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center; line-height: 1;
  box-shadow: 0 1px 3px rgba(0,0,0,.22);
  animation: finCountWave 1.9s ease-out infinite; }
@keyframes finCountWave {
  0%   { box-shadow: 0 1px 3px rgba(0,0,0,.22), 0 0 0 0 color-mix(in srgb, var(--amber) 62%, transparent); }
  70%  { box-shadow: 0 1px 3px rgba(0,0,0,.22), 0 0 0 10px color-mix(in srgb, var(--amber) 0%, transparent); }
  100% { box-shadow: 0 1px 3px rgba(0,0,0,.22), 0 0 0 0 color-mix(in srgb, var(--amber) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .fin-count { animation: none; } }
.fin-count[hidden] { display: none; }
.fin-col .fin-count { position: static; order: 2; margin-left: auto; }
.fin-arrow { color: #b9c6c4; flex: 0 0 auto; }
/* The CUSTOMERS flow: a fixed two-column grid so every stem lands on its tile's centre line
   whatever the labels weigh. Columns are 140px with no gap, so the centres sit at 70 and 210;
   the merge SVG (178 wide, stems at 9 and 169) centred in the 280px span hits both exactly,
   and Create Invoice's 70px offset puts its centre on the merge stem. Change the column
   width and those three numbers move together - keep --ffw and the SVG in step. */
.fin-flow { --ffw: 140px;
  display: grid; grid-template-columns: var(--ffw) var(--ffw) max-content; row-gap: 2px;
  justify-content: start; margin: 6px 0; }
.fin-flow .ffc { display: flex; align-items: center; justify-content: center; }
.fin-flow .fin-item { width: var(--ffw); min-width: 0; flex: none; }
/* The picker that narrows the list to one customer. */
.inv-cust { max-width: 220px; font: inherit; font-size: 12.5px; padding: 5px 8px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--field-bg); color: var(--field-fg); cursor: pointer; }
/* Account balances on the home screen, the way QuickBooks shows them: the money accounts
   at a glance, each row opening the register behind it. */
/* Wide enough that a long account name and a seven-figure balance are not fighting each other
   for the same line, and that a group heading like OTHER CURRENT LIABILITY fits on one. */
.fin-mid { width: 340px; display: flex; flex-direction: column; gap: 22px; }
.fin-bal { padding-bottom: 8px; }
.fin-bal-list { display: flex; flex-direction: column; max-height: 460px; overflow-y: auto; margin: 2px -6px 0; }
.fin-bal-wait { color: var(--muted); font-size: 12.5px; padding: 8px 6px; }
/* Same colour as the ACCOUNT BALANCES chip above them: these are headings of the same kind,
   one level down, so they should read as the same voice rather than as greyed-out noise. */
.fin-bal-grp { font-size: 12px; font-weight: 800; letter-spacing: .9px; color: var(--green-dark);
  text-transform: uppercase; padding: 10px 6px 3px; }
.fin-bal-row { display: flex; align-items: baseline; gap: 10px; width: 100%; background: none;
  border: 1px solid transparent; border-radius: 8px; padding: 6px 6px; cursor: pointer; text-align: left; }
.fin-bal-row:hover { background: var(--bg); border-color: var(--line); }
.fin-bal-nm { flex: 1; font-size: 12.5px; font-weight: 600; color: var(--ink); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.fin-bal-amt { font-size: 12.5px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink); }
.fin-bal-amt.neg { color: var(--danger); }
@media (max-width: 1180px) { .fin-mid { width: 290px; } }
@media (max-width: 900px) { .fin-wrap { flex-direction: column; } .fin-side { width: 100%; }
  .fin-mid { width: 100%; } .fin-bal-list { max-height: none; } }

/* ---------- Finance workspace: desktop with draggable child windows ---------- */
.ws { position: relative; margin: -26px -32px; height: 100vh; overflow: hidden; background: var(--ws-bg); }
.ws-win { position: absolute; display: flex; flex-direction: column; background: var(--card);
  border: 1px solid var(--line); border-radius: 0; overflow: hidden;
  box-shadow: 0 14px 44px rgba(0,0,0,.20); min-width: 340px; min-height: 220px; }
.ws-title { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 8px 8px 14px; background: var(--title-bar); border-bottom: 1px solid var(--line);
  cursor: move; user-select: none; font-weight: 700; font-size: 13.5px; color: var(--ink); }
/* Window controls: the glyph itself carries the colour - minimise yellow, maximise green, close
   red - and hovering lays a soft tint of that same colour behind it. */
.ws-ctl { display: flex; gap: 3px; align-items: center; }
.ws-ctl button { background: none; border: 0; cursor: pointer; line-height: 1; flex: none;
  width: 34px; height: 28px; border-radius: 7px; color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .13s ease; }
.ws-ctl button svg { display: block; width: 18px; height: 18px; }
.ws-ctl button[data-w="min"] { color: #f0a72a; }
.ws-ctl button[data-w="max"] { color: #23b794; }
.ws-ctl button[data-w="close"], .ws-ctl .x { color: #f0574f; }
.ws-ctl button[data-w="min"]:hover  { background: color-mix(in srgb, #f0a72a 22%, transparent); }
.ws-ctl button[data-w="max"]:hover  { background: color-mix(in srgb, #23b794 22%, transparent); }
.ws-ctl button[data-w="close"]:hover, .ws-ctl .x:hover { background: color-mix(in srgb, #f0574f 24%, transparent); }
.ws-ctl button:active { background: color-mix(in srgb, var(--ink) 16%, transparent); }
.ws-body { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
.ws-grip { position: absolute; right: 1px; bottom: 1px; width: 18px; height: 18px; z-index: 6;
  cursor: nwse-resize; opacity: .5; border-bottom-right-radius: 9px;
  background: linear-gradient(135deg, transparent 0 55%, #93a7a5 55% 61%, transparent 61% 70%,
    #93a7a5 70% 76%, transparent 76% 85%, #93a7a5 85% 91%, transparent 91%); }
.ws-grip:hover { opacity: 1; }
/* Drag any of the four sides to resize a window. The side strips stop short of the title bar so
   dragging the header still MOVES the window; the top strip is the thin band above it. */
.ws-edge { position: absolute; z-index: 6; }
.ws-edge-l, .ws-edge-r { top: 42px; bottom: 30px; width: 7px; cursor: ew-resize; }
.ws-edge-l { left: 0; } .ws-edge-r { right: 0; }
.ws-edge-t, .ws-edge-b { left: 9px; right: 9px; height: 7px; cursor: ns-resize; }
.ws-edge-t { top: 0; } .ws-edge-b { bottom: 0; }
/* invoice sheets: the SIDE strips also stay clear of the green band (top) and the footer buttons */
.ws-win:has(.qb-sheet) > .ws-edge-l, .ws-win:has(.qb-sheet) > .ws-edge-r,
.qb-sheet.qb-float > .ws-edge-l, .qb-sheet.qb-float > .ws-edge-r { top: 118px; bottom: 68px; }
.ws-edge:hover { background: color-mix(in srgb, var(--green) 16%, transparent); }
.ws-home { padding: 18px; }
/* Email-invoice dialog: a movable/resizable window with the form + a live invoice
   preview side by side (QuickBooks-style). Sized by makeDialogWindow (inline px). */
.email-inv-dlg .modal-body { overflow: hidden; }        /* the panes scroll, not the whole body */
.email-inv-cols { display: flex; gap: 20px; align-items: stretch; height: 100%; }
.email-inv-form { flex: 0 0 44%; min-width: 0; overflow: auto; display: flex; flex-direction: column; }
/* the Message field grows to fill the tall left pane so there's plenty of room to type */
.email-inv-msg { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.email-inv-dlg .email-inv-msg textarea { flex: 1; min-height: 220px; resize: vertical; }
.em-ccbcc-toggle { font-size: 11.5px; font-weight: 600; margin-left: 8px; color: var(--green-dark); }
.em-ccbcc-toggle.on { text-decoration: underline; }
.email-inv-preview { flex: 1; min-width: 0; display: flex; flex-direction: column;
  background: #eef1f0; border: 1px solid var(--line); border-radius: 10px; padding: 12px; }
.email-inv-preview-label { font-size: 10.5px; font-weight: 800; letter-spacing: .8px; color: var(--muted); margin-bottom: 10px; }
.email-inv-preview-page { flex: 1; overflow: auto; min-height: 0; }
/* Render the real invoice sheet, scaled to fit the pane (transform doesn't shrink the
   layout box, so the wrapper is widened by 1/scale to compensate). */
.email-inv-preview-page .inv-sheet { transform: scale(.72); transform-origin: top left; width: 138.9%;
  flex: none; min-height: 0; box-shadow: 0 2px 10px rgba(0,0,0,.12); padding: 30px 34px; margin-bottom: -28%; }
.email-inv-preview-page .table-wrap { overflow: visible; }   /* show every column in the preview */
@media (max-width: 780px) {
  .email-inv-cols { flex-direction: column; height: auto; }
  .email-inv-form { flex: none; }
  .email-inv-preview-page .inv-sheet { transform: scale(.9); width: 111%; margin-bottom: -10%; }
}

/* Dynamic pricing - FIFO batches (inside the item edit window) */
.med-dyn { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.med-dyn-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.med-dyn-head b { font-size: 13px; }
/* ---- Item pictures: one main, two more ------------------------------------------------- */
/* Always three across - there are exactly three slots, and they are meant to be read as a set.
   minmax(0,1fr) rather than auto-fit: auto-fit adds a fourth and fifth empty track once the
   window is wide, leaving three small tiles stranded against a gap. The tiles shrink instead,
   and the buttons under them wrap on their own when it gets genuinely tight. */
.pic-slots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; max-width: 520px; }
.pic-slot { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.pic-frame { position: relative; aspect-ratio: 1; border: 1px dashed var(--line); border-radius: 10px;
  background: var(--field-bg); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.pic-slot.has .pic-frame { border-style: solid; }
/* The main picture is the one that represents the item, so it says so without a label. */
.pic-slot.primary.has .pic-frame { border-color: var(--green); box-shadow: 0 0 0 2px color-mix(in srgb, var(--green) 22%, transparent); }
.pic-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pic-empty { color: var(--muted); font-size: 20px; text-align: center; line-height: 1.35; }
.pic-empty small { font-size: 11px; }
.pic-acts { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.pic-acts .btn.sm { padding: 2px 8px; font-size: 11.5px; }
.pic-size { font-size: 11px; }
.dyn-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.dyn-table th { text-align: left; color: var(--muted); font-size: 10px; font-weight: 800; letter-spacing: .5px; padding: 4px 8px; border-bottom: 1px solid var(--line); }
.dyn-table td { padding: 5px 8px; border-bottom: 1px solid var(--line); }
.dyn-table .right { text-align: right; }
.dyn-table tr.dyn-active { background: var(--green-light); }
.dyn-table .btn.sm { padding: 2px 8px; }

/* Reports (QuickBooks-style Report Center) */
.rep-center { padding: 18px; display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; align-items: start; }
.rep-cat { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; box-shadow: var(--shadow); }
.rep-card { display: block; width: 100%; text-align: left; background: none; border: 0; border-top: 1px solid var(--line); padding: 10px 6px; cursor: pointer; }
.rep-cat .rep-card:first-of-type { border-top: 0; }
.rep-card b { display: block; font-size: 13.5px; color: var(--ink); }
.rep-card span { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.rep-card:hover b { color: var(--green-dark); }
.rep-body { padding: 0 0 12px; }
.rep-select, .rep-date { padding: 7px 10px; border: 1px solid var(--line); border-radius: 8px; font-size: 13px; background: var(--field-bg); }
tr.rep-total td { font-weight: 700; border-top: 2px solid var(--ink); background: var(--card); }
tr.rep-grand td { font-size: 15px; }
tr.rep-sec td { font-weight: 700; background: var(--th-bg); }
.rep-ind td:first-child { padding-left: 34px; }
.rep-neg { color: #b3261e; }
/* Profit and Loss. Rows arrive from the server already indented, so these only carry weight and
   the hairline above a group subtotal. rep-total keeps its heavy rule for the section totals. */
tr.pl-hdr td { font-weight: 700; }
tr.pl-grp td { font-weight: 600; }
tr.pl-sub td { font-weight: 600; }
tr.pl-sub td + td { border-top: 1px solid var(--line); }

/* Chart of Accounts */
.coa-sec td { background: var(--th-bg); color: var(--muted); font-size: 10.5px; font-weight: 800; letter-spacing: .9px; padding: 6px 16px; border-bottom: 1px solid var(--line); }
.coa-actions .btn.sm { padding: 3px 10px; font-size: 12px; }
.coa-indent { color: var(--muted); }
.coa-caret { background: none; border: 0; cursor: pointer; font-size: 17px; line-height: 1; font-weight: 700;
  color: var(--green-dark); padding: 0; margin-right: 7px; width: 18px; display: inline-block; text-align: center; vertical-align: -2px; }
.coa-caret:hover { color: var(--green); transform: scale(1.15); }
.coa-caret-sp { display: inline-block; width: 18px; margin-right: 7px; }
.coa-kidcount { display: inline-block; font-size: 10.5px; font-weight: 700; color: var(--green-dark);
  background: var(--green-light); border-radius: 9px; padding: 0 7px; margin-left: 8px; }
/* Tint parent (main) rows and their sub-accounts so the grouping reads at a glance. */
tr.coa-main > td { background: color-mix(in srgb, var(--green) 16%, var(--card)); }
tr.coa-main > td:first-child { box-shadow: inset 3px 0 0 var(--green); }
tr.coa-sub > td { background: color-mix(in srgb, var(--green) 5%, var(--card)); }
tr.coa-sub.coa-d2 > td { background: color-mix(in srgb, var(--green) 9%, var(--card)); }
tr.coa-sub.coa-d3 > td { background: color-mix(in srgb, var(--green) 12%, var(--card)); }
tr.coa-sub > td:first-child { box-shadow: inset 3px 0 0 #cfe0de; }
/* Scan box on the invoice / quotation / sales order sheets. The dot IS the state: green
   when it has focus and is ready, grey when a stray scan would land somewhere else. */
.iv-scan { display: inline-flex; align-items: center; gap: 9px; margin-top: 10px; margin-right: 10px;
  padding: 5px 12px 5px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--field-bg); }
.iv-scan-dot { width: 9px; height: 9px; border-radius: 50%; background: #c8d2d1; flex: none; transition: background .15s; }
.iv-scan:focus-within .iv-scan-dot { background: var(--green); box-shadow: 0 0 0 3px rgba(45,122,113,.16); }
/* padding-left keeps the scanned digits off the field's left edge. A bar code lands here as one
   burst with no chance to reposition, so text starting hard against the border reads as clipped. */
.iv-scan-in { border: 0; outline: 0; font-size: 13px; padding: 3px 6px 3px 9px; width: 190px; background: transparent; }
.iv-scan:focus-within { border-color: var(--green); }
.iv-scan::after { content: "Click here to scan"; font-size: 11px; color: var(--muted); }
.iv-scan:focus-within::after { content: "Ready to scan"; color: var(--green-dark); font-weight: 600; }
/* A failed scan stays red until the next one - the toast is gone in 2.6 seconds. */
.iv-scan.err { border-color: var(--danger); background: var(--tint-red); }
.iv-scan.err .iv-scan-dot { background: #c0392b; }
.iv-scan.err::after { content: "Not found - scan again"; color: var(--danger); font-weight: 600; }
/* Insert-items mode: the bar stays visible so the till looks the same either way, but it is
   plainly out of use and says which button turns it back on. The input itself is disabled, so
   this is only the appearance of the state, not the state. */
.iv-scan.off { opacity: .5; cursor: not-allowed; }
.iv-scan.off .iv-scan-in { cursor: not-allowed; }
.iv-scan.off::after { content: "Switch to Scan bar code to use this"; }
.iv-scan.off:focus-within::after { content: "Switch to Scan bar code to use this"; color: var(--muted); font-weight: 400; }
/* "Open this invoice's page" sits under the totals rather than as an anonymous icon in the purple
   band. It is the one action there that LEAVES the sheet, so it reads better as a labelled button
   than as an arrow nobody hovers long enough to identify. Right-aligned to sit under the totals
   column it belongs to. */
.qb-openpage { display: flex; justify-content: flex-end; margin-top: 14px; }
/* Same colour as the band at the top of the sheet - var(--green-dark), which is the accent the
   whole theme turns on, so this follows a theme change without knowing anything about it. Sized
   to the totals column beside it rather than shrink-wrapped: as a flex item it collapsed to the
   narrowest word and wrapped the label onto four lines. min-width plus nowrap is what stops that;
   width alone does not, because flex-shrink would undo it. */
.qb-openpage .btn {
  min-width: 232px; white-space: nowrap; flex: none;
  background: var(--green-dark); color: var(--on-green); border: 1px solid var(--green-dark);
  border-radius: 9px; padding: 9px 18px; font-size: 13px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: filter .15s, box-shadow .15s;
}
.qb-openpage .btn:hover { filter: brightness(1.12); box-shadow: 0 2px 10px rgba(0,0,0,.14); }
.qb-openpage .btn:active { filter: brightness(.95); }

/* Item and description share ONE column again. They are still two fields - `detail` is what Time
   and Billing writes a running timer's notes into, and deleting it would hide text that is
   already printing on saved invoices - but they read as a single block: the item name on top,
   its description directly under it, no border between them and no second column heading. */
.iv-itemcell input[name="d"] { display: block; width: 100%; }
.iv-itemcell .line-detail { display: block; width: 100%; margin-top: 3px; border: 0; padding: 2px 0 0;
  background: transparent; resize: vertical; font-size: 12.5px; color: var(--muted); }
.iv-itemcell .line-detail:focus { outline: 0; color: var(--text); }

/* In scan mode the pill WAVES, the same "this one is live" signal the nav badge, workspace chip
   and company dot use: the pill holds perfectly still and a soft ring travels outward and fades.
   It stops in insert-items mode (.off) because the pill is explicitly out of use there, and on a
   failed scan (.err) where the red border is the message and a wave would fight it. */
@keyframes wave-scan {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70%  { box-shadow: 0 0 0 10px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}
.iv-scan:not(.off):not(.err) { animation: wave-scan 1.9s ease-out infinite; }
@media (prefers-reduced-motion: reduce) { .iv-scan { animation: none; } }
@keyframes iv-flash { from { background: #d8efeb; } to { background: transparent; } }
tr.iv-flash > td { animation: iv-flash .6s ease-out; }
/* the invoice page rendered inside a workspace window */
.ws-body.iv-in-win { padding: 14px 18px 18px; background: var(--bg); display: block; }
.ws-body.iv-in-win .page-head { margin-bottom: 12px; flex-wrap: wrap; gap: 8px; }
.ws-body.iv-in-win .page-head h2 { font-size: 18px; }
/* Invoice detail: green "hat" header, matching every other finance window */
.ws-body.iv-in-win > .page-head { background: var(--green-dark); color: var(--on-green); margin: -14px -18px 16px; padding: 13px 18px; align-items: center; }
.ws-body.iv-in-win > .page-head > div:first-child { min-width: 0; }
.ws-body.iv-in-win > .page-head h2 { color: #fff; }
.ws-body.iv-in-win > .page-head h2 .muted { color: color-mix(in srgb, var(--on-green) 72%, transparent) !important; }
/* Invoice detail header: keep the ‹ › browse arrows pinned at the far left so they don't
   shift under the cursor when an invoice's action buttons (Mark paid / Refund / Edit …) change
   width. Arrows live in a left group; the action buttons stay right-anchored and free to reflow. */
.iv-head-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.iv-nav { display: inline-flex; align-items: center; flex: none; }
.iv-acts { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.ws-body.iv-in-win .inv-sheet { padding: 30px 34px; }
.ws-bar { position: absolute; left: 0; right: 0; bottom: 0; z-index: 99990; display: flex; gap: 8px;
  align-items: center; padding: 7px 14px; background: rgba(24,39,39,.94); }
.ws-chip { background: #2e4241; color: #cfe0de; border: 0; border-radius: 7px; padding: 6px 14px;
  font-size: 12.5px; font-weight: 600; cursor: pointer; max-width: 220px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; touch-action: none; }
.ws-chip:hover { background: #3a5554; color: #fff; }
/* The chip for the window you are in sends a wave out, rather than breathing. The earlier version
   scaled 1.8% against a 4px ring at 30%, which is under the threshold you actually notice in the
   corner of your eye - it read as nothing happening. The chip now holds still and the ring alone
   travels, further (12px) and from a stronger start, so the movement is the signal. */
.ws-chip.active { background: var(--green); color: var(--on-green);
  animation: wsChipWave 1.9s ease-out infinite; }
@keyframes wsChipWave {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 62%, transparent); }
  70%  { box-shadow: 0 0 0 12px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .ws-chip.active { animation: none; } }
.ws-chip-drag { opacity: .9; box-shadow: 0 5px 16px rgba(0,0,0,.4); transform: translateY(-2px) scale(1.03);
  cursor: grabbing; z-index: 2; position: relative; }
/* pages rendered inside a window: neutralize the full-page pinned-header bleed */
.ws-win .page-pin { position: sticky; top: 0; margin: 0; padding: 14px 16px 10px; }
.ws-win .page-head { margin-bottom: 12px; }
.ws-win .page-head h2 { font-size: 17px; }
.ws-win .table-wrap { margin: 0 16px 16px; }
.ws-win .pager { margin: 0 16px 14px; }
/* Green "hat" header for list-style workspace windows (matches the invoice band) */
.win-band { display: flex; align-items: center; gap: 12px; background: var(--green-dark); padding: 14px 18px; flex-wrap: wrap; row-gap: 8px; }
.ws-win .win-band { position: sticky; top: 0; z-index: 20; }
.win-btn:disabled { opacity: .5; cursor: default; }
.win-band .rep-select, .win-band .rep-date { background: var(--field-bg); border: 0; border-radius: 7px;
  padding: 7px 10px; font-size: 13px; color: var(--ink); cursor: pointer; }
.win-band-head { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: none; }
.win-band-head h2 { margin: 0; font-size: 17px; color: var(--on-green); line-height: 1.2; white-space: nowrap; }
/* --on-green is now measured against the chosen accent (see onInkFor in app.js), so this follows
   the band instead of assuming it is green. Raised from 72% to 82%: at 12px the fainter mix was
   the weakest text on the band on several accents. */
.win-band-head .sub { font-size: 12px; color: color-mix(in srgb, var(--on-green) 82%, transparent); margin-top: 1px; white-space: nowrap; }
/* Workspace company switcher (multi-company) - sits at the right of the green home band. */
.ws-company-btn { margin-left: auto; display: inline-flex; align-items: center; gap: 7px; flex: none;
  background: rgba(255,255,255,.14); color: #fff; border: 1px solid rgba(255,255,255,.30);
  border-radius: 9px; padding: 7px 12px; font-size: 13px; font-weight: 600; cursor: pointer; max-width: 320px; }
.ws-company-btn:hover { background: rgba(255,255,255,.24); }
/* How many companies are on this account, on the switcher itself. Same wave as the sidebar
   unread badge, but the pill does not scale with it: a number that jiggles is hard to read, and
   the ring alone is what carries the "there is more behind this" signal. White rather than the
   badge's green, because the band underneath is already green. */
/* The pill is white in BOTH themes, so its text cannot follow --green-dark: dark mode lifts that
   green to sit on a dark page, and the lifted version on white measured 3.27:1. Mixing it back
   toward near-black keeps the accent's hue while staying readable on white whatever the theme. */
.ws-co-count { flex: none; display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 19px; padding: 0 6px; border-radius: 10px; background: #fff;
  color: color-mix(in srgb, var(--green-dark) 55%, #0b1a1a); font-size: 11px; font-weight: 800;
  line-height: 1; animation: coCountWave 1.7s ease-out infinite; }
@keyframes coCountWave {
  0%   { box-shadow: 0 0 0 0 rgba(255,255,255,.6); }
  70%  { box-shadow: 0 0 0 10px rgba(255,255,255,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); }
}
@media (prefers-reduced-motion: reduce) { .ws-co-count { animation: none; } }
.ws-company-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-company-caret { opacity: .85; font-size: 11px; }
.ws-co-menu { background: var(--card); border: 1px solid var(--line, #dbe3ea); border-radius: 11px; min-width: 234px;
  box-shadow: 0 14px 38px rgba(0,0,0,.20); padding: 6px; }
.ws-co-menu-head { font-size: 10.5px; font-weight: 800; letter-spacing: .8px; color: var(--muted, #7a898a); padding: 7px 10px 5px; }
.ws-co-item { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; background: none; border: 0;
  padding: 9px 10px; border-radius: 8px; cursor: pointer; font-size: 13.5px; color: var(--ink, #1f2a30); }
.ws-co-item:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.ws-co-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-co-dot { width: 8px; height: 8px; border-radius: 50%; background: #cdd8d7; flex: none; }
/* The company you are in waves, like every other "this one is live" marker in the app. The dot
   holds still and only the ring travels, same as the counts. */
.ws-co-item.on .ws-co-dot { background: var(--green); animation: coDotWave 1.9s ease-out infinite; }
@keyframes coDotWave {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 62%, transparent); }
  70%  { box-shadow: 0 0 0 9px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .ws-co-item.on .ws-co-dot { animation: none; } }
.ws-co-item.on { font-weight: 700; }
.ws-co-new { color: var(--green, #2f8f8b); font-weight: 700; border-top: 1px solid var(--line, #eef1f0); margin-top: 4px; }
.win-band-search { flex: 0 1 300px; min-width: 120px; background: var(--field-bg); border: 0; border-radius: 7px;
  padding: 8px 11px; font-size: 14px; margin-left: 6px; color: var(--ink); }
.win-band-search::placeholder { color: #9aa8a7; }
.modal-inline-action { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.cd-cur.locked input { background: var(--surface); color: var(--muted); cursor: not-allowed; }
.cd-lock { font-size: 15px; opacity: .85; padding: 0 6px; }

/* ---------- Customer Center (QuickBooks-style master-detail) ---------- */
.cc-wrap { display: flex; min-height: 0; height: calc(100vh - 176px); background: var(--card);
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden; }
.ws-win .cc-wrap { flex: 1; height: auto; border: 0; border-radius: 0; }
.cc-list-pane { width: 340px; flex: none; display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--line); }
.cc-list-top { padding: 10px 12px; border-bottom: 1px solid var(--line); }
.cc-filter { width: 100%; padding: 7px 10px; border: 1px solid var(--line); border-radius: 7px; font-size: 13px; background: var(--card); color: var(--ink); cursor: pointer; }
/* Age range, revealed only when the "Between ages" filter is chosen. Tokens throughout so it
   follows the theme like every other control; a hardcoded white here is what broke the customers
   header in dark mode before. */
.cc-age { display: flex; align-items: center; gap: 7px; margin-top: 8px; }
.cc-age input { flex: 1; min-width: 0; padding: 6px 9px; border: 1px solid var(--line);
  border-radius: 7px; font-size: 13px; background: var(--card); color: var(--ink);
  font-family: inherit; }
.cc-age input:focus { outline: none; border-color: var(--green); }
.cc-age-to { font-size: 12px; color: var(--muted); flex: none; }
.cc-age-note { margin-top: 6px; font-size: 11.5px; color: var(--muted); line-height: 1.4; }
/* Retired customers. Greyed rather than hidden when the Inactive filter is on, so the list still
   reads as a list; the badge names the state on the detail pane. Same idea as .row-inactive in
   Inventory, kept visually consistent with it. */
.cc-row.retired .cc-name { color: var(--muted); font-style: italic; }
.cc-retired { font-size: 11px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px;
  vertical-align: middle; margin-left: 8px; }
.cc-info-btns { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
/* Edit is neutral, Make inactive is amber (.btn.warn, the existing house style for an action
   that changes data without destroying it), and Delete is the rare one. Outlined rather than a
   solid red slab: three filled buttons in a row all shout at once, and the destructive one
   should be the quietest until you actually reach for it. It fills on hover so the commitment
   is obvious at the moment of clicking.
   Previously this carried .btn.danger, which sets a red BACKGROUND, plus a rule setting the
   text red - so the word "Delete" was red on red and only the bin icon was visible. */
.cc-del {
  background: var(--card); color: var(--danger);
  border: 1px solid var(--danger); transition: background .13s, color .13s;
}
.cc-del:not(:disabled):hover { background: var(--danger); color: #fff; }
/* Disabled is the COMMON state here: most customers have invoices. It must read as unavailable
   rather than as an armed red button, so it drops the red entirely. The tooltip says why. */
.cc-del:disabled {
  background: var(--card); color: var(--muted);
  border-color: var(--line); cursor: not-allowed; opacity: 1;
}
.cc-info-btns .btn:disabled { cursor: not-allowed; }
.cc-list-head { display: flex; align-items: center; gap: 8px; padding: 6px 14px; font-size: 10.5px;
  font-weight: 800; letter-spacing: .5px; color: var(--muted); background: var(--th-bg); border-bottom: 1px solid var(--line); }
.cc-list { flex: 1; overflow: auto; min-height: 0; }
.cc-row { display: flex; align-items: center; gap: 8px; padding: 9px 14px; cursor: pointer;
  border-bottom: 1px solid #eef2f1; font-size: 13.5px; }
.cc-row:hover { background: var(--green-light); }
/* The tick box builds a mailing list. It keeps its own column so the name, balance and
   credit stay aligned with the header above them. */
.cc-pick, .cc-pick-sp { flex: none; width: 15px; height: 15px; margin: 0; }
.cc-pick { cursor: pointer; accent-color: var(--green); }
.cc-row.sel .cc-pick { accent-color: #fff; }
.cc-row.sel { background: var(--green); color: var(--on-green); }
.cc-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cc-bal { flex: none; width: 60px; text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
.cc-bal.owed { color: #b26a00; font-weight: 700; }
.cc-cr { flex: none; width: 84px; text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); white-space: nowrap; }
.cc-cr.has { color: var(--green-dark); font-weight: 700; }
.cc-row.sel .cc-bal, .cc-row.sel .cc-bal.owed, .cc-row.sel .cc-cr, .cc-row.sel .cc-cr.has { color: #fff; }
.cc-pager { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 12px; border-top: 1px solid var(--line); font-size: 12px; }
.cc-pager .btn.sm { padding: 3px 12px; }
.cc-vsplit { flex: none; width: 7px; cursor: col-resize; position: relative; align-self: stretch; touch-action: none; }
.cc-vsplit::after { content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 1px; background: var(--line); }
.cc-vsplit:hover::after, .cc-vsplit.drag::after { background: var(--green); width: 2px; left: 2.5px; }
.cc-hsplit { flex: none; height: 7px; cursor: row-resize; position: relative; touch-action: none; }
.cc-hsplit::after { content: ""; position: absolute; left: 0; right: 0; top: 3px; height: 1px; background: var(--line); }
.cc-hsplit:hover::after, .cc-hsplit.drag::after { background: var(--green); height: 2px; top: 2.5px; }
.cc-detail { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; overflow: auto; }
.cc-info { flex: none; overflow: auto; }
.cc-blank { padding: 44px 24px; color: var(--muted); text-align: center; }
.cc-blank.sm { padding: 22px; text-align: left; }
.cc-info { padding: 16px 22px; }
.cc-info-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.cc-info-head h2 { margin: 0; font-size: 20px; }
.cc-info-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 30px; }
.cc-fld { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cc-lbl { font-size: 10.5px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; color: var(--muted); }
.cc-val { font-size: 14px; overflow: hidden; text-overflow: ellipsis; }
.cc-val.strong { font-weight: 700; font-size: 15px; }
.cc-tabs { display: flex; align-items: center; gap: 2px; padding: 8px 14px 0; border-bottom: 1px solid var(--line); flex: none; }
.cc-tab { background: none; border: 0; border-bottom: 2px solid transparent; padding: 8px 14px; margin-bottom: -1px;
  font-size: 13.5px; font-weight: 600; color: var(--muted); cursor: pointer; }
.cc-tab:hover { color: var(--ink); }
.cc-tab.active { color: var(--green-dark); border-bottom-color: var(--green); }
.cc-tab-spacer { flex: 1; }
.cc-tab-body { flex: 1; overflow: auto; min-height: 0; }
.cc-table { width: 100%; border-collapse: collapse; }
/* --th-bg / --line, not fixed hexes: these were near-white literals, so in dark mode the
   header painted as a white band across the panel and the row rules glowed. */
.cc-table th { text-align: left; font-size: 10.5px; font-weight: 800; letter-spacing: .5px; color: var(--muted);
  padding: 8px 12px; border-bottom: 1px solid var(--line); background: var(--th-bg); position: sticky; top: 0; z-index: 1; }
.cc-table td { padding: 8px 12px; border-bottom: 1px solid var(--line); font-size: 13px; white-space: nowrap; }
.cc-table th.right, .cc-table td.right { text-align: right; }
.cc-table tr.clickable:hover { background: var(--green-light); cursor: pointer; }
.cc-table td.owed { color: #b26a00; font-weight: 700; }
.cc-aging { color: #b3261e; font-weight: 700; }
@media (max-width: 820px) { .cc-info-grid { grid-template-columns: 1fr; } .cc-list-pane { width: 250px; } }

/* ---------- Enter Bills (accounts payable) ---------- */
.bill-wrap { display: flex; flex: 1; min-height: 0; }
.bill-main { flex: 1; min-width: 0; overflow: auto; padding: 16px 18px; }
.bill-side { width: 280px; flex: none; border-left: 1px solid var(--line); background: var(--th-bg); overflow: auto; padding: 14px 16px; }
.bill-sheet { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 14px 18px 16px; }
.bill-word { font-size: 30px; font-weight: 800; color: color-mix(in srgb, var(--ink) 72%, var(--card)); letter-spacing: .5px; margin-bottom: 8px; line-height: 1; }
.bill-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 10px 24px; align-items: start; }
.bill-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.bill-field.span2 { grid-column: 1 / -1; }
.bill-field.grid-tall { grid-row: span 2; }
.bill-field label { font-size: 10px; font-weight: 800; letter-spacing: .8px; color: var(--muted); }
.bill-field input, .bill-field textarea { border: 1px solid var(--line); border-radius: 7px; padding: 7px 9px; font-size: 13.5px; background: var(--field-bg); color: var(--field-fg); width: 100%; }
.bill-field input[readonly] { background: var(--surface); color: var(--muted); font-weight: 700; }
.bill-field textarea { resize: vertical; min-height: 44px; }
.bill-lines-head { display: flex; align-items: baseline; gap: 12px; margin: 16px 0 6px; font-size: 14px; }
.bill-lines-wrap { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.bill-lines-tbl { width: 100%; border-collapse: collapse; }
.bill-lines-tbl th { text-align: left; font-size: 10px; font-weight: 800; letter-spacing: .5px; color: var(--muted); background: var(--th-bg); padding: 7px 10px; border-bottom: 1px solid var(--line); }
.bill-lines-tbl th.right { text-align: right; }
.bill-lines-tbl td { padding: 4px 8px; border-bottom: 1px solid var(--line); }
.bill-lines-tbl td.right { text-align: right; }
.bill-lines-tbl select, .bill-lines-tbl input { border: 1px solid transparent; border-radius: 6px; padding: 6px 7px; font-size: 13px; width: 100%; background: var(--field-bg); color: var(--field-fg); }
.bill-lines-tbl select:focus, .bill-lines-tbl input:focus { border-color: var(--green); outline: none; }
.bill-lines-tbl .bl-amt { text-align: right; }
.bl-x { background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 13px; }
.bl-x:hover { color: var(--danger); }
/* The line-remove ✕ in the invoice/quote editor: red, since it deletes the row. Overrides the
   ghost button it borrows its shape from - text and border go red, filling red on hover. */
.qb-rm.btn.ghost { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--line)); font-weight: 700; }
.qb-rm.btn.ghost:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.bill-foot { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-top: 1px solid var(--line); background: var(--card); flex: none; }
.bill-total-big { font-size: 14px; color: var(--muted); }
.bill-total-big b { font-size: 20px; color: var(--ink); margin-left: 8px; }
.bill-toggle { color: #fff; font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; gap: 5px; margin-left: 8px; cursor: pointer; }
.bill-toggle input { accent-color: #fff; }
.bill-side-h { font-size: 15px; font-weight: 700; margin-bottom: 8px; }
.bill-side-name { font-weight: 700; font-size: 15px; margin-bottom: 4px; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bill-side-edit { background: none; border: 1px solid var(--line); border-radius: 6px; width: 27px; height: 25px; cursor: pointer; color: var(--muted); flex: none; }
.bill-side-edit:hover { background: var(--green-light); color: var(--green-dark); border-color: var(--green); }
.bill-side-row b.bill-ell { max-width: 165px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
.bill-side-sec { font-size: 10px; font-weight: 800; letter-spacing: .8px; color: var(--muted); margin: 14px 0 6px; }
.bill-side-row { display: flex; justify-content: space-between; gap: 8px; padding: 5px 2px; font-size: 13px; border-bottom: 1px solid var(--line); }
.bill-side-row.clickable { cursor: pointer; }
.bill-side-row.clickable:hover { background: var(--green-light); }
.bill-side-row b.owed { color: var(--amber); }

/* ---------- Account register (ledger) ---------- */
.reg-wrap { flex: 1; min-height: 0; overflow: auto; }
.reg-tbl { width: 100%; border-collapse: collapse; }
/* --th-bg, not a literal: every other table header in the app already uses it, and the hardcoded
   light grey here is what left the Pay Bills and register headers as a white bar across a dark
   window. Same for the row rule, which was a light literal on a dark background. */
.reg-tbl th { position: sticky; top: 0; z-index: 1; text-align: left; font-size: 10px; font-weight: 800; letter-spacing: .5px;
  color: var(--muted); background: var(--th-bg); padding: 7px 10px; border-bottom: 1px solid var(--line); }
.reg-tbl th.right { text-align: right; }
.reg-tbl td { padding: 3px 8px; border-bottom: 1px solid var(--line); font-size: 13px; vertical-align: middle; }
.reg-tbl td.right { text-align: right; }
.reg-row.ro td { background: var(--th-bg); color: var(--muted); }
.reg-row.ro td b { color: var(--ink); }
/* A row someone typed in, rather than one a document produced. Same amber as the "Hand-entered"
   figure in the bar above, so the two read as the same idea, with a stripe down the near edge.
   Deliberately weaker than the hover and selection rules below, which still take over. */
tr.reg-manual > td { background: color-mix(in srgb, var(--amber) 15%, var(--card)); }
tr.reg-manual > td:first-child { box-shadow: inset 3px 0 0 var(--amber); }
.reg-row.reg-open { cursor: pointer; }
.reg-row.reg-open:hover > td { background: color-mix(in srgb, var(--green) 9%, transparent); }
.reg-tbl tr.reg-row.sel > td { background: color-mix(in srgb, var(--green) 22%, var(--card)); color: var(--ink); }
.reg-row.sel:focus { outline: none; }
.reg-entry td { background: color-mix(in srgb, var(--amber) 12%, var(--card)); }
.reg-tbl .re-c { width: 100%; border: 1px solid transparent; border-radius: 5px; padding: 5px 6px; font-size: 13px; background: transparent; color: var(--ink); }
.reg-tbl .re-c:hover { border-color: var(--line); background: var(--field-bg); }
.reg-tbl .re-c:focus { border-color: var(--green); background: var(--field-bg); outline: none; }
.reg-tbl .re-c.right { text-align: right; }
/* Same red remove button as an invoice line (.qb-rm): red on a red-tinted outline, filling solid
   on hover, so "this deletes something" reads the same wherever you meet it. */
.reg-del, .reg-rmrow { background: var(--card); color: var(--danger); cursor: pointer;
  font-size: 12.5px; font-weight: 700; line-height: 1; padding: 4px 9px; border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--danger) 40%, var(--line));
  transition: background .13s ease, border-color .13s ease, color .13s ease; }
.reg-del:hover, .reg-rmrow:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
/* Banner shown when a register is too long to draw in one go (a 13-year A/R is 73,131
   lines). It has to state what is on screen, or a partial ledger reads as the whole one. */
.reg-more-band { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 16px; font-size: 12px; color: var(--muted);
  background: var(--card); border-bottom: 1px solid var(--line); flex: none; }
.reg-more-band b { color: var(--text); }
.reg-more-band .win-btn { margin-left: 4px; }

/* Does the balance agree with the documents behind it? Green when the whole balance came from
   invoices and credit notes, amber when something was typed in by hand and needs a human to
   say whether it belongs (a payment to the tax office does; a stray line does not). */
.reg-recon { display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 9px 16px; font-size: 12.5px; color: var(--muted);
  border-bottom: 1px solid var(--line); flex: none; }
.reg-recon b { color: var(--ink); font-variant-numeric: tabular-nums; }
.reg-recon.ties { background: color-mix(in srgb, var(--green) 10%, var(--card)); }
.reg-recon.has-manual { background: color-mix(in srgb, var(--amber) 14%, var(--card)); }
.reg-recon-dot { opacity: .45; }
.reg-recon-ok { margin-left: auto; color: var(--green-dark); font-weight: 700; }
.reg-recon-btn { margin-left: auto; cursor: pointer; font-size: 12px; font-weight: 700;
  color: var(--amber); background: none; border: 1px solid color-mix(in srgb, var(--amber) 45%, var(--line));
  border-radius: 8px; padding: 4px 11px; transition: background .13s ease, color .13s ease; }
.reg-recon-btn:hover { background: var(--amber); color: #2b1f04; }
/* the filter itself */
.reg-only-manual #reg-rows tr.reg-row:not(.reg-manual) { display: none; }
.reg-band-hint { margin-left: auto; font-style: italic; opacity: .75; }
/* Shown when a report is too long to draw in full. It has to be impossible to miss:
   a truncated total that looks complete is the worst thing an accounting screen can do. */
/* Shown when an invoice will close a customer's appointment. Visible on purpose: closing
   someone's visit is a real consequence, so it should never happen silently. */
.iv-appt { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 14px; font-size: 12.5px; color: var(--green-dark, #1e5c56);
  background: var(--green-light); border-bottom: 1px solid var(--green-line); }
.iv-appt select { border: 1px solid var(--green-line); border-radius: 7px; background: var(--field-bg); padding: 3px 6px;
  font-size: 12.5px; font-weight: 600; color: var(--green-dark, #1e5c56); cursor: pointer; max-width: 340px; }
.rep-cap-band { margin: 0 0 10px; padding: 9px 13px; font-size: 12.5px; border-radius: 8px;
  color: var(--text); background: var(--warn-bg, #fff6e5); border: 1px solid var(--warn-line, #f0d9a8); }
.reg-foot { display: flex; align-items: center; gap: 12px; padding: 10px 16px; border-top: 1px solid var(--line); background: var(--card); flex: none; }
.reg-ending { font-size: 13px; color: var(--muted); }
.reg-ending b { font-size: 19px; color: var(--ink); margin-left: 8px; }
.reg-ro-hint { display: inline-flex; align-items: center; gap: 6px; }
.reg-ro-tag { font-size: 10px; font-weight: 800; letter-spacing: .4px; text-transform: uppercase;
  background: rgba(255,255,255,.18); color: #eaf3f3; border-radius: 6px; padding: 2px 7px; margin-left: 8px; vertical-align: 1px; }

/* ---------- Pay Bills ---------- */
.pb-tbl td.pb-chk, .pb-tbl th.pb-chk { text-align: center; padding-left: 6px; padding-right: 6px; }
.pb-tbl .pb-check, .pb-tbl #pb-all { width: 15px; height: 15px; cursor: pointer; accent-color: var(--green); }
.pb-row { cursor: default; }
.pb-row:hover > td { background: color-mix(in srgb, var(--green) 9%, transparent); }
.pb-tbl tr.pb-row.pb-sel > td { background: color-mix(in srgb, var(--green) 20%, var(--card)); }
.pb-overdue { color: var(--danger); font-weight: 600; }
.pb-tbl .pb-amt { width: 100%; border: 1px solid var(--line); border-radius: 5px; padding: 5px 6px; font-size: 13px;
  background: #fffef4; color: var(--ink); text-align: right; }
.pb-tbl .pb-amt:focus { border-color: var(--green); background: var(--field-bg); outline: none; }
.pb-open { cursor: pointer; }
.pb-filter { display: inline-flex; align-items: center; gap: 6px; color: #eaf3f3; font-size: 12.5px; font-weight: 600; }
.pb-filter input[type="checkbox"] { accent-color: #fff; }
.pb-date { width: 110px; border: 1px solid var(--line); border-radius: 6px; padding: 5px 8px; font-size: 13px; }
.win-band .pb-filter .pb-date { border-color: rgba(255,255,255,.4); background: rgba(255,255,255,.14); color: #fff; }
.win-band .pb-filter .pb-date::placeholder { color: color-mix(in srgb, var(--on-green) 72%, transparent); }
.pb-foot { display: flex; align-items: center; gap: 16px; padding: 10px 16px; border-top: 1px solid var(--line); background: var(--card); flex: none; flex-wrap: wrap; }
.pb-pay { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.pb-pay label { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); font-weight: 600; }
.pb-pay select { border: 1px solid var(--line); border-radius: 6px; padding: 5px 8px; font-size: 13px; background: var(--field-bg); color: var(--field-fg); }
.pb-total { font-size: 13px; color: var(--muted); }
.pb-total b { font-size: 19px; color: var(--ink); margin-left: 8px; }
.pb-foot .btn:disabled { opacity: .5; cursor: not-allowed; }
.win-band-jump { display: inline-flex; align-items: center; gap: 8px; margin-left: 18px;
  background: rgba(255,255,255,.14); border-radius: 8px; padding: 5px 6px 5px 12px; flex: none; }
.win-band-jump > span { font-size: 10px; font-weight: 800; letter-spacing: 1px; color: color-mix(in srgb, var(--on-green) 72%, transparent); }
.win-jump-input { background: var(--field-bg); border: 0; border-radius: 6px; padding: 6px 10px; font-size: 13px;
  color: var(--ink); width: 124px; }
.win-jump-input::placeholder { color: #9aa8a7; }
.win-jump-input.bad { box-shadow: 0 0 0 2px #e5533c; }
.win-band-actions { margin-left: auto; display: flex; gap: 8px; flex: none; }
.win-btn { background: rgba(255,255,255,.15); color: #fff; border: 0; border-radius: 7px;
  padding: 8px 14px; font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.win-btn:hover { background: rgba(255,255,255,.28); }
.win-btn.primary { background: var(--card); color: var(--green-dark); font-weight: 700; }
.win-btn.primary:hover { background: color-mix(in srgb, var(--on-green) 12%, var(--green)); }
/* Calendar inside a workspace window: fit the day-view to the window and scroll
   internally, instead of the full-page calc(100vh) height that overflows the window. */
.ws-win .cal-layout { padding: 16px; flex: 1; min-height: 0; align-items: stretch; }
.ws-win .cal-side { align-self: flex-start; }
.ws-win .day-col { display: flex; flex-direction: column; }
.ws-win .day-scroll { height: auto; flex: 1; min-height: 0; }

/* the invoice sheet, when it lives inside a window instead of the overlay */
.qb-sheet.qb-in-win { flex: 1; display: flex; flex-direction: column; min-height: 0; width: auto;
  box-shadow: none; border-radius: 0; max-width: none; max-height: none; margin: 0; }

/* ---------- QuickBooks-style invoice sheet ---------- */
.qb-back { align-items: flex-start; padding: 2.5vh 2vw; }
/* floating-dialog variant (opened outside the workspace): movable/resizable/maximizable */
.qb-sheet.qb-float { max-width: none; max-height: none; margin: 0; box-shadow: 0 18px 60px rgba(0,0,0,.35); }
.qb-float .qb-top { cursor: move; user-select: none; }
/* The editor's close button inherits the shared .ws-ctl treatment above. */
.qb-float .ws-grip { border-bottom-right-radius: 12px; }
.qb-sheet { background: var(--card); border-radius: 12px; width: 100%; max-width: 1240px; margin: 0 auto;
  max-height: 95vh; display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 24px 70px rgba(0,0,0,.30); }
.qb-top { display: flex; align-items: center; justify-content: space-between; padding: 10px 18px;
  border-bottom: 1px solid #cfdbd9; background: #dfe9e7; }
.qb-top h3 { margin: 0; font-size: 15px; }
.qb-top .x { background: none; border: 0; font-size: 22px; line-height: 1; cursor: pointer; color: var(--muted); }
.qb-band { display: flex; align-items: flex-end; gap: 18px; background: var(--green-dark); padding: 12px 20px; }
.qb-band label { display: block; font-size: 10px; font-weight: 800; letter-spacing: 1px; color: color-mix(in srgb, var(--on-green) 72%, transparent); margin-bottom: 4px; }
.qb-band-cust input { width: 320px; max-width: 60vw; background: var(--field-bg); border: 0; border-radius: 7px; padding: 8px 11px; font-size: 14px; }
.qb-nav { display: flex; gap: 4px; padding-bottom: 1px; }
/* Nav arrows + Find: translucent, they sit quietly on the band. */
.qb-nav button, #qb-find { background: rgba(255,255,255,.16); color: #fff;
  border: 1px solid rgba(255,255,255,.34); border-radius: 9px; cursor: pointer;
  transition: background .15s ease, box-shadow .15s ease, border-color .15s ease, transform .08s ease; }
.qb-nav button { width: 36px; height: 36px; font-size: 15px; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; }
#qb-find { padding: 0 15px; height: 36px; font-size: 13px; font-weight: 600; margin-bottom: 1px; }
.qb-nav button:hover, #qb-find:hover { background: rgba(255,255,255,.30); border-color: rgba(255,255,255,.55);
  box-shadow: 0 2px 9px rgba(0,0,0,.16); }
/* Print / email / open: solid white chips with the accent-coloured icon, so the real actions
   pop off the band and read as buttons instead of muddy translucent squares. */
#qb-print, #qb-email, #qb-open { width: 38px; height: 36px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  background: #fff; color: var(--green-dark); border: 0; border-radius: 10px;
  box-shadow: 0 1px 3px rgba(0,0,0,.22);
  transition: background .15s ease, box-shadow .15s ease, transform .09s ease; }
#qb-print svg, #qb-email svg, #qb-open svg { width: 18px; height: 18px; }
#qb-print:hover, #qb-email:hover, #qb-open:hover { transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0,0,0,.26); }
#qb-print:active, #qb-email:active, #qb-open:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(0,0,0,.22); }
.qb-nav button:active, #qb-find:active { transform: translateY(1px); box-shadow: none; }
.qb-nav button:focus-visible, #qb-find:focus-visible, #qb-print:focus-visible, #qb-email:focus-visible, #qb-open:focus-visible {
  outline: 2px solid rgba(255,255,255,.85); outline-offset: 1px; }
.qb-viewonly { align-self: center; background: #fdf6e3; color: #b8860b; border: 1px solid #ecd9a0;
  font-size: 11px; font-weight: 800; letter-spacing: .6px; padding: 4px 12px; border-radius: 9px; white-space: nowrap; }
.row-inactive td { opacity: .45; }
.row-inactive td:last-child { opacity: 1; }
.ev-flash { animation: evflash 1.4s ease-out 2; }
@keyframes evflash { 0% { box-shadow: 0 0 0 4px var(--green); } 100% { box-shadow: 0 0 0 0 rgba(47,143,139,0); } }
/* The appointment you jumped to keeps a gentle "breathing" glow so you can spot it in a
   busy day - until you click it. Lifts above (and un-dims) the other blocks. */
.ev.ev-breathe { animation: evbreathe 1.7s ease-in-out infinite; z-index: 9; opacity: 1; }
/* Highlighting an appointment must not repaint it - the colour is its status. Just bring a faded
   one (no-show, cancelled) up to full strength so it is clearly the one being pointed at. */
.ev.ev-breathe.out-done, .ev.ev-breathe.out-noshow, .ev.ev-breathe.out-cancelled { opacity: 1; }
@keyframes evbreathe {
  0%, 100% { box-shadow: 0 0 0 2px var(--green), 0 1px 3px rgba(0,0,0,.10); }
  50%      { box-shadow: 0 0 0 5px color-mix(in srgb, var(--green) 40%, transparent), 0 3px 12px color-mix(in srgb, var(--green) 35%, transparent); }
}
.qb-find-list { max-height: 260px; overflow-y: auto; margin-top: 12px; border-top: 1px solid var(--line); padding-top: 6px; }
/* dialog-as-window (makeDialogWindow): Find Invoices, New email, … */
.dlg-win { display: flex; flex-direction: column; max-width: none; }
.dlg-win .modal-body { flex: 1; overflow-y: auto; min-height: 0; }
.dlg-win .modal-head { cursor: move; user-select: none; }
.dlg-win .ws-grip { border-bottom-right-radius: 12px; }
.qb-find-dlg .qb-find-list { max-height: none; overflow: visible; }
.qb-tmpl { margin-left: auto; font-size: 12px; color: color-mix(in srgb, var(--on-green) 72%, transparent); padding-bottom: 8px; }
.qb-tmpl b { color: var(--on-green); }
.qb-cols { display: flex; flex: 1; min-height: 0; }
.qb-mainpane { flex: 1; min-width: 0; padding: 20px 24px; overflow-y: auto; position: relative; }
.qb-pastdue { position: absolute; top: 74px; right: 36px; z-index: 5; font-size: 42px; font-weight: 800;
  letter-spacing: 3px; color: rgba(179,38,30,.28); border: 5px solid rgba(179,38,30,.28); border-radius: 10px;
  padding: 4px 18px; transform: rotate(-14deg); pointer-events: none; }
.qb-sidepane { width: 264px; flex: 0 0 auto; background: var(--th-bg); padding: 16px 18px; overflow-y: auto; }
.qb-split { flex: 0 0 7px; cursor: col-resize; border-left: 1px solid var(--line); background: transparent; }
.qb-split:hover, .qb-split:active { background: var(--green-light); border-left-color: var(--green); }
.qb-headrow { display: flex; gap: 22px; align-items: flex-start; margin-bottom: 16px; flex-wrap: wrap; }
.qb-invword { font-size: 34px; font-weight: 300; letter-spacing: .5px; color: color-mix(in srgb, var(--ink) 78%, var(--card)); }
.qb-meta { display: flex; gap: 16px; margin-left: auto; }
.qb-field label, .qb-billto label { display: block; font-size: 10px; font-weight: 800; letter-spacing: 1px;
  color: var(--muted); margin-bottom: 4px; }
.qb-field input[type="date"] { padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; font-size: 13.5px; }
.qb-due-row { position: relative; display: flex; gap: 4px; align-items: stretch; }
.qb-term-num { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; padding: 0 8px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--th-bg); font-weight: 700; font-size: 13px; color: var(--ink); }
.qb-due-btn { width: 30px; align-self: stretch; border: 1px solid var(--line); background: var(--field-bg);
  border-radius: 8px; cursor: pointer; color: var(--muted); font-size: 12px; }
.qb-due-btn:hover { background: var(--green-light); color: var(--green-dark); border-color: var(--green); }
.qb-due-btn:disabled { opacity: .4; cursor: default; }
.qb-due-menu { position: absolute; top: calc(100% + 4px); right: 0; z-index: 60; background: var(--card);
  border: 1px solid var(--line); border-radius: 9px; box-shadow: 0 10px 28px rgba(0,0,0,.16);
  padding: 4px; display: flex; flex-direction: column; min-width: 110px; }
.qb-due-menu[hidden] { display: none; }
.qb-due-menu button { text-align: left; background: none; border: 0; padding: 7px 12px; border-radius: 6px;
  font-size: 13px; cursor: pointer; }
.qb-due-menu button:hover { background: var(--green-light); color: var(--green-dark); }
.qb-ro { padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; font-size: 13.5px;
  background: var(--bg); color: var(--muted); min-width: 64px; text-align: center; }
.qb-billto { min-width: 210px; max-width: 280px; }
.qb-billto > div { background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
  padding: 9px 12px; font-size: 13px; min-height: 40px; line-height: 1.45; }
.qb-table { width: 100%; border-collapse: collapse; margin-top: 6px; }
.qb-table th { text-align: left; font-size: 10.5px; letter-spacing: .8px; color: var(--muted);
  border-bottom: 2px solid var(--line); padding: 7px 8px; }
.qb-table th.right { text-align: right; }
.qb-table td { padding: 5px 6px; border-bottom: 1px solid var(--line); font-size: 13.5px; }
/* Every line row carries the same faint tint, so each white field reads as its own boxed cell -
   uniform, instead of only the alternating rows looking framed. */
.qb-table tbody tr td { background: color-mix(in srgb, var(--ink) 4%, transparent); }
.qb-table input { width: 100%; border: 1px solid transparent; background: var(--field-bg); border-radius: 6px;
  padding: 7px 8px; font-size: 13.5px; }
.qb-table input:focus { background: var(--field-bg); border-color: var(--green); outline: none; }
.qb-amt { font-weight: 600; white-space: nowrap; }
.qb-totals { margin-left: auto; width: 300px; margin-top: 18px; display: flex; flex-direction: column; gap: 7px; font-size: 13px; }
.qb-totals > div { display: flex; justify-content: space-between; align-items: baseline; }
.qb-totals > div[hidden] { display: none; }
.qb-totals span { color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .8px; }
.qb-grand { border-top: 2px solid var(--ink); padding-top: 8px; }
.qb-grand b { font-size: 17px; }
/* discount input inside the totals stack (PERCENT off BEFORE tax) */
.qb-totals .qb-disc-line { align-items: center; }
.qb-totals .qb-disc-wrap { display: flex; align-items: center; gap: 10px; }
.qb-totals .qb-disc-line input { width: 58px; text-align: right; padding: 4px 8px; font-size: 13.5px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--field-bg); }
.qb-totals .qb-disc-line input:focus { border-color: var(--green); outline: none; }
.qb-foot { display: flex; gap: 10px; align-items: center; padding: 13px 24px; border-top: 1px solid var(--line); background: var(--th-bg); }
.qb-side-name { font-weight: 700; font-size: 15px; margin-bottom: 4px; display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.qb-side-edit { background: none; border: 1px solid var(--line); border-radius: 6px; width: 27px; height: 25px;
  cursor: pointer; color: var(--muted); font-size: 13px; line-height: 1; flex: 0 0 auto; }
.qb-side-edit:hover { background: var(--green-light); color: var(--green-dark); border-color: var(--green); }
.qb-side-h { font-size: 10px; font-weight: 800; letter-spacing: 1px; color: var(--muted); margin: 16px 0 6px;
  border-bottom: 1px solid var(--line); padding-bottom: 4px; }
.qb-kv { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; padding: 4px 0; }
.qb-kv span { color: var(--muted); }
.qb-kv b { font-weight: 600; text-align: right; }
.qb-kv b { min-width: 0; }
.qb-ell { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qb-red { color: var(--danger); }
.qb-link { cursor: pointer; border-radius: 6px; }
.qb-link:hover { background: var(--green-light); }
.qb-side-empty { color: var(--muted); font-size: 12.5px; margin-top: 10px; line-height: 1.5; }
@media (max-width: 900px) { .qb-sidepane, .qb-split { display: none; } }

/* ---------- Page bits ---------- */
/* Pinned page header (Customers / Inventory / Invoices): the title row + search bar stay
   fixed at the top of the window while only the table scrolls beneath them. Bleeds over
   main's 26/32px padding so table rows never peek out around the pinned block's edges. */
.page-pin { position: sticky; top: 0; z-index: 20; background: var(--bg);
  margin: -26px -32px 16px; padding: 26px 32px 10px; }
.page-pin .toolbar { margin-bottom: 0; }
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 20px; }
/* space out the action buttons in a page header so they don't touch */
.page-head button + button { margin-left: 10px; }
.page-head h2 { margin: 0; font-size: 22px; }
.page-head .sub { color: var(--muted); font-size: 13px; margin-top: 2px; }

.btn {
  background: var(--green); color: var(--on-green); border: 0; padding: 9px 16px; border-radius: 8px;
  font-size: 14px; font-weight: 600;
}
.btn:hover { background: var(--green-dark); }
.btn.ghost { background: var(--card); color: var(--ink); border: 1px solid var(--line); }
.btn.ghost:hover { background: var(--bg); }
.btn.danger { background: var(--danger); }
/* Amber "think before you click" button, for actions that overwrite data but are not deletions.
   Dark text on amber, because white on yellow is unreadable. */
.btn.warn { background: #f2b202; color: #3d2c00; border: 1px solid #d99e00; }
.btn.warn:hover { background: #dea201; }
.btn.sm { padding: 5px 10px; font-size: 12.5px; }
/* Restore dialog: a proper drop target instead of the browser's raw file input, which looks
   unfinished next to the rest of the app. The native input stays in the DOM but hidden, so
   clicking the label still opens the file chooser and keyboard users keep the same path. */
.rs-drop {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 26px 18px; border: 2px dashed var(--line); border-radius: 12px;
  background: var(--bg); cursor: pointer; text-align: center;
  transition: border-color .15s, background .15s;
}
.rs-drop:hover, .rs-drop.over { border-color: var(--green); background: var(--green-light); }
.rs-drop.chosen { border-style: solid; border-color: var(--green); background: var(--green-light); }
.rs-drop-ic { font-size: 30px; line-height: 1; }
.rs-drop-main { font-weight: 700; font-size: 14.5px; color: var(--ink); }
.rs-drop-sub { font-size: 12.5px; color: var(--muted); }
.rs-group { margin: 16px 0 6px; font-size: 11.5px; font-weight: 700; letter-spacing: .06em;
            text-transform: uppercase; color: var(--muted); }
.rs-count { font-size: 12.5px; color: var(--muted); }

.toolbar { display: flex; gap: 10px; margin-bottom: 16px; align-items: center; flex-wrap: wrap; }
.search { flex: 1; min-width: 200px; }
input.search, .field input, .field select, .field textarea,
.wt-fields input:not([type=color]), .wt-fields textarea {
  padding: 9px 11px; border: 1px solid var(--line); border-radius: 8px; font-size: 14px; width: 100%;
  background: var(--field-bg); font-family: inherit;
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--green); border-color: var(--green); }

/* phone/mobile with a fixed, non-editable country-code chip */
.ph-input { display: flex; }
.ph-input input { flex: 1; min-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; }
.ph-cc { display: inline-flex; align-items: center; padding: 0 9px; background: #eef1f0; border: 1px solid var(--line);
  border-right: 0; border-radius: 8px 0 0 8px; color: #333; font-size: 14px; font-weight: 600; white-space: nowrap; user-select: none; }
.ph-cc:empty { display: none; }                 /* no country selected -> plain input */
.ph-cc:empty + input { border-radius: 8px; }

/* country picker dropdown (all countries shown; matches float to the top) */
.cc-field { position: relative; }
.cc-dd { position: absolute; left: 0; right: 0; top: 100%; margin-top: 3px; background: var(--card); border: 1px solid var(--line);
  border-radius: 8px; box-shadow: 0 12px 30px rgba(0,0,0,.18); max-height: 220px; overflow-y: auto; z-index: 50; }
.cc-opt { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 9px 12px; cursor: pointer; font-size: 14px; }
.cc-opt:hover, .cc-opt.active { background: var(--green-light); }
.cc-opt .cc-pfx { color: var(--muted); font-size: 12.5px; }

/* Cards / stats */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 14px; margin-bottom: 24px; }
.stat { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--shadow); }
.stat .n { font-size: 26px; font-weight: 700; color: var(--green-dark); }
.stat .l { color: var(--muted); font-size: 12.5px; margin-top: 3px; text-transform: uppercase; letter-spacing: .03em; }

.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.card h3 { margin: 0; padding: 14px 18px; border-bottom: 1px solid var(--line); font-size: 15px; }
.card-head-flex { display: flex; align-items: center; justify-content: space-between; padding: 10px 18px; border-bottom: 1px solid var(--line); }
.card-head-flex h3 { padding: 0; border: 0; }
.card .card-body { padding: 14px 18px; }

/* Tables */
/* Only the page scrolls vertically (the sidebar is sticky and stays put). The table keeps
   horizontal scroll for wide columns, but no vertical scroll of its own - otherwise Windows
   shows TWO vertical scrollbars (page + table) and you'd scroll inside both. */
.table-wrap { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow-x: auto; box-shadow: var(--shadow); }
/* always-visible accent HORIZONTAL scrollbar so you can scroll right to reach clipped columns.
   Scoped to :horizontal deliberately. It used to set `width: 13px` and colour the thumb for BOTH
   axes, which painted a fat accent-coloured VERTICAL bar wherever a container gave the table a
   vertical scrollbar of its own - inside a register window that reads as a purple line sitting
   right beside the window's own grey scrollbar, two bars fighting for the same 13 pixels. The
   accent belongs to the horizontal bar, which is the one this rule was written for; anything
   vertical keeps the platform's own, which is what the comment above always intended. */
.table-wrap::-webkit-scrollbar:horizontal { height: 13px; }
.table-wrap::-webkit-scrollbar-track:horizontal { background: #eef1f0; border-radius: 0 0 var(--radius) var(--radius); }
.table-wrap::-webkit-scrollbar-thumb:horizontal { background: var(--green); border-radius: 7px; border: 3px solid #eef1f0; }
.table-wrap::-webkit-scrollbar-thumb:horizontal:hover { background: var(--green-dark); }

/* Checkbox column (multi-select for bulk email) */
.chk-col { width: 34px; text-align: center; overflow: visible !important; }
.chk-col input[type="checkbox"] { width: 15px; height: 15px; cursor: pointer; accent-color: var(--green); vertical-align: middle; }

/* WhatsApp chat page */
.wa-hint { background: #eef7f4; border: 1px solid #cfe8e2; color: #2c6b60; border-radius: 8px;
  padding: 10px 14px; font-size: 13px; margin-bottom: 14px; }
.wa-hint a { color: #1c7c6c; font-weight: 600; }
.btn.wa-btn { background: #25d3bd; border-color: #25d3bd; color: #fff; }
.btn.wa-btn:hover { background: #1eb6a4; border-color: #1eb6a4; }

/* ---- Embedded WhatsApp inbox ---- */
.wa-me-head { display: flex; align-items: center; gap: 14px; }
.wa-me-av { width: 46px; height: 46px; min-width: 46px; font-size: 18px; cursor: pointer; position: relative; }
.wa-me-av:hover { filter: brightness(.9); }
/* "Change photo" badge - a crisp drawn camera, not the 📷 emoji (which rendered as
   an unreadable white dot at this size). */
.wa-me-av::after {
  content: "";
  position: absolute; right: -3px; bottom: -3px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--field-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%232f8f5b' d='M9 5h6l1.3 2H20a2.2 2.2 0 0 1 2.2 2.2V18A2.2 2.2 0 0 1 20 20.2H4A2.2 2.2 0 0 1 1.8 18V9.2A2.2 2.2 0 0 1 4 7h3.7z'/%3E%3Ccircle cx='12' cy='13.4' r='3.7' fill='%23ffffff'/%3E%3Ccircle cx='12' cy='13.4' r='1.9' fill='%232f8f5b'/%3E%3C/svg%3E") center / 12px 12px no-repeat;
  border: 1px solid #e6eceb;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
}
/* Non-admins can't change the business profile, so don't dangle a camera badge at them. */
.wa-me-av.no-edit { cursor: default; }
.wa-me-av.no-edit:hover { filter: none; }
.wa-me-av.no-edit::after { display: none; }
.wa-tabs { display: flex; align-items: center; gap: 8px; }
/* View actions (Unread / Archived / New) sit in the page header rather than the list column.
   margin-left:auto groups them with the connector chips on the right; the margin reset stops
   .page-head's "button + button" rule from stacking on top of the flex gap. */
.wa-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.wa-actions button + button { margin-left: 0; }

/* your profile panel (modal) */
.wa-pf { text-align: center; }
.wa-pf-pic { width: 96px; height: 96px; border-radius: 50%; margin: 4px auto 10px; background: #25d3bd; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 36px; font-weight: 700; background-size: cover; background-position: center; }
.wa-pf-pic.has-pic { color: transparent; font-size: 0; }
.wa-pf-name { font-weight: 700; font-size: 16px; margin-top: 10px; }
.wa-pf-num { font-size: 13px; }
.wa-tab { display: inline-flex; align-items: center; gap: 7px; padding: 7px 14px; border-radius: 8px;
  border: 1px solid var(--border, #dde3e0); background: var(--card); cursor: pointer; font-size: 13px; font-weight: 600; color: #333; }
.wa-tab.active { background: #e7f6f3; border-color: #9fd9d1; color: #1c7c6c; }
/* colour-coded actions, matching the soft-tint style of the active tab */
#wa-restart { background: #fdf3d3; border-color: #e6c757; color: #8a6a12; }
#wa-restart:hover:not(:disabled) { background: #fbecba; border-color: #dcb941; }
#wa-unlink { background: var(--tint-red); border-color: #e3a1a1; color: #b3261e; }
#wa-unlink:hover:not(:disabled) { background: var(--tint-red); border-color: #d98a8a; }
.wa-dot { width: 9px; height: 9px; border-radius: 50%; background: #c2c8c5; }
.wa-dot.on { background: #25d3bd; } .wa-dot.wait { background: #f0ad3c; } .wa-dot.off { background: #c2c8c5; }

.wa-body { height: calc(100vh - 150px); min-height: 420px; }
.wa-center { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--muted); }

.spinner { width: 34px; height: 34px; border: 3px solid #d9e4e2; border-top-color: #25d3bd; border-radius: 50%; animation: waspin .8s linear infinite; }
@keyframes waspin { to { transform: rotate(360deg); } }

/* connect / QR screens */
.wa-connect { max-width: 460px; margin: 4vh auto 0; text-align: center; background: var(--card); border: 1px solid var(--border, #dde3e0); border-radius: 12px; padding: 30px 28px; }
.wa-connect h3 { margin: 6px 0 14px; }
.wa-big { font-size: 44px; }
.wa-qr { width: 300px; height: 300px; margin: 0 auto 14px; display: flex; align-items: center; justify-content: center; background: var(--card); border: 1px solid #eee; border-radius: 10px; }
.wa-qr img { border-radius: 6px; }
.wa-steps { text-align: left; max-width: 320px; margin: 0 auto 12px; color: #444; font-size: 13.5px; line-height: 1.7; }
.wa-warn { background: #fff4e5; border: 1px solid #f3d19e; color: #9a5b00; border-radius: 8px; padding: 8px 12px; font-size: 12px; margin-top: 8px; }
.wa-err { color: var(--danger); font-size: 12.5px; word-break: break-word; }
/* Telegram two-step-verification password entry */
.tg-pw { display: flex; gap: 8px; max-width: 340px; margin: 6px auto 12px; }
.tg-pw-input { flex: 1; padding: 10px 12px; border: 1px solid var(--border, #cfd8d3); border-radius: 8px; font-size: 14px; background: var(--field-bg); color: var(--field-fg); }
.tg-pw-input:focus { outline: none; border-color: #25d3bd; box-shadow: 0 0 0 2px rgba(37,211,189,.15); }
.tg-pw .btn { white-space: nowrap; }

/* two-pane inbox */
/* Thin top bar in the chat list while a freshly-linked account syncs its history. */
.wa-syncing { background: #fff7e6; color: #8a6d1f; border-bottom: 1px solid #f0e2bf;
  padding: 7px 12px; font-size: 12px; font-weight: 600; text-align: center; flex: none; }
.wa-inbox { display: flex; height: 100%; border: 1px solid var(--border, #dde3e0); border-radius: 12px; overflow: hidden; background: var(--card); }
.wa-list { width: 320px; min-width: 320px; border-right: 1px solid var(--border, #dde3e0); display: flex; flex-direction: column; }
.wa-list-head { display: flex; gap: 8px; padding: 10px; border-bottom: 1px solid var(--border, #eee); }
.wa-list-head .search.sm { flex: 1; min-width: 0; padding: 7px 10px; font-size: 13px; }
.wa-filter { border: 1px solid var(--border, #dde3e0); background: var(--card); border-radius: 15px; padding: 6px 11px; font-size: 12px; cursor: pointer; white-space: nowrap; color: #444; flex: 0 0 auto; }
.wa-filter:hover { background: #f4f6f5; }
.wa-filter.active { background: #e7f6f3; border-color: #9fd9d1; color: #1c7c6c; font-weight: 700; }
.wa-chats { flex: 1; overflow-y: auto; }
.wa-chat { display: flex; gap: 10px; padding: 10px 12px; cursor: pointer; border-bottom: 1px solid #f2f4f3; position: relative; }
.wa-chat:hover { background: #f6f9f8; }
.wa-chat.active { background: #e7f6f3; }
/* Archive control: hidden until the row is hovered, so it never competes with the message preview.
   Kept keyboard-reachable - :focus-visible reveals it for anyone tabbing rather than mousing. */
.wa-chat-arch { position: absolute; right: 10px; bottom: 8px; opacity: 0; transition: opacity .12s;
  border: 1px solid var(--line); background: var(--card); color: var(--muted); border-radius: 6px;
  padding: 2px 8px; font-size: 11px; font-family: inherit; cursor: pointer; }
.wa-chat:hover .wa-chat-arch, .wa-chat-arch:focus-visible { opacity: 1; }
.wa-chat-arch:hover { background: var(--green-light); border-color: var(--green); color: var(--green-dark); }
.wa-av { width: 40px; height: 40px; min-width: 40px; border-radius: 50%; background: #25d3bd; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; }
.wa-chat-main { flex: 1; min-width: 0; }
.wa-chat-top { display: flex; justify-content: space-between; gap: 6px; }
.wa-chat-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wa-chat-time { font-size: 11px; color: var(--muted); white-space: nowrap; }
.wa-chat-bot { display: flex; justify-content: space-between; align-items: center; gap: 6px; margin-top: 2px; }
.wa-snip { font-size: 12.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wa-unread { background: #25d3bd; color: #fff; font-size: 11px; font-weight: 700; border-radius: 11px; min-width: 20px; height: 20px; padding: 0 6px; display: inline-flex; align-items: center; justify-content: center; }

.wa-thread { flex: 1; display: flex; flex-direction: column; min-width: 0; background: #efe7de; }
.wa-thread-head { display: flex; align-items: center; gap: 10px; padding: 8px 14px; background: var(--card); border-bottom: 1px solid var(--border, #eee); }
.wa-th-id { min-width: 0; }
.wa-th-name { font-weight: 700; line-height: 1.2; }
.wa-add-cust { margin-left: auto; flex-shrink: 0; }
.wa-th-sub { font-size: 12px; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wa-biz { display: inline-block; background: #e7f6f3; color: #1c7c6c; border: 1px solid #bfe6e0; border-radius: 4px; padding: 0 5px; font-size: 10.5px; font-weight: 700; vertical-align: middle; }
/* Live presence pill next to the Business badge - same shape, filled green for "online". */
.wa-presence { display: inline-block; background: #2fae9a; color: #fff; border: 1px solid #2fae9a; border-radius: 4px; padding: 0 6px; font-size: 10.5px; font-weight: 700; vertical-align: middle; }
.wa-presence.typing { background: #eaf6f4; color: #1c7c6c; border-color: #bfe6e0; font-style: italic; }
.wa-presence.offline { background: #eef1f4; color: #6b7783; border-color: #d7dee4; }
.wa-lastseen { font-size: 11px; vertical-align: middle; }
.wa-media { font-style: italic; opacity: .92; }
.wa-msg.call { justify-content: center; }
.wa-msg.call .wa-bubble { background: #eef1f0; color: #555; font-size: 12.5px; text-align: center; box-shadow: none; }
.wa-msgs { flex: 1; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 6px; }
.wa-loadmore { align-self: center; margin: 2px 0 8px; padding: 4px 12px; border-radius: 12px; background: rgba(0,0,0,.05); color: var(--muted); font-size: 12px; }
.wa-msg { display: flex; }
.wa-msg.me { justify-content: flex-end; }
.wa-bubble { max-width: 72%; padding: 7px 10px 5px; border-radius: 8px; font-size: 13.5px; line-height: 1.4; position: relative; word-wrap: break-word; white-space: pre-wrap; box-shadow: 0 1px 0 rgba(0,0,0,.08); }
.wa-msg.them .wa-bubble { background: var(--card); }
.wa-msg.me .wa-bubble { background: #d3fde2; }
.wa-link-a { color: #1c74c4; text-decoration: underline; word-break: break-all; }
.wa-link-a:hover { color: #12579b; }
.wa-mtime { display: block; text-align: right; font-size: 10px; color: #667; margin-top: 2px; }
/* Delivery ticks on sent messages: grey = sent/delivered, blue = read (like WhatsApp) */
.wa-tick { display: inline-flex; align-items: center; margin-left: 4px; color: #92a3ae; vertical-align: -1px; }
.wa-tick.read { color: #53bdeb; }
.wa-tick.err { color: var(--danger); font-weight: 700; font-size: 11px; }
.wa-composer { display: flex; gap: 10px; padding: 10px 12px; background: var(--card); border-top: 1px solid var(--border, #eee); align-items: flex-end; }
.wa-composer textarea { flex: 1; resize: none; max-height: 120px; padding: 9px 12px; border: 1px solid var(--border, #dde3e0); border-radius: 20px; font: inherit; font-size: 14px; }
.wa-clip { font-size: 19px; line-height: 1; padding: 6px 11px; }

/* staged attachment preview(s) above the composer */
.wa-attach-preview { padding: 10px 12px; background: var(--card); border-top: 1px solid var(--border, #eee); }
.wa-ap-items { display: flex; gap: 12px; overflow-x: auto; padding: 4px 4px 6px; }
.wa-ap-item { position: relative; width: 64px; flex: 0 0 auto; }
.wa-ap-thumb { width: 64px; height: 64px; border-radius: 8px; overflow: hidden; background: #eef1f0; display: flex; align-items: center; justify-content: center; }
.wa-ap-thumb img { width: 100%; height: 100%; object-fit: cover; }
.wa-ap-ic { font-size: 28px; }
.wa-ap-x { position: absolute; top: -6px; right: -6px; width: 20px; height: 20px; border-radius: 50%; border: 2px solid #fff; background: #444; color: #fff; font-size: 10px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.wa-ap-x:hover { background: #c0392b; }
.wa-ap-name { font-size: 10px; color: var(--muted); margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; }
.wa-ap-hint { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* profile pictures on the avatar circles */
.wa-av { background-size: cover; background-position: center; overflow: hidden; }
.wa-av.group { background-color: #6b8fa3; font-size: 18px; } /* background-COLOR only - the `background` shorthand would reset background-size:cover and break group photos */
.wa-av.has-pic { color: transparent; font-size: 0; }   /* must come AFTER .group so a group WITH a photo hides its icon */

/* inline media: photos, stickers, voice/video/document */
.wa-photo { max-width: 260px; max-height: 320px; border-radius: 6px; display: block; }
.wa-photo.sticker { max-width: 120px; max-height: 120px; }
.wa-photo-wrap { position: relative; display: inline-block; line-height: 0; }
.wa-dl { position: absolute; top: 6px; right: 6px; width: 30px; height: 30px; border-radius: 50%; border: none;
  background: rgba(0,0,0,.55); color: #fff; font-size: 15px; cursor: pointer; display: flex; align-items: center;
  justify-content: center; opacity: 0; transition: opacity .12s; }
.wa-photo-wrap:hover .wa-dl { opacity: 1; }
.wa-dl:hover { background: rgba(0,0,0,.8); }
.wa-mediabox { min-width: 70px; }
.wa-mbtn { background: #f0f4f2; border: 1px solid #cfe0dc; color: #1c6b62; border-radius: 16px; padding: 6px 13px; font-size: 13px; cursor: pointer; font-weight: 600; }
.wa-mbtn:hover { background: #e4efec; }
.wa-mbtn:disabled { opacity: .7; cursor: default; }
.wa-video { max-width: 280px; max-height: 320px; border-radius: 6px; display: block; }

/* compact inline voice-note player (stays a pill, plays in place) */
.wa-voice { display: flex; align-items: center; gap: 9px; min-width: 210px; }
.wa-vplay { width: 30px; height: 30px; min-width: 30px; border-radius: 50%; border: none; background: #25d3bd; color: #fff; font-size: 12px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.wa-vplay:hover { background: #1eb6a4; }
.wa-vbar { flex: 1; height: 5px; background: #ccd7d3; border-radius: 3px; position: relative; cursor: pointer; min-width: 90px; }
.wa-vfill { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: #25d3bd; border-radius: 3px; }
.wa-vtime { font-size: 11px; color: #5a6b66; min-width: 30px; text-align: right; }
/* appointment "resolved / done" chip toggle */
.done-toggle { display: inline-flex; align-items: center; gap: 9px; margin-top: 6px; padding: 9px 14px;
  border: 1px solid var(--line); border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px;
  color: var(--muted); user-select: none; transition: background .12s, border-color .12s, color .12s; }
.done-toggle:hover { border-color: #b7c9c8; }
.done-toggle input { width: 18px; height: 18px; accent-color: var(--green); cursor: pointer; margin: 0; flex: none; }
.done-toggle.on { background: var(--green-light); border-color: #9fd9d1; color: var(--green-dark); }
/* appointment participant rows (multiple clients in one slot) */
.ap-client-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.ap-client-row .ac-wrap, .ap-client-row > input { flex: 1; min-width: 0; }
.ap-client-x { flex: none; width: 34px; height: 34px; border: 1px solid var(--line); background: var(--card); border-radius: 8px; cursor: pointer; color: var(--danger); font-size: 13px; }
.ap-client-x:hover { border-color: var(--danger); background: var(--tint-red); }
/* permission chips (same chip style as the done toggle) */
.perm-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 6px; }
.perm-chip { display: flex; align-items: center; gap: 9px; padding: 9px 14px; border: 1px solid var(--line);
  border-radius: 8px; cursor: pointer; font-weight: 600; font-size: 14px; color: var(--muted); user-select: none;
  transition: background .12s, border-color .12s, color .12s; }
.perm-chip:hover { border-color: #b7c9c8; }
.perm-chip input { width: 18px; height: 18px; accent-color: var(--green); cursor: pointer; margin: 0; flex: none; }
.perm-chip.on { background: var(--green-light); border-color: #9fd9d1; color: var(--green-dark); }
.perm-chip.wide { grid-column: 1 / -1; }
.perm-chip.locked { cursor: not-allowed; opacity: .65; }
.perm-chip.locked input { cursor: not-allowed; }
.scope-pick { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; }
.scope-opt { display: flex; align-items: flex-start; gap: 10px; padding: 10px 13px; border: 1px solid var(--line);
  border-radius: 9px; cursor: pointer; font-size: 13px; line-height: 1.4; transition: border-color .12s, background .12s; }
.scope-opt:hover { border-color: #b7c9c8; }
.scope-opt input { width: 17px; height: 17px; accent-color: var(--green); cursor: pointer; margin: 1px 0 0; flex: none; }
.scope-opt:has(input:checked) { background: var(--green-light); border-color: #9fd9d1; }
.scope-opt b { color: var(--green-dark); }
.smtp-note { font-size: 12px; margin-top: 10px; padding: 9px 11px; background: #fff8e6; border: 1px solid #f0e0b0; border-radius: 8px; line-height: 1.45; }
.smtp-note:empty { display: none; }

/* Email Connection Setup - list of connected accounts */
.ea-list { display: flex; flex-direction: column; gap: 8px; }
.ea-row {
  display: flex; align-items: center; gap: 12px; padding: 11px 13px;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px; cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}
.ea-row:hover, .ea-row:focus { border-color: var(--green); box-shadow: 0 2px 8px color-mix(in srgb, var(--green) 12%, transparent); outline: none; }
.ea-av {
  width: 38px; height: 38px; min-width: 38px; border-radius: 50%;
  background: var(--green); color: var(--on-green); font-weight: 700; font-size: 16px;
  display: flex; align-items: center; justify-content: center;
}
.ea-main { flex: 1; min-width: 0; }
.ea-addr { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 8px; }
.ea-sub { font-size: 12.5px; margin-top: 1px; }
.ea-badge {
  font-size: 10.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  color: var(--green-dark); background: #e8f5f5; border: 1px solid #bfe3e0;
  padding: 1px 7px; border-radius: 999px;
}
.ea-go { color: var(--muted); font-size: 22px; line-height: 1; }

.mail-head-actions { display: flex; align-items: center; gap: 8px; }

/* Compact Email header: the connected mailbox IS the title, with an unread pill
   beside it - one line instead of two, so the inbox list below gets more height. */
.mail-head { margin-bottom: 14px; }
.mail-head-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.mail-head-title h2 { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60vw; }
.mail-unread-pill {
  flex: none; background: var(--green); color: var(--on-green); border: 0;
  border-radius: 999px; padding: 3px 11px; font-size: 12px; font-weight: 700; white-space: nowrap;
}

/* Email nav: caret + collapsible mailbox switcher under the Email item */
.nav-caret {
  margin-left: auto; margin-right: -4px; background: none; border: none; cursor: pointer;
  color: #8fb7b4; font-size: 17px; font-weight: 700; line-height: 1; padding: 5px 6px; border-radius: 6px;
  transition: transform .18s, color .15s;
}
.nav-caret:hover { color: #fff; background: rgba(255,255,255,.08); }
.nav-caret.open { transform: rotate(180deg); }
/* the badge already claims margin-left:auto; when it's visible the caret sits after it */
.nav-badge + .nav-caret { margin-left: 6px; }

.nav-sub { max-height: 0; overflow: hidden; transition: max-height .22s ease; }
.nav-sub.open { max-height: 340px; overflow-y: auto; }
.nav-sub-row {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  background: none; border: none; cursor: pointer;
  padding: 8px 20px 8px 24px; color: #9fbcbb; font-size: 12.5px; font-weight: 500;
  border-left: 3px solid transparent;
}
.nav-sub-row:hover { background: rgba(255,255,255,.05); color: #fff; }
/* --acct-color is set per-row (each mailbox its own colour) - accent bar + dot use it */
.nav-sub-row.active { color: #fff; border-left-color: var(--acct-color, var(--green)); }
.nav-sub-check { width: 14px; flex: none; color: var(--acct-color, var(--green)); font-weight: 700; font-size: 13px; line-height: 1; }
.nav-sub-row:not(.active) .nav-sub-check { font-size: 15px; }   /* the • dot reads a touch bigger */
/* Website's rows are sections of one thing rather than a list of accounts, so they take the theme
   accent instead of a per-row colour, and their glyphs are already the right size. */
#web-nav-sub .nav-sub-check { font-size: 12px; }
#web-nav-sub .nav-sub-row:not(.active) .nav-sub-check { font-size: 12px; opacity: .75; }
.nav-sub-addr { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* "＋ Add messenger" row - a muted call-to-action under the connected list */
.nav-sub-add { color: rgba(255,255,255,.55); }
.nav-sub-add .nav-sub-check { color: rgba(255,255,255,.55); font-size: 15px; }
.nav-sub-add:hover { color: #fff; }
/* per-messenger unread count pill, anchored to the right of its row */
.msgr-unread { margin-left: auto; flex: none; background: #25d3bd; color: #fff; border-radius: 10px;
  min-width: 18px; height: 18px; padding: 0 6px; font-size: 10.5px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center; }
/* Add-messenger picker (modal) */
.msgr-add-grid { display: flex; flex-direction: column; gap: 10px; }
.msgr-add-btn { display: flex; align-items: center; gap: 12px; width: 100%; padding: 13px 15px; border: 1px solid var(--line, #dbe3ea);
  border-radius: 10px; background: var(--card); cursor: pointer; font-size: 15px; font-weight: 600; color: #1c2b3a; text-align: left; transition: border-color .12s, background .12s; }
.msgr-add-btn:hover { border-color: var(--green, #2f8f8b); background: #f6faf9; }
.msgr-add-dot { width: 12px; height: 12px; border-radius: 50%; flex: none; }
.msgr-add-name { flex: 1; }
.msgr-add-arrow { color: #9aa7b2; font-size: 20px; }
/* collapsed icon-only sidebar: hide the switcher entirely */
.sidebar.collapsed .nav-caret, .sidebar.collapsed .nav-sub { display: none !important; }
.wa-cap { margin-top: 5px; }
/* link preview card + inline player */
.wa-linkprev { margin-top: 8px; }
.wa-linkprev.card { display: block; width: min(300px, 100%); border: 1px solid rgba(0,0,0,.1); border-radius: 12px; overflow: hidden; background: rgba(0,0,0,.03); }
.wa-lp-media { position: relative; width: 100%; background: #0000000f; display: block; line-height: 0; }
.wa-lp-media img { width: 100%; display: block; object-fit: cover; }
.wa-linkprev.card:not(.portrait) .wa-lp-media img { aspect-ratio: 16 / 9; }
.wa-linkprev.card.portrait .wa-lp-media img { height: 300px; }
.wa-lp-play { position: absolute; inset: 0; margin: auto; width: 52px; height: 52px; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 20px; padding-left: 3px; box-shadow: 0 2px 10px rgba(0,0,0,.4); }
.wa-lp-meta { padding: 8px 10px; }
.wa-lp-title { font-weight: 600; font-size: 13px; line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.wa-lp-site { font-size: 11.5px; color: var(--muted); margin-top: 3px; text-transform: capitalize; }
.wa-linkprev.embed .wa-lp-frame { position: relative; width: min(300px, 100%); border-radius: 12px; overflow: hidden; background: #000; }
.wa-linkprev.embed:not(.portrait) .wa-lp-frame { aspect-ratio: 16 / 9; }
.wa-linkprev.embed.portrait .wa-lp-frame { width: min(260px, 100%); aspect-ratio: 9 / 16; }
.wa-lp-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.wa-lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: flex; align-items: center; justify-content: center; z-index: 3000; cursor: zoom-out; }
.wa-lb-inner { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.wa-lightbox img { max-width: 92vw; max-height: 84vh; border-radius: 6px; box-shadow: 0 8px 40px rgba(0,0,0,.5); cursor: default; }
.wa-lb-dl { background: #25d3bd; color: #fff; border: none; padding: 9px 18px; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; }
.wa-lb-dl:hover { background: #1eb6a4; }
/* Prev/next arrows pinned to the screen edges, so they never crowd the picture. */
.wa-lb-nav { position: fixed; top: 50%; transform: translateY(-50%); width: 46px; height: 76px; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.12); color: #fff; border: none; border-radius: 8px; font-size: 34px; line-height: 1; cursor: pointer; user-select: none; }
.wa-lb-nav:hover { background: rgba(255,255,255,.26); }
.wa-lb-nav.prev { left: 16px; }
.wa-lb-nav.next { right: 16px; }
.wa-lb-count { color: rgba(255,255,255,.72); font-size: 13px; letter-spacing: .04em; cursor: default; }
.wa-lightbox img.loading { opacity: .45; transition: opacity .12s; }

/* WhatsApp account dialog */
.wa-status { padding: 8px 12px; border-radius: 6px; font-size: 13px; margin-bottom: 12px; }
/* Cash exchange on the invoice sheet, under the paid note. Prints with the invoice: the customer
   gets a record of what they handed over and what came back. */
.inv-cash { margin-top: 6px; padding-top: 6px; border-top: 1px dotted #cfdada; }
.inv-cash div { display: flex; justify-content: space-between; font-size: 12.5px; color: #556564; }
.inv-cash div:last-child { font-weight: 700; color: var(--ink); }
/* Till helper on the "mark as paid" dialog: type what the customer handed over, read the change.
   Shown for Cash only. The invoice is still settled for its full amount either way. */
/* Cash tendered can arrive in another currency; the picker sits against the amount so it
   reads as one control, and the conversion line shows the sum being done rather than just
   its result - a till figure nobody can check is a till figure nobody trusts. */
.cash-in-row { display: flex; gap: 8px; align-items: stretch; }
.cash-in-row select { flex: none; width: 84px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--field-bg); font-size: 15px; font-weight: 700; padding: 0 6px; cursor: pointer; }
.cash-in-row #cash-in { flex: 1; }
.cash-conv span { color: var(--muted); font-size: 12.5px; }
/* The change line carries its own currency picker: a customer who paid with a $20 note
   usually wants dollars back, not guilders. */
.cash-change select { flex: none; margin-left: auto; margin-right: 8px; border: 1px solid var(--line);
  border-radius: 7px; background: var(--field-bg); font-size: 12.5px; font-weight: 700; padding: 2px 4px; cursor: pointer; }
.cash-change { display: flex; align-items: center; gap: 6px; }
/* On the invoice: the foreign figure reads first because that is what changed hands, with
   the local value beside it so the books can always be tied back. Prints as it shows. */
.inv-fx { color: var(--muted); font-weight: 400; font-size: .88em; margin-left: 5px; }
.cash-conv b { font-weight: 600; }
.cash-box { margin-top: 12px; padding: 12px 14px; border: 1px solid var(--line);
            border-radius: 10px; background: var(--bg); }
.cash-lbl { display: block; font-size: 12.5px; font-weight: 600; color: var(--muted); margin-bottom: 5px; }
.cash-box input {
  width: 100%; padding: 10px 12px; font-size: 20px; font-weight: 700; text-align: right;
  border: 1px solid var(--line); border-radius: 8px; background: var(--field-bg); color: var(--ink);
}
.cash-box input:focus { outline: none; border-color: var(--green); }
.cash-line { display: flex; justify-content: space-between; align-items: baseline;
             margin-top: 8px; font-size: 13px; color: var(--muted); }
.cash-line b { color: var(--ink); font-size: 14px; }
.cash-change { padding-top: 8px; border-top: 1px dashed var(--line); }
.cash-change b { font-size: 19px; }
.cash-change b.cash-ok { color: var(--green); }
.cash-change b.cash-short { color: var(--danger); }
/* Save was pressed while the counter is still short: draw the eye back to the box. */
.cash-box.cash-nudge { border-color: var(--danger); animation: cashNudge .28s ease; }
@keyframes cashNudge {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}
.wa-status.ok { background: #e7f6f3; color: #1c7c6c; border: 1px solid #bfe6e0; }
/* Neutral variant, used to name the company a settings dialog is editing. */
.wa-status:not(.ok):not(.err) { background: var(--bg); border: 1px solid var(--line); color: var(--ink); }
.wa-test-row { display: flex; align-items: center; gap: 12px; margin-top: 14px; flex-wrap: wrap; }
.wa-test-out { font-size: 13px; }
.wa-test-out.ok { color: #1c7c6c; }
.wa-test-out.err { color: var(--danger); }

/* BCC recipient preview inside the bulk-email dialog */
.bcc-box { max-height: 90px; overflow: auto; background: var(--th-bg); border: 1px solid var(--line);
  border-radius: 6px; padding: 8px 10px; font-size: 12.5px; color: var(--muted); word-break: break-word; line-height: 1.5; }

/* Bulk-email drip progress bar */
.bulk-bar { height: 12px; background: var(--th-bg); border-radius: 999px; overflow: hidden; margin-top: 14px; }
.bulk-bar-fill { height: 100%; width: 0; background: var(--green); border-radius: 999px; transition: width .4s ease; }
.queued-chip { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 999px;
  background: rgba(58,143,142,.12); color: var(--green); font-size: 12.5px; font-weight: 600; white-space: nowrap; cursor: default; }

/* Resizable columns: drag the right edge of a header to widen/narrow it. */
table.resizable.locked { table-layout: fixed; }
table.resizable.locked th, table.resizable.locked td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* sticky headers: column labels + green resize grips stay visible while scrolling rows */
.table-wrap thead th { position: sticky; top: 0; z-index: 2; }
.col-resizer { position: absolute; top: 0; right: 0; width: 10px; height: 100%; cursor: col-resize; z-index: 3; }
/* always-visible green grip so it's obvious where to drag */
.col-resizer::after {
  content: ""; position: absolute; right: 3px; top: 22%; height: 56%; width: 3px;
  border-radius: 2px; background: var(--green);
}
.col-resizer:hover::after { top: 0; height: 100%; width: 4px; background: var(--green-dark); }
body.col-resizing-active, body.col-resizing-active * { cursor: col-resize !important; user-select: none !important; }
/* arrow marking the currently-sorted column (set via the Sort dialog) */
.sort-arrow { color: var(--green); font-size: 11px; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 11px 16px; font-size: 13.5px; }
th { background: var(--th-bg); color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: .03em; border-bottom: 1px solid var(--line); }
tbody tr { border-top: 1px solid var(--line); }
tbody tr:hover { background: var(--green-light); }
td.right, th.right { text-align: right; }
/* Inline-editable inventory cells: click to edit, Enter/blur to save. */
.edit-cell { cursor: text; }
.edit-cell:hover { box-shadow: inset 0 0 0 1px var(--green, #2f8f8b); background: var(--green-light); }
.cell-edit { width: 100%; box-sizing: border-box; font: inherit; padding: 4px 6px; margin: -3px 0; border: 1px solid var(--green, #2f8f8b); border-radius: 4px; background: var(--field-bg); color: var(--ink, #1d2b2b); }
td.right .cell-edit { text-align: right; }
.row-actions { display: flex; gap: 6px; justify-content: flex-end; }
.clickable { cursor: pointer; }
/* Approve Invoice: the status filter and what you can do with the result. */
.inv-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 14px; border-bottom: 1px solid var(--line); background: var(--th-bg); flex: none; }
.inv-filters { display: inline-flex; background: var(--card); border: 1px solid var(--line);
  border-radius: 9px; padding: 2px; gap: 2px; }
.inv-filter { border: 0; background: none; padding: 6px 14px; border-radius: 7px; cursor: pointer;
  font-size: 13px; font-weight: 600; color: var(--muted); transition: background .12s, color .12s; }
.inv-filter:hover { color: var(--ink); background: color-mix(in srgb, var(--green) 10%, transparent); }
.inv-filter.on { background: var(--green); color: var(--on-green); }
.inv-sel-note { font-size: 12.5px; font-weight: 700; color: var(--green-dark); }
.inv-chk-th, .inv-chk-td { width: 34px; text-align: center; }
.inv-chk-td { cursor: default; }
/* Dashboard rows that link somewhere get a gentle hover so they read as clickable. */
.card tr.clickable { transition: background .12s ease; }
.card tr.clickable:hover td { background: color-mix(in srgb, var(--green) 10%, transparent); }

.badge { display: inline-block; padding: 2px 9px; border-radius: 20px; font-size: 12px; font-weight: 600; }
.badge.green { background: var(--green-light); color: var(--green-dark); }
.badge.amber { background: var(--tint-amber); color: var(--amber); }
.badge.red { background: var(--tint-red); color: var(--danger); }
.badge.gray { background: var(--tint-gray); color: var(--muted); }

.pager { display: flex; gap: 10px; align-items: center; justify-content: flex-end; margin-top: 14px; color: var(--muted); font-size: 13px; }
.empty { padding: 40px; text-align: center; color: var(--muted); }
.muted { color: var(--muted); }

/* Modal */
/* Dialogs sit ABOVE the whole Finance workspace: windows raise their z-index on
   every click (unbounded), and the taskbar is at 99990 - so the modal layer must
   beat both, or an "Edit customer" opened from a busy window sinks behind it. */
.modal-back { position: fixed; inset: 0; background: rgba(20,30,30,.45); display: flex; align-items: flex-start; justify-content: center; padding: 40px 16px; z-index: 99995; overflow: auto; }
.modal { background: var(--card); color: var(--ink); border-radius: 12px; width: 540px; max-width: 100%; box-shadow: 0 24px 70px rgba(0,0,0,.3); }
.modal.wide { width: 760px; }
.modal-head { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid var(--line); }
.modal-head h3 { margin: 0; font-size: 17px; }
.acct-modal .modal-head { background: var(--green-dark); border-bottom: 0; border-radius: 12px 12px 0 0; }
.acct-modal .modal-head h3 { color: #fff; }
.acct-modal .modal-head .x { color: #cfe0de; }
.acct-modal .modal-head .x:hover { color: #fff; }
.modal-head .x { background: none; border: 0; font-size: 22px; color: var(--muted); line-height: 1; }
.modal-body { padding: 20px; }
.modal-foot { padding: 14px 20px; border-top: 1px solid var(--line); display: flex; justify-content: flex-end; gap: 10px; }
.modal.confirm-modal { width: 460px; }
.confirm-msg { font-size: 14.5px; line-height: 1.55; color: var(--ink); }
/* refund choice (store credit vs cash) */
.refund-opts { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.refund-opt { display: flex; align-items: flex-start; gap: 11px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 8px; cursor: pointer; }
.refund-opt:hover { border-color: #9fd9d1; background: var(--green-light); }
.refund-opt:has(input:checked) { border-color: var(--green); background: var(--green-light); }
.refund-opt input { margin-top: 2px; width: 17px; height: 17px; accent-color: var(--green); flex: none; }
.refund-opt-txt { display: flex; flex-direction: column; gap: 2px; }
.refund-opt-txt b { font-size: 14px; }
.refund-opt-txt .muted { font-size: 12.5px; }
.inv-refund-note { margin-top: 8px; color: var(--amber); font-size: 13px; font-weight: 600; }
.inv-paid-note { margin-top: 8px; color: var(--green-dark); font-size: 13px; font-weight: 600; }
.inv-usd { color: var(--green-dark); font-size: 13px; font-weight: 600; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.field { display: flex; flex-direction: column; }
.field.full { grid-column: 1 / -1; }
.field label { font-size: 12px; color: var(--muted); font-weight: 600; margin-bottom: 5px; }
/* a field whose input sits next to a small action button (e.g. Group + add) */
.field-with-btn { display: flex; gap: 8px; align-items: stretch; }
.field-with-btn > select, .field-with-btn > input { flex: 1; min-width: 0; }
.add-inline { flex: none; padding: 0 13px; font-size: 17px; line-height: 1; font-weight: 700; }
.field textarea { min-height: 70px; resize: vertical; }
/* inline autocomplete dropdown */
.ac-wrap { position: relative; }
.ac-menu { position: fixed; display: none; z-index: 200; background: var(--card); border: 1px solid var(--line);
  border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.18); max-height: 240px; overflow-y: auto; min-width: 280px; }
.ac-item { display: flex; justify-content: space-between; gap: 12px; padding: 8px 12px; cursor: pointer; font-size: 13.5px; }
.ac-item:hover, .ac-item.active { background: var(--green-light); }
.ac-item .ac-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-item .ac-sub { color: var(--muted); font-size: 12px; white-space: nowrap; }
.ac-item .ac-rm { border: 0; background: none; color: var(--muted); font-size: 15px; line-height: 1;
  padding: 0 3px; cursor: pointer; border-radius: 4px; flex: none; }
.ac-item .ac-rm:hover { color: #b3261e; background: rgba(179,38,30,.1); }
.ac-item.ac-create { color: var(--green-dark); font-weight: 600; border-bottom: 1px solid var(--line); background: var(--green-light); }
.ac-item.ac-create:hover, .ac-item.ac-create.active { background: #d3ecea; }
.perm-cb { display: flex; gap: 8px; align-items: center; font-weight: 500; }
.perm-cb.locked { opacity: .5; cursor: not-allowed; }
.perm-cb.locked input { cursor: not-allowed; }

/* Toast */
.tip-pop { position: fixed; z-index: 100000; background: #182727; color: #e8f5f5; font-size: 12px;
  font-weight: 600; padding: 6px 11px; border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.28);
  pointer-events: none; max-width: 280px; line-height: 1.4; animation: tipin .12s ease-out; }
.tip-pop[hidden] { display: none; }
@keyframes tipin { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
.toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--toast-bg); color: var(--toast-fg); padding: 11px 20px; border-radius: 8px; font-size: 14px; z-index: 99999; box-shadow: 0 8px 30px rgba(0,0,0,.3); }
/* Send/Receive: the circular arrows spin while inboxes are being checked */
.sr-ico { display: inline-block; line-height: 0; vertical-align: -2px; }
.sr-ico.spinning { animation: sr-spin .9s linear infinite; }
@keyframes sr-spin { to { transform: rotate(360deg); } }
.toast.err { background: var(--danger); }

/* Persistent, dismissable update nudge (stays until the user closes it). */
.update-toast {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 10px;
  background: var(--ink); color: #fff; padding: 10px 10px 10px 18px;
  border-radius: 10px; font-size: 14px; z-index: 200;
  box-shadow: 0 8px 30px rgba(0,0,0,.35); max-width: min(92vw, 560px);
  animation: updateToastIn .18s ease-out;
}
@keyframes updateToastIn { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
.update-toast-msg {
  background: none; border: 0; color: inherit; font: inherit; text-align: left;
  cursor: pointer; padding: 2px 0; flex: 1 1 auto;
}
.update-toast-msg:hover { text-decoration: underline; }
.update-toast-x {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 6px;
  background: rgba(255,255,255,.14); border: 0; color: #fff; cursor: pointer;
  font-size: 13px; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.update-toast-x:hover { background: rgba(255,255,255,.3); }
/* Brief highlight of the update card when arriving from the toast. */
.sw-upd-flash { animation: swUpdFlash .9s ease-in-out 0s 2; border-radius: var(--radius); }
@keyframes swUpdFlash { 0%, 100% { box-shadow: 0 0 0 0 rgba(224,164,59,0); } 50% { box-shadow: 0 0 0 3px rgba(224,164,59,.9); } }

/* Settings list buttons */
.settings-list { display: flex; flex-direction: column; gap: 12px; max-width: 560px; }
.settings-item {
  display: flex; align-items: center; gap: 14px; width: 100%; text-align: left;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px; box-shadow: var(--shadow); font-size: 14px; color: var(--ink);
}
.settings-item:hover { border-color: var(--green); background: var(--green-light); }
.settings-item .si-icon { font-size: 24px; line-height: 1; }
.settings-item .si-text { display: flex; flex-direction: column; flex: 1; gap: 2px; }
.settings-item .si-text .muted { font-size: 12.5px; }
.settings-item .si-arrow { font-size: 24px; color: var(--muted); }
/* inventory groups manager */
.grp-list { max-height: 50vh; overflow-y: auto; }
.grp-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 2px; border-bottom: 1px solid var(--line); }
.grp-row:last-child { border-bottom: 0; }
.grp-name { font-size: 14px; }

/* Invoice sheet */
/* the invoice view: let the sheet grow to fill the screen so there's no grey gap.
   Class-based (not :has) + min-height:100vh flex column = works in Safari too. */
/* White background on the whole invoice view so no grey ever shows through,
   even if a browser (Brave/Safari) doesn't paint the flex-grown sheet area. */
main.invoice-view { display: flex; flex-direction: column; min-height: 100vh; background: #fff; }
.inv-sheet { background: #fff; padding: 44px 48px; border: 1px solid var(--line); border-radius: var(--radius);
  flex: 1 0 auto; box-shadow: var(--shadow); display: flex; flex-direction: column; }
/* zebra rows on the invoice document - soft grey-green, so the hover/active green stays its own thing */
.inv-sheet tbody tr:nth-child(even) td { background: #f4f7f6; }
.inv-footer { margin-top: auto; padding-top: 40px; color: var(--muted); font-size: 13px; line-height: 1.6; }
.inv-head { display: flex; justify-content: space-between; margin-bottom: 34px; }
.inv-head h1 { margin: 0 0 14px; font-size: 24px; color: var(--green-dark); }
.inv-head .company-lines { line-height: 1.6; }
.inv-total-row { display: flex; justify-content: flex-end; margin-top: 28px; }
.inv-totals { width: 340px; }
.inv-totals div { display: flex; justify-content: space-between; gap: 18px; padding: 4px 0; }
.inv-totals .inv-usd span:first-child, .inv-totals .inv-paid-note { white-space: nowrap; }
.inv-totals .grand { font-weight: 700; font-size: 17px; border-top: 2px solid var(--ink); margin-top: 6px; padding-top: 8px; }
/* Each part already taken on a part-paid invoice: quieter than the totals around it, and its
   label may wrap because it carries a date, a method and sometimes a foreign-money note. */
.inv-totals .inv-part { font-size: 12.5px; color: var(--muted); align-items: baseline; }
.inv-totals .inv-part span:first-child { text-align: left; }

@media print {
  .sidebar, .page-head .btn, .no-print { display: none !important; }
  /* Force a white page everywhere so the app's grey background never prints as a
     grey block below the invoice on the last page. */
  html, body { background: #fff !important; }
  main, main.invoice-view { padding: 0; display: block; min-height: 0; background: #fff !important; }
  /* Keep the browser's default page margins so the logo isn't clipped.
     min-height:100vh makes the sheet fill at least one page, so on a SHORT
     invoice the footer still sits at the bottom of the page. For a 2-page bill
     a small script (see _invoicePrintFooter) grows the sheet to ~2 pages so the
     footer drops to the bottom of page 2 as well. */
  /* A comfortable margin inside the paper, so the content never prints flush to the page edge
     even when the browser's own page margin is set to None. box-sizing:border-box (set globally)
     keeps this within the 100vh sheet, so it does not spill onto a second page. */
  .inv-sheet { border: 0; min-height: 100vh; box-shadow: none; padding: 8mm 14mm; flex: none; background: #fff !important; }
  /* print every line in solid black; keep ONLY the logo green */
  .inv-sheet, .inv-sheet * { color: #000 !important; }
  .inv-sheet h1 { color: #1f6b68 !important; }
  /* Clean pagination for long invoices: repeat the ITEM/PRICE/QTY/AMOUNT header
     on each page, never split a single row, and keep the totals + footer whole. */
  .inv-sheet table { page-break-inside: auto; }
  .inv-sheet thead { display: table-header-group; }
  .inv-sheet tr { page-break-inside: avoid; }
  /* The document always prints on white paper, whatever theme is on screen. The table wrap and
     header carry a themed background that would print dark in dark mode, so pin them light here.
     This is the belt to the braces of the light-palette override on .inv-sheet. */
  .inv-sheet .table-wrap { background: #fff !important; box-shadow: none !important; border-color: #e2e8e7 !important; }
  .inv-sheet thead th, .inv-sheet th { background: #f7fafa !important;
    -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .inv-sheet tbody tr:nth-child(odd) td { background: #fff !important; }
  /* keep the zebra rows on paper too (browsers skip backgrounds otherwise) */
  .inv-sheet tbody tr:nth-child(even) td { background: #f4f7f6 !important;
    -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .inv-total-row { page-break-inside: avoid; break-inside: avoid; }
  /* The bank/CRIB footer now flows at the END of the document (bottom of the
     LAST page) rather than being fixed on every page, so it never lands on top
     of the items. margin-top:auto keeps it pinned to the bottom on a 1-page bill. */
  .inv-footer { position: static; margin-top: auto; padding: 28px 0 0; break-inside: avoid; page-break-inside: avoid; }
}

/* ---- Printable customer list ---- */
#print-root { display: none; }
@page cust-list { size: A4 landscape; margin: 14mm; }
@media print {
  /* when printing the list, hide the whole app and show only the print sheet */
  body.printing-list #app,
  body.printing-list #login,
  body.printing-list #modal-root,
  body.printing-list #toast { display: none !important; }
  /* A little inner padding so the sheet never prints flush to the paper even when the browser's
     own page margin is set to None. */
  body.printing-list #print-root { display: block !important; page: cust-list; color: #000; padding: 3mm 4mm; }

  #print-root .print-head h1 { font-size: 17pt; margin: 0 0 3px; color: #1f6b68; font-weight: 800; letter-spacing: .2px; }
  #print-root .print-meta { font-size: 8.5pt; color: #6b7d7d; margin: 0 0 15px; padding-bottom: 11px;
    border-bottom: 1px solid #d8e2e0; }
  /* list-only table styling (scoped so it never restyles an invoice sheet in print-root) */
  /* table-layout:fixed + colgroup %s + width:100% => columns can never run off the page */
  body.printing-list #print-root table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 9pt; }
  /* Appointment day sheet. Each day starts a new page so a doctor is handed one sheet for
     their day rather than a roll of everyone's, and no row is split across a page break. */
  body.printing-list #print-root .appt-print-day + .appt-print-day { break-before: page; page-break-before: always; }
  body.printing-list #print-root .appt-print-day { margin-bottom: 16px; }
  body.printing-list #print-root .appt-print-day h2 { font-size: 13pt; margin: 0 0 9px; padding-bottom: 6px;
    border-bottom: 2px solid #1f6b68; color: #1f6b68; display: flex; align-items: baseline; font-weight: 800; }
  body.printing-list #print-root .appt-print-count { font-size: 8.5pt; font-weight: 500; color: #6b7d7d;
    margin-left: auto; letter-spacing: .3px; }
  body.printing-list #print-root .appt-print-day tbody tr { break-inside: avoid; page-break-inside: avoid; }
  /* Cleaner report look for the day sheet: no boxed grid, just a header rule and light row
     separators with zebra shading and roomier cells. Scoped to .appt-print-day, so the customer
     list keeps its own grid from the base rule below. */
  body.printing-list #print-root .appt-print-day th,
  body.printing-list #print-root .appt-print-day td { border: 0; border-bottom: 1px solid #dbe4e2; padding: 7px 10px; }
  body.printing-list #print-root .appt-print-day thead th { background: #e8f5f5 !important; color: #1f5b58;
    font-size: 8pt; font-weight: 800; text-transform: uppercase; letter-spacing: .6px; border-bottom: 1.5px solid #bcd8d5; }
  body.printing-list #print-root .appt-print-day tbody tr:nth-child(even) td { background: #f4f8f7;
    -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* Short values only. "30 min" or "01:30" split over two lines doubles every row's height. */
  body.printing-list #print-root .appt-print-day .nw { white-space: nowrap; }
  body.printing-list #print-root th, body.printing-list #print-root td {
    border: 1px solid #999; padding: 4px 6px; text-align: left; vertical-align: top;
    overflow-wrap: anywhere; word-break: break-word;
  }
  body.printing-list #print-root th { background: #e8f5f5 !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  body.printing-list #print-root thead { display: table-header-group; }   /* repeat header on every page */
  body.printing-list #print-root tr { page-break-inside: avoid; }

  /* Paper is white whatever the screen theme is.
     Reports print through this same #print-root path, and every one of them is drawn from the
     palette variables: tr.rep-sec uses --th-bg, tr.rep-total uses --card and a --ink rule,
     tr.coa-main mixes --green into --card. In dark mode those variables are dark, so a printed
     Profit and Loss came out as near-black bands on white paper with the totals rule invisible.
     Re-declaring the LIGHT palette here flips all seventeen reports at once, which is the whole
     reason the app was written against variables. Chasing it row by row would have missed one. */
  body.printing-list #print-root,
  body.printing-inv #print-root {
    --ink: #1d2b2b; --muted: #6b7d7d; --line: #e2e8e7;
    --bg: #ffffff; --card: #ffffff; --field-bg: #ffffff; --field-fg: #1d2b2b;
    --green: #2f8f8b; --green-dark: #1f6b68; --green-light: #e8f5f5;
    --th-bg: #f7fafa; --green-line: #bfe3e0; --title-bar: #dfe9e7;
    --tint-amber: #fdf3d7; --tint-red: #fdeaea; --tint-gray: #eef1f0;
    --danger: #c0392b; --amber: #b8860b;
    --shadow: none;
    color-scheme: light;
    background: #fff;
  }
  /* The screen card these tables sit in carries a themed fill and a shadow. On paper it is just
     the sheet. */
  body.printing-list #print-root .table-wrap,
  body.printing-list #print-root .rep-owed { background: #fff; box-shadow: none; }
  /* Browsers drop background fills when printing unless told otherwise, and on a financial
     report the shading IS the structure: section headers, subtotal bands, tinted parent rows.
     Without this the rows print as undifferentiated text and the grouping is lost. */
  body.printing-list #print-root tr.rep-sec td,
  body.printing-list #print-root tr.rep-total td,
  body.printing-list #print-root tr.coa-sec td,
  body.printing-list #print-root tr.coa-main > td,
  body.printing-list #print-root tr.coa-sub > td {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }

  /* printing ONE invoice from the browsing sheet: hide the app, show only the
     shared .inv-sheet rendered into #print-root - the same template the invoice
     page prints (its @media print rules above apply to it unchanged). */
  body.printing-inv #app,
  body.printing-inv #login,
  body.printing-inv #modal-root,
  body.printing-inv #toast { display: none !important; }
  body.printing-inv #print-root { display: block !important; color: #000; }
}
@media (max-width: 800px) {
  .grid2 { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .sidebar { width: 64px; }
  .side-brand span:not(.leaf), #nav a span:not(.ic), .side-foot, .wa-upd { display: none !important; }
}

/* ===== Appointments: month calendar + day timeline ===== */
/* The padding used to come from `.ws-win .cal-layout`, which only applied while the calendar
   was a window inside the Workspace. It is its own page now and never in a window, so that rule
   is dead and the month grid sat hard against the green band. */
.cal-layout { display: flex; gap: 20px; align-items: flex-start; padding: 18px; }
.cal-side { position: relative; width: 300px; flex: none; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 14px; }
.cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.cal-head b { font-size: 15px; }
.cal-title-btn { display: inline-flex; align-items: center; gap: 5px; background: none; border: 0; padding: 4px 6px; margin: -4px -6px; border-radius: 6px; font-size: 15px; font-weight: 700; color: var(--ink); cursor: pointer; }
.cal-title-btn:hover { background: var(--green-light); color: var(--green-dark); }
.cal-caret { font-size: 10px; color: var(--muted); }
/* month / year jump picker */
.cal-picker { position: absolute; left: 14px; right: 14px; top: 48px; bottom: 14px; background: var(--card); z-index: 6; flex-direction: column; }
.cal-picker[hidden] { display: none; }
.cal-picker:not([hidden]) { display: flex; }
.cal-pick-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.cal-pick-year { background: none; border: 0; font-size: 15px; font-weight: 700; color: var(--ink); cursor: pointer; padding: 4px 10px; border-radius: 6px; }
.cal-pick-year:hover { background: var(--green-light); color: var(--green-dark); }
.cal-pick-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; flex: 1; align-content: center; }
.cal-pick-cell { border: 1px solid var(--line); background: var(--card); border-radius: 8px; padding: 12px 0; cursor: pointer; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.cal-pick-cell:hover { border-color: var(--green); background: var(--green-light); color: var(--green-dark); }
.cal-pick-cell.sel { background: var(--green); border-color: var(--green); color: var(--on-green); }
.cal-navs { display: flex; gap: 4px; }
.cal-nav { width: 28px; height: 28px; border: 0; background: none; border-radius: 6px; cursor: pointer; font-size: 17px; color: var(--muted); }
.cal-nav:hover { background: var(--green-light); color: var(--green-dark); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-dow { text-align: center; font-size: 11px; color: var(--muted); font-weight: 600; padding: 4px 0; }
.cal-day { position: relative; aspect-ratio: 1; border: 0; background: none; cursor: pointer; border-radius: 8px; font-size: 13px; color: var(--ink); display: flex; align-items: center; justify-content: center; }
.cal-day:hover { background: var(--green-light); }
.cal-day.other { color: #b7c2c0; }
.cal-day.today .cal-num { color: var(--green-dark); font-weight: 700; }
.cal-day.sel { background: var(--green); }
.cal-day.sel .cal-num { color: var(--on-green); font-weight: 700; }
.cal-day.sel:hover { background: var(--green-dark); }
.cal-dot { position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%); width: 5px; height: 5px; border-radius: 50%; background: #9fb3b2; }
.cal-dot.pend { background: var(--amber); }
.cal-day.sel .cal-dot { background: rgba(255,255,255,.9); }
.cal-legend { margin-top: 12px; font-size: 11px; color: var(--muted); display: flex; align-items: center; }
.cal-legend .cal-dot { position: static; transform: none; display: inline-block; margin: 0 4px; }

/* Per-user seat billing: the explanation and the per-person list on the Subscription page.
   The computed total lives on its own .sub-status-row, never inside .sub-price, which is
   26px/800/nowrap and would overflow the plan row on a phone. */
.sub-note { margin: 12px 0 0; font-size: 12.5px; line-height: 1.55; color: var(--muted); }
.sub-seats { margin-top: 12px; border-top: 1px solid var(--line); }
.sub-seat-row { display: flex; align-items: baseline; gap: 10px; padding: 7px 0;
  border-bottom: 1px solid var(--line); font-size: 13px; }
.sub-seat-row > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sub-seat-row > span i { color: var(--muted); font-style: normal; font-size: 12px; }
.sub-seat-row > b { white-space: nowrap; }
.sub-seat-row > em { flex: 0 0 auto; color: var(--muted); font-style: normal; font-size: 12px;
  white-space: nowrap; }
@media (max-width: 520px) {
  .sub-seat-row { flex-wrap: wrap; }
  .sub-seat-row > em { flex-basis: 100%; }
}

/* "Hours to show" presets, and the print column chooser. */
.hours-presets { display: flex; flex-wrap: wrap; gap: 8px; }
.hours-preset { padding: 7px 12px; font-size: 13px; }
.hours-preset.on { background: var(--green); border-color: var(--green); color: var(--on-green); }
.print-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 14px; }
.print-cols label { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 500;
  padding: 5px 7px; border-radius: 7px; cursor: pointer; }
.print-cols label:hover { background: var(--bg); }
.print-cols input { width: 15px; height: 15px; accent-color: var(--green); }

.day-col { flex: 1; min-width: 0; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.day-head { display: flex; align-items: center; gap: 13px; padding: 13px 16px; border-bottom: 1px solid var(--line); background: linear-gradient(180deg, var(--card), rgba(0,0,0,.012)); }
.dh-badge { display: flex; flex-direction: column; align-items: center; justify-content: center; min-width: 50px; padding: 5px 9px 6px; background: var(--green-light); border-radius: 12px; line-height: 1; flex: none; }
.dh-badge-dow { font-size: 10px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--green-dark); opacity: .85; }
.dh-badge-num { font-size: 22px; font-weight: 800; color: var(--green-dark); margin-top: 3px; }
.dh-badge.today { background: var(--green); box-shadow: 0 2px 8px rgba(46,120,125,.28); }
.dh-badge.today .dh-badge-dow { color: var(--on-green); opacity: .92; }
.dh-badge.today .dh-badge-num { color: var(--on-green); }
.dh-titles { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.dh-weekday { font-size: 16px; font-weight: 700; color: var(--ink); line-height: 1.2; }
.dh-full { color: var(--muted); font-size: 13px; }
.dh-today-pill { margin-left: auto; align-self: center; font-size: 11px; font-weight: 700; color: var(--green-dark); background: var(--green-light); border: 1px solid var(--green); padding: 3px 11px; border-radius: 999px; text-transform: uppercase; letter-spacing: .04em; }
.day-scroll { position: relative; display: flex; height: calc(100vh - 230px); min-height: 460px; overflow-y: auto; }
.time-gutter { position: relative; width: 56px; flex: none; }
.hour-lbl { position: absolute; right: 8px; font-size: 11px; color: var(--muted); }
.events-track { position: relative; flex: 1; border-left: 1px solid var(--line); cursor: copy; }
.hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--line); }
.now-line { position: absolute; left: 0; right: 0; height: 0; border-top: 2px solid var(--danger); z-index: 5; }
.now-line::before { content: ""; position: absolute; left: -5px; top: -5px; width: 9px; height: 9px; border-radius: 50%; background: var(--danger); }
.ev { position: absolute; display: flex; gap: 10px; align-items: flex-start; background: var(--green-light); border-left: 3px solid var(--green); border-radius: 5px; padding: 3px 7px; cursor: pointer; box-shadow: 0 1px 2px rgba(0,0,0,.08); z-index: 1; }
.ev:hover { box-shadow: 0 2px 8px rgba(0,0,0,.16); z-index: 6; }
.ev-main { flex: 0 1 auto; min-width: 0; max-width: 55%; }
.ev-t { font-size: 10.5px; color: var(--green-dark); font-weight: 600; white-space: nowrap; }
.ev-n { font-size: 12.5px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the note sits to the RIGHT of the time/name, filling the free horizontal space */
.ev-note { flex: 1 1 0; min-width: 0; align-self: center; font-size: 11px; color: var(--muted); white-space: pre-wrap; overflow-wrap: anywhere; }
/* Outcome colours for calendar blocks. One meaning per colour, matching the status badges in the
   lists: still to happen is amber, seen is green, did not turn up fades grey, called off is red.
   Mixed against --card so they hold up in both themes. */
.ev.out-pending { background: color-mix(in srgb, var(--amber) 22%, var(--card)); border-left-color: var(--amber); }
.ev.out-pending .ev-t { color: var(--amber); }
/* Booked but not finished yet: nothing is owed and nobody is waiting, so it stays plain. It turns
   amber on its own once the end time passes. Kept as a clean card rather than a grey fill, so it
   never reads as the faded grey of a no-show. */
.ev.out-pending.ev-upcoming { background: var(--card); border-left-color: color-mix(in srgb, var(--ink) 32%, transparent); }
.ev.out-pending.ev-upcoming .ev-t { color: var(--muted); }
.ev.out-done { background: var(--green-light); border-left-color: var(--green); }
.ev.out-done .ev-t { color: var(--green-dark); }
.ev.out-noshow { background: color-mix(in srgb, var(--muted) 20%, var(--card)); border-left-color: var(--muted); opacity: .88; }
.ev.out-noshow .ev-t { color: var(--muted); }
.ev.out-cancelled { background: var(--tint-red); border-left-color: var(--danger); opacity: .9; }
.ev.out-cancelled .ev-n { text-decoration: line-through; color: var(--danger); }
.ev.out-cancelled .ev-t { color: var(--danger); }
/* bill / invoice button on the right of each appointment block */
.ev-bill { flex: none; margin-left: auto; align-self: center; width: 26px; height: 26px; border: 1px solid var(--line); background: var(--card); border-radius: 6px; cursor: pointer; font-size: 13px; line-height: 1; display: flex; align-items: center; justify-content: center; padding: 0; }
.ev-bill:hover { border-color: var(--green); background: var(--green-light); }
.ev-bill.billed { border-color: var(--green); }
.badge.sm { padding: 1px 7px; font-size: 10.5px; vertical-align: middle; }
/* PAID watermark on a paid invoice sheet */
.inv-sheet.pastdue-stamp { position: relative; }
.inv-sheet.pastdue-stamp::after { content: "PAST DUE"; position: absolute; top: 120px; right: 48px; z-index: 5;
  font-size: 54px; font-weight: 800; letter-spacing: 4px; color: rgba(179,38,30,.22);
  border: 6px solid rgba(179,38,30,.22); border-radius: 12px; padding: 6px 22px; transform: rotate(-14deg); pointer-events: none; }
.inv-sheet.paid-stamp { position: relative; }
.inv-sheet.paid-stamp::after { content: "PAID"; position: absolute; top: 120px; right: 48px; z-index: 5; font-size: 60px; font-weight: 800; letter-spacing: 4px; color: rgba(47,143,139,.22); border: 6px solid rgba(47,143,139,.22); border-radius: 12px; padding: 6px 22px; transform: rotate(-14deg); pointer-events: none; }
/* keep the stamp above the items table in every engine (table cells can create
   their own stacking); the sticky header sits below it */
.inv-sheet.paid-stamp .table-wrap { z-index: 0; }
/* Stamp toggle (the button on the invoice toolbar): suppress the PAID/UNPAID/PAST DUE/REFUNDED
   stamp on screen and in print. Wins over each stamp's own ::after via !important. */
.inv-sheet.stamp-off::after { display: none !important; content: none !important; }
/* UNPAID stamp (amber) on an open invoice that isn't overdue yet */
.inv-sheet.unpaid-stamp { position: relative; }
.inv-sheet.unpaid-stamp::after { content: "UNPAID"; position: absolute; top: 120px; right: 40px; z-index: 5;
  font-size: 54px; font-weight: 800; letter-spacing: 4px; color: rgba(184,134,11,.22);
  border: 6px solid rgba(184,134,11,.22); border-radius: 12px; padding: 6px 22px; transform: rotate(-14deg); pointer-events: none; }
/* PARTLY PAID stamp (amber) - money has arrived, the invoice is not settled. Narrower letter
   spacing and a smaller size than UNPAID because the word is twice as long and would otherwise
   run off the right edge of the sheet. */
.inv-sheet.partly-stamp { position: relative; }
.inv-sheet.partly-stamp::after { content: "PARTLY PAID"; position: absolute; top: 120px; right: 30px; z-index: 5;
  font-size: 38px; font-weight: 800; letter-spacing: 2px; color: rgba(184,134,11,.22);
  border: 6px solid rgba(184,134,11,.22); border-radius: 12px; padding: 6px 20px; transform: rotate(-14deg); pointer-events: none; }
/* REFUNDED stamp (amber) */
.inv-sheet.refunded-stamp { position: relative; }
.inv-sheet.refunded-stamp::after { content: "REFUNDED"; position: absolute; top: 120px; right: 30px; z-index: 5; font-size: 44px; font-weight: 800; letter-spacing: 3px; color: rgba(184,134,11,.22); border: 6px solid rgba(184,134,11,.22); border-radius: 12px; padding: 6px 20px; transform: rotate(-14deg); pointer-events: none; }
/* store-credit row inside the invoice form */
.iv-credit { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 4px 0 2px; padding: 10px 12px; background: var(--green-light); border: 1px solid #9fd9d1; border-radius: 8px; font-size: 13.5px; }
.iv-credit[hidden] { display: none; }
.iv-credit-avail { color: var(--green-dark); }
.iv-credit-apply { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-weight: 600; }
.iv-credit-apply input { width: 90px; }
@media (max-width: 720px) { .cal-layout { flex-direction: column; } .cal-side { width: 100%; } }

/* ---------- Email / webmail client ---------- */
.mail-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
.mail-tabs-group { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mail-filter { border: 1px solid var(--line); background: var(--card); padding: 8px 16px; border-radius: 8px; font-size: 13.5px; font-weight: 600; color: var(--muted); cursor: pointer; }
.mail-filter:hover { border-color: var(--green); color: var(--green-dark); }
.mail-filter.active { background: var(--green); border-color: var(--green); color: var(--on-green); }
.mail-empty { border: 1px solid #e5b3b3; background: var(--tint-red); color: var(--danger); padding: 8px 16px; border-radius: 8px; font-size: 13.5px; font-weight: 600; cursor: pointer; }
.mail-empty:hover { background: #c0392b; border-color: var(--danger); color: #fff; }
.mail-empty:disabled { opacity: .5; cursor: default; }
.mail-tabs { display: inline-flex; background: var(--th-bg); border: 1px solid var(--line);
  border-radius: 9px; padding: 3px; }
.mail-tab { border: 0; background: none; padding: 7px 18px; border-radius: 6px; font-size: 13.5px; font-weight: 600; color: var(--muted); cursor: pointer; }
.mail-tab { transition: background .12s, color .12s; }
.mail-tab:hover { color: var(--ink); background: color-mix(in srgb, var(--green) 10%, transparent); }
.mail-tab.active { background: var(--green); color: var(--on-green); box-shadow: none; }
.mail-tab.active:hover { background: var(--green); }
.mail-search-wrap { display: flex; gap: 8px; align-items: center; flex: 1; justify-content: flex-end; }
.mail-search { flex: 1; min-width: 160px; max-width: 320px; padding: 9px 12px; border: 1px solid var(--line); border-radius: 8px; font-size: 13.5px; }
.mail-filter-btn { flex: none; border: 1px solid var(--line); background: var(--card); padding: 9px 14px; border-radius: 8px; font-size: 13.5px; font-weight: 600; color: var(--muted); cursor: pointer; white-space: nowrap; }
.mail-filter-btn:hover { border-color: var(--green, #2f8f8b); color: var(--green, #2f8f8b); }
.mail-filter-btn.on { background: var(--green); border-color: var(--green); color: var(--on-green); }   /* a filter is active */
.mail-chk { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 500; cursor: pointer; padding-top: 4px; }
.mail-chk input { width: 16px; height: 16px; }
.mail-search:focus { outline: 2px solid var(--green); border-color: var(--green); }
.mail-split { display: flex; gap: 10px; align-items: flex-start; }
.mail-list { width: 340px; flex-shrink: 0; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; max-height: calc(100vh - 176px); overflow-y: auto; }

/* Drag handle between the message list and the reading pane - a faint grip line
   that's always a little visible so you can find it, and turns green on hover/drag. */
.mail-resize {
  flex: 0 0 8px; align-self: stretch; min-height: calc(100vh - 176px);
  cursor: col-resize; position: relative; background: transparent;
}
.mail-resize::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 4px; border-radius: 4px; background: #cbd5d4; transition: background .15s;
}
.mail-resize:hover::before, .mail-resize.dragging::before { background: var(--green); }
/* Preview pane OFF: hide the reading pane + divider, let the list fill the width */
.mail-split.no-preview .mail-read, .mail-split.no-preview .mail-resize { display: none; }
.mail-split.no-preview .mail-list { width: 100% !important; }
#mail-preview-toggle.active { background: var(--green-light); border-color: var(--green); color: var(--green-dark); }
.mail-item { position: relative; padding: 11px 14px; border-bottom: 1px solid var(--line); cursor: pointer; user-select: none; }
.mail-item.checked { background: color-mix(in srgb, #3b82f6 15%, var(--card)); box-shadow: inset 3px 0 0 #3b82f6; }
.mail-item.checked.sel { background: color-mix(in srgb, #3b82f6 24%, var(--card)); }
.mail-del { position: absolute; top: 8px; right: 8px; display: none; border: 0; background: transparent; cursor: pointer; font-size: 14px; line-height: 1; padding: 4px 7px; border-radius: 6px; color: var(--muted); }
.mail-item:hover .mail-del { display: inline-flex; }
.mail-item:hover .mi-date { visibility: hidden; }   /* trash takes the date's spot on hover */
.mail-del:hover { background: var(--tint-red); color: var(--danger); }
.mail-del:disabled { opacity: .5; cursor: default; }
.mail-item:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); }
.mail-item.sel { background: color-mix(in srgb, var(--green) 15%, var(--card)); }
.mail-item.unread .mi-from, .mail-item.unread .mi-subj { font-weight: 700; color: var(--ink); }
.mail-item.unread { border-left: 3px solid var(--green); padding-left: 11px; }
.mi-row { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.mi-from { font-size: 13.5px; color: color-mix(in srgb, var(--ink) 82%, var(--muted)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mi-date { font-size: 11.5px; color: var(--muted); flex-shrink: 0; }
.mi-subj { font-size: 12.5px; color: var(--muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail-more-wrap { padding: 12px; text-align: center; }
.mail-read { flex: 1; min-width: 0; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; min-height: 300px; max-height: calc(100vh - 176px); overflow-y: auto; }
.mail-read-empty { padding: 60px 20px; text-align: center; }
.mr-head { border-bottom: 1px solid var(--line); padding-bottom: 12px; margin-bottom: 14px; }
.mr-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.mr-actions { display: flex; gap: 6px; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.mr-subj { margin: 0 0 8px; font-size: 19px; }
.mr-meta { font-size: 13px; margin-top: 2px; }
.mr-when { margin-left: 8px; }
.mr-atts { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }

/* Double-click pop-out email window (Outlook-style) */
.modal.mail-window { width: 940px; max-width: 96vw; }
.modal.mail-window .modal-body { max-height: 78vh; overflow-y: auto; }
.mw-toolbar { display: flex; gap: 8px; flex-wrap: wrap; padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--line); }
.mw-meta { font-size: 13px; margin: 3px 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.mw-when { margin-left: auto; }
.mw-body { margin-top: 14px; }
.mw-body .mail-frame { width: 100%; border: 0; min-height: 200px; }
.mw-body .mail-text { white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 1.5; }
.mail-att { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; padding: 5px 6px 5px 10px; background: #f4f6f5; border: 1px solid var(--line); border-radius: 6px; }
.mail-att:hover { background: var(--green-light); }
.mail-att a { text-decoration: none; color: var(--green-dark); }
.mail-att-open:hover { text-decoration: underline; }
.mail-att-dl { border-left: 1px solid var(--line); padding: 0 6px 0 8px; font-size: 14px; line-height: 1; }
.mail-att-dl:hover { color: #111; }
.mc-sig-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.sig-prev { margin-top: 6px; padding: 10px; border: 1px dashed var(--line); border-radius: 8px; background: #fafcfc; display: flex; align-items: center; justify-content: center; min-height: 60px; }
.sig-prev img { max-width: 100%; max-height: 160px; height: auto; border-radius: 4px; }
.mail-frame { width: 100%; border: 0; min-height: 200px; }
.mail-text { white-space: pre-wrap; word-wrap: break-word; font-size: 14px; line-height: 1.5; }
.mail-text a { color: var(--green-dark); }
@media (max-width: 820px) { .mail-split { flex-direction: column; } .mail-list { width: 100%; max-height: 320px; } }

/* ---------- Company Details: repeatable bank / currency rows ---------- */
.cd-sec-label { display: block; font-size: 11.5px; font-weight: 700; color: var(--muted); margin: 18px 0 6px; text-transform: uppercase; letter-spacing: .3px; }
.cd-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.cd-row input { flex: 1; padding: 9px 11px; border: 1px solid var(--line); border-radius: 8px; font-size: 14px; }
.cd-row input:focus { outline: 2px solid var(--green); border-color: var(--green); }
.cd-x { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: 15px; padding: 4px 9px; border-radius: 6px; flex-shrink: 0; }
.cd-x:hover { background: var(--tint-red); color: var(--danger); }

/* ---- Licensing: lock screen + reminder banner ---- */
/* Scrollable, and in the product's own colours.
   NOT align-items:center. A centred flex item that grows taller than the viewport overflows in
   BOTH directions, so the top goes off-screen and cannot be reached however you scroll - which
   is what happened once Stripe's embedded checkout was mounted inside the card. margin:auto on
   the child centres it while there is room and lets it start at the top once there is not,
   and overflow-y here gives the overlay something to scroll. */
#lock-screen { position: fixed; inset: 0; z-index: 5000; display: flex;
  justify-content: center; overflow-y: auto; padding: 20px;
  background: linear-gradient(135deg, var(--green) 0%, var(--green-dark) 100%); }
.lock-card { background: var(--card); border-radius: 16px; padding: 36px 40px; max-width: 480px; width: 100%;
  margin: auto; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,.4); }
.lock-card .lock-icon { font-size: 40px; margin-bottom: 6px; }
.lock-card h2 { margin: 0 0 10px; }
.lock-card textarea { width: 100%; margin-top: 14px; padding: 10px; border: 1px solid var(--line);
  border-radius: 8px; font-family: ui-monospace, Menlo, monospace; font-size: 12px; resize: vertical; }
.lock-card .btn { width: 100%; margin-top: 12px; }
.lock-error { color: var(--danger); font-size: 13px; min-height: 18px; margin-top: 6px; }
.lock-links { margin-top: 14px; font-size: 13px; display: flex; flex-direction: column; gap: 8px; }
.lock-links a { color: var(--green-dark); }
#license-banner { position: fixed; bottom: 18px; right: 18px; z-index: 900; display: flex;
  align-items: center; gap: 10px; background: #fff8e6; border: 1px solid #e8d9a8; color: #6b5b1e;
  border-radius: 10px; padding: 9px 12px; font-size: 13px; box-shadow: 0 6px 24px rgba(0,0,0,.12); }
#license-banner button { border: 0; background: var(--green-dark); color: var(--on-green); border-radius: 7px;
  padding: 5px 10px; font-size: 12.5px; cursor: pointer; }
#license-banner i { cursor: pointer; font-style: normal; color: #9a8a4a; padding: 0 2px; }
.lic-row { display: flex; justify-content: space-between; gap: 16px; padding: 7px 0;
  border-bottom: 1px solid var(--line); font-size: 14px; }
.lic-row span { color: var(--muted); }

/* Subscribe buttons (lock screen + trial banner) */
.lock-card .lock-subscribe { width: 100%; margin-bottom: 6px; background: var(--green); }
#license-banner .lb-subscribe { background: var(--green-dark); color: var(--on-green); }

/* Sidebar Subscription link - matches the regular nav items (#nav a) */
.side-sub {
  display: flex; align-items: center; gap: 10px; padding: 11px 12px 11px 20px; color: #b9cdcb;
  text-decoration: none; font-size: 14px; font-weight: 500; border-left: 3px solid transparent;
}
.side-sub:hover { background: rgba(255,255,255,.05); color: #fff; }
.side-sub.active { background: color-mix(in srgb, var(--green) 22%, transparent); color: #fff; border-left-color: var(--green); }
.side-sub .ic { width: 20px; text-align: center; font-size: 16px; }
.side-sub-days { margin-left: auto; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 10px; white-space: nowrap; }
.side-sub-days:empty { display: none; }
.side-sub-days.trial { background: rgba(184,134,11,.28); color: #e8c274; }
.side-sub-days.grace { background: rgba(192,57,43,.24); color: #e79684; }
.side-sub-days.soon  { background: color-mix(in srgb, var(--green) 30%, transparent); color: var(--green); }
.side-sub-days.ok    { background: color-mix(in srgb, var(--green) 26%, transparent); color: var(--green); }
/* Only the LABEL span flexes (grows to fill, truncates with … when tight) so a wide
   badge never spills past the sidebar edge. Exclude the badge spans - otherwise they'd
   get flex:1 too and stretch across the row instead of hugging their text. */
.side-sub > span:not(.ic):not(.side-sub-days),
#nav a > span:not(.ic):not(.nav-badge) {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.side-sub-days, .nav-badge { flex: 0 0 auto; }   /* natural width, anchored right, never stretch */

/* In-app Control Panel - the same dark console as the desktop Sealuno Control app.
   Palette lifted from control_panel.html so the two never drift apart. */
.ctrl-dark {
  --c-panel: #151f1f;
  --c-panel-2: #111a1a;
  --c-ink: #eaf3f3;
  --c-ink-soft: #adbdbc;
  --c-ink-faint: #7c8d8c;
  --c-line: #24302f;
  --c-brand: #2fcebc;
  --c-good: #37d977;
  --c-good-glow: rgba(55,217,119,.5);
  --c-off: #5f6f6e;
  background:
    radial-gradient(1200px 700px at 15% -10%, #0e1617, transparent 60%),
    radial-gradient(1000px 600px at 100% 0%, #0a1110, transparent 55%),
    #0c1213;
  color: var(--c-ink);
  /* Fill the whole content area edge-to-edge (eat main's 26x32 padding) instead of
     floating as a rounded card. */
  margin: -26px -32px;
  min-height: 100vh;
  padding: 40px 32px 48px;
}
/* Centre a narrower column of controls inside the full-width dark background. */
.ctrl-inner { max-width: 960px; margin: 0 auto; }
.ctrl-head { display: flex; align-items: center; gap: 14px; margin-bottom: 22px; }
.ctrl-head h2 { margin: 0; font-size: 22px; color: var(--c-ink); }
.ctrl-head-sub { font-size: 13px; color: var(--c-ink-faint); font-weight: 500; }
.ctrl-mark {
  width: 44px; height: 44px; border-radius: 13px; flex: 0 0 auto;
  background: linear-gradient(160deg, #2fcebc, #27b8ab);
  display: grid; place-items: center;
  box-shadow: 0 6px 16px rgba(55,217,119,.32);
}
.ctrl-wait { padding: 30px 0; text-align: center; color: var(--c-ink-faint); font-size: 14px; }

.ctrl-cards { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.ctrl-card {
  flex: 1; min-width: 190px; background: var(--c-panel-2); border: 1px solid var(--c-line);
  border-radius: 14px; padding: 16px 18px; position: relative;
}
.ctrl-card.ok { border-color: rgba(55,217,119,.32); }
.ctrl-dot { width: 12px; height: 12px; border-radius: 50%; background: var(--c-off); margin-bottom: 10px; }
.ctrl-card.ok .ctrl-dot {
  background: var(--c-good);
  animation: ctrl-pulse 2.4s ease-in-out infinite;
}
@keyframes ctrl-pulse {
  0%, 100% { box-shadow: 0 0 10px 0 var(--c-good-glow); }
  50%      { box-shadow: 0 0 16px 3px var(--c-good-glow); }
}
.ctrl-lab { font-size: 11px; font-weight: 700; letter-spacing: .06em; color: var(--c-ink-faint); }
.ctrl-big { font-size: 19px; font-weight: 700; margin: 3px 0 2px; color: var(--c-ink); }
.ctrl-card.ok .ctrl-big { color: var(--c-good); }
.ctrl-sub { font-size: 12.5px; color: var(--c-ink-soft); }

.ctrl-urls { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; }
.ctrl-url {
  flex: 1; min-width: 240px; background: var(--c-panel-2); border: 1px solid var(--c-line);
  border-radius: 12px; padding: 12px 14px; display: flex; flex-direction: column; gap: 2px;
}
.ctrl-url .muted { font-size: 12px; }
.ctrl-url b { font-size: 14px; color: var(--c-ink); }
.ctrl-url .btn { align-self: flex-start; margin-top: 8px; padding: 5px 12px; font-size: 12.5px; }

.ctrl-acts { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.ctrl-acts .btn { flex: 1; min-width: 180px; }

.ctrl-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: var(--c-panel-2); border: 1px solid var(--c-line); border-radius: 12px;
  padding: 14px 16px; margin-bottom: 12px; flex-wrap: wrap;
}
.ctrl-row b { color: var(--c-ink); }
.ctrl-active-box { background: var(--c-panel-2); border: 1px solid var(--c-line); border-radius: 12px; padding: 14px 16px; margin-bottom: 12px; }
.ctrl-active-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.ctrl-active-head b { color: var(--c-ink); }
.ctrl-active-count { font-size: 12px; color: var(--c-ink-faint); }
.ctrl-active { display: flex; flex-direction: column; }
.ctrl-user { display: flex; align-items: center; gap: 10px; padding: 6px 2px; font-size: 13.5px; color: var(--c-ink); border-top: 1px solid var(--c-line); }
.ctrl-user:first-child { border-top: 0; }
.ctrl-user b { color: var(--c-ink); font-weight: 600; }
.ctrl-user-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--c-ink-faint); flex: none; }
.ctrl-user-dot.on { background: var(--c-good); box-shadow: 0 0 0 3px rgba(55,217,119,.18); }
.ctrl-user-dot.idle { background: #e0a83a; }
.ctrl-user-dot.away { background: var(--c-ink-faint); }
.ctrl-user-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctrl-user-status { margin-left: auto; font-size: 12.5px; color: var(--c-ink-faint); }
.ctrl-user-acts { display: flex; gap: 6px; align-items: center; flex: none; }
.ctrl-user-btn { background: transparent; border: 1px solid var(--c-line); color: var(--c-ink-faint);
  font-size: 11.5px; padding: 3px 9px; border-radius: 7px; cursor: pointer; white-space: nowrap; }
.ctrl-user-btn:hover { color: var(--c-ink); border-color: var(--c-ink-faint); }
.ctrl-user-btn.danger:hover { color: #ff8a8a; border-color: #ff8a8a; }
.row-suspended td { opacity: .55; }
.row-suspended td.row-actions { opacity: 1; }
.grp-row.row-suspended .grp-name { opacity: .55; }
.ctrl-dark .muted { color: var(--c-ink-faint); }
.ctrl-dark a { color: var(--c-brand); }

/* The app's light-grey buttons disappear on this surface, so re-theme them here. */
.ctrl-dark .btn.ghost {
  background: var(--c-panel); border-color: var(--c-line); color: var(--c-ink);
}
.ctrl-dark .btn.ghost:hover { border-color: var(--c-brand); color: var(--c-brand); }
.ctrl-dark .btn:not(.ghost) {
  background: linear-gradient(180deg, #2fcebc, #27b8ab);
  border-color: transparent; color: #071312; font-weight: 700;
}
.ctrl-dark .btn:not(.ghost):hover { filter: brightness(1.08); }

/* Sidebar collapse toggle - frees up screen width for the content */
.side-toggle {
  margin-left: auto; flex: none; background: none; border: 0; color: #8fb7b4;
  cursor: pointer; font-size: 21px; font-weight: 700; line-height: 1; padding: 4px 7px; border-radius: 6px;
}
.side-toggle:hover { background: rgba(255,255,255,.10); color: #fff; }

.sidebar.collapsed { width: 64px; }
.sidebar.collapsed .side-brand { padding: 18px 4px; justify-content: center; gap: 2px; }
.sidebar.collapsed .side-brand span:not(.leaf) { display: none; }   /* wordmark only; keep the shield */
.sidebar.collapsed .side-brand .leaf { font-size: 20px; }
.sidebar.collapsed .side-toggle { margin-left: 0; font-size: 19px; padding: 4px; }
.sidebar.collapsed #nav a,
.sidebar.collapsed .side-sub {
  justify-content: center; padding-left: 0; padding-right: 0; border-left-color: transparent;
}
.sidebar.collapsed #nav a span:not(.ic),
.sidebar.collapsed .side-sub span:not(.ic),
.sidebar.collapsed .side-sub-days,
.sidebar.collapsed .nav-badge,
.sidebar.collapsed .wa-upd { display: none !important; }
.sidebar.collapsed .side-foot { padding: 14px 0; text-align: center; }
.sidebar.collapsed .side-foot > div { display: none; }              /* the "Administrator" line */

/* Subscription page */
.sub-wrap { max-width: 640px; margin: 0 auto; }
.sub-card {
  background: var(--card); border: 1px solid var(--line); border-radius: 16px;
  padding: 26px; box-shadow: 0 1px 2px rgba(16,24,40,.05);
}
.sub-plan-row {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; padding-bottom: 18px; border-bottom: 1px solid var(--line);
}
.sub-plan { font-size: 18px; font-weight: 700; }
.sub-desc { color: var(--muted); font-size: 13px; margin-top: 3px; }
.sub-price { font-size: 26px; font-weight: 800; white-space: nowrap; }
.sub-price span { font-size: 14px; font-weight: 600; color: var(--muted); }
.sub-status-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 11px 0; border-bottom: 1px solid var(--line); font-size: 14px;
}
.sub-status-row > span:first-child { color: var(--muted); }
.sub-badge { font-weight: 600; font-size: 13px; }
.sub-badge.ok { color: #126d80; }
.sub-badge.trial { color: var(--amber); }
.sub-badge.exp { color: var(--danger); }
.sub-go { width: 100%; margin-top: 20px; font-size: 15px; padding: 13px; background: var(--green); }
.sub-secure { text-align: center; color: var(--muted); font-size: 12px; margin: 10px 0 0; }
.sub-embed { margin-top: 18px; }
.sub-embed-load {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 34px; text-align: center; color: var(--muted); font-size: 14px;
}
#sub-embed-mount {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 8px; min-height: 60px;
}

/* Account Charts import preview: colour-code what each row will do. */
.ai-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.ai-table th { text-align: left; padding: 7px 9px; background: var(--bg); border-bottom: 1px solid var(--line);
               position: sticky; top: 0; font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.ai-table td { padding: 7px 9px; border-bottom: 1px solid var(--line); vertical-align: top; }
.ai-table tr.ai-add td { background: #f2faf9; }
.ai-table tr.ai-skip td { color: var(--muted); }
.ai-table tr.ai-conflict td { background: var(--tint-red); }

/* Till mode: type item names, or scan them. Sits in the dark header beside the customer
   box, so it reads as a setting for this sheet rather than another field to fill in. */
.iv-mode { display: inline-flex; align-items: stretch; user-select: none; margin-left: 10px;
  padding: 3px; border-radius: 9px; background: rgba(0,0,0,.18);
  border: 1px solid rgba(255,255,255,.22); white-space: nowrap; }
.iv-mode-b { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; border: 0;
  padding: 6px 12px; border-radius: 7px; background: transparent; color: rgba(255,255,255,.72);
  font-size: 12.5px; font-weight: 600; letter-spacing: .2px; font-family: inherit;
  transition: background .13s, color .13s; }
.iv-mode-b:hover { color: #fff; background: rgba(255,255,255,.12); }
/* The active mode is a filled chip: which one you are in has to be readable at a glance
   from across a counter, not inferred from a tick. */
.iv-mode-b.on { background: var(--field-bg); color: var(--green-dark, #1e5c56); box-shadow: 0 1px 2px rgba(0,0,0,.18); }
.iv-mode-b.on:hover { background: var(--field-bg); }
.iv-mode-i { font-size: 11px; opacity: .8; }
.iv-mode-b.on .iv-mode-i { opacity: 1; }

/* ---- Dangerous zone + workspace archive (handover feature) ---- */
/* The only red block in Settings. It sits below the ordinary rows with a rule above it, so a
   destructive action never lines up flush with a harmless one. */
.dz { margin-top: 26px; border-top: 1px solid var(--line); padding-top: 16px; }
.dz-head { margin: 0 0 8px; font-size: 11px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--danger); }
.settings-item.danger:hover { border-color: var(--danger); background: var(--tint-red); }
.settings-item.danger .si-arrow { color: var(--danger); }

/* Passphrase panel: shown once, so it has to read as important without looking like an error. */
.ho-pass-wrap { margin-top: 14px; border: 1px solid #e5b3b3; background: var(--tint-red); border-radius: 10px; padding: 14px; }
.ho-pass-label { font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--danger); margin-bottom: 8px; }
.ho-pass { font-family: var(--font-mono, monospace); font-size: 22px; font-weight: 700; letter-spacing: 3px;
  text-align: center; color: #1f2d2c; user-select: all; }

/* Export/import status chips inside the dialogs. */
.aw-chip { border-radius: 8px; padding: 8px 12px; font-size: 13px; }
.aw-chip.ok { background: var(--green-light); border: 1px solid var(--green-line); color: var(--green-dark); }
.aw-chip.warn { background: #fff7ed; border: 1px solid #f0d3a8; color: #9a6412; }

/* The archive list. Neutral .card styling on purpose - it is where data is rescued, not destroyed,
   so nothing here is red. */
.ar-wrap { display: flex; flex-direction: column; gap: 10px; max-width: 720px; }
.ar-row { display: flex; align-items: center; gap: 16px; padding: 14px 16px; }
.ar-main { flex: 1; min-width: 0; }
.ar-name { font-weight: 700; font-size: 15px; }
.ar-meta { font-size: 12.5px; color: var(--muted); margin-top: 3px; }
.ar-acts { display: flex; gap: 8px; flex-shrink: 0; }

/* The invoice / quote / sales-order document is a picture of the printed page, so it stays a white
   sheet in dark mode - on screen (read-only view AND the email preview) and on paper. Re-declaring
   the LIGHT palette on the sheet turns every var()-driven colour inside it back to its light value:
   the table wrap (var(--card)) and the header (var(--th-bg)) were going dark and showing through the
   transparent odd rows, so the rows read as black-on-black. This fixes them at the source. */
:root[data-theme="dark"] main.invoice-view,
:root[data-theme="dark"] .inv-sheet {
  --bg: #f4f7f6; --card: #ffffff; --surface: #f0f5f4; --th-bg: #f7fafa;
  --ink: #1d2b2b; --muted: #6b7d7d; --line: #e2e8e7; --green-line: #bfe3e0;
  --field-bg: #ffffff; --field-fg: #1d2b2b; --field-ph: #94a6a5;
  --green: #2f8f8b; --green-dark: #1f6b68; --green-light: #e8f5f5; --on-green: #ffffff;
  --tint-amber: #fdf3d7; --tint-red: #fdeaea; --tint-gray: #eef1f0;
  color: #1d2b2b; background: #ffffff;
}

/* An account box that has text in it matching nothing: say so quietly rather than saving a blank. */
.bl-acct-bad { border-color: var(--danger) !important; background: var(--tint-red); }

/* Icons inside a button: sit on the text baseline and keep a consistent gap, so a labelled icon
   button lines up the same wherever it appears. */
.btn-ico { display: inline-block; vertical-align: -3px; margin-right: 5px; flex: none; }

/* ---- Email payment reminders ---- */
.rem-sum { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 10px 12px; border-radius: 10px; background: var(--th-bg); border: 1px solid var(--line);
  font-size: 13.5px; }
.rem-sum-amt { font-size: 16px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ink); }
.rem-list { margin-top: 10px; max-height: 210px; overflow-y: auto; border: 1px solid var(--line);
  border-radius: 10px; background: var(--card); }
.rem-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px;
  border-bottom: 1px solid var(--line); font-size: 13px; }
.rem-row:last-child { border-bottom: 0; }
.rem-no { flex: none; min-width: 42px; font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }
.rem-who { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.rem-mail { font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rem-amt { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; }
.rem-skip { margin-top: 10px; padding: 9px 12px; border-radius: 9px; font-size: 12.5px;
  background: var(--tint-amber); color: var(--ink); border: 1px solid color-mix(in srgb, var(--amber) 45%, var(--line)); }
.rem-lbl { display: block; margin: 14px 0 5px; font-size: 12.5px; font-weight: 700; }
#rem-msg { width: 100%; box-sizing: border-box; font: inherit; font-size: 13px; line-height: 1.5;
  padding: 9px 11px; border: 1px solid var(--line); border-radius: 9px;
  background: var(--field-bg); color: var(--field-fg); resize: vertical; }
.rem-foot-note { margin-top: 8px; font-size: 12px; color: var(--muted); }

/* ---- Subscription hover panel ---- */
/* Sizes to its widest line rather than a fixed width, so a long plan name and the price breakdown
   each sit on one line, while short trial states stay compact. Capped so it never runs off a
   narrow screen. */
.sub-tip { position: fixed; z-index: 9000; width: max-content; min-width: 250px; max-width: min(430px, 92vw);
  padding: 12px 14px; border-radius: 12px;
  background: var(--card); color: var(--ink); border: 1px solid var(--line);
  box-shadow: 0 12px 34px rgba(0,0,0,.28); font-size: 12.5px; pointer-events: none;
  animation: subTipIn .13s ease-out; }
/* Rises from its bottom-left corner, matching where it is anchored. */
@keyframes subTipIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .sub-tip { animation: none; } }
.sub-tip-name { white-space: nowrap; }        /* the full plan name on one line */
.sub-tip-head { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: 13px;
  padding-bottom: 8px; margin-bottom: 4px; border-bottom: 1px solid var(--line); }
/* --green-dark, not --green: at 10px the lighter green measured 3.6:1 on the light chip, which is
   under the 4.5 needed for text this size. Same reason the amber below is mixed toward ink. */
.sub-tip-chip { margin-left: auto; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 10px;
  background: var(--green-light); color: var(--green-dark); }
.sub-tip-chip.trial { background: var(--tint-amber); color: var(--ink); }
.sub-tip-chip.grace { background: var(--tint-red); color: var(--danger); }
.sub-tip-tbl { width: 100%; border-collapse: collapse; }
.sub-tip-tbl td { padding: 5px 0; vertical-align: top; }
.sub-tip-tbl td:first-child { color: var(--muted); white-space: nowrap; padding-right: 10px; }
.sub-tip-tbl td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.sub-tip-warn { color: color-mix(in srgb, var(--amber) 72%, var(--ink)); }
.sub-tip-calc { display: block; font-size: 10.5px; color: var(--muted); font-weight: 400; margin-top: 1px; white-space: nowrap; }
.sub-tip-foot { margin-top: 8px; padding-top: 7px; border-top: 1px solid var(--line);
  font-size: 11px; color: var(--muted); }

/* Build this workspace is running, in the Settings header. Quiet by default: it is reference,
   not a call to action - it only takes the amber treatment when an update is waiting. */
/* --muted straight on --th-bg measured 4.15 at this size, under the 4.5 AA floor; mixed toward
   --ink it clears in both themes while still reading as secondary. */
.ver-chip { flex: none; font-size: 11.5px; font-weight: 700; letter-spacing: .2px;
  padding: 4px 10px; border-radius: 10px; background: var(--th-bg);
  color: color-mix(in srgb, var(--muted) 50%, var(--ink));
  border: 1px solid var(--line); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ver-chip.upd { background: var(--tint-amber); color: var(--ink);
  border-color: color-mix(in srgb, var(--amber) 45%, var(--line)); }
.ver-chip[hidden] { display: none; }

/* Version chip on the sidebar. The sidebar keeps its own dark palette whatever the theme, so
   this cannot inherit .ver-chip's --th-bg / --line - in light mode that painted a white chip
   on a near-black panel. */
.side-ver { background: rgba(255,255,255,.10); color: #cfe3e1; border-color: rgba(255,255,255,.18); }
.side-ver.upd { background: rgba(240,167,42,.22); color: #f6dca6; border-color: rgba(240,167,42,.45); }
.sidebar.collapsed .side-ver { display: none; }

/* ---- Messenger (Telegram / WhatsApp) in dark mode ----
   The messenger skin is a deliberate WhatsApp look - cream chat pane, green "me" bubbles - and
   every colour in it was written for light mode only. In dark it stayed cream and glared. This
   remaps just those hardcoded values to a proper dark chat look; light mode is untouched. Also
   fixes the borders: they used var(--border, ...) and --border is defined nowhere, so the light
   fallback showed through in dark. */
:root[data-theme="dark"] {
  --border: #2a393a;                 /* now the messenger borders follow the theme */
}
:root[data-theme="dark"] .wa-thread { background: #0e1415; }          /* the chat backdrop */
:root[data-theme="dark"] .wa-msgs .wa-loadmore { background: rgba(255,255,255,.06); }
:root[data-theme="dark"] .wa-msg.them .wa-bubble { background: #1e2828; color: var(--ink); }
:root[data-theme="dark"] .wa-msg.me .wa-bubble { background: #12424d; color: #eaf6f4; }
:root[data-theme="dark"] .wa-bubble { box-shadow: 0 1px 0 rgba(0,0,0,.25); }
:root[data-theme="dark"] .wa-mtime { color: #9db3b3; }
:root[data-theme="dark"] .wa-msg.call .wa-bubble { background: #202b2b; color: var(--muted); }
:root[data-theme="dark"] .wa-link-a { color: #6fb2f0; }
:root[data-theme="dark"] .wa-link-a:hover { color: #96c8f5; }
/* chat list */
:root[data-theme="dark"] .wa-chat { border-bottom-color: var(--line); }
:root[data-theme="dark"] .wa-chat:hover { background: rgba(255,255,255,.04); }
:root[data-theme="dark"] .wa-chat.active { background: color-mix(in srgb, var(--green) 20%, var(--card)); }
:root[data-theme="dark"] .wa-filter { color: var(--muted); }
:root[data-theme="dark"] .wa-filter:hover { background: rgba(255,255,255,.05); }
:root[data-theme="dark"] .wa-filter.active,
:root[data-theme="dark"] .wa-tab.active { background: color-mix(in srgb, var(--green) 24%, var(--card));
  border-color: color-mix(in srgb, var(--green) 45%, var(--line)); color: var(--green-dark); }
/* small chips + thumbs */
:root[data-theme="dark"] .wa-biz { background: color-mix(in srgb, var(--green) 22%, var(--card));
  color: var(--green-dark); border-color: color-mix(in srgb, var(--green) 40%, var(--line)); }
:root[data-theme="dark"] .wa-presence.typing { background: color-mix(in srgb, var(--green) 20%, var(--card));
  color: var(--green-dark); border-color: color-mix(in srgb, var(--green) 40%, var(--line)); }
:root[data-theme="dark"] .wa-presence.offline { background: #202b2b; color: var(--muted); border-color: var(--line); }
:root[data-theme="dark"] .wa-ap-thumb,
:root[data-theme="dark"] .wa-msg.call .wa-bubble { background: #202b2b; }

/* ---- Automatic cloud backup dialog ---- */
.ab-toggle { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 600; cursor: pointer; margin: 0 0 12px; }
.ab-toggle input { width: 18px; height: 18px; accent-color: var(--green); flex: none; }
.ab-when { transition: opacity .15s; }
.ab-row { display: flex; align-items: center; gap: 8px; font-size: 13.5px; flex-wrap: wrap; }
.ab-row select { font: inherit; font-size: 13.5px; padding: 6px 8px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--field-bg); color: var(--field-fg); cursor: pointer; }
.ab-status { margin-top: 14px; padding: 10px 12px; border-radius: 9px; background: var(--th-bg);
  border: 1px solid var(--line); font-size: 12.5px; color: var(--ink); }

/* ---- Cloud backups list inside the Automatic Cloud Backup dialog ---- */
.ab-restore { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.ab-restore-head { font-size: 12.5px; font-weight: 800; margin-bottom: 8px; }
.ab-bk { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 9px;
  border: 1px solid var(--line); background: var(--card); margin-bottom: 6px; font-size: 12.5px; }
.ab-bk-when { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.ab-bk-when .muted { font-size: 11px; }
.ab-bk-size { flex: none; color: var(--muted); font-variant-numeric: tabular-nums; }
.ab-bk-go { flex: none; }

/* ---- Cloud Backup add-on upsell ---- */
.ab-price { display: flex; align-items: baseline; gap: 8px; margin: 10px 0 14px; }
.ab-price b { font-size: 30px; line-height: 1; }
.ab-price span { color: var(--muted); font-size: 13px; }
.ab-sell { margin: 0 0 16px; padding-left: 20px; font-size: 13.5px; line-height: 1.85; }
.ab-sell li { margin: 0; }

/* ---- Automatic Cloud Backup: inline Settings panel ---- */
.ab-panel { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 18px 18px 20px; margin-bottom: 18px; }
.ab-p-head { display: flex; align-items: center; gap: 9px; font-size: 15px; }
.ab-p-head b { font-size: 15px; }
.ab-p-ic { font-size: 18px; }
.ab-p-state { margin-left: auto; font-size: 11px; font-weight: 800; letter-spacing: .3px;
  padding: 2px 9px; border-radius: 10px; }
.ab-p-state.on { background: var(--green-light); color: var(--green-dark); }
.ab-p-state.off { background: var(--th-bg); color: var(--muted); border: 1px solid var(--line); }
.ab-p-lead { font-size: 13px; color: var(--muted); margin: 10px 0 4px; }
.ab-panel .ab-toggle { margin-top: 14px; }
.ab-p-status { margin-top: 12px; padding: 9px 11px; border-radius: 9px; background: var(--th-bg);
  border: 1px solid var(--line); font-size: 12px; color: var(--ink); }
.ab-panel .btn.sm { padding: 8px 12px; font-size: 13px; }

/* Cap the cloud-backups list at ~5 rows (row stride 57px) and scroll inside, so the panel does
   not grow without bound as backups accumulate. padding-right keeps the scrollbar off the
   Restore buttons. */
#ab-p-list, #ab-list { max-height: 300px; overflow-y: auto; padding-right: 3px; }

/* Draws the eye to the step that still needs pressing after step 1 finishes. */
@keyframes pulse-cta { 0%,100% { box-shadow: 0 0 0 0 rgba(58,160,157,.55); } 50% { box-shadow: 0 0 0 9px rgba(58,160,157,0); } }
.pulse-cta { animation: pulse-cta 1.2s ease-out 4; }

/* The per-line description cell in the invoice/quotation/sales-order editors: looks like
   the neighbouring inputs, grows by dragging, and Enter makes a second row. */
.qb-table .line-detail { width: 100%; min-height: 38px; height: 38px; resize: vertical;
  font: inherit; padding: 8px 10px; }

/* When a line's description grows several rows tall, the item box, qty, price, amount and
   the remove button stay at the TOP of the row (they used to float to the vertical middle). */
.qb-table td { vertical-align: top; }
.qb-table td.qb-amt, .qb-table td:last-child { padding-top: 13px; }

/* The compact "Invoiced: #N" chip on a converted quotation or sales order - replaces the
   diagonal stamp that used to sprawl across the form fields. Click opens the invoice. */
.inv-conv-chip { display: block; margin-top: 8px; width: fit-content; background: var(--green-light);
  color: var(--green-dark); border: 1px solid color-mix(in srgb, var(--green-dark) 35%, transparent);
  border-radius: 999px; font-size: 13px; font-weight: 800; letter-spacing: .3px;
  padding: 5px 14px; cursor: pointer; }
.inv-conv-chip:hover { filter: brightness(1.06); }

/* Account Balances: each account type is its own card. */
.fin-bal-list { gap: 10px; padding: 2px; }
.fin-bal-block { background: color-mix(in srgb, var(--ink) 3%, transparent);
  border: 1px solid var(--line); border-radius: 11px; padding: 9px 10px 7px; }
.fin-bal-block .fin-bal-grp { margin: 0 4px 4px; }

/* Sub-option buttons under a payment method (which bank an online payment landed at):
   tap targets, not a dropdown - the chosen one fills in green. */
.pm-sub-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 10px 30px; }
.pm-sub-btn { border: 1.5px solid var(--line); background: transparent; color: var(--ink);
  border-radius: 999px; padding: 7px 16px; font-size: 13px; font-weight: 700; cursor: pointer; }
.pm-sub-btn:hover { border-color: var(--green-dark); }
.pm-sub-btn.on { background: var(--green-light); border-color: var(--green-dark); color: var(--green-dark); }

/* Currency pills inside the cash box: same buttons, till-sized. */
.cash-cur-pills { gap: 6px; }
.cash-cur-pills .pm-sub-btn { padding: 4px 11px; font-size: 12px; }

/* Home layout: COMPANY tools live inside the CUSTOMERS card's empty right half, and the
   ACCOUNT BALANCES column takes the whole right side at full height. */
.cust-row { display: flex; gap: 18px; align-items: stretch; }
/* The workflow side needs enough room for the full flow (two 140px columns, the Customers
   tile, and COMPANY beside it) before the balances column takes what is left. .fin-wrap
   wraps, so on a narrow Home window the balances column drops BELOW the workflow rather
   than squeezing it - a squeezed flow clips its own arrows. Not a media query: Home is a
   draggable window, so what matters is its width, never the viewport's. */
/* 760 = the flow's own 444 (140 + 140 + 24 gap + 140) + the card's 42 of padding,
   + 18 gap + the 240 COMPANY column beside it. */
.fin-main { min-width: 760px; }
/* Grows to fill the right side, but STOPS. flex:1 alone let it swallow every pixel of a
   maximised window, so an account name sat on the far left with its figure stranded against
   the opposite edge and the eye had to travel the whole screen to pair them up. 560 fits the
   longest group heading (OTHER CURRENT LIABILITY) and a seven-figure balance on one line. */
.fin-mid { flex: 1; min-width: 300px; max-width: 560px; }
.fin-bal-list { max-height: none; }

/* The next button to press WAVES until it is pressed - the same wave every "this one is live"
   marker in the app uses (nav badge, workspace chip, company dot): the button holds perfectly
   still and a soft green ring travels outward and fades. Step 1 waves first; once it locks,
   Step 2 takes over the wave. */
@keyframes wave-cta {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 62%, transparent); }
  70%  { box-shadow: 0 0 0 12px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}
.wave-cta { animation: wave-cta 1.9s ease-out infinite; }
.wave-cta:disabled { animation: none; box-shadow: none; }
@media (prefers-reduced-motion: reduce) { .wave-cta { animation: none; } }

/* A button that cannot be pressed yet looks grey and dead, not green. */
.btn:disabled { background: var(--line); color: var(--muted); cursor: not-allowed;
  box-shadow: none; }
.btn:disabled:hover { background: var(--line); }

/* ---------- Company picker ---------- */
/* Replaces the old dropdown. Three cards across, wrapping onto the next row, so the list stays
   readable whether there are three companies or thirty - a hanging menu could do neither. */
.co-modal { width: 620px; max-width: 100%; }
.co-search {
  width: 100%; box-sizing: border-box; padding: 10px 12px; font-size: 14px;
  border: 1px solid var(--line); border-radius: 9px; background: var(--field-bg);
  color: var(--field-fg); margin-bottom: 14px;
}
.co-search:focus { outline: none; border-color: var(--green); }
.co-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
/* The card fills its cell; the pencil sits on top of it rather than inside, so the whole card
   stays one big target for the thing you nearly always want, which is to switch. */
.co-cell { position: relative; display: flex; }
.co-cell[hidden] { display: none; }
.co-cell .co-card { flex: 1; min-width: 0; }
.co-rename {
  position: absolute; top: 6px; right: 6px; width: 26px; height: 26px; border-radius: 7px;
  border: 0; background: none; color: var(--muted-2); cursor: pointer; font-size: 13px;
  line-height: 1; opacity: 0; transition: opacity .12s ease;
}
.co-cell:hover .co-rename, .co-rename:focus-visible { opacity: 1; }
.co-rename:hover { background: var(--card); color: var(--green); }
.co-card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px; text-align: left;
  padding: 13px 13px 12px; border: 1px solid var(--line); border-radius: 11px;
  background: var(--card); color: var(--ink); cursor: pointer; min-height: 84px;
  font-size: 13.5px; font-weight: 600; line-height: 1.35;
}
.co-card:hover { border-color: var(--green); background: var(--bg); }
.co-card[hidden] { display: none; }
.co-card-dot { width: 9px; height: 9px; border-radius: 50%; background: #cdd8d7; flex: none; }
.co-card-name { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-word; padding-right: 22px; }
/* The company you are already in. Marked, and it waves like every other "this one is live"
   signal in the app: the card holds still and a ring travels out from it. */
.co-card.on { border-color: var(--green); background: color-mix(in srgb, var(--green) 10%, transparent); }
.co-card.on .co-card-dot { background: var(--green); animation: coDotWave 1.9s ease-out infinite; }
.co-card-now { font-size: 10.5px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase;
  color: var(--green-dark); margin-top: auto; }
.co-none { padding: 22px 4px; color: var(--muted); font-size: 13.5px; text-align: center; }
.co-new {
  display: block; width: 100%; margin-top: 14px; padding: 11px; border-radius: 10px;
  border: 1px dashed var(--line); background: none; color: var(--green); cursor: pointer;
  font-size: 13.5px; font-weight: 700;
}
.co-new:hover { border-color: var(--green); background: var(--bg); }
@media (max-width: 560px) { .co-grid { grid-template-columns: repeat(2, 1fr); } }

/* Data Notes: the issue-type filter chips above the list. A chip is a count first and a name
   second - the number is what tells you whether it is worth opening. `warn` marks the kinds
   that may mean money is in the wrong place, as opposed to a note about a decision already
   taken correctly (an invoice that had to be renumbered is not a problem). */
.gi-groups { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }
.gi-chip {
  display: inline-flex; align-items: baseline; gap: 6px; padding: 5px 10px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--card);
  color: var(--ink); cursor: pointer; font-size: 12.5px; line-height: 1.3;
}
.gi-chip b { font-size: 13.5px; }
.gi-chip:hover { border-color: var(--green); }
.gi-chip.on { background: var(--green); border-color: var(--green); color: var(--on-accent); }
.gi-chip.warn b { color: var(--danger); }
.gi-chip.on.warn b { color: inherit; }
.sm { font-size: 11.5px; }

/* Check Migration: the verdict banner, then the accounts that differ. Green means the ledger
   reproduces the source system account for account - deliberately worded so it cannot be read
   as "every document came across", which is a different question the import counts answer. */
.qv-verdict { padding: 13px 15px; border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--card); margin-bottom: 14px; }
.qv-verdict b { display: block; font-size: 15.5px; margin-bottom: 3px; }
.qv-verdict.ok { border-color: var(--green); background: var(--green-light); }
.qv-verdict.bad { border-color: var(--danger); background: var(--tint-red); }
.qv-h { margin: 16px 0 8px; font-size: 13px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); }
/* Shown when the accounts that differ cancel out - a missing transaction, not a wrong posting. */
.qv-hint { margin-top: 9px; padding: 8px 11px; border-radius: 8px; background: var(--tint-amber);
  border: 1px solid #f0e0b0; font-size: 13px; color: var(--ink); }

/* Sales Tax Liability: the closing figure, kept out of the table on purpose - it is the opening
   balance plus what was charged less what was paid over, not the sum of any column above it. */
.rep-owed { margin-top: 14px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--card); max-width: 560px; margin-left: auto; }
.rep-owed-line { display: flex; justify-content: space-between; gap: 20px; padding: 4px 0;
  font-size: 13.5px; }
.rep-owed-line.grand { border-top: 2px solid var(--ink); margin-top: 6px; padding-top: 8px;
  font-size: 15px; }
.rep-owed-line.grand b { font-size: 16px; }
.rep-owed .sm { margin-top: 9px; line-height: 1.45; }

/* Store credit at the till. Deliberately loud: this is the moment cash changes hands, and a
   customer holding credit was being asked for money they had already left with the business. */
.pm-credit { margin: 0 0 12px; padding: 11px 13px; border-radius: 10px;
  background: var(--tint-amber); border: 1px solid #f0e0b0; }
.pm-credit-top { font-size: 14px; color: var(--ink); margin-bottom: 3px; }
.pm-credit .sm { font-size: 12px; line-height: 1.45; }
.pm-credit .btn { margin-top: 9px; }

/* ---- Duplicate item name: the "this already exists" dialog ------------------------------
   Built from the palette variables rather than fixed colours, so it follows light/dark and
   the accent picker without a second rule. The card is the point of the dialog: it has to be
   obvious at a glance that this is a REAL existing item, not a warning about an abstraction. */
.dup-card {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; border-radius: var(--radius);
  border: 1px solid var(--green-line);
  background: color-mix(in srgb, var(--green) 8%, var(--card));
}
.dup-badge {
  flex: none; min-width: 58px; padding: 7px 10px; border-radius: 8px;
  background: var(--green); color: var(--on-accent);
  font-weight: 800; font-size: 13.5px; text-align: center; letter-spacing: .3px;
}
.dup-main { min-width: 0; }
.dup-main b { display: block; font-size: 15.5px; line-height: 1.3; }
/* The name can be long and there is nowhere for it to go, so wrap rather than push the
   dialog wider than the screen. */
.dup-main b { overflow-wrap: anywhere; }
.dup-main .muted { font-size: 12.5px; margin-top: 3px; }
.dup-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.dup-actions .btn { flex: 1 1 auto; min-width: 150px; justify-content: center; }

/* ---- A single checkbox on its own line inside a form --------------------------------------
   `.field input` gives every input in a form the full box treatment: 100% width, a border and
   padding. Applied to a checkbox that turns it into a stretched bordered strip with its label
   stranded underneath, which is exactly what it did on the Log time dialog. This resets it and
   puts the label back beside the box where it belongs. */
.chk-line { display: flex; align-items: center; gap: 10px; cursor: pointer;
  font-size: 14px; font-weight: 500; color: var(--ink); user-select: none;
  padding: 9px 12px; border: 1px solid var(--line); border-radius: 8px;
  transition: border-color .12s, background .12s; }
.chk-line:hover { border-color: var(--green); }
.chk-line input[type="checkbox"] {
  width: 17px; height: 17px; min-width: 17px; flex: none;
  margin: 0; padding: 0; border: 0; border-radius: 0;
  accent-color: var(--green); cursor: pointer; box-shadow: none; background: none; }
.chk-line span { line-height: 1.35; }
.chk-line .muted { display: block; font-size: 12px; font-weight: 400; margin-top: 1px; }

/* ---- The running stopwatch on the Time screen ---------------------------------------------
   Deliberately loud while it is running: a timer you forget about bills the client for your
   lunch. The dot pulses only when the clock is actually moving, so a paused timer is visibly
   different from a running one at a glance rather than on a second read. */
.tmr { display: flex; align-items: center; gap: 16px; margin: 0 18px 14px;
  padding: 14px 18px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--card); box-shadow: var(--shadow); }
.tmr.on { border-color: var(--green);
  background: color-mix(in srgb, var(--green) 7%, var(--card)); }
.tmr-dot { width: 11px; height: 11px; border-radius: 50%; flex: none;
  background: var(--muted); }
.tmr.on .tmr-dot { background: var(--green); animation: tmr-pulse 1.6s ease-in-out infinite; }
@keyframes tmr-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70%      { box-shadow: 0 0 0 9px transparent; }
}
/* Tabular figures: without them the whole clock jiggles left and right every second as the
   digits change width, which is maddening to sit next to. */
.tmr-clock { font-size: 27px; font-weight: 700; letter-spacing: .5px; color: var(--ink);
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; flex: none; }
.tmr-what { min-width: 0; flex: 1; }
.tmr-what b { display: block; font-size: 14.5px; overflow-wrap: anywhere; }
.tmr-what .muted { font-size: 12.5px; }
.tmr-actions { display: flex; gap: 8px; flex: none; }
@media (max-width: 700px) {
  .tmr { flex-wrap: wrap; gap: 10px; }
  .tmr-what { flex: 1 1 100%; order: 3; }
  .tmr-actions { flex: 1 1 100%; order: 4; }
}
@media (prefers-reduced-motion: reduce) { .tmr.on .tmr-dot { animation: none; } }

/* ---- The running clock on the Time menu item ----------------------------------------------
   Same pill as the unread badges, but monospaced digits so it does not twitch every second,
   and wide enough for mm:ss without squeezing. Paused goes grey and stops pulsing: at a glance
   you should be able to tell a clock that is counting from one that is waiting for you. */
.nav-badge.timer {
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum";
  min-width: 54px; letter-spacing: .2px; padding: 0 8px;
}
.nav-badge.timer.paused {
  background: var(--tint-gray); color: var(--muted); animation: none;
}

/* ---- Notes taken while the clock runs -----------------------------------------------------
   Full width under the card's top row, because what you were doing is usually a sentence and
   not three words, and this text is what the client reads on the invoice. */
.tmr { flex-wrap: wrap; }
.tmr-notes { flex: 1 1 100%; display: flex; align-items: flex-start; gap: 10px; margin-top: 2px; }
.tmr-notes textarea {
  flex: 1; min-height: 40px; resize: vertical; font: inherit; font-size: 13px;
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--line);
  background: var(--field-bg); color: var(--field-fg); }
.tmr-notes textarea:focus { outline: none; border-color: var(--green); }
.tmr-notes textarea::placeholder { color: var(--field-ph); }
/* Deliberately quiet. It should confirm without competing with the clock. */
.tmr-saved { flex: none; min-width: 58px; padding-top: 10px;
  font-size: 11.5px; color: var(--muted); }

/* ---- "Bill a client": who has unbilled work, and how much ---------------------------------- */
.bill-pick { display: flex; flex-direction: column; gap: 6px; max-height: 46vh; overflow-y: auto; }
.bill-row { display: flex; align-items: center; gap: 12px; cursor: pointer;
  padding: 10px 12px; border: 1px solid var(--line); border-radius: 9px;
  transition: border-color .12s, background .12s; }
.bill-row:hover { border-color: var(--green); }
.bill-row.on { border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, var(--card)); }
.bill-row input { width: 16px; height: 16px; flex: none; margin: 0; padding: 0; border: 0;
  accent-color: var(--green); box-shadow: none; background: none; }
.bill-who { flex: 1; min-width: 0; }
.bill-who b { display: block; font-size: 14px; overflow-wrap: anywhere; }
.bill-who .muted { font-size: 12px; }
/* Tabular figures so the money column lines up down the list. */
.bill-amt { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; }

/* The rate a timer will bill at, stated before it starts. Quiet, but not so quiet it gets
   skipped: the rate is frozen when the entry is logged, so this is the moment it matters. */
.rate-note { margin: 4px 0 0; padding: 9px 12px; border-radius: 8px;
  border: 1px solid var(--green-line);
  background: color-mix(in srgb, var(--green) 7%, var(--card));
  font-size: 13px; }

/* ---- Bank reconciliation ------------------------------------------------------------------- */
.br-bar { display: flex; flex-wrap: wrap; gap: 26px; align-items: flex-end;
  padding: 14px 18px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--card); box-shadow: var(--shadow); }
.br-bar.ok { border-color: var(--green); background: color-mix(in srgb, var(--green) 7%, var(--card)); }
.br-bar > div { display: flex; flex-direction: column; gap: 2px; }
.br-bar .muted { font-size: 11px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase; }
.br-bar b { font-size: 17px; font-variant-numeric: tabular-nums; }
/* The difference is the number the whole screen exists to drive to zero, so it leads. */
.br-diff b { font-size: 22px; }
.br-bar.ok .br-diff b { color: var(--green-dark); }
.br-bar:not(.ok) .br-diff b { color: var(--danger); }
tr.br-on > td { background: color-mix(in srgb, var(--green) 7%, var(--card)); }
.br-tick { width: 17px; height: 17px; accent-color: var(--green); cursor: pointer; }

/* ---- What the bank sent, beside what the books say ----------------------------------------- */
.br-stmt { margin-top: 14px; padding: 14px 16px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--card); }
.br-stmt-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
.br-stmt-head b { font-size: 14.5px; }
.br-stmt-head .muted { font-size: 12.5px; }

/* ---- Import a transaction listing ---------------------------------------------------------- */
.im-controls { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 14px; }
.im-controls .field { min-width: 260px; flex: 1 1 260px; }
/* A row that cannot be imported is greyed rather than hidden: knowing what was left out matters
   more than a tidy list. */
tr.im-bad > td { opacity: .55; background: color-mix(in srgb, var(--danger) 6%, var(--card)); }
select.im-row { width: 100%; }

/* ---- Narrowing the movements list ---------------------------------------------------------- */
.br-filter { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.br-filter .field { min-width: 150px; }
.br-filter .field label { font-size: 11px; }
/* A sortable heading should look clickable before you click it. */
th.br-sort { cursor: pointer; user-select: none; }
th.br-sort:hover { color: var(--green-dark); }

/* ---- One line per row, with draggable column widths ----------------------------------------
   A wrapped date turns a 40-row page into 80 rows of scrolling, and a column reads far faster
   when every row lines up. So nothing wraps: anything too long is cut with an ellipsis and kept
   in full in the tooltip. If a column is too narrow to be useful, drag it wider - the width is
   remembered per table, per browser. */
.tbl-1line th, .tbl-1line td {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tbl-1line td.nw { width: 1%; }          /* dates: exactly as wide as the date, no more */
.tbl-1line th { position: relative; }
/* The handle is a wide invisible target with a thin VISIBLE line down the middle. Nobody drags
   an edge they cannot see, and a 1px line you can actually hit is a 1px line with 7px of hit
   area around it. */
.col-grip {
  position: absolute; top: 0; right: -3px; width: 7px; height: 100%;
  cursor: col-resize; z-index: 3; }
.col-grip::after {
  content: ""; position: absolute; left: 3px; top: 15%; bottom: 15%; width: 1px;
  background: var(--line); transition: background .12s, top .12s, bottom .12s; }
.col-grip:hover::after {
  background: var(--green); width: 2px; left: 2.5px; top: 0; bottom: 0; }
body.col-resizing .col-grip::after { background: var(--green); width: 2px; left: 2.5px; top: 0; bottom: 0; }
/* While dragging, the whole page should feel like it is resizing rather than selecting text. */
body.col-resizing { cursor: col-resize; user-select: none; }

/* "Debit" means opposite things to a bank and to a ledger: to MCB a debit is money leaving your
   account, to the books a debit on a bank account is money arriving. The statement's wording wins
   here, because these columns sit beside the statement being read - but it gets a plain-language
   suffix so nobody has to know which convention is in play. */
.th-sub { font-weight: 400; font-size: 9.5px; letter-spacing: .04em; margin-left: 3px; }

/* The bulk-record window can hold 130 rows. The LIST scrolls; the "set them all to" pull-down,
   the heading and the Record button stay where they are. Laid out from script rather than here,
   because .modal-body is shared with every other dialog and already scrolls itself. */

/* How far a candidate is from the statement line. Shown rather than hidden: a near miss should be
   a decision, not a surprise discovered later. */
.tie-diff { display: block; font-size: 11.5px; font-weight: 600; color: var(--danger); }

/* Why a movement carries a tick. Quiet, but present: a tick nobody can explain is a tick nobody
   should trust. */
.tick-why { font-size: 11px; color: var(--green-dark); opacity: .85; }

/* An account box whose text matches nothing. Marked rather than silently ignored: a half-typed
   name that looks accepted and posts to Ask My Accountant is a surprise found weeks later. */
input.bad { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 8%, var(--field-bg)); }
.bk-row, #bk-bulk, #rc-acct { width: 100%; }

/* ---- Banking home: the two steps, side by side and numbered ------------------------------ */
.step-row { display: flex; gap: 14px; flex-wrap: wrap; margin: 4px 0 22px; }
/* One measure for the whole screen, so the account list lines up under the cards
   instead of stopping short of them on a wide monitor. */
.step-row, .bk-list, .step-h { max-width: 1040px; }
.step-card { flex: 1 1 320px; min-width: 300px; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px 18px 18px; cursor: pointer;
  display: flex; flex-direction: column;
  transition: border-color .12s, transform .12s, box-shadow .12s; }
.step-card:hover { border-color: var(--green); transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,.08), 0 8px 22px rgba(0,0,0,.06); }
.step-top { display: flex; align-items: center; gap: 10px; margin-bottom: 9px; }
.step-n { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%; background: var(--green);
  color: var(--on-green); font-weight: 700; font-size: 14px; display: flex; align-items: center;
  justify-content: center; }
.step-card h3 { margin: 0; font-size: 16.5px; }
.step-card p { margin: 0 0 7px; font-size: 13.5px; line-height: 1.5; }
.step-card p.step-when { color: var(--muted); font-size: 12.5px; margin-bottom: 13px; }
.step-card .btn { width: 100%; margin-top: auto; }
.step-h { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
  font-weight: 700; margin: 0 0 8px; }

/* One line per bank account. Deliberately not the same table the reconciler's picker uses:
   this answers "where am I", it is not a second copy of the chooser. */
.bk-list { display: flex; flex-direction: column; gap: 8px; }
.bk-acct { display: grid; grid-template-columns: minmax(170px, 1.1fr) minmax(180px, 1.6fr) auto auto;
  gap: 4px 16px; align-items: center; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 10px 14px; cursor: pointer; font-size: 13px;
  transition: border-color .12s; }
.bk-acct:hover { border-color: var(--green); }
.bk-name span { font-size: 11.5px; margin-left: 6px; white-space: nowrap; }
.bk-wait { line-height: 1.45; }
.bk-wait b { color: var(--ink); }
.bk-clear { color: var(--green-dark); font-weight: 600; }
.bk-last { text-align: right; white-space: nowrap; font-size: 12.5px; }
/* Always occupies its column, pill or not, so the dates stay in line down the list. */
.bk-flag { justify-self: end; min-width: 84px; text-align: right; }
.bk-open { display: inline-block; background: var(--tint-amber); color: var(--amber); border-radius: 999px;
  padding: 2px 9px; font-size: 11.5px; font-weight: 700; white-space: nowrap; }
/* The four-column row needs about 694px of content width and cannot shrink below it: two of
   the tracks have pixel floors and the other two hold nowrap text. Subtract the 230px sidebar
   and the page padding and that runs out at roughly a 1030px window, not at 720px, which is
   where this used to collapse. Between the two it overflowed its own rounded border and put a
   horizontal scrollbar on the whole page. Measured, so this breakpoint is not a guess. */
@media (max-width: 1080px) {
  .bk-acct { grid-template-columns: minmax(0, 1fr) auto; }
  .bk-name { grid-column: 1; }
  .bk-flag { grid-column: 2; grid-row: 1; justify-self: end; min-width: 0; }
  .bk-wait { grid-column: 1 / -1; }
  .bk-last { grid-column: 1 / -1; text-align: left; white-space: normal; }
}

/* A "pays invoice" box the machine filled in itself. Visible on purpose: a suggestion sitting
   quietly in a grid gets accepted, so it has to look like a suggestion, and its tooltip says
   what the evidence was. Typing anything clears the tint. */
input.im-auto { border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, var(--field-bg)); }

/* ---- Split payment: the parts already taken, shown as removable chips ------------------- */
.pm-tenders { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }
.pm-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--green-light);
  border: 1px solid var(--green-line); border-radius: 999px; padding: 3px 10px; font-size: 12.5px; }
.pm-chip-x { border: 0; background: none; cursor: pointer; color: var(--muted); font-size: 14px;
  padding: 0 2px; line-height: 1; }
.pm-chip-x:hover { color: var(--danger); }
.pm-chip-left { background: var(--tint-amber); border-color: transparent; }

/* ---------- Website Templates picker + shop front ------------------------------------ */
/* Its own page now, so the tiles get room: wider minimum, capped so three or four across on a
   big screen still read as cards rather than banners. */
.wt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px; max-width: 1180px; }
.wt-actions { display: flex; justify-content: flex-end; gap: 10px; margin: 22px 0 0;
  max-width: 1180px; }
.wt-card { display: flex; flex-direction: column; gap: 6px; text-align: left; padding: 12px;
  border: 2px solid var(--line); border-radius: 12px; background: var(--card); cursor: pointer; }
.wt-card:hover { border-color: var(--green-dark); }
.wt-card.on { border-color: var(--green-dark); box-shadow: 0 0 0 3px rgba(47,143,91,.16); }
.wt-card b { font-size: 14px; }
.wt-card .muted { font-size: 12px; line-height: 1.4; }
/* A drawing of the layout, not a screenshot: no image to ship and it follows the theme. */
.wt-art { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; padding: 8px;
  border-radius: 8px; background: var(--bg); margin-bottom: 4px; }
.wt-art span { display: block; border-radius: 3px; background: var(--line); }
.wt-bar { grid-column: 1 / -1; height: 8px; background: var(--green-dark) !important; }
.wt-hero { grid-column: 1 / -1; height: 26px; }
.wt-tile { height: 20px; }

.shop-frame { border: 1px solid var(--line); border-radius: 14px; background: var(--card); overflow: hidden; }
.shop-head { padding: 26px 24px; text-align: center; background: var(--green-dark); color: var(--on-green); }
.shop-head h1 { margin: 0; font-size: 24px; }
.shop-head p { margin: 6px 0 0; opacity: .85; font-size: 13px; }
.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 16px; padding: 22px; }
/* A column so the price can be pushed to the bottom: without it, a tile whose description runs
   to two lines drops its price below the one next to it and the row reads as ragged. */
.shop-item { display: flex; flex-direction: column; border: 1px solid var(--line);
  border-radius: 12px; overflow: hidden; background: var(--bg); }
.shop-item h4 { margin: 10px 12px 0; font-size: 14px; }
.shop-item p { margin: 4px 12px 0; font-size: 12px; }
.shop-pic { aspect-ratio: 4 / 3; display: flex; align-items: center; justify-content: center;
  background: var(--line); }
.shop-pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shop-pic-ph { font-size: 26px; opacity: .45; }
.shop-row { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 10px 12px 12px; margin-top: auto; }
.shop-row .badge { white-space: nowrap; }   /* "Out of stock" must not break across two lines */
.shop-price { font-weight: 700; }
.shop-empty { padding: 40px 24px; text-align: center; }
.shop-foot { padding: 16px 24px; border-top: 1px solid var(--line); text-align: center;
  font-size: 12px; color: var(--muted); }

/* ---------- "Make it yours": restyling a template you own ---------------------------- */
.wt-style { margin: 34px 0 0; padding: 24px 0 0; border-top: 1px solid var(--line); max-width: 1180px; }
.wt-style h3 { margin: 0 0 6px; font-size: 16px; }
.wt-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.wt-fields label { display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
.wt-fields label > span:first-child { color: var(--muted); font-weight: 600; }
.wt-fields label.wide { grid-column: 1 / -1; max-width: 640px; }
.wt-fields textarea { resize: vertical; min-height: 74px; font: inherit; }
/* The swatch and the hex box are one control: click to pick, or paste the value you were given. */
.wt-colour { display: flex; gap: 8px; align-items: center; }
.wt-colour input[type="color"] { width: 42px; height: 38px; padding: 2px; border: 1px solid var(--line);
  border-radius: 8px; background: var(--card); cursor: pointer; flex: none; }
.wt-colour input:not([type="color"]) { flex: 1; min-width: 0; font-family: ui-monospace, monospace; }

/* The website tick on an item.
   Deliberately NOT a .field: that is a column flexbox whose `label` rule paints text in --muted,
   which both squeezed this to one character per line and made it unreadable in dark mode. This is
   a direct child of .form-grid with its own colours. */
.shop-toggle {
  grid-column: 1 / -1;
  display: flex; align-items: flex-start; gap: 11px;
  padding: 13px 15px; margin-top: 2px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--field-bg);
  cursor: pointer; transition: border-color .15s, background .15s;
}
.shop-toggle:hover { border-color: var(--green); }
.shop-toggle input[type="checkbox"] {
  flex: none; width: 17px; height: 17px; margin: 1px 0 0; accent-color: var(--green); cursor: pointer;
}
/* min-width:0 so a long hint wraps inside the box instead of forcing the row wider than the dialog */
.shop-toggle .st-text { min-width: 0; }
.shop-toggle b { display: block; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.shop-toggle small { display: block; margin-top: 3px; font-size: 12px; font-weight: 400;
  line-height: 1.45; color: var(--muted); }
/* Ticked reads as on at a glance, rather than needing a look at the box itself. */
.shop-toggle:has(input:checked) { border-color: var(--green); background: var(--green-light); }

/* ---------- Website payments ---------------------------------------------------------- */
.pay-row { display: flex; align-items: center; gap: 11px; margin: 0 18px 16px;
  padding: 12px 16px; border: 1px solid var(--line); border-radius: 10px; background: var(--card);
  font-size: 13.5px; }
.pay-row .dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--muted); }
.pay-row.on .dot { background: var(--green); }
.pay-row > span:nth-child(2) { flex: 1; min-width: 0; }
.pay-row .btn { flex: none; }
.pay-form label { display: block; margin-bottom: 14px; font-size: 12.5px; }
.pay-form label > span:first-child { display: block; color: var(--muted); font-weight: 600; margin-bottom: 5px; }
.pay-form input, .pay-form select { width: 100%; padding: 9px 11px; border: 1px solid var(--line);
  border-radius: 8px; font-size: 14px; background: var(--field-bg); color: var(--field-fg); font-family: inherit; }
.pay-form small { display: block; margin-top: 5px; font-size: 11.5px; line-height: 1.45; }
.pay-note { margin: 4px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--muted); }

/* ---------- shop preview: the "edit me" frames -------------------------------------------- */
/* Dashed on purpose: unmistakably scaffolding, never mistakable for the shop itself. */
.ph-frame { display: flex; align-items: center; gap: 10px; padding: 10px 13px;
  border: 1.5px dashed color-mix(in srgb, var(--green) 55%, var(--line));
  border-radius: 10px; background: color-mix(in srgb, var(--green) 5%, transparent);
  color: inherit; text-decoration: none; font-size: 12.5px; line-height: 1.35; text-align: left; }
a.ph-frame:hover { border-color: var(--green); background: color-mix(in srgb, var(--green) 10%, transparent); }
.ph-frame .ph-plus { flex: none; font-size: 15px; color: var(--green); }
.ph-frame b { display: block; font-size: 12.5px; font-weight: 600; }
.ph-frame small { display: block; color: var(--muted); font-size: 11.5px; margin-top: 1px; }
.shop-legend { margin: 0 0 14px; padding: 10px 14px; border-radius: 10px; font-size: 12.5px;
  color: var(--muted); background: var(--bg); border: 1px solid var(--line); }
.shop-frame .shop-legend { margin: 14px 18px 0; }
.shop-topbar { display: flex; align-items: center; gap: 12px; padding: 12px 18px;
  border-bottom: 1px solid var(--line); }
.shop-topbar b { font-size: 14px; }
.shop-topbar .ph-frame { padding: 6px 10px; }
.shop-logo-ok { font-size: 12px; color: var(--green); font-weight: 600; }
.shop-head .ph-frame { max-width: 420px; margin: 12px auto 0;
  border-color: rgba(255,255,255,.65); background: rgba(255,255,255,.12); color: #fff; }
.shop-head .ph-frame .ph-plus { color: #fff; }
.shop-head .ph-frame small { color: rgba(255,255,255,.75); }
.shop-item .ph-frame { margin: 6px 12px 0; padding: 7px 10px; }
.shop-pic.noimg { background: var(--card); }
.shop-pic .ph-frame { margin: 10px; }
.shop-about { padding: 6px 22px 0; max-width: 640px; margin: 0 auto; text-align: center; }
.shop-about p { color: var(--muted); font-size: 14px; }
.shop-about .ph-frame { text-align: left; }
.shop-contact { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px; padding: 22px; max-width: 840px; margin: 0 auto; }
.shop-cc { border: 1px solid var(--line); border-radius: 12px; padding: 16px 14px;
  text-align: center; background: var(--bg); }
.shop-cc > span { display: block; font-size: 18px; color: var(--green); margin-bottom: 6px; }
.shop-cc b { display: block; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); margin-bottom: 5px; }
.shop-cc p { margin: 0; font-size: 13.5px; }
.shop-cc.empty { border-style: dashed; }
.shop-cc .ph-frame { border: 0; background: none; padding: 2px 0 0; justify-content: center; }

/* ---------- shop preview: the product page, mirroring the live /p/<id> design ---------- */
.shop-item.click { cursor: pointer; transition: transform .15s, box-shadow .15s; }
.shop-item.click:hover { transform: translateY(-2px); box-shadow: 0 8px 22px rgba(0,0,0,.10); }
.shop-pdp { padding: 20px 22px 30px; }
.shop-crumb { border: 0; background: none; color: var(--muted); font: inherit; font-size: 13.5px;
  cursor: pointer; padding: 0; margin-bottom: 18px; }
.shop-crumb:hover { color: var(--green); }
.shop-pdp-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: 34px; align-items: start; }
@media (max-width: 860px) { .shop-pdp-grid { grid-template-columns: 1fr; } }
.shop-galmain { aspect-ratio: 1/1; display: flex; align-items: center; justify-content: center;
  overflow: hidden; border: 1px solid var(--line); border-radius: 14px; background: var(--bg); }
.shop-galmain img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shop-galmain .ph-frame { margin: 14px; }
.shop-thumbs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.shop-thumb { width: 58px; height: 58px; padding: 0; overflow: hidden; cursor: pointer; flex: none;
  border: 1px solid var(--line); border-radius: 9px; background: none; }
.shop-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.shop-thumb.on { border-color: var(--green); box-shadow: 0 0 0 2px color-mix(in srgb, var(--green) 30%, transparent); }
.shop-pdp-info h1 { margin: 0 0 8px; font-size: 26px; letter-spacing: -.02em; }
.shop-pdp-price { margin: 0 0 20px; font-size: 21px; font-weight: 700; }
.shop-pdp-btns { display: flex; flex-direction: column; gap: 10px; max-width: 340px; }
.shop-pdp-btns button { padding: 13px 18px; border-radius: 26px; font: inherit; font-size: 14.5px;
  font-weight: 650; cursor: pointer; }
.pv-add { background: var(--green-dark); border: 1px solid var(--green-dark); color: var(--on-green); }
.pv-add:hover { filter: brightness(1.07); }
.pv-buy { background: none; border: 1.5px solid var(--ink); color: var(--ink); }
.pv-buy:hover { background: var(--ink); color: var(--card); }
.shop-pdp-details { margin-top: 28px; border-top: 1px solid var(--line); padding-top: 16px;
  font-size: 13.5px; }
.shop-pdp-details > b { display: block; margin-bottom: 10px; font-size: 14.5px; }
.shop-pdp-details p { margin: 0 0 12px; color: var(--muted); line-height: 1.55; }
.shop-pdp-details dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 18px; margin: 12px 0 0; }
.shop-pdp-details dt { font-weight: 600; }
.shop-pdp-details dd { margin: 0; color: var(--muted); }

/* ---------- picture framing dialog ---------------------------------------------------- */
/* Square, because every frame the shop shows a picture in is square - so what you see here is
   exactly what a shopper gets. */
.crop-box { position: relative; width: min(440px, 78vw); aspect-ratio: 1/1; margin: 0 auto;
  overflow: hidden; border: 1px solid var(--line); border-radius: 12px; background: #fff;
  cursor: grab; touch-action: none; }
.crop-box:active { cursor: grabbing; }
.crop-box img { position: absolute; top: 0; left: 0; transform-origin: 0 0; max-width: none;
  user-select: none; -webkit-user-drag: none; }
.crop-row { display: flex; align-items: center; gap: 12px; margin: 14px auto 0; max-width: 440px; }
.crop-row input[type="range"] { flex: 1; accent-color: var(--green); }

/* The memo on a sales order / quotation. It was an unstyled <input> at the browser's default
   ~180px, which truncated after four words. Full width and two rows, growable by hand; the
   placeholder says what the label cannot: this note is internal and never prints. */
.qb-memo-field { width: 100%; }
.qb-memo { display: block; width: 100%; min-height: 54px; resize: vertical;
  padding: 8px 11px; border: 1px solid var(--line); border-radius: 8px;
  font: inherit; font-size: 13.5px; line-height: 1.45;
  background: var(--field-bg); color: var(--field-fg); }
.qb-memo:focus { outline: 2px solid var(--green); border-color: var(--green); }

/* MEMO header row: the label left, the print tick right. The tick is the whole point - a memo
   is internal unless the owner deliberately says otherwise. */
.memo-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 4px; }
.memo-head label { margin-bottom: 0; }
.memo-print { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 500;
  color: var(--muted); cursor: pointer; letter-spacing: 0; text-transform: none; }
.memo-print input { accent-color: var(--green); cursor: pointer; }

/* The printed NOTE block on the sheet - same look on screen, in print and in the emailed PDF. */
.inv-note { margin-top: 26px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 8px; }
.inv-note span { display: block; font-size: 10px; font-weight: 800; letter-spacing: 1px;
  color: var(--muted); margin-bottom: 4px; }
.inv-note p { margin: 0; font-size: 13px; line-height: 1.55; white-space: pre-wrap; }

/* Under the sales-order total: how an online order was actually paid. Green because it is the
   good news on the document, and it names the gateway - "paid online" stops being an answer the
   moment there is more than one way to be paid online. */
.qb-paidline { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--line);
  font-size: 12.5px; font-weight: 600; color: var(--green); text-align: right; }
