/* ==========================================================================
   SPARC design system
   Dorset Australia brand: charcoal #323E48 (Pantone 432c), logo red #DC2B26,
   logo orange #F07830 — see memory: dorset-brand-colours
   ========================================================================== */

:root {
  --charcoal: #323E48;
  --charcoal-800: #232C33;
  --charcoal-light: #515B63;
  --red: #DC2B26;
  --orange: #F07830;
  --orange-dark: #D0651F;

  /* The two brand button surfaces used everywhere — every orange (primary)
     and charcoal (secondary) button app-wide shares these, so there's one
     place to keep them consistent instead of each button re-declaring its
     own gradient (Nick, 2026-09-20: buttons had drifted to a flat orange
     in places, and the charcoal ones read as too subtle to look gradient
     at button size). */
  --gradient-orange: linear-gradient(135deg, var(--orange) 0%, var(--red) 130%);
  /* One charcoal gradient, used everywhere a charcoal surface appears
     (buttons, sidebar, route card, stat tiles, trend tiles) — deliberately
     wide contrast so it reads as an actual gradient rather than flat at
     small sizes like a button (Nick, 2026-09-20). */
  --gradient-charcoal: linear-gradient(135deg, var(--charcoal-light) 0%, var(--charcoal) 45%, var(--charcoal-800) 100%);

  --bg: #F5F6F8;
  --card-bg: #FFFFFF;
  --text: #1C2226;
  --muted: #6B7680;
  --border: #E6E8EB;

  --success-bg: #E4F4EA;
  --success-text: #1C6B3C;

  /* In Progress badge (Nick, 2026-09-30: was sharing Completed's green,
     needs to read as its own distinct state) - a warm yellow, not the
     Dorset brand orange (already used for Review). */
  --progress-bg: #FCF1D0;
  --progress-text: #8A6A0A;

  /* Scorecard chart series only - Overall reuses the charcoal brand colour,
     these three are just distinct enough to tell apart in a small clustered
     bar (Nick, 2026-09-22). Not used anywhere else in the app. */
  --chart-actions: var(--orange);
  --chart-followup: #F5D74F;
  --chart-opportunities: #DC2B26;
  --review-bg: #FDECDF;
  --review-text: #A34C0A;
  --error: #B3261E;

  --radius: 14px;
  --radius-sm: 10px;
  --shadow-card: 0 1px 2px rgba(20, 24, 28, 0.04), 0 4px 16px rgba(20, 24, 28, 0.06);
  --shadow-elevated: 0 12px 32px rgba(20, 24, 28, 0.14);
}

/* Dark mode — mobile only (Nick, 2026-09-18: PC always stays light, this is
   purely a mobile-in-the-field preference). The toggle in Settings just sets
   data-theme="dark" on <html>; the max-width query below makes that silently
   inert at desktop widths, so there's no need to police it in JS. */
@media (max-width: 767px) {
  html[data-theme="dark"] {
    --bg: #14181C;
    --card-bg: #2A323C;
    --text: #EDEFF1;
    --muted: #9AA3AD;
    --border: #3E4750;
    --success-bg: #163826;
    --success-text: #4ADE80;
    --progress-bg: #3A2E10;
    --progress-text: #E8C860;
    --review-bg: #3A2A1C;
    --review-text: #F2A65C;
  }
  html[data-theme="dark"] body { background: var(--bg); color: var(--text); }
  html[data-theme="dark"] .topbar { background: var(--card-bg); border-color: var(--border); }
  html[data-theme="dark"] .bottom-nav { background: var(--card-bg); border-color: var(--border); }
  /* Mobile SPARC. logo in dark mode (Nick, 2026-10-02): charcoal-on-light
     reads as near-invisible against the dark page background, so swap to
     white text - the dot stays orange either way, no override needed. */
  html[data-theme="dark"] .mobile-brand { color: var(--text); }
  html[data-theme="dark"] form input,
  html[data-theme="dark"] form textarea,
  html[data-theme="dark"] form select,
  html[data-theme="dark"] .time-picker-trigger,
  html[data-theme="dark"] .cal-picker-trigger,
  html[data-theme="dark"] .note-textarea { background: var(--card-bg); color: var(--text); border-color: var(--border); }
  html[data-theme="dark"] .date-strip-item,
  html[data-theme="dark"] .stat-tile,
  html[data-theme="dark"] .contact-row-icon,
  html[data-theme="dark"] .schedule-strip-icon { background: var(--card-bg); }
  html[data-theme="dark"] .day-nav-arrow:hover,
  html[data-theme="dark"] .date-strip-arrow:hover,
  html[data-theme="dark"] .schedule-strip-edit:hover { background: var(--border); }

  /* --charcoal is a fixed brand colour used two different ways — a dark
     SURFACE (sidebar, CTA buttons, meant to stay dark in both themes) and
     fixed "ink" TEXT colour (secondary buttons, icon badges, tab labels).
     The text usage breaks in dark mode (dark text on a now-dark card), so
     swap it to the theme-aware --text token wherever it's foreground
     content, not a background (Nick, 2026-09-18). */
  html[data-theme="dark"] .tab-btn.active,
  html[data-theme="dark"] .refresh-brief-btn,
  html[data-theme="dark"] .run-card-time,
  html[data-theme="dark"] .contact-row-icon,
  html[data-theme="dark"] .schedule-strip-icon,
  html[data-theme="dark"] .run-card-pin { color: var(--text); }

  /* The pin's circle background was var(--bg) — near-black in dark mode,
     barely distinguishable from both the page and the card behind it, so
     the icon inside read as "too dark to see properly" even with a light
     stroke colour (Nick, 2026-09-19). A lighter, visibly-distinct circle. */
  html[data-theme="dark"] .run-card-pin { background: var(--border); }
  html[data-theme="dark"] .run-card-pin:hover { background: #4a5560; }

  /* A flat colour-only surface reads as "just a black page with white
     writing" — a soft rim-light + lifted shadow gives cards actual
     presence against the near-black background (Nick, 2026-09-19). */
  html[data-theme="dark"] .card,
  html[data-theme="dark"] .run-card,
  html[data-theme="dark"] .schedule-strip,
  html[data-theme="dark"] .stat-tile,
  html[data-theme="dark"] .date-strip-item,
  html[data-theme="dark"] .time-picker-trigger,
  html[data-theme="dark"] .avatar-dropdown,
  html[data-theme="dark"] .cal-picker-popover,
  html[data-theme="dark"] .modal,
  html[data-theme="dark"] .login-card {
    box-shadow: 0 0 0 1px rgba(255,255,255,0.12), 0 10px 28px rgba(0,0,0,0.6);
  }
  html[data-theme="dark"] .stat-tile-primary {
    box-shadow: 0 0 0 1px rgba(255,255,255,0.12), 0 0 28px rgba(240,120,48,0.35), 0 10px 28px rgba(0,0,0,0.6);
  }
  html[data-theme="dark"] .new-event-btn {
    box-shadow: 0 0 24px rgba(240,120,48,0.4), 0 4px 14px rgba(0,0,0,0.5);
  }
  html[data-theme="dark"] .live-dot {
    box-shadow: 0 0 7px 1px var(--progress-text);
  }
  html[data-theme="dark"] .status-badge.completed {
    box-shadow: 0 0 10px rgba(74,222,128,0.25);
  }
  html[data-theme="dark"] .status-badge.active {
    box-shadow: 0 0 10px rgba(232,200,96,0.25);
  }
  html[data-theme="dark"] .status-badge.review {
    box-shadow: 0 0 10px rgba(242,166,92,0.25);
  }

  /* The generic ".stat-tile { background: var(--card-bg) }" rule above
     actually out-specifies these coloured-gradient tiles (an extra `html`
     selector edges past two plain classes), so it was silently flattening
     every Growth/Drop-off tile to charcoal — a real bug, not a deliberate
     dark-mode choice (Nick, 2026-09-19: "could some things stay coloured,
     even if a darker shade"). Darker versions of the same colours, not grey. */
  html[data-theme="dark"] .trend-tile.trend-strong-growth,
  html[data-theme="dark"] .trend-tile.trend-growing {
    background: linear-gradient(135deg, #1F6E3D 0%, #0E3A1F 100%);
  }
  html[data-theme="dark"] .trend-tile.trend-declining,
  html[data-theme="dark"] .trend-tile.trend-sharp-drop-off {
    background: linear-gradient(135deg, #8A2622 0%, #4A130F 100%);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

h1 { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.01em; margin: 0 0 1.1rem; }
h2 { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 600; }

/* --- App shell: sidebar (desktop) + topbar (desktop) + content --- */
.app-shell { display: flex; min-height: 100vh; width: 100%; }
.app-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.sidebar {
  display: none; /* shown ≥768px only */
  flex-direction: column;
  width: 210px; flex-shrink: 0; /* was 232px - ~10% narrower (Nick, 2026-10-01) */
  background: var(--gradient-charcoal);
  padding: 1rem 0.75rem;
  position: sticky; top: 0; height: 100vh; z-index: 5;
  transition: width 0.15s ease;
}
.sidebar.collapsed { width: 68px; }
.sidebar-nav { display: flex; flex-direction: column; gap: 0.2rem; }
/* This border sits exactly between the two <nav> groups in base.html, so it
   always falls right after however many tabs are in the main group (Nick,
   2026-09-22: repeatedly reported as not visible/not moving - it WAS
   correctly positioned, just far too faint at 10% white opacity to actually
   see against the charcoal sidebar). */
.sidebar-nav-secondary { margin-top: 0.6rem; padding-top: 0.6rem; border-top: 1px solid rgba(255,255,255,0.35); }
.sidebar-link {
  display: flex; align-items: center; gap: 0.85rem;
  padding: 0.65rem 0.75rem; border-radius: var(--radius-sm);
  color: rgba(255,255,255,0.68); text-decoration: none; font-size: 0.92rem; font-weight: 500;
  white-space: nowrap; overflow: hidden;
}
.sidebar-link svg { width: 20px; height: 20px; flex-shrink: 0; }
.sidebar-link.active, .sidebar-link:hover { background: rgba(255,255,255,0.09); color: #fff; }
.sidebar.collapsed .sidebar-link span { display: none; }
.sidebar-footer {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
  padding: 0.4rem 0.75rem 0.6rem;
  margin-top: auto; /* pins to the bottom - .sidebar-nav and .sidebar-nav-secondary
    now pack tightly together above it (see .sidebar's own comment history:
    justify-content:space-between on the parent was spreading ALL THREE
    children apart evenly instead of just pushing this one down). */
}
.sidebar-brand {
  display: flex; align-items: center; justify-content: center; gap: 0.65rem;
  color: #fff; text-decoration: none; font-weight: 700; font-size: 1.15rem;
  white-space: nowrap; overflow: hidden; min-width: 0;
}
.sidebar.collapsed .sidebar-brand span { display: none; }
.sparc-wordmark-brand {
  /* align-items: baseline (overriding .sidebar-brand's center above, same
     class-specificity but declared later) so the dot aligns to the actual
     text baseline, exactly like .sparc-phrase in the intro - NOT flex-end,
     which aligns to the bottom of the flex line's full cross-size (line-
     height included) and sat visibly lower than a real full stop (Nick,
     2026-10-01: "too low"). font-family/weight explicitly matched to the
     intro animation's .sparc-phrase too ("make sure the font ... matches"). */
  align-items: baseline;
  gap: 0; font-size: 1.7rem;
  font-family: 'Inter', sans-serif;
}
.sparc-wordmark-s, .sparc-wordmark-rest { font-weight: 900; letter-spacing: 0.01em; }
.sparc-wordmark-dot {
  display: inline-block; flex-shrink: 0;
  width: 0.26em; height: 0.26em; border-radius: 50%;
  background: var(--gradient-orange); margin-left: 0.16em;
}
/* Collapsed sidebar: keep S + dot, hide the rest of the word (Nick,
   2026-10-01). The first rule overrides the blanket span-hiding rule above
   for this specific brand variant; the second then re-hides just "PARC".
   The second selector must have >= specificity of the first (3 classes +
   a "span" type selector = (0,3,1)) or it silently loses regardless of
   source order - a plain `.sidebar.collapsed .sparc-wordmark-rest` is only
   (0,3,0) and the un-hide rule above wins instead, which is why this
   looked "correct" on disk but still showed "PARC" when collapsed. */
.sidebar.collapsed .sparc-wordmark-brand span { display: inline-block; }
.sidebar.collapsed .sparc-wordmark-brand .sparc-wordmark-rest { display: none; }

.sidebar-collapse-btn {
  flex-shrink: 0; width: 1.9rem; height: 1.9rem; border-radius: var(--radius-sm);
  background: transparent; border: none; color: rgba(255,255,255,0.4);
  cursor: pointer; box-shadow: none; padding: 0;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.15s, color 0.15s;
}
.sidebar-collapse-btn:hover { background: rgba(255,255,255,0.1); color: #fff; }
.sidebar-collapse-btn svg { width: 14px; height: 14px; transition: transform 0.15s; }
.sidebar.collapsed .sidebar-collapse-btn svg { transform: rotate(180deg); }

.topbar {
  display: none; /* shown ≥768px only */
  align-items: center; justify-content: space-between;
  padding: 0.7rem 1.5rem; background: var(--card-bg); border-bottom: 1px solid var(--border);
}
.topbar-email { font-size: 0.85rem; color: var(--muted); font-weight: 500; }
.topbar-actions { display: flex; align-items: center; gap: 0.75rem; }

.mobile-topbar-actions {
  position: fixed; top: calc(0.75rem + env(safe-area-inset-top)); right: 0.85rem; z-index: 25;
  display: flex; align-items: center; gap: 0.6rem;
}
/* Mobile-only SPARC. wordmark (Nick, 2026-10-01) - the sidebar brand is
   desktop-only (.sidebar is display:none below 768px), so mobile had no
   logo at all until now. Mirrors .mobile-topbar-actions on the opposite
   corner; reuses the exact same markup/classes as the sidebar brand so the
   font/weight/dot-alignment stay identical, just smaller and in the page's
   ink colour instead of white-on-charcoal. */
/* Solid bar behind the mobile logo/notif/avatar row (Nick, 2026-10-05) -
   those were just floating directly over whatever content happened to
   scroll underneath, no backdrop. Sits one z-index below them. */
.mobile-topbar-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 24;
  height: calc(3.6rem + env(safe-area-inset-top));
  background: var(--card-bg); border-bottom: 1px solid var(--border);
}
@media (min-width: 768px) { .mobile-topbar-bar { display: none; } }

.mobile-brand {
  position: fixed; top: calc(0.75rem + env(safe-area-inset-top)); left: 0.95rem; z-index: 25;
  /* was var(--text) (#1C2226, near-black) - should be the actual brand
     charcoal like everywhere else (Nick, 2026-10-01: "looks more black"). */
  color: var(--charcoal); text-decoration: none; font-size: 1.2rem;
}
.mobile-brand .sparc-wordmark-dot { background: var(--gradient-orange); }
@media (min-width: 768px) { .mobile-brand { display: none; } }
/* Shared by the mobile topbar (inside .mobile-topbar-actions) and the
   desktop topbar (Nick, 2026-09-23: "same size as the avatar") - same
   2.1rem circle as .avatar-btn in both places, since it's meant to read as
   a matching pair next to it, not a smaller/different accessory. */
.notif-btn {
  position: relative;
  width: 2.1rem; height: 2.1rem; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--card-bg); color: var(--muted); padding: 0; cursor: pointer;
  border: 1.5px solid rgba(0,0,0,0.08); box-shadow: var(--shadow-card);
}
.notif-btn svg { width: 19px; height: 19px; }
.notif-btn.active { color: var(--orange-dark); }
.notif-btn:hover { filter: brightness(1.15); }
.notif-dot {
  position: absolute; top: -0.05rem; right: -0.05rem;
  width: 0.6rem; height: 0.6rem; border-radius: 50%;
  background: var(--orange); border: 1.5px solid var(--card-bg);
}
.notif-dropdown { width: 22rem; max-width: min(22rem, calc(100vw - 2rem)); max-height: 70vh; overflow-y: auto; padding: 0; }
.notif-panel-body { max-height: 60vh; overflow-y: auto; }
.notif-row {
  display: flex; gap: 0.6rem; align-items: flex-start;
  padding: 0.7rem 1rem; text-decoration: none; color: var(--text);
  border-bottom: 1px solid var(--border);
}
/* The dropdown itself carries class="avatar-dropdown notif-dropdown", so
   each row also matches `.avatar-dropdown a { display: block }` below -
   which wins on pure specificity (a class + element beats one class
   alone) regardless of being declared first here, silently turning this
   back into an inline/block link. That's why .notif-row-dot's width/
   height had no effect (inline elements don't size via width/height) even
   though its colour logic was already correct (Nick, 2026-10-02: "bell has
   a dot but entries don't") - confirmed via a real headless-browser check,
   not guessed. Re-asserted here at higher specificity than that rule. */
.avatar-dropdown a.notif-row { display: flex; padding: 0.7rem 1rem; }
.notif-row:last-child { border-bottom: none; }
.notif-row:hover { background: var(--bg); }
.notif-row-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 50%; flex-shrink: 0; margin-top: 0.4rem;
  background: transparent;
}
.notif-row.unread .notif-row-dot { background: var(--orange); }
.notif-row-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.notif-row-message { font-size: 0.88rem; font-weight: 600; }
.notif-row.unread .notif-row-message { font-weight: 700; }
.notif-row-time { font-size: 0.76rem; color: var(--muted); }

@media (min-width: 768px) {
  .sidebar { display: flex; }
  .topbar { display: flex; }
  .mobile-topbar-actions { display: none; }
}

/* --- Avatar menu --- */
.avatar-menu { position: relative; margin-left: auto; }
.avatar-btn {
  width: 2.1rem; height: 2.1rem; border-radius: 50%;
  color: #fff; border: 1.5px solid rgba(0,0,0,0.08); box-shadow: var(--shadow-card);
  font-size: 0.9rem; font-weight: 700; cursor: pointer;
  padding: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.avatar-btn:hover { filter: brightness(1.15); }
.avatar-btn img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-dropdown {
  position: absolute; top: calc(100% + 0.6rem); right: 0;
  background: var(--card-bg); color: var(--text); border-radius: var(--radius-sm); min-width: 190px;
  box-shadow: var(--shadow-elevated); overflow: hidden; z-index: 30;
  border: 1px solid var(--border);
}
.avatar-dropdown-name {
  padding: 0.75rem 1rem 0.55rem; font-size: 0.85rem; font-weight: 600;
  border-bottom: 1px solid var(--border); word-break: break-word;
}
.avatar-dropdown a {
  display: block; padding: 0.65rem 1rem; color: var(--text); text-decoration: none; font-size: 0.9rem;
}
.avatar-dropdown a:hover { background: var(--bg); }
.avatar-dropdown-toggle {
  display: flex; align-items: center; justify-content: center;
  padding: 0.65rem 1rem; border-top: 1px solid var(--border);
}

.theme-switch {
  position: relative; width: 2.9rem; height: 1.5rem; border-radius: 999px;
  background: var(--border); border: none; padding: 0; cursor: pointer; flex-shrink: 0;
  transition: background 0.15s;
}
.theme-switch.on { background: var(--charcoal); }
.theme-switch:hover { background: var(--border); }
.theme-switch.on:hover { background: var(--charcoal-800); }
.theme-switch-track {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: space-between;
  padding: 0 0.3rem; font-size: 0.68rem; line-height: 1; pointer-events: none;
}
.theme-switch-knob {
  position: absolute; top: 0.15rem; left: 0.15rem; width: 1.2rem; height: 1.2rem;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.35);
  transition: left 0.15s;
}
.theme-switch.on .theme-switch-knob { left: calc(100% - 1.35rem); }

/* --- Main --- */
.app-main {
  flex: 1;
  padding: 1.1rem 1rem 5.5rem;
  max-width: 640px;
  width: 100%;
  margin: 0 auto;
}
body.no-nav .app-main { padding-bottom: 1.1rem; }

@media (min-width: 768px) {
  .app-main { max-width: 780px; padding-bottom: 2rem; position: relative; }
}
/* The fixed-position mobile logo (top-left) and notif/avatar icons
   (top-right) float above the page without pushing content down, so every
   page's own heading - not just Home's Dashboard/Action Centre switch -
   needs clearance or it runs into them (Nick, 2026-10-01: "Transcripts Log"
   example). One site-wide rule instead of patching each page. */
@media (max-width: 767px) {
  /* Was 3.25rem - the mobile topbar bar (Nick, 2026-10-05) is 3.6rem tall
     plus env(safe-area-inset-top), so content was underlapping it slightly
     (Nick: "Dashboard/Action Centre toggle sits a bit high... underlaps the
     top banner"). Matches the bar's own height plus a small gap. */
  .app-main { padding-top: calc(3.6rem + env(safe-area-inset-top) + 0.5rem); }
}

/* Tile-grid pages (Action Centre) scale with the viewport instead of
   staying capped at reading-column width (Nick, 2026-09-29: "look at all
   the wasted space" on a full monitor) - other pages (forms, debrief text,
   tables) keep the narrower default, since a wide reading column isn't
   actually more readable. */
@media (min-width: 1024px) { .app-main.wide-main { max-width: 1100px; } }
@media (min-width: 1400px) { .app-main.wide-main { max-width: 1500px; } }
@media (min-width: 1800px) { .app-main.wide-main { max-width: 1900px; } }

/* --- Back icon button (desktop only — Android's own back button covers mobile) --- */
.back-icon-btn { display: none; }
@media (min-width: 768px) {
  .back-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 1.1rem;
    right: 0;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    color: var(--text-secondary, #6b7680);
    background: transparent;
    transition: background 0.15s, color 0.15s;
  }
  .back-icon-btn:hover { background: var(--border, #e4e6ea); color: var(--text); }
  .back-icon-btn svg { width: 18px; height: 18px; }
}

/* --- Bottom nav --- */
.bottom-nav {
  position: fixed; bottom: 0; left: 0; right: 0;
  display: flex;
  background: var(--card-bg);
  border-top: 1px solid var(--border);
  padding: 0.35rem 0 calc(0.35rem + env(safe-area-inset-bottom));
  z-index: 20;
  box-shadow: 0 -2px 10px rgba(20,24,28,0.05);
}
.bottom-nav a {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  padding: 0.35rem 0;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.68rem; font-weight: 500;
}
.bottom-nav a svg { width: 22px; height: 22px; }
.bottom-nav a.active { color: var(--orange-dark); }

.bottom-nav-more-btn {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  padding: 0.35rem 0;
  color: var(--muted); background: transparent; border: none; box-shadow: none;
  font-size: 0.68rem; font-weight: 500; cursor: pointer;
}
.bottom-nav-more-btn svg { width: 22px; height: 22px; }
.bottom-nav-more-btn.active { color: var(--orange-dark); }
.bottom-nav-more-menu {
  position: fixed; right: 0.6rem; bottom: calc(3.6rem + env(safe-area-inset-bottom));
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-elevated); padding: 0.4rem; z-index: 21;
  display: flex; flex-direction: column; min-width: 10rem;
}
.bottom-nav-more-menu a {
  display: flex; align-items: center; gap: 0.7rem; padding: 0.6rem 0.7rem;
  border-radius: var(--radius-sm); color: var(--text); text-decoration: none; font-size: 0.88rem; font-weight: 500;
}
.bottom-nav-more-menu a svg { width: 18px; height: 18px; color: var(--muted); flex-shrink: 0; }
.bottom-nav-more-menu a.active { background: var(--bg); color: var(--orange-dark); }
.bottom-nav-more-menu a.active svg { color: var(--orange-dark); }
@media (min-width: 768px) {
  .bottom-nav-more-menu { display: none; }
}

/* Mobile-only, always — must come after the base .bottom-nav rule above so
   it actually wins the cascade at desktop widths (a bug found 2026-09-16:
   this exact override previously sat BEFORE the base rule and lost). */
@media (min-width: 768px) {
  .bottom-nav { display: none; }
}
.bottom-nav a.active svg { stroke: var(--orange-dark); }

/* --- Cards / forms (shared) --- */
.card {
  background: var(--card-bg);
  border-radius: var(--radius);
  padding: 1.25rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-card);
  border: 1px solid var(--border);
}
.login-card { background: var(--card-bg); border-radius: var(--radius); padding: 1.75rem 1.5rem; margin-top: 2rem; box-shadow: var(--shadow-elevated); }
.login-card h1 { margin-top: 0; }
/* Branded error pages (Nick, 2026-10-02) - 404/403/500/etc. reuse the same
   standalone centred card as the login page, rather than a bare FastAPI
   JSON error, so it still reads as "the app", not a broken server. */
.error-card { text-align: center; }
.error-code {
  font-size: 3.4rem; font-weight: 900; color: var(--charcoal); line-height: 1;
  margin: 1.25rem 0 0.4rem;
}
.error-message { font-size: 1rem; color: var(--text); margin: 0 0 1.4rem; }
.error-home-link { display: inline-block; text-decoration: none; }
.error-fine-print {
  margin: 1.5rem 0 0; padding-top: 1rem; border-top: 1px solid var(--border);
  font-size: 0.76rem; color: var(--muted); font-family: ui-monospace, monospace;
  word-break: break-word;
}
/* Same SPARC. wordmark markup/classes as the sidebar/mobile logo (Nick,
   2026-10-01: login's plain "SPARC." text heading "needs to match other
   logos throughout the app") - .login-brand just supplies the missing
   `display: flex` (normally inherited from .sidebar-brand, which this
   standalone heading doesn't also carry) plus centering and the bigger
   size a login page heading warrants. The compound selector beats
   .sparc-wordmark-brand's own font-size regardless of rule order. */
.login-brand.sparc-wordmark-brand {
  display: flex; align-items: baseline; justify-content: center;
  color: var(--charcoal); font-size: 2.2rem;
}

form label { display: block; margin-bottom: 1rem; font-size: 0.88rem; color: var(--muted); font-weight: 500; }
form input, form textarea, form select {
  display: block; width: 100%; margin-top: 0.4rem; padding: 0.7rem 0.8rem;
  font-size: 0.95rem; border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  font-family: inherit; background: var(--card-bg); color: var(--text);
  transition: border-color 0.15s;
}
form input:focus, form textarea:focus, form select:focus {
  outline: none; border-color: var(--orange);
}
form input[type="checkbox"] { accent-color: var(--charcoal); width: auto; }
/* A checkbox with its own label text on one line, used by Generate Price
   List's scope/output toggles (Nick, 2026-10-07) - not a bespoke style per
   form, since any future checkbox+label row can reuse this. */
.checkbox-row { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; font-weight: 400; }

/* Trade Login's contact list (Nick, 2026-10-14) - checkbox, name (flexes),
   editable email pinned to a fixed-ish width on the right - distinct from
   a plain .checkbox-row since that one's label text is meant to flex full
   width, not share the row with its own input field. */
.tl-contact-row { padding: 0.5rem 0; border-bottom: 1px solid var(--border); cursor: default; }
.tl-contact-row:last-child { border-bottom: none; }
.tl-contact-name { flex: 1; }
.tl-contact-email { width: 13rem; max-width: 45%; }

button, .btn {
  padding: 0.75rem 1.15rem; background: var(--gradient-orange); color: #fff;
  border: none; border-radius: var(--radius-sm); font-size: 0.95rem; font-weight: 600; cursor: pointer;
  text-decoration: none; display: inline-block; text-align: center;
  transition: filter 0.15s, transform 0.1s;
}
button:hover, .btn:hover { filter: brightness(1.05); }
button:active, .btn:active { transform: scale(0.98); }
button.secondary, .btn.secondary {
  background: var(--gradient-charcoal); color: #fff; border: none;
}
button.secondary:hover, .btn.secondary:hover { filter: brightness(1.15); }
button.link-btn, .link-btn {
  background: none; border: none; color: var(--muted); text-decoration: underline;
  font-size: 0.8rem; padding: 0; cursor: pointer; font-weight: 500;
}
.link-btn:hover { color: var(--error); background: none; }
button:disabled { opacity: 0.5; cursor: default; }
.btn-danger { background: var(--card-bg); color: var(--error); border: 1.5px solid var(--error); }
.btn-danger:hover { background: #fdf1f0; }
.error { color: var(--error); font-size: 0.9rem; }
.success-note { color: var(--success-text); font-size: 0.9rem; font-weight: 500; }

/* --- Search list --- */
.search-box input {
  width: 100%; padding: 0.85rem 1rem; font-size: 1rem; border: 1.5px solid var(--border);
  border-radius: var(--radius-sm); margin-bottom: 0.75rem; background: var(--card-bg);
}
.result-row {
  display: flex; align-items: center; justify-content: space-between; cursor: pointer;
  background: var(--card-bg); border-radius: var(--radius-sm); padding: 0.85rem 1rem; margin-bottom: 0.5rem;
  box-shadow: var(--shadow-card); border: 1px solid var(--border);
}
.result-row .name { font-weight: 500; }
.result-row button { padding: 0.5rem 0.9rem; font-size: 0.85rem; }
.empty-state { color: var(--muted); text-align: center; padding: 2.5rem 1rem; font-size: 0.92rem; }

/* --- Modal --- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(30,35,40,0.55); backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center; z-index: 50; padding: 1rem;
}
.modal { background: var(--card-bg); border-radius: var(--radius); padding: 1.5rem; max-width: 360px; width: 100%; text-align: center; box-shadow: var(--shadow-elevated); }
.modal h3 { margin-top: 0; }
.modal .actions { display: flex; gap: 0.75rem; margin-top: 1.25rem; }
.modal .actions button { flex: 1; }
[hidden] { display: none !important; }

/* Schedule-edit spinner (Nick, 2026-10-06) - a time/length edit always
   triggers a real round trip (save, recompute the day's schedule server-
   side, often a fresh Directions call for the route card too) before the
   tiles/map actually reflect it; with nothing on screen in the meantime it
   read as broken rather than just working ("could there be a little loader
   or timer... to show it is doing stuff"). */
.rs-updating-pill {
  position: absolute; top: 0.6rem; right: 0.6rem; z-index: 5;
  display: flex; align-items: center; gap: 0.4rem;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: 999px;
  padding: 0.3rem 0.7rem; font-size: 0.78rem; color: var(--muted);
  box-shadow: var(--shadow-card);
}
.rs-spinner {
  width: 13px; height: 13px; border-radius: 50%; flex-shrink: 0;
  border: 2px solid var(--border); border-top-color: var(--orange);
  animation: rs-spin 0.7s linear infinite;
}
@keyframes rs-spin { to { transform: rotate(360deg); } }

.loading-bar-track {
  width: 100%; height: 0.55rem; border-radius: 999px; background: var(--border); overflow: hidden;
}
.loading-bar-fill {
  height: 100%; width: 0%; border-radius: 999px; background: var(--gradient-orange);
  transition: width 0.25s linear;
}

/* Enter Order's review form, popped up in a modal instead of navigating to
   its own page (Nick, 2026-09-23) - wider and left-aligned, scrollable
   since order lines can run long, unlike the small centered confirm-style
   modals above. */
.action-review-modal {
  max-width: 32rem; text-align: left; max-height: 90vh; overflow-y: auto;
}
.action-review-head {
  position: relative; margin-bottom: 0.4rem;
  display: flex; flex-direction: column; align-items: flex-start; gap: 0.35rem;
  padding-right: 2.1rem;
}
.action-review-head .action-review-customer { text-align: left; }
.action-review-close {
  position: absolute; top: -0.3rem; right: -0.3rem;
  display: flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem; border-radius: 50%; flex-shrink: 0;
  color: var(--muted); text-decoration: none; font-size: 1.3rem; line-height: 1;
  transition: background 0.15s, color 0.15s;
}
.action-review-close:hover { background: var(--bg); color: var(--error); }

.brief-meta-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.refresh-brief-btn {
  display: inline-flex; align-items: center; gap: 0.4rem; background: var(--card-bg);
  color: var(--charcoal); border: 1.5px solid var(--border); border-radius: 999px;
  padding: 0.4rem 0.9rem 0.4rem 0.7rem; font-size: 0.8rem; font-weight: 600;
}
.refresh-brief-btn:hover { background: var(--bg); border-color: var(--charcoal); }
.refresh-brief-btn svg { width: 14px; height: 14px; }

.key-objective-card { border-left: 4px solid var(--orange); }
.key-objective-label {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--muted); font-weight: 700; display: block; margin-bottom: 0.4rem;
}
.key-objective { font-size: 1.02rem; font-weight: 500; margin: 0; }

.trend-tile { align-items: flex-start; }
.trend-emoji { font-size: 1.5rem; line-height: 1; }
.trend-tile.trend-strong-growth, .trend-tile.trend-growing { background: linear-gradient(135deg, var(--success-text) 0%, #164f2c 100%); }
.trend-tile.trend-declining, .trend-tile.trend-sharp-drop-off { background: linear-gradient(135deg, var(--red) 0%, #a11e1a 100%); }
.trend-tile.trend-flat, .trend-tile.trend-no-recent-activity { background: var(--gradient-charcoal); }

.dot-list { list-style: none; padding: 0; }
.dot-list li { display: flex; align-items: flex-start; gap: 0.6rem; margin-bottom: 0.55rem; }
.dot-list-marker { width: 7px; height: 7px; border-radius: 50%; background: var(--orange); flex-shrink: 0; margin-top: 0.45rem; }

.bar-chart { display: flex; align-items: flex-end; gap: 0.6rem; height: 8rem; padding-top: 1.2rem; }
.bar-chart-col { flex: 1; display: flex; flex-direction: column; align-items: center; height: 100%; min-width: 0; }
.bar-chart-value { font-size: 0.62rem; font-weight: 700; color: var(--muted); margin-bottom: 0.3rem; white-space: nowrap; }
.bar-chart-track { flex: 1; width: 100%; display: flex; align-items: flex-end; }
.bar-chart-fill { width: 100%; min-height: 3px; background: linear-gradient(180deg, var(--orange) 0%, var(--red) 100%); border-radius: 5px 5px 0 0; }
.bar-chart-label { font-size: 0.68rem; color: var(--muted); margin-top: 0.4rem; }

.pricing-chip-list { display: flex; flex-direction: column; gap: 0.65rem; }
.pricing-chip-row { display: flex; justify-content: space-between; font-size: 0.88rem; margin-bottom: 0.3rem; }
.pricing-chip-name { font-weight: 600; }
.pricing-chip-value { font-variant-numeric: tabular-nums; color: var(--muted); }
.pricing-chip-track { height: 8px; background: var(--bg); border-radius: 999px; overflow: hidden; }
.pricing-chip-fill { height: 100%; background: linear-gradient(90deg, var(--orange) 0%, var(--red) 100%); border-radius: 999px; }

/* --- Brief / debrief sections --- */
.brief-section { margin-bottom: 1.5rem; }
.brief-section h2 { margin-bottom: 0.6rem; border-bottom: 1px solid var(--border); padding-bottom: 0.4rem; }

.scorecard-rep-picker { margin-bottom: 1rem; }
.scorecard-rep-picker select { width: 100%; max-width: 320px; }
.scorecard-section-title { margin: 1.4rem 0 0.15rem; }
.scorecard-section-title:first-of-type { margin-top: 0; }

/* --- Scorecard: rolling 12-month clustered bar chart --- */
.score-chart-legend { display: flex; flex-wrap: wrap; gap: 0.9rem; margin: 0.5rem 0 1rem; }
.score-chart-legend-item { display: flex; align-items: center; gap: 0.4rem; font-size: 0.76rem; color: var(--muted); font-weight: 600; }
.score-chart-legend-dot { width: 0.6rem; height: 0.6rem; border-radius: 50%; flex-shrink: 0; }
.score-chart-legend-dot.dim-overall { background: var(--charcoal); }
.score-chart-legend-dot.dim-actions_generated { background: var(--chart-actions); }
.score-chart-legend-dot.dim-follow_up { background: var(--chart-followup); }
.score-chart-legend-dot.dim-opportunities_identified { background: var(--chart-opportunities); }

.score-chart-scroll { overflow-x: auto; margin: 0 -1rem; padding: 0 1rem 0.25rem; -webkit-overflow-scrolling: touch; }
.score-chart { display: flex; align-items: flex-end; gap: 1.1rem; height: 9rem; padding-top: 1rem; }
.score-chart-month { display: flex; flex-direction: column; align-items: center; height: 100%; flex-shrink: 0; }
.score-chart-cluster { flex: 1; display: flex; align-items: flex-end; gap: 3px; }
.score-chart-bar { width: 7px; min-height: 3px; border-radius: 3px 3px 0 0; }
.score-chart-bar.dim-overall { background: var(--charcoal); }
.score-chart-bar.dim-actions_generated { background: var(--chart-actions); }
.score-chart-bar.dim-follow_up { background: var(--chart-followup); }
.score-chart-bar.dim-opportunities_identified { background: var(--chart-opportunities); }
.score-chart-label { font-size: 0.66rem; color: var(--muted); margin-top: 0.45rem; white-space: nowrap; }

/* --- Scorecard: coaching tips as cards, not a bullet list (Nick, 2026-09-22:
   "I hate dotpoint paragraphs for things like this") --- */
.coaching-tip-list { display: flex; flex-direction: column; gap: 0.75rem; margin-top: 0.75rem; }
.coaching-tip-card {
  background: var(--card-bg); border: 1px solid var(--border); border-left: 4px solid var(--chart-followup);
  border-radius: var(--radius-sm); padding: 0.85rem 1rem;
}
.coaching-tip-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; flex-wrap: wrap; }
.coaching-tip-customer { font-weight: 700; font-size: 0.94rem; }
.coaching-tip-score { font-weight: 700; color: var(--muted); font-size: 0.85rem; flex-shrink: 0; }
.coaching-tip-date { font-size: 0.72rem; color: var(--muted); margin-top: 0.1rem; }
.coaching-tip-note { margin: 0.4rem 0 0; font-size: 0.88rem; }

/* --- Debrief: Follow-up Actions, label on its own line above the
   description rather than an inline "Kind: description" that wraps badly
   on mobile (Nick, 2026-09-22) --- */
.action-item-list { display: flex; flex-direction: column; gap: 0.85rem; }
.action-item-head { display: flex; align-items: center; gap: 0.55rem; }
.action-item-kind { font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--charcoal); }
.action-item-desc { margin: 0.3rem 0 0 1.15rem; font-size: 0.92rem; }

.review-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.85rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.review-header-text { flex: 1 1 auto; min-width: 0; }
.review-header-text h1 { word-break: break-word; }
/* Vertically stacked, screen-wide tiles rather than a cramped side-by-side
   grid (Nick, 2026-09-22: needed to be mobile-friendly) - the Overall tile
   leads in charcoal, same pattern as .stat-tile-primary elsewhere. */
.event-score-stack { display: flex; flex-direction: column; gap: 0.75rem; margin-top: 0.9rem; }
.event-score-tile { background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1rem; text-align: center; }
.event-score-value { font-size: 1.6rem; font-weight: 700; color: var(--charcoal); }
.event-score-max { font-size: 0.95rem; font-weight: 500; color: var(--muted); }
.event-score-label { font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); margin: 0.2rem 0 0.5rem; }
.event-score-tile-overall { background: var(--gradient-charcoal); border: none; }
.event-score-tile-overall .event-score-value { color: #fff; font-size: 2rem; }
.event-score-tile-overall .event-score-max { color: rgba(255,255,255,0.65); }
.event-score-tile-overall .event-score-label { color: rgba(255,255,255,0.75); margin-bottom: 0; }
.activity-summary { padding-left: 0; margin: 0; }
.growth-note { background: var(--review-bg); color: var(--review-text); padding: 0.8rem 1rem; border-radius: var(--radius-sm); font-size: 0.9rem; margin: 0.9rem 0 1.4rem; }
.account-flag {
  background: #FBEAE9; color: var(--error); border: 1px solid #F3C8C5;
  padding: 0.65rem 0.9rem; border-radius: var(--radius-sm); font-size: 0.9rem; font-weight: 500;
  margin-bottom: 1rem;
}

/* --- Task Manager --- */
.task-tile-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 0.9rem;
  margin-bottom: 1.5rem;
}
.task-tile {
  position: relative; overflow: hidden;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-card); padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: 0.5rem;
}
/* Opaque "In progress..." cover while Enter Order's Sales Order creation
   runs in the background (Nick, 2026-10-09: "put like an opaque orange
   tile over the action card with white writing... user can carry on with
   other actions") - the tile underneath keeps its real layout/content, this
   just sits on top of it until the poll in _task_tile_grid.html's script
   sees the card land on pushed/draft and refreshes the grid. */
.task-tile-overlay {
  position: absolute; inset: 0; background: var(--gradient-orange); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 0.95rem; letter-spacing: 0.01em; z-index: 5;
}
/* Badge above name, always (Nick, 2026-10-07) - the old row layout had the
   customer name float right and wrap below the badge once it ran long,
   so a tile's layout changed depending purely on how long the customer's
   name happened to be. Stacked order is consistent regardless of name
   length, for both the tile and its review pop-up (.action-review-head
   below reuses this same .task-tile-kind/.task-tile-customer pairing). */
.task-tile-head { display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem; }
/* Small date stamp, top right corner of the card (Nick, 2026-10-14) - when
   the card was actually created, so an old card sitting unactioned stands
   out at a glance without having to open it. */
.task-tile-date-stamp { position: absolute; top: 0.7rem; right: 0.9rem; font-size: 0.68rem; color: var(--muted); }
.task-tile-kind {
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  color: var(--orange-dark); background: var(--review-bg); padding: 0.2rem 0.55rem; border-radius: 999px;
}
.task-tile-customer { font-weight: 700; font-size: 0.92rem; text-align: left; }
.task-tile-desc { font-size: 0.9rem; color: var(--text); margin: 0; }
.task-tile-meta { font-size: 0.76rem; color: var(--muted); margin: 0; }
.task-tile-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-top: auto; padding-top: 0.4rem; }
.task-tile-actions-main { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; flex: 1; min-width: 0; }
.task-tile-inline-form { margin: 0; }
.task-tile-btn { padding: 0.5rem 0.9rem; font-size: 0.85rem; }
/* Generate Price List's blocked-by-an-open-Set-Pricing-card state (Nick,
   2026-10-07: "make the pending button... grey, as in like greyed out") -
   visibly disabled-looking, not an inviting action colour, so it reads as
   "waiting on something else" rather than "ready to review". Still a real
   clickable button (not [disabled]) so tapping it can explain why. */
.task-tile-btn-pending {
  background: var(--border); color: var(--muted); border: none; cursor: pointer;
}
.task-tile-btn-pending:hover { background: var(--muted); color: #fff; }
.task-tile-delete-btn {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 2.2rem; height: 2.2rem; padding: 0; border-radius: 50%;
  color: var(--muted); background: transparent; border: none; cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.task-tile-delete-btn svg { width: 16px; height: 16px; }
.task-tile-delete-btn:hover { background: var(--bg); color: var(--error); }
.task-tile-done { opacity: 0.55; }
.task-tile-done .task-tile-kind { background: var(--border); color: var(--muted); }

/* --- Task Manager: Enter Order review screen --- */
.order-line {
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.85rem;
  margin-bottom: 0.75rem; background: var(--card-bg);
}
.order-line-requested { font-weight: 600; font-size: 0.92rem; }
.order-line-note { font-size: 0.8rem; color: var(--muted); margin: 0.2rem 0 0; }
.order-line-row { display: flex; align-items: flex-start; gap: 0.6rem; margin-top: 0.6rem; flex-wrap: wrap; }
.order-line-search { flex: 1 1 14rem; min-width: 10rem; margin: 0; position: relative; }
.order-line-search input { margin-bottom: 0; }
.order-line-qty { width: 5rem; flex-shrink: 0; }
.order-line-remove { flex-shrink: 0; font-size: 0.8rem; color: var(--error); }
.order-line-results:not(:empty) {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 10; margin-top: 0.3rem;
  max-height: 12rem; overflow-y: auto; background: var(--card-bg); border: 1px solid var(--border);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-elevated); padding: 0.3rem;
}
@media (max-width: 480px) {
  .order-line-row { flex-direction: column; align-items: stretch; }
  .order-line-qty { width: 100%; }
  /* .order-line-search's flex-basis (14rem) means WIDTH in the normal row
     layout, but once flex-direction flips to column right above, the same
     basis applies to its cross-axis instead - HEIGHT - stretching the
     search box to a blank 224px box with nothing in it (Nick, 2026-10-07,
     confirmed live on Set Pricing's review modal, which reuses this same
     class - pre-existing on Enter Order's identical layout too, just never
     surfaced until this reused it). flex-basis: auto lets height follow
     its actual content again. */
  .order-line-search { flex-basis: auto; }
}

/* --- Set Pricing: mixed Group/Item rows in one list (Nick, 2026-10-08) --- */
.pricing-row-kind-label {
  font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); margin-bottom: 0.3rem;
}
.pricing-row-item .pricing-row-kind-label { color: var(--orange); }
.pricing-row-group .pricing-row-kind-label { color: var(--charcoal); }
.pricing-item-notes {
  width: 100%; margin-top: 0.6rem; font-family: inherit; font-size: 0.85rem;
  resize: vertical; min-height: 2.4rem;
}
.pricing-add-buttons { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 0.5rem; }

.knowledge-toolbar { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.knowledge-search-box { flex: 1; min-width: 10rem; margin: 0; }

/* Action Centre's Customer Name / Action Type filters (Nick, 2026-10-14;
   restyled same day - "the dropdown list is very oldschool... the customer
   name text filter is huge" - neither was actually inside a <form>, so
   neither picked up this app's own form input/select styling at all and
   fell back to raw unstyled browser chrome. Styled directly here instead,
   at a size that fits a compact inline toolbar rather than reusing
   .search-box's page-level large search input or a bare native <select>'s
   own arrow.) */
.task-tile-filter-bar { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.task-tile-filter-input {
  flex: 1; min-width: 10rem; max-width: 18rem; padding: 0.55rem 0.8rem; font-size: 0.85rem;
  font-family: inherit; border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card-bg); color: var(--text); transition: border-color 0.15s;
}
.task-tile-filter-input:focus { outline: none; border-color: var(--orange); }
.task-tile-filter-select-wrap { position: relative; }
.task-tile-filter-select {
  appearance: none; -webkit-appearance: none;
  padding: 0.55rem 2.1rem 0.55rem 0.8rem; font-size: 0.85rem; font-family: inherit;
  border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card-bg); color: var(--text); cursor: pointer; transition: border-color 0.15s;
}
.task-tile-filter-select:focus { outline: none; border-color: var(--orange); }
.task-tile-filter-select-chevron {
  position: absolute; top: 50%; right: 0.7rem; width: 14px; height: 14px;
  transform: translateY(-50%); color: var(--muted); pointer-events: none;
}
.knowledge-search-box input { margin-bottom: 0; }

/* --- Settings --- */
.settings-section { margin-bottom: 2rem; }
.settings-section h2 { font-size: 1.05rem; text-transform: none; letter-spacing: 0; color: var(--text); margin-bottom: 0.75rem; }
.small { font-size: 0.8rem; color: var(--muted); }
textarea.prompt-editor { min-height: 260px; font-family: ui-monospace, monospace; font-size: 0.8rem; }

.tabs {
  display: inline-flex; gap: 0.2rem; margin-bottom: 1.5rem;
  background: var(--border); border-radius: var(--radius-sm); padding: 0.25rem;
}
.tab-btn {
  appearance: none; -webkit-appearance: none;
  background: transparent; border: none; outline: none;
  color: var(--muted); font: inherit; font-size: 0.88rem;
  padding: 0.5rem 1.1rem; border-radius: 8px; cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.tab-btn.active { background: var(--card-bg); color: var(--charcoal); font-weight: 600; box-shadow: 0 1px 2px rgba(0,0,0,0.08); }
.tab-btn:hover { background: var(--card-bg); color: var(--text); }

/* Home's Dashboard/Task Manager switch reads "Dashboard, Task Manager" on a
   phone (Dashboard loads first) but "Task Manager, Dashboard" on a computer
   (Task Manager loads first) - Nick, 2026-09-23. Scoped to this one switch,
   not .tabs generally (Settings' tab bar also uses .tabs and must not flip). */
@media (min-width: 768px) {
  .home-view-tabs { flex-direction: row-reverse; }
}
.home-view-tabs-row { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.home-view-tabs-row .home-view-tabs { margin-bottom: 0; }
/* A small orange count bubble pinned to the Action Centre toggle's own
   corner (Nick, 2026-10-08: "instead of the 'X cards to action' badge...
   just the number in an orange bubble on the top right corner of the
   Action Centre toggle... visible regardless of computer or mobile view")
   - replaces the old separate "N cards to action" pill, which only showed
   while the Action Centre view itself was open; this one is part of the
   toggle button, so it's there on page load regardless of which view is
   active or showing. */
.tab-btn-with-badge { position: relative; overflow: visible; }
.tab-badge-bubble {
  position: absolute; top: -0.4rem; right: -0.4rem; min-width: 1.15rem; height: 1.15rem;
  padding: 0 0.3rem; border-radius: 999px; background: var(--gradient-orange); color: #fff;
  font-size: 0.68rem; font-weight: 700; line-height: 1.15rem; text-align: center;
}

.user-table { width: 100%; border-collapse: collapse; }
.user-table th {
  text-align: left; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); padding: 0.4rem 0.5rem; border-bottom: 1px solid var(--border);
}
.user-table td { padding: 0.5rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
.user-table input, .user-table select { margin: 0; padding: 0.45rem; font-size: 0.85rem; }
.user-name-cell { font-weight: 500; }
.user-avatar-thumb {
  width: 2rem; height: 2rem; border-radius: 50%; object-fit: cover;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 600; font-size: 0.8rem; flex-shrink: 0;
}
.user-row-actions { display: flex; gap: 0.4rem; white-space: nowrap; }
.user-row-actions button { padding: 0.4rem 0.7rem; font-size: 0.8rem; }
.status-badge { font-size: 0.72rem; padding: 0.28rem 0.7rem; border-radius: 999px; font-weight: 700; letter-spacing: 0.01em; }
.status-badge.active { background: var(--progress-bg); color: var(--progress-text); }
.status-badge.completed { background: var(--success-bg); color: var(--success-text); }
.status-badge.inactive { background: #f1f1f1; color: var(--muted); }
.status-badge.review { background: var(--review-bg); color: var(--review-text); }
.status-badge.neutral { background: var(--border); color: var(--muted); }
/* Confirmed (Nick, 2026-10-06): same grey pill as Tentative, just the Begin
   button's dark green text - only once the rep has actually set the time
   themselves, not the scheduler's own auto-computed guess. */
.status-badge.neutral.confirmed-time { color: var(--success-text); }
.status-badge.unmatched { background: #F5C518; color: #1C2226; }
.add-user-form { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: flex-end; margin-bottom: 1.5rem; }
.add-user-form label { margin: 0; flex: 1; min-width: 120px; }
.new-link-banner {
  background: var(--success-bg); border: 1px solid #bcdfca; border-radius: var(--radius-sm);
  padding: 0.8rem 1rem; margin-bottom: 1.25rem; font-size: 0.85rem; word-break: break-all;
}

/* --- Profile --- */
.profile-card { background: var(--card-bg); border-radius: var(--radius); padding: 1.5rem; box-shadow: var(--shadow-card); border: 1px solid var(--border); margin-top: 1rem; }
.profile-section { padding-bottom: 1.5rem; margin-bottom: 1.5rem; border-bottom: 1px solid var(--border); }
.profile-section:last-of-type { border-bottom: none; margin-bottom: 0; padding-bottom: 0; }
.profile-section h2 { margin: 0 0 0.9rem; }
.profile-section form input[type="text"] { margin-top: 0; }
.avatar-preview-row { display: flex; align-items: center; gap: 1.25rem; }
.avatar-preview { width: 5rem; height: 5rem; border-radius: 50%; object-fit: cover; flex-shrink: 0; box-shadow: 0 0 0 3px var(--bg), 0 0 0 4px var(--border); }
.avatar-preview-fallback { display: flex; align-items: center; justify-content: center; color: #fff; font-size: 1.8rem; font-weight: 700; }
.avatar-preview-clickable { cursor: pointer; transition: transform 0.12s; }
.avatar-preview-clickable:hover { transform: scale(1.05); }
.avatar-preview-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 0.6rem; }

.avatar-view-large img, .avatar-view-large-fallback {
  width: 260px; height: 260px; border-radius: 50%; object-fit: cover;
  box-shadow: 0 0 0 5px rgba(255,255,255,0.9), 0 12px 40px rgba(0,0,0,0.4);
}
.avatar-view-large-fallback {
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 5rem; font-weight: 700;
}

.crop-modal { max-width: 340px; }
.crop-stage { width: 280px; height: 280px; margin: 0 auto; position: relative; overflow: hidden; border-radius: 12px; background: var(--charcoal-800); touch-action: none; cursor: grab; }
.crop-stage:active { cursor: grabbing; }
#crop-image { position: absolute; user-select: none; -webkit-user-drag: none; }
.crop-circle-mask { position: absolute; inset: 0; pointer-events: none; border-radius: 50%; box-shadow: 0 0 0 2000px rgba(0,0,0,0.55); }
.zoom-slider { width: 100%; margin-top: 1rem; }

/* --- Transcript view (admin) --- */
.transcript-view { background: var(--card-bg); border-radius: var(--radius-sm); padding: 1rem; max-height: 480px; overflow-y: auto; font-size: 0.9rem; border: 1px solid var(--border); }
.transcript-line { display: flex; gap: 0.6rem; padding: 0.4rem 0; border-bottom: 1px solid var(--border); }
.transcript-line:last-child { border-bottom: none; }
.transcript-time { color: var(--muted); font-variant-numeric: tabular-nums; flex-shrink: 0; width: 3rem; }
.transcript-speaker { font-weight: 600; flex-shrink: 0; width: 5rem; }
.transcript-text { flex: 1; }
.transcript-flat { white-space: pre-wrap; font-family: inherit; background: var(--card-bg); border-radius: var(--radius-sm); padding: 1rem; font-size: 0.9rem; border: 1px solid var(--border); }

/* ==========================================================================
   Dashboard (Rep Run)
   ========================================================================== */
.event-btn-row { display: flex; gap: 0.75rem; margin-bottom: 1.4rem; }
.event-btn-row > a { flex: 1; }

.new-event-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.4rem;
  padding: 0.9rem 0.6rem; color: #fff; border-radius: var(--radius);
  font-weight: 700; font-size: 0.95rem; text-decoration: none; white-space: nowrap;
  background: var(--gradient-orange);
  box-shadow: 0 4px 14px rgba(240, 120, 48, 0.35);
}
@media (max-width: 400px) {
  .new-event-btn { font-size: 0.82rem; gap: 0.3rem; padding: 0.85rem 0.4rem; }
  .new-event-btn svg { width: 16px; height: 16px; }
}
.new-event-btn:hover { filter: brightness(1.05); }
.new-event-btn svg { width: 20px; height: 20px; }


.run-card {
  /* Vertical stack, not the old row (letter-circle | name+chips | actions) -
     Nick, 2026-10-05: that squeezed the schedule chips into a narrow
     column, forcing them to wrap and making the whole tile tall. Full
     width top-to-bottom instead: badge+name, then chips (room to be
     bigger, not smaller), then actions. */
  display: flex; flex-direction: column; gap: 0.6rem; background: var(--card-bg); border-radius: 18px;
  padding: 1.1rem 1.25rem; margin-bottom: 0.85rem;
  border: 1.5px solid transparent; transition: transform 0.15s ease, border-color 0.15s ease;
}
.run-card-top { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
/* No shadow — instead a slight "pop" (scale up + a faint border) on hover,
   since the box-shadow was clipping at panel edges and stacking awkwardly
   with neighbouring cards (Nick, 2026-09-21). */
.run-card:has(.run-card-tap:hover) {
  transform: scale(1.015);
  border-color: var(--border);
}
.run-card-review { border-left: 4px solid var(--orange); }

/* ===== Auto-scheduler: time/duration chips, Lunch card, day-start row,
   conflict indicator (Nick, 2026-10-02) ===== */
.run-card-schedule {
  display: flex; align-items: center; gap: 0.4rem; margin-top: 0.4rem; flex-wrap: wrap;
}
.rs-chip {
  /* Bigger tap target (Nick, 2026-10-05: "the start and length selectors
     aren't so small") - there's room for it now the tile's a full-width
     stack instead of a squeezed side column. */
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-size: 0.86rem; font-weight: 600; padding: 0.45rem 0.8rem; border-radius: 999px;
  background: var(--bg); border: 1.5px dashed var(--border); color: var(--muted);
  cursor: pointer;
}
.rs-chip:hover { border-color: var(--orange); color: var(--text); }
/* Confirmed = solid border + ink colour, tentative = dashed + muted - the
   visual distinction IS the tentative/confirmed status, no separate label
   needed (Nick, 2026-10-02: "as soon as the rep manually edits it, it
   becomes confirmed"). */
.rs-chip.confirmed { border-style: solid; border-color: var(--charcoal); color: var(--charcoal); background: var(--card-bg); }
.rs-chip.conflict { border-color: var(--red); color: var(--red); background: var(--review-bg); }
.rs-chip svg { width: 14px; height: 14px; flex-shrink: 0; }
/* Reschedule (Nick, 2026-10-08) - pushed to the far right of the same row
   as the time/duration chips via margin-left: auto, charcoal to read as a
   deliberate, slightly weightier action than the dashed chips next to it. */
.reschedule-btn {
  margin-left: auto; font-size: 0.82rem; font-weight: 600; padding: 0.45rem 0.8rem;
  border-radius: 999px; background: var(--charcoal); color: #fff; border: none; cursor: pointer;
}
.reschedule-btn:hover { background: var(--charcoal-800); }
/* Loading state for whichever chip was actually tapped (Nick, 2026-10-06:
   the page-level "Updating…" pill sits up by the route card, invisible if
   you're scrolled down editing a tile further down - "what do you mean by
   'pill' though? Are we talking about the same thing?" made clear he'd
   never once seen it). This one replaces the tapped chip's own icon+text
   with a spinner in place, so it's visible exactly where you're already
   looking, whatever your scroll position. */
.rs-chip.rs-loading { color: transparent; pointer-events: none; position: relative; }
.rs-chip.rs-loading svg { visibility: hidden; }
.rs-chip.rs-loading::after {
  content: ''; position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: auto;
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: var(--orange);
  animation: rs-spin 0.7s linear infinite;
}

.day-start-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  padding: 0.7rem 1.1rem; margin-bottom: 0.85rem;
  background: var(--card-bg); border-radius: 14px; font-size: 0.88rem; color: var(--muted);
}
.day-start-row strong { color: var(--text); font-weight: 600; }

.lunch-card {
  display: flex; align-items: center; gap: 1rem; background: var(--card-bg); border-radius: 18px;
  padding: 1.1rem 1.25rem; margin-bottom: 0.85rem; border: 1.5px dashed var(--border);
}
.lunch-card-icon {
  flex-shrink: 0; width: 2.6rem; height: 2.6rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--gradient-orange); color: #fff;
}
.lunch-card-icon svg { width: 18px; height: 18px; }
.lunch-card-body { flex: 1; min-width: 0; }
.lunch-card-name { font-weight: 700; font-size: 1.02rem; margin-bottom: 0.3rem; }

.rs-duration-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1rem 0; }
.rs-duration-chip {
  padding: 0.5rem 0.9rem; border-radius: 999px; border: 1.5px solid var(--border);
  background: var(--card-bg); color: var(--text); font-size: 0.88rem; font-weight: 600; cursor: pointer;
}
.rs-duration-chip:hover { border-color: var(--orange); }
.rs-duration-chip.active { background: var(--gradient-orange); border-color: transparent; color: #fff; }
.run-card-time {
  flex-shrink: 0; width: 4.2rem; font-weight: 700; color: var(--charcoal);
  font-variant-numeric: tabular-nums; align-self: flex-start; padding-top: 0.15rem; font-size: 0.92rem;
}
.run-card-body { flex: 1; min-width: 0; }
.run-card .status-badge { display: inline-flex; align-items: center; gap: 0.3rem; flex-shrink: 0; }
.run-card-name { font-weight: 700; font-size: 1.02rem; min-width: 0; }
.run-card-time-inline { font-size: 0.82rem; color: var(--muted); margin-top: 0.3rem; }
.run-card-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.4rem; }
.run-card-btn { padding: 0.42rem 0.85rem; font-size: 0.83rem; display: inline-flex; align-items: center; gap: 0.35rem; }
.run-card-btn svg { width: 15px; height: 15px; }

/* Bottom action row (Begin + the directions pin) - full width now that the
   tile is a vertical stack, not squeezed into a fixed-width side column. */
.run-card-actions-row { display: flex; align-items: center; gap: 0.65rem; }
.run-card-actions-row .start-stop-pill { flex: 1; }

.run-card-tap { flex: 1; min-width: 0; display: block; text-decoration: none; color: inherit; }
.run-card-pin {
  flex-shrink: 0; width: 2.3rem; height: 2.3rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--charcoal); background: var(--bg); transition: background 0.15s ease;
}
.run-card-pin:hover { background: var(--border); }
.run-card-pin svg { width: 16px; height: 16px; }

.start-stop-pill {
  flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  height: 2.3rem; padding: 0 1.15rem; border-radius: 999px; font-size: 0.86rem;
  font-weight: 700; border: none; cursor: pointer; color: #fff;
  transition: filter 0.15s ease, transform 0.12s ease;
}
.start-stop-pill svg { width: 15px; height: 15px; }
.start-stop-pill.start { background: var(--success-text); }
.start-stop-pill:hover { filter: brightness(1.1); }
.start-stop-pill:active { transform: scale(0.96); }

.live-dot {
  /* Yellow, matching the In Progress badge it always sits inside (Nick,
     2026-10-09: "has a yellow In Progress badge... but a green flashing
     dot... make it a yellow flashing dot") - only ever used there, see
     --progress-text above. */
  width: 7px; height: 7px; border-radius: 50%; background: var(--progress-text);
  animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* --- Dashboard carousel --- */
.dash-viewport-wrap { position: relative; }
.day-nav-row {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  margin-bottom: 0.7rem;
}
.day-nav-arrow { display: none; } /* mobile navigates by swipe instead */
@media (min-width: 768px) {
  .day-nav-arrow { display: flex; }
}

.route-card {
  background: var(--gradient-charcoal);
  border-radius: var(--radius); overflow: hidden; margin-bottom: 1rem;
}
.route-info { padding: 1rem 1.1rem 1.1rem; }
.route-stats-row { display: flex; align-items: center; justify-content: center; gap: 1.2rem; margin-bottom: 0.9rem; }
.route-stat { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; }
.route-stat-label {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em;
  color: rgba(255,255,255,0.55); font-weight: 600;
}
.route-stat-value { font-size: 1.05rem; color: #fff; font-weight: 500; }
.route-stat-value strong { font-weight: 700; }
.route-stat-divider { width: 1px; height: 1.8rem; background: rgba(255,255,255,0.15); }

.route-open-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.5rem;
  width: 100%; padding: 0.75rem 1.15rem;
  background: var(--gradient-orange);
  color: #fff; border-radius: var(--radius-sm); font-weight: 700; font-size: 0.92rem;
  text-decoration: none; box-shadow: 0 4px 14px rgba(240, 120, 48, 0.35);
}
.route-open-btn:hover { filter: brightness(1.05); }
.route-open-btn svg { width: 17px; height: 17px; flex-shrink: 0; }

.dash-day-label { flex: 1; font-weight: 700; font-size: 0.95rem; text-align: center; color: var(--muted); }
.day-nav-arrow {
  display: flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem; padding: 0; border-radius: 50%; color: var(--muted);
  background: transparent; border: none; cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.day-nav-arrow:hover { background: var(--border); color: var(--text); }
.day-nav-arrow svg { width: 15px; height: 15px; }

.dash-viewport { overflow: hidden; }
.dash-track { display: flex; width: 300%; transform: translateX(-33.3333%); }
.dash-track.animating { transition: transform 0.28s ease; }
.dash-panel { width: 33.3333%; flex-shrink: 0; min-width: 0; padding: 0 8px; position: relative; }

.dash-carousel {
  display: flex; flex-direction: column; gap: 0.65rem;
}
.dash-carousel-draggable {
  display: flex; flex-direction: column; gap: 0.65rem;
}
.dash-carousel-draggable:empty { display: none; }
.dash-carousel-card { width: 100%; }
.dash-carousel-card .run-card { margin-bottom: 0; }


/* --- Event profile page --- */
.event-profile-card { margin-top: 1rem; margin-bottom: 1.2rem; }
.schedule-heading { font-size: 1rem; margin: 0 0 0.9rem; }

/* --- Schedule strip (view mode) --- */
.schedule-strip {
  display: flex; align-items: center; gap: 0.75rem; background: var(--card-bg);
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 0.65rem 0.7rem 0.65rem 0.9rem; margin: 0.9rem 0 1rem; box-shadow: var(--shadow-card);
}
.schedule-strip-icon {
  width: 1.9rem; height: 1.9rem; border-radius: 50%; background: var(--bg);
  display: flex; align-items: center; justify-content: center; color: var(--charcoal); flex-shrink: 0;
}
.schedule-strip-icon svg { width: 14px; height: 14px; }
.schedule-strip-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.schedule-strip-text strong { font-size: 0.92rem; }
.schedule-strip-time { font-size: 0.8rem; color: var(--muted); }
.schedule-strip-edit {
  flex-shrink: 0; width: 2rem; height: 2rem; padding: 0; border-radius: 50%; background: transparent;
  border: none; color: var(--muted); display: flex; align-items: center; justify-content: center;
  transition: background 0.15s, color 0.15s;
}
.schedule-strip-edit:hover { background: var(--bg); color: var(--text); }
.schedule-strip-edit svg { width: 14px; height: 14px; }

/* --- Customer Overview: stat tiles + contact card --- */
.stat-tile-row { display: flex; gap: 0.75rem; margin: 0 0 1rem; }
.stat-tile {
  flex: 1; min-width: 0; border-radius: var(--radius); padding: 0.9rem 1rem;
  display: flex; flex-direction: column; gap: 0.4rem; background: var(--card-bg);
  border: 1px solid var(--border); box-shadow: var(--shadow-card);
}
.stat-tile svg { width: 18px; height: 18px; color: var(--orange); }
.stat-tile-value { font-size: 1.2rem; font-weight: 700; color: var(--text); }
.stat-tile-label { font-size: 0.7rem; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.02em; }
.stat-tile-primary { background: var(--gradient-charcoal); border: none; }
.stat-tile-primary .stat-tile-value { color: #fff; }
.stat-tile-primary .stat-tile-label { color: rgba(255,255,255,0.65); }
@media (max-width: 380px) { .stat-tile-row { flex-direction: column; } }

/* Sales Stats has 5 tiles, not 4 - wraps onto a second line instead of
   squeezing (Nick, 2026-10-08: "number of visits debriefed tile, number
   of customers tile, few other metrics... growth metric"), each tile
   given a sane minimum instead of flex:1 shrinking it illegibly thin. */
.stat-tile-row-wrap { flex-wrap: wrap; }
/* Wide enough to hold a $ value without wrapping on a normal phone, but
   the value itself still scales down and wraps as a last resort instead
   of overflowing the tile (Nick, 2026-10-08: "tile text runs off the
   tile... need to scale text to fit") - min-width:0 is what actually lets
   a flex child shrink below its content's natural width at all. */
.stat-tile-row-wrap .stat-tile { flex: 1 1 140px; min-width: 0; }
.stat-tile-row-wrap .stat-tile-value {
  font-size: clamp(0.95rem, 5vw, 1.2rem); overflow-wrap: break-word; word-break: break-word;
}
/* Green when sales grew YoY, red when they shrank - the growth figure IS
   the colour, no separate up/down icon needed (Nick, 2026-10-08: "the most
   important thing is some sort of growth metric"). */
.stat-tile-growth-up .stat-tile-value { color: var(--success-text); }
.stat-tile-growth-down .stat-tile-value { color: var(--error); }

/* Sales Stats' own single-series bar chart. NOT inside .score-chart-scroll
   (Nick, 2026-10-08: "graph is all bunch up over left hand side instead of
   using width") - that wrapper's overflow-x:auto plus the Event Score
   chart's fixed-width months make sense there (clustered 4-bar groups,
   deliberately horizontally scrollable past 12 months), but it was wrong
   for this chart: 12 fixed-width columns in a scrollable flex row just
   left-aligned instead of filling the card, since a scrolling container
   never stretches its children to fill unused space. This one has no
   scroller at all - each month is a flex:1 share of the full card width. */
.sales-chart { display: flex; align-items: flex-end; gap: 0.5rem; height: 9rem; padding-top: 1rem; margin-bottom: 1.5rem; }
.sales-chart-month { flex: 1; display: flex; flex-direction: column; align-items: center; height: 100%; min-width: 0; }
.sales-chart-bar-wrap { flex: 1; display: flex; align-items: flex-end; width: 100%; }
.sales-chart-bar { width: 100%; min-height: 3px; border-radius: 3px 3px 0 0; background: var(--orange); }

.contact-card { padding: 0.6rem; }
.contact-card .schedule-heading { padding: 0.5rem 0.6rem 0.5rem; margin: 0; }
.contact-row {
  display: flex; align-items: center; gap: 0.85rem; padding: 0.7rem 0.6rem;
  text-decoration: none; color: inherit; border-radius: var(--radius-sm);
}
.contact-row:not(:last-child) { border-bottom: 1px solid var(--border); }
a.contact-row:hover { background: var(--bg); }
.contact-row-icon {
  width: 2.3rem; height: 2.3rem; border-radius: var(--radius-sm); background: var(--bg);
  display: flex; align-items: center; justify-content: center; color: var(--charcoal); flex-shrink: 0;
}
.contact-row-icon svg { width: 15px; height: 15px; }
.contact-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.1rem; }
.contact-row-label { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); font-weight: 600; }
.contact-row-value { font-size: 0.9rem; font-weight: 600; color: var(--text); word-break: break-word; }
.contact-row-chevron { flex-shrink: 0; color: var(--muted); }
.contact-row-chevron svg { width: 13px; height: 13px; }

/* --- Photos --- */
.photo-gallery { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.photo-thumb-wrap { position: relative; width: 4.6rem; height: 4.6rem; border-radius: var(--radius-sm); overflow: hidden; }
.photo-thumb { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-delete-form { position: absolute; top: 2px; right: 2px; margin: 0; }
.photo-delete-btn {
  width: 1.2rem; height: 1.2rem; border-radius: 50%; background: rgba(0,0,0,0.55);
  color: #fff; border: none; font-size: 0.75rem; line-height: 1; padding: 0;
  display: flex; align-items: center; justify-content: center;
}
.photo-add-btn {
  width: 4.6rem; height: 4.6rem; padding: 0; border-radius: var(--radius-sm);
  background: transparent; border: 1.5px dashed var(--border);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.2rem;
  color: var(--muted); cursor: pointer; font-size: 0.6rem; font-weight: 600; text-align: center;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.photo-add-btn:hover { background: var(--bg); color: var(--text); border-color: var(--charcoal); }
.photo-add-btn svg { width: 18px; height: 18px; }

/* --- Notes --- */
.notes-preview { font-size: 0.9rem; color: var(--text); white-space: pre-line; margin: 0; }
.note-textarea {
  width: 100%; min-height: 140px; padding: 0.7rem 0.8rem; border: 1.5px solid var(--border);
  border-radius: var(--radius-sm); font-family: inherit; font-size: 0.92rem; resize: vertical;
}
.note-modal { max-width: 380px; }
.note-modal .actions { margin-top: 0.9rem; }

/* Voice dictation button for Manual Notes (Nick, 2026-10-07) - hidden by
   default, JS reveals it only when the browser actually supports the Web
   Speech API over a secure context (see event_profile.html). */
.mic-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.4rem;
  width: 100%; margin-top: 0.6rem; padding: 0.5rem 0.9rem;
  background: var(--bg); color: var(--muted); border: 1.5px solid var(--border);
  border-radius: var(--radius-sm); font: inherit; font-size: 0.85rem; font-weight: 600;
  cursor: pointer; transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.mic-btn svg { width: 16px; height: 16px; }
.mic-btn:hover { border-color: var(--charcoal); color: var(--text); }
.mic-btn.listening {
  background: rgba(220,43,38,0.1); color: var(--red); border-color: var(--red);
  animation: pulse 1.6s ease-in-out infinite;
}

/* --- Cancel / Complete --- */
.event-actions-row { display: flex; gap: 0.75rem; margin-top: 1rem; }
.event-actions-row > button { flex: 1; }
.complete-btn {
  background: var(--success-text); color: #fff; border: none; border-radius: var(--radius-sm);
  padding: 0.75rem 1.15rem; font-size: 0.95rem; font-weight: 600; cursor: pointer;
}
.complete-btn:hover { filter: brightness(1.1); }
.complete-btn.disabled { background: var(--bg); color: var(--muted); border: 1.5px solid var(--border); }
.complete-btn.disabled:hover { filter: none; }

.cancel-reason-form { display: flex; flex-direction: column; gap: 0.6rem; }
.cancel-reason-form button { width: 100%; }

.start-event-btn { width: 100%; margin: 0.9rem 0 1rem; background: var(--success-text); }
.start-event-btn:hover { filter: brightness(1.1); }

.schedule-modal { max-width: 340px; }
.event-save-btn { width: 100%; margin-top: 1.1rem; }
.save-event-btn { margin-bottom: 1.2rem; }

.date-strip-row { display: flex; align-items: center; gap: 0.4rem; margin-bottom: 1rem; }
.date-strip-wrap { flex: 1; min-width: 0; }
.date-strip-arrow {
  display: none; flex-shrink: 0; width: 1.8rem; height: 1.8rem; border-radius: 50%;
  align-items: center; justify-content: center; color: var(--muted);
  background: transparent; border: 1.5px solid var(--border); cursor: pointer; padding: 0;
  transition: background 0.15s, color 0.15s;
}
.date-strip-arrow:hover { background: var(--bg); color: var(--text); }
.date-strip-arrow svg { width: 12px; height: 12px; }
.date-strip-arrow-right svg { transform: scaleX(-1); }
@media (min-width: 768px) { .date-strip-arrow { display: flex; } }
.date-strip {
  position: relative; display: flex; gap: 0.5rem; overflow-x: auto; scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-bottom: 0.15rem;
}
.date-strip::-webkit-scrollbar { display: none; }
.date-strip-item {
  flex: 0 0 auto; width: 3.3rem; padding: 0.5rem 0.2rem;
  border: 1.5px solid var(--border); border-radius: var(--radius-sm); background: var(--card-bg);
  display: flex; flex-direction: column; align-items: center; gap: 0.2rem;
  scroll-snap-align: start; cursor: pointer; color: var(--muted); font-weight: 600;
  transition: border-color 0.15s, background 0.15s, color 0.15s; font-family: inherit;
}
.date-strip-item .dow { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.03em; }
.date-strip-item .dnum { font-size: 1.05rem; color: var(--text); }
.date-strip-item:hover { background: var(--bg); color: var(--text); border-color: var(--charcoal); }
.date-strip-item.active { border-color: var(--orange); background: var(--review-bg); color: var(--review-text); }
.date-strip-item.active .dnum { color: var(--review-text); }

.brief-btn {
  width: 100%; margin: 0.85rem 0 1.2rem; display: flex; align-items: center;
  justify-content: center; gap: 0.5rem; padding: 0.65rem 1.15rem;
}
.brief-btn svg { width: 17px; height: 17px; flex-shrink: 0; }
.brief-btn-pending { opacity: 0.6; cursor: default; }
.brief-btn-pending:hover { background: none; }

.time-picker-trigger {
  display: block; width: 100%; text-align: left; background: var(--card-bg); color: var(--text);
  border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  padding: 0.6rem 0.7rem; font-size: 0.9rem; font-weight: 500; font-family: inherit;
  cursor: pointer; margin-top: 0.4rem; transition: border-color 0.15s, background 0.15s;
}
.time-picker-trigger:hover { background: var(--bg); }
.time-picker-trigger.placeholder { color: var(--muted); font-weight: 400; }

.time-modal { max-width: 320px; }
.time-modal-header { display: flex; align-items: center; justify-content: space-between; }
.time-modal-header h3 { margin: 0; }

.time-wheel-wrap {
  position: relative; display: flex; align-items: center; justify-content: center;
  height: 294px; overflow: hidden; margin: 1.1rem 0 0.5rem;
}
.time-wheel-highlight {
  position: absolute; left: 0.5rem; right: 0.5rem; top: 50%; transform: translateY(-50%);
  height: 42px; background: var(--bg); border-radius: var(--radius-sm); z-index: 0; pointer-events: none;
}
.time-wheel-col {
  position: relative; z-index: 1; width: 4.4rem; height: 100%;
  overflow-y: scroll; scroll-snap-type: y mandatory; -webkit-overflow-scrolling: touch;
  scrollbar-width: none; padding: 126px 0;
}
.time-wheel-col::-webkit-scrollbar { display: none; }
.time-wheel-item {
  height: 42px; line-height: 42px; text-align: center; font-size: 1.05rem;
  color: var(--muted); scroll-snap-align: center; user-select: none; cursor: pointer;
  transition: font-size 0.1s, font-weight 0.1s, color 0.1s;
}
.time-wheel-item.active { color: var(--text); font-weight: 700; font-size: 1.3rem; }
.time-wheel-sep { position: relative; z-index: 1; font-size: 1.3rem; font-weight: 700; padding: 0 0.2rem; color: var(--text); }

/* --- Coming soon placeholder screens --- */
.coming-soon {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 4rem 1.5rem; color: var(--muted);
}
.coming-soon svg { width: 52px; height: 52px; margin-bottom: 1.2rem; color: var(--border); stroke: var(--border); }
.coming-soon h1 { color: var(--text); }
.coming-soon-badge {
  display: inline-block; margin-top: 0.9rem; padding: 0.3rem 0.8rem; border-radius: 999px;
  background: var(--review-bg); color: var(--review-text); font-size: 0.75rem; font-weight: 700;
  letter-spacing: 0.03em; text-transform: uppercase;
}

/* --- Settings: Ideas tab --- */
.idea-tile-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1rem;
}
.idea-tile h3 { margin: 0 0 0.5rem; font-size: 1rem; }
.idea-tile-brief { font-size: 0.88rem; color: var(--muted); white-space: pre-wrap; margin: 0 0 0.75rem; }

/* --- Transcripts Log / user profile page shared bits --- */
.back-link {
  display: inline-block; margin-bottom: 0.6rem; color: var(--muted);
  font-size: 0.85rem; font-weight: 600; text-decoration: none;
}
.back-link:hover { color: var(--orange); }

/* --- Transcripts Log: a proper stacked card list instead of a table-style
   grid that just hides the date/rep columns once the screen gets narrow
   (Nick, 2026-09-22: "still looks stuck in the 2010s") - every row shows
   everything at every width, just wrapped instead of clipped. --- */
.translog-row { display: flex; align-items: center; gap: 0.5rem; border-bottom: 1px solid var(--border); }
.translog-row:last-child { border-bottom: none; }
.translog-row:hover { background: var(--bg); }
.translog-row-link {
  flex: 1; min-width: 0; display: block; color: var(--text); text-decoration: none;
  padding: 0.85rem 1.1rem;
}
.translog-row-top { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
.translog-row-top svg { width: 16px; height: 16px; color: var(--muted); flex-shrink: 0; }
.translog-row-customer { font-size: 0.94rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.translog-row-meta { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.2rem; font-size: 0.78rem; color: var(--muted); }
.translog-row-dot { opacity: 0.6; }
.translog-row-ignore-btn {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 2.4rem; height: 2.4rem; margin-right: 0.5rem; border-radius: 50%;
  color: var(--muted); background: transparent; border: none; cursor: pointer;
}
.translog-row-ignore-btn:hover { background: var(--border); color: var(--error); }

/* A styled native date input rather than the browser's own bare-default
   look (Nick, 2026-09-23: "clunky... make it more modern and fresh") -
   shared between Event Log and Transcripts Log. */
.cal-picker {
  position: relative; margin-bottom: 1rem;
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
}
.cal-picker-quick { display: flex; gap: 0.4rem; }
.cal-picker-quick-btn {
  padding: 0.55rem 0.85rem; font: inherit; font-size: 0.82rem; font-weight: 600;
  color: var(--muted); background: var(--card-bg);
  border: 1.5px solid var(--border); border-radius: 999px;
  cursor: pointer; transition: border-color 0.15s, color 0.15s;
}
.cal-picker-quick-btn:hover { border-color: var(--orange); color: var(--text); }
.cal-picker-trigger {
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.65rem 1rem; font: inherit; font-size: 0.9rem; font-weight: 600;
  color: var(--text); background: var(--card-bg);
  border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card); cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s;
}
.cal-picker-trigger:hover, .cal-picker-trigger:focus-visible {
  border-color: var(--orange); outline: none;
}
.cal-picker-trigger svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--muted); }
.cal-picker-chevron { width: 12px; height: 12px; margin-left: 0.1rem; transition: transform 0.15s; }
.cal-picker-trigger[aria-expanded="true"] .cal-picker-chevron { transform: rotate(180deg); }

.cal-picker-popover {
  position: absolute; top: calc(100% + 0.5rem); left: 0; z-index: 30;
  width: 17.5rem; padding: 0.9rem;
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-elevated);
  animation: cal-picker-pop 0.14s ease-out;
}
@keyframes cal-picker-pop {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.cal-picker-header {
  display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.7rem;
}
/* Clickable now, not just a label (Nick, 2026-10-09: "ability to click on
   month/year to jump back quickly") - toggles the year grid below in place
   of the day grid, same popover, no separate control needed. Needs its own
   reset since it's a <button> now - otherwise it'd pick up the global
   button/.btn style (orange gradient, padding) like every plain <button>
   in this app does by default. */
.cal-picker-month-label {
  appearance: none; -webkit-appearance: none; background: none; border: none; padding: 0.2rem 0.4rem;
  font: inherit; font-size: 0.92rem; font-weight: 700; color: var(--text); border-radius: var(--radius-sm);
  cursor: pointer; transition: background 0.12s, color 0.12s;
}
.cal-picker-month-label:hover { background: var(--bg); color: var(--orange-dark); }
.cal-picker-months { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.3rem; }
.cal-picker-month-cell {
  font: inherit; font-size: 0.85rem; font-weight: 500; color: var(--text);
  background: transparent; border: none; border-radius: var(--radius-sm); padding: 0.6rem 0;
  cursor: pointer; transition: background 0.12s, color 0.12s;
}
.cal-picker-month-cell:hover { background: var(--bg); }
.cal-picker-month-cell.today-month { color: var(--orange); font-weight: 700; }
.cal-picker-month-cell.selected { background: var(--gradient-orange); color: #fff; font-weight: 700; }
.cal-picker-month-cell.selected.today-month { color: #fff; }
.cal-picker-nav {
  display: flex; align-items: center; justify-content: center;
  width: 1.9rem; height: 1.9rem; border-radius: 50%; padding: 0;
  background: transparent; border: none; color: var(--muted); cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.cal-picker-nav:hover { background: var(--bg); color: var(--text); }
.cal-picker-nav svg { width: 13px; height: 13px; }
.cal-picker-weekdays, .cal-picker-days {
  display: grid; grid-template-columns: repeat(7, 1fr);
}
.cal-picker-weekdays span {
  text-align: center; font-size: 0.68rem; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.02em; padding-bottom: 0.4rem;
}
.cal-picker-days { row-gap: 0.15rem; }
.cal-picker-cell { position: relative; display: flex; }
.cal-picker-cell.in-range { background: var(--review-bg); }
.cal-picker-cell.range-start { border-top-left-radius: 999px; border-bottom-left-radius: 999px; }
.cal-picker-cell.range-end { border-top-right-radius: 999px; border-bottom-right-radius: 999px; }
.cal-picker-day {
  position: relative; z-index: 1;
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  margin: 0 auto; width: 2.1rem; max-width: 100%;
  font: inherit; font-size: 0.85rem; font-weight: 500; color: var(--text);
  background: transparent; border: none; border-radius: 50%; cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.cal-picker-day:hover { background: var(--bg); }
.cal-picker-day.today { color: var(--orange); font-weight: 700; }
.cal-picker-day.selected { background: var(--gradient-orange); color: #fff; font-weight: 700; }
.cal-picker-day.selected.today { color: #fff; }
.cal-picker-hint { margin: 0.6rem 0 0; font-size: 0.78rem; color: var(--muted); text-align: center; }
.cal-picker-clear-btn {
  display: block; width: 100%; margin-top: 0.5rem; background: none; border: none;
  color: var(--muted); font-size: 0.8rem; font-weight: 600; text-decoration: underline; cursor: pointer;
}
.cal-picker-clear-btn:hover { color: var(--error); }

.transcript-detail-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.transcript-detail-actions button { flex: 1; min-width: 8rem; }

/* ===== SPARC. opening intro (Nick, 2026-10-01; redesigned same day -
   scrolling marquee was unreadable, replaced with fade in -> hold -> the
   non-SPARC letters fade+collapse away so S/P/A/R/C + the dot close in
   together) ===== */
/* Offline awareness (Nick, 2026-10-08) - see base.html for when each one
   shows. The banner is ambient (any page, stays up the whole time there's
   no connection); the toast is a one-off pointed notice for a specific
   action that just failed because of it. */
.offline-banner {
  position: sticky; top: 0; z-index: 500;
  background: var(--orange); color: #fff; text-align: center;
  font-size: 0.82rem; font-weight: 600; padding: 0.5rem 1rem;
}
/* "View App As" (Nick, 2026-10-14: "view the whole app from the
   perspective of any user, without logging into their account") - sticky,
   always-visible, deliberately a different colour from .offline-banner
   above so the two are never mistaken for each other at a glance. */
.view-as-banner {
  position: sticky; top: 0; z-index: 500;
  background: var(--charcoal); color: #fff; text-align: center;
  font-size: 0.82rem; font-weight: 600; padding: 0.5rem 1rem;
}
.view-as-banner .link-btn { color: var(--orange); font-weight: 700; margin-left: 0.5rem; }
.offline-notice-toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, 0.5rem);
  z-index: 600; max-width: 90vw; background: var(--charcoal); color: #fff;
  font-size: 0.85rem; font-weight: 500; padding: 0.7rem 1.1rem; border-radius: 999px;
  box-shadow: var(--shadow-elevated); opacity: 0; pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.offline-notice-toast.visible { opacity: 1; transform: translate(-50%, 0); }

.sparc-intro {
  position: fixed; inset: 0; z-index: 9999;
  background: var(--bg); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.sparc-intro[hidden] { display: none; }
.sparc-intro-stage {
  position: relative; width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1.5rem; overflow: hidden;
}
/* "by [Dorset Australia logo]" (Nick, 2026-10-01) - fades in once "SPARC."
   has formed (during the brief settle pause, see sparc-intro.js), fades
   back out the moment the dot starts charging so it doesn't linger through
   the explosion/reveal. Plain "by", not "an app by" - the logo already
   says the company name, so the caption only needs to say the relationship. */
.sparc-attribution {
  display: flex; flex-direction: column; align-items: center; gap: 0.4rem;
  opacity: 0; transition: opacity 0.6s ease;
}
.sparc-attribution.sparc-visible { opacity: 1; }
.sparc-attribution-by {
  font-family: 'Inter', sans-serif; font-size: 0.8rem; font-weight: 500;
  color: var(--muted);
}
.sparc-attribution-logo { height: 35px; width: auto; display: block; }
.sparc-phrase {
  /* flex-wrap (not nowrap) so the phrase wraps to multiple lines on
     tablet/mobile instead of overflowing (Nick, 2026-10-01: "doesn't fit
     across a tablet or mobile screen"). Each word's initial+remainder are
     grouped into one .sparc-word unit (below) so a line break can only ever
     land between whole words/spaces, never splitting a letter off its word. */
  display: inline-flex; flex-wrap: wrap; align-items: baseline;
  justify-content: center; row-gap: 0.2em;
  font-family: 'Inter', sans-serif; font-weight: 900; letter-spacing: 0.01em;
  color: #323e48;
  font-size: clamp(1.15rem, 4.6vw, 3rem);
  opacity: 0; transition: opacity 0.45s ease;
  max-width: min(92vw, 56rem);
  padding: 0 1rem; /* breathing room so "readable size" never touches the edges */
}
.sparc-phrase.sparc-visible { opacity: 1; }
.sparc-word { display: inline-flex; align-items: baseline; }
.sparc-initial { display: inline-block; }
.sparc-collapse {
  display: inline-block; overflow: hidden; white-space: pre;
  opacity: 1;
  /* Letters fade out slowly first (~3s, Nick, 2026-10-01: "slowly fade
     away over about 3 seconds"), THEN close the gap - width/margin/padding
     are delayed so they only kick in once the fade is most of the way
     through, instead of the shrink and the fade happening at the same
     time. JS drives the exact delay (see TIMINGS.fade/closeIn). */
  transition: opacity 3s ease, width 0.9s cubic-bezier(.4,0,.2,1),
              margin 0.9s cubic-bezier(.4,0,.2,1), padding 0.9s cubic-bezier(.4,0,.2,1);
}
.sparc-collapse.sparc-fading { opacity: 0; }
.sparc-collapse.sparc-collapsed { width: 0 !important; margin: 0 !important; padding: 0 !important; }
.sparc-dot {
  position: relative;
  display: inline-block; flex-shrink: 0; box-sizing: border-box;
  /* Bottom-aligned like a real full stop, not vertically centred - centring
     looked "weird" across a full phrase even though it read fine on the
     small sidebar logo (Nick, 2026-10-01). Inherits the phrase's
     align-items: baseline so it always sits low, consistently with the
     sidebar logo's dot (see .sparc-wordmark-dot below, same treatment). */
  width: 0.24em; height: 0.24em; aspect-ratio: 1 / 1;
  border-radius: 50%; background: #323e48;
  margin-left: 0.1em; vertical-align: middle;
  /* GPU-composited layer: without this, some browsers re-rasterise the
     border-radius on every frame of a transform+box-shadow animation and
     the circle visibly flattens at one edge for a frame or two (Nick,
     2026-10-01: "flashes to a slightly flat edged dot"). The charge itself
     is driven by WAAPI animations in JS, not CSS transitions, so colour
     swaps never interrupt a transition mid-flight. */
  will-change: transform, box-shadow, background-color;
  backface-visibility: hidden;
  transform: translateZ(0);
}
/* The dot's real final look is the logo's own orange-red gradient, not a
   flat colour - backgroundColor can't animate TO a gradient, so the
   gradient lives here on ::after and is faded in by JS across the same
   charge animation that moves the base colour charcoal -> orange -> red
   (Nick, 2026-10-07). A dedicated gradient, not --gradient-orange itself -
   that one puts its red stop at 130% so it fades softly across a large
   surface, which on something as small as this dot just reads as flat
   orange with barely a hint of red (Nick, 2026-10-07: "it seems to go flat
   orange"). Ending the red stop at 100% instead means the full red is
   actually visible at the dot's far edge. */
.sparc-dot::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: linear-gradient(135deg, var(--orange) 0%, var(--red) 100%); opacity: 0;
}
/* Static fallback for the reduced-motion path (no WAAPI animation runs) -
   jumps straight to the finished gradient dot, no transition at all. */
.sparc-dot.sparc-dot-final::after { opacity: 1; }

.sparc-skip {
  /* Washed out (Nick, 2026-10-01: "less obvious") - a functional escape
     hatch, not something that should compete with the animation itself.
     appearance:none - without it, some browsers render their OWN native
     button chrome (a solid default border) on top of/instead of the one
     below. outline:none on the base rule - this button gets .focus()
     called on it the instant the intro mounts (for accessibility), which
     draws a native focus ring that has nothing to do with `border` at all;
     no amount of lightening `border` was ever going to touch THAT dark
     ring (Nick, 2026-10-01: "STILL HAS A DARK BORDER"). A custom
     :focus-visible style replaces it so keyboard users still get
     something. */
  appearance: none; -webkit-appearance: none; outline: none;
  position: absolute; z-index: 10; bottom: 1.25rem; right: 1.25rem;
  background: transparent; border: 1px solid rgba(50,62,72,0.22); color: rgba(50,62,72,0.4);
  padding: 0.5rem 0.9rem; border-radius: 999px; font-size: 0.78rem; font-weight: 500;
  cursor: pointer;
}
.sparc-skip:hover { border-color: rgba(50,62,72,0.4); color: var(--text); }
.sparc-skip:focus-visible { outline: 2px solid rgba(240,120,48,0.5); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .sparc-phrase { transition: none; }
}

/* ===== "Ask SPARC." floating chat widget (Nick, 2026-10-02) ===== */
/* Both the bottom-nav's "More" popover and this widget live in the same
   bottom-right corner on mobile - without this, the widget (being on top,
   z-index 30) sat in front of the "More" menu instead of getting out of
   its way (Nick, 2026-10-02). :has() reacts straight to the menu's own
   [hidden] state, no extra JS wiring needed to keep two toggle points in
   sync. */
body:has(#bottom-nav-more-menu:not([hidden])) .ask-sparc { display: none; }

.ask-sparc {
  position: fixed; right: 1rem; z-index: 30;
  /* Above the mobile bottom-nav (its own height + safe area + a gap) on
     mobile; the bottom-nav is display:none >=768px, so a plain lower
     offset is fine there. */
  bottom: calc(4.75rem + env(safe-area-inset-bottom));
}
@media (min-width: 768px) {
  .ask-sparc { bottom: 1.5rem; }
}
.ask-sparc-toggle {
  width: 2.6rem; height: 2.6rem; border-radius: 50%; border: none;
  background: var(--gradient-charcoal); color: #fff; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-elevated);
}
.ask-sparc-toggle:hover { filter: brightness(1.08); }
/* An SVG's width/height HTML ATTRIBUTES aren't honoured for flex-item
   sizing, only real CSS width/height are - without this, Playwright
   confirmed the icon's rendered width collapses to ~0.02px (height stayed
   correct) inside these flex-centered buttons, which is why it looked like
   a blank button (Nick, 2026-10-02). Verified fixed via a real screenshot,
   not guessed. */
.ask-sparc-toggle svg { width: 23px; height: 23px; flex-shrink: 0; }
.ask-sparc-close svg { width: 16px; height: 16px; flex-shrink: 0; }
.ask-sparc-form button svg { width: 19px; height: 19px; flex-shrink: 0; }
.ask-sparc-panel {
  position: absolute; bottom: calc(2.6rem + 0.75rem); right: 0;
  width: min(22rem, calc(100vw - 2rem)); height: min(28rem, 70vh);
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-elevated);
  display: flex; flex-direction: column; overflow: hidden;
}
.ask-sparc-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.75rem 1rem; font-weight: 700; color: var(--charcoal);
  border-bottom: 1px solid var(--border);
}
.ask-sparc-close {
  background: transparent; border: none; color: var(--muted); cursor: pointer;
  padding: 0.25rem; display: flex;
}
.ask-sparc-close:hover { color: var(--text); }
.ask-sparc-messages {
  flex: 1; overflow-y: auto; padding: 0.9rem 1rem; display: flex;
  flex-direction: column; gap: 0.6rem;
}
.ask-sparc-msg {
  max-width: 85%; padding: 0.55rem 0.8rem; border-radius: 12px;
  font-size: 0.88rem; line-height: 1.4; white-space: pre-wrap;
}
.ask-sparc-msg-bot {
  align-self: flex-start; background: var(--bg); color: var(--text);
  border: 1px solid var(--border);
}
.ask-sparc-msg-user {
  align-self: flex-end; background: var(--gradient-charcoal); color: #fff;
}
.ask-sparc-msg-pending { opacity: 0.6; font-style: italic; }
.ask-sparc-form {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem; border-top: 1px solid var(--border);
}
.ask-sparc-form input {
  flex: 1; border: 1.5px solid var(--border); border-radius: 999px;
  padding: 0.55rem 0.9rem; font-size: 0.88rem; background: var(--card-bg); color: var(--text);
}
.ask-sparc-form input:focus { outline: none; border-color: var(--orange); }
.ask-sparc-form button {
  width: 2.3rem; height: 2.3rem; border-radius: 50%; border: none;
  background: var(--gradient-orange); color: #fff; cursor: pointer; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.ask-sparc-form button:hover { filter: brightness(1.08); }

/* ===== Event Scheduler (Nick, 2026-10-08) ===== */
.sched-calendar {
  background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.25rem; margin-bottom: 1.5rem; box-shadow: var(--shadow-elevated);
}
.sched-calendar-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
.sched-calendar-month { font-size: 1rem; font-weight: 700; }
.sched-calendar-weekdays, .sched-calendar-days {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.4rem;
}
.sched-calendar-weekdays span { text-align: center; font-size: 0.7rem; color: var(--muted); font-weight: 600; margin-bottom: 0.4rem; }
/* Dots, not bars (Nick, 2026-10-08: "the calendar bit old-school looking...
   maybe dots better... fit 3 or 4 across") - capped at 4 regardless of the
   real count, which is the whole point: "we don't want the number... that'll
   make it look like it's the 4th of the month". Same small-fixed-circle
   convention as the date-picker calendar elsewhere (.cal-picker-day) - the
   day number itself stays a neat small circle, not the whole wide grid
   cell, with the dot row sitting underneath it as its own small strip. */
.sched-cal-day {
  appearance: none; border: none; background: transparent;
  display: flex; flex-direction: column; align-items: center; gap: 0.3rem;
  padding: 0.3rem 0; cursor: pointer; color: var(--text);
}
.sched-cal-day-num {
  display: flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; border-radius: 50%; font-size: 0.86rem;
  transition: background 0.15s, color 0.15s;
}
.sched-cal-day:hover .sched-cal-day-num { background: var(--bg); }
.sched-cal-day.today .sched-cal-day-num { color: var(--orange); font-weight: 700; }
.sched-cal-day.selected .sched-cal-day-num { background: var(--gradient-orange); color: #fff; font-weight: 700; }
.sched-cal-day-bars { display: flex; gap: 2px; align-items: center; justify-content: center; height: 4px; }
.sched-cal-day-bar { width: 4px; height: 4px; border-radius: 50%; background: var(--charcoal); }

.sched-divider { border: none; border-top: 1px solid var(--border); margin: 1.5rem 0; }

.sched-row-list { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }
.sched-row {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  border-radius: var(--radius-sm); padding: 0.7rem 0.9rem; flex-wrap: wrap;
}
.sched-row-main { display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem; flex: 1; min-width: 0; }
.sched-row-name-line, .sched-row-stats-line { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.sched-row-name { font-weight: 700; font-size: 0.92rem; }
.sched-row-city { font-size: 0.8rem; color: var(--muted); }
.sched-row-meta { font-size: 0.8rem; color: var(--muted); white-space: nowrap; }
/* Time + duration, right-aligned on the tile (Nick, 2026-10-08: "location
   beside the name as it is now, but then have time and duration
   right-aligned... both editable") - .sched-row-main's own flex:1 already
   pushes this group (and the delete button after it) to the right. */
.sched-row-schedule { display: flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }

/* Scheduled Events = orange tint, Shortlist = charcoal tint, Customers =
   plain white/grey - the three list "colours" the rep learns to read at a
   glance (Nick, 2026-10-08). */
.sched-row-event { background: rgba(240, 120, 48, 0.08); border: 1px solid rgba(240, 120, 48, 0.25); }
/* Pending = staged locally, not a real event until Save Changes (Nick,
   2026-10-08) - a dashed border on top of the usual orange tint marks it
   as not-yet-committed, distinct from a genuinely scheduled tile. */
.sched-row-pending { border-style: dashed; }
.sched-pending-badge { color: var(--orange); font-weight: 600; }
.sched-save-btn { width: 100%; margin-top: 0.75rem; }
.sched-row-shortlist { background: rgba(50, 62, 72, 0.06); border: 1px solid rgba(50, 62, 72, 0.18); }
/* Plain white, no zebra striping (Nick, 2026-10-08: "the alternating line
   colours on the main list when it is more tiles than a table... just make
   them all white") - this is a stack of tiles, not an actual table, so
   alternating backgrounds read as a mistake rather than a table convention. */
.sched-row-customer { background: var(--card-bg); border: 1px solid var(--border); }

/* Time edit reuses the exact Dashboard rs-chip look (Nick, 2026-10-08:
   "needs to be more like our other time selectors, keeping style
   consistent") - same shared wheel picker (rsOpenTime), not a native
   <select>. */
/* A small, quiet grey circle with a charcoal x (Nick, 2026-10-08: "way too
   big and prominent... make it just a small circle... same grey as the
   time/duration selectors") - same muted .rs-chip background instead of a
   raised white card-bg circle with a shadow, which read as a much bigger,
   more "tap me" element than a delete action should be next to it. */
.sched-row-delete {
  /* padding:0 + min-width:0 matter here, not just decoration - the global
     button rule's own padding (0.75rem 1.15rem) otherwise survives
     underneath this and, as a flex item, a button's implicit min-width:auto
     won't let it shrink below that padding+icon size even with an explicit
     width set - rendered as a stretched oval, not a circle (Nick,
     2026-10-08: "its in a bean shaped thing rather than a circle" -
     confirmed live, this was the actual cause). */
  display: flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem;
  min-width: 0; padding: 0; line-height: 1; border-radius: 50%; border: none;
  background: var(--bg); color: var(--charcoal); cursor: pointer; flex-shrink: 0;
}
/* Without this, the SVG's own width/height HTML attributes get ignored
   inside this flex button and it renders at 0 width - invisible (Nick,
   2026-10-08: confirmed live, same "needs its own explicit svg rule" as
   every other icon button in this file, e.g. .task-tile-delete-btn svg). */
.sched-row-delete svg { width: 10px; height: 10px; flex-shrink: 0; }
.sched-row-delete:hover { background: var(--border); color: var(--error); }

.sched-shortlist-toggle {
  display: flex; align-items: center; gap: 0.35rem; font-size: 0.78rem; color: var(--muted);
  white-space: nowrap; cursor: pointer; font-weight: 500;
}
/* Charcoal, not the browser's default blue (Nick, 2026-10-08: "the blue
   checkbox for the shortlist, make it proper charcoal") - same accent-color
   convention used on every other checkbox in this app. */
.sched-shortlist-toggle input[type="checkbox"] { accent-color: var(--charcoal); }
.sched-add-btn { padding: 0.45rem 0.9rem; font-size: 0.82rem; white-space: nowrap; }

.sched-search-row { display: flex; gap: 0.6rem; margin-bottom: 0.9rem; flex-wrap: wrap; }
.sched-search-input {
  flex: 1 1 14rem; padding: 0.6rem 0.8rem; border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  font-size: 0.88rem; background: var(--card-bg); color: var(--text);
}
@media (max-width: 600px) {
  .sched-row { flex-direction: column; align-items: stretch; }
  .sched-row-main { gap: 0.4rem 1rem; }
}

/* ===== Customers tab (Nick, 2026-10-08) - "a collage of tiles" ===== */
.cust-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; }
.cust-tile {
  position: relative; background: var(--card-bg); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1rem; cursor: pointer; transition: border-color 0.15s, transform 0.15s;
}
.cust-tile:hover { border-color: var(--orange); transform: translateY(-2px); }
.cust-tile-name { font-weight: 700; font-size: 0.95rem; padding-right: 1.8rem; }
.cust-tile-city { font-size: 0.82rem; color: var(--muted); margin-top: 0.1rem; }
.cust-tile-stats { display: flex; flex-direction: column; gap: 0.15rem; margin-top: 0.6rem; font-size: 0.78rem; color: var(--muted); }
.cust-fav-btn {
  position: absolute; top: 0.8rem; right: 0.8rem; background: none; border: none; padding: 0;
  color: var(--border); cursor: pointer; display: flex;
}
.cust-fav-btn.active, .cust-fav-btn:hover { color: var(--orange); }

/* Full-page-feeling profile popup (Nick, 2026-10-08: "needs to be bigger,
   more of a full page kind of pop-up... a bit more visual") - much larger
   than the standard confirm/cancel .modal, its own header/snapshot/tabs/
   footer layout, scrolls internally once content outgrows the viewport
   rather than the backdrop itself scrolling. Collapses to a true full-
   screen sheet on phones (see media query below). */
.cust-profile-modal {
  max-width: 640px; width: 100%; max-height: 88vh; display: flex; flex-direction: column;
  text-align: left; padding: 0; overflow: hidden;
}
.cust-profile-header {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 0.75rem;
  padding: 1.25rem 1.5rem 1rem; border-bottom: 1px solid var(--border);
}
.cust-profile-header h2 { margin: 0; font-size: 1.25rem; }
.cust-profile-fav-btn { background: none; border: none; padding: 0.2rem; color: var(--border); cursor: pointer; flex-shrink: 0; }
.cust-profile-fav-btn.active, .cust-profile-fav-btn:hover { color: var(--orange); }
.cust-profile-fav-btn svg { width: 22px; height: 22px; }

.cust-profile-body { overflow-y: auto; padding: 1.25rem 1.5rem; flex: 1; }

/* Icon + label snapshot grid - "icons for various fields (map pin for
   location, person for primary contact, etc)" (Nick, 2026-10-08). Fields
   with no value just don't render a row at all, rather than showing an
   empty dash - the icon list grows over future syncs without every
   customer's popup looking half-empty in the meantime. */
/* Company Profile / Sales Activity each get their own clearly-bounded tile
   (Nick, 2026-10-08: "isn't very clearly segmented... make those labels
   bold, and put each segment in its own slightly greyer or whiter
   rounded-edge tile/box") - a subtler surface than the card itself so the
   grouping reads at a glance, bold label instead of the all-caps-but-thin
   subhead used for Open/Completed further down. */
.cust-profile-section { background: var(--bg); border-radius: var(--radius-sm); padding: 0.9rem 1rem; margin-bottom: 0.8rem; }
.cust-profile-section-title { font-weight: 700; font-size: 0.85rem; margin: 0 0 0.7rem; }
.cust-profile-facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 0.6rem 1.2rem; }
.cust-profile-fact { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.88rem; }
.cust-profile-fact svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 0.1rem; color: var(--orange); }
.cust-profile-fact-label { display: block; font-size: 0.72rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.02em; }
.cust-profile-fact-value { display: block; font-weight: 600; }
.cust-profile-fact a { color: var(--text); text-decoration: none; }
.cust-profile-fact a:hover { color: var(--orange-dark); text-decoration: underline; }

/* Segmented-control tabs, not an underline (Nick, 2026-10-08: "don't like
   the little orange edge thing under selected tab... need a neater way of
   indicating which tab is being viewed") - active tab reads as a solid
   white pill sitting on the grey track, same idea as an iOS segmented
   control, rather than a border accent easily mistaken for a stray line. */
.cust-profile-tabs { display: flex; gap: 0.25rem; background: var(--bg); border-radius: var(--radius-sm); padding: 0.25rem; margin: 0.4rem 0 1rem; }
.cust-profile-tab {
  flex: 1; background: none; border: none; padding: 0.5rem 0.6rem; font-size: 0.88rem;
  font-weight: 600; color: var(--muted); cursor: pointer; border-radius: calc(var(--radius-sm) - 2px);
  transition: background 0.15s, color 0.15s;
}
.cust-profile-tab.active { color: var(--text); background: var(--card-bg); box-shadow: var(--shadow-elevated); }

.cust-profile-subhead { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.02em; color: var(--muted); margin: 1rem 0 0.5rem; }
.cust-profile-subhead:first-child { margin-top: 0; }

/* Completed Action Cards / Events, collapsed by default (Nick, 2026-10-08:
   "have COMPLETED on both... collapsible, defaulting to collapsed") -
   plain <details>/<summary>, own chevron instead of the browser's default
   marker triangle, consistent with the rest of this file's icon language. */
.cust-profile-collapsible { margin-top: 1rem; }
.cust-profile-collapsible summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 0.35rem;
}
.cust-profile-collapsible summary::-webkit-details-marker { display: none; }
.cust-profile-collapsible summary::before {
  content: ''; width: 7px; height: 7px; border-right: 1.8px solid var(--muted); border-bottom: 1.8px solid var(--muted);
  transform: rotate(-45deg); transition: transform 0.15s; margin-top: -2px;
}
.cust-profile-collapsible[open] summary::before { transform: rotate(45deg); margin-top: 0; }
.cust-profile-collapsible .cust-profile-list, .cust-profile-collapsible .empty-state { margin-top: 0.5rem; }
.cust-profile-list { display: flex; flex-direction: column; gap: 0.5rem; }
.cust-profile-item {
  display: flex; align-items: center; justify-content: space-between; gap: 0.75rem;
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 0.65rem 0.85rem;
  font-size: 0.86rem;
}
.cust-profile-item-main { min-width: 0; }
.cust-profile-item-title { font-weight: 600; display: block; }
.cust-profile-item-sub { color: var(--muted); font-size: 0.78rem; }
a.cust-profile-item { text-decoration: none; color: inherit; cursor: pointer; }
a.cust-profile-item:hover { border-color: var(--orange); }

.cust-profile-footer {
  display: flex; flex-direction: column; gap: 0.6rem; padding: 1rem 1.5rem 1.25rem;
  border-top: 1px solid var(--border);
}
.cust-profile-footer .btn { width: 100%; }

@media (max-width: 600px) {
  .cust-profile-modal { max-width: none; width: 100%; height: 100%; max-height: 100%; border-radius: 0; }
  .cust-profile-facts { grid-template-columns: 1fr; }
  .modal-backdrop:has(.cust-profile-modal) { padding: 0; }
}

/* Favourites get their own outer orange box up top, collapsible (Nick,
   2026-10-08: "a neat orange box, with white favourite tile/s in it...
   defaults to expanded, but can be collapsed") - the white .cust-tile
   cards sit on the orange surface instead of the page's own background,
   same tile markup/styling as the plain grid below, just nested here. */
.cust-fav-section { background: var(--gradient-orange); border-radius: var(--radius); padding: 1rem; margin-bottom: 1.2rem; }
.cust-fav-section-toggle {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  background: none; border: none; padding: 0; color: #fff; font-weight: 700; font-size: 0.95rem; cursor: pointer;
}
.cust-fav-section-toggle svg { width: 18px; height: 18px; transform: rotate(90deg); transition: transform 0.15s; }
.cust-fav-section.collapsed .cust-fav-section-toggle svg { transform: rotate(0deg); }
.cust-fav-section-title { display: flex; align-items: center; gap: 0.5rem; }
.cust-fav-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; margin-top: 1rem; }
.cust-fav-section.collapsed .cust-fav-grid { display: none; }
.cust-fav-grid .cust-tile { background: var(--card-bg); }

/* Generate Price List's date range - two of the shared single-date
   calendar pickers side by side (Nick, 2026-10-09: "the calendar date
   range selector... is old-school, clunky... in keeping with the style")
   rather than a bare native <input type="date">. */
.pl-date-range-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.pl-date-range-sep { font-size: 0.82rem; color: var(--muted); }

/* Tools tab (Nick, 2026-10-09) - each tool is a plain link styled as a
   .task-tile, same card language as everywhere else in the app. */
.tools-tile { text-decoration: none; color: inherit; cursor: pointer; transition: border-color 0.15s, transform 0.15s; }
.tools-tile:hover { border-color: var(--orange); transform: translateY(-2px); }

/* Generic segmented-control toggle (Nick, 2026-10-09) - same pill-on-grey-
   track look as the Customer profile popup's Action Cards/Events tabs,
   reused here for Create Estimate's Live Opp / Generic Price List toggle
   (and anywhere else a simple two/three-way picker is needed). */
.seg-toggle { display: flex; gap: 0.25rem; background: var(--bg); border-radius: var(--radius-sm); padding: 0.25rem; }
.seg-toggle-btn {
  flex: 1; background: none; border: none; padding: 0.55rem 0.8rem; font-size: 0.88rem;
  font-weight: 600; color: var(--muted); cursor: pointer; border-radius: calc(var(--radius-sm) - 2px);
  transition: background 0.15s, color 0.15s;
}
.seg-toggle-btn.active { color: var(--text); background: var(--card-bg); box-shadow: var(--shadow-elevated); }

/* Send Email (Nick, 2026-10-09) */
.email-test-banner {
  background: var(--progress-bg); color: var(--progress-text); border-radius: var(--radius-sm);
  padding: 0.7rem 0.9rem; font-size: 0.85rem; margin-bottom: 1rem;
}
.email-preview-frame {
  width: 100%; min-height: 14rem; border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  background: #fff;
}

/* Email signature composite image (Nick, 2026-10-12) - a wide photo+logos
   row, not a circular avatar, so its own preview shape rather than reusing
   .avatar-preview's border-radius:50%. */
.email-sig-image-preview {
  max-width: 16rem; max-height: 4rem; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: #fff; object-fit: contain; flex-shrink: 0;
}
.email-sig-image-preview-empty {
  display: flex; align-items: center; justify-content: center; width: 16rem; height: 4rem;
  color: var(--muted); font-size: 0.82rem;
}
.email-sig-image-preview-clickable { cursor: pointer; transition: transform 0.12s; }
.email-sig-image-preview-clickable:hover { transform: scale(1.03); }
