/* ============================================================================
   Dart CRM — shared design system ("Voltage")
   One stylesheet for the whole hub: design tokens + the sidebar app shell +
   reusable components. Loaded on every page by nav.js (the shell). Component
   classes are namespaced `v-` so they never collide with a page's own styles
   (important for the big standalone /quote calculator).
   ========================================================================== */

/* Every box measures itself including its own padding and border.

   This was missing, and 21 pages rely on this stylesheet without declaring it
   themselves — so on those pages an input styled `width: 100%` was actually
   100% *plus* its padding and border, and therefore wider than the box holding
   it. That is the "containers are the wrong size / things stick out" problem at
   its source, rather than one page at a time. The pages that carry their own
   reset already set exactly this, so they are unaffected.

   It can only ever make an element narrower, never wider, so it cannot create
   a new overflow — only close existing ones. */
*, *::before, *::after { box-sizing: border-box; }

:root {
  /* Core surfaces (heavy dark) */
  --v-bg:        #0a0813;   /* app background */
  --v-bg-2:      #120f24;   /* raised background */
  --v-panel:     #14112a;   /* cards / panels */
  --v-panel-2:   #1b1836;   /* nested / hover */
  --v-line:      #2a2545;   /* borders */
  --v-line-soft: #201c3a;

  /* Text */
  --v-text:   #ece9f7;
  --v-text-2: #b7b0d4;   /* secondary */
  --v-muted:  #8f88b0;   /* tertiary / labels */

  /* Brand — violet primary, green secondary (zero orange) */
  --v-primary:      #8b5cf6;
  --v-primary-600:  #7c3aed;
  --v-primary-700:  #6d28d9;
  --v-primary-soft: #241a3d;
  --v-on-soft:      #c4b5fd;   /* text that sits on a --v-primary-soft pill/banner */
  --v-link:         #a78bfa;   /* inline links — brand colour, but readable as text */
  --v-accent:       #10b981;
  --v-accent-2:     #34d399;
  --v-accent-soft:  #123329;

  /* Status */
  --v-danger:      #fb7185;
  --v-danger-soft: #3a1622;
  --v-warn:        #fbbf24;
  --v-info:        #60a5fa;

  /* Shape + motion */
  --v-radius:    14px;
  --v-radius-sm: 9px;
  --v-radius-lg: 20px;
  --v-shadow:    0 10px 30px rgba(0,0,0,0.35);
  --v-shadow-sm: 0 3px 12px rgba(0,0,0,0.25);
  --v-ring:      0 0 0 3px rgba(139,92,246,0.35);
  --v-ease:      0.16s cubic-bezier(0.4,0,0.2,1);

  --v-sidebar-w:  244px;
  --v-sidebar-cw: 72px;   /* collapsed icon-rail width */
  --v-topbar-h:   60px;
  --v-pagetabs-h: 44px;
  --v-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;

  /* Theme-swappable chrome (light themes override these at the bottom of the file) */
  --v-text-strong:  #ffffff;
  --v-sidebar-bg:   linear-gradient(180deg, #100d22 0%, #0c0a1a 100%);
  --v-topbar-bg:    rgba(10,8,19,0.72);
  --v-hover:        rgba(255,255,255,0.05);
  --v-hover-strong: rgba(255,255,255,0.06);
  --v-scroll:       #2c2748;
  --v-scroll-hover: #3a3460;
  color-scheme: dark;
}

/* ── Base, applied once the shell is present so standalone pages opt in ─────── */
body.gpw-has-shell {
  background:
    radial-gradient(1200px 600px at 80% -10%, rgba(139,92,246,0.10), transparent 60%),
    radial-gradient(900px 500px at -10% 10%, rgba(16,185,129,0.06), transparent 55%),
    var(--v-bg);
  color: var(--v-text);
  font-family: var(--v-font);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  padding-top: var(--v-topbar-h);
  padding-left: var(--v-sidebar-w);
  transition: padding-left var(--v-ease);
}
body.gpw-has-shell.gpw-sb-collapsed { padding-left: var(--v-sidebar-cw); }
/* Pages in a multi-page area carry the tab strip under the topbar — make room. */
body.gpw-has-shell.gpw-has-tabs { padding-top: calc(var(--v-topbar-h) + var(--v-pagetabs-h)); }
@media (max-width: 767px) {
  body.gpw-has-shell,
  body.gpw-has-shell.gpw-sb-collapsed { padding-left: 0; }
}

body.gpw-has-shell ::-webkit-scrollbar { width: 10px; height: 10px; }
body.gpw-has-shell ::-webkit-scrollbar-thumb { background: var(--v-scroll); border-radius: 999px; border: 2px solid transparent; background-clip: content-box; }
body.gpw-has-shell ::-webkit-scrollbar-thumb:hover { background: var(--v-scroll-hover); background-clip: content-box; }

/* A generic page content wrapper pages can adopt for consistent gutters. */
.v-wrap { max-width: 1140px; margin: 0 auto; padding: 1.75rem 1.5rem 3rem; }
@media (max-width: 640px) { .v-wrap { padding: 1.1rem 1rem 2.5rem; } }

/* ── Page header ──────────────────────────────────────────────────────────── */
.v-page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.4rem; }
.v-page-title { font-size: 1.55rem; font-weight: 800; letter-spacing: -0.02em; display: flex; align-items: center; gap: 0.6rem; }
.v-page-sub { color: var(--v-muted); font-size: 0.9rem; margin-top: 0.25rem; }

/* ============================================================================
   Sidebar app shell (built by nav.js)
   ========================================================================== */
#gpw-sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--v-sidebar-w); z-index: 9000;
  background: var(--v-sidebar-bg);
  border-right: 1px solid var(--v-line); display: flex; flex-direction: column;
  padding: 16px 12px; gap: 4px; font-family: var(--v-font);
  transition: width var(--v-ease), transform var(--v-ease); overflow: hidden;
}
#gpw-brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 14px; }

/* Collapse toggle (desktop) — a chevron pinned in the brand row */
#gpw-sb-toggle { margin-left: auto; background: none; border: none; color: var(--v-muted);
  cursor: pointer; font-size: 1rem; padding: 6px; border-radius: 8px; line-height: 1; flex-shrink: 0; }
#gpw-sb-toggle:hover { background: var(--v-hover-strong); color: var(--v-text-strong); }

/* ── Collapsed (icon-rail) state ─────────────────────────────────────────── */
body.gpw-sb-collapsed #gpw-sidebar { width: var(--v-sidebar-cw); padding-left: 8px; padding-right: 8px; }
body.gpw-sb-collapsed #gpw-brand .name,
body.gpw-sb-collapsed .gpw-navlink span:not(.ic),
body.gpw-sb-collapsed #gpw-create .label { display: none; }
body.gpw-sb-collapsed #gpw-brand { justify-content: center; padding: 6px 0 14px; }
body.gpw-sb-collapsed #gpw-sb-toggle { display: none; }
body.gpw-sb-collapsed .gpw-navlink { justify-content: center; padding: 10px 0; }
body.gpw-sb-collapsed #gpw-create { padding: 11px 0; font-size: 0; } /* font-size:0 hides the label text/node; the ＋ span keeps its inline size */
body.gpw-sb-collapsed .gpw-nav-sep { margin: 8px 14px; }
/* tooltip on hover when collapsed */
body.gpw-sb-collapsed .gpw-navlink { position: relative; }
body.gpw-sb-collapsed .gpw-navlink:hover::after {
  content: attr(data-label); position: absolute; left: calc(100% + 10px); top: 50%; transform: translateY(-50%);
  background: var(--v-panel); border: 1px solid var(--v-line); color: var(--v-text); padding: 5px 10px;
  border-radius: 8px; font-size: 0.8rem; white-space: nowrap; box-shadow: var(--v-shadow); z-index: 9500; }
#gpw-brand .gpw-brand-home { display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; border-radius: 12px; }
#gpw-brand .logo { width: 34px; height: 34px; border-radius: 10px; background: linear-gradient(135deg, var(--v-primary), var(--v-primary-700)); display: grid; place-items: center; font-size: 1.05rem; box-shadow: 0 4px 14px rgba(124,58,237,0.5); flex-shrink: 0; transition: transform .15s ease, box-shadow .15s ease; }
#gpw-brand .gpw-brand-home:hover .logo { transform: translateY(-1px); box-shadow: 0 6px 20px rgba(124,58,237,0.8); }
#gpw-brand .name { font-weight: 800; font-size: 0.95rem; line-height: 1.1; color: var(--v-text-strong); }
#gpw-brand .name small { display: block; font-weight: 600; font-size: 0.68rem; color: var(--v-muted); letter-spacing: 0.02em; }

#gpw-create {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin: 2px 4px 12px; padding: 11px 14px; border: none; border-radius: 12px; cursor: pointer;
  background: linear-gradient(135deg, var(--v-primary), var(--v-primary-700)); color: #fff;
  font-weight: 700; font-size: 0.9rem; font-family: var(--v-font);
  box-shadow: 0 6px 18px rgba(124,58,237,0.45); transition: transform var(--v-ease), box-shadow var(--v-ease);
}
#gpw-create:hover { transform: translateY(-1px); box-shadow: 0 10px 24px rgba(124,58,237,0.6); }
#gpw-create:active { transform: translateY(0); }

.gpw-navlink { display: flex; align-items: center; gap: 11px; padding: 10px 12px; border-radius: 10px; color: var(--v-text-2); text-decoration: none; font-size: 0.9rem; font-weight: 600; transition: background var(--v-ease), color var(--v-ease); }
.gpw-navlink .ic { font-size: 1.05rem; width: 22px; text-align: center; flex-shrink: 0; }
.gpw-navlink:hover { background: var(--v-hover); color: var(--v-text-strong); }
.gpw-navlink.active { background: var(--v-primary-soft); color: var(--v-text-strong); box-shadow: inset 3px 0 0 var(--v-primary); }
.gpw-nav-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; display: flex; flex-direction: column; gap: 4px; scrollbar-width: thin; }
.gpw-nav-scroll::-webkit-scrollbar { width: 6px; }
.gpw-nav-scroll::-webkit-scrollbar-thumb { background: var(--v-line); border-radius: 3px; }
.gpw-nav-spacer { flex: 1; }
.gpw-nav-sep { height: 1px; background: var(--v-line-soft); margin: 8px 10px; }

/* ── Page tabs (built by nav.js) ────────────────────────────────────────────
   The rail has no dropdowns: an area that spans several pages (Job Log,
   Calculator, Messages, Financials, Classroom, Checklists, Settings) is one nav
   row, and its pages ride this strip under the topbar. Same place, several
   tabs. Scrolls sideways on a phone rather than wrapping into two rows. */
#gpw-pagetabs {
  position: fixed; top: var(--v-topbar-h); right: 0; left: var(--v-sidebar-w); z-index: 8400;
  height: var(--v-pagetabs-h); display: flex; align-items: stretch; gap: 2px; padding: 0 14px;
  background: var(--v-topbar-bg); backdrop-filter: blur(12px); border-bottom: 1px solid var(--v-line);
  font-family: var(--v-font); transition: left var(--v-ease);
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
#gpw-pagetabs::-webkit-scrollbar { display: none; }
body.gpw-sb-collapsed #gpw-pagetabs { left: var(--v-sidebar-cw); }
.gpw-ptab {
  display: flex; align-items: center; gap: 7px; padding: 0 12px; white-space: nowrap;
  color: var(--v-muted); text-decoration: none; font-size: 0.86rem; font-weight: 700;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color var(--v-ease), border-color var(--v-ease);
}
.gpw-ptab .ic { font-size: 0.95rem; }
.gpw-ptab:hover { color: var(--v-text); }
.gpw-ptab.active { color: var(--v-primary); border-bottom-color: var(--v-primary); }

/* ── Compact density (Settings → Appearance) ───────────────────────────────
   Tightens the shell + the standard page wrapper so more fits on one screen. */
:root[data-density="compact"] .gpw-navlink { padding: 7px 11px; font-size: 0.86rem; }
:root[data-density="compact"] .gpw-ptab { padding: 0 10px; font-size: 0.82rem; }
:root[data-density="compact"] .gpw-nav-scroll { gap: 2px; }
:root[data-density="compact"] .gpw-nav-sep { margin: 5px 10px; }
:root[data-density="compact"] #gpw-create { padding: 9px 14px; margin-bottom: 9px; }
:root[data-density="compact"] .v-wrap { padding: 1.1rem 1.1rem 2rem; max-width: 1320px; }
:root[data-density="compact"] .v-card-pad { padding: 0.9rem 1rem; }
:root[data-density="compact"] .v-page-head { margin-bottom: 0.9rem; }
:root[data-density="compact"] .v-page-title { font-size: 1.3rem; }
:root[data-density="compact"] .v-table td { padding: 0.5rem 0.65rem; }
:root[data-density="compact"] .v-table th { padding: 0.45rem 0.65rem; }

/* Top bar */
#gpw-topbar {
  position: fixed; top: 0; right: 0; left: var(--v-sidebar-w); height: var(--v-topbar-h); z-index: 8500;
  display: flex; align-items: center; gap: 12px; padding: 0 18px;
  background: var(--v-topbar-bg); backdrop-filter: blur(12px); border-bottom: 1px solid var(--v-line);
  font-family: var(--v-font); transition: left var(--v-ease);
}
body.gpw-sb-collapsed #gpw-topbar { left: var(--v-sidebar-cw); }
#gpw-hamburger { display: none; background: none; border: none; color: var(--v-text); font-size: 1.3rem;
  cursor: pointer; padding: 6px 8px; border-radius: 8px; line-height: 1; }
#gpw-hamburger:hover { background: var(--v-hover-strong); }
/* Persistent expand control (desktop): the in-sidebar toggle is hidden while the
   rail is collapsed, so this lives in the topbar and only shows when collapsed. */
#gpw-sb-expand { display: none; background: none; border: none; color: var(--v-text); font-size: 1.25rem;
  cursor: pointer; padding: 6px 10px; border-radius: 8px; line-height: 1; flex-shrink: 0; }
#gpw-sb-expand:hover { background: var(--v-hover-strong); color: var(--v-text-strong); }
body.gpw-sb-collapsed #gpw-sb-expand { display: inline-flex; }
@media (max-width: 767px) { #gpw-sb-expand { display: none !important; } } /* mobile uses the hamburger drawer */
#gpw-search-wrap { position: relative; flex: 1 1 120px; min-width: 0; max-width: 480px; }
#gpw-search { width: 100%; padding: 9px 12px 9px 36px; border-radius: 10px; border: 1px solid var(--v-line); background: var(--v-panel); color: var(--v-text); font-size: 0.88rem; font-family: var(--v-font); }
#gpw-search:focus { outline: none; border-color: var(--v-primary); box-shadow: var(--v-ring); }
#gpw-search-wrap .si { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--v-muted); font-size: 0.9rem; pointer-events: none; }
#gpw-search-results { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 12px; box-shadow: var(--v-shadow); overflow: hidden; display: none; z-index: 9500; }
#gpw-search-results.open { display: block; }
#gpw-search-results a { display: block; padding: 10px 14px; color: var(--v-text); text-decoration: none; border-bottom: 1px solid var(--v-line-soft); font-size: 0.86rem; }
#gpw-search-results a:last-child { border-bottom: none; }
#gpw-search-results a:hover { background: var(--v-panel-2); }
#gpw-search-results .r-name { font-weight: 600; }
#gpw-search-results .r-meta { color: var(--v-muted); font-size: 0.78rem; margin-top: 1px; }
#gpw-search-results .r-empty { padding: 12px 14px; color: var(--v-muted); font-size: 0.84rem; }

#gpw-topbar .tb-right { margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none; }
/* Topbar can never overflow: as width tightens, drop the least-critical labels
   before the fixed-size controls have to overlap. Icons + avatar always fit. */
.gpw-ev-btn .ev-eye { display: none; }               /* label shows at full width */
@media (max-width: 1040px) {
  #gpw-topbar .tb-uname { display: none; }            /* keep the avatar, drop the name */
  .gpw-ev-btn .ev-label { display: none; }            /* collapse "Employee View" to the eye */
  .gpw-ev-btn .ev-eye { display: inline; font-size: 1rem; }
  .gpw-ev-btn { padding: 7px 10px; }
}
@media (max-width: 767px) {
  #gpw-search-wrap { display: none; }                 /* phones: search lives in the drawer, reclaim the bar */
}
#gpw-topbar .tb-user { display: flex; align-items: center; gap: 8px; font-size: 0.82rem; color: var(--v-text-2); }
#gpw-topbar .tb-avatar { width: 32px; height: 32px; border-radius: 50%; background: linear-gradient(135deg, var(--v-primary), var(--v-primary-700)); color: #fff; display: grid; place-items: center; font-weight: 700; font-size: 0.8rem; }
#gpw-topbar .tb-logout { color: var(--v-muted); text-decoration: none; font-size: 0.82rem; font-weight: 600; padding: 6px 10px; border-radius: 8px; }
#gpw-topbar .tb-logout:hover { color: var(--v-danger); background: var(--v-danger-soft); }

/* Back button — styled as a topbar icon button (.gpw-icon-btn), always reachable */
#gpw-back { flex-shrink: 0; }

/* Grouped global-search results (clients / quotes / invoices / jobs) */
#gpw-search-results .r-group { padding: 8px 14px 4px; font-size: 0.62rem; font-weight: 800;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--v-muted);
  background: var(--v-panel-2); border-bottom: 1px solid var(--v-line-soft); }
#gpw-search-results a.active { background: var(--v-primary-soft); }

/* User menu (avatar dropdown) */
#gpw-user-wrap { position: relative; }
#gpw-topbar button.tb-user { border: 1px solid transparent; border-radius: 10px; padding: 4px 8px 4px 6px;
  cursor: pointer; font-family: var(--v-font); background: none; }
#gpw-topbar button.tb-user:hover { background: var(--v-hover-strong); border-color: var(--v-line); }
#gpw-topbar button.tb-user .tb-uname { font-size: 0.82rem; color: var(--v-text-2); }
#gpw-topbar button.tb-user .tb-caret { font-size: 0.7rem; color: var(--v-muted); margin-left: 2px; }
#gpw-user-menu { position: absolute; right: 0; top: calc(100% + 8px); z-index: 9600;
  background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 14px;
  box-shadow: var(--v-shadow); padding: 6px; min-width: 176px; display: none; }
#gpw-user-menu.open { display: block; }
#gpw-user-menu button { display: flex; align-items: center; gap: 10px; width: 100%; background: none;
  border: none; color: var(--v-text); padding: 9px 11px; border-radius: 9px; cursor: pointer;
  font-size: 0.88rem; font-weight: 600; font-family: var(--v-font); text-align: left; }
#gpw-user-menu button:hover { background: var(--v-panel-2); }
#gpw-user-menu button#gpw-logout:hover { color: var(--v-danger); background: var(--v-danger-soft); }
#gpw-user-menu .um-ic { width: 18px; text-align: center; }

/* Notification bell + badge + dropdown */
#gpw-notif-wrap { position: relative; }
#gpw-notif-btn { position: relative; }
#gpw-notif-badge { position: absolute; top: 1px; right: 1px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; background: var(--v-danger); color: #fff; font-size: 0.6rem; font-weight: 800;
  line-height: 15px; text-align: center; box-shadow: 0 0 0 2px var(--v-topbar-bg, var(--v-bg)); }
#gpw-notif-menu { position: absolute; right: 0; top: calc(100% + 8px); z-index: 9600;
  background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 14px;
  box-shadow: var(--v-shadow); padding: 6px; min-width: 288px; max-width: 340px;
  max-height: 70vh; overflow-y: auto; display: none; }
#gpw-notif-menu.open { display: block; }
#gpw-notif-menu .ntf-head { display: flex; align-items: center; justify-content: space-between;
  padding: 8px 10px 4px; font-size: 0.62rem; font-weight: 800;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--v-muted); }
#gpw-notif-menu .ntf-clearall { border: none; background: transparent; cursor: pointer;
  color: var(--v-primary); font-family: var(--v-font); font-size: 0.62rem; font-weight: 800;
  letter-spacing: 0.04em; text-transform: uppercase; padding: 2px 4px; border-radius: 6px; }
#gpw-notif-menu .ntf-clearall:hover { background: var(--v-primary-soft); }
#gpw-notif-menu .ntf-note, #gpw-notif-menu .ntf-empty { padding: 14px 12px; color: var(--v-muted);
  font-size: 0.86rem; text-align: center; }
/* Each row: content (link or static) + a dismiss checkmark pinned to the right. */
#gpw-notif-menu .ntf-row { position: relative; border-radius: 9px; }
#gpw-notif-menu .ntf-row:hover { background: var(--v-panel-2); }
#gpw-notif-menu a, #gpw-notif-menu .ntf-body { display: block; padding: 8px 11px; border-radius: 9px;
  color: var(--v-text); text-decoration: none; }
#gpw-notif-menu .ntf-row a, #gpw-notif-menu .ntf-row .ntf-body { padding-right: 34px; }
#gpw-notif-menu a:hover { background: var(--v-panel-2); }
#gpw-notif-menu .ntf-name { font-weight: 600; font-size: 0.85rem; }
#gpw-notif-menu .ntf-sub { color: var(--v-muted); font-size: 0.76rem; margin-top: 1px; }
#gpw-notif-menu .ntf-time { color: var(--v-muted); font-size: 0.68rem; margin-top: 2px; }
#gpw-notif-menu .ntf-static { padding: 8px 11px; border-radius: 9px; }
#gpw-notif-menu .ntf-row.unread { background: var(--v-primary-soft); }
#gpw-notif-menu .ntf-row.unread .ntf-name::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--v-primary); margin-right: 6px; vertical-align: middle; }
#gpw-notif-menu .ntf-dismiss { position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 22px; height: 22px; display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 6px; cursor: pointer; background: transparent; color: var(--v-muted);
  font-size: 0.8rem; line-height: 1; padding: 0; }
#gpw-notif-menu .ntf-dismiss:hover { background: var(--v-primary-600); color: #fff; }
#gpw-notif-menu .ntf-enable { display: block; width: 100%; text-align: left; margin-bottom: 4px;
  padding: 9px 11px; border: 1px solid var(--v-primary); background: var(--v-primary-soft);
  color: var(--v-primary); border-radius: 10px; font-weight: 700; font-size: 0.8rem; cursor: pointer; font-family: var(--v-font); }
#gpw-notif-menu .ntf-enable:hover:not([disabled]) { background: var(--v-primary-600); color: #fff; }

/* Messages icon (admin) — customer-texting inbox: badge on the topbar button,
   opening it slides in a full-height panel from the right edge of the
   viewport (Jobber's Message Center is the model), not a small anchored
   dropdown. Panel + backdrop are appended straight to <body> (like #gpw-scrim
   below) so they sit above everything regardless of the topbar's own
   stacking context. */
#gpw-msg-wrap { position: relative; }
#gpw-msg-btn { position: relative; }
/* Soft bg + danger-coloured text + a 1px danger border, not a solid-danger
   fill with white text (the pattern the bell badge above uses) — that white-
   on-danger combo only clears WCAG 1.4.3 in the light theme (~2.7:1 in dark).
   This pairing is also what the rest of the app already uses for "danger"
   everywhere else (.v-btn-danger, .v-badge.red) — box-sizing: border-box so
   the added border doesn't grow the dot past the bell badge's footprint. */
#gpw-msg-badge { position: absolute; top: 1px; right: 1px; min-width: 15px; height: 15px; padding: 0 3px;
  box-sizing: border-box; border-radius: 999px; background: var(--v-danger-soft); color: var(--v-danger);
  border: 1px solid var(--v-danger); font-size: 0.6rem; font-weight: 800;
  line-height: 13px; text-align: center; box-shadow: 0 0 0 2px var(--v-topbar-bg, var(--v-bg)); }

#gpw-msg-backdrop { position: fixed; inset: 0; z-index: 9600; background: rgba(0,0,0,.45);
  opacity: 0; pointer-events: none; transition: opacity .2s ease; }
#gpw-msg-backdrop.open { opacity: 1; pointer-events: auto; }
#gpw-msg-panel { position: fixed; top: 0; right: 0; bottom: 0; z-index: 9601; width: min(420px, 100vw);
  background: var(--v-panel); border-left: 1px solid var(--v-line); box-shadow: -10px 0 30px rgba(0,0,0,.2);
  display: flex; flex-direction: column; transform: translateX(100%); visibility: hidden;
  transition: transform .22s ease, visibility 0s linear .22s; }
#gpw-msg-panel.open { transform: translateX(0); visibility: visible; transition: transform .22s ease; }
#gpw-msg-panel .mp-head { display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.1rem .7rem; border-bottom: 1px solid var(--v-line); flex-shrink: 0; }
#gpw-msg-panel .mp-head h2 { font-size: 1.3rem; font-weight: 800; margin: 0; }
#gpw-msg-panel .mp-actions { display: flex; gap: .4rem; }
#gpw-msg-panel .mp-actions button { border: 1px solid var(--v-line); background: var(--v-panel);
  color: var(--v-text-2); width: 2.15rem; height: 2.15rem; border-radius: 9px; font-size: 1rem;
  cursor: pointer; display: flex; align-items: center; justify-content: center; }
#gpw-msg-panel .mp-actions button:hover { background: var(--v-panel-2); color: var(--v-primary-600); border-color: var(--v-primary); }
#gpw-msg-panel .mp-search { position: relative; padding: .7rem 1.1rem; flex-shrink: 0; }
#gpw-msg-panel .mp-sic { position: absolute; left: 1.55rem; top: 50%; transform: translateY(-50%);
  color: var(--v-muted); font-size: .82rem; pointer-events: none; }
#gpw-msg-panel .mp-search input { width: 100%; border: 1px solid var(--v-line); border-radius: 999px;
  padding: .55rem .8rem .55rem 2.15rem; font: inherit; font-size: .88rem; background: var(--v-panel-2); color: var(--v-text); }
#gpw-msg-panel .mp-search input:focus-visible { outline: none; border-color: var(--v-primary); box-shadow: var(--v-ring); background: var(--v-panel); }
#gpw-msg-panel .mp-list { flex: 1; overflow-y: auto; padding: 0 .5rem .5rem; }
#gpw-msg-panel .mp-empty { color: var(--v-muted); font-size: .85rem; text-align: center; padding: 2rem 1rem; }
#gpw-msg-panel .mp-divider { padding: .8rem .6rem .3rem; font-size: .66rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--v-muted); }
#gpw-msg-panel .mp-row { display: block; width: 100%; padding: .65rem .6rem; border-radius: 10px;
  border: 0; background: transparent; color: var(--v-text); text-align: left; font: inherit;
  cursor: pointer; position: relative; }
#gpw-msg-panel .mp-row:hover { background: var(--v-panel-2); }
#gpw-msg-panel .mp-row:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--v-primary); }
#gpw-msg-panel .mp-top { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }
#gpw-msg-panel .mp-name { font-weight: 700; font-size: .92rem; }
#gpw-msg-panel .mp-pill { font-size: .62rem; font-weight: 800; text-transform: uppercase; letter-spacing: .03em;
  color: #fff; background: var(--v-primary-600); border-radius: 999px; padding: .12rem .5rem; flex-shrink: 0; }
#gpw-msg-panel .mp-prev { color: var(--v-muted); font-size: .8rem; font-style: italic; margin-top: .2rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#gpw-msg-panel .mp-time { color: var(--v-muted); font-size: .7rem; font-weight: 500; margin-top: .25rem; }
#gpw-msg-panel .mp-row.unread { background: var(--v-primary-soft); }
#gpw-msg-panel .mp-row.unread .mp-name::before {
  content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--v-primary); margin-right: 6px; vertical-align: middle; }

/* Thread view — the conversation replied to right inside the panel, no
   navigating away (see wireThreadChrome/openThreadInline in nav.js). */
#gpw-msg-panel .mp-back { border: 0; background: transparent; color: var(--v-text); font-size: 1.3rem;
  line-height: 1; cursor: pointer; padding: .2rem .3rem; border-radius: 7px; flex-shrink: 0; }
#gpw-msg-panel .mp-back:hover { background: var(--v-panel-2); }
#gpw-msg-panel .mp-back:focus-visible { outline: none; box-shadow: var(--v-ring); }
#gpw-msg-panel .mp-thread-who { flex: 1; min-width: 0; }
#gpw-msg-panel .mp-thread-name { font-weight: 700; font-size: .92rem; }
#gpw-msg-panel .mp-thread-name a { color: inherit; text-decoration: none; }
#gpw-msg-panel .mp-thread-name a:hover { text-decoration: underline; }
#gpw-msg-panel .mp-thread-sub { font-size: .74rem; color: var(--v-muted); margin-top: .1rem; }
#gpw-msg-panel .mp-msgs { flex: 1; overflow-y: auto; padding: .9rem .8rem; display: flex; flex-direction: column; gap: .4rem; }
#gpw-msg-panel .mp-bub { max-width: 82%; padding: .5rem .7rem; border-radius: 15px; font-size: .85rem;
  line-height: 1.4; white-space: pre-wrap; word-break: break-word; }
#gpw-msg-panel .mp-bub.in { align-self: flex-start; background: var(--v-panel-2); color: var(--v-text); border-bottom-left-radius: 4px; }
#gpw-msg-panel .mp-bub.out { align-self: flex-end; background: var(--v-primary-600); color: #fff; border-bottom-right-radius: 4px; }
#gpw-msg-panel .mp-bub img { max-width: 100%; border-radius: 10px; margin-top: .35rem; display: block; }
#gpw-msg-panel .mp-bmeta { font-size: .64rem; margin-top: .25rem; opacity: .8; }
#gpw-msg-panel .mp-bub.out .mp-bmeta { color: rgba(255,255,255,.8); text-align: right; }
#gpw-msg-panel .mp-bub.in .mp-bmeta { color: var(--v-muted); }
#gpw-msg-panel .mp-failed { color: #fecaca; font-weight: 700; }
#gpw-msg-panel .mp-callrow { align-self: center; max-width: 88%; background: var(--v-panel-2); border: 1px solid var(--v-line);
  border-radius: 12px; padding: .5rem .8rem; font-size: .78rem; color: var(--v-text-2); text-align: center; }
#gpw-msg-panel .mp-call-time { color: var(--v-muted); font-size: .68rem; }
#gpw-msg-panel .mp-callrow audio { margin-top: .4rem; width: 220px; max-width: 100%; height: 32px; }
#gpw-msg-panel .mp-call-tx { margin-top: .35rem; font-style: italic; color: var(--v-muted); line-height: 1.4; }
#gpw-msg-panel .mp-composer { border-top: 1px solid var(--v-line); padding: .55rem .65rem; display: flex;
  gap: .5rem; align-items: flex-end; flex-shrink: 0; }
#gpw-msg-panel .mp-composer textarea { flex: 1; resize: none; border-radius: 10px; border: 1px solid var(--v-line);
  padding: .5rem .6rem; font: inherit; font-size: .85rem; background: var(--v-panel); color: var(--v-text);
  max-height: 110px; min-height: 40px; }
#gpw-msg-panel .mp-composer textarea:focus-visible { outline: none; border-color: var(--v-primary); box-shadow: var(--v-ring); }
#gpw-msg-panel .mp-composer button { border: 0; background: var(--v-primary-600); color: #fff; font: inherit;
  font-weight: 700; font-size: .84rem; border-radius: 10px; padding: .55rem 1rem; cursor: pointer; flex-shrink: 0; }
#gpw-msg-panel .mp-composer button:hover:not(:disabled) { background: var(--v-primary-700); }
#gpw-msg-panel .mp-composer button:disabled { opacity: .5; cursor: not-allowed; }
#gpw-msg-panel .mp-reply-err { padding: 0 .8rem .6rem; color: #fb7185; font-size: .78rem; min-height: 1em; flex-shrink: 0; }
@media (max-width: 480px) { #gpw-msg-panel { width: 100vw; } }

/* Mobile: sidebar becomes an off-canvas drawer (no bottom bar) */
#gpw-scrim { display: none; position: fixed; inset: 0; z-index: 8900; background: rgba(0,0,0,0.55);
  opacity: 0; pointer-events: none; transition: opacity var(--v-ease); }
@media (max-width: 767px) {
  #gpw-hamburger { display: inline-flex; }
  #gpw-topbar { left: 0 !important; }
  #gpw-pagetabs { left: 0 !important; padding: 0 8px; }
  #gpw-sidebar { transform: translateX(-100%); width: var(--v-sidebar-w) !important;
    padding-left: 12px !important; padding-right: 12px !important; box-shadow: none; }
  /* on mobile the drawer always shows full labels regardless of collapsed flag */
  body.gpw-sb-collapsed .gpw-navlink span:not(.ic),
  body.gpw-sb-collapsed #gpw-brand .name,
  body.gpw-sb-collapsed #gpw-create .label { display: inline; }
  body.gpw-sb-collapsed .gpw-navlink { justify-content: flex-start; padding: 10px 12px; }
  body.gpw-sb-open #gpw-sidebar { transform: none; box-shadow: 0 0 44px rgba(0,0,0,0.65); }
  /* The "collapse to an icon rail" chevron makes no sense in a slide-out drawer,
     and at 21x28px it was the smallest tap target in the app — on every page. */
  #gpw-sb-toggle { display: none; }
  #gpw-scrim { display: block; }

  /* A thumb is a much blunter instrument than a mouse pointer. Small utility
     buttons — the period pills on Financials, the toggles on the quote
     calculator, every little "x" close — sat between 25 and 30px on a phone,
     which is where mis-taps come from. This only ever grows a control that is
     too small; anything already comfortable is untouched. */
  button, .v-btn, a.v-btn, input[type="submit"], input[type="button"] {
    min-height: 34px; min-width: 34px;
  }
  /* The same problem, one class of control later: the standalone text links that
     behave like buttons — "Full schedule ↗", "Open schedule →", "All charts &
     detail →", "← All clients" — were 15px tall on a phone, half a thumb. Only
     these named, on-their-own-line links are grown; a link inside a sentence is
     left alone so nothing about text wrapping changes. */
  .gpwcal-link, .sec-head .link, .backlink {
    display: inline-flex; align-items: center; min-height: 30px;
  }
  /* The phone number and address on a pipeline card. Kept as full-width rows
     rather than inline-flex: they are meant to be tappable across the whole card,
     so shrinking them to the width of the text would trade height for width and
     gain nothing. Written as a.c-phone / a.c-addr rather than .c-phone / .c-addr
     because pipeline.html sets `display: block` on both in its own stylesheet,
     which loads after this file — an equally specific rule here would lose, and
     the row would keep its old top-aligned text. */
  a.c-phone, a.c-addr { display: flex; align-items: center; min-height: 30px; }
  body.gpw-sb-open #gpw-scrim { opacity: 1; pointer-events: auto; }
}

/* Create dropdown menu (desktop, anchored under the sidebar Create button) */
#gpw-create-menu { position: fixed; z-index: 9600; background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 14px; box-shadow: var(--v-shadow); padding: 6px; min-width: 210px; display: none; }
#gpw-create-menu.open { display: block; }
#gpw-create-menu button { display: flex; align-items: center; gap: 11px; width: 100%; background: none; border: none; color: var(--v-text); padding: 10px 12px; border-radius: 9px; cursor: pointer; font-size: 0.9rem; font-weight: 600; font-family: var(--v-font); text-align: left; }
#gpw-create-menu button:hover { background: var(--v-panel-2); }
#gpw-create-menu button .ic { font-size: 1.1rem; width: 22px; text-align: center; }
#gpw-create-menu .cm-sub { color: var(--v-muted); font-weight: 500; font-size: 0.76rem; }

/* ── Employee View (admin impersonation) ─────────────────────────────────── */
#gpw-ev-wrap { position: relative; }
.gpw-ev-btn {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  background: var(--v-primary-soft, rgba(139,92,246,0.14)); color: var(--v-on-soft);
  border: 1px solid var(--v-primary); border-radius: 10px;
  padding: 7px 12px; font-size: 0.82rem; font-weight: 700; cursor: pointer;
  font-family: var(--v-font);
}
.gpw-ev-btn:hover { background: var(--v-primary-600); color: #fff; }
#gpw-ev-menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 9600;
  background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 14px;
  box-shadow: var(--v-shadow); padding: 6px; min-width: 232px; display: none;
}
#gpw-ev-menu.open { display: block; }
#gpw-ev-menu .ev-head { color: var(--v-muted); font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; padding: 6px 10px 4px; }
#gpw-ev-menu .ev-note { color: var(--v-muted); font-size: 0.84rem; padding: 10px 12px; }
#gpw-ev-menu button {
  display: flex; align-items: center; gap: 11px; width: 100%; background: none;
  border: none; color: var(--v-text); padding: 9px 10px; border-radius: 9px;
  cursor: pointer; font-family: var(--v-font); text-align: left;
}
#gpw-ev-menu button:hover { background: var(--v-panel-2); }
#gpw-ev-menu .ev-ava { width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-weight: 700; font-size: 0.82rem; color: #fff;
  background: linear-gradient(135deg, var(--v-primary), var(--v-primary-700)); }
#gpw-ev-menu .ev-name { font-weight: 600; font-size: 0.9rem; }
#gpw-ev-menu .ev-sub { color: var(--v-muted); font-size: 0.76rem; }

/* Banner shown while an admin is viewing as an employee */
#gpw-imp-banner {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px;
  margin: 0 4px; padding: 6px 12px; border-radius: 10px;
  background: var(--v-warn-soft, rgba(234,179,8,0.14));
  border: 1px solid var(--v-warn, #eab308); color: var(--v-text);
}
#gpw-imp-banner .imp-eye { font-size: 1rem; }
#gpw-imp-banner .imp-text { font-size: 0.82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#gpw-imp-banner .imp-exit {
  margin-left: auto; flex: none; background: var(--v-text); color: var(--v-bg);
  border: none; border-radius: 8px; padding: 6px 11px; font-size: 0.8rem;
  font-weight: 700; cursor: pointer; font-family: var(--v-font); white-space: nowrap;
}
#gpw-imp-banner .imp-exit:hover { opacity: 0.88; }
@media (max-width: 767px) {
  .gpw-ev-btn span, .gpw-ev-btn { font-size: 0.78rem; }
  #gpw-imp-banner .imp-text b { font-weight: 700; }
  /* Tighten the banner and let its text ellipsize so the exit button can never
     be pushed over the bell/theme/avatar icons. */
  #gpw-imp-banner { gap: 6px; padding: 5px 8px; margin: 0 2px; }
  #gpw-imp-banner .imp-text { min-width: 0; }
  #gpw-imp-banner .imp-exit { padding: 6px 9px; }
}
/* Very narrow phones: collapse the exit button to just its ↩ icon (title still
   reads "Back to my admin") so the whole topbar fits without overlap. */
@media (max-width: 600px) {
  #gpw-imp-banner .imp-exit-label { display: none; }
}

/* ============================================================================
   Reusable components (v-namespaced)
   ========================================================================== */
.v-card { background: var(--v-panel); border: 1px solid var(--v-line); border-radius: var(--v-radius); box-shadow: var(--v-shadow-sm); }
.v-card-pad { padding: 1.25rem 1.35rem; }
.v-card-head { display: flex; align-items: center; gap: 0.6rem; padding: 1rem 1.35rem; border-bottom: 1px solid var(--v-line-soft); font-weight: 700; }

.v-grid { display: grid; gap: 1rem; }
.v-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.v-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.v-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.v-grid.cols-5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 900px) { .v-grid.cols-3, .v-grid.cols-4, .v-grid.cols-5 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .v-grid.cols-2, .v-grid.cols-3, .v-grid.cols-4, .v-grid.cols-5 { grid-template-columns: 1fr; } }

/* Stat tile */
.v-stat { background: var(--v-panel); border: 1px solid var(--v-line); border-radius: var(--v-radius); padding: 1.1rem 1.2rem; position: relative; overflow: hidden; }
.v-stat::after { content: ''; position: absolute; inset: 0 0 auto auto; width: 70px; height: 70px; background: radial-gradient(circle at top right, rgba(139,92,246,0.18), transparent 70%); }
.v-stat .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.07em; color: var(--v-muted); font-weight: 700; }
.v-stat .value { font-size: 1.7rem; font-weight: 800; letter-spacing: -0.02em; margin-top: 0.3rem; }
.v-stat .delta { font-size: 0.78rem; margin-top: 0.2rem; color: var(--v-accent-2); }

/* Buttons */
.v-btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 0.6rem 1.05rem; border: 1px solid transparent; border-radius: var(--v-radius-sm); font-size: 0.86rem; font-weight: 700; font-family: var(--v-font); cursor: pointer; transition: transform var(--v-ease), background var(--v-ease), border-color var(--v-ease); text-decoration: none; white-space: nowrap; }
.v-btn:active { transform: translateY(1px); }
.v-btn:disabled { opacity: 0.55; cursor: not-allowed; }
.v-btn-primary { background: linear-gradient(135deg, var(--v-primary), var(--v-primary-700)); color: #fff; box-shadow: 0 6px 16px rgba(124,58,237,0.4); }
.v-btn-primary:hover:not(:disabled) { box-shadow: 0 9px 22px rgba(124,58,237,0.55); }
.v-btn-ghost { background: var(--v-panel); color: var(--v-text); border-color: var(--v-line); }
.v-btn-ghost:hover:not(:disabled) { background: var(--v-panel-2); border-color: var(--v-primary); }
.v-btn-accent { background: linear-gradient(135deg, var(--v-accent), #059669); color: #fff; }
.v-btn-danger { background: var(--v-danger-soft); color: var(--v-danger); border-color: transparent; }
.v-btn-danger:hover:not(:disabled) { background: #4a1f2c; }
.v-btn-sm { padding: 0.4rem 0.75rem; font-size: 0.8rem; }

/* Badges / pills */
.v-badge { display: inline-flex; align-items: center; gap: 5px; font-size: 0.72rem; font-weight: 700; padding: 0.24rem 0.6rem; border-radius: 999px; background: var(--v-panel-2); color: var(--v-text-2); white-space: nowrap; }
.v-badge.violet { background: var(--v-primary-soft); color: var(--v-on-soft); }
.v-badge.green  { background: var(--v-accent-soft); color: var(--v-accent-2); }
.v-badge.red    { background: var(--v-danger-soft); color: var(--v-danger); }
.v-badge.gray   { background: var(--v-panel-2); color: var(--v-muted); }
.v-badge .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* Forms */
.v-field { margin-bottom: 0.95rem; }
.v-field label { display: block; font-size: 0.78rem; font-weight: 700; color: var(--v-text-2); margin-bottom: 0.35rem; }
.v-field .hint { font-size: 0.74rem; color: var(--v-muted); margin-top: 0.3rem; }
.v-input, .v-select, .v-textarea {
  width: 100%; padding: 0.62rem 0.8rem; border-radius: var(--v-radius-sm);
  border: 1px solid var(--v-line); background: var(--v-bg-2); color: var(--v-text);
  font-size: 0.9rem; font-family: var(--v-font); transition: border-color var(--v-ease), box-shadow var(--v-ease);
}
.v-input::placeholder, .v-textarea::placeholder { color: #6b6488; }
.v-input:focus, .v-select:focus, .v-textarea:focus { outline: none; border-color: var(--v-primary); box-shadow: var(--v-ring); }
.v-textarea { min-height: 88px; resize: vertical; }
.v-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.8rem; }
.v-field-row.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
.v-input:disabled, .v-select:disabled { opacity: 0.6; cursor: not-allowed; background: var(--v-panel-2); }

/* Field label with a right-aligned inline action (e.g. "Edit list") */
.v-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.35rem; }
.v-label-row label { margin-bottom: 0; }
.v-linkbtn { background: none; border: none; padding: 0; cursor: pointer; font-family: var(--v-font); font-size: 0.72rem; font-weight: 700; color: var(--v-primary); }
.v-linkbtn:hover { text-decoration: underline; }

/* Inline "add a new option" row shown beneath a <select> */
.v-addrow { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.45rem; }
.v-addrow[hidden] { display: none; }  /* a class `display` otherwise defeats the [hidden] attribute */
.v-addrow .v-input { flex: 1 1 100%; }

/* Lead-source manager: a list of name inputs + reorder / remove controls */
.ls-list { display: flex; flex-direction: column; gap: 0.45rem; margin-bottom: 0.7rem; }
.ls-row { display: flex; align-items: center; gap: 0.4rem; }
.ls-row .ls-name { flex: 1; }
.ls-icon { flex: 0 0 auto; width: 32px; height: 34px; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--v-radius-sm); border: 1px solid var(--v-line); background: var(--v-panel-2); color: var(--v-text-2); cursor: pointer; font-size: 0.95rem; line-height: 1; transition: border-color var(--v-ease), color var(--v-ease), background var(--v-ease); }
.ls-icon:hover:not(:disabled) { border-color: var(--v-primary); color: var(--v-text); }
.ls-icon:disabled { opacity: 0.4; cursor: not-allowed; }
.ls-del:hover:not(:disabled) { border-color: var(--v-danger); color: var(--v-danger); background: var(--v-danger-soft); }
.ls-addrow { display: flex; gap: 0.5rem; align-items: center; padding-top: 0.7rem; border-top: 1px solid var(--v-line-soft); }
.ls-addrow .v-input { flex: 1; }
@media (max-width: 520px) { .v-field-row, .v-field-row.cols-3 { grid-template-columns: 1fr; } }

/* Table */
.v-table { width: 100%; border-collapse: collapse; font-size: 0.87rem; }
.v-table th { text-align: left; padding: 0.6rem 0.8rem; font-size: 0.68rem; font-weight: 800; color: var(--v-muted); text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--v-line); }
.v-table td { padding: 0.72rem 0.8rem; border-bottom: 1px solid var(--v-line-soft); color: var(--v-text-2); vertical-align: middle; }
.v-table tbody tr { transition: background var(--v-ease); cursor: default; }
.v-table tbody tr:hover td { background: rgba(139,92,246,0.06); }
.v-table td .strong { color: var(--v-text); font-weight: 600; }

/* Empty state */
.v-empty { text-align: center; padding: 3rem 1.5rem; color: var(--v-muted); }
.v-empty .em-ic { font-size: 2.2rem; opacity: 0.5; }
.v-empty .em-title { color: var(--v-text-2); font-weight: 700; margin-top: 0.6rem; }
.v-empty .em-sub { font-size: 0.85rem; margin-top: 0.3rem; }

/* ── Modal / drawer ────────────────────────────────────────────────────────── */
/* ⚠️ A CLOSED backdrop is opacity:0 but still full-screen at z-index 10000. It MUST keep
   pointer-events:none (and .open MUST set pointer-events:auto), or it becomes an invisible
   click-trap over the whole page — nothing is clickable and the cursor shows the default
   arrow. Clients & Schedule keep a backdrop always in the DOM, so they broke this way once
   (2026-07-29). Keep pointer-events paired with opacity on BOTH rules below. */
.v-modal-backdrop { position: fixed; inset: 0; z-index: 10000; background: rgba(5,4,12,0.6); backdrop-filter: blur(3px); display: flex; align-items: flex-start; justify-content: center; padding: 5vh 1rem 1rem; opacity: 0; pointer-events: none; transition: opacity var(--v-ease); overflow-y: auto; }
.v-modal-backdrop.open { opacity: 1; pointer-events: auto; }
/* The lead-source manager can be launched from inside a page's own modal (e.g. the
   Leads editor at z-index 20000), so it floats above everything when stacked. */
.v-modal-backdrop.v-modal-top { z-index: 30000; }
.v-modal { width: 100%; max-width: 540px; background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 18px; box-shadow: var(--v-shadow); transform: translateY(12px) scale(0.98); transition: transform var(--v-ease); }
.v-modal-backdrop.open .v-modal { transform: none; }
.v-modal-head { display: flex; align-items: center; gap: 0.7rem; padding: 1.1rem 1.3rem; border-bottom: 1px solid var(--v-line-soft); }
.v-modal-head h3 { font-size: 1.05rem; font-weight: 800; flex: 1; }
.v-modal-head .close { background: none; border: none; color: var(--v-muted); font-size: 1.4rem; cursor: pointer; line-height: 1; padding: 2px 6px; border-radius: 8px; }
.v-modal-head .close:hover { background: var(--v-panel-2); color: var(--v-text); }
.v-modal-body { padding: 1.2rem 1.3rem; }
.v-modal-foot { display: flex; justify-content: flex-end; gap: 0.6rem; padding: 1rem 1.3rem; border-top: 1px solid var(--v-line-soft); }

/* Combobox (client picker) */
.v-combo { position: relative; }
.v-combo-list { position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 10px; box-shadow: var(--v-shadow); max-height: 220px; overflow-y: auto; z-index: 20; display: none; }
.v-combo-list.open { display: block; }
.v-combo-list button { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--v-text); padding: 9px 12px; cursor: pointer; font-size: 0.86rem; font-family: var(--v-font); border-bottom: 1px solid var(--v-line-soft); }
.v-combo-list button:hover { background: var(--v-panel-2); }
.v-combo-list .cl-meta { color: var(--v-muted); font-size: 0.76rem; }

/* Toast */
#gpw-toasts { position: fixed; bottom: 20px; right: 20px; z-index: 11000; display: flex; flex-direction: column; gap: 10px; }
@media (max-width: 899px) { #gpw-toasts { bottom: 92px; left: 16px; right: 16px; } }
.v-toast { background: var(--v-panel); border: 1px solid var(--v-line); border-left: 4px solid var(--v-primary); border-radius: 12px; padding: 0.8rem 1rem; box-shadow: var(--v-shadow); color: var(--v-text); font-size: 0.87rem; min-width: 240px; max-width: 360px; animation: v-toast-in var(--v-ease); }
.v-toast.ok { border-left-color: var(--v-accent); }
.v-toast.err { border-left-color: var(--v-danger); }
.v-toast .t-title { font-weight: 700; }
.v-toast .t-sub { color: var(--v-muted); font-size: 0.8rem; margin-top: 2px; }
@keyframes v-toast-in { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: none; } }

/* Utilities */
/* Wrap by default so button rows never overflow / overlap at any width. */
.v-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.v-row.nowrap { flex-wrap: nowrap; }
.v-row.wrap { flex-wrap: wrap; }
.v-spacer { flex: 1; }
.v-muted { color: var(--v-muted); }
.v-mt { margin-top: 1rem; } .v-mb { margin-bottom: 1rem; }

/* ============================================================================
   Light-background themes  (day mode — pick from the topbar 🎨 menu)
   Shared light base for all five palettes, then per-theme brand + canvas.
   The sidebar/topbar/content all go light; brand accent varies per theme.
   ========================================================================== */
:root[data-theme="light"],
:root[data-theme="mint"],
:root[data-theme="sky"],
:root[data-theme="rose"],
:root[data-theme="sand"] {
  --v-bg-2:      #ffffff;
  --v-panel:     #ffffff;
  --v-panel-2:   #f3f0fb;
  --v-line:      rgba(60,40,110,0.12);
  --v-line-soft: rgba(60,40,110,0.07);
  --v-text:      #241a3d;
  --v-text-2:    #4c4370;
  --v-muted:     #6c628c;
  --v-text-strong: #140a26;
  --v-on-soft:     #4c1d95;   /* the soft pills go pale in day mode, so this goes dark */
  --v-link:        var(--v-primary-600);   /* each theme's deeper brand shade reads on white */
  --v-danger:      #e11d48;
  --v-danger-soft: #fbe9ef;
  --v-warn:        #b45309;
  --v-info:        #2563eb;
  --v-shadow:    0 10px 30px rgba(30,20,60,0.10);
  --v-shadow-sm: 0 3px 12px rgba(30,20,60,0.07);
  --v-sidebar-bg:   linear-gradient(180deg, #ffffff 0%, #f6f3fc 100%);
  --v-topbar-bg:    rgba(255,255,255,0.82);
  --v-hover:        rgba(60,40,110,0.05);
  --v-hover-strong: rgba(60,40,110,0.07);
  --v-scroll:       #d3cbe8;
  --v-scroll-hover: #bcb1dd;
  color-scheme: light;
}

/* Snow — clean white + violet */
:root[data-theme="light"] {
  --v-bg: #fbfaff;
  --v-primary: #7c3aed; --v-primary-600: #6d28d9; --v-primary-700: #5b21b6;
  --v-primary-soft: #efeafc;
  --v-accent: #059669; --v-accent-2: #047857; --v-accent-soft: #e7f7f0;
  --v-ring: 0 0 0 3px rgba(124,58,237,0.25);
}
/* Mint — white + emerald */
:root[data-theme="mint"] {
  --v-bg: #f4fbf7;
  --v-primary: #059669; --v-primary-600: #047857; --v-primary-700: #065f46;
  --v-primary-soft: #e2f5ec;
  --v-accent: #6366f1; --v-accent-2: #4f46e5; --v-accent-soft: #e9e9fb;
  --v-ring: 0 0 0 3px rgba(5,150,105,0.25);
}
/* Sky — white + indigo/blue */
:root[data-theme="sky"] {
  --v-bg: #f3f6ff;
  --v-primary: #4f46e5; --v-primary-600: #4338ca; --v-primary-700: #3730a3;
  --v-primary-soft: #e7e9fc;
  --v-accent: #0891b2; --v-accent-2: #0e7490; --v-accent-soft: #e2f4f8;
  --v-ring: 0 0 0 3px rgba(79,70,229,0.25);
}
/* Rose — white + rose/pink */
:root[data-theme="rose"] {
  --v-bg: #fff5f8;
  --v-primary: #e11d48; --v-primary-600: #be123c; --v-primary-700: #9f1239;
  --v-primary-soft: #fbe4ec;
  --v-accent: #7c3aed; --v-accent-2: #6d28d9; --v-accent-soft: #efeafc;
  --v-ring: 0 0 0 3px rgba(225,29,72,0.22);
}
/* Sand — warm cream + amber */
:root[data-theme="sand"] {
  --v-bg: #faf6ee;
  --v-panel: #fffdf9; --v-panel-2: #f3ecdd;
  --v-line: rgba(120,80,20,0.14); --v-line-soft: rgba(120,80,20,0.08);
  --v-sidebar-bg: linear-gradient(180deg, #fffdf9 0%, #f5eede 100%);
  --v-primary: #b45309; --v-primary-600: #92400e; --v-primary-700: #78350f;
  --v-primary-soft: #f5e8d3;
  --v-accent: #059669; --v-accent-2: #047857; --v-accent-soft: #e5f4ed;
  --v-ring: 0 0 0 3px rgba(180,83,9,0.22);
}

/* Day mode: flat white canvas — drop the purple/green radial glow. */
:root[data-theme="light"] body.gpw-has-shell,
:root[data-theme="mint"]  body.gpw-has-shell,
:root[data-theme="sky"]   body.gpw-has-shell,
:root[data-theme="rose"]  body.gpw-has-shell,
:root[data-theme="sand"]  body.gpw-has-shell { background: var(--v-bg); }

/* ── Topbar theme picker (🎨) ─────────────────────────────────────────────── */
#gpw-theme-wrap { position: relative; }
.gpw-icon-btn {
  /* padding:0 is load-bearing. The quote calculator sets a blanket
     `button { padding: 11px 24px }`, which leaked into the shell's own topbar
     buttons: 48px of padding inside a 34px-wide box left no room at all, so the
     bell and palette icons spilled 18px outside their own button. The shell has
     to be immune to whatever a page does to bare elements. */
  width: 34px; height: 34px; padding: 0; display: grid; place-items: center;
  background: none; border: 1px solid transparent; border-radius: 9px;
  color: var(--v-text-2); font-size: 1rem; cursor: pointer; line-height: 1;
  transition: background var(--v-ease), border-color var(--v-ease);
}
.gpw-icon-btn:hover { background: var(--v-hover-strong); border-color: var(--v-line); }
.gpw-icon-btn:focus-visible { outline: none; box-shadow: var(--v-ring); }

/* Visually-hidden but still reachable by screen readers — for real <label>s on
   fields that are only visually labelled by a placeholder today. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
#gpw-theme-menu {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 184px;
  background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 14px;
  box-shadow: var(--v-shadow); padding: 6px; display: none; z-index: 9600;
}
#gpw-theme-menu.open { display: block; }
#gpw-theme-menu .tm-head {
  font-size: 0.62rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--v-muted); padding: 8px 8px 4px;
}
.gpw-tm-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: none; padding: 8px 8px; border-radius: 9px;
  color: var(--v-text); font-size: 0.86rem; font-weight: 600; font-family: var(--v-font);
  cursor: pointer; text-align: left; transition: background var(--v-ease);
}
.gpw-tm-item:hover { background: var(--v-panel-2); }
.gpw-tm-item.active { background: var(--v-primary-soft); color: var(--v-text-strong); }
.gpw-tm-swatch { width: 20px; height: 20px; border-radius: 6px; flex: none; border: 1px solid rgba(120,120,140,0.3); }
.gpw-tm-item .tm-check { margin-left: auto; color: var(--v-primary); font-weight: 800; opacity: 0; }
.gpw-tm-item.active .tm-check { opacity: 1; }

/* ── Invoice line-item editor (shared "New invoice" modal in nav.js) ──────── */
.inv-lines-head,
.inv-line { display: grid; grid-template-columns: 1fr 56px 84px 74px 26px; gap: 0.4rem; align-items: center; }
.inv-lines-head { margin-bottom: 0.35rem; font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; color: var(--v-muted); }
.inv-lines-head span:nth-child(2), .inv-lines-head span:nth-child(3), .inv-lines-head span:nth-child(4) { text-align: right; }
.inv-line { margin-bottom: 0.4rem; }
.inv-line .v-input { padding: 0.5rem 0.55rem; }
.inv-line .inv-qty, .inv-line .inv-price { text-align: right; }
.inv-amt { font-variant-numeric: tabular-nums; font-weight: 700; text-align: right; color: var(--v-text-2); font-size: 0.85rem; }
.inv-del { border: none; background: transparent; color: var(--v-muted); font-size: 1.25rem; line-height: 1; cursor: pointer; border-radius: 6px; padding: 0 0.2rem; }
.inv-del:hover { color: var(--v-danger); background: var(--v-danger-soft); }
.inv-totals { margin: 0.7rem 0 0.2rem; }
.inv-trow { display: flex; justify-content: space-between; font-size: 0.9rem; color: var(--v-text-2); padding: 0.16rem 0; }
.inv-trow.inv-total { font-size: 1.08rem; font-weight: 800; color: var(--v-text); border-top: 1px solid var(--v-line); margin-top: 0.35rem; padding-top: 0.45rem; }
.inv-trow.inv-total span:last-child { color: var(--v-primary); }

/* ══ Charts ═══════════════════════════════════════════════════════════════════
   Design tokens + shared chrome for public/charts.js. The renderer draws SVG and
   never hardcodes a colour — everything below is what it reads.

   THE PALETTE IS FIXED ACROSS THEMES, on purpose. The theme picker restyles the
   chrome; it must not restyle the DATA. If "Meta" is pink on Snow and violet on
   Mint, every chart Grant has learned to read breaks the moment he changes theme.
   The one thing that swaps is the light/dark STEP of each hue, because a colour
   that reads on white is not the same colour that reads on #14112a.

   Both step sets were validated with the dataviz palette checker (six checks:
   lightness band, chroma floor, adjacent CVD separation, normal-vision floor,
   contrast vs surface) and pass in both modes — worst adjacent pair ΔE 10.1
   deutan / 20.5 normal on light, 13.4 / 22.6 on dark, all slots ≥3:1 against
   their surface. Do not "tidy" these hexes without re-running that checker.
   ────────────────────────────────────────────────────────────────────────────── */
:root {
  /* Categorical — for telling series APART (lead sources, new vs repeat).
     Assigned in fixed slot order and never cycled; a 6th+ series folds into
     "Other" rather than inventing a hue nobody can distinguish. Dark steps. */
  --v-chart-1: #8b5cf6;   /* violet  — also the single-series default */
  --v-chart-2: #0d9668;   /* emerald */
  --v-chart-3: #3b82f6;   /* blue    */
  --v-chart-4: #ec4899;   /* pink    */
  --v-chart-5: #b8800a;   /* gold    */
  --v-chart-6: #0d9cb5;   /* cyan    */
  --v-chart-other: #6b6a86;   /* the folded tail, and de-emphasised context */

  /* Magnitude — one hue, more-is-darker. Used when bars are ranked, where a
     second hue would double-encode length and say nothing new. */
  --v-chart-seq:      #8b5cf6;
  --v-chart-seq-soft: rgba(139,92,246,0.20);

  /* Polarity — profit above the line vs a loss below it. */
  --v-chart-pos: #10b981;
  --v-chart-neg: #fb7185;

  /* Chrome. Grid and axes sit one shade off the surface and stay there — a
     gridline you notice is a gridline competing with the data. */
  --v-chart-grid:    rgba(255,255,255,0.07);
  --v-chart-axis:    rgba(255,255,255,0.14);
  /* Reference lines (the $50k/month goal, a chart's average) are deliberately a
   NEUTRAL, not a hue. Every hue on these charts already means something — violet
   is data, green/red are profit and loss, and the brand carries no orange — so an
   amber "target" line would read as a fifth series. Weight and a bold label are
   what separate it from a gridline, not colour. */
--v-chart-goal:    #a8a3c4;
  --v-chart-surface: var(--v-panel);
}
:root[data-theme="light"],
:root[data-theme="mint"],
:root[data-theme="sky"],
:root[data-theme="rose"],
:root[data-theme="sand"] {
  --v-chart-1: #7c3aed;
  --v-chart-2: #059669;
  --v-chart-3: #2563eb;
  --v-chart-4: #db2777;
  --v-chart-5: #a16207;
  --v-chart-6: #0891b2;
  --v-chart-other: #8b8aa3;
  --v-chart-seq:      #7c3aed;
  --v-chart-seq-soft: rgba(124,58,237,0.16);
  --v-chart-pos: #059669;
  --v-chart-neg: #e11d48;
  --v-chart-grid: rgba(60,40,110,0.10);
  --v-chart-axis: rgba(60,40,110,0.20);
  --v-chart-goal: #6c628c;
}

/* ── Card ─────────────────────────────────────────────────────────────────── */
.v-chart { position: relative; }
.v-chart-head { display: flex; align-items: flex-start; gap: 0.8rem; margin-bottom: 0.15rem; }
.v-chart-titles { flex: 1; min-width: 0; }
.v-chart-title { font-size: 0.95rem; font-weight: 800; color: var(--v-text); line-height: 1.3; }
.v-chart-sub { font-size: 0.78rem; color: var(--v-muted); line-height: 1.45; margin-top: 0.2rem; }
.v-chart-sub b { color: var(--v-text-2); font-weight: 700; }
/* The table-view toggle. Never the only way to read a value — it's the WCAG-clean
   twin of the plot, for anyone the colours don't work for. */
.v-chart-toggle { flex: none; background: none; border: 1px solid var(--v-line); color: var(--v-muted);
  border-radius: 8px; padding: 0.3rem 0.55rem; font-size: 0.72rem; font-weight: 700; cursor: pointer;
  font-family: var(--v-font); white-space: nowrap; }
.v-chart-toggle:hover { background: var(--v-panel-2); color: var(--v-text); }

/* ── Plot ─────────────────────────────────────────────────────────────────── */
/* Height is set on the SVG's viewBox and the container grows to fit — a fixed
   container height is what crops x-axis labels into a nested scrollbar. */
.v-chart-plot { position: relative; margin-top: 0.7rem; }
/* NO width:100% / height:auto here. charts.js emits a viewBox that already matches
   the container in CSS pixels, so the SVG must render 1:1 — scaling it would blow
   up every 10.5px label along with the drawing. max-width guards the one frame
   where a re-render hasn't caught up with a shrink. */
.v-chart-plot svg { display: block; max-width: 100%; overflow: visible; }
.v-chart-plot.is-stale { opacity: 0.45; transition: opacity var(--v-ease); }   /* refetch: hold, don't flash */
.vc-grid    { stroke: var(--v-chart-grid); stroke-width: 1; shape-rendering: crispEdges; }
.vc-axis    { stroke: var(--v-chart-axis); stroke-width: 1; shape-rendering: crispEdges; }
.vc-tick    { fill: var(--v-muted); font-size: 10.5px; font-family: var(--v-font); font-variant-numeric: tabular-nums; }
.vc-tick-y  { text-anchor: end; }
/* Values and labels wear TEXT tokens, never the series colour — the mark beside
   them already carries the identity, and coloured text just reads as low-contrast. */
.vc-val     { fill: var(--v-text-2); font-size: 10.5px; font-weight: 700; font-family: var(--v-font); text-anchor: middle; }
/* Alignment modifiers, as CLASSES rather than text-anchor="" attributes on the
   element: a presentation attribute loses to any CSS rule, so `.vc-val`'s
   text-anchor:middle silently overrode every attribute and pushed horizontal-bar
   value labels back over their own bars. */
.vc-val.vc-s { text-anchor: start; }
.vc-val.vc-e { text-anchor: end; }
.vc-val-in  { fill: #fff; font-size: 10.5px; font-weight: 700; font-family: var(--v-font); }
.vc-name    { fill: var(--v-text); font-size: 11.5px; font-weight: 600; font-family: var(--v-font); }
.vc-goal    { stroke: var(--v-chart-goal); stroke-width: 1.5; opacity: 0.75; }
.vc-goal-lb { fill: var(--v-chart-goal); font-size: 10px; font-weight: 800; font-family: var(--v-font); }
.vc-bar     { transition: opacity var(--v-ease); }
.vc-line    { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.vc-dot     { stroke: var(--v-chart-surface); stroke-width: 2; }   /* 2px surface ring, not a border */
.vc-hit     { fill: transparent; cursor: pointer; }                /* generous hit area over thin marks */
.v-chart-plot g.vc-dim .vc-bar,
.v-chart-plot g.vc-dim .vc-line { opacity: 0.32; }

/* ── Legend ───────────────────────────────────────────────────────────────── */
/* Always present for 2+ series, so identity is never carried by colour alone. */
.v-chart-legend { display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; margin-top: 0.7rem; }
.vc-key { display: inline-flex; align-items: center; gap: 0.38rem; font-size: 0.76rem; font-weight: 600;
  color: var(--v-text-2); cursor: default; }
.vc-key i { width: 10px; height: 10px; border-radius: 3px; flex: none; display: inline-block; }
.vc-key.vc-key-line i { height: 3px; border-radius: 2px; width: 14px; }

/* ── Tooltip ──────────────────────────────────────────────────────────────── */
.v-chart-tip { position: absolute; z-index: 40; pointer-events: none; opacity: 0; transform: translate(-50%, -108%);
  background: var(--v-panel-2); border: 1px solid var(--v-line); border-radius: 9px; padding: 0.5rem 0.65rem;
  box-shadow: var(--v-shadow-sm); font-size: 0.78rem; color: var(--v-text); white-space: nowrap;
  transition: opacity 0.1s; min-width: 0; }
.v-chart-tip.on { opacity: 1; }
.vc-tip-h { font-weight: 800; margin-bottom: 0.2rem; }
.vc-tip-r { display: flex; align-items: center; gap: 0.4rem; color: var(--v-text-2); line-height: 1.55; }
.vc-tip-r i { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.vc-tip-r b { color: var(--v-text); font-variant-numeric: tabular-nums; margin-left: auto; padding-left: 0.7rem; }

/* ── Table view ───────────────────────────────────────────────────────────── */
.v-chart-table { margin-top: 0.7rem; max-height: 340px; overflow: auto; }
.v-chart-table table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.v-chart-table th { text-align: left; font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--v-muted); font-weight: 800; padding: 0.35rem 0.5rem; border-bottom: 1px solid var(--v-line);
  position: sticky; top: 0; background: var(--v-panel); }
.v-chart-table td { padding: 0.35rem 0.5rem; border-bottom: 1px solid var(--v-line-soft); color: var(--v-text-2); }
.v-chart-table td.num { text-align: right; font-variant-numeric: tabular-nums; color: var(--v-text); }
.v-chart-table tr:last-child td { border-bottom: none; }

/* ── States ───────────────────────────────────────────────────────────────── */
/* "Nothing happened yet" and "the query broke" must never look the same. */
.v-chart-empty, .v-chart-err { padding: 2.2rem 1rem; text-align: center; font-size: 0.85rem; line-height: 1.6; }
.v-chart-empty { color: var(--v-muted); }
.v-chart-err { color: var(--v-danger); }
.v-chart-err button { margin-top: 0.6rem; }
.v-chart-skel { height: 150px; border-radius: 10px; background: var(--v-panel-2); animation: vc-pulse 1.4s ease-in-out infinite; }
@keyframes vc-pulse { 0%,100% { opacity: 0.45; } 50% { opacity: 0.8; } }

/* ── Layout ───────────────────────────────────────────────────────────────── */
/* align-items:start, not the default stretch. A three-stage funnel next to a
   twelve-month column chart would otherwise be stretched to match it and sit in
   half a card of empty white. Cards size to their own content. */
.v-chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 1rem; align-items: start; }
.v-chart-grid > .v-card { min-width: 0; }
.v-chart-wide { grid-column: 1 / -1; }
@media (max-width: 640px) {
  .v-chart-grid { grid-template-columns: 1fr; }
  .vc-tick { font-size: 9.5px; }
  .vc-val  { font-size: 9.5px; }
}
@media (prefers-reduced-motion: reduce) {
  .vc-bar, .v-chart-plot, .v-chart-tip { transition: none; }
  .v-chart-skel { animation: none; }
}

/* ── Service map (public/mapview.js) ─────────────────────────────────────────
   The tiles are light-mode raster imagery from OpenStreetMap, so Midnight
   inverts them rather than sitting a bright rectangle in a dark app. Hue-rotate
   puts the greens and blues back after the inversion flips them; the rest just
   takes the glare off. The five day themes leave the imagery alone.
   Pin colour comes from the chart palette, NOT a new pair of hex values — those
   two steps are already validated against both grounds and for colour blindness. */
:root { --v-map-filter: invert(1) hue-rotate(180deg) saturate(0.55) brightness(0.97) contrast(0.94); }
:root[data-theme="light"], :root[data-theme="mint"], :root[data-theme="sky"],
:root[data-theme="rose"],  :root[data-theme="sand"] { --v-map-filter: none; }

.dmap { position: relative; overflow: hidden; border-radius: var(--v-radius); background: var(--v-panel-2);
        border: 1px solid var(--v-line); cursor: grab; touch-action: none; user-select: none; }
.dmap.dragging { cursor: grabbing; }
.dmap-tiles { position: absolute; inset: 0; filter: var(--v-map-filter); }
.dmap-tiles img { position: absolute; top: 0; left: 0; display: block; will-change: transform; }
.dmap-pins { position: absolute; inset: 0; }

.dmap-pin { position: absolute; top: 0; left: 0; padding: 0; border-radius: 50%; cursor: pointer;
            background: var(--v-chart-1); border: 2px solid var(--v-panel);
            box-shadow: 0 1px 5px rgba(20,10,40,0.45); transition: background var(--v-ease); }
.dmap-pin.unpriced { background: var(--v-chart-2); }
.dmap-pin:hover { background: var(--v-primary-600); z-index: 4; }
.dmap-pin.unpriced:hover { background: var(--v-chart-2); }
.dmap-pin.sel { z-index: 6; box-shadow: 0 0 0 3px var(--v-panel), 0 0 0 6px var(--v-chart-1), 0 4px 14px rgba(20,10,40,0.5); }
.dmap-pin.unpriced.sel { box-shadow: 0 0 0 3px var(--v-panel), 0 0 0 6px var(--v-chart-2), 0 4px 14px rgba(20,10,40,0.5); }
.dmap-pin:focus-visible { outline: none; box-shadow: var(--v-ring); }

.dmap-zoom { position: absolute; right: 10px; bottom: 26px; z-index: 5; display: flex; flex-direction: column;
             gap: 1px; background: var(--v-line); border: 1px solid var(--v-line);
             border-radius: 11px; overflow: hidden; box-shadow: var(--v-shadow-sm); }
.dmap-zoom button { width: 34px; height: 32px; border: none; cursor: pointer; background: var(--v-panel);
                    color: var(--v-text-2); font-size: 15px; font-family: var(--v-font); line-height: 1; }
.dmap-zoom button:hover { background: var(--v-panel-2); color: var(--v-text); }
.dmap-zoom button.fit { font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; height: 28px; }

.dmap-attr { position: absolute; right: 6px; bottom: 4px; z-index: 5; font-size: 0.62rem;
             color: var(--v-muted); background: var(--v-panel); padding: 1px 6px; border-radius: 6px;
             border: 1px solid var(--v-line-soft); opacity: 0.9; }
.dmap-attr a { color: inherit; }

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

/* ============================================================================
   Mobile hardening — phones (≤ 767px)
   One shared safety net so no page can break the viewport on a phone. app.css
   is injected after each page's own <style>, so these win on equal specificity.
   Everything here is scoped to phone widths; desktop/tablet layout is untouched.
   Wide content (data tables, code) is given its own scroll box elsewhere, so
   the overflow guard below only ever clips accidental overflow — never content.
   ========================================================================== */

/* Drop-in horizontal scrollers for any wide block (data tables especially).
   `.tbl-wrap` is defined per-page on some pages and — critically — NOT on others
   (e.g. financials wrapped its tables in .tbl-wrap but never styled it, so a wide
   table there escaped its card on a phone). Defining both here, once, means the
   wrapper always scrolls, whether or not the page also declares it. Identical
   behaviour to the per-page copies, so those still win harmlessly on tie. */
.v-scroll-x, .tbl-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }

@media (max-width: 767px) {
  /* The page itself never scrolls sideways. overflow-x lives on <html> so the
     viewport stays the vertical scroller and position:sticky keeps working.
     Intentional horizontal scrollers (kanban board, calendar strip, settings
     rail) have their own overflow box, so they still scroll inside themselves. */
  html { overflow-x: hidden; }

  /* Media and embeds stay inside their column instead of forcing width. */
  img, video, iframe { max-width: 100%; }
  img, video { height: auto; }

  /* Form controls count their own padding/border inside width:100% (no global
     border-box reset exists), otherwise a full-width search box overflows its
     card by its padding and drags the page sideways (Clients, Pipeline). */
  input, select, textarea { box-sizing: border-box; max-width: 100%; }

  /* Long unbreakable strings (emails, URLs, references, addresses, file names)
     wrap instead of pushing panels wider than the screen. Only breaks a token
     when there's no other break opportunity, so normal text is unaffected. */
  .v-card, .v-modal, .v-table td, .panel, .wrap, .log-table td {
    overflow-wrap: break-word;
  }

  /* NOTE: data tables are kept inside a scroll wrapper per-page (.tbl-wrap /
     .v-scroll-x) so they scroll horizontally within their card instead of
     forcing the page wide. The html overflow-x guard above is the backstop. */

  /* Topbar: tighten the gaps so the icon cluster (Employee-View eye · bell ·
     theme · avatar) never overlaps on a narrow phone, and let the icon buttons
     shrink a touch. The avatar keeps the name hidden (already handled ≤1040). */
  #gpw-topbar { gap: 6px; padding: 0 10px; }
  #gpw-topbar .tb-right { gap: 6px; }
  #gpw-topbar .gpw-icon-btn { padding: 6px 7px; }
  #gpw-topbar button.tb-user { padding: 4px 4px 4px 4px; }

  /* Any flex row of buttons/actions wraps rather than overlapping. Page toolbars
     opt in with .v-row (already wraps); this catches the common ad-hoc header. */
  .v-page-head { gap: 0.6rem; }
}

/* ============================================================================
   Calendar widget (GPWCalendar) — shared by the Schedule page and the admin +
   technician home pages. A soft dot/pill month where each job wears its own
   colour, matched to its card in the day list below. See public/calendar.js.
   ========================================================================== */
.mc-card { background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 22px; padding: 1rem 0.7rem 1.1rem; }
.mc-dow { display: grid; grid-template-columns: repeat(7,1fr); margin-bottom: 4px; }
.mc-dow span { text-align: center; font-size: 0.72rem; font-weight: 800; color: var(--v-muted); }
.mc-week { position: relative; display: grid; grid-template-columns: repeat(7,1fr); }
.mc-pill { position: absolute; top: 7px; height: 40px; z-index: 0; }
.mc-day { position: relative; z-index: 1; min-height: 55px; display: flex; flex-direction: column; align-items: center; gap: 4px; padding-top: 7px; cursor: pointer; border-radius: 15px; }
.mc-day.sel { outline: 2px solid var(--v-primary); outline-offset: -3px; }
.mc-num { width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center; font-size: 0.98rem; font-weight: 650; color: var(--v-text); line-height: 1; }
.mc-day.other .mc-num { color: var(--v-muted); font-weight: 500; }
.mc-day.on .mc-num { color: #fff; font-weight: 800; }
.mc-day.today:not(.sel) .mc-num { box-shadow: 0 0 0 2px var(--v-primary); }
.mc-dots { display: flex; gap: 3px; height: 6px; align-items: center; }
.mc-dots i { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }
.mc-dots b { font-size: 0.54rem; font-weight: 800; color: var(--v-muted); line-height: 1; }

.evl { margin-top: 1.1rem; display: flex; flex-direction: column; gap: 0.7rem; }
.evl-head { display: flex; align-items: baseline; gap: 0.55rem; margin: 0.2rem 2px 0.15rem; }
.evl-head .d { font-size: 1.02rem; font-weight: 800; letter-spacing: -0.01em; }
.evl-head .n { font-size: 0.74rem; font-weight: 800; color: var(--v-primary); text-transform: uppercase; letter-spacing: 0.05em; }
.ev-card { background: var(--v-panel); border: 1px solid var(--v-line); border-radius: 16px; padding: 0.85rem 0.95rem; display: flex; align-items: center; gap: 0.85rem; cursor: pointer; transition: box-shadow var(--v-ease), border-color var(--v-ease); }
.ev-card:hover { border-color: var(--v-primary); box-shadow: 0 6px 18px rgba(30,20,60,0.09); }
.ev-when { flex: none; width: 52px; font-size: 0.76rem; font-weight: 700; color: var(--v-muted); line-height: 1.25; }
.ev-bar { flex: none; width: 4px; align-self: stretch; border-radius: 4px; min-height: 36px; }
.ev-body { flex: 1; min-width: 0; }
.ev-title { font-size: 0.98rem; font-weight: 800; color: var(--v-text-strong); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ev-sub { font-size: 0.8rem; color: var(--v-text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.ev-tag { flex: none; font-size: 0.55rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.03em; padding: 2px 7px; border-radius: 999px; color: #fff; }
.ev-go { flex: none; color: var(--v-muted); font-size: 1.3rem; font-weight: 700; }
.evl-empty { text-align: center; color: var(--v-muted); font-size: 0.9rem; padding: 1.5rem 1rem; border: 1px dashed var(--v-line); border-radius: 16px; }

.sched-fab { position: fixed; right: 22px; bottom: 22px; width: 58px; height: 58px; border-radius: 50%; border: none; cursor: pointer; background: var(--v-primary-600); color: #fff; box-shadow: 0 12px 26px rgba(124,58,237,0.42); font-size: 1.7rem; line-height: 1; display: grid; place-items: center; z-index: 60; transition: transform var(--v-ease); }
.sched-fab:hover { transform: translateY(-2px); }
.sched-fab:active { transform: translateY(0); }

/* Home-page widget chrome: the month-nav row above the calendar. */
.gpwcal-nav { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.8rem; flex-wrap: wrap; }
.gpwcal-arrow { width: 34px; height: 34px; border-radius: 9px; border: 1px solid var(--v-line); background: var(--v-panel); color: var(--v-text); cursor: pointer; font-size: 1rem; }
.gpwcal-arrow:hover { border-color: var(--v-primary); }
.gpwcal-today { padding: 0 0.9rem; height: 34px; border-radius: 9px; border: 1px solid var(--v-line); background: var(--v-panel); color: var(--v-text); font-weight: 700; font-size: 0.83rem; cursor: pointer; }
.gpwcal-today:hover { border-color: var(--v-primary); }
.gpwcal-title { font-size: 1.1rem; font-weight: 800; letter-spacing: -0.01em; margin-left: 0.3rem; }
.gpwcal-spacer { flex: 1; }
.gpwcal-add { width: 34px; height: 34px; border-radius: 9px; border: none; background: var(--v-primary-600); color: #fff; font-size: 1.2rem; line-height: 1; cursor: pointer; }
.gpwcal-link { font-size: 0.82rem; font-weight: 700; color: var(--v-primary); text-decoration: none; }
.gpwcal-link:hover { text-decoration: underline; }

@media (max-width: 820px) {
  .mc-card { padding: 0.8rem 0.35rem 1rem; border-radius: 18px; }
  .mc-num { width: 37px; height: 37px; font-size: 0.92rem; }
  .mc-day { min-height: 50px; }
}

