/* ============================================================
   Henderson Tech Services — design tokens
   Grounded in the existing brand: near-black + electric blue,
   and in the subject itself — a Windows-only IT tool built with
   Windows' own system fonts (Segoe UI / Cascadia Mono) so it feels
   native rather than borrowed from a generic web-app template.
   ============================================================ */
:root {
  --bg: #0a0c10;
  --surface: #14171d;
  --surface-2: #1b1f26;
  --surface-3: #22262e;
  --border: #262b33;
  --border-soft: #1d2129;

  --text: #eaeef3;
  --text-dim: #8c93a0;
  --text-faint: #5b616c;

  --accent: #0095fc;
  --accent-2: #00c2ff;
  --accent-soft: rgba(0, 149, 252, 0.14);
  --accent-border: rgba(0, 149, 252, 0.35);

  --success: #22c58b;
  --success-soft: rgba(34, 197, 139, 0.14);
  --warning: #ffb238;
  --warning-soft: rgba(255, 178, 56, 0.14);
  --danger: #ff5c7a;
  --danger-soft: rgba(255, 92, 122, 0.14);
  --info: #8b8fff;
  --info-soft: rgba(139, 143, 255, 0.14);

  /* A shade above --surface-3, so the bar reads as texture rather than as a
     control sitting on top of the app. */
  --scroll-thumb: #2b303a;

  --font-display: 'Segoe UI Semibold', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-body: 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-mono: 'Cascadia Mono', 'Cascadia Code', Consolas, 'Courier New', monospace;

  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
}

/* Light mode — same token names, different values. --accent / --accent-2 /
   --accent-soft / --accent-border are intentionally NOT redefined here: the
   user's chosen accent color is applied as an inline style on <html> (see
   applyTheme() in js/app.js), which always wins over these rules regardless
   of theme. */
:root[data-theme="light"] {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-2: #f0f1f4;
  --surface-3: #e5e7eb;
  --border: #dde1e6;
  --border-soft: #e8eaed;

  --text: #14171d;
  --text-dim: #5b616c;
  --text-faint: #8c93a0;

  --scroll-thumb: #d3d7dd;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

button, input, select, textarea { font-family: inherit; font-size: inherit; color: inherit; }

/* Scrollbars — the standard properties, not ::-webkit-scrollbar.

   Chromium ignores EVERY ::-webkit-scrollbar rule on an element that also sets
   scrollbar-width, and renders the OS default instead. That is how the sidebar
   ended up wearing a bright white Windows scrollbar in a near-black app: it set
   scrollbar-width: thin for the narrower bar, and thereby threw away the colours
   set right next to it. The two syntaxes cannot be mixed on one element, so the
   whole app uses the standard one.

   scrollbar-color inherits, so html covers everything; scrollbar-width does not,
   hence the universal selector. */
html { scrollbar-color: var(--scroll-thumb) transparent; }
* { scrollbar-width: thin; }

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

/* ---------- App shell ---------- */
#app {
  display: grid;
  grid-template-columns: 240px 1fr;
  height: 100vh;
  width: 100vw;
}

/* min-height:0 is what lets this shrink inside the grid — grid items default
   to min-height:auto, which would size the sidebar to its content and push
   the footer (quick-add, profile) off-screen in a short window. */
.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--border-soft);
  display: flex;
  flex-direction: column;
  padding: 20px 16px;
  min-height: 0;
  overflow: hidden;
  -webkit-app-region: drag;
}

.sidebar * { -webkit-app-region: no-drag; }

.brand {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 4px 18px 4px;
  flex-shrink: 0;
}

/* Capped so the logo can't crowd out the nav; the cap tightens in a short
   window, where vertical space is worth more than logo size. */
.brand-logo {
  width: 100%;
  max-height: 120px;
  height: auto;
  object-fit: contain;
  display: block;
}

@media (max-height: 700px) {
  .brand { padding-bottom: 12px; }
  .brand-logo { max-height: 68px; }
}

/* flex:1 + min-height:0 lets the nav shrink and scroll inside a short
   window instead of pushing the footer (quick-add, profile) off-screen. */
.nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

.nav-item { flex-shrink: 0; }

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  cursor: pointer;
  font-size: 13.5px;
  font-weight: 500;
  border: 1px solid transparent;
  user-select: none;
}

.nav-item:hover { background: var(--surface-2); color: var(--text); }

.nav-item.active {
  background: var(--accent-soft);
  color: var(--accent-2);
  border-color: var(--accent-border);
}

.nav-icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.nav-icon svg { width: 16px; height: 16px; }

/* Dashboard and the Calendar icon share one row. */
.nav-row { display: flex; gap: 4px; flex-shrink: 0; }
.nav-row .nav-item:not(.nav-icon-only) { flex: 1; min-width: 0; }
.nav-item.nav-icon-only { justify-content: center; padding-left: 10px; padding-right: 10px; }
.nav-item.nav-icon-only .nav-icon, .nav-item.nav-icon-only .nav-icon svg { width: 18px; height: 18px; }

/* ---------- Full-screen pay QR ---------- */
/* For handing the screen to a client. Everything they need to pay, nothing
   else: the code, what it is for, how much, and the address for anyone whose
   camera will not scan. */
.qr-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: #ffffff;
  color: #111;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 32px;
  text-align: center;
  cursor: pointer;
}
.qr-fullscreen.hidden { display: none; }
.qr-fullscreen svg { width: min(70vh, 70vw); height: auto; display: block; }
.qr-fullscreen-title { font-family: var(--font-display); font-weight: 700; font-size: 22px; }
.qr-fullscreen-amount { font-family: var(--font-mono); font-weight: 700; font-size: 34px; }
.qr-fullscreen-sub { font-size: 15px; color: #555; max-width: 60ch; }
.qr-fullscreen-url { font-family: var(--font-mono); font-size: 13px; color: #333; word-break: break-all; max-width: 90vw; }
.qr-fullscreen-hint { font-size: 12px; color: #999; }
@media print { .qr-fullscreen { display: none !important; } }

/* ---------- Device code sign-in ---------- */
.device-code {
  font-family: var(--font-mono);
  font-size: 30px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-align: center;
  padding: 18px;
  margin: 14px 0 6px 0;
  background: var(--surface-2);
  border: 1px solid var(--accent-border);
  border-radius: var(--radius-md);
  color: var(--accent-2);
  user-select: all;
}

/* ---------- Attention queue ---------- */
.nav-badge {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--danger);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.attention-card { border-left: 3px solid var(--border); }
.attention-card.attention-danger { border-left-color: var(--danger); }
.attention-card.attention-warn { border-left-color: var(--warning); }
.attention-card.attention-info { border-left-color: var(--info); }

.attention-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--border);
}
.attention-danger .attention-dot { background: var(--danger); }
.attention-warn .attention-dot { background: var(--warning); }
.attention-info .attention-dot { background: var(--info); }

/* ---------- Global search ---------- */
/* Looks like a search FIELD, not a nav item. When it was styled as a nav row it
   competed with Dashboard for the top of the list; as a box it reads as a tool,
   which is what it is — a way to find something when you do not know where it
   lives, not a place to go. */
.nav-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin-bottom: 14px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-faint);
  font-size: 13px;
  cursor: pointer;
  user-select: none;
}
.nav-search:hover { border-color: var(--text-faint); color: var(--text-dim); }
.nav-search .nav-icon svg { width: 15px; height: 15px; }

.nav-kbd {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 2px 5px;
  border-radius: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  color: var(--text-faint);
}

.search-input {
  font-size: 15px;
  padding: 12px 14px;
  margin-bottom: 12px;
}

.search-results { max-height: 52vh; overflow-y: auto; }

.search-row {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid transparent;
}
.search-row:hover { background: var(--surface-2); }
.search-row.selected {
  background: var(--accent-soft);
  border-color: var(--accent-border);
}

.search-icon { color: var(--text-faint); flex-shrink: 0; padding-top: 1px; }
.search-main { flex: 1; min-width: 0; }
.search-title { font-size: 13.5px; font-weight: 600; }
.search-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 1px; }
.search-context {
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 3px;
  font-style: italic;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.search-empty {
  padding: 22px 12px;
  color: var(--text-faint);
  font-size: 12.5px;
  text-align: center;
  line-height: 1.6;
}

/* The segmented Business|Residential switch that used to sit here is gone —
   both sides are collapsible nav groups now (see sideGroups() in js/render.js). */

.nav-divider {
  height: 1px;
  background: var(--border-soft);
  margin: 10px 2px;
  flex-shrink: 0;
}

.nav-item.nav-sub {
  padding-left: 26px;
  font-size: 12.5px;
}

.sidebar-footer {
  padding-top: 14px;
  border-top: 1px solid var(--border-soft);
  margin-top: 14px;
  flex-shrink: 0;
}

/* ---------- Quick add (+) ---------- */
#quick-add { position: relative; margin-bottom: 12px; -webkit-app-region: no-drag; }

.quick-add-btn {
  margin-top: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
}
.quick-add-btn .nav-icon { width: 18px; height: 18px; }
.quick-add-btn .nav-icon svg { width: 18px; height: 18px; }
.quick-add-btn.active { filter: brightness(1.1); }

.quick-add-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  width: 100%;
  min-width: 190px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
  padding: 6px;
  z-index: 20;
}

.quick-add-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
}
.quick-add-row:hover { background: var(--surface-2); color: var(--accent-2); }

.quick-add-divider {
  height: 1px;
  background: var(--border-soft);
  margin: 5px 4px;
}

.save-indicator {
  font-size: 11px;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 6px;
}

.save-indicator::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  flex-shrink: 0;
}

.save-indicator.saving::before { background: var(--warning); }
.save-indicator.saving { color: var(--warning); }

/* Momentary confirmation after a deliberate Save press. */
.save-indicator.flash-saved { color: var(--success); font-weight: 600; }
.save-indicator.flash-saved::before { background: var(--success); }

/* ---------- Profile switcher ---------- */
#profile-switcher { position: relative; margin-bottom: 10px; -webkit-app-region: no-drag; }

.profile-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.profile-chip:hover, .profile-chip.active { background: var(--surface-2); }

.profile-avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  flex-shrink: 0;
}
.profile-avatar.sm { width: 22px; height: 22px; font-size: 10px; }

.profile-chip-name { font-size: 13px; font-weight: 600; flex: 1; }
.profile-chip .nav-icon { color: var(--accent-2); width: 14px; height: 14px; }

/* Width matches the rail rather than being a fixed 260px: the sidebar's
   usable width is 208px (240 minus padding) and it clips overflow, so a wider
   menu had its right edge — and the Admin badge — cut off. */
.profile-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
  padding: 6px;
  z-index: 10;
  max-height: 320px;
  overflow-y: auto;
}

.profile-menu-row { padding: 6px; border-radius: var(--radius-sm); }
.profile-menu-row.active { background: var(--accent-soft); }
.profile-menu-row-main { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13px; min-width: 0; }
.profile-menu-row-main:hover { color: var(--accent-2); }

/* A long name truncates instead of shoving the badge out of view. */
.profile-menu-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.profile-menu-row-main .badge { flex-shrink: 0; }

.profile-pin-box { display: flex; gap: 6px; margin-top: 6px; }
.pin-input { letter-spacing: 4px; text-align: center; }

.profile-menu-footer {
  border-top: 1px solid var(--border-soft);
  margin-top: 4px;
  padding-top: 6px;
}

.profile-menu-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-faint);
  padding: 4px 6px 6px 6px;
}

/* Who is signed in. Not a row you can click — there is nothing to switch to
   any more, and making it look pressable would promise something the app
   stopped doing. */
.profile-menu-who {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px;
  font-size: 13px;
}
.profile-menu-sub {
  font-size: 11px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Admin settings, lock and sign out. Separated by a rule rather than a second
   heading: they act on the person the menu is already about, so a label would
   only restate what the menu says. */
.profile-menu-actions {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.profile-menu-action {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 7px 6px;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.profile-menu-action:hover { background: var(--surface-3); color: var(--accent-2); }
/* Sign out is the one that costs you something to press by accident. */
.profile-menu-action.danger:hover { color: var(--danger); }
.profile-menu-action svg { width: 14px; height: 14px; flex: 0 0 auto; }

.profile-menu-footer .profile-menu-row-main {
  border-radius: var(--radius-sm);
  color: var(--text-dim);
}
.profile-menu-footer .profile-menu-row-main:hover { background: var(--surface-2); }
.profile-menu-footer .profile-menu-row-main.active { color: var(--accent-2); background: var(--accent-soft); }

/* ---------- Main content ---------- */
.main {
  overflow-y: auto;
  padding: 32px 40px 60px 40px;
}

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 24px;
  gap: 16px;
}

.page-title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 4px 0;
}

.page-subtitle {
  color: var(--text-dim);
  font-size: 13px;
  margin: 0;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1.5px;
  color: var(--accent-2);
  text-transform: uppercase;
  margin-bottom: 6px;
  display: block;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: background 0.12s, border-color 0.12s;
}
.btn:hover { background: var(--surface-3); border-color: var(--text-faint); }
.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #04101a;
}
.btn-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }

.btn-danger { color: var(--danger); }
.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); }

.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--surface-2); }

.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn-block { width: 100%; margin-top: 14px; }

/* ---------- Cards / stats ---------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin-bottom: 28px;
}

.stat-card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 18px;
}

.stat-value {
  font-family: var(--font-mono);
  font-size: 26px;
  font-weight: 600;
  margin: 6px 0 2px 0;
}

.stat-label {
  color: var(--text-dim);
  font-size: 12px;
}

.stat-section-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0 0 10px 2px;
}
.stat-section-label .nav-icon, .stat-section-label .nav-icon svg { width: 13px; height: 13px; }
.stat-grid + .stat-section-label { margin-top: 4px; }

.stat-sub {
  color: var(--text-faint);
  font-size: 11px;
  font-family: var(--font-mono);
}

.due-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--warning-soft);
  color: var(--warning);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  margin-top: 12px;
  font-size: 13px;
}
.due-banner .btn { margin-left: auto; }

.stat-card.accent .stat-value { color: var(--accent-2); }
.stat-card.warn .stat-value { color: var(--warning); }
.stat-card.ok .stat-value { color: var(--success); }

.card {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 20px;
  margin-bottom: 18px;
}

.card-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 14px;
  margin: 0 0 14px 0;
}

/* ---------- Record actions (Edit / Save / Cancel / Delete) ---------- */
.record-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-shrink: 0;
}

.edit-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  margin-bottom: 18px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  border: 1px solid var(--accent-border);
  color: var(--accent-2);
  font-size: 12.5px;
}
.edit-banner .nav-icon { width: 14px; height: 14px; flex-shrink: 0; }
.edit-banner .nav-icon svg { width: 14px; height: 14px; }

/* Locked fields should read as "not editable right now" rather than broken. */
.form-input:disabled,
.form-select:disabled,
.form-textarea:disabled {
  opacity: 1;
  color: var(--text-dim);
  background: var(--surface-2);
  border-color: transparent;
  cursor: default;
}
.form-input:disabled::placeholder,
.form-textarea:disabled::placeholder { color: transparent; }

/* ---------- Collapsible cards ---------- */
.collapsible-head { cursor: pointer; user-select: none; }
.collapsible-head .card-title { display: flex; align-items: center; gap: 8px; margin-bottom: 0; }

.collapse-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  color: var(--text-faint);
  transition: transform 0.15s ease;
}
.collapse-caret svg { width: 14px; height: 14px; }
.collapse-caret.open { transform: rotate(90deg); color: var(--accent-2); }

.card-body { margin-top: 14px; }

.count-pill {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--text-dim);
}

/* ---------- Dashboard: coming up ---------- */
.upcoming-day { margin-bottom: 14px; }
.upcoming-day:last-child { margin-bottom: 0; }

.upcoming-day-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--text-faint);
  margin-bottom: 7px;
}
.upcoming-day-label.today { color: var(--accent-2); }

.upcoming-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 14px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  cursor: pointer;
  margin-bottom: 6px;
}
.upcoming-item:hover { border-color: var(--accent-border); background: var(--surface-2); }

.upcoming-time {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--accent-2);
  width: 68px;
  flex-shrink: 0;
}

.upcoming-main { flex: 1; min-width: 0; }
.upcoming-title { font-size: 13.5px; font-weight: 600; margin-bottom: 2px; }

/* ---------- Tables / lists ---------- */
.list { display: flex; flex-direction: column; gap: 8px; }

.row-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 14px;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}
.row-item:hover { border-color: var(--accent-border); background: var(--surface-2); }

.row-main { flex: 1; min-width: 0; }
.row-title { font-weight: 600; font-size: 13.5px; margin-bottom: 2px; }
.row-sub { color: var(--text-dim); font-size: 12px; }

.row-code {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
}

.row-amount {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 14px;
  white-space: nowrap;
}

/* ---------- Badges / status ---------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 100px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid transparent;
}

.badge-scheduled { background: var(--info-soft); color: var(--info); }
.badge-progress { background: var(--accent-soft); color: var(--accent-2); }
.badge-completed { background: var(--success-soft); color: var(--success); }
.badge-unpaid { background: var(--warning-soft); color: var(--warning); }
.badge-paid { background: var(--success-soft); color: var(--success); }
.badge-residential { background: var(--surface-3); color: var(--text-dim); }
.badge-business { background: var(--accent-soft); color: var(--accent-2); }
.data-path {
  font-size: 11.5px;
  color: var(--text-dim);
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 9px 11px;
  word-break: break-all;
  user-select: text;
}

/* ---------- Commercial / MSP ---------- */
.badge-contract-active { background: var(--success-soft); color: var(--success); }
.badge-contract-paused { background: var(--warning-soft); color: var(--warning); }
.badge-contract-cancelled { background: var(--surface-3); color: var(--text-dim); }

.badge-ticket-open { background: var(--info-soft); color: var(--info); }
.badge-ticket-assigned { background: var(--accent-soft); color: var(--accent-2); }
.badge-ticket-waiting { background: var(--warning-soft); color: var(--warning); }
.badge-ticket-resolved { background: var(--success-soft); color: var(--success); }
.badge-ticket-cancelled { background: var(--surface-3); color: var(--text-dim); }

.badge-priority-low { background: var(--surface-3); color: var(--text-faint); }
.badge-priority-medium { background: var(--surface-3); color: var(--text-dim); }
.badge-priority-high { background: var(--warning-soft); color: var(--warning); }
.badge-priority-critical { background: var(--danger-soft); color: var(--danger); }

.vault-secret {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--accent-2);
  margin-top: 6px;
  user-select: all;
  word-break: break-all;
}
.vault-secret:not(:empty)::after {
  content: ' — copied, hides in 20s';
  font-family: var(--font-body);
  font-size: 11px;
  color: var(--text-faint);
}

.profit-hourly {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 14px;
  padding: 14px 16px;
  background: var(--surface-2);
  border-radius: var(--radius-md);
}
.profit-hourly .stat-value { font-size: 22px; margin: 2px 0 0 0; }

/* ---------- Attachments ---------- */
.attach-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px;
}

.attach-tile {
  margin: 0;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  overflow: hidden;
  cursor: pointer;
  transition: border-color 0.12s ease;
}
.attach-tile:hover { border-color: var(--accent-border); }

.attach-thumb {
  height: 104px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-3);
  color: var(--text-faint);
  overflow: hidden;
}
.attach-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.attach-thumb .nav-icon, .attach-thumb .nav-icon svg { width: 26px; height: 26px; }

.attach-tile figcaption {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 7px 8px;
  font-size: 11.5px;
}
.attach-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-dim);
}
.attach-del { opacity: 0; flex-shrink: 0; }
.attach-tile:hover .attach-del { opacity: 1; }

.attach-viewer {
  display: flex;
  align-items: center;
  justify-content: center;
  max-height: 62vh;
  overflow: auto;
  background: var(--surface-2);
  border-radius: var(--radius-md);
}
.attach-viewer img { max-width: 100%; max-height: 62vh; display: block; }

/* ---------- Payment states ---------- */
.badge-pay-draft { background: var(--surface-3); color: var(--text-dim); }
.badge-pay-sent { background: var(--info-soft); color: var(--info); }
.badge-pay-partial { background: var(--accent-soft); color: var(--accent-2); }
.badge-pay-paid { background: var(--success-soft); color: var(--success); }
.badge-pay-overdue { background: var(--danger-soft); color: var(--danger); }
.badge-pay-void { background: var(--surface-3); color: var(--text-faint); }
.badge-pay-refunded { background: var(--warning-soft); color: var(--warning); }

.form-select-sm { padding: 5px 8px; font-size: 12px; width: auto; }

/* ---------- Ticket activity stream ---------- */
.ticket-stream {
  max-height: 380px;
  overflow-y: auto;
  padding-right: 6px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.stream-entry {
  border-left: 3px solid var(--border-soft);
  background: var(--surface-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 9px 12px;
}
.stream-entry.stream-work_note { border-left-color: var(--accent); }
.stream-entry.stream-client_comment { border-left-color: var(--info); }
.stream-entry.stream-system { border-left-color: var(--border); background: transparent; }
.stream-entry.stream-system .log-text { color: var(--text-dim); font-size: 12.5px; }

.stream-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 4px;
}
.stream-kind { font-size: 11px; font-weight: 700; color: var(--text); }
.stream-head .log-time { min-width: 0; padding-top: 0; }
.stream-del { margin-left: auto; opacity: 0; transition: opacity 0.12s ease; }
.stream-entry:hover .stream-del { opacity: 1; }

.resolution-bar {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  background: var(--success-soft);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin-bottom: 18px;
  color: var(--success);
  font-size: 13px;
}
.resolution-bar .log-text { color: var(--text); }
.resolution-bar.cancelled { background: var(--surface-2); color: var(--text-dim); }

.badge-sla-breach { background: var(--danger-soft); color: var(--danger); display: inline-flex; align-items: center; gap: 4px; }
.badge-sla-breach .nav-icon, .badge-sla-breach .nav-icon svg { width: 12px; height: 12px; }
.badge-sla-late { background: var(--warning-soft); color: var(--warning); }
.badge-sla-ok { background: var(--success-soft); color: var(--success); }
.badge-sla-running { background: var(--info-soft); color: var(--info); }
.badge-sla-paused { background: var(--surface-3); color: var(--text-dim); }

.per-mo { font-size: 11px; font-weight: 500; color: var(--text-faint); margin-left: 2px; }

.stat-card.danger .stat-value { color: var(--danger); }

.sla-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  margin-bottom: 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-soft);
  background: var(--surface);
  font-size: 13px;
}
.sla-bar .nav-icon, .sla-bar .nav-icon svg { width: 18px; height: 18px; flex-shrink: 0; }
.sla-bar.breach { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
.sla-bar.paused { background: var(--surface-2); border-color: var(--border); color: var(--text-dim); }
.sla-bar.late { background: var(--warning-soft); border-color: var(--warning); color: var(--warning); }
.sla-bar.ok { background: var(--success-soft); border-color: var(--success); color: var(--success); }
.sla-bar.running { background: var(--info-soft); border-color: var(--info); color: var(--info); }
.sla-bar .form-hint { color: inherit; opacity: 0.75; }

.ticket-timeline { display: flex; flex-direction: column; gap: 10px; font-size: 13px; }
.ticket-timeline > div { display: flex; justify-content: space-between; padding-bottom: 8px; border-bottom: 1px solid var(--border-soft); }
.ticket-timeline > div:last-child { border-bottom: none; padding-bottom: 0; }

.badge-quote-draft { background: var(--surface-3); color: var(--text-dim); }
.badge-quote-sent { background: var(--info-soft); color: var(--info); }
.badge-quote-accepted { background: var(--success-soft); color: var(--success); }
.badge-quote-declined { background: var(--danger-soft); color: var(--danger); }

.pulse-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-2);
  flex-shrink: 0;
  box-shadow: 0 0 0 0 rgba(0, 194, 255, 0.6);
  animation: pulse 1.8s infinite;
}

@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(0, 194, 255, 0.55); }
  70% { box-shadow: 0 0 0 6px rgba(0, 194, 255, 0); }
  100% { box-shadow: 0 0 0 0 rgba(0, 194, 255, 0); }
}

/* ---------- Filters / search ---------- */
.toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  flex-wrap: wrap;
}

.search-input {
  flex: 1;
  min-width: 200px;
  padding: 9px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
}
.search-input:focus { outline: none; border-color: var(--accent); }

.tab-group { display: flex; gap: 4px; background: var(--surface); padding: 4px; border-radius: var(--radius-sm); border: 1px solid var(--border-soft); }

.tab {
  padding: 6px 12px;
  border-radius: 5px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-dim);
  cursor: pointer;
}
.tab:hover { color: var(--text); }
.tab.active { background: var(--accent-soft); color: var(--accent-2); }

/* ---------- Empty state ---------- */
.empty-state {
  text-align: center;
  padding: 56px 20px;
  color: var(--text-dim);
}
.empty-state-title { font-family: var(--font-display); font-weight: 700; color: var(--text); margin-bottom: 6px; font-size: 15px; }
.empty-state-sub { font-size: 13px; margin-bottom: 18px; }

/* ---------- Forms ---------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.form-grid.full { grid-template-columns: 1fr; }
.form-field { display: flex; flex-direction: column; gap: 6px; }
.form-field.span-2 { grid-column: span 2; }

.form-label { font-size: 12px; font-weight: 600; color: var(--text-dim); }

.form-input, .form-select, .form-textarea {
  padding: 9px 11px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  width: 100%;
}
.form-input:focus, .form-select:focus, .form-textarea:focus { outline: none; border-color: var(--accent); }
.form-textarea { resize: vertical; min-height: 70px; font-family: var(--font-body); }

.form-hint { font-size: 11px; color: var(--text-faint); }

/* ---------- Parts table ---------- */
.parts-table { width: 100%; border-collapse: collapse; margin-bottom: 10px; }
.parts-table th {
  text-align: left;
  font-size: 11px;
  color: var(--text-faint);
  font-weight: 600;
  padding: 0 8px 8px 8px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.parts-table td { padding: 6px 8px; }
.parts-table input { width: 100%; }
.parts-table .col-qty { width: 70px; }
.parts-table .col-cost { width: 100px; }
.parts-table .col-total { width: 90px; font-family: var(--font-mono); text-align: right; }
.parts-table .col-del { width: 36px; }

/* ---------- Work log ---------- */
.log-entry {
  display: flex;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-soft);
}
.log-entry:last-child { border-bottom: none; }
.log-time {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-faint);
  white-space: nowrap;
  padding-top: 2px;
  min-width: 130px;
}
.log-text { font-size: 13px; line-height: 1.5; white-space: pre-wrap; }

.log-add { display: flex; gap: 8px; margin-top: 12px; }
.log-add textarea { flex: 1; min-height: 44px; }

/* A failed save must be impossible to miss — everything typed after it is
   at risk until it clears. */
.save-indicator.save-failed {
  color: var(--danger);
  font-weight: 700;
}
.save-indicator.save-failed::before { background: var(--danger); }

.readonly-value {
  font-size: 13px;
  padding: 9px 0 0 0;
  color: var(--text);
}

/* ---------- Price book ---------- */
.service-picker { display: flex; gap: 8px; margin-bottom: 12px; }
.service-picker .form-select { flex: 1; max-width: 420px; }

.line-discount {
  font-size: 11px;
  font-family: var(--font-mono);
  color: var(--warning);
  margin-top: 4px;
}

/* ---------- Paged lists ---------- */
.list-more {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-soft);
  font-size: 12px;
}
.list-more-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.list-more-actions .btn.active {
  background: var(--accent-soft);
  border-color: var(--accent-border);
  color: var(--accent-2);
}

/* ---------- Client contact log ---------- */
.contact-add {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 12px;
}
.contact-add-row { display: flex; gap: 8px; }
.contact-add-row .form-select { max-width: 210px; }
.contact-add-row .form-input { max-width: 220px; }
.contact-add textarea { min-height: 64px; }
.contact-add .btn { align-self: flex-end; }

.contact-log { margin-top: 6px; }

.contact-entry {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-soft);
}
.contact-entry:last-child { border-bottom: none; }

.contact-entry-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  border-radius: 8px;
  background: var(--surface-3);
  color: var(--text-dim);
}
.contact-entry-icon svg { width: 15px; height: 15px; }
.contact-entry-icon.kind-call { background: var(--accent-soft); color: var(--accent-2); }
.contact-entry-icon.kind-email { background: var(--info-soft); color: var(--info); }
.contact-entry-icon.kind-visit { background: var(--warning-soft); color: var(--warning); }
.contact-entry-icon.kind-text { background: var(--success-soft); color: var(--success); }

.contact-entry-main { flex: 1; min-width: 0; }
.contact-entry-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}
.contact-entry-head .log-time { min-width: 0; padding-top: 0; }
.contact-kind {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--text);
}
.contact-entry-actions { display: flex; gap: 2px; opacity: 0; transition: opacity 0.12s ease; }
.contact-entry:hover .contact-entry-actions { opacity: 1; }

/* ---------- Totals summary ---------- */
.totals-box {
  background: var(--surface-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin-top: 4px;
}
.totals-row { display: flex; justify-content: space-between; font-size: 13px; padding: 4px 0; color: var(--text-dim); }
.totals-row.grand {
  border-top: 1px solid var(--border);
  margin-top: 6px;
  padding-top: 10px;
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
}

/* ---------- Modal ---------- */
.modal-root {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal-root.hidden { display: none; }

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(4, 6, 9, 0.7);
  backdrop-filter: blur(2px);
}

.modal-shell {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  width: min(640px, 92vw);
  max-height: 88vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 22px;
  border-bottom: 1px solid var(--border-soft);
  position: sticky;
  top: 0;
  background: var(--surface);
  z-index: 2;
}

.modal-title { font-family: var(--font-display); font-weight: 700; font-size: 16px; }
.modal-body { padding: 22px; display: flex; flex-direction: column; gap: 16px; }
.modal-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 22px;
  border-top: 1px solid var(--border-soft);
  position: sticky;
  bottom: 0;
  background: var(--surface);
}

.close-x {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--text-dim);
  font-size: 16px;
  background: transparent;
  border: none;
}
.close-x:hover { background: var(--surface-3); color: var(--text); }

/* ---------- Invoice print view ---------- */
.invoice-sheet {
  background: #ffffff;
  color: #111318;
  border-radius: var(--radius-md);
  padding: 32px;
  font-family: var(--font-body);
}
.invoice-sheet * { color: inherit; }
.invoice-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; }
.invoice-brand { font-family: var(--font-display); font-weight: 700; font-size: 18px; color: #0077C8; }
.invoice-meta { text-align: right; font-size: 12px; color: #555; }
.invoice-section-title { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #888; margin-bottom: 6px; }
.invoice-table { width: 100%; border-collapse: collapse; margin: 16px 0; }
.invoice-table th { text-align: left; font-size: 11px; color: #888; border-bottom: 1px solid #ddd; padding: 6px 8px; }
.invoice-table td { padding: 8px; border-bottom: 1px solid #eee; font-size: 13px; }
.invoice-table .num { text-align: right; font-family: var(--font-mono); }
.invoice-total-row td { font-weight: 700; font-size: 15px; border-top: 2px solid #111; border-bottom: none; }

/* Pay panel. Fixed light colours rather than theme variables: this block is
   printed, and a dark-theme background would come out of the printer as a
   black rectangle with an unscannable QR code in it. */
.invoice-pay {
  display: flex; gap: 16px; align-items: center;
  margin-top: 22px; padding: 14px 16px;
  border: 1px solid #d8dde3; border-radius: 8px;
  background: #f7f9fb;
  break-inside: avoid; page-break-inside: avoid;
}
.invoice-pay-qr { flex: 0 0 auto; line-height: 0; }
.invoice-pay-qr svg { display: block; }
.invoice-pay-body { min-width: 0; }
.invoice-pay-title {
  font-size: 11px; text-transform: uppercase; letter-spacing: 1px;
  color: #0077C8; font-weight: 700; margin-bottom: 4px;
}
.invoice-pay-text { font-size: 12.5px; color: #333; margin-bottom: 6px; }
.invoice-pay-url {
  font-family: var(--font-mono); font-size: 11.5px; color: #111;
  word-break: break-all;
}
.invoice-pay-note { font-size: 11px; color: #777; margin-top: 6px; }
.invoice-pay-status {
  margin-top: 20px; padding: 10px 12px; font-size: 12.5px;
  border-left: 3px solid #0077C8; background: #f2f7fb; color: #333;
  break-inside: avoid; page-break-inside: avoid;
}
.invoice-pay-status.is-failed { border-left-color: #c0392b; background: #fdf3f2; }

@media print {
  body * { visibility: hidden; }
  .invoice-sheet, .invoice-sheet * { visibility: visible; }
  .invoice-sheet { position: absolute; top: 0; left: 0; width: 100%; }
  /* Printers and PDF engines drop background colours by default, which would
     leave the panel as floating text. The border carries it either way. */
  .invoice-pay { background: #f7f9fb !important; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ---------- Quote preview (mirrors invoice sheet; see js/quote.js) ---------- */
.quote-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; }
.quote-brand { font-family: var(--font-display); font-weight: 700; font-size: 18px; color: #0077C8; }
.quote-meta { text-align: right; font-size: 12px; color: #555; }
.quote-section-title { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #888; margin-bottom: 6px; }
.quote-table { width: 100%; border-collapse: collapse; margin: 16px 0; }
.quote-table th { text-align: left; font-size: 11px; color: #888; border-bottom: 1px solid #ddd; padding: 6px 8px; }
.quote-table td { padding: 8px; border-bottom: 1px solid #eee; font-size: 13px; }
.quote-table .num { text-align: right; font-family: var(--font-mono); }
.quote-total-row td { font-weight: 700; font-size: 15px; border-top: 2px solid #111; border-bottom: none; }

/* ---------- Contract preview (read-only, echoes js/contract.js output) ---------- */
.contract-preview {
  background: #ffffff;
  color: #111318;
  border-radius: var(--radius-md);
  padding: 28px 32px;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 12.5px;
  line-height: 1.5;
  max-height: 420px;
  overflow-y: auto;
  border: 1px solid var(--border-soft);
}
.contract-preview * { color: inherit; }
.contract-preview h1 { font-family: var(--font-display); color: #0077C8; font-size: 18px; margin: 0 0 2px 0; }
.contract-preview h1.sub { color: #111318; font-size: 14px; margin: 0 0 18px 0; }
.contract-preview h2 { font-family: var(--font-display); color: #0077C8; font-size: 12.5px; margin: 18px 0 6px 0; }
.contract-preview p { margin: 0 0 8px 0; }
.contract-preview ul { margin: 0 0 8px 0; padding-left: 18px; }
.contract-preview li { margin-bottom: 3px; }
.contract-preview .blank-fill { border-bottom: 1px solid #999; padding: 0 4px; }
.contract-preview .sig-block { display: flex; gap: 20px; margin-top: 20px; border: 1px solid #ddd; border-radius: 6px; padding: 14px; }
.contract-preview .sig-col { flex: 1; }
.contract-preview .sig-col h3 { font-family: var(--font-display); font-size: 11px; margin: 0 0 8px 0; }
.contract-preview .sig-img { max-width: 100%; height: 60px; border-bottom: 1px solid #999; display: block; object-fit: contain; object-position: left bottom; }
.contract-preview .sig-line { height: 60px; border-bottom: 1px solid #999; }
.contract-preview .sig-meta { font-size: 10px; color: #555; margin-top: 5px; }
.contract-preview .cancel-notice { margin-top: 20px; padding-top: 14px; border-top: 2px solid #111; }
.contract-preview .cancel-notice h2.center { text-align: center; color: #111318; }
.contract-preview .audit-footer { margin-top: 20px; padding-top: 10px; border-top: 1px dashed #ccc; font-family: var(--font-mono); font-size: 9.5px; color: #666; }
.contract-preview .audit-footer div { margin-bottom: 2px; }

/* ---------- Signature pad ---------- */
.sig-pad-wrap { background: #ffffff; border-radius: var(--radius-md); border: 1px solid var(--border-soft); padding: 10px; }
#signature-canvas {
  width: 100%;
  height: 180px;
  display: block;
  border: 1px dashed #ccc;
  border-radius: var(--radius-sm);
  touch-action: none;
  cursor: crosshair;
}
.sig-toolbar { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; }

/* ---------- Calendar ---------- */
.cal-toolbar {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 18px;
  flex-wrap: wrap;
}
.cal-nav-group { display: flex; gap: 4px; }
.cal-label {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  flex: 1;
}

.cal-weekday-row {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
  margin-bottom: 6px;
}
.cal-weekday {
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--text-faint);
  text-transform: uppercase;
  padding: 4px 0;
}

.cal-month-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: 108px;
  gap: 8px;
}

.cal-cell {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm);
  padding: 8px;
  cursor: pointer;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: border-color 0.12s, background 0.12s;
}
.cal-cell:hover { border-color: var(--accent-border); background: var(--surface-2); }
.cal-cell-muted { opacity: 0.4; }
.cal-cell-today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }

.cal-cell-date { font-family: var(--font-mono); font-size: 12px; color: var(--text-dim); }
.cal-cell-today .cal-cell-date { color: var(--accent-2); font-weight: 700; }

.cal-cell-jobs { display: flex; flex-direction: column; gap: 3px; overflow: hidden; }

.cal-chip {
  font-size: 10.5px;
  padding: 3px 6px;
  border-radius: 5px;
  background: var(--accent-soft);
  color: var(--accent-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  border-left: 2px solid var(--accent);
}
.cal-chip-progress { background: var(--accent-soft); border-left-color: var(--accent-2); color: var(--accent-2); }
.cal-chip-completed { background: var(--success-soft); border-left-color: var(--success); color: var(--success); }
.cal-chip-scheduled { background: var(--info-soft); border-left-color: var(--info); color: var(--info); }

.cal-more { font-size: 10px; color: var(--text-faint); padding: 1px 6px; }

.cal-week-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
}
.cal-week-col {
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 10px;
  min-height: 360px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.cal-week-col:hover { border-color: var(--accent-border); }
.cal-week-col-head {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border-soft);
  margin-bottom: 2px;
}
.cal-week-col-body { display: flex; flex-direction: column; gap: 5px; }
.cal-empty-hint { color: var(--text-faint); font-size: 12px; text-align: center; padding: 12px 0; }

/* ---------- Settings / theme swatches ---------- */
.swatch-grid { display: flex; gap: 10px; flex-wrap: wrap; }

.swatch {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  cursor: pointer;
  border: 2px solid transparent;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.15);
  transition: transform 0.1s, border-color 0.12s;
}
.swatch:hover { transform: scale(1.08); }
.swatch.active { border-color: var(--text); }

.swatch-custom {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.swatch-custom input[type="color"] {
  position: absolute;
  inset: -4px;
  width: calc(100% + 8px);
  height: calc(100% + 8px);
  border: none;
  padding: 0;
  cursor: pointer;
  opacity: 0;
}

/* ---------- Utility ---------- */
.text-dim { color: var(--text-dim); }
.text-faint { color: var(--text-faint); }
.mono { font-family: var(--font-mono); }
.mt-0 { margin-top: 0; }
.flex-between { display: flex; justify-content: space-between; align-items: center; }
.flex-row { display: flex; align-items: center; }
.gap-8 { gap: 8px; }

/* ---------- Sign-in gate ---------- */
/* Stands in place of the whole app shell, so it is a sibling of #app rather
   than a modal over it. On a local day it is never shown. */
.gate.hidden, #app.hidden, .connection-indicator.hidden, .gate-error.hidden { display: none; }

.gate {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  padding: 24px;
  overflow-y: auto;
}

.gate-card {
  width: 100%;
  max-width: 380px;
  text-align: center;
}

.gate-logo { width: 132px; margin-bottom: 28px; }
.gate-title { font-size: 20px; font-weight: 700; margin: 0 0 10px; }
.gate-body { font-size: 13px; color: var(--text-dim); line-height: 1.55; margin: 0 0 18px; }

/* Server messages and email addresses, which can be long and unbroken. */
.gate-detail {
  font-size: 12px;
  color: var(--text-faint);
  line-height: 1.5;
  margin: 0 0 18px;
  overflow-wrap: anywhere;
}

.gate-form { text-align: left; }

.gate-label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 6px;
}

.gate-input {
  width: 100%;
  padding: 10px 12px;
  margin-bottom: 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
}
.gate-input:focus { outline: none; border-color: var(--accent); }

.gate-error {
  font-size: 12px;
  color: var(--danger);
  line-height: 1.5;
  margin: 0 0 14px;
}

.gate-submit { width: 100%; }

.gate-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
}
.gate-actions .btn { width: 100%; }

/* A quieter control than .btn, for the way out of a screen rather than the
   way through it. */
.btn-link {
  background: none;
  border: none;
  padding: 4px;
  color: var(--text-dim);
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  text-decoration: underline;
}
.btn-link:hover { color: var(--text); }

.gate-reset { display: block; margin: 10px auto 0; }

/* ---------- Live connection ---------- */
.connection-indicator {
  font-size: 11px;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}

.connection-indicator::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  flex-shrink: 0;
}

.connection-indicator.offline { color: var(--warning); }
.connection-indicator.offline::before { background: var(--warning); }

.storage-status {
  font-size: 13px;
  line-height: 1.6;
  color: var(--text);
}

/* ---------- Sidebar status row + attention light ---------- */
.sidebar-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}

.sidebar-status-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* Replaces the old "Needs you" nav row. The point is that it answers "is
   anything on fire" without being clicked, so colour does the work and the
   count is secondary. */
.attention-light {
  position: relative;
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-faint);
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, box-shadow 120ms ease, background 120ms ease;
}

.attention-light svg { width: 17px; height: 17px; }

/* Calm is deliberately dull. A light that is always lit is a light nobody
   reads, so "nothing to do" has to look like nothing to do. */
.attention-light.calm:hover { color: var(--text-dim); border-color: var(--text-faint); }

.attention-light.warn {
  color: var(--warning);
  border-color: var(--warning);
  background: var(--warning-soft);
  box-shadow: 0 0 0 3px rgba(255, 178, 56, 0.10), 0 0 12px rgba(255, 178, 56, 0.35);
}

.attention-light.danger {
  color: var(--danger);
  border-color: var(--danger);
  background: var(--danger-soft);
  box-shadow: 0 0 0 3px rgba(255, 92, 122, 0.12), 0 0 14px rgba(255, 92, 122, 0.45);
  animation: attention-pulse 2.4s ease-in-out infinite;
}

/* Slow enough to read as "look here" rather than as an alarm you want to
   silence. Respects a reduced-motion preference below. */
@keyframes attention-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(255, 92, 122, 0.12), 0 0 14px rgba(255, 92, 122, 0.45); }
  50%      { box-shadow: 0 0 0 5px rgba(255, 92, 122, 0.05), 0 0 22px rgba(255, 92, 122, 0.70); }
}

@media (prefers-reduced-motion: reduce) {
  .attention-light.danger { animation: none; }
}

.attention-count {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 9px;
  background: var(--danger);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
  border: 2px solid var(--bg);
}

.attention-light.warn .attention-count { background: var(--warning); color: #2a1c00; }


/* Setup screen: the key is long enough that a single-line input hides most of
   it, which makes a paste error impossible to spot. */
.gate-key {
  resize: vertical;
  min-height: 66px;
  line-height: 1.4;
  word-break: break-all;
}

.gate-hint {
  font-size: 11.5px;
  color: var(--text-faint);
  line-height: 1.5;
  margin: -6px 0 16px;
}

/* ---------- Update ready ---------- */
/* Quiet on purpose. A new version is worth mentioning, not worth interrupting
   someone mid-quote with a dialog. */
.update-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  margin-bottom: 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent-border);
  background: var(--accent-soft);
  color: var(--accent-2);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.update-banner:hover { border-color: var(--accent); }
.update-banner.hidden { display: none; }

.update-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent-2);
  flex-shrink: 0;
}

.update-action {
  margin-left: auto;
  text-decoration: underline;
  white-space: nowrap;
}

/* ---------- Lock screen ---------- */
/* The PIN box is deliberately large and centred: it is typed many times a day,
   often in a hurry. */
.gate-pin {
  width: 100%;
  padding: 14px 12px;
  margin-bottom: 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 30px;
  letter-spacing: 0.5em;
  text-align: center;
  text-indent: 0.5em;
}
.gate-pin:focus { outline: none; border-color: var(--accent); }

.gate-pin-form { text-align: center; }

/* A checkbox with its label on one line — used where a setting is a plain
   yes/no rather than a value. */
.check-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text);
  padding: 5px 0;
  cursor: pointer;
  user-select: none;
}
.check-row input[type="checkbox"] { width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent); }

/* People and signing */
.members-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.members-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  padding: 0 10px 8px 0;
  border-bottom: 1px solid var(--border-soft);
}
.members-table td { padding: 10px 10px 10px 0; border-bottom: 1px solid var(--border-soft); vertical-align: top; }

/* The People list. Rows open a detail panel, so they read as pressable — but
   only when there is something behind them: a row that highlights and then
   does nothing is a worse answer than one that never suggested it would. */
.people-table td { vertical-align: middle; padding: 12px 10px 12px 0; }
.people-table td:last-child { width: auto; }
.people-row { cursor: pointer; }
.people-row:hover td { background: var(--surface-3); }
.people-row:hover td:first-child { border-top-left-radius: 6px; border-bottom-left-radius: 6px; }
.people-row:hover td:last-child { border-top-right-radius: 6px; border-bottom-right-radius: 6px; }
.members-table tr:last-child td { border-bottom: none; }
.members-table td:last-child { width: 40%; padding-right: 0; }

/* Document wording editor */
.clause-row {
  display: flex;
  gap: 10px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-soft);
}
.clause-row:last-of-type { border-bottom: none; }

.clause-controls { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }
.clause-controls .btn { padding: 3px 7px; min-width: 30px; }

.clause-fields { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.clause-body { font-size: 12px; line-height: 1.5; }

.template-row {
  padding: 12px 0;
  border-bottom: 1px solid var(--border-soft);
}
.template-row:last-of-type { border-bottom: none; }
.template-row .form-input { margin-bottom: 6px; }
.template-row .form-textarea { font-size: 12.5px; line-height: 1.5; }
