﻿  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

  /* ── Design tokens ──────────────────────────────────────────────────── */
  /* Token system — every color in the CSS resolves through one of these.
     Light theme overrides live at the bottom of this file under
     [data-theme="light"]. Refactored 2026-05-07 to (a) soften the dark
     palette (eye-strain reduction) and (b) make the dark/light toggle
     possible without per-rule rewrites.
     ─────────────────────────────────────────────────────────────── */
  :root {
    /* Surfaces — softened from near-black to slate-900 family */
    --bg:               #0f172a;
    --bg-grad-end:      #11192d;
    --bg-grad-1:        rgba(96,165,250,0.05);
    --panel:            #1e293b;
    --panel-2:          #182338;
    --panel-3:          #131c2e;
    --surface-deep:     #0b1220;
    --row-hover:        #2a3855;
    /* Softer hover specifically for data-grid rows. The default
       --row-hover is appropriate for buttons / selects (high-affordance
       interactive elements) but too contrasty under a cursor that just
       happens to be hovering a 11-column data row — eye jumps. This
       blue-tinted overlay reads as "this row, no big deal." */
    --row-hover-soft:   rgba(96, 165, 250, 0.06);

    /* Borders */
    --border:           #2c3a55;
    --border-strong:    #3b4f76;
    --border-subtle:    #232838;

    /* Text — body text dropped from ~17:1 to ~12:1 contrast */
    --text:             #cbd5e1;
    --text-strong:      #f1f5f9;
    --text-soft:        #94a3b8;
    --text-muted:       #6b7fa3;
    --text-subtle:      #4a5568;
    --text-faint:       #475a76;

    /* Stays-white-on-color (toggle thumb, blue-button text, etc.) */
    --on-color:         #ffffff;

    /* Brand blue */
    --blue:             #3b82f6;
    --blue-hover:       #4f8df7;
    --blue-bright:      #60a5fa;
    --blue-light:       #93c5fd;
    --blue-lighter:     #bfdbfe;
    --blue-lightest:    #dbeafe;
    --blue-soft:        rgba(59,130,246,0.14);
    --blue-overlay:     rgba(96,165,250,0.06);

    /* Semantic accents */
    --green:            #4ade80;
    --green-text:       #86efac;
    --green-soft:       #6ee7b7;

    --red:              #ef4444;
    --red-text:         #fca5a5;
    --red-bright:       #f87171;

    --amber:            #fbbf24;
    --amber-text:       #fde68a;
    --amber-bright:     #facc15;
    --orange:           #fdba74;

    --purple:           #c4b5fd;
    --purple-soft:      #a5b4fc;
    --indigo:           #c7d2fe;
    --pink:             #f9a8d4;
    --cyan:             #67e8f9;
    --violet:           #a78bfa;

    /* Toast / status backgrounds (kept saturated in both themes) */
    --toast-error-bg:     #1a0a0a;
    --toast-error-border: #7f1d1d;
    --toast-success-bg:     #0a1f1a;
    --toast-success-border: #065f46;

    /* Layout */
    --radius-md:     12px;
    --radius-lg:     18px;
    --radius-xl:     22px;
    --shadow-card:   0 10px 30px rgba(0,0,0,0.30);
    --shadow-blue:   0 8px 24px rgba(37,99,235,0.32);
  }

  body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-feature-settings: 'cv11', 'ss01';
    background:
      radial-gradient(circle at top left, var(--bg-grad-1), transparent 28%),
      linear-gradient(180deg, var(--bg) 0%, var(--bg-grad-end) 100%);
    color: var(--text); min-height: 100vh;
    padding: 24px 16px 48px;
    -webkit-font-smoothing: antialiased;
  }
  .container { max-width: 1440px; margin: 0 auto; }

  /* ── Logo header ── */
  .logo-header {
    display: flex; align-items: center; gap: 14px;
    margin-bottom: 28px; padding-bottom: 20px;
    border-bottom: 1px solid var(--border);
  }
  .logo-img { height: 48px; width: auto; }
  .logo-text { display: flex; flex-direction: column; }
  .logo-name {
    font-size: 16px; font-weight: 700; color: var(--text-strong);
    letter-spacing: 0.02em; line-height: 1.2;
  }
  .logo-tagline {
    font-size: 11px; color: var(--blue); font-weight: 500;
    letter-spacing: 0.08em; text-transform: uppercase; margin-top: 2px;
  }

  /* ── Section heading rule ── */
  .section-rule {
    font-size: 10px; font-weight: 700; color: var(--blue);
    text-transform: uppercase; letter-spacing: 0.1em;
    margin: 22px 0 12px; padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
    display: flex; align-items: center; gap: 8px;
  }
  .section-rule::before {
    content: ''; display: inline-block; width: 3px; height: 12px;
    background: var(--blue); border-radius: 2px; flex-shrink: 0;
  }

  /* ── Top controls card ── */
  .controls {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    padding: 20px 22px; margin-bottom: 20px;
    box-shadow: var(--shadow-card);
  }
  .top-row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
  .search-wrap { flex: 1; min-width: 220px; position: relative; }
  .search-wrap input {
    width: 100%; padding: 10px 36px 10px 36px;
    border: 1px solid var(--border); border-radius: 8px;
    font-size: 14px; color: var(--text); background: var(--panel-3);
    outline: none; transition: border 0.15s, box-shadow 0.15s;
  }
  /* Clear (X) button — appears on the right when there's text in the
     input, click to wipe + refocus. The .has-text class is toggled by
     the input handler in JS. Sized so the click target hits comfortably. */
  .search-clear-btn {
    position: absolute; right: 6px; top: 50%;
    transform: translateY(-50%);
    width: 26px; height: 26px;
    display: none; align-items: center; justify-content: center;
    background: transparent; border: 0;
    border-radius: 6px; cursor: pointer;
    color: var(--text-muted);
    transition: background 0.12s, color 0.12s;
    padding: 0;
  }
  .search-wrap.has-text .search-clear-btn { display: inline-flex; }
  .search-clear-btn:hover { background: rgba(96,165,250,0.12); color: var(--text); }
  .search-clear-btn svg { width: 14px; height: 14px; }
  .search-wrap input:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(59,130,246,0.15); }
  .search-wrap input::placeholder { color: var(--text-muted); }
  .search-wrap::before {
    content: ''; position: absolute; left: 14px; top: 50%;
    transform: translateY(-50%);
    width: 16px; height: 16px;
    background: no-repeat center/16px url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236f83a8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
  }
  .btn-icon { width: 14px; height: 14px; flex-shrink: 0; }
  .button {
    height: 44px; padding: 0 16px;
    border-radius: var(--radius-md); font-size: 13px;
    font-family: inherit; font-weight: 500; cursor: pointer;
    border: 1px solid var(--border-strong); background: var(--panel);
    color: var(--text);
    transition: background 160ms ease, border 160ms ease, color 160ms ease, transform 160ms ease;
    white-space: nowrap; display: inline-flex; align-items: center; gap: 6px;
  }
  .button:hover {
    border-color: var(--border-strong); background: var(--row-hover);
    transform: translateY(-1px);
  }

  /* Button rendered as a toggle switch: "Show archived [○      ]"
     flips to "Hide archived [      ●]" when active. */
  .button.toggle-btn {
    background: transparent;
    border-color: var(--border);
    gap: 12px;
  }
  /* 3-segment archive filter pill (Phase 4.3) — Active / Archived / All.
     Replaces the old binary toggle. Reads faster: each state is its own
     visible button, and the active one fills with the brand blue. */
  .archive-pill {
    display: inline-flex; align-items: stretch;
    background: var(--panel-3);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 3px;
    gap: 2px;
  }
  .archive-pill-seg {
    background: none; border: none;
    color: var(--text-soft);
    font-family: inherit; font-size: 12.5px; font-weight: 500;
    padding: 6px 14px;
    border-radius: 8px;
    cursor: pointer;
    transition: background 160ms ease, color 160ms ease;
  }
  .archive-pill-seg:hover {
    color: var(--text-strong);
    background: rgba(255, 255, 255, 0.04);
  }
  .archive-pill-seg.active {
    background: var(--blue);
    color: var(--on-color);
  }
  .archive-pill-seg.active:hover {
    background: var(--blue-hover);
  }
  [data-theme="light"] .archive-pill-seg:hover {
    background: rgba(15,23,42,0.04);
  }

  .button.toggle-btn .toggle-track {
    position: relative; display: inline-block;
    width: 34px; height: 18px; border-radius: 100px;
    background: var(--border);
    transition: background 160ms ease;
    flex-shrink: 0;
  }
  .button.toggle-btn .toggle-thumb {
    position: absolute; top: 2px; left: 2px;
    width: 14px; height: 14px; border-radius: 50%;
    background: var(--on-color); box-shadow: 0 1px 2px rgba(0,0,0,0.4);
    transition: left 160ms ease, background 160ms ease;
  }
  .button.toggle-btn.active .toggle-track {
    background: var(--blue);
  }
  .button.toggle-btn.active .toggle-thumb {
    left: 18px;
  }
  .button.toggle-btn:hover .toggle-track { background: var(--row-hover); }
  .button.toggle-btn.active:hover .toggle-track { background: var(--blue-hover); }
  .button.active { background: var(--panel-2); border-color: var(--border-strong); color: var(--blue-bright); }
  .button.match-cta { background: var(--panel-2); border-color: var(--border-strong); color: var(--purple); }
  .button.match-cta:hover { background: var(--purple); }
  .button:disabled { opacity: 0.5; cursor: not-allowed; }

  .meta-row {
    display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
    color: var(--text-muted); font-size: 12px; margin-top: 14px;
  }
  .count-pill {
    padding: 6px 14px; border-radius: 100px; font-weight: 500;
    font-size: 12px;
    background: var(--blue-soft); color: var(--blue-light);
    border: 1px solid rgba(59,130,246,0.28);
    cursor: pointer; transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
  }
  .count-pill:hover {
    background: rgba(59,130,246,0.22); border-color: rgba(59,130,246,0.42);
    transform: translateY(-1px);
  }
  .count-pill.active-scope {
    background: rgba(59,130,246,0.28); color: var(--blue-light);
    border-color: rgba(59,130,246,0.55);
    box-shadow: 0 0 0 2px rgba(59,130,246,0.18);
  }
  .count-pill.archived {
    background: rgba(251,146,60,0.12); color: var(--orange);
    border: 1px solid rgba(251,146,60,0.25);
  }
  .count-pill.archived:hover { background: rgba(251,146,60,0.22); border-color: rgba(251,146,60,0.4); }
  .count-pill.archived.active-scope {
    background: rgba(251,146,60,0.28); color: var(--orange);
    border-color: rgba(251,146,60,0.55);
    box-shadow: 0 0 0 2px rgba(251,146,60,0.18);
  }
  .count-pill.unmatched {
    background: rgba(167,139,250,0.12); color: var(--purple);
    border: 1px solid rgba(167,139,250,0.25);
  }
  .count-pill.unmatched:hover { background: rgba(167,139,250,0.22); border-color: rgba(167,139,250,0.4); }

  /* ── Section/category filter blocks ── */
  .filter-sections {
    display: grid; grid-template-columns: repeat(3, 1fr);
    gap: 14px; margin-top: 4px;
  }
  .section-block {
    background: var(--panel-3); border: 1px solid var(--border); border-radius: 12px;
    padding: 12px 12px 8px;
    display: flex; flex-direction: column; gap: 8px;
    transition: border 0.15s, background 0.15s;
  }
  /* Collapsed sections: hide everything except the head, and drop the
     bottom padding so the card hugs its label. */
  .section-block.collapsed { padding-bottom: 12px; gap: 0; }
  .section-block.collapsed .section-block-head { padding-bottom: 0; border-bottom: none; }
  .section-block.collapsed > details.category { display: none; }
  .section-block-head {
    display: flex; align-items: center; gap: 8px;
    font-size: 11px; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase;
    padding-bottom: 6px; border-bottom: 1px solid var(--border);
    cursor: pointer; user-select: none;
    transition: color 0.15s;
  }
  .section-block-head .chev {
    margin-left: 4px; font-size: 10.5px; opacity: 0.6;
    transition: transform 0.15s, opacity 0.15s, background 0.15s;
  }
  .section-block:not(.collapsed) .section-block-head .chev { transform: rotate(180deg); opacity: 0.9; }
  .section-block-toggle {
    background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08);
    color: inherit; font-family: inherit;
    cursor: pointer; padding: 3px 7px; line-height: 1;
    border-radius: 6px; flex-shrink: 0;
  }
  .section-block-toggle:hover {
    background: rgba(255,255,255,0.10); border-color: rgba(255,255,255,0.18);
    opacity: 1;
  }
  .section-block:not(.collapsed) .section-block-toggle {
    background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.14);
  }
  .section-block-head .dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; transition: transform 0.15s; }
  .section-block-head .name { flex-shrink: 0; transition: color 0.15s; }
  .section-block-head:hover .name { color: var(--text); }
  .section-block-head:hover .dot { transform: scale(1.15); }
  .section-block.leads    .dot { background: var(--violet); }
  .section-block.jobs     .dot { background: var(--blue-bright); }
  .section-block.projects .dot { background: var(--green); }
  .section-block.leads    .section-block-head { color: var(--purple); }
  .section-block.jobs     .section-block-head { color: var(--blue-light); }
  .section-block.projects .section-block-head { color: var(--green-soft); }
  .section-block.active.leads    { background: rgba(167,139,250,0.08); border-color: rgba(167,139,250,0.45); }
  .section-block.active.jobs     { background: rgba(96,165,250,0.08);  border-color: rgba(96,165,250,0.45); }
  .section-block.active.projects { background: rgba(52,211,153,0.08);  border-color: rgba(52,211,153,0.45); }
  .section-block-count {
    margin-left: auto; font-size: 10px; font-weight: 600;
    color: var(--text-muted); background: rgba(255,255,255,0.04);
    padding: 2px 7px; border-radius: 100px; letter-spacing: 0;
    text-transform: none;
  }
  .section-block-clear {
    background: none; border: none; color: inherit;
    font-size: 14px; font-family: inherit;
    cursor: pointer; padding: 0 4px; line-height: 1;
    opacity: 0; visibility: hidden; transition: opacity 0.15s;
  }
  .section-block.active .section-block-clear { opacity: 0.85; visibility: visible; }
  .section-block-clear:hover { opacity: 1; color: var(--red-bright); }

  details.category {
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
    padding: 0; transition: border 0.15s;
  }
  details.category[open] { border-color: var(--border-strong); }
  details.category summary {
    list-style: none; cursor: pointer; padding: 9px 12px;
    display: flex; align-items: center; gap: 8px;
    font-size: 12px; color: var(--text); font-weight: 500;
    user-select: none;
  }
  details.category summary::-webkit-details-marker { display: none; }
  details.category summary::after {
    content: '▸'; margin-left: auto;
    font-size: 10px; color: var(--text-muted); transition: transform 0.15s;
  }
  details.category[open] summary::after { transform: rotate(90deg); }
  details.category summary:hover { color: var(--text); }
  details.category .cat-count {
    font-size: 10px; color: var(--text-muted);
    background: rgba(255,255,255,0.04);
    padding: 1px 6px; border-radius: 100px;
  }
  details.category .cat-selected-count {
    font-size: 10px; font-weight: 700;
    background: rgba(59,130,246,0.18); color: var(--blue-bright);
    padding: 1px 7px; border-radius: 100px;
  }
  .cat-body { display: flex; flex-direction: column; gap: 2px; padding: 0 8px 8px; }
  .cat-row {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 8px; border-radius: 6px;
    font-size: 12px; color: var(--text-soft); cursor: pointer;
    transition: background 0.15s, color 0.15s;
  }
  .cat-row:hover { background: var(--row-hover); color: var(--text); }
  .cat-row input[type="checkbox"] {
    margin: 0; accent-color: var(--blue); width: 14px; height: 14px; cursor: pointer;
  }
  .cat-row .cc-dot {
    display: inline-block; width: 10px; height: 10px;
    border-radius: 100px;
    background: var(--text-subtle);
    flex-shrink: 0;
    box-shadow: 0 0 0 1px rgba(255,255,255,0.08) inset;
  }
  .cat-row .label-text { flex: 1; }
  .cat-row .label-count {
    font-size: 10px; color: var(--text-muted);
    background: rgba(255,255,255,0.04);
    padding: 1px 7px; border-radius: 100px;
  }
  .cat-row.active { background: rgba(59,130,246,0.12); color: var(--blue-light); }
  .cat-row.active .label-count { background: rgba(59,130,246,0.2); color: var(--blue-lighter); }
  .cat-empty { font-size: 11px; color: var(--text-subtle); font-style: italic; padding: 6px 8px; }

  .filter-actions {
    display: flex; gap: 8px; align-items: center;
    margin-top: 14px; flex-wrap: wrap;
  }
  .filter-actions .mode-switch {
    display: inline-flex; border: 1px solid var(--border);
    border-radius: 8px; overflow: hidden; background: var(--panel-3);
  }
  .filter-actions .mode-btn {
    padding: 6px 12px; font-size: 12px; background: transparent;
    border: none; cursor: pointer; color: var(--text-muted); font-family: inherit;
  }
  .filter-actions .mode-btn.active { background: var(--panel-2); color: var(--blue-bright); }
  .filter-actions .clear-link {
    background: none; border: none; color: var(--text-muted); font-size: 12px;
    cursor: pointer; padding: 4px 6px; font-family: inherit;
  }
  .filter-actions .clear-link:hover { color: var(--red-bright); }

  /* ── Job list: multi-column populated list ── */
  .job-list {
    display: flex; flex-direction: column;
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    overflow: hidden; background: var(--panel);
    box-shadow: var(--shadow-card);
  }
  /* Wrapper allows horizontal scroll when the row grid exceeds viewport so
     the right-side action buttons never get clipped. */
  .job-list-scroll {
    overflow-x: auto; overflow-y: visible;
    border-radius: var(--radius-xl);
  }
  .job-list-scroll > .job-list { min-width: max-content; }
  /* All Jobs uses the card layout — no horizontal scroll needed; cards
     reflow inside the viewport width. We detect the card layout by
     checking that #job-rows holds .aj-card children (renderJobs is the
     only consumer that writes aj-card; the legacy grid is gone). */
  .job-list-scroll:has(#job-rows .aj-card) > .job-list { min-width: 0; }
  #job-rows {
    padding: 12px 14px 14px;
    display: flex; flex-direction: column;
    gap: 8px;
    background: transparent;
  }
  /* Columns: Job | Client | Address | Status | Billing | Permit | Inspection | Project Stage | Added | Modified | Actions
     Reordered 2026-04-28 v6 per Matt — dropdowns now flow Status → Billing →
     Permit → Inspection → Project Stage between Address and Date Added.
     2026-04-29 v7: Added "Modified" column showing last activity (updated_at)
     so Matt can spot stale jobs at a glance.
     2026-05-18 — switched from fixed to minmax(MIN, FRm) so columns
     fluidly fill available width. Wider viewports show "Uptown Air
     Conditioning Ltd." in full; narrow viewports respect the per-column
     minimum so nothing collapses below readable size. Long content in
     one row still can't push other columns wider (grid fr is computed
     once across the whole grid, not per row). */
  .grid-cols {
    display: grid;
    grid-template-columns:
      64px                   /* Thumb — Street View / satellite, 56×42 image */
      minmax(150px, 1.2fr)   /* Job — name link, wraps within cell */
      minmax(190px, 1.6fr)   /* Client — fits "Uptown Air Conditioning Ltd." */
      minmax(180px, 1.6fr)   /* Address — fits "1356 Vining Street, Victoria, BC" */
      minmax(140px, 1.1fr)   /* Status */
      minmax(80px,  0.6fr)   /* Billing */
      minmax(140px, 1.1fr)   /* Permit */
      minmax(150px, 1.2fr)   /* Inspection */
      minmax(140px, 1.1fr)   /* Project Stage */
      minmax(85px,  0.6fr)   /* Added */
      minmax(85px,  0.6fr)   /* Modified */
      minmax(120px, 0.8fr);  /* Actions — Schedule + Meeting + CC */
    align-items: center; gap: 8px;
  }
  /* Compact-grid mode (Phase 4.2). Hides Billing(6), Permit(7),
     Inspection(8), Added(10) by display:none — indices include the
     leading Thumb column (1). Toggle via the "More columns" button
     + persisted in localStorage 'peak-grid-compact'. */
  .job-list.compact .grid-cols {
    grid-template-columns:
      64px                   /* Thumb */
      minmax(150px, 1.2fr)   /* Job */
      minmax(190px, 1.6fr)   /* Client */
      minmax(180px, 1.6fr)   /* Address */
      minmax(140px, 1.1fr)   /* Status */
      minmax(140px, 1.1fr)   /* Project Stage */
      minmax(85px,  0.6fr)   /* Modified */
      minmax(120px, 0.8fr);  /* Actions */
  }
  .job-list.compact .grid-cols > *:nth-child(6),  /* Billing */
  .job-list.compact .grid-cols > *:nth-child(7),  /* Permit */
  .job-list.compact .grid-cols > *:nth-child(8),  /* Inspection */
  .job-list.compact .grid-cols > *:nth-child(10)  /* Added */
  { display: none; }
  .job-list-head {
    padding: 14px 20px;
    background: var(--panel-3); border-bottom: 1px solid var(--border);
    font-size: 11px; font-weight: 600; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--text-muted);
  }
  .col-head {
    display: flex; align-items: center; gap: 4px;
    cursor: default; user-select: none;
  }
  .col-head.sortable { cursor: pointer; }
  .col-head.sortable:hover { color: var(--text); }
  .col-head .sort-arrow { font-size: 10.5px; opacity: 0.4; }
  .col-head.sorted .sort-arrow { opacity: 1; color: var(--blue-bright); }
  .col-head.actions { justify-content: flex-end; }

  .job-row {
    padding: 8px 20px;
    min-height: 40px;
    border-bottom: 1px solid var(--border);
    transition: background 0.12s;
    align-items: center;
  }
  /* Every grid cell (except Actions) contains its content so long strings
     can't push other columns wider. Grid items default to min-width: auto,
     which would otherwise let content expand the track. */
  .job-row > *, .job-list-head > * { min-width: 0; }
  .job-row:last-child { border-bottom: none; }
  .job-row:hover { background: var(--row-hover-soft); }
  .job-row.archived { opacity: 0.72; background: repeating-linear-gradient(45deg, transparent 0 12px, rgba(251,146,60,0.03) 12px 24px); }

  .job-title {
    font-size: 14px; font-weight: 600; color: var(--text-strong);
    line-height: 1.3; word-break: break-word;
  }
  /* Keep the job title looking the same as before we made it clickable —
     inherit the parent's light color, no underline until hover. */
  .job-title-link {
    color: inherit; text-decoration: none;
    transition: color 0.15s;
  }
  .job-title-link:hover { color: var(--blue-light); text-decoration: underline; }
  .job-title-edit {
    background: none; border: none; cursor: pointer;
    color: var(--text-subtle); font-family: inherit; font-size: 12px;
    padding: 2px 6px; margin-left: 6px; border-radius: 5px;
    vertical-align: middle; opacity: 0; transition: opacity 0.15s, background 0.15s, color 0.15s;
  }
  .job-row:hover .job-title-edit { opacity: 1; }
  .job-title-edit:hover { background: rgba(96,165,250,0.12); color: var(--blue-bright); }

  .detail-title-edit {
    background: none; border: none; cursor: pointer;
    color: var(--text-subtle); font-family: inherit; font-size: 14px;
    padding: 4px 10px; margin-left: 10px; border-radius: 6px;
    vertical-align: middle; transition: background 0.15s, color 0.15s;
  }
  .detail-title-edit:hover { background: rgba(96,165,250,0.15); color: var(--blue-bright); }

  /* Calendar view — weekday time-grid. Each weekday is a column, each event
     is a positioned tile. Overlapping events split into side-by-side
     sub-columns so nothing stacks visually. */
  .cal-wrap {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 16px 18px;
    margin: 14px 0;
  }
  .cal-topbar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
    padding-bottom: 14px; margin-bottom: 10px;
    border-bottom: 1px solid var(--border);
  }
  /* Crew roster strip — draggable chips above the calendar grid. Drop
     onto any event tile to assign that crew member; click × on a chip
     badge inside an event to unassign. */
  .cal-crew-strip {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 8px;
    padding: 10px 12px;
    margin-bottom: 12px;
    background: var(--panel-3);
    border: 1px dashed var(--border-subtle);
    border-radius: 8px;
  }
  .cal-crew-strip-label {
    font-size: 11px; font-weight: 600; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--text-muted);
    margin-right: 4px;
  }
  .cal-crew-strip-hint {
    font-size: 12px; color: var(--text-muted); font-style: italic;
  }

  /* All-day event strip — sits between the crew bar and the time grid.
     Mirrors Google Calendar's "All day" row: spanning bars replace the
     per-column "All day" tiles that used to appear squashed at 7 AM. */
  .cal-allday-section {
    display: flex; align-items: stretch;
    border-bottom: 1px solid var(--border);
    background: var(--panel-3);
    min-height: 30px;
  }
  .cal-allday-axis {
    flex-shrink: 0; width: 56px;
    display: flex; align-items: flex-start; justify-content: flex-end;
    padding: 6px 8px 0 0;
    font-size: 9.5px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.06em; color: var(--text-muted);
    border-right: 1px solid var(--border);
  }
  .cal-allday-grid {
    flex: 1 1 auto;
    display: grid;
    /* grid-template-columns and grid-template-rows set inline per visible day count */
    padding: 4px 0 4px;
    row-gap: 2px;
    column-gap: 0;
    align-items: center;
  }
  .cal-allday-event {
    margin: 0 3px;
    padding: 3px 10px 3px 8px;
    border-radius: 5px;
    font-size: 11.5px; font-weight: 600;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    cursor: pointer;
    background: color-mix(in srgb, var(--ev-color) 72%, var(--panel));
    color: #fff;
    border-left: 3px solid var(--ev-color);
    transition: filter 0.12s, transform 0.08s;
    user-select: none;
  }
  .cal-allday-event:hover {
    filter: brightness(1.15);
    transform: translateY(-1px);
  }
  /* BC statutory-holiday markers — passive, non-interactive. */
  .cal-allday-event[data-event-id^="stat-holiday-"],
  .cal-month-ev[data-event-id^="stat-holiday-"] {
    cursor: default;
    font-style: italic;
    opacity: 0.9;
  }
  .cal-allday-event[data-event-id^="stat-holiday-"]:hover {
    filter: none;
    transform: none;
  }
  /* ── Google Tasks chips (Peak Stuff list) ────────────────────────────
     Dated tasks render on their due day the way Google Calendar draws
     them — a checkbox chip. Week/2wk all-day strip (.cal-task-chip) +
     month cells (.cal-month-task). Click = mark done / reopen (wired in
     07-views.js). Distinct classes keep them out of every event handler
     (day-detail modal, drag, context menu, duplicate). */
  .cal-task-chip,
  .cal-month-task {
    display: flex; align-items: center; gap: 5px;
    font-size: 11px; font-weight: 600;
    white-space: nowrap; overflow: hidden;
    cursor: pointer;
    color: var(--text-strong);
    background: color-mix(in srgb, var(--blue-light) 16%, var(--panel));
    border: 1px solid color-mix(in srgb, var(--blue-light) 45%, transparent);
    border-radius: 5px;
    user-select: none;
    transition: filter 0.12s;
  }
  .cal-task-chip { margin: 0 3px; padding: 2px 8px 2px 6px; }
  .cal-month-task { margin-bottom: 2px; padding: 2px 6px; }
  .cal-task-chip:hover, .cal-month-task:hover { filter: brightness(1.12); }
  .cal-task-chip:focus-visible, .cal-month-task:focus-visible {
    outline: 2px solid var(--blue-light); outline-offset: 1px;
  }
  .cal-task-title { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
  .cal-task-circle {
    flex: 0 0 auto;
    width: 12px; height: 12px;
    border-radius: 50%;
    border: 1.5px solid var(--blue-light);
    box-sizing: border-box;
    position: relative;
  }
  .cal-task-done .cal-task-circle {
    background: var(--blue-light);
  }
  .cal-task-done .cal-task-circle::after {
    content: '';
    position: absolute;
    left: 3px; top: 1px;
    width: 3px; height: 6px;
    border: solid var(--panel);
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
  }
  .cal-task-done { opacity: 0.72; }
  .cal-task-done .cal-task-title { text-decoration: line-through; }
  /* Overdue open task, rolled forward to today (Google Calendar behavior). */
  .cal-task-overdue {
    background: color-mix(in srgb, var(--red) 14%, var(--panel));
    border-color: color-mix(in srgb, var(--red) 55%, transparent);
  }
  .cal-task-overdue .cal-task-circle { border-color: var(--red-bright); }
  .cal-task-overdue .cal-task-title { color: var(--red-text); }
  /* Left-clipped: event started before the visible week — no left border,
     square left edge to signal it continues from the left. */
  .cal-allday-event.cal-allday-clip-left {
    border-left: none;
    border-radius: 0 5px 5px 0;
    padding-left: 10px;
    margin-left: 0;
  }
  /* Right-clipped: event continues past the visible week — square right
     edge, slight visual hint it extends off the right side. */
  .cal-allday-event.cal-allday-clip-right {
    border-radius: 5px 0 0 5px;
    margin-right: 0;
  }
  .cal-allday-event.cal-allday-clip-left.cal-allday-clip-right {
    border-radius: 0;
  }
  /* Crew chip in the calendar header strip. Single role-colored pill
     with the crew's first name inside. (Used to be a 2-tone chip with
     a small initials circle next to a name label — now the pill is
     the whole thing, with the role color as the background.) */
  .cal-crew-chip {
    display: inline-flex; align-items: center;
    padding: 0;
    background: transparent;
    border: none;
    cursor: grab;
    user-select: none;
    transition: transform 120ms ease;
  }
  .cal-crew-chip:active { cursor: grabbing; }
  .cal-crew-chip:hover { transform: translateY(-1px); }
  .cal-crew-chip-dragging { opacity: 0.4; }
  /* Off-for-the-whole-week crew: faded + non-interactive but still visible
     so the strip reads as "here's the crew, this one's out". Hover lift is
     suppressed since the chip isn't draggable. */
  .cal-crew-chip-off { cursor: not-allowed; opacity: 0.35; filter: grayscale(0.6); }
  .cal-crew-chip-off:hover { transform: none; }
  .cal-crew-chip-off .cal-crew-chip-initials { text-decoration: line-through; }
  /* Partial PTO during visible week: draggable, but flagged with amber
     ring + slight dim so the drop-block isn't a surprise. */
  .cal-crew-chip-off-partial { opacity: 0.72; }
  .cal-crew-chip-off-partial .cal-crew-chip-initials { box-shadow: 0 0 0 1.5px var(--amber); }
  .cal-crew-chip-initials {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 22px; height: 26px;
    padding: 0 12px;
    border-radius: 999px;
    background: var(--blue, #2563eb);
    color: #fff;
    font-size: 12px; font-weight: 700;
    letter-spacing: 0.01em;
    text-shadow: 0 1px 1px rgba(0,0,0,0.3);
    white-space: nowrap;
  }
  /* Drop target highlight when a chip is dragged over an event tile. */
  .cal-event.cal-event-drop-target {
    outline: 2px solid var(--blue, #2563eb);
    outline-offset: 1px;
  }
  /* Assignment badges inside event tiles — vertical stack of crew
     first-name pills, sorted top-down by role hierarchy (owner →
     foreman → journeyman → apprentice). Anchored bottom-right of
     the tile so they grow upward as more crew are added. */
  .cal-assign-badges {
    position: absolute;
    bottom: 3px; right: 3px;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap-reverse;
    justify-content: flex-end;
    align-items: center;
    gap: 2px;
    /* Cap width to tile-minus-margin so chips wrap upward (wrap-reverse)
       instead of overflowing horizontally off the right edge. Wide tiles
       (focused-day single lane, all-crew banner) fit every chip in one
       row across the bottom; narrow tiles fall back to one chip per row,
       matching the old column behavior. */
    max-width: calc(100% - 6px);
    pointer-events: auto;
  }
  .cal-assign-badge {
    position: relative;
    display: inline-flex; align-items: center;
  }
  /* Per-event assignment badge — small pill on the corner of the event
     tile. Width grows with the first-name text. */
  .cal-assign-badge-initials {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px;
    padding: 0 7px;
    border-radius: 999px;
    background: rgba(37, 99, 235, 0.85);
    color: #fff;
    font-size: 10px; font-weight: 700;
    border: 1px solid rgba(255,255,255,0.4);
    text-shadow: 0 1px 1px rgba(0,0,0,0.3);
    white-space: nowrap;
    letter-spacing: 0.01em;
  }
  /* Partial-day window — second line INSIDE the same tinted pill
     ("Chase" over "til 3p"), so it can't wrap away from the name on
     narrow tiles (2026-08-17; the old sibling-span layout orphaned the
     time onto its own line, looking like a stray label). */
  .cal-assign-badge-initials-win {
    flex-direction: column;
    height: auto;
    padding: 2px 7px 3px;
    line-height: 1.15;
    border-radius: 9px;
  }
  .cal-assign-badge-window {
    font-size: 9px;
    font-weight: 600;
    opacity: 0.92;
    white-space: nowrap;
  }
  .cal-assign-badge-x {
    position: absolute;
    top: -4px; right: -4px;
    width: 12px; height: 12px;
    padding: 0;
    line-height: 1;
    border: 0;
    border-radius: 50%;
    background: rgba(248, 113, 113, 0.9);
    color: #fff;
    font-size: 9px; font-weight: 700;
    cursor: pointer;
    opacity: 0;
    transition: opacity 120ms ease;
  }
  .cal-assign-badge:hover .cal-assign-badge-x { opacity: 1; }
  .cal-title-text { font-size: 18px; color: var(--text); margin: 0; }
  .cal-sub-text { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
  .cal-legend {
    display: flex; gap: 12px; flex-wrap: wrap; align-items: center;
    padding: 6px 10px; border-radius: 8px;
    background: rgba(15,19,28,0.4);
    border: 1px solid rgba(42,51,71,0.6);
  }
  .cal-legend-item {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 11.5px; color: var(--text-soft);
    white-space: nowrap;
  }
  .cal-legend-dot {
    width: 10px; height: 10px; border-radius: 3px;
    display: inline-block; flex-shrink: 0;
    box-shadow: 0 0 0 1px rgba(0,0,0,0.25);
  }
  .cal-legend-sep {
    width: 1px; height: 14px; background: var(--border);
    display: inline-block;
  }
  .cal-legend-hint {
    font-size: 10.5px; color: var(--text-muted);
    font-style: italic; margin-left: 4px; cursor: help;
  }
  .cal-empty { padding: 40px; color: var(--text-muted); font-style: italic; text-align: center; }

  .cal-grid {
    display: flex; gap: 0;
    overflow-x: auto;
  }
  .cal-axis {
    flex-shrink: 0; width: 56px;
    border-right: 1px solid var(--border);
  }
  .cal-axis-header {
    height: 38px; border-bottom: 1px solid var(--border);
  }
  .cal-axis-body { position: relative; }
  .cal-axis-label {
    position: absolute; left: 6px; right: 6px;
    text-align: right;
    font-size: 10.5px; color: var(--text-muted);
    transform: translateY(-6px);
  }

  .cal-days {
    display: flex; flex: 1 1 auto; min-width: 0;
  }
  .cal-day-col {
    flex: 1 1 0; min-width: 130px;
    border-right: 1px solid var(--border);
    transition: flex-grow 0.18s ease, background 0.15s, opacity 0.18s;
  }
  /* 2026-05-19 — focused-day click-to-expand. Click any column header
     to widen that column ~3x the others; click again to balance. */
  .cal-day-col.cal-day-col-focused {
    flex-grow: 3;
    box-shadow: inset 0 0 0 2px rgba(96, 165, 250, 0.45);
  }
  .cal-day-col.cal-day-col-focused .cal-day-col-header {
    background: rgba(59, 130, 246, 0.18);
    color: var(--blue-light);
    font-weight: 700;
  }
  .cal-day-col-focus-x {
    margin-left: 6px; font-weight: 800;
    color: var(--blue-light); opacity: 0.85;
  }
  /* Non-focused columns dim slightly when ANY column is focused so the
     focused one really pops. Keeps the columns visible enough to scan. */
  .cal-day-col.cal-day-col-dim {
    flex-grow: 0.5;
    opacity: 0.72;
  }
  .cal-day-col.cal-day-col-dim .cal-event-title,
  .cal-day-col.cal-day-col-dim .cal-event-sub {
    /* Narrow columns truncate via ellipsis already; this just keeps
       text from looking aggressively clipped while dimmed. */
    letter-spacing: 0;
  }
  /* Header is now a clickable button — strip default button styling
     and add a subtle hover affordance so it reads as interactive. */
  button.cal-day-col-header {
    width: 100%; cursor: pointer;
    appearance: none; border: 0; outline: 0;
    font-family: inherit; font-size: 12px; font-weight: 600;
    transition: background 0.12s, color 0.12s;
  }
  button.cal-day-col-header:hover {
    background: rgba(96, 165, 250, 0.10);
    color: var(--blue-light);
  }
  button.cal-day-col-header:focus-visible {
    box-shadow: inset 0 0 0 2px rgba(96, 165, 250, 0.55);
  }
  /* 2026-05-19 — cross-day drag drop target. Lights up the column the
     cursor is currently over so Matt sees which day his event will
     land on if he releases here. Cleared on mouseup or abort. */
  .cal-day-col.cal-day-col-drop-target {
    background: rgba(59, 130, 246, 0.13);
    box-shadow: inset 0 0 0 2px rgba(59, 130, 246, 0.45);
  }
  .cal-day-col.cal-day-col-drop-target .cal-day-col-header {
    color: var(--blue-light);
  }
  /* Saturday + Sunday — slight faded background + dimmer header text. */
  .cal-day-col.cal-day-weekend {
    background: rgba(15, 19, 28, 0.6);
  }
  .cal-day-col.cal-day-weekend .cal-day-col-header {
    color: var(--text-muted);
    opacity: 0.7;
  }
  /* Today — accent line at the top + brighter header. Top bar dialed
     back from 0.85 → 0.55 alpha so it doesn't compete with the red now-line
     for attention. */
  .cal-day-col.cal-day-today {
    background: rgba(22, 163, 74, 0.09);
    box-shadow: inset 0 3px 0 0 rgba(34, 197, 94, 0.55);
  }
  .cal-day-col.cal-day-today .cal-day-col-header {
    color: var(--green);
    font-weight: 700;
    background: rgba(22, 163, 74, 0.12);
  }
  /* Week navigation — sits in the calendar topbar, between legend + refresh. */
  .cal-week-nav {
    display: flex; align-items: center; gap: 6px;
    margin-left: 12px;
  }
  .cal-week-nav-btn {
    background: var(--panel-3); border: 1px solid var(--border);
    color: var(--text); font-family: inherit; font-size: 13px;
    padding: 4px 10px; border-radius: 6px;
    cursor: pointer; transition: background 0.12s, border-color 0.12s;
    line-height: 1; font-weight: 600;
  }
  /* ‹ Today › are primary tap targets on the iPad — same two-tap trap. */
  @media (hover: hover) {
    .cal-week-nav-btn:hover:not(:disabled) {
      background: rgba(96, 165, 250, 0.15); border-color: rgba(96, 165, 250, 0.4);
      color: var(--blue-light);
    }
  }
  .cal-week-nav-btn:disabled {
    opacity: 0.4; cursor: not-allowed;
  }
  .cal-week-nav-btn.cal-week-today {
    font-size: 11px; padding: 4px 10px;
  }
  .cal-week-range {
    margin-left: 4px;
    font-size: 12.5px; font-weight: 600;
    color: var(--text);
    white-space: nowrap;
  }
  .cal-day-col:last-child { border-right: none; }
  .cal-day-col-header {
    height: 38px; display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 600; color: var(--text-soft);
    letter-spacing: 0.08em; text-transform: uppercase;
    border-bottom: 1px solid var(--border);
    background: var(--panel-3);
  }
  .cal-day-col-body {
    position: relative; background: var(--panel-3);
  }
  .cal-hour-line {
    position: absolute; left: 0; right: 0; height: 0;
    border-top: 1px solid rgba(26,42,68,0.6);
    pointer-events: none;
  }
  .cal-half-hour-line {
    position: absolute; left: 8px; right: 0; height: 0;
    border-top: 1px dashed rgba(26,42,68,0.35);
    pointer-events: none;
  }

  /* Past-time shading — fade the part of today's column that's already
     elapsed, OR the full column for any prior day in the visible week.
     Sits above the hour lines but below the event tiles so events render
     normally on top. */
  .cal-past-shade {
    position: absolute; left: 0; right: 0; top: 0;
    background: rgba(15, 23, 42, 0.45);
    pointer-events: none;
    z-index: 1;
  }
  /* The "now line" — a horizontal red rule on today's column at the live
     time-of-day. Includes a small dot at the start and an inline time
     label so Matt can see at a glance which slot is current. */
  .cal-now-line {
    position: absolute; left: 0; right: 0; height: 0;
    border-top: 2px solid var(--red);
    pointer-events: none;
    z-index: 5;
  }
  .cal-now-dot {
    position: absolute; left: -4px; top: -5px;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--red);
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.25);
  }
  .cal-now-time {
    position: absolute; right: 4px; top: -8px;
    padding: 1px 6px; border-radius: 4px;
    background: var(--red); color: var(--on-color);
    font-size: 10px; font-weight: 700;
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
  }
  /* Past day columns: very subtle dim on the header so it's clear they're
     historical, plus the full-column shade above. */
  .cal-day-past .cal-day-col-header {
    color: var(--text-soft);
    opacity: 0.6;
  }
  /* Calendar header help button — small (?) icon replacing the previous
     "How to refresh" text button. Hover reveals the explanation tooltip. */
  .cal-help-btn {
    width: 26px; height: 26px;
    border-radius: 50%;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 13px; font-weight: 700; line-height: 1;
    cursor: help;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    padding: 0;
  }
  .cal-help-btn:hover {
    background: rgba(96,165,250,0.12);
    color: var(--text);
    border-color: var(--blue);
  }

  /* View mode toggle — Week / 2 Wk / Month segmented control. */
  .cal-view-toggle {
    display: flex; gap: 0;
    border: 1px solid var(--border);
    border-radius: 7px;
    overflow: hidden;
    flex-shrink: 0;
  }
  .cal-view-btn {
    background: var(--panel-3); border: none;
    color: var(--text-soft); font-family: inherit;
    font-size: 12px; font-weight: 600;
    padding: 5px 11px; cursor: pointer;
    transition: background 0.12s, color 0.12s;
    border-right: 1px solid var(--border);
    white-space: nowrap;
  }
  .cal-view-btn:last-child { border-right: none; }
  .cal-view-btn:hover:not(.active) { background: rgba(96,165,250,0.1); color: var(--blue-light); }
  .cal-view-btn.active {
    background: rgba(59,130,246,0.22); color: var(--blue-light);
  }

  /* Create event button — top-right of calendar topbar. */
  .cal-create-btn {
    background: rgba(59,130,246,0.18);
    border: 1px solid rgba(59,130,246,0.45);
    color: var(--blue-light); font-family: inherit;
    font-size: 12px; font-weight: 700;
    padding: 5px 13px; border-radius: 7px;
    cursor: pointer; white-space: nowrap;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
    flex-shrink: 0;
  }
  .cal-create-btn:hover {
    background: rgba(59,130,246,0.32);
    border-color: rgba(96,165,250,0.7);
    color: var(--blue-lighter);
  }

  /* Right-click context menu for calendar events. */
  .cal-ctx-menu {
    display: none;
    position: fixed; z-index: 9999;
    min-width: 210px;
    background: #1a2235;
    border: 1px solid rgba(59,130,246,0.35);
    border-radius: 9px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.55);
    padding: 6px 0 6px;
    font-size: 13px;
  }
  .cal-ctx-title {
    padding: 5px 14px 8px;
    font-size: 11.5px; font-weight: 700;
    color: var(--text-soft);
    border-bottom: 1px solid rgba(42,51,71,0.8);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 200px;
    margin-bottom: 4px;
  }
  .cal-ctx-item {
    display: block; width: 100%;
    padding: 7px 14px;
    background: none; border: none;
    color: var(--text); font-family: inherit; font-size: 13px;
    text-align: left; cursor: pointer;
    transition: background 0.1s, color 0.1s;
  }
  .cal-ctx-item:hover { background: rgba(59,130,246,0.18); color: var(--blue-light); }
  .cal-ctx-item-danger { color: var(--red-bright); }
  .cal-ctx-item-danger:hover { background: rgba(239,68,68,0.18); color: var(--red-text); }
  .cal-ctx-sep {
    height: 1px; background: rgba(42,51,71,0.8);
    margin: 4px 0;
  }
  /* Light theme: the menu panel hardcodes a dark elevated surface above;
     flip it to a white popover (same treatment as .cal-event-color-menu). */
  [data-theme="light"] .cal-ctx-menu {
    background: #ffffff;
    border-color: var(--border);
    box-shadow: 0 8px 32px rgba(15,23,42,0.16);
  }
  [data-theme="light"] .cal-ctx-title { border-bottom-color: var(--border-subtle); }
  [data-theme="light"] .cal-ctx-item:hover { background: rgba(37,99,235,0.08); }
  [data-theme="light"] .cal-ctx-sep { background: var(--border-subtle); }

  /* Month view grid. */
  .cal-month-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0;
    border-top: 1px solid var(--border);
  }
  .cal-month-dow {
    padding: 7px 0;
    text-align: center;
    font-size: 11px; font-weight: 700; letter-spacing: 0.07em;
    text-transform: uppercase; color: var(--text-soft);
    background: var(--panel-3);
    border-bottom: 1px solid var(--border);
    border-right: 1px solid var(--border);
  }
  .cal-month-dow:last-child { border-right: none; }
  .cal-month-cell {
    min-height: 100px;
    padding: 4px;
    border-bottom: 1px solid var(--border);
    border-right: 1px solid var(--border);
    background: var(--panel-3);
    cursor: pointer;
    transition: background 0.1s;
    vertical-align: top;
    overflow: hidden;
  }
  .cal-month-cell:nth-child(7n) { border-right: none; }
  .cal-month-cell:hover { background: rgba(59,130,246,0.06); }
  .cal-month-cell.cal-month-today {
    background: rgba(22,163,74,0.09);
    box-shadow: inset 0 0 0 2px rgba(34,197,94,0.5);
  }
  .cal-month-cell.cal-month-other-month { opacity: 0.42; }
  .cal-month-cell.cal-month-past .cal-month-cell-num { color: var(--text-muted); }
  .cal-month-cell-num {
    font-size: 12px; font-weight: 700;
    color: var(--text-soft);
    margin-bottom: 3px; padding: 1px 4px;
    display: inline-block; border-radius: 50%;
    min-width: 22px; text-align: center;
    line-height: 20px;
  }
  .cal-month-today .cal-month-cell-num {
    background: #22c55e; color: #fff;
  }
  .cal-month-ev {
    display: block;
    margin-bottom: 2px;
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 11px; font-weight: 600;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    cursor: pointer;
    background: color-mix(in srgb, var(--ev-color) 34%, var(--panel));
    border-left: 3px solid var(--ev-color);
    color: var(--text);
    transition: filter 0.1s;
  }
  .cal-month-ev:hover { filter: brightness(1.15); }
  .cal-month-ev-time {
    font-size: 10px; font-weight: 700;
    color: color-mix(in srgb, var(--ev-color) 75%, white);
    margin-right: 4px;
  }
  .cal-month-overflow {
    font-size: 10.5px; color: var(--text-muted);
    padding: 1px 4px; cursor: pointer;
  }
  .cal-month-overflow:hover { color: var(--blue-light); }

  /* 2-week stacked view — divider bar between week 1 and week 2 */
  .cal-week-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 0 4px;
    margin: 2px 0 0;
    border-top: 2px solid rgba(99,130,182,0.25);
  }
  .cal-week-divider::before {
    content: '';
    display: inline-block;
    width: 3px; height: 16px;
    background: #4f6fad;
    border-radius: 2px;
    flex-shrink: 0;
  }
  .cal-week-divider-label {
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: #4f6fad;
    text-transform: uppercase;
  }

  .cal-event {
    position: absolute;
    padding: 5px 7px 4px 9px;
    border-radius: 6px;
    font-size: 11.5px;
    cursor: pointer;
    overflow: hidden;
    display: flex; flex-direction: column; gap: 1px;
    border-left: 4px solid var(--ev-color);
    background: color-mix(in srgb, var(--ev-color) 34%, var(--panel));
    color: var(--text);
    transition: transform 0.1s, box-shadow 0.15s, filter 0.15s;
    line-height: 1.2;
    z-index: 2;
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
  }
  .cal-event:hover {
    box-shadow: 0 6px 18px rgba(0,0,0,0.4);
    transform: translateY(-1px);
    filter: brightness(1.1);
    z-index: 4;
  }
  /* Drag + resize visual cues. */
  .cal-event.cal-event-dragging {
    cursor: grabbing;
    opacity: 0.3;      /* dimmed — ghost is the visual proxy */
    transition: none;
  }
  /* Fixed-position ghost that floats freely across columns + weeks. */
  .cal-event.cal-event-ghost {
    cursor: grabbing;
    border-radius: 6px;
    border-left: 4px solid var(--ev-color);
    background: color-mix(in srgb, var(--ev-color) 34%, var(--panel-3));
    transition: none;
  }
  .cal-event.cal-event-resizing {
    cursor: ns-resize;
    box-shadow: 0 12px 32px rgba(0,0,0,0.55);
    transform: none;
    z-index: 10;
    transition: none;
  }
  /* Resize handles — top + bottom edges of every event tile, 7px
     tall each. Both use ns-resize cursor. Faint background appears
     on hover so the affordance is discoverable; otherwise invisible
     so the tile reads clean. Top edge drag → adjusts start time;
     bottom edge drag → adjusts end time. Body drag moves the whole
     event. */
  .cal-event-resize-handle {
    position: absolute;
    left: 0; right: 0;
    height: 7px;
    cursor: ns-resize;
    background: transparent;
    transition: background 0.12s;
    z-index: 2;
  }
  .cal-event-resize-handle-top    { top: 0; }
  .cal-event-resize-handle-bottom { bottom: 0; }
  .cal-event-resize-handle:hover,
  .cal-event-resize-handle:active {
    background: rgba(255,255,255,0.18);
  }
  /* 2026-07-30 — floating time readout during drag/resize. A 30-min
     tile is ~27px tall and .cal-event-time clips to nothing inside it,
     so the time you were actually setting was invisible exactly when
     you needed to see it. This badge lives on <body>, so the tile and
     the column can never clip it.

     Position is FIXED — one spot, right-hand side, vertically centred.
     v1 tracked the dragged edge and flipped to the other side of the
     tile near the viewport edge; mid-drag that flipping read as the
     badge jumping side to side (Matt, same day). A stationary readout
     your eye can learn beats one that follows the cursor. Being
     stationary is also why all the JS positioning math is gone. */
  .cal-drag-time-badge {
    position: fixed;
    right: 18px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 10000;
    pointer-events: none;
    padding: 7px 13px;
    border-radius: 8px;
    background: var(--panel-3);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 14px;
    font-weight: 700;
    /* tabular-nums stops digits jittering; min-width + centring stops the
       BOX itself resizing as the label goes "45m" → "1h 30m" → "12h 45m",
       which would otherwise still slide its left edge ~46px mid-drag. */
    font-variant-numeric: tabular-nums;
    min-width: 250px;
    text-align: center;
    white-space: nowrap;
    box-shadow: 0 8px 26px rgba(0,0,0,0.45);
  }
  .cal-event-peak { --ev-color: var(--blue); }
  .cal-event-matt { --ev-color: var(--orange); }
  /* 2026-05-19 v2 — day-note pill on event tiles. Sits at the top of
     the tile content, pushing the time + title down. Block-level
     (not absolute) so it can't overlap the color-cycle dot at
     top-right. Right margin (22px) clears the color dot. Shows the
     note preview when set so Matt can scan it at a glance without
     opening the modal. */
  .cal-event-day-note {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    max-width: calc(100% - 22px);
    margin: 0 22px 4px 0;
    padding: 1px 7px 1px 6px;
    background: rgba(0,0,0,0.22);
    border: 1px solid rgba(255,255,255,0.20);
    border-radius: 999px;
    color: rgba(255,255,255,0.78);
    font-size: 10px;
    font-weight: 600;
    line-height: 1.3;
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
    overflow: hidden;
  }
  .cal-event-day-note:hover {
    background: rgba(0,0,0,0.40);
    color: #fff;
    border-color: rgba(255,255,255,0.45);
  }
  /* "Set" state — note has content. Slight amber tint so a tile
     carrying a note pops in Matt's scan. */
  .cal-event-day-note-set {
    background: rgba(245, 158, 11, 0.22);
    border-color: rgba(245, 158, 11, 0.55);
    color: #fff;
  }
  .cal-event-day-note-set:hover {
    background: rgba(245, 158, 11, 0.32);
    border-color: rgba(245, 158, 11, 0.75);
  }
  .cal-event-day-note-icon { font-size: 10px; flex-shrink: 0; }
  .cal-event-day-note-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* On compact tiles (very short events) hide the label, keep just
     the icon so it still fits. */
  .cal-event-compact .cal-event-day-note-text { display: none; }
  .cal-event-compact .cal-event-day-note {
    padding: 1px 5px;
  }
  /* Phase 4c — original-times chip. Surfaces "was 2:00p-3:00p" on tiles
     whose schedule was shifted by gcal-shift-trigger. Amber so it reads
     as "informational override" rather than alarm. Sits above the time
     row (same stack as day-note). Hover for full timestamp via title. */
  .cal-event-shift-chip {
    display: inline-block;
    margin: 2px 0 2px 6px;
    padding: 1px 6px;
    border-radius: 4px;
    background: rgba(251, 191, 36, 0.18);
    color: var(--amber);
    border: 1px solid rgba(251, 191, 36, 0.30);
    font-size: 9.5px;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.25;
    text-transform: lowercase;
    font-variant-numeric: tabular-nums;
    cursor: default;
    white-space: nowrap;
    max-width: calc(100% - 12px);
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* On compact tiles, hide the chip — too cluttered. The chip still
     lives in the DOM so the title-attribute tooltip works on hover. */
  .cal-event-compact .cal-event-shift-chip { display: none; }
  /* 2026-05-19 — past-event fade (Google Calendar mirror).
     Tiles whose end time has already passed dim to ~55% opacity so
     today + upcoming work pop visually. Crew badges + time text +
     job title all stay readable; this is just a contrast knock-down,
     not a hide. Matt explicitly wants names preserved on completed
     jobs for the historical-glance use case. Hovering restores full
     contrast so the past tile is still readable on demand. */
  .cal-event.cal-event-past,
  .cal-allday-event.cal-event-past {
    opacity: 0.55;
    filter: saturate(0.7);
    transition: opacity 0.15s, filter 0.15s;
  }
  .cal-event.cal-event-past:hover,
  .cal-allday-event.cal-event-past:hover {
    opacity: 0.92;
    filter: none;
  }
  /* 2026-05-19 — day-note modal. Centered overlay with a textarea for
     the per-event note. Same visual language as other modals so it
     feels native to the CRM. */
  .cal-day-note-modal-backdrop {
    /* 6000 keeps this ABOVE the job-detail modal (.ti-modal-backdrop, 5000)
       so the "+ Add day note" editor opens nested on top of it, not behind.
       Still below the toast/notification layer (9999). */
    position: fixed; inset: 0; z-index: 6000;
    background: rgba(0,0,0,0.55);
    display: flex; align-items: center; justify-content: center;
    padding: 24px;
  }
  .cal-day-note-modal {
    background: var(--panel, #0f131c);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(0,0,0,0.55);
    width: 100%; max-width: 480px;
    padding: 18px 18px 14px;
    display: flex; flex-direction: column; gap: 10px;
  }
  .cal-day-note-head {
    display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  }
  .cal-day-note-title {
    font-weight: 700; font-size: 15px; color: var(--text);
  }
  .cal-day-note-sub {
    font-size: 12px; color: var(--text-muted); margin-top: 2px;
  }
  .cal-day-note-close {
    background: transparent; border: none; cursor: pointer;
    color: var(--text-muted); font-size: 22px; line-height: 1;
    padding: 0 4px;
  }
  .cal-day-note-close:hover { color: var(--text); }
  .cal-day-note-hint {
    font-size: 12px; color: var(--text-soft);
    background: rgba(96, 165, 250, 0.08);
    border-left: 2px solid var(--blue);
    padding: 6px 10px;
    border-radius: 4px;
  }
  .cal-day-note-text {
    width: 100%;
    background: var(--panel-2);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px 10px;
    font: inherit;
    font-size: 13.5px;
    resize: vertical;
    min-height: 88px;
  }
  .cal-day-note-text:focus {
    outline: none;
    border-color: var(--blue);
  }
  .cal-day-note-actions {
    display: flex; align-items: center; gap: 8px;
  }
  .cal-event-time {
    font-size: 10.5px; font-weight: 600;
    color: color-mix(in srgb, var(--ev-color) 75%, white);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    margin-bottom: 1px;
  }
  /* Title — Google-Calendar style: wraps to a second line if there's room,
     hard-clipped via line-clamp once the tile runs out of vertical space. */
  .cal-event-title {
    font-weight: 600; color: var(--text);
    word-break: break-word;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  /* Week-grid tiles only: the job name is a click-through to Job Detail
     (rest of the tile opens the day card). Today-view mirror tiles are
     excluded — their whole tile opens the day card, no separate hotspot. */
  .cal-event:not(.today-cal-event) .cal-event-title:hover {
    text-decoration: underline;
    cursor: pointer;
  }
  .cal-event-sub {
    font-size: 10.5px; color: var(--text-soft);
    word-break: break-word;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  /* Compact mode for very short events (< ~36px tall): collapse to a single
     line so the tile stays legible instead of stacking time over a clipped
     title. Triggered by a class added in renderCalendar. */
  .cal-event.cal-event-compact {
    padding: 2px 7px 2px 8px;
    flex-direction: row; gap: 6px; align-items: baseline;
  }
  .cal-event.cal-event-compact .cal-event-time {
    margin-bottom: 0; flex-shrink: 0;
  }
  .cal-event.cal-event-compact .cal-event-title {
    -webkit-line-clamp: 1; flex: 1 1 auto;
  }
  .cal-event.cal-event-compact .cal-event-sub { display: none; }

  /* Color-cycle button — small swatch in the top-right of each tile. Click
     advances through Matt's 4-stop GCal coding (regular → set time →
     tentative → time off → regular). Plain tile click still navigates as
     before; this button stops propagation so the two gestures don't collide. */
  .cal-event-color-cycle {
    position: absolute; top: 4px; right: 4px;
    width: 12px; height: 12px;
    border-radius: 50%;
    border: 1.5px solid rgba(255,255,255,0.35);
    box-shadow: 0 0 0 1px rgba(0,0,0,0.4), inset 0 0 0 1px rgba(255,255,255,0.12);
    cursor: pointer; padding: 0;
    opacity: 0.85;
    transition: transform 0.12s, opacity 0.12s, box-shadow 0.12s;
    z-index: 3;
  }
  .cal-event-color-cycle:hover {
    transform: scale(1.35);
    opacity: 1;
    box-shadow: 0 0 0 2px rgba(255,255,255,0.85), inset 0 0 0 1px rgba(0,0,0,0.4);
  }
  .cal-event.cal-event-compact .cal-event-color-cycle {
    top: 50%; transform: translateY(-50%);
    width: 10px; height: 10px;
  }
  .cal-event.cal-event-compact .cal-event-color-cycle:hover {
    transform: translateY(-50%) scale(1.35);
  }

  /* Color-picker popup menu — anchored next to the swatch, floats above
     all calendar content. Body-mounted (position:fixed) so it escapes any
     overflow:hidden on the event tile or day column. */
  .cal-event-color-menu {
    position: fixed;
    z-index: 9999;
    background: var(--panel, #1a2030);
    border: 1px solid var(--border, #2a3347);
    border-radius: 8px;
    box-shadow: 0 8px 20px rgba(0,0,0,0.45);
    padding: 4px;
    min-width: 140px;
    display: flex; flex-direction: column;
    gap: 2px;
    user-select: none;
  }
  .cal-event-color-option {
    display: flex; align-items: center; gap: 8px;
    width: 100%;
    padding: 6px 8px;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--text, #e5e7eb);
    font-size: 12px; font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: background 100ms ease;
  }
  .cal-event-color-option:hover { background: rgba(255,255,255,0.06); }
  .cal-event-color-option.is-current { background: rgba(255,255,255,0.04); }
  .cal-event-color-option-swatch {
    width: 12px; height: 12px;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.25);
    flex: 0 0 auto;
  }
  .cal-event-color-option-label { flex: 1 1 auto; }
  .cal-event-color-option-check {
    color: var(--text-muted, #9ca3af);
    font-size: 11px;
    flex: 0 0 auto;
  }
  [data-theme="light"] .cal-event-color-menu {
    background: #fff;
    border-color: rgba(0,0,0,0.12);
    box-shadow: 0 8px 20px rgba(0,0,0,0.18);
  }
  [data-theme="light"] .cal-event-color-option { color: #1f2937; }
  [data-theme="light"] .cal-event-color-option:hover { background: rgba(0,0,0,0.05); }
  [data-theme="light"] .cal-event-color-option.is-current { background: rgba(0,0,0,0.035); }
  [data-theme="light"] .cal-event-color-option-swatch {
    border-color: rgba(0,0,0,0.18);
  }
  .job-title .archived-chip {
    font-size: 10.5px; padding: 1px 6px; margin-left: 6px;
    border-radius: 100px; text-transform: uppercase;
    letter-spacing: 0.05em; vertical-align: middle;
    background: rgba(251,146,60,0.15); color: var(--orange);
    border: 1px solid rgba(251,146,60,0.3);
  }
  .job-sub-name {
    font-size: 10.5px; color: var(--text-subtle); margin-top: 2px;
    display: flex; gap: 4px;
  }

  .client-col { display: flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden; }
  .client-col::before { content: '👤'; font-size: 12px; opacity: 0.7; flex-shrink: 0; }
  .client-link {
    font-size: 14px; font-style: italic; color: var(--blue-light);
    text-decoration: none; word-break: break-word;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    transition: color 0.15s;
  }
  .client-link:hover { color: var(--blue-bright); text-decoration: underline; }
  .client-missing { color: var(--text-muted); font-size: 12px; font-style: italic; }
  .match-btn {
    background: rgba(167,139,250,0.12); border: 1px solid rgba(167,139,250,0.35);
    color: var(--purple); padding: 3px 9px; border-radius: 6px;
    font-size: 10.5px; font-family: inherit; cursor: pointer;
    transition: background 0.15s;
  }
  .match-btn:hover { background: rgba(167,139,250,0.22); }
  /* Tiny edit-pencil button for re-matching an already-matched client.
     Sits inline next to the client-link on pipeline rows and on Job Detail.
     2026-04-29: hover-only by default to reduce visual noise. The parent
     row's :hover state un-hides it. Still visible on Job Detail (which
     isn't a row) so it stays discoverable there. */
  .rematch-btn {
    background: none; border: none; cursor: pointer;
    color: var(--text-subtle); font-family: inherit; font-size: 12px;
    padding: 1px 5px; margin-left: 4px; border-radius: 4px;
    vertical-align: baseline; transition: opacity 0.12s, background 0.15s, color 0.15s;
    opacity: 0;
  }
  /* Reveal on row hover, focus-within (keyboard nav), or when the button
     itself is focused. Job Detail and Client Detail use .rematch-btn-always
     (added below) to keep the pencil visible at all times since they're not
     row-based. */
  tr:hover .rematch-btn,
  .pt-card:hover .rematch-btn,
  .client-row:hover .rematch-btn,
  .rematch-btn:focus,
  .rematch-btn:focus-visible,
  .rematch-btn-always {
    opacity: 1;
  }
  .rematch-btn:hover { background: rgba(167,139,250,0.18); color: var(--purple); }

  /* Match-modal: mark the client currently assigned to the job. */
  .modal-row.match-current { border-left: 3px solid var(--purple); }
  .match-current-badge {
    display: inline-block; margin-left: 6px; padding: 1px 7px;
    border-radius: 999px; font-size: 10px; font-weight: 600;
    background: rgba(167,139,250,0.16); border: 1px solid rgba(167,139,250,0.4);
    color: var(--purple); vertical-align: middle;
  }

  .addr-col { display: flex; align-items: flex-start; gap: 5px; min-width: 0; }
  .addr-col::before { content: '📍'; font-size: 11px; opacity: 0.7; flex-shrink: 0; margin-top: 3px; }
  .addr-link {
    color: var(--text-soft); text-decoration: none; font-size: 12.5px;
    overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
    -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    transition: color 0.15s;
  }
  .addr-link:hover { color: var(--blue-lighter); text-decoration: underline; }
  .addr-missing { color: var(--text-subtle); font-size: 11px; font-style: italic; }

  /* Dropdown-like status cells */
  .status-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .status-select {
    width: 100%; padding: 7px 24px 7px 10px;
    font-size: 12px; font-family: inherit; font-weight: 500;
    background: var(--panel-3) url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3e%3cpath d='M1 1l4 4 4-4' stroke='%236f83a8' stroke-width='1.4' fill='none'/%3e%3c/svg%3e") no-repeat right 10px center;
    border: 1px solid var(--border); border-radius: 10px;
    color: var(--text); cursor: pointer;
    -webkit-appearance: none; appearance: none;
    transition: border 160ms ease, background 160ms ease, color 160ms ease;
  }
  .status-select:hover { border-color: var(--border-strong); background-color: var(--row-hover); }
  /* When a value is selected, the dropdown gets an inline style from
     statusSelectStyle() with the exact CC label color. The .has-value
     class just marks the state — no color overrides here so inline wins. */
  .status-select.has-value { font-weight: 500; }
  /* Neutral cells (Project Stage / Inspection / Permit / Billing in the
     Dashboard grid) stay panel-3 + soft text regardless of their value so
     only the Status column draws the eye. The CC inline color is
     suppressed in renderStatusCell when opts.neutral is true; this rule
     locks the visual treatment + dials font-weight back to normal so
     neutral cells visually defer to Status. */
  .status-select.neutral,
  .status-select.neutral.has-value {
    background-color: var(--panel-3);
    color: var(--text-soft);
    border-color: var(--border);
    font-weight: 400;
  }
  .status-select.neutral:hover {
    background-color: var(--row-hover);
    color: var(--text);
  }
  .status-select:disabled { opacity: 0.4; cursor: not-allowed; }
  .status-select option {
    background: var(--panel); color: var(--text);
  }
  .status-multi-hint {
    font-size: 10.5px; color: var(--text-subtle); margin-top: 4px;
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  }
  /* Duplicate-label cleanup chip — only renders when a project has 2+
     labels in a single category. Click × to drop just that one. */
  .status-multi-chip {
    display: inline-flex; align-items: center; gap: 3px;
    background: rgba(248,113,113,0.10);
    border: 1px solid rgba(248,113,113,0.32);
    color: var(--red-text);
    font-size: 10px; font-weight: 500;
    padding: 1px 6px;
    border-radius: 999px;
    cursor: pointer;
  }
  .status-multi-chip:hover {
    background: rgba(248,113,113,0.20);
    color: #fecaca;
  }
  .status-multi-chip span { font-size: 11px; line-height: 1; }

  .action-stack {
    display: flex; gap: 4px; justify-content: flex-end;
  }
  /* On the main Dashboard list each row shows only a single CC icon —
     compact square button so the row height stays tight. */
  .job-row .action-stack .action-btn {
    width: 32px; height: 32px; padding: 0;
    border-radius: 6px;
  }
  .job-row .action-stack .action-btn .icon { width: 16px; height: 16px; }
  .job-row .action-stack .action-btn .icon svg { width: 16px; height: 16px; }
  .action-btn {
    padding: 7px 4px; border-radius: 7px;
    font-size: 10.5px; font-family: inherit; font-weight: 500;
    cursor: pointer; border: 1px solid transparent;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px; text-decoration: none; text-align: center;
    transition: background 0.15s, border 0.15s, opacity 0.15s;
    min-width: 0;
  }
  .action-btn .icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 14px; height: 14px; flex-shrink: 0;
  }
  .action-btn .icon svg { width: 14px; height: 14px; }
  .action-btn .label { line-height: 1.1; font-size: 10.5px; }
  .action-btn.cal  { background: rgba(251,146,60,0.12); color: var(--orange); border-color: rgba(251,146,60,0.28); }
  .action-btn.cal:hover  { background: rgba(251,146,60,0.22); }
  .action-btn.meet { background: rgba(244,114,182,0.12); color: var(--pink); border-color: rgba(244,114,182,0.28); }
  .action-btn.meet:hover { background: rgba(244,114,182,0.22); }
  .action-btn.cc   { background: rgba(59,130,246,0.12); color: var(--blue-bright); border-color: rgba(59,130,246,0.28); }
  .action-btn.cc:hover   { background: rgba(59,130,246,0.22); }
  .action-btn.permit { background: rgba(234,179,8,0.12); color: var(--amber-bright); border-color: rgba(234,179,8,0.28); }
  .action-btn.permit:hover { background: rgba(234,179,8,0.22); }
  .action-btn.permit.has-permit { background: rgba(16,185,129,0.12); color: var(--green-soft); border-color: rgba(16,185,129,0.28); }
  .action-btn.permit.has-permit:hover { background: rgba(16,185,129,0.22); }
  .action-btn.phone { background: rgba(34,197,94,0.12); color: var(--green-text); border-color: rgba(34,197,94,0.28); }
  .action-btn.phone:hover { background: rgba(34,197,94,0.22); }
  .action-btn.email { background: rgba(168,85,247,0.12); color: var(--purple); border-color: rgba(168,85,247,0.28); }
  .action-btn.email:hover { background: rgba(168,85,247,0.22); }
  /* Phone / Email buttons fall back to a muted slate look when the linked
     QBO customer has no phone or email on file. Click still works — it
     opens the QBO customer page so Matt can add the missing field. */
  .action-btn.action-btn-missing {
    background: rgba(148,163,184,0.10) !important;
    color: var(--text-muted) !important;
    border-color: rgba(148,163,184,0.22) !important;
  }
  .action-btn.action-btn-missing:hover {
    background: rgba(148,163,184,0.18) !important;
    color: var(--text-soft) !important;
  }
  /* Bare .action-btn.qbo (no subclass) — used by the new QuickBooks split
     button's primary half. Picks up the same purple as the QBO history
     button family so the whole QuickBooks group reads as one color. */
  .action-btn.qbo { background: rgba(139,92,246,0.12); color: var(--purple); border-color: rgba(139,92,246,0.28); }
  .action-btn.qbo:hover { background: rgba(139,92,246,0.22); }
  .action-btn.qbo.history { background: rgba(139,92,246,0.12); color: var(--purple); border-color: rgba(139,92,246,0.28); }
  .action-btn.qbo.history:hover { background: rgba(139,92,246,0.22); }
  .action-btn.qbo.invoice,
  .action-btn.qbo.estimate {
    background: rgba(52,211,153,0.12); color: var(--green-soft); border-color: rgba(52,211,153,0.28);
  }
  .action-btn.qbo.invoice:hover,
  .action-btn.qbo.estimate:hover { background: rgba(52,211,153,0.22); }
  .action-btn.archive {
    background: rgba(148,163,184,0.10); color: var(--text-soft); border-color: rgba(148,163,184,0.28);
  }
  .action-btn.archive:hover { background: rgba(148,163,184,0.20); color: var(--text); }
  .action-btn.archive.is-archived {
    background: rgba(251,146,60,0.12); color: var(--orange); border-color: rgba(251,146,60,0.30);
  }
  .action-btn.archive.is-archived:hover { background: rgba(251,146,60,0.22); }
  .action-btn:disabled { opacity: 0.5; cursor: wait; }

  /* ── Split button + dropdown groups ─────────────────────────────────────
     The unified 4-button action strip used on Job Detail + pipeline tiles.
     Each group is a "split button" — clicking the LABEL fires the primary
     action; clicking the CHEVRON opens a dropdown of secondary actions.
     The "More ⋯" group has no primary; the chevron is the whole button. */
  .action-group {
    position: relative;
    display: inline-flex;
    align-items: stretch;
    /* min-width keeps the split button readable at narrow card widths */
    min-width: 0;
  }
  /* Buttons inside an action-group AND the standalone CompanyCam button
     (which is intentionally outside any group since it has no dropdown)
     all adopt the sleeker pipeline-tile look — horizontal (icon + label
     inline), shorter height, smaller padding. Keeps the new strip
     consistent across Job Detail and the pipelines, and ensures the
     CompanyCam button matches the height of its split-button neighbors. */
  .action-group .action-btn,
  .action-group .action-btn-chevron,
  .detail-actions > .action-btn.cc,
  .pt-actions > .action-btn.cc {
    flex-direction: row;
    align-items: center;
    gap: 6px;
    height: 32px;
    padding: 0 10px;
    font-size: 11.5px;
    line-height: 1;
  }
  .action-group .action-btn .icon,
  .detail-actions > .action-btn.cc .icon,
  .pt-actions > .action-btn.cc .icon { width: 14px; height: 14px; }
  .action-group .action-btn .icon svg,
  .detail-actions > .action-btn.cc .icon svg,
  .pt-actions > .action-btn.cc .icon svg { width: 14px; height: 14px; }
  .action-group .action-btn .label,
  .detail-actions > .action-btn.cc .label,
  .pt-actions > .action-btn.cc .label { font-size: 11.5px; line-height: 1; }

  .action-group .action-btn-primary {
    /* Right side flat so the chevron sits flush against it. */
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
    padding-right: 8px;
  }
  .action-group .action-btn-chevron {
    /* Chevron-only narrow button on the right of the split. Same color
       class as the primary half so they read as one button. */
    border-top-left-radius: 0 !important;
    border-bottom-left-radius: 0 !important;
    margin-left: -1px;          /* merge the borders so it looks like one button */
    padding: 0 8px;
    min-width: 22px;
    justify-content: center;
    font-family: inherit;
    cursor: pointer;
    /* When a chevron is the WHOLE button (no primary, e.g. More), it gets
       its own border + bg via .action-btn class — the next rule below
       handles that case. */
  }
  /* "More" group has no primary action — the whole button IS the chevron.
     Restore full radius and slightly more horizontal padding so the
     "More ⋯" label sits comfortably. */
  .action-group.no-primary .action-btn-chevron {
    border-radius: 7px !important;
    margin-left: 0;
    padding: 0 12px;
    min-width: 60px;
  }
  .action-group.no-primary .action-btn-chevron .label {
    font-size: 11.5px;
    font-weight: 500;
  }
  /* Open state — chevron stays visually depressed while menu is open. */
  .action-group.is-open .action-btn-chevron {
    background: rgba(255,255,255,0.06);
  }

  .action-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 200px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.5);
    padding: 4px;
    z-index: 100;
    display: none;
  }
  .action-group.is-open .action-dropdown { display: block; }
  .action-dropdown-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    background: transparent;
    color: var(--text);
    border: none;
    border-radius: 5px;
    font-size: 12px;
    font-family: inherit;
    cursor: pointer;
    text-align: left;
    text-decoration: none;     /* in case an <a> is used as an item */
  }
  .action-dropdown-item:hover:not(:disabled) {
    background: rgba(59,130,246,0.14);
    color: var(--text-strong);
  }
  .action-dropdown-item:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }
  .action-dropdown-item .icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-soft);
  }
  .action-dropdown-item .icon svg { width: 14px; height: 14px; }
  .action-dropdown-divider {
    height: 1px;
    background: var(--border);
    margin: 4px 2px;
  }

  /* ── Job detail drawer (Phase 4.1) ──────────────────────────────────
     When viewing a Job Detail, the container becomes a right-side
     drawer overlay so the previous list/pipeline view stays visible
     behind a dimmed scrim. Slide-in from the right; backdrop fades.
     applyViewVisibility (06-render.js) adds .as-drawer to
     #job-detail-view and unhides #job-detail-backdrop when active. */
  .job-detail-backdrop {
    position: fixed; inset: 0;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 90;
    opacity: 0;
    transition: opacity 200ms ease;
    pointer-events: none;
  }
  .job-detail-backdrop[hidden] { display: none; }
  .job-detail-backdrop.is-open {
    opacity: 1;
    pointer-events: auto;
  }
  [data-theme="light"] .job-detail-backdrop {
    background: rgba(15, 23, 42, 0.32);
  }
  #job-detail-view.as-drawer {
    position: fixed;
    top: 0; right: 0; bottom: 0;
    width: min(900px, 65vw);
    background: var(--bg);
    border-left: 1px solid var(--border);
    box-shadow: -12px 0 36px rgba(0, 0, 0, 0.45);
    padding: 24px 28px;
    overflow-y: auto;
    z-index: 100;
    transform: translateX(100%);
    transition: transform 240ms cubic-bezier(0.22, 1, 0.36, 1);
  }
  #job-detail-view.as-drawer.is-open {
    transform: translateX(0);
  }
  /* Expanded mode — toggled via the Expand button in the detail topbar.
     Width grows to fill the viewport minus the 250px sidebar so the nav
     stays visible (rule: never trap the user on the detail view). */
  #job-detail-view.as-drawer.is-expanded {
    width: calc(100vw - 250px);
  }
  @media (max-width: 900px) {
    /* On narrow screens the sidebar is already collapsed; expanded mode
       just goes edge-to-edge. */
    #job-detail-view.as-drawer.is-expanded { width: 100vw; }
  }
  .detail-expand-btn {
    display: inline-flex; align-items: center; gap: 6px;
    margin-left: 8px;
  }
  .detail-expand-icon { font-size: 14px; line-height: 1; }
  [data-theme="light"] #job-detail-view.as-drawer {
    box-shadow: -12px 0 36px rgba(15, 23, 42, 0.18);
  }
  /* Mobile / narrow screens: drawer becomes full-width so the back-arrow
     remains reachable without horizontal scroll. */
  @media (max-width: 900px) {
    #job-detail-view.as-drawer { width: 100vw; }
  }

  /* (Floating tools-launcher FAB + popover CSS removed 2026-07-05 — the
     electrical utilities are now the "Toolbox" sidebar hub. Styling comes
     from the generic .nav-hub / .nav-sub rules.) */

  /* ── Empty / loading ──
     Polished empty state: solid-but-soft border instead of dashed, slightly
     more breathing room, optional .empty-state-icon slot at the top, a
     stronger headline so the call-to-action reads first, and softer body
     copy so the hint feels like a suggestion not an error. Dashed borders
     read as 'broken' in modern UI; solid + low-contrast reads as
     'intentional waiting state'. */
  .empty-state {
    text-align: center; padding: 72px 28px;
    color: var(--text-muted);
    background: var(--panel);
    border: 1px solid var(--border-subtle);
    border-radius: 18px;
  }
  .empty-state-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 56px; height: 56px; border-radius: 16px;
    background: var(--blue-soft); color: var(--blue-bright);
    margin: 0 auto 16px;
  }
  .empty-state-icon svg { width: 28px; height: 28px; }
  .empty-state h3 {
    font-size: 17px; font-weight: 600; color: var(--text-strong);
    margin-bottom: 8px; letter-spacing: -0.005em;
  }
  .empty-state p { font-size: 13px; line-height: 1.5; max-width: 420px; margin: 0 auto; }
  .spinner {
    display: inline-block; width: 16px; height: 16px;
    border: 2px solid var(--border); border-top-color: var(--blue);
    border-radius: 50%; animation: spin 0.8s linear infinite;
    vertical-align: middle; margin-right: 6px;
  }
  /* Smaller in-button spinner — used by Push to QBO, etc. while a write
     round-trip is in flight. Sized to sit comfortably on a button-small
     button without forcing line-height changes. */
  .spinner-inline {
    display: inline-block; width: 11px; height: 11px;
    border: 2px solid currentColor; border-top-color: transparent;
    border-radius: 50%; animation: spin 0.7s linear infinite;
    vertical-align: -1px; margin-right: 5px; opacity: 0.85;
  }
  @keyframes spin { to { transform: rotate(360deg); } }

  /* Refresh button spinner — applied while loadEverything is in flight,
     regardless of which view is active. Spins the inline SVG icon and
     dims the button so you can see at a glance that a refresh is running.
     Cleared in loadEverything's finally block so a fetch error or timeout
     can't leave the button perma-spinning. */
  .refresh-btn-loading { opacity: 0.65; cursor: progress; }
  .refresh-btn-loading .btn-icon {
    animation: spin 0.9s linear infinite;
    transform-origin: center;
  }

  /* ── Toast ── */
  .toast {
    position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
    padding: 12px 18px; font-size: 13px; color: var(--text);
    box-shadow: 0 8px 24px rgba(0,0,0,0.6); z-index: 9999;
    max-width: 90vw; opacity: 0; pointer-events: none;
    transition: opacity 0.2s, transform 0.2s;
  }
  .toast.show { opacity: 1; transform: translateX(-50%) translateY(-4px); pointer-events: auto; }
  .toast.error { border-color: var(--toast-error-border); color: var(--red-bright); background: var(--toast-error-bg); }
  .toast.success { border-color: var(--toast-success-border); color: var(--green); background: var(--toast-success-bg); }
  /* Inline undo / action button on a toast — sits next to the message text. */
  .toast-action {
    margin-left: 14px;
    background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.18);
    color: inherit; font-family: inherit; font-size: 12px; font-weight: 600;
    padding: 4px 10px; border-radius: 6px; cursor: pointer;
    text-transform: uppercase; letter-spacing: 0.04em;
    transition: background 0.12s;
  }
  .toast-action:hover { background: rgba(255,255,255,0.18); }

  /* ── Modal ── */
  .modal-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,0.7);
    display: flex; align-items: center; justify-content: center;
    z-index: 10000; padding: 16px;
  }
  .modal-overlay.hidden { display: none; }
  .modal {
    background: var(--panel); border: 1px solid var(--border); border-radius: 14px;
    max-width: 560px; width: 100%; max-height: 85vh; overflow-y: auto;
    padding: 22px; box-shadow: 0 8px 32px rgba(0,0,0,0.7);
  }
  .modal h2 { font-size: 16px; color: var(--text-strong); margin-bottom: 6px; }
  .modal .sub { font-size: 12px; color: var(--text-muted); margin-bottom: 14px; }
  .modal-row {
    padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px;
    margin-bottom: 6px; cursor: pointer; transition: background 0.15s, border 0.15s;
  }
  .modal-row:hover { background: var(--row-hover); border-color: var(--blue); }
  .modal-row .n { font-size: 14px; color: var(--text); font-weight: 500; }
  .modal-row .m { font-size: 11px; color: var(--text-muted); margin-top: 2px; }
  .modal-close { margin-top: 10px; text-align: right; }
  .modal-close button {
    background: none; border: 1px solid var(--border); border-radius: 6px;
    padding: 6px 12px; color: var(--text-soft); font-family: inherit;
    font-size: 12px; cursor: pointer;
  }
  .modal-close button:hover { color: var(--text); border-color: var(--border-strong); }

  /* ── Schedule Job modal — form layout + dark-themed inputs ── */
  .sj-form {
    display: flex; flex-direction: column; gap: 12px;
    margin-bottom: 16px;
  }
  .sj-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  .sj-field { display: flex; flex-direction: column; gap: 5px; }
  .sj-field label {
    font-size: 11px; color: var(--text-soft);
    text-transform: uppercase; letter-spacing: 0.06em;
    font-weight: 600;
  }
  .sj-field input, .sj-field select, .sj-field textarea {
    background: var(--panel); border: 1px solid var(--border); border-radius: 6px;
    color: var(--text); font-family: inherit; font-size: 13px;
    padding: 8px 10px; width: 100%; box-sizing: border-box;
    transition: border-color 0.12s, background 0.12s;
  }
  .sj-field input:focus, .sj-field select:focus, .sj-field textarea:focus {
    outline: none; border-color: var(--blue);
    background: var(--panel-2);
  }
  .sj-field textarea { resize: vertical; min-height: 60px; font-family: inherit; }
  /* Date/time native pickers — dark mode hint so the calendar popups don't
     blast white. Modern browsers respect color-scheme on the input.
     Light theme must flip it back or the native calendar icon renders
     white-on-white (invisible "calendar button", reported 2026-07-17). */
  .sj-field input[type=date], .sj-field input[type=time] { color-scheme: dark; }
  [data-theme="light"] .sj-field input[type=date],
  [data-theme="light"] .sj-field input[type=time] { color-scheme: light; }
  .sj-actions {
    display: flex; justify-content: flex-end; gap: 8px;
    padding-top: 4px; border-top: 1px solid var(--border); margin-top: 4px; padding-top: 14px;
  }
  .sj-btn {
    background: none; border: 1px solid var(--border); border-radius: 6px;
    padding: 7px 16px; color: var(--text); font-family: inherit;
    font-size: 12.5px; font-weight: 600; cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .sj-btn.sj-cancel:hover { color: var(--text); border-color: var(--border-strong); }
  .sj-btn.sj-primary {
    background: var(--blue); border-color: var(--blue); color: var(--text-strong);
  }
  .sj-btn.sj-primary:hover:not(:disabled) { background: var(--blue-hover); border-color: var(--blue-hover); }
  .sj-btn:disabled { opacity: 0.6; cursor: progress; }
  .sj-after-hours-link {
    font-size: 11px; color: var(--text-muted); text-decoration: none; cursor: pointer;
  }
  .sj-after-hours-link:hover { color: var(--blue); }

  /* Today view — single-page summary of what's on Matt's plate right now. */
  .today-pane { display: flex; flex-direction: column; gap: 18px; }

  /* Half-width row: calendar tile (left) + Peak Stuff reminders panel
     (right). Stacks vertically below 980px so the reminders panel
     doesn't get crushed on narrow viewports.
     2026-05-25 (afternoon) — reminders panel is now position:absolute
     inside its grid cell so its content height doesn't push the row
     taller than the calendar tile needs. Calendar dictates row height;
     reminders fills that space and scrolls the list internally when it
     has more items than fit. */
  .today-cal-rem-row {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 16px;
    align-items: stretch;
  }
  .today-rem-third {
    position: relative;
    min-height: 240px;  /* failsafe when calendar tile is unusually short */
  }
  .today-cal-half > .pipeline-tile,
  .today-rem-half > .today-reminders-panel,
  .today-cal-twothirds > .pipeline-tile {
    height: 100%;
  }
  .today-rem-third > .today-reminders-panel {
    position: absolute;
    inset: 0;
  }
  @media (max-width: 980px) {
    .today-cal-rem-row { grid-template-columns: 1fr; }
    /* On narrow viewports the row stacks, so the absolute positioning
       trick breaks — restore in-flow so each tile keeps its content. */
    .today-rem-third { position: static; min-height: 0; }
    .today-rem-third > .today-reminders-panel { position: static; height: auto; }
  }

  /* Today's photos strip — today-only R2 uploads as a filmstrip under the
     calendar/reminders row (07-views.js fillTodayPhotosStrip). Tiles open the
     shared Photos lightbox; the strip self-hides when the day has no photos. */
  .today-photos-strip {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-card);
    padding: 12px 14px;
  }
  .today-photos-head {
    display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px;
  }
  .today-photos-title { font-size: 14px; font-weight: 600; color: var(--text); }
  .today-photos-count {
    font-size: 11px; font-weight: 600; color: var(--text-muted);
    background: var(--surface-2, rgba(128, 128, 128, 0.14));
    border-radius: 999px; padding: 1px 8px; font-variant-numeric: tabular-nums;
  }
  .today-photos-row {
    display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px;
    scrollbar-width: thin;
  }
  .today-photo-tile {
    position: relative; flex: 0 0 auto;
    width: 76px; height: 76px; padding: 0;
    border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
    background: rgba(128, 128, 128, 0.12); cursor: pointer;
    transition: transform 0.08s ease, box-shadow 0.08s ease;
  }
  .today-photo-tile:hover { transform: translateY(-1px); box-shadow: var(--shadow-card); }
  .today-photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .today-photo-badge {
    position: absolute; left: 4px; bottom: 4px;
    min-width: 18px; height: 18px; padding: 0 4px;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 700; color: #fff;
    background: rgba(0, 0, 0, 0.6); border-radius: 6px; letter-spacing: 0.3px;
  }

  /* Today's focused-day calendar tile — read-only mirror of the Calendar
     tab's focused-day view. Tile chrome matches .pipeline-tile; inside,
     an axis rail (40px) + day column flex side-by-side. Re-uses the
     .cal-day-col-body / .cal-event / .cal-hour-line classes from the
     Calendar tab styling so visuals stay aligned. */
  .today-cal-tile-focused .today-cal-tile-body {
    padding: 0;
  }
  .today-cal-tile-focused .today-cal-allday {
    display: flex; flex-direction: column; gap: 3px;
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
    background: var(--panel-2, var(--panel));
  }
  .today-cal-allday-row {
    display: flex; align-items: center; gap: 6px;
    font-size: 11.5px; color: var(--text-soft);
    line-height: 1.4;
  }
  .today-cal-allday-dot {
    width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px;
  }
  .today-cal-allday-text {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .today-cal-grid {
    display: flex; align-items: stretch;
    overflow: auto;
  }
  .today-cal-axis {
    position: relative; flex: 0 0 44px;
    border-right: 1px solid var(--border);
    background: var(--panel-3);
  }
  .today-cal-axis-label {
    position: absolute; left: 6px; right: 4px;
    font-size: 10px; color: var(--text-muted);
    transform: translateY(-50%);
    font-variant-numeric: tabular-nums;
  }
  .today-cal-day-col {
    flex: 1 1 auto; min-width: 200px;
  }
  /* Jump-to-Calendar button in the tile header */
  .today-cal-jump-btn {
    appearance: none; border: 1px solid var(--border);
    background: var(--panel-3); color: var(--text-soft);
    font-family: inherit; font-size: 11px; font-weight: 600;
    padding: 3px 8px; border-radius: 5px;
    cursor: pointer; margin-left: auto;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .today-cal-jump-btn:hover {
    background: rgba(96, 165, 250, 0.15);
    border-color: rgba(96, 165, 250, 0.4);
    color: var(--blue-light);
  }
  /* 2026-05-25 — promoted variant. Today's calendar tile no longer
     leans on a tiny ghost link for "Open in Calendar" — the button
     is the primary out from the glance tile. */
  .today-cal-jump-btn-lg {
    font-size: 13px; padding: 7px 14px; border-radius: 7px;
  }
  /* Event tiles inside Today's focused-day tile — same .cal-event base
     style as the Calendar tab; this overlay adds a click affordance. */
  .today-cal-event {
    cursor: pointer;
  }
  .today-cal-event-note {
    position: absolute; top: 2px; left: 4px; right: 4px;
    font-size: 10px; color: var(--text-soft);
    background: rgba(0, 0, 0, 0.25); border-radius: 3px;
    padding: 1px 5px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    pointer-events: none;
  }

  /* Reminders panel — mirrors .pipeline-tile visual language but with
     its own quick-add input + list of VTODO rows. Source of truth is
     iCloud; this is a glance mirror polled every 3 min by the Today
     view. Writes go through icloud-reminders.js + are reconciled on
     the next poll. */
  .today-reminders-panel {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    padding: 14px 16px;
    box-shadow: var(--shadow-card);
    display: flex; flex-direction: column;
    min-height: 240px;
  }
  .today-reminders-head {
    display: flex; align-items: baseline; gap: 10px;
    margin-bottom: 10px;
  }
  .today-reminders-head h3 {
    margin: 0; font-size: 14px; color: var(--text);
  }
  .today-reminders-sub {
    font-size: 11px; color: var(--text-muted);
    margin-left: auto;
    font-variant-numeric: tabular-nums;
  }
  .today-reminders-error {
    padding: 14px 12px;
    font-size: 12.5px;
    color: var(--red-text);
    background: rgba(248, 113, 113, 0.08);
    border: 1px solid rgba(248, 113, 113, 0.3);
    border-radius: 8px;
  }
  .today-reminders-empty {
    padding: 18px 6px;
    font-size: 12px; color: var(--text-muted);
    font-style: italic;
  }
  .today-reminders-quickadd { margin-bottom: 8px; }
  .today-reminders-quickadd input {
    width: 100%;
    padding: 7px 10px;
    background: var(--panel-3);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    font: inherit; font-size: 12.5px;
  }
  .today-reminders-quickadd input:focus { outline: 0; border-color: var(--blue, #2563eb); }
  .today-reminders-list {
    display: flex; flex-direction: column;
    gap: 2px;
    overflow-y: auto;
    flex: 1 1 0;
    min-height: 0;
    /* No max-height — the panel itself is bounded by the calendar tile's
       height (see .today-rem-third absolute positioning); the list fills
       whatever room is left after head + quickadd and scrolls internally
       when overflowing. */
  }
  .reminder-row {
    display: flex; align-items: flex-start;
    gap: 10px;
    padding: 7px 4px;
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .reminder-row:last-child { border-bottom: 0; }
  .reminder-row-overdue { background: rgba(248,113,113,0.06); border-radius: 4px; }
  .reminder-row-done .reminder-summary { color: var(--text-muted); text-decoration: line-through; }
  .reminder-check {
    flex: 0 0 20px;
    width: 20px; height: 20px;
    padding: 0;
    border: 1.5px solid var(--border-strong, var(--border));
    background: transparent;
    color: var(--green-text, #22c55e);
    border-radius: 5px;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 13px;
    margin-top: 1px;
    transition: background 120ms ease, border-color 120ms ease;
  }
  .reminder-check:hover { border-color: var(--green-text, #22c55e); }
  .reminder-check.on {
    background: rgba(34, 197, 94, 0.14);
    border-color: var(--green-text, #22c55e);
  }
  .reminder-body {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column;
    gap: 3px;
  }
  .reminder-summary {
    font-size: 13px;
    color: var(--text);
    line-height: 1.35;
    word-break: break-word;
  }
  .reminder-meta {
    display: flex; align-items: center;
    gap: 6px;
    font-size: 11px;
    flex-wrap: wrap;
  }
  .reminder-due {
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
  }
  .reminder-due-today {
    color: var(--blue-light, #60a5fa);
    font-weight: 600;
  }
  .reminder-due-overdue {
    color: var(--red-text);
    font-weight: 600;
  }
  .reminder-snooze-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    border-radius: 999px;
    padding: 1px 8px;
    font-size: 10.5px;
    cursor: pointer;
    line-height: 1;
  }
  .reminder-snooze-btn:hover { color: var(--text); border-color: var(--border-strong); }
  /* Completed section toggle — sits between active rows and done rows. */
  .reminders-done-toggle {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 4px;
    margin-top: 4px;
    font-size: 11.5px; color: var(--text-muted);
    cursor: pointer;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
    user-select: none;
  }
  .reminders-done-toggle:hover { color: var(--text); }
  .reminders-done-arrow { font-size: 10px; }
  /* Clickable title that opens the inline edit panel. */
  .reminder-summary-open {
    cursor: pointer;
  }
  .reminder-summary-open:hover { color: var(--blue-light, #60a5fa); }
  /* Inline edit panel — appears below the clicked row. */
  .reminder-edit-panel {
    margin: 0 4px 6px 30px; /* indent past drag handle + checkbox */
    padding: 10px 12px;
    background: var(--panel-3, rgba(255,255,255,0.04));
    border: 1px solid var(--border);
    border-radius: 8px;
    display: flex; flex-direction: column;
    gap: 8px;
  }
  .rem-edit-title {
    width: 100%; box-sizing: border-box;
    padding: 6px 8px;
    background: var(--panel);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 5px;
    font: inherit; font-size: 13px;
  }
  .rem-edit-title:focus { outline: 0; border-color: var(--blue, #2563eb); }
  .rem-edit-date-row { display: flex; align-items: center; gap: 6px; }
  .rem-edit-date {
    flex: 1 1 auto;
    padding: 5px 8px;
    background: var(--panel);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 5px;
    font: inherit; font-size: 12.5px;
  }
  .rem-edit-date:focus { outline: 0; border-color: var(--blue, #2563eb); }
  .rem-edit-clear-date {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    border-radius: 5px;
    padding: 4px 9px;
    cursor: pointer;
    font-size: 13px; line-height: 1;
  }
  .rem-edit-clear-date:hover { color: var(--text); border-color: var(--border-strong); }
  .rem-edit-actions { display: flex; gap: 6px; }
  .rem-edit-save {
    padding: 4px 12px;
    background: var(--blue, #2563eb);
    color: #fff;
    border: none; border-radius: 5px;
    font: inherit; font-size: 12px; font-weight: 600;
    cursor: pointer;
  }
  .rem-edit-save:hover:not(:disabled) { background: var(--blue-light, #3b82f6); }
  .rem-edit-save:disabled { opacity: 0.5; cursor: default; }
  .rem-edit-cancel {
    padding: 4px 10px;
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 5px;
    font: inherit; font-size: 12px;
    cursor: pointer;
  }
  .rem-edit-cancel:hover { color: var(--text); border-color: var(--border-strong); }
  /* Drag-to-reorder affordance for undated reminder rows. */
  .reminder-drag-handle {
    flex: 0 0 auto;
    color: var(--text-muted);
    opacity: 0.45;
    cursor: grab;
    font-size: 15px;
    line-height: 1;
    padding: 2px 0;
    user-select: none;
    margin-top: 1px;
  }
  .reminder-row-draggable:hover .reminder-drag-handle { opacity: 0.85; }
  .reminder-row-dragging { opacity: 0.35; }
  /* Insertion-line indicators — appear above or below the target row,
     never as a container highlight. 0-spread box-shadow = no layout shift. */
  .reminder-row-insert-before { box-shadow: 0 -2px 0 0 var(--blue, #2563eb); }
  .reminder-row-insert-after  { box-shadow: 0  2px 0 0 var(--blue, #2563eb); }
  .today-date {
    font-size: 13px; color: var(--text-muted); font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    padding: 0 4px;
  }
  .today-section {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 10px; padding: 12px 14px;
  }
  .today-section-head {
    display: flex; align-items: baseline; gap: 8px;
    margin-bottom: 8px; padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
  }
  .today-section-title {
    font-size: 13.5px; font-weight: 600; color: var(--text);
  }
  .today-section-count {
    padding: 1px 8px; border-radius: 100px;
    background: rgba(96,165,250,0.15); color: var(--blue-light);
    font-size: 11px; font-weight: 600;
  }
  .today-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    align-items: baseline; gap: 18px;
    padding: 7px 6px; border-radius: 6px;
    cursor: pointer; transition: background 0.12s;
  }
  .today-row:hover { background: rgba(96,165,250,0.06); }
  /* Calendar event rows have a wider time column (the time range like
     "8:30am – 4:30pm" needs ~150px) and a generous middle gap so the
     event title doesn't run into the time. */
  .today-event-row {
    grid-template-columns: 150px minmax(0, 1fr) minmax(0, 1.2fr);
    gap: 18px;
    cursor: default;
  }
  .today-event-row:hover { background: transparent; }
  .today-row-time {
    font-size: 12px; color: var(--blue-light); font-weight: 600;
    font-variant-numeric: tabular-nums; white-space: nowrap;
  }
  .today-row-name {
    font-size: 13px; color: var(--text-strong); font-weight: 500;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .today-row-sub {
    font-size: 11.5px; color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .today-empty {
    padding: 8px 6px; font-size: 12px; color: var(--text-faint); font-style: italic;
  }

  /* Quote follow-up tile — one row per pending QBO estimate that's been
     waiting >7 days for a decision. Three lines per row: customer +
     age, estimate # + total + email, action cluster. */
  .today-followup-tile {}
  .today-followup-row {
    display: flex; flex-direction: column; gap: 4px;
    padding: 10px 12px;
    border-radius: 6px;
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.05));
  }
  .today-followup-row:last-child { border-bottom: 0; }
  .today-followup-row:hover { background: rgba(96,165,250,0.05); }
  .today-followup-main {
    display: flex; align-items: center; gap: 8px;
    font-size: 13.5px;
  }
  .today-followup-main strong { color: var(--text-strong); }
  .today-followup-job {
    color: var(--text-muted); font-size: 12.5px;
  }
  .today-followup-age {
    margin-left: auto;
    font-size: 10.5px; font-weight: 600;
    padding: 2px 8px;
    background: rgba(251, 191, 36, 0.14);
    color: var(--amber);
    border-radius: 999px;
    white-space: nowrap;
  }
  .today-followup-age-old {
    background: rgba(248, 113, 113, 0.16);
    color: var(--red-text);
  }
  .today-followup-meta {
    font-size: 12px; color: var(--text-muted);
    display: flex; gap: 10px; align-items: center;
    flex-wrap: wrap;
  }
  .today-followup-email {
    color: var(--text-soft);
    font-variant-numeric: tabular-nums;
  }
  .today-followup-email-missing {
    color: rgba(248,113,113,0.85);
    font-style: italic;
  }
  .today-followup-actions {
    display: flex; gap: 8px; align-items: center;
    margin-top: 2px;
  }
  .today-followup-actions .button[disabled] {
    opacity: 0.45; cursor: not-allowed;
  }
  .today-followup-link {
    font-size: 12px; color: var(--blue-light);
    text-decoration: none;
    padding: 4px 8px;
  }
  .today-followup-link:hover { text-decoration: underline; }
  .today-followup-hint {
    font-size: 11px; color: var(--text-faint);
    margin: 8px 12px 4px;
    font-style: italic;
  }

  /* Crew rows — Today feed "Crew today" tile (2026-05-20 expansion;
     2026-05-21 redesign to fold scheduled events into the row).
     Top line: dot · name · stats (hrs + jobs + live tick) · status badge.
     Sub-line: scheduled events chips for the day. Click row name opens
     the per-employee breakdown modal; click event chip opens the day-
     detail modal for that event. */
  .today-crew-row {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.12s;
    font-size: 13px;
  }
  .today-crew-row-top {
    display: grid;
    grid-template-columns: 14px minmax(110px, 1fr) auto auto;
    align-items: center;
    gap: 12px;
  }
  /* Scheduled-events sub-row */
  .today-crew-events {
    display: flex; flex-wrap: wrap;
    gap: 4px 6px;
    padding-left: 26px;  /* aligns under the name (dot + gap) */
    margin-top: 2px;
  }
  .today-crew-event {
    display: inline-flex; align-items: baseline; gap: 4px;
    padding: 2px 7px;
    border-radius: 4px;
    background: rgba(96, 165, 250, 0.08);
    border: 1px solid rgba(96, 165, 250, 0.18);
    color: var(--text);
    text-decoration: none;
    font-size: 11.5px;
    line-height: 1.3;
    max-width: 100%;
    overflow: hidden;
    transition: background 0.12s, border-color 0.12s;
  }
  .today-crew-event:hover {
    background: rgba(96, 165, 250, 0.16);
    border-color: rgba(96, 165, 250, 0.32);
  }
  .today-crew-event-time {
    color: var(--blue-light, #93c5fd);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  .today-crew-event-name {
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 240px;
  }
  /* Past-ended events on a still-active day: dimmed + strikethrough.
     Makes "what's left to do today" obvious. */
  .today-crew-event-ended { opacity: 0.5; }
  .today-crew-event-ended .today-crew-event-name { text-decoration: line-through; }

  /* 2026-06-17 — actual clock-in chips. Green now means ONE thing: on the
     clock right now (the open/live chip). A completed entry is neutral
     slate so a clocked-out day no longer reads as live; an approved
     entry adds a green check. Scheduled-event chips stay blue. */
  .today-crew-actual {
    display: inline-flex; align-items: baseline; gap: 4px;
    padding: 2px 7px;
    border-radius: 4px;
    background: rgba(148, 163, 184, 0.10);
    border: 1px solid rgba(148, 163, 184, 0.22);
    color: var(--text);
    font-size: 11.5px;
    line-height: 1.3;
    max-width: 100%;
    overflow: hidden;
    cursor: default;
  }
  .today-crew-actual .today-crew-event-time {
    color: var(--text, #cbd5e1);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  .today-crew-actual .today-crew-event-name {
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 240px;
  }
  /* Approved-and-logged: small green check reinforces "filed". */
  .today-crew-actual-check {
    color: var(--green, #34d399);
    font-weight: 700;
    align-self: center;
    line-height: 1;
  }
  /* The ONLY green chip — still on the clock. Time stays green, job name
     full-strength; everything completed around it is neutral. */
  .today-crew-actual-open {
    background: rgba(52, 211, 153, 0.16);
    border-color: rgba(52, 211, 153, 0.40);
    box-shadow: 0 0 0 1px rgba(52, 211, 153, 0.18);
  }
  .today-crew-actual-open .today-crew-event-time { color: var(--green, #34d399); }
  .today-crew-actual-open .today-crew-event-name { color: var(--text); }
  .today-crew-row:hover { background: rgba(96,165,250,0.06); }
  .today-crew-row-on { background: rgba(52, 211, 153, 0.05); }
  .today-crew-row-on:hover { background: rgba(52, 211, 153, 0.10); }
  .today-crew-dot {
    width: 8px; height: 8px; border-radius: 50%;
    justify-self: center;
  }
  .today-crew-dot-on   { background: var(--green); box-shadow: 0 0 6px rgba(52, 211, 153, 0.6); }
  .today-crew-dot-done { background: var(--blue, #3b82f6); }
  .today-crew-dot-off  { background: #4b5563; }
  .today-crew-name {
    font-weight: 600; color: var(--text-strong);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* Stats cluster — hours always present, jobs count + live tick optional.
     Tabular nums so columns align across rows. */
  .today-crew-stats {
    display: inline-flex; align-items: baseline; gap: 10px;
    color: var(--text-muted); font-size: 12px;
    font-variant-numeric: tabular-nums;
  }
  .today-crew-hours { color: var(--text); font-weight: 600; min-width: 38px; text-align: right; }
  .today-crew-jobs  { color: var(--text-muted); }
  .today-crew-tick  { color: var(--blue-light); font-weight: 500; }
  /* Status badges — small pills on the right edge. Match the Active
     Timesheets pill palette so users get consistent semantics across
     Today and Billing tabs. */
  .today-crew-badge {
    display: inline-block;
    padding: 2px 8px; border-radius: 999px;
    font-size: 10.5px; font-weight: 700;
    letter-spacing: 0.04em; text-transform: uppercase;
    white-space: nowrap;
  }
  .today-crew-badge-active {
    background: rgba(52, 211, 153, 0.15);
    color: var(--green, #34d399);
    border: 1px solid rgba(52, 211, 153, 0.35);
  }
  .today-crew-badge-done {
    background: rgba(59, 130, 246, 0.12);
    color: var(--blue-light, #93c5fd);
    border: 1px solid rgba(59, 130, 246, 0.32);
  }
  .today-crew-badge-unapproved {
    background: rgba(251, 146, 60, 0.14);
    color: #fb923c;
    border: 1px solid rgba(251, 146, 60, 0.35);
  }
  .today-crew-dot-warn { background: #fb923c; }
  .today-crew-badge-off {
    background: rgba(168, 85, 247, 0.10);
    color: var(--purple);
    border: 1px solid rgba(168, 85, 247, 0.28);
  }
  .today-crew-badge-scheduled {
    background: rgba(251, 191, 36, 0.10);
    color: var(--amber);
    border: 1px solid rgba(251, 191, 36, 0.24);
  }
  .today-crew-badge-idle {
    background: rgba(148, 163, 184, 0.08);
    color: var(--text-faint, #94a3b8);
    border: 1px solid rgba(148, 163, 184, 0.20);
  }
  /* Badge + (optional) End-from-CRM button share the last grid cell so
     the row's 4-column grid stays intact. Crew tab renders both; Today
     view renders only the badge — empty after the badge collapses to 0
     and the cell sizes to the badge alone. */
  .today-crew-badge-cell {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
  }
  .crew-end-inline {
    background: transparent;
    border: 1px solid rgba(248, 113, 113, 0.35);
    color: var(--red-text);
    border-radius: 4px;
    padding: 2px 8px;
    font-size: 11px; font-weight: 600;
    letter-spacing: 0.04em; text-transform: uppercase;
    cursor: pointer;
    line-height: 1.3;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .crew-end-inline:hover {
    background: rgba(248, 113, 113, 0.12);
    border-color: rgba(248, 113, 113, 0.55);
    color: #fecaca;
  }
  /* Back-compat: kept the .today-crew-status + .today-crew-dur classes for
     any external surface still using them, but new rows render the stats
     cluster + badge instead. */
  .today-crew-status {
    color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .today-crew-status-off { color: var(--text-faint); font-style: italic; }
  .today-crew-dur {
    font-variant-numeric: tabular-nums;
    color: var(--blue-light);
    text-align: right;
    font-weight: 500;
  }

  /* Reimburse watch bar — pending crew reimbursements. Purple-ish so it
     reads as "you owe somebody money" without being alarming red. */
  .today-reimburse-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(168, 85, 247, 0.08);
    border: 1px solid rgba(168, 85, 247, 0.3);
    font-size: 12.5px; min-width: 0;
    cursor: pointer; transition: background 0.12s;
  }
  .today-reimburse-bar:hover { background: rgba(168, 85, 247, 0.15); }
  .today-reimburse-dot {
    flex: 0 0 auto;
    width: 7px; height: 7px; border-radius: 50%;
    background: #a855f7;
  }
  .today-reimburse-label { flex: 0 0 auto; font-weight: 600; color: var(--purple); }
  .today-reimburse-count {
    flex: 0 0 auto;
    padding: 1px 8px; border-radius: 999px;
    background: rgba(168, 85, 247, 0.25); color: #ede9fe;
    font-weight: 600; font-size: 11px;
  }
  .today-reimburse-money {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
  }
  .today-reimburse-names {
    flex: 1 1 auto; min-width: 0;
    color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Receipts watch bar — mirrors Reimburse bar pattern, blue palette */
  .today-receipts-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(59, 130, 246, 0.08);
    border: 1px solid rgba(59, 130, 246, 0.3);
    font-size: 12.5px; min-width: 0;
    cursor: pointer; transition: background 0.12s;
  }
  .today-receipts-bar:hover { background: rgba(59, 130, 246, 0.15); }
  .today-receipts-dot {
    flex: 0 0 auto;
    width: 7px; height: 7px; border-radius: 50%;
    background: #3b82f6;
  }
  .today-receipts-label { flex: 0 0 auto; font-weight: 600; color: var(--blue-light); }
  .today-receipts-count {
    flex: 0 0 auto;
    padding: 1px 8px; border-radius: 999px;
    background: rgba(59, 130, 246, 0.25); color: var(--blue-lightest);
    font-weight: 600; font-size: 11px;
  }
  .today-receipts-meta {
    flex: 1 1 auto; min-width: 0;
    color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Today header row — date label on the left, watch-bar stack on the right. */
  .today-header-row {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    padding: 0 4px;
  }
  /* Stack permit / inspection / A/R bars tight against each other so missing
     bars don't leave a visible blank (gap is much smaller than .today-pane's). */
  .today-watch-stack {
    display: flex; flex-direction: column; gap: 6px;
    flex: 1 1 auto; min-width: 0;
  }
  .today-permit-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.3);
    font-size: 12.5px; min-width: 0;
  }
  .today-permit-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--amber);
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.15);
  }
  .today-permit-label { color: var(--amber); font-weight: 600; flex: 0 0 auto; }
  .today-permit-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(245, 158, 11, 0.2); color: var(--amber);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-permit-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .permit-watch-name {
    color: var(--amber-text); text-decoration: none; border-bottom: 1px dotted rgba(253, 230, 138, 0.4);
  }
  .permit-watch-name:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }

  /* Inspection Watch — same shape as Permit Watch but red theme. Sits on
     its own row beneath the date+permit row. Only renders when there's at
     least one inspection-tagged active project (no all-clear state, since
     most days are quiet — silence = clean). */
  .today-header-row-inspection { padding: 0 4px; }
  .today-inspection-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(220, 38, 38, 0.08);
    border: 1px solid rgba(220, 38, 38, 0.32);
    font-size: 12.5px; min-width: 0;
  }
  .today-inspection-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--red);
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.16);
  }
  .today-inspection-label {
    color: var(--red-text); font-weight: 600; flex: 0 0 auto;
  }
  .today-inspection-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(220, 38, 38, 0.22); color: var(--red-text);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-inspection-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .today-inspection-bar .permit-watch-name {
    color: var(--red-text); border-bottom-color: rgba(254, 202, 202, 0.4);
  }
  .today-inspection-bar .permit-watch-name:hover {
    color: var(--text-strong); border-bottom-color: var(--text-strong);
  }

  /* Quote Watch — same shape as Permit/Inspection Watch, green theme to
     match the Status-label dot on the Leads pipeline. Only renders when
     at least one active lead sits in "Needs Quote" — silence = nothing
     waiting on a quote from Matt. */
  .today-quote-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(22, 163, 74, 0.08);
    border: 1px solid rgba(22, 163, 74, 0.32);
    font-size: 12.5px; min-width: 0;
  }
  .today-quote-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #16a34a;
    box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.16);
  }
  .today-quote-label {
    color: var(--green); font-weight: 600; flex: 0 0 auto;
  }
  .today-quote-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(22, 163, 74, 0.22); color: var(--green-text);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-quote-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .today-quote-bar .permit-watch-name {
    color: var(--green-text); border-bottom-color: rgba(134, 239, 172, 0.4);
  }
  .today-quote-bar .permit-watch-name:hover {
    color: var(--text-strong); border-bottom-color: var(--text-strong);
  }

  /* Today calendar event quick-links column. 3 buttons (CC + Cal + Map)
     after the 2026-05-21 trim — Matt dropped Day + QBO chips because
     too many actions in a narrow tail looked sloppy and "blinked" on
     hover (the cursor crossing adjacent buttons re-triggered each one's
     transition). Current size sized to fit 3 buttons cleanly without
     touching the address cell to the left.
     2026-05-21 — ALL transitions dropped. No fade in/out, no
     border-animation, nothing. Hover state is an instant swap so the
     cursor sweeping across buttons never triggers a chain of animations
     that read as flicker. */
  .today-event-row {
    grid-template-columns: 150px minmax(0, 1.2fr) minmax(0, 1fr) 135px !important;
  }
  .today-row-sub {
    /* Hard truncate when address is long — prevents text from leaking
       under the buttons cluster on narrow viewports. min-width: 0 lets
       the grid cell shrink even when its content (the location chip
       hyperlink) would otherwise force-expand it. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .today-row-links {
    display: flex; gap: 4px; justify-content: flex-end; align-items: center;
  }
  .today-event-link {
    padding: 2px 8px;
    border-radius: 4px;
    background: rgba(96, 165, 250, 0.08);
    color: var(--blue-light);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-decoration: none;
    border: 1px solid rgba(96, 165, 250, 0.18);
    /* No transition. Hover swap is instant - eliminates any possible
       fade-related flicker when the cursor moves rapidly between
       adjacent buttons. */
    white-space: nowrap;
    line-height: 1.4;
    cursor: pointer;
  }
  .today-event-link:hover {
    background: rgba(96, 165, 250, 0.20);
    border-color: rgba(96, 165, 250, 0.45);
  }
  /* Job-Detail hyperlink on the event title. Keeps the existing weight
     and color of .today-row-name but adds an underline-on-hover affordance
     so it reads as clickable without overpowering the row. */
  .today-event-title-link {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dashed transparent;
    cursor: pointer;
    transition: border-color 0.12s, color 0.12s;
  }
  .today-event-title-link:hover {
    color: var(--blue-light);
    border-bottom-color: var(--blue-light);
  }
  /* Google-Maps hyperlink on the event location (sub line). Subtle —
     reads as a normal address until you hover. */
  .today-event-loc {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted transparent;
    transition: border-color 0.12s, color 0.12s;
  }
  .today-event-loc:hover {
    color: var(--blue-light);
    border-bottom-color: var(--blue-light);
  }

  /* Client-edit modal grid: 2-column form with stacked label/input. */
  .client-edit-grid {
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px;
    margin: 6px 0 10px;
  }
  .client-edit-grid label {
    display: flex; flex-direction: column; gap: 4px;
    font-size: 11px; color: var(--text-soft); font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  .client-edit-grid input {
    width: 100%; padding: 8px 10px;
    border: 1px solid var(--border); border-radius: 7px;
    font-size: 13px; color: var(--text); background: var(--panel-3);
    outline: none; font-family: inherit;
    text-transform: none; letter-spacing: 0;
  }
  .client-edit-grid input:focus { border-color: var(--blue); }
  .client-edit-hint {
    font-size: 11.5px; color: var(--text-muted); padding: 8px 0;
    line-height: 1.5;
  }
  .client-edit-hint.saving { color: var(--blue-light); }
  .client-edit-hint.failed { color: var(--red-bright); }

  #match-search {
    width: 100%; padding: 9px 12px; margin-bottom: 10px;
    border: 1px solid var(--border); border-radius: 7px;
    font-size: 13px; color: var(--text); background: var(--panel-3);
    outline: none; font-family: inherit;
  }
  #match-search:focus { border-color: var(--blue); }

  /* The match modal has hundreds of customers in #match-results. The default
     .modal overflow-y:auto would scroll the WHOLE modal as one block, which
     pushes the search input off the top once you scroll down. Lock the modal
     itself, let the results list be the only scroll container. */
  #match-modal .modal {
    display: flex; flex-direction: column;
    overflow: hidden;
  }
  #match-modal #match-results {
    flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0;
    margin-bottom: 4px;
  }
  .match-context {
    padding: 10px 12px; border-radius: 8px; margin-bottom: 10px;
    background: rgba(59,130,246,0.08); border: 1px solid rgba(59,130,246,0.25);
    font-size: 12px; color: var(--text);
  }
  .match-context b { color: var(--blue-light); }

  /* ── Top-level tabs ── */
  .view-tabs {
    display: flex; gap: 4px;
    border-bottom: 1px solid var(--border);
    margin: 0 0 20px 0;
  }
  .view-tab {
    background: none; border: none; cursor: pointer;
    padding: 12px 20px; font-size: 14px; font-weight: 600;
    color: var(--text-muted); letter-spacing: 0.02em;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
  }
  .view-tab:hover { color: var(--text); }
  .view-tab.active { color: var(--text-strong); border-bottom-color: var(--blue-bright); }
  .view-tab .tab-count {
    display: inline-block; margin-left: 8px; padding: 1px 8px;
    border-radius: 100px; background: var(--border); color: var(--text-soft);
    font-size: 11px; font-weight: 600;
  }
  .view-tab.active .tab-count { background: rgba(96,165,250,0.2); color: var(--blue-light); }

  /* ── Client list ── */
  /* Two-column layout: Companies on the left, People on the right.
     Each column has its own header + vertically-stacked rows. Falls back
     to a single column on narrow viewports so it still reads on phones. */
  .client-list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
    align-items: start;
  }
  @media (max-width: 760px) {
    .client-list { grid-template-columns: 1fr; }
  }
  .client-column {
    display: flex; flex-direction: column;
    gap: 4px; min-width: 0;
  }
  .client-section-header {
    display: flex; align-items: baseline; gap: 8px;
    margin: 0 4px 6px; padding: 0;
    font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--text-muted);
  }
  .client-section-header .count {
    font-size: 10.5px; color: var(--text-faint);
    font-weight: 500; text-transform: none; letter-spacing: 0;
  }
  /* Compact list row, one client per row. Grid-based so name / phone /
     email / job-count all line up vertically across rows — phone numbers
     start at the same x-coordinate on every row, same for emails. Much
     easier to scan than a comma-separated meta line. */
  .client-row {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1.5fr) auto auto auto;
    align-items: center; gap: 12px;
    padding: 8px 14px; border: 1px solid var(--border); border-radius: 8px;
    background: var(--panel); cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
  }
  .client-row:hover { background: var(--row-hover); border-color: var(--border-strong); }
  /* Header row — same grid template as a data row, but styled like a
     muted column-label strip. Cursor stays default + chips drop their
     pill backgrounds so they read as labels, not values. */
  .client-row.client-row-header {
    background: transparent; border-color: transparent;
    padding-top: 4px; padding-bottom: 4px;
    cursor: default;
    text-transform: uppercase; letter-spacing: 0.04em;
    font-size: 11px; font-weight: 600;
    color: var(--text-muted);
  }
  .client-row.client-row-header:hover { background: transparent; border-color: transparent; }
  .client-row.client-row-header .client-row-name,
  .client-row.client-row-header .client-row-phone,
  .client-row.client-row-header .client-row-email {
    color: var(--text-muted); font-weight: 600; font-size: 11px;
  }
  .client-row.client-row-header .client-row-jobs,
  .client-row.client-row-header .client-row-invoices,
  .client-row.client-row-header .client-row-qbo {
    background: transparent; color: var(--text-muted);
    border: 0; padding: 0; font-size: 11px;
  }
  .client-row-name {
    font-size: 13.5px; font-weight: 600; color: var(--text-strong);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .client-row-phone, .client-row-email {
    font-size: 11.5px; color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .client-row-phone { font-variant-numeric: tabular-nums; }
  .client-row-email { color: var(--text-muted); }
  .client-row-jobs {
    padding: 2px 9px; border-radius: 100px;
    background: rgba(96,165,250,0.15); color: var(--blue-light);
    font-size: 10.5px; font-weight: 600; white-space: nowrap;
    justify-self: end;
  }
  .client-row-jobs.unmatched { background: rgba(107,127,163,0.18); color: var(--text-soft); }
  .client-row-invoices {
    padding: 2px 8px; border-radius: 100px;
    background: rgba(34, 197, 94, 0.12); color: var(--green-text);
    font-size: 11px; font-weight: 600;
    white-space: nowrap; flex: 0 0 auto;
  }
  .client-row-invoices.empty { background: rgba(107,127,163,0.12); color: var(--text-muted); }
  .client-row-invoices.loading { background: rgba(107,127,163,0.08); color: var(--text-faint); font-style: italic; }
  .client-row-qbo {
    padding: 2px 8px; border-radius: 5px;
    background: rgba(96, 165, 250, 0.14);
    color: var(--blue-light);
    font-size: 11px; font-weight: 700;
    text-decoration: none;
    border: 1px solid rgba(96, 165, 250, 0.28);
    transition: background 0.12s, color 0.12s;
    white-space: nowrap; flex: 0 0 auto;
  }
  .client-row-qbo:hover { background: rgba(96, 165, 250, 0.25); color: var(--blue-lightest); }

  /* Phone / email contact cells — clickable link plus a small copy button.
     Used everywhere a phone or email is rendered: Clients view, Client
     Detail, Job Detail (planned). The compact variant trims the typography
     for tight grid cells like the Clients list rows. */
  .contact-cell {
    display: inline-flex; align-items: center; gap: 4px;
    min-width: 0; overflow: hidden;
  }
  .contact-link {
    color: var(--blue-light); text-decoration: none;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    transition: color 0.12s;
  }
  .contact-link.compact { font-size: 11.5px; color: var(--text-muted); }
  .contact-link:hover { color: var(--blue-bright); text-decoration: underline; }
  .contact-empty { color: var(--text-faint); }
  .contact-copy {
    flex-shrink: 0;
    background: none; border: none; cursor: pointer;
    color: var(--text-faint); font-family: inherit; font-size: 11px;
    padding: 1px 4px; border-radius: 4px;
    line-height: 1;
    transition: color 0.12s, background 0.12s;
  }
  .contact-copy:hover {
    color: var(--blue-light); background: rgba(96,165,250,0.12);
  }
  .contact-copy.contact-copy-done {
    color: var(--green); background: rgba(34,197,94,0.15);
  }
  /* Legacy tile classes — keep so the Client Detail subsections (which
     reuse client-tile-name) still render correctly. */
  .client-tile {
    padding: 14px 16px; border: 1px solid var(--border); border-radius: 12px;
    background: var(--panel); cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
  }
  .client-tile:hover { background: var(--row-hover); border-color: var(--border-strong); }
  .client-tile-name {
    font-size: 14px; font-weight: 600; color: var(--text-strong);
    margin-bottom: 6px;
  }
  .client-tile-meta {
    font-size: 11px; color: var(--text-muted);
    display: flex; gap: 12px; flex-wrap: wrap;
  }
  .client-tile-chip {
    padding: 2px 8px; border-radius: 100px;
    background: rgba(96,165,250,0.15); color: var(--blue-light);
    font-size: 10px; font-weight: 600;
  }
  .client-tile-chip.unmatched {
    background: rgba(251,146,60,0.15); color: var(--orange);
  }

  /* ── Detail pane (used for client & job detail) ── */
  .detail-pane {
    border: 1px solid var(--border); border-radius: 14px;
    background: var(--panel); padding: 20px 24px;
  }
  .detail-back {
    background: none; border: none; cursor: pointer;
    color: var(--blue-bright); font-size: 13px; padding: 0;
  }
  .detail-back:hover { color: var(--blue-light); }
  .detail-topbar {
    display: flex; justify-content: space-between; align-items: center;
    gap: 12px; margin-bottom: 14px;
  }
  .detail-topbar .button { font-size: 12px; padding: 6px 12px; }
  .detail-header {
    display: flex; justify-content: space-between; align-items: start;
    gap: 16px; flex-wrap: wrap; margin-bottom: 18px;
    padding-bottom: 16px; border-bottom: 1px solid var(--border);
  }
  .detail-title {
    font-size: 22px; font-weight: 700; color: var(--text-strong); margin: 0;
  }
  .detail-subtitle {
    font-size: 13px; color: var(--text-soft); margin-top: 4px;
  }
  .detail-actions { display: flex; gap: 8px; flex-wrap: wrap; }
  .detail-info {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 8px 24px; font-size: 13px; color: var(--text);
    margin-bottom: 20px;
  }
  .detail-info div b { color: var(--text-soft); margin-right: 6px; font-weight: 600; }
  /* Job description box — maps to CC's project.description field.
     Wiring is stubbed for now; we just surface the UI so it's in place. */
  .detail-description {
    margin: 8px 0 22px;
    display: flex; flex-direction: column; gap: 6px;
  }
  .detail-description-label {
    font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text-muted);
  }
  .detail-description-textarea {
    width: 100%; min-height: 84px; resize: vertical;
    padding: 10px 12px;
    background: var(--panel-3);
    border: 1px solid var(--border);
    border-radius: 10px;
    color: var(--text);
    font-family: inherit; font-size: 13px; line-height: 1.45;
    transition: border-color 0.15s, background 0.15s;
  }
  .detail-description-textarea::placeholder { color: var(--text-muted); }
  .detail-description-textarea:focus {
    outline: none; border-color: var(--blue);
    background: var(--panel-2);
  }
  .detail-description-hint {
    font-size: 10.5px; color: var(--text-muted);
    font-style: italic;
    transition: color 0.15s;
  }
  .detail-description-hint.saving { color: var(--amber); font-style: normal; }
  .detail-description-hint.saved { color: var(--green-soft); font-style: normal; }
  .detail-description-hint.failed { color: var(--red-bright); font-style: normal; }

  /* Crew job scope — the job-detail "Scope" tab (first in the tab row).
     Lived under Description in the hero until 2026-08-05; every variant
     tried there (list, bounded box, button + modal) crowded the Permits /
     BC Hydro tiles, so it moved out to its own full-width panel and the
     modal shell that used to hold it was retired with it.
     Quoted jobs: the quote's scope lines, priced (CRM is Matt's surface —
     crew payloads are stripped server-side). T&M jobs: a textarea saved to
     the jobScopes state slice. The panel itself lays out as a normal tab
     panel; the flex column is on the body so `.detail-tab-panel.is-active`
     (display:block, later in this file) can't fight it. */
  .detail-crew-scope-body { display: flex; flex-direction: column; gap: 6px; }
  .detail-crew-scope-note { font-size: 11.5px; color: var(--text-muted); line-height: 1.45; }
  .detail-crew-scope-preview { align-self: flex-start; }
  .detail-crew-scope-lines { margin: 4px 0 0; padding-left: 18px; }
  .detail-crew-scope-lines li { font-size: 12.5px; line-height: 1.45; margin-bottom: 3px; white-space: pre-wrap; }
  .detail-crew-scope-amt {
    float: right; margin-left: 14px; opacity: 0.75;
    font-variant-numeric: tabular-nums;
  }
  .detail-crew-scope-total {
    text-align: right; font-weight: 600; color: var(--text-soft);
    padding-top: 4px; border-top: 1px solid var(--border);
  }
  .detail-crew-scope-textarea { min-height: 64px; max-width: 720px; }
  /* Quote on top, hand-typed addendum underneath. Separate containers so the
     quote re-rendering can't wipe a box being typed into; the rule makes the
     notes read as Matt's own rather than another quote line. */
  .detail-crew-scope-quote { display: flex; flex-direction: column; gap: 6px; }
  /* Multiple quotes on one job (2026-08-16, 952 Richmond: invoiced #1079 +
     new accepted #1135). Each quote is its own section; Closed ones are
     <details> starting collapsed, their summary carrying doc # + status +
     total so the old quote stays one glance away without crowding the new. */
  .detail-crew-scope-qsec { display: flex; flex-direction: column; gap: 6px; }
  .detail-crew-scope-qsec + .detail-crew-scope-qsec,
  .detail-crew-scope-qsec + .detail-crew-scope-closedq,
  .detail-crew-scope-closedq + .detail-crew-scope-qsec,
  .detail-crew-scope-closedq + .detail-crew-scope-closedq {
    margin-top: 8px; padding-top: 10px; border-top: 1px solid var(--border);
  }
  .detail-crew-scope-qhead { font-weight: 600; }
  /* summary typography rides its .detail-crew-scope-note class */
  details.detail-crew-scope-closedq summary { cursor: pointer; user-select: none; }
  details.detail-crew-scope-closedq summary:hover { color: var(--text-soft); }
  details.detail-crew-scope-closedq[open] summary { margin-bottom: 6px; }
  .detail-crew-scope-extra {
    display: flex; flex-direction: column; gap: 6px;
    margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border);
  }

  /* Links in the job-detail header (address, client) read easier in near-white
     than the browser-default royal blue. Underline shows on hover. */
  .detail-info a, .detail-subtitle a {
    color: var(--text); text-decoration: none;
    border-bottom: 1px dotted rgba(158, 176, 207, 0.35);
    transition: color 0.15s, border-color 0.15s;
  }
  .detail-info a:hover, .detail-subtitle a:hover {
    color: var(--text-strong); border-bottom-color: rgba(230, 238, 252, 0.7);
  }
  .detail-section-title {
    font-size: 11px; font-weight: 700; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text-muted);
    margin: 18px 0 10px;
  }

  /* ── Client detail: Recent invoices + Recent estimates panels ───────── */
  .client-history-grid {
    display: grid; grid-template-columns: 1fr 1fr; gap: 18px;
    margin: 18px 0 8px;
  }
  @media (max-width: 900px) {
    .client-history-grid { grid-template-columns: 1fr; }
  }
  .client-history-section {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    padding: 14px 16px; display: flex; flex-direction: column; min-height: 80px;
  }
  .client-history-header {
    display: flex; justify-content: space-between; align-items: baseline;
    margin-bottom: 6px;
  }
  .client-history-header .detail-section-title { margin: 0; }
  .client-history-meta {
    color: var(--text-muted); font-size: 11.5px;
  }
  .client-history-meta a {
    color: var(--blue-light); text-decoration: none;
  }
  .client-history-meta a:hover { text-decoration: underline; color: var(--blue-lightest); }
  .client-history-list { display: flex; flex-direction: column; gap: 4px; }
  .client-history-row {
    display: grid;
    grid-template-columns: 64px 1fr auto auto;
    gap: 10px; align-items: baseline;
    padding: 8px 10px; border-radius: 6px;
    color: var(--text); text-decoration: none; font-size: 12.5px;
    transition: background 0.15s, border-color 0.15s;
    border: 1px solid transparent;
  }
  .client-history-row:hover {
    background: rgba(59,130,246,0.07);
    border-color: rgba(59,130,246,0.20);
  }
  .chr-doc {
    color: var(--blue-light); font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 12px; font-weight: 600;
  }
  .chr-job {
    color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .chr-date { color: var(--text-muted); font-size: 11.5px; white-space: nowrap; }
  .chr-total {
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; font-weight: 500;
    text-align: right; white-space: nowrap;
  }
  .chr-total small {
    font-size: 10.5px; color: var(--amber-bright); font-weight: 500;
    margin-left: 2px;
  }
  .chr-paid { color: var(--green-soft); }
  .chr-open { color: var(--amber-text); }
  .chr-status { color: var(--text-soft); }
  .client-history-empty {
    color: var(--text-muted); font-size: 12.5px; font-style: italic;
    margin: 4px 0 0;
  }
  /* Job-detail label grid — mirrors the main list's dropdowns so labels
     can be changed from the detail pane too. */
  .detail-label-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(144px, 1fr));
    gap: 14px 18px;
    margin-bottom: 10px;
  }
  .detail-label-col {
    display: flex; flex-direction: column; gap: 6px; min-width: 0;
  }
  .detail-label-head {
    font-size: 10px; font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--text-muted);
  }
  .detail-label-extras {
    margin-top: 14px; font-size: 12px; color: var(--text);
    padding-top: 12px; border-top: 1px dashed var(--border);
  }
  .detail-label-extras b { color: var(--text-soft); margin-right: 6px; font-weight: 600; }

  /* ── CC files (Job Detail) ─────────────────────────────────────────────
     Lists PDF documents attached to this project's CompanyCam record.
     Each row has an Open-in-markup-tool action that deep-links into
     plan-markup.html with the file pre-selected. Primary entry point
     into the markup tool now that the global sidebar item is being
     de-emphasized. */
  .detail-cc-files {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
  }
  /* ── Job Notes (CRM-side) ─────────────────────────────────────────
     Mirrors the mobile Notes UI structurally — title-only cards,
     tap to expand into an edit modal. Backend: mobile's job-notes.js
     function called cross-origin with the MOBILE_ADMIN_TOKEN. */
  .detail-job-notes {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
  }
  .detail-job-notes-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 6px;
  }
  .detail-job-notes-head h3 {
    margin: 0; font-size: 15px; font-weight: 600; color: var(--text);
  }
  .detail-job-notes-sub {
    font-size: 12px; color: var(--text-muted);
    margin-bottom: 10px;
    line-height: 1.45;
  }
  .detail-jn-add-btn {
    display: inline-flex; align-items: center;
    padding: 6px 12px;
    background: rgba(34, 197, 94, 0.10);
    color: var(--green-text, #22c55e);
    border: 1px solid rgba(34, 197, 94, 0.35);
    border-radius: 6px;
    font-size: 12.5px; font-weight: 500;
    cursor: pointer;
  }
  .detail-jn-add-btn:hover {
    background: rgba(34, 197, 94, 0.18);
    border-color: rgba(34, 197, 94, 0.55);
  }
  .detail-job-notes-list {
    display: flex; flex-direction: column; gap: 6px;
  }
  .detail-jn-empty {
    padding: 14px 12px;
    font-size: 12.5px; color: var(--text-muted);
    font-style: italic;
    border: 1px dashed var(--border);
    border-radius: 8px;
  }
  .detail-jn-card {
    background: var(--panel-3);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: 10px 14px 8px;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s;
  }
  .detail-jn-card:hover {
    border-color: var(--border-strong);
    background: var(--panel);
  }
  .detail-jn-card-head {
    display: flex; align-items: baseline; gap: 8px;
    margin-bottom: 4px;
  }
  .detail-jn-card-title {
    flex: 1; min-width: 0;
    font-size: 14.5px; font-weight: 600; color: var(--text-strong);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .detail-jn-card-size {
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    padding: 1px 5px;
    background: rgba(59,130,246,0.10);
    border-radius: 4px;
  }
  .detail-jn-card-kind {
    font-size: 10px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--text-muted);
    padding: 2px 6px;
    background: rgba(255,255,255,0.04);
    border-radius: 4px;
  }
  .detail-jn-card-foot {
    padding-top: 4px;
  }
  .detail-jn-foot-stamp {
    font-size: 10.5px; color: var(--text-muted);
    font-variant-numeric: tabular-nums;
  }
  /* Edit modal — uses the existing .ti-modal styling; these rules
     style the body-kind chips + row layout inside it. */
  .crm-jn-kind-btn {
    flex: 1 1 0;
    padding: 6px 10px;
    background: var(--panel-3);
    color: var(--text-soft);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 12.5px; font-weight: 500;
    cursor: pointer;
  }
  .crm-jn-kind-btn:hover { color: var(--text); border-color: var(--border-strong); }
  .crm-jn-kind-btn.active {
    background: var(--blue, #2563eb); color: #fff;
    border-color: var(--blue, #2563eb);
  }
  .crm-jn-row {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .crm-jn-row:last-child { border-bottom: 0; }
  .crm-jn-row-check {
    flex: 0 0 24px;
    width: 24px; height: 24px;
    border: 1.5px solid var(--border);
    background: transparent;
    border-radius: 5px;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--green-text, #22c55e);
    font-size: 14px;
    padding: 0;
  }
  .crm-jn-row-check.on {
    border-color: var(--green-text, #22c55e);
    background: rgba(34, 197, 94, 0.14);
  }
  .crm-jn-row-bullet,
  .crm-jn-row-num {
    flex: 0 0 24px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
  }
  .crm-jn-row-input {
    flex: 1; min-width: 0;
    background: transparent;
    border: 0;
    color: var(--text);
    font: inherit; font-size: 14px;
    padding: 4px 2px;
  }
  .crm-jn-row-input:focus { outline: 0; }
  .crm-jn-row-input-done { color: var(--text-muted); text-decoration: line-through; }
  .crm-jn-row-del {
    flex: 0 0 24px;
    background: transparent; border: 0;
    color: var(--text-muted);
    font-size: 18px; line-height: 1;
    cursor: pointer; padding: 0;
    opacity: 0.6;
  }
  .crm-jn-row-del:hover { opacity: 1; color: var(--red); }
  .crm-jn-history-line {
    margin-top: 14px;
    font-size: 11px; color: var(--text-muted);
    font-style: italic;
    padding: 8px 10px;
    background: rgba(34, 197, 94, 0.06);
    border-left: 3px solid rgba(34, 197, 94, 0.55);
    border-radius: 4px;
  }

  /* ─── Note reader (read-only view) ─────────────────────────────────
     Clicking a note card opens this instead of the edit form. Reading a
     note should feel like reading a note — big title, clean list, no
     input chrome. Edit is one click away in the footer. The jnv-* class
     names are mirrored in Peak Mobile so both surfaces stay in step. */
  .jnv-backdrop {
    position: fixed; inset: 0;
    background: rgba(15, 23, 42, 0.62);
    /* Above the job-detail modal (.ti-modal-backdrop, 5000). This is the
       overlay, NOT the card — a static block can never paint above
       positioned content inside .app-shell. */
    z-index: 5200;
    display: flex; align-items: flex-start; justify-content: center;
    padding: 72px 16px 32px;
    overflow-y: auto;
  }
  .jnv-card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 14px;
    width: min(620px, 94vw);
    max-height: calc(100vh - 110px);
    display: flex; flex-direction: column;
    overflow: hidden;
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
  }
  [data-theme="light"] .jnv-card { box-shadow: 0 18px 50px rgba(15, 23, 42, 0.18); }
  .jnv-head {
    position: relative;
    padding: 22px 24px 16px;
    border-bottom: 1px solid var(--border-subtle);
  }
  .jnv-title {
    margin: 0 40px 0 0;
    font-size: 21px; font-weight: 650; line-height: 1.25;
    color: var(--text-strong);
    overflow-wrap: anywhere;
  }
  .jnv-close {
    position: absolute; top: 14px; right: 14px;
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent; border: 0; border-radius: 6px;
    color: var(--text-muted); font-size: 22px; line-height: 1;
    cursor: pointer; padding: 0;
  }
  .jnv-close:hover { background: var(--panel-3); color: var(--text); }
  .jnv-meta {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    margin-top: 9px;
    font-size: 12px; color: var(--text-muted);
  }
  .jnv-kind {
    font-size: 10px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    padding: 3px 7px; border-radius: 4px;
    color: var(--text-soft);
    background: var(--panel-3);
    border: 1px solid var(--border-subtle);
  }
  .jnv-kind-checklist { color: var(--green-text, #22c55e); background: rgba(34, 197, 94, 0.10); border-color: rgba(34, 197, 94, 0.28); }
  .jnv-count { font-variant-numeric: tabular-nums; }
  .jnv-progress {
    height: 4px; margin-top: 12px;
    background: var(--border-subtle);
    border-radius: 999px; overflow: hidden;
  }
  .jnv-progress-fill {
    height: 100%;
    background: var(--green-text, #22c55e);
    border-radius: 999px;
    transition: width 0.18s ease;
  }
  .jnv-body {
    padding: 10px 24px 20px;
    overflow-y: auto;
  }
  .jnv-empty {
    padding: 18px 0;
    font-size: 13px; color: var(--text-muted); font-style: italic;
  }
  /* Free-form notes keep the author's line breaks — a wall of re-flowed
     text loses the shape of a materials list typed as plain text. */
  .jnv-text {
    font-size: 14.5px; line-height: 1.65; color: var(--text);
    white-space: pre-wrap; overflow-wrap: anywhere;
    padding: 4px 0;
  }
  /* No dividers between rows on purpose — spacing alone reads as a note;
     hairlines read as a table. */
  .jnv-list { display: flex; flex-direction: column; }
  .jnv-row {
    display: flex; align-items: flex-start; gap: 12px;
    width: 100%;
    padding: 8px 8px; margin: 0 -8px;
    border: 0; border-radius: 8px;
    background: transparent;
    color: var(--text);
    font: inherit; font-size: 14.5px; line-height: 1.5;
    text-align: left;
  }
  button.jnv-row { cursor: pointer; }
  button.jnv-row:hover { background: var(--panel-3); }
  .jnv-txt { flex: 1; min-width: 0; overflow-wrap: anywhere; padding-top: 1px; }
  .jnv-row.is-done .jnv-txt { color: var(--text-muted); text-decoration: line-through; }
  .jnv-box {
    flex: 0 0 19px;
    width: 19px; height: 19px; margin-top: 2px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1.5px solid var(--border-strong);
    border-radius: 5px;
    /* Dark ink on the fill: --green-text is a PALE green in dark theme,
       so a white tick all but disappears. Light theme's green is dark
       enough that the tick has to flip white (override below). */
    color: #0b1220;
    transition: background 0.12s, border-color 0.12s;
  }
  .jnv-box.on {
    background: var(--green-text, #22c55e);
    border-color: var(--green-text, #22c55e);
  }
  [data-theme="light"] .jnv-box { color: #fff; }
  .jnv-num {
    flex: 0 0 22px;
    text-align: right; padding-top: 1px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    font-size: 13.5px;
  }
  /* Height tracks the row's line box so the dot centres on the FIRST
     line of a wrapping item instead of floating above it. */
  .jnv-dot {
    flex: 0 0 19px; height: 1.5em;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .jnv-dot::before {
    content: ''; width: 5px; height: 5px; border-radius: 50%;
    background: var(--text-muted);
  }
  .jnv-foot {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 24px;
    border-top: 1px solid var(--border-subtle);
    background: var(--panel-3);
  }
  .jnv-stamp {
    flex: 1; min-width: 0;
    font-size: 11.5px; color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* CC files section — supports drag-and-drop. Section wraps the
     dropmask overlay so .is-dropping shows the cue across the whole
     box, not just the header. position:relative is what lets the
     absolute-positioned mask anchor properly. */
  .detail-cc-files {
    position: relative;
  }
  .detail-cc-files-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
  }
  .detail-cc-files-headline { flex: 1 1 auto; min-width: 0; }
  .detail-cc-files-head h3 {
    margin: 0; font-size: 15px; font-weight: 600; color: var(--text);
    line-height: 1.3;
  }
  .detail-cc-files-sub {
    display: block;
    font-size: 12px; color: var(--text-muted);
    margin-top: 2px;
  }
  /* Upload button — ghost-style with an inline up-arrow icon. Lighter
     visual weight than the old solid-blue button so it doesn't shout
     for attention when the user's just browsing files. Drag-and-drop
     is the primary path; button is the explicit fallback. */
  .detail-cc-upload-btn {
    flex: 0 0 auto;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px;
    background: rgba(59, 130, 246, 0.10);
    color: var(--blue-light, #60a5fa);
    border: 1px solid rgba(59, 130, 246, 0.35);
    border-radius: 6px;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    transition: background 120ms ease, border-color 120ms ease;
    white-space: nowrap;
  }
  .detail-cc-upload-btn:hover {
    background: rgba(59, 130, 246, 0.18);
    border-color: rgba(59, 130, 246, 0.55);
  }
  .detail-cc-upload-btn:disabled {
    opacity: 0.7; cursor: progress;
  }
  .detail-cc-upload-icon {
    width: 14px; height: 14px;
    flex: 0 0 14px;
  }
  /* Drop-mask overlay — invisible until the section is being dragged
     over. Pointer-events: none so the drag-over events fire on the
     section underneath without bouncing off the mask. */
  .detail-cc-files-dropmask {
    position: absolute;
    inset: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(59, 130, 246, 0.10);
    border: 2px dashed rgba(59, 130, 246, 0.55);
    border-radius: 10px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 120ms ease;
    z-index: 5;
  }
  .detail-cc-files.is-dropping .detail-cc-files-dropmask { opacity: 1; }
  .detail-cc-files-dropmask-inner {
    display: flex; flex-direction: column; align-items: center;
    gap: 8px;
    color: var(--blue-light, #60a5fa);
    font-size: 14px; font-weight: 600;
  }
  .detail-cc-files-list {
    display: flex; flex-direction: column; gap: 6px;
  }
  .detail-cc-files-loading,
  .detail-cc-files-empty,
  .detail-cc-files-error {
    padding: 14px;
    background: transparent;
    border: 1px dashed var(--border);
    border-radius: 8px;
    color: var(--text-muted);
    font-size: 13px;
    font-style: italic;
    text-align: center;
  }
  .detail-cc-files-error { color: var(--red-bright); }
  .detail-cc-files-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 8px;
  }
  .detail-cc-files-row:hover {
    background: var(--panel-2, var(--panel));
    border-color: var(--border-strong, var(--border));
  }
  .detail-cc-files-name {
    display: flex; align-items: center; gap: 8px;
    flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    color: var(--text); font-size: 13.5px;
  }
  .detail-cc-files-icon {
    flex: 0 0 auto; font-size: 16px;
  }
  .detail-cc-files-meta {
    color: var(--text-muted); font-size: 12px;
    margin-left: 8px;
  }
  .detail-cc-files-actions {
    flex: 0 0 auto;
  }
  .detail-cc-files-link {
    color: var(--text);
    text-decoration: none;
    border-bottom: 1px dotted rgba(147, 197, 253, 0.35);
    transition: color 120ms ease, border-bottom-color 120ms ease;
    overflow: hidden; text-overflow: ellipsis;
  }
  .detail-cc-files-link:hover {
    color: var(--blue-lightest, #93c5fd);
    border-bottom-color: rgba(147, 197, 253, 0.85);
  }
  /* Files sort toggle — small muted control right-aligned above the rows. */
  .detail-cc-files-sortbar {
    display: flex; justify-content: flex-end;
    margin: 0 0 6px;
  }
  .detail-cc-files-sortbtn {
    background: transparent; border: 0; padding: 2px 6px;
    color: var(--text-muted); font-size: 12px;
    cursor: pointer; border-radius: 6px;
    transition: color 120ms ease, background 120ms ease;
  }
  .detail-cc-files-sortbtn:hover {
    color: var(--text);
    background: var(--panel-2, var(--panel));
  }
  /* Pencil rename button — muted, brightens on hover. */
  .detail-cc-files-rename {
    flex: 0 0 auto;
    display: inline-flex; align-items: center;
    background: transparent; border: 0; padding: 3px 5px;
    color: var(--text-muted);
    cursor: pointer; border-radius: 6px; line-height: 1;
    transition: color 120ms ease;
  }
  .detail-cc-files-rename:hover { color: var(--text); }
  /* Inline rename editor — input fills the name slot; Save/Cancel hug it. */
  .detail-cc-files-rename-input {
    flex: 1 1 auto; min-width: 0;
    background: var(--panel-2, var(--panel));
    border: 1px solid var(--border-strong, var(--border));
    border-radius: 6px;
    color: var(--text); font: inherit; font-size: 13px;
    padding: 4px 8px;
  }
  .detail-cc-files-rename-input:focus {
    outline: none;
    border-color: var(--blue-lightest, #93c5fd);
  }
  .detail-cc-files-name .button { flex: 0 0 auto; }

  /* "Open project in CompanyCam ↗" link in the CC Files section sub-header. */
  .detail-cc-notes-external {
    color: var(--blue-lightest, #93c5fd);
    text-decoration: none;
    margin-left: 6px;
    border-bottom: 1px dotted rgba(147, 197, 253, 0.4);
  }
  .detail-cc-notes-external:hover {
    color: var(--text); border-bottom-color: var(--text);
  }

  /* ── Notes section (Job Detail) — backed by CC Project Conversation.
     Same layout pattern as the CC Files section above it. */
  .detail-cc-notes {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
  }
  .detail-cc-notes-refresh {
    background: transparent; border: 0; padding: 0 6px;
    color: var(--text-muted); font-size: 16px;
    cursor: pointer; vertical-align: middle;
    margin-left: 6px;
    transition: color 120ms ease;
  }
  .detail-cc-notes-refresh:hover { color: var(--text); }
  .detail-cc-notes-refresh.spinning { animation: cc-spin 800ms linear infinite; }
  @keyframes cc-spin { to { transform: rotate(360deg); } }

  .detail-cc-notes-compose {
    display: flex; flex-direction: column; gap: 6px;
    margin: 10px 0 12px;
    padding: 10px 12px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 8px;
  }
  .detail-cc-notes-title {
    background: var(--panel-2, var(--panel)); color: var(--text);
    border: 1px solid var(--border); border-radius: 6px;
    padding: 6px 10px; font: inherit; font-size: 14px; font-weight: 600;
    line-height: 1.4;
  }
  .detail-cc-notes-title::placeholder { font-weight: 400; opacity: 0.7; }
  .detail-cc-notes-title:focus,
  .detail-cc-notes-input:focus {
    outline: none;
    border-color: var(--blue-light, #60a5fa);
    box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.18);
  }
  .detail-cc-notes-input {
    background: var(--panel-2, var(--panel)); color: var(--text);
    border: 1px solid var(--border); border-radius: 6px;
    padding: 6px 10px; font: inherit; font-size: 13px; line-height: 1.5;
    resize: vertical; min-height: 60px; max-height: 240px;
  }
  .detail-cc-notes-input:disabled,
  .detail-cc-notes-title:disabled { opacity: 0.6; cursor: wait; }
  .detail-cc-notes-actions {
    display: flex; justify-content: flex-end; gap: 8px;
  }

  .detail-cc-note-row {
    padding: 10px 14px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 6px;
  }
  .detail-cc-note-head {
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
    margin-bottom: 4px;
  }
  .detail-cc-note-title { font-size: 14px; font-weight: 600; color: var(--text); }
  .detail-cc-note-meta-spacer { flex: 1 1 auto; }
  .detail-cc-note-body {
    color: var(--text); font-size: 13px; line-height: 1.5;
    white-space: pre-wrap;
  }

  /* ── History popover ── */
  .history-wrap { position: relative; display: inline-block; }
  .history-popover {
    position: absolute; top: 100%; right: 0; margin-top: 4px;
    background: var(--panel-3); border: 1px solid var(--border); border-radius: 8px;
    padding: 4px; z-index: 20; min-width: 140px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  }
  .history-popover button {
    display: flex; align-items: center; gap: 8px; width: 100%;
    background: none; border: none; cursor: pointer;
    padding: 8px 12px; border-radius: 6px; text-align: left;
    font-size: 12px; color: var(--text);
  }
  .history-popover button:hover { background: var(--row-hover); color: var(--text-strong); }
  .history-popover button:disabled { opacity: 0.5; cursor: not-allowed; }

  /* ── Date Added column cell ── */
  .added-col {
    font-size: 12px; color: var(--text-soft);
    font-variant-numeric: tabular-nums;
  }
  /* ── Date Modified column cell — relative time (e.g. "3d ago"). Slightly
        dimmer than Added so it reads as secondary metadata. ── */
  .modified-col {
    font-size: 11.5px; color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    font-style: italic;
  }
  /* Stale job tint — soft amber background on rows where a job has sat in
     Needs Scheduling > 7d or Active > 30d. The chip in the title cell
     names the reason + age so it's not just a mystery glow. */
  /* ── Scrollbars ── */
  ::-webkit-scrollbar { width: 8px; height: 8px; }
  ::-webkit-scrollbar-track { background: var(--panel-3); }
  ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
  ::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

  /* Narrow viewports: grid stays at the same fixed widths; .job-list-scroll
     handles the horizontal scroll. Only drop to single-column at the mobile
     breakpoint below. */
  @media (max-width: 980px) {
    .filter-sections { grid-template-columns: 1fr; }
    .job-list-head { display: none; }
    .job-row.grid-cols {
      grid-template-columns: 1fr;
      gap: 8px;
    }
    .action-stack { justify-content: start; }
    /* Drop the horizontal-scroll floor on narrow screens — the row is single-column there. */
    .job-list-scroll { overflow-x: visible; }
    .job-list-scroll > .job-list { min-width: 0; }
  }
  @media (max-width: 640px) {
    body { padding: 16px 10px 32px; }
    .controls { padding: 14px; }
    .logo-img { height: 38px; }
    .action-stack { grid-template-columns: repeat(3, 1fr); gap: 4px; }
    .action-btn { font-size: 10px; padding: 6px 2px; }
    .action-btn .icon { font-size: 13px; }
  }

  /* ─────────────────────────────────────────────────────────────────────
     APP SHELL · left sidebar nav + main content
     ───────────────────────────────────────────────────────────────────── */
  body { padding: 0; }
  .app-shell { display: flex; min-height: 100vh; align-items: stretch; }
  .sidebar {
    width: 250px; flex-shrink: 0;
    background: var(--bg);
    border-right: 1px solid var(--border);
    padding: 24px 14px; display: flex; flex-direction: column; gap: 4px;
    position: sticky; top: 0; align-self: flex-start;
    /* Fill the viewport so the right-border divider runs top-to-bottom even
       when the nav is short (2026-07-05 — the old footer used to backstop the
       bottom; now the account card lives in the top-right header). min==max
       so it stays exactly one screen tall and scrolls internally if the nav
       ever overflows. */
    min-height: 100vh; max-height: 100vh; overflow-y: auto;
  }
  /* Top-of-sidebar logo block. Bigger image, subtle gradient surround so the
     logo reads as a brand statement instead of a stray asset. The hover lift
     is slightly more pronounced to feel intentional. */
  .sidebar .logo-wrap {
    display: flex; justify-content: center; align-items: center;
    padding: 12px 8px 22px;
    border-bottom: 1px solid var(--panel-2);
    margin-bottom: 14px;
    position: relative;
  }
  .sidebar .logo-wrap::after {
    content: ''; position: absolute;
    left: 18%; right: 18%; bottom: -1px; height: 1px;
    background: linear-gradient(90deg, transparent, rgba(59,130,246,0.55), transparent);
    pointer-events: none;
  }
  .sidebar .logo-wrap a {
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 14px; padding: 14px 16px;
    background: linear-gradient(180deg, rgba(59,130,246,0.05) 0%, rgba(15,23,42,0.0) 100%);
    border: 1px solid transparent;
    transition: background 0.18s ease, transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
  }
  .sidebar .logo-wrap a:hover {
    background: linear-gradient(180deg, rgba(59,130,246,0.14) 0%, rgba(59,130,246,0.04) 100%);
    border-color: rgba(59,130,246,0.35);
    box-shadow: 0 6px 18px rgba(59,130,246,0.12);
    transform: translateY(-1px);
  }
  .sidebar .logo-wrap img {
    height: 88px; width: auto; display: block;
    filter: drop-shadow(0 2px 6px rgba(0,0,0,0.35));
  }
  /* Theme-aware logo swap. logo.png has a black bg (pops on dark sidebar);
     logo-light.png has a white bg (blends into the light sidebar). The
     FOUC-prevention script in <head> sets data-theme before paint, so the
     right one shows up on first render — no flash. */
  .sidebar .logo-wrap .logo-img-light { display: none; }
  [data-theme="light"] .sidebar .logo-wrap .logo-img-dark  { display: none; }
  [data-theme="light"] .sidebar .logo-wrap .logo-img-light { display: block; }
  /* Drop shadow from above is too heavy on a light bg — soften it. */
  [data-theme="light"] .sidebar .logo-wrap img {
    filter: drop-shadow(0 1px 3px rgba(15,23,42,0.10));
  }
  .nav-section-label {
    font-size: 10px; font-weight: 600; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 0.16em;
    padding: 18px 14px 10px;
  }
  .nav-item {
    position: relative;
    display: flex; align-items: center; gap: 12px;
    height: 44px; padding: 0 14px;
    border-radius: 12px;
    cursor: pointer; background: none; border: none;
    color: var(--text-soft); font-family: inherit; font-size: 14px;
    font-weight: 500; text-align: left; width: 100%;
    transition: background 160ms ease, color 160ms ease, transform 160ms ease;
  }
  /* 2026-08-14 — every sidebar :hover now sits behind (hover: hover). iOS
     Safari withholds the click on the FIRST tap of any element whose :hover
     changes its rendering, so nav took two taps on the iPad: tap one painted
     this grey state, tap two actually navigated. A touch device no longer
     matches the rule at all, which is the only reliable fix — neutralising
     the values still leaves Safari a hover rule to find.
     Known tradeoff: an iPad on a Magic Keyboard trackpad reports hover:hover
     and gets the two-tap back for finger taps. Rare enough not to chase. */
  @media (hover: hover) {
    .nav-item:hover {
      background: rgba(255, 255, 255, 0.04);
      color: var(--text-strong);
      box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
    }
  }
  /* Active state: subtle blue tint + a small left-side accent bar instead
     of a solid blue fill. Quieter, Linear-style — the content wins,
     not the navigation. */
  .nav-item.active,
  .nav-item.active:hover {
    background: var(--blue-soft);
    color: var(--blue-bright);
    box-shadow: none;
  }
  .nav-item.active::before {
    content: '';
    position: absolute;
    left: 4px;
    top: 50%; transform: translateY(-50%);
    width: 3px; height: 60%;
    border-radius: 2px;
    background: var(--blue);
  }
  .nav-item .nav-icon {
    width: 20px; height: 20px; flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    opacity: 0.9;
  }
  .nav-item .nav-icon svg { width: 18px; height: 18px; }
  .nav-item .nav-label { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .nav-item .nav-count {
    background: var(--panel-3);
    color: var(--text-soft); padding: 2px 8px; border-radius: 100px;
    font-size: 11px; font-weight: 600; flex-shrink: 0;
  }
  .nav-item.active .nav-count {
    background: rgba(96,165,250,0.18);
    color: var(--blue-bright);
  }
  /* Hide count pills that are empty or "0" — toggled by
     hideZeroNavCounts() in 03-utils.js. A pill that always says "0" is
     visual noise; counts only earn their pixels when they're > 0. */
  .nav-item .nav-count.is-zero { display: none; }

  /* ── + Create button (refinement C) ──────────────────────────────────
     Sits at the top of the sidebar between the logo and the nav. Single
     blue-filled button that opens a small dropdown menu — New Job /
     New Client / New Quote / New Invoice. The "primary action" pattern
     ServiceTitan / Jobber / Buildertrend all use. */
  .nav-create-wrap {
    position: relative;
    margin: 4px 4px 14px;
  }
  .nav-create-btn {
    display: flex; align-items: center; gap: 10px;
    width: 100%; height: 40px; padding: 0 14px;
    border-radius: 12px;
    border: 1px solid transparent;
    background: var(--blue);
    color: var(--on-color);
    font-family: inherit; font-size: 13px; font-weight: 600;
    cursor: pointer;
    box-shadow: var(--shadow-blue);
    transition: background 160ms ease, transform 160ms ease, box-shadow 160ms ease;
  }
  @media (hover: hover) {
    .nav-create-btn:hover {
      background: var(--blue-hover);
      transform: translateY(-1px);
    }
  }
  .nav-create-plus {
    font-size: 18px; font-weight: 400; line-height: 1;
    width: 20px; display: inline-flex; align-items: center; justify-content: center;
  }
  .nav-create-label { flex: 1; text-align: left; }
  .nav-create-chev { font-size: 10px; opacity: 0.75; }
  .nav-create-btn[aria-expanded="true"] .nav-create-chev { transform: rotate(180deg); }
  .nav-create-menu {
    position: absolute; left: 0; right: 0; top: calc(100% + 6px);
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 6px;
    box-shadow: var(--shadow-card);
    display: flex; flex-direction: column; gap: 2px;
    z-index: 50;
  }
  .nav-create-menu[hidden] { display: none; }
  .nav-create-item {
    text-align: left;
    background: none; border: none;
    color: var(--text); font-family: inherit; font-size: 13px;
    padding: 8px 10px; border-radius: 8px;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
  }
  @media (hover: hover) {
    .nav-create-item:hover {
      background: var(--blue-soft);
      color: var(--blue-bright);
    }
  }

  /* ── Recents mini-list (refinement D) ────────────────────────────────
     Last 5 jobs/clients viewed. Hidden by JS when empty. Each row is a
     compact nav-item-style button with the entity name + a small
     subtitle (client name / address / "Client"). */
  .nav-recents {
    margin: 0 0 14px;
  }
  .nav-recents[hidden] { display: none; }
  .nav-recents-label {
    padding: 4px 14px 6px;
  }
  .nav-recents-list {
    display: flex; flex-direction: column; gap: 2px;
  }
  .nav-recent-item {
    display: flex; flex-direction: column;
    width: 100%;
    padding: 6px 14px;
    border-radius: 10px;
    background: none; border: none;
    color: var(--text-soft);
    font-family: inherit; text-align: left;
    cursor: pointer;
    transition: background 160ms ease, color 160ms ease;
  }
  @media (hover: hover) {
    .nav-recent-item:hover {
      background: rgba(255, 255, 255, 0.04);
      color: var(--text-strong);
    }
  }
  .nav-recent-name {
    font-size: 13px; font-weight: 500;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .nav-recent-meta {
    font-size: 10.5px; color: var(--text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  @media (hover: hover) {
    [data-theme="light"] .nav-recent-item:hover {
      background: rgba(15, 23, 42, 0.04);
    }
  }

  /* ── Hubs ────────────────────────────────────────────────────────────
     A hub is a primary nav slot (Work / Schedule / Billing / Crew) that
     expands to reveal sub-items. The head is itself a .nav-item so it
     inherits hover + spacing; the body is a flex column of .nav-sub
     items that slides in when .nav-hub-open is set on the parent. */
  .nav-hub {
    display: flex; flex-direction: column;
    gap: 2px;
    /* Positioning context so the drag-reorder grip (.nav-grip is position:
       absolute) lands on the hub head instead of resolving against the sticky
       sidebar. Without this every hub's grip piled at the sidebar's top-left
       corner and the hubs couldn't be grabbed to reorder. (Latent bug, not new
       — fixed 2026-07-05.) */
    position: relative;
  }
  .nav-hub-head .nav-hub-chev {
    font-size: 12px; opacity: 0.6;
    margin-left: 4px;
    /* Expand the click target — the chevron is the explicit collapse
       affordance, so give it real area instead of a 10px glyph. */
    padding: 6px 8px; margin-right: -4px;
    border-radius: 4px;
    transition: transform 160ms ease, opacity 160ms ease, background-color 120ms ease;
  }
  /* Hub headers are tap targets too — same two-tap trap as .nav-item. */
  @media (hover: hover) {
    .nav-hub-head:hover .nav-hub-chev { opacity: 0.9; }
    .nav-hub-head .nav-hub-chev:hover {
      background: rgba(255, 255, 255, 0.06);
      opacity: 1;
    }
  }
  .nav-hub.nav-hub-open .nav-hub-head .nav-hub-chev {
    transform: rotate(180deg); opacity: 0.9;
  }
  .nav-hub-body {
    display: none;
    flex-direction: column;
    gap: 1px;
    padding: 2px 0 4px 12px;
    margin-bottom: 2px;
  }
  .nav-hub.nav-hub-open .nav-hub-body { display: flex; }
  /* Hub that contains the currently-active sub-item: subtle hint that the
     parent is "the right way home." Soft blue text on the head, no fill,
     so the actual active sub-item still wins the eye. */
  .nav-hub.nav-hub-has-active .nav-hub-head .nav-label {
    color: var(--blue-light);
  }
  /* Sub-items: smaller, indented, no icon — visual hierarchy. */
  .nav-item.nav-sub {
    height: 34px;
    padding-left: 16px;
    font-size: 13px;
    color: var(--text-muted);
  }
  @media (hover: hover) {
    .nav-item.nav-sub:hover {
      color: var(--text-strong);
    }
  }
  /* Active sub-item uses the same blue tint + left bar as primary
     nav-items (defined in Phase 1.1), but the bar lives further left
     because of the indent — adjust position. */
  .nav-item.nav-sub.active::before {
    left: 6px;
    height: 50%;
  }
  /* An item dragged INTO a hub becomes a sub-item; hide its icon so it reads
     like the natively-authored (icon-less) sub-items. The <svg> node stays in
     the DOM (display:none), so the page-header icon cloning still finds it. */
  .nav-item.nav-sub .nav-icon { display: none; }

  /* ── Sidebar tab reordering (drag-and-drop) ──────────────────────────────
     Grip handle fades in on hover; it's the only thing that starts a drag, so
     ordinary clicks-to-navigate are never mistaken for a drag. Positioned in
     the left padding gutter so it doesn't shove the icon/label. */
  .nav-grip {
    position: absolute;
    top: 50%; left: 1px;
    transform: translateY(-50%);
    width: 14px; height: 26px;
    display: flex; align-items: center; justify-content: center;
    color: var(--text-faint);
    opacity: 0; cursor: grab;
    border-radius: 4px; z-index: 2;
    transition: opacity .12s ease, color .12s ease, background .12s ease;
  }
  .nav-hub > .nav-grip { top: 22px; }   /* ride the hub HEAD row, not the whole hub */
  /* The grip revealing on nav-item hover is itself a rendering change on the
     first tap, so it has to go behind the query too or it re-arms the two-tap
     on every row. Touch gets a permanently visible grip instead — see the
     (any-pointer: coarse) block near the end of this file. */
  @media (hover: hover) {
    .nav-item:hover > .nav-grip,
    .nav-hub:hover  > .nav-grip { opacity: 0.5; }
    .nav-grip:hover { opacity: 1; color: var(--text-soft); background: rgba(255,255,255,0.07); }
    [data-theme="light"] .nav-grip:hover { background: rgba(15,23,42,0.06); }
  }
  .nav-grip:active { cursor: grabbing; }
  /* Drag feedback. */
  .nav-dragging { opacity: 0.4; }
  /* Insertion bar — a thick glowing pill in the seam where the drop will
     land (the old 2px inset shadow hid inside the row's rounded corners and
     was easy to miss). Rendered as ::after so it can't collide with the
     .active::before accent bar. Sub-item targets sit inside the hub body's
     12px indent, so their bar paints indented automatically — indented bar
     + hub ring = "inside the folder"; full-width bar = top level. */
  .nav-drop-before::after,
  .nav-drop-after::after {
    content: '';
    position: absolute;
    left: 6px; right: 6px;
    height: 4px;
    border-radius: 999px;
    background: var(--blue-bright);
    box-shadow: 0 0 0 1px var(--bg), 0 0 10px 2px rgba(59,130,246,0.55);
    pointer-events: none;
    z-index: 6;
  }
  .nav-drop-before::after { top: -4px; }
  .nav-drop-after::after  { bottom: -4px; }
  /* Hub the drop would land INSIDE — ring + tint the whole folder for as
     long as the drop resolves into it, so inside-vs-beside is never a
     guess; the insertion bar marks the exact slot between its sub-items. */
  .nav-into {
    box-shadow: inset 0 0 0 2px var(--blue);
    border-radius: 12px;
    background: var(--blue-soft);
  }
  .nav-into > .nav-hub-head .nav-label { color: var(--blue-bright); }

  /* ── Sidebar collapse toggle + off-canvas mechanics ──────────────────────
     A small tab on the sidebar's right border. Collapsing slides the sidebar
     off-canvas (transform) and drops it from the flex flow (negative margin)
     so main reclaims the width; the tab parks at the screen edge as a pull
     handle. The collapse class lives on <html> (.sidebar-collapsed) so the
     <head> bootstrap can pre-apply it before paint. */
  .sidebar { transition: transform 0.26s ease, margin-left 0.26s ease; will-change: transform; }
  .sidebar-toggle {
    position: fixed; top: 50%; left: 250px;
    transform: translate(-50%, -50%);
    width: 22px; height: 52px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: var(--panel); color: var(--text-soft);
    border: 1px solid var(--border); border-radius: 8px;
    cursor: pointer; z-index: 80;
    box-shadow: var(--shadow-card);
    transition: left 0.26s ease, transform 0.26s ease,
                background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  }
  .sidebar-toggle:hover {
    background: var(--panel-2); color: var(--text-strong); border-color: var(--border-strong);
  }
  .sidebar-toggle svg { width: 15px; height: 15px; transition: transform 0.2s ease; }
  .sidebar-collapsed .sidebar {
    margin-left: -250px;
    transform: translateX(-100%);
    border-right-width: 0;
    pointer-events: none;
  }
  .sidebar-collapsed .sidebar-toggle {
    left: 0;
    transform: translate(0, -50%);
    border-top-left-radius: 0; border-bottom-left-radius: 0;
  }
  .sidebar-collapsed .sidebar-toggle svg { transform: rotate(180deg); }

  .sidebar-footer {
    margin-top: auto; padding-top: 18px;
    display: flex; flex-direction: column; gap: 10px;
  }
  /* Theme toggle — small sun/moon button that flips dark↔light app-wide.
     Sits above the profile card so it's easy to reach. Persists to
     localStorage; first visit honors prefers-color-scheme. */
  .theme-toggle {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; padding: 9px 12px;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--panel-3);
    color: var(--text-soft); font-family: inherit;
    font-size: 11.5px; font-weight: 600; letter-spacing: 0.04em;
    cursor: pointer; user-select: none;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .theme-toggle:hover {
    border-color: var(--border-strong);
    color: var(--text);
    background: var(--panel-2);
  }
  .theme-toggle-label { text-transform: uppercase; }
  .theme-toggle-icons {
    display: inline-flex; align-items: center; gap: 4px;
  }
  .theme-toggle-icon {
    width: 16px; height: 16px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%;
    transition: color 0.15s, background 0.15s, transform 0.15s;
  }
  .theme-toggle-icon svg { width: 14px; height: 14px; }
  /* Active icon is highlighted; inactive is muted. The .is-light class on
     the toggle itself flags the active mode so we can swap which icon
     glows without re-rendering. */
  .theme-toggle .theme-toggle-icon-moon { color: var(--blue-light); }
  .theme-toggle .theme-toggle-icon-sun  { color: var(--text-faint); }
  .theme-toggle.is-light .theme-toggle-icon-moon { color: var(--text-faint); }
  .theme-toggle.is-light .theme-toggle-icon-sun  { color: var(--amber); }

  .sidebar-profile {
    display: flex; align-items: center; gap: 12px;
    padding: 12px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    background: var(--panel);
  }
  .sp-avatar {
    width: 42px; height: 42px; flex-shrink: 0;
    border-radius: 50%;
    background: rgba(59,130,246,0.18);
    color: var(--blue-light);
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: 13px; letter-spacing: 0.02em;
  }
  .sp-info { flex: 1; min-width: 0; text-align: left; }
  .sp-name {
    display: block;
    font-size: 13px; font-weight: 500; color: var(--text-strong);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .sp-role {
    display: block;
    font-size: 11.5px; color: var(--text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }

  /* Profile is now a clickable hub (Phase 3.2). Wrap holds the button
     and the popover above it. The button reuses .sidebar-profile
     styling but gains a chevron + hover affordance. */
  .sidebar-profile-wrap {
    position: relative;
    display: flex; align-items: stretch; gap: 8px;
  }
  .sidebar-profile-wrap > button.sidebar-profile { flex: 1 1 auto; width: auto; min-width: 0; }
  /* Make .sidebar-profile work as a <button> instead of a <div>. */
  button.sidebar-profile {
    width: 100%;
    font-family: inherit;
    cursor: pointer;
    transition: background 160ms ease, border-color 160ms ease;
  }
  button.sidebar-profile:hover {
    background: var(--panel-2);
    border-color: var(--border-strong);
  }
  .sp-chev {
    font-size: 10px; color: var(--text-muted);
    flex-shrink: 0;
    transition: transform 160ms ease;
  }
  button.sidebar-profile[aria-expanded="true"] .sp-chev {
    transform: rotate(180deg);
  }
  .sidebar-profile-menu {
    position: absolute; left: 0; right: 0; bottom: calc(100% + 8px);
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 6px;
    box-shadow: var(--shadow-card);
    display: flex; flex-direction: column; gap: 2px;
    z-index: 60;
  }
  .sidebar-profile-menu[hidden] { display: none; }
  .sp-menu-item {
    display: flex; align-items: center; gap: 10px;
    width: 100%;
    background: none; border: none;
    color: var(--text); font-family: inherit; font-size: 13px;
    padding: 8px 10px; border-radius: 8px;
    text-align: left;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
  }
  .sp-menu-item:hover {
    background: var(--blue-soft);
    color: var(--blue-bright);
  }
  .sp-menu-icon {
    flex-shrink: 0; width: 18px; height: 18px;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--text-muted);
  }
  .sp-menu-item:hover .sp-menu-icon { color: var(--blue-bright); }
  .sp-menu-icon svg { width: 16px; height: 16px; }
  .sp-menu-sep {
    height: 1px; background: var(--border);
    margin: 4px 6px;
  }
  .sp-menu-meta {
    font-size: 10.5px; color: var(--text-muted);
    padding: 4px 10px 6px;
  }

  /* QBO token menu item — two-line layout (label + live expiry status) plus a
     status dot. refreshQboStatus() (99-boot.js) sets data-qbo-state on the
     item + dot: ok (green) | warn (amber, ≤14 days) | bad (red, expired/none)
     | unknown. So the ~100-day refresh-token expiry is visible before it
     silently breaks billing. */
  .sp-menu-item-qbo { align-items: center; }
  .sp-qbo-text {
    display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1;
    text-align: left;
  }
  .sp-qbo-label { font-size: 13px; color: inherit; }
  .sp-qbo-status {
    font-size: 10.5px; line-height: 1.3; color: var(--text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .sp-menu-item-qbo[data-qbo-state="warn"] .sp-qbo-status { color: var(--amber); }
  .sp-menu-item-qbo[data-qbo-state="bad"]  .sp-qbo-status { color: var(--red); }
  .sp-qbo-dot {
    flex-shrink: 0;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--text-faint);
  }
  .sp-qbo-dot[data-qbo-state="ok"]   { background: var(--green); }
  .sp-qbo-dot[data-qbo-state="warn"] { background: var(--amber); }
  .sp-qbo-dot[data-qbo-state="bad"]  { background: var(--red); }

  .main {
    flex: 1; min-width: 0;
    padding: 28px 32px 48px;
  }
  .main-inner { max-width: 1600px; }

  /* ── Page header (title + actions) ── */
  .page-header {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 20px; margin-bottom: 26px; padding-bottom: 22px;
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
  }
  /* Left side of the page header: section icon (set by updatePageHeader
     in 06-render.js by cloning the matching sidebar nav-item's SVG)
     plus the title/subtitle block. Reinforces "where am I" so the user
     ties the page to its sidebar entry. */
  .page-header-title {
    display: flex; align-items: flex-start; gap: 16px;
    min-width: 0; flex: 1 1 0;
  }
  .page-header-text { min-width: 0; }
  .page-icon {
    flex-shrink: 0;
    width: 44px; height: 44px;
    border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--blue-soft);
    color: var(--blue-bright);
    margin-top: 2px;
  }
  .page-icon:empty { display: none; }
  .page-icon svg { width: 24px; height: 24px; }
  .page-header h1 {
    font-size: 32px; font-weight: 600; color: var(--text-strong);
    letter-spacing: -0.02em; line-height: 1.1;
  }
  .page-header .page-sub {
    font-size: 14px; color: var(--text-soft); margin-top: 8px;
  }
  /* When the subtitle is empty (data-dense views: Dashboard, Clients,
     Reports, Permits, Fleet, Crew, Tool Inventory, Product Inventory),
     drop it from the layout entirely so the header doesn't reserve
     vertical space. Workflow views (Today, New Job, Leads/Scheduling/
     Projects, Quote Builder, Billing, Calendar, Map, Job detail) still
     get a subtitle as a workflow hint. */
  .page-header .page-sub:empty { display: none; margin-top: 0; }
  .page-header-actions {
    display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
    position: relative;
    /* Balance against .page-header-title (also flex:1 1 0) so the search
       between them sits centered on the page. Right-align the controls. */
    flex: 1 1 0; justify-content: flex-end;
  }

  /* ── Top-right theme toggle (moved from sidebar 2026-07-05) ──────────
     Reuse the .theme-toggle element but render it as a compact 40×40 icon
     button matching the notification bell. Hide the "Dark"/"Light" text
     label and show only the icon for the CURRENT mode. */
  .page-header-actions .theme-toggle {
    width: 40px; height: 40px; padding: 0; gap: 0;
    justify-content: center;
    border-radius: 12px;
    background: var(--panel); color: var(--text-soft);
  }
  .page-header-actions .theme-toggle:hover {
    background: var(--row-hover); border-color: var(--border-strong);
    color: var(--text-strong); transform: translateY(-1px);
  }
  .page-header-actions .theme-toggle .theme-toggle-label { display: none; }
  .page-header-actions .theme-toggle .theme-toggle-icon { width: 18px; height: 18px; }
  .page-header-actions .theme-toggle .theme-toggle-icon svg { width: 18px; height: 18px; }
  /* Show only the active-mode icon. Default (dark) → moon; .is-light → sun. */
  .page-header-actions .theme-toggle .theme-toggle-icon-sun { display: none; }
  .page-header-actions .theme-toggle.is-light .theme-toggle-icon-moon { display: none; }
  .page-header-actions .theme-toggle.is-light .theme-toggle-icon-sun { display: inline-flex; }

  /* ── Top-right account card (moved from sidebar 2026-07-05) ──────────
     Full card (avatar + name + role) but sized to the 40px header row, and
     its menu opens DOWNWARD (the sidebar version opened upward). */
  .page-header-actions .sidebar-profile-wrap { align-items: center; }
  .page-header-actions .sidebar-profile {
    padding: 5px 12px 5px 6px;
    border-radius: 12px;
    background: var(--panel);
  }
  .page-header-actions .sidebar-profile .sp-avatar { width: 32px; height: 32px; font-size: 12px; }
  .page-header-actions .sidebar-profile .sp-name { font-size: 12.5px; }
  .page-header-actions .sidebar-profile .sp-role { font-size: 11px; }
  .page-header-actions .sidebar-profile-menu {
    top: calc(100% + 8px); bottom: auto;
    left: auto; right: 0;
    min-width: 224px;
  }

  /* (Notification-bell CSS removed 2026-07-05 along with the bell itself —
     it was an unwired placeholder. QBO token-expiry status now lives on the
     account-menu item; see .sp-menu-item-qbo / .sp-qbo-* above.) */
  .button.primary {
    background: var(--blue);
    color: var(--on-color); border-color: transparent; font-weight: 600;
    box-shadow: var(--shadow-blue);
  }
  .button.primary:hover {
    background: var(--blue-hover);
    transform: translateY(-1px);
  }

  /* ── Dashboard ── */
  .dashboard-grid {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
    margin-bottom: 24px;
  }
  .dashboard-card {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 14px; padding: 18px;
    display: flex; flex-direction: column; gap: 12px;
    min-height: 260px;
  }
  .dashboard-card-head {
    display: flex; align-items: center; gap: 10px;
  }
  .dashboard-card-head .dc-dot {
    width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0;
  }
  .dashboard-card-head h3 {
    font-size: 14px; font-weight: 600; color: var(--text-strong);
    flex: 1;
  }
  .dashboard-card-head .dc-count {
    background: rgba(255,255,255,0.05);
    color: var(--text-soft); padding: 2px 10px; border-radius: 100px;
    font-size: 11px; font-weight: 600;
  }
  .dashboard-card .dc-sub {
    font-size: 11.5px; color: var(--text-muted); margin-top: -6px;
  }
  .dashboard-card ul {
    list-style: none; display: flex; flex-direction: column; gap: 6px;
    max-height: 420px; overflow-y: auto;
  }
  .dashboard-card li {
    padding: 10px 12px; border-radius: 8px;
    background: var(--panel-3); border: 1px solid var(--border-subtle);
    font-size: 12.5px; color: var(--text);
    display: flex; flex-direction: column; gap: 3px;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s;
  }
  .dashboard-card li:hover { border-color: var(--border-strong); background: var(--panel); }
  .dashboard-card li[draggable="true"] { cursor: grab; }
  .dashboard-card li.dc-dragging { opacity: 0.4; cursor: grabbing; }
  .dashboard-card.dc-drop-target {
    outline: 2px dashed var(--blue-bright);
    outline-offset: 2px;
    background: rgba(96,165,250,0.06);
  }

  /* ── New Job view — embedded Form Builder iframe ──────────────────── */
  .new-job-frame-wrap {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-card);
    overflow: hidden;
    min-height: calc(100vh - 220px);
    display: flex;
  }
  #new-job-frame {
    flex: 1;
    width: 100%;
    min-height: calc(100vh - 220px);
    border: 0;
    background: transparent;
  }

  /* Generic iframe wrapper used by Billing / Load Calc / Panel Schedule. */
  .tool-frame-wrap {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-card);
    overflow: hidden;
    min-height: calc(100vh - 220px);
    display: flex;
  }
  .tool-frame {
    flex: 1; width: 100%;
    min-height: calc(100vh - 220px);
    border: 0; background: transparent;
  }
  .tool-placeholder {
    background: var(--panel); border: 1px dashed var(--border-strong);
    border-radius: var(--radius-lg);
    padding: 40px 44px;
    max-width: 640px; margin: 20px auto;
    color: var(--text-soft);
  }
  .tool-placeholder h2 { color: var(--text); margin: 0 0 12px; font-size: 18px; }
  .tool-placeholder p  { margin: 0 0 10px; font-size: 13px; line-height: 1.5; }
  .tool-placeholder code {
    background: var(--panel-3); border: 1px solid var(--border);
    padding: 1px 6px; border-radius: 4px;
    font-size: 12px; color: var(--text);
  }
  .tool-placeholder-hint { font-size: 12px; color: var(--text-muted); font-style: italic; }
  .tool-placeholder-sub { font-size: 13px; color: var(--text-muted); margin: 4px 0 18px; }
  .tool-placeholder .button { margin-top: 10px; display: inline-block; }

  /* ── Quote templates (Quote Builder v1) ───────────────────────────
     Saved sets of line items the user can apply to a fresh QBO
     estimate. Card grid like Reports/Fleet. Editor modal for CRUD,
     Use modal for customer-pick + push. */
  .qt-toolbar {
    display: flex; align-items: center; gap: 14px;
    margin-bottom: 16px;
  }
  .qt-toolbar-count { font-size: 12px; color: var(--text-muted); }
  .qt-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px;
  }
  .qt-card {
    background: var(--panel-3);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: 14px;
    display: flex; flex-direction: column; gap: 8px;
    transition: border-color 0.12s, background 0.12s;
  }
  .qt-card:hover { border-color: var(--border-strong); background: var(--panel); }
  .qt-card-head { display: flex; align-items: baseline; gap: 10px; }
  .qt-card-head h3 {
    flex: 1; margin: 0;
    font-size: 14.5px; font-weight: 600; color: var(--text-strong);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .qt-card-total {
    font-size: 13px; font-weight: 600; color: var(--green-text);
    font-variant-numeric: tabular-nums;
  }
  .qt-card-desc { font-size: 12px; color: var(--text-soft); line-height: 1.4; }
  .qt-card-sample { font-size: 11.5px; color: var(--text-muted); line-height: 1.4; }
  .qt-card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }
  .qt-card-delete { color: var(--red-text) !important; }
  .qt-empty {
    text-align: center; padding: 40px 20px;
    color: var(--text-muted);
    border: 1px dashed var(--border); border-radius: 10px;
  }
  .qt-empty-hint { font-size: 12px; color: var(--text-soft); margin-top: 8px; }
  /* Editor + Use modals share the line-item table. */
  .qt-edit-modal, .qt-use-modal {
    max-width: 760px;
    width: 90vw;
  }
  .qt-modal-label {
    display: block; margin-top: 12px;
    font-size: 12px; color: var(--text-muted);
  }
  .qt-edit-modal input[type="text"],
  .qt-edit-modal input[type="number"],
  .qt-edit-modal textarea,
  .qt-edit-modal select,
  .qt-use-modal input[type="text"],
  .qt-use-modal input[type="number"],
  .qt-use-modal select {
    width: 100%;
    padding: 6px 8px;
    margin-top: 4px;
    background: var(--panel); color: var(--text);
    border: 1px solid var(--border); border-radius: 4px;
    font: inherit; font-size: 13px;
  }
  .qt-edit-modal textarea { resize: vertical; }
  .qt-rows-head {
    display: flex; align-items: center; justify-content: space-between;
    margin: 16px 0 6px;
  }
  .qt-rows-head h3 { margin: 0; font-size: 13px; color: var(--text); }
  .qt-rows {
    width: 100%;
    border-collapse: collapse;
    font-size: 12.5px;
  }
  .qt-rows th, .qt-rows td {
    padding: 4px 6px; vertical-align: middle;
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .qt-rows th {
    text-align: left;
    font-size: 11px; font-weight: 600; text-transform: uppercase;
    color: var(--text-muted); letter-spacing: 0.04em;
  }
  .qt-rows td input,
  .qt-rows td select {
    margin-top: 0 !important;
  }
  .qt-row-total {
    text-align: right; font-variant-numeric: tabular-nums;
    color: var(--text);
  }
  .qt-use-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
    margin-top: 6px;
  }

  /* Reports grid — one card per eventual QBO favorite. */
  .reports-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 16px; margin-top: 14px;
  }
  .report-card {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: var(--radius-lg); padding: 18px 20px;
    display: flex; flex-direction: column; gap: 8px;
    transition: border-color 0.15s, transform 0.15s;
    cursor: pointer;
  }
  .report-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }
  .report-card-title { font-weight: 600; color: var(--text); font-size: 15px; }
  .report-card-hint  { font-size: 12.5px; color: var(--text-soft); }
  /* Report detail view */
  .rpt-detail { display: flex; flex-direction: column; min-height: 0; }
  .rpt-detail-head {
    display: flex; align-items: center; gap: 12px;
    padding-bottom: 14px; border-bottom: 1px solid var(--border); margin-bottom: 16px; flex-shrink: 0;
  }
  .rpt-back-btn {
    background: none; border: 1px solid var(--border); border-radius: var(--radius-md);
    color: var(--text-soft); padding: 6px 12px; cursor: pointer; font-size: 13px; font-family: inherit;
    transition: border-color 0.15s, color 0.15s;
  }
  .rpt-back-btn:hover { border-color: var(--border-strong); color: var(--text); }
  .rpt-detail-title  { font-weight: 600; font-size: 16px; flex: 1; }
  /* Date range picker in the reports detail head. Only renders for reports
     whose meta.takesDates is true; from/to inputs + a preset dropdown for
     common ranges (This month / This quarter / This FY / Last 30 days …). */
  .rpt-date-picker {
    display: inline-flex; align-items: center; gap: 8px;
    flex-shrink: 0;
  }
  .rpt-date-label {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 11px; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 0.06em;
  }
  .rpt-date-label input[type="date"],
  .rpt-date-preset {
    background: var(--panel-3);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 5px 8px;
    color: var(--text);
    font-family: inherit;
    font-size: 12.5px;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
  }
  .rpt-date-label input[type="date"]:hover,
  .rpt-date-preset:hover {
    border-color: var(--border-strong);
  }
  .rpt-date-label input[type="date"]:focus,
  .rpt-date-preset:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.18);
  }
  /* Tint the native date-picker icon in dark mode so it doesn't look black */
  [data-theme="dark"] .rpt-date-label input[type="date"]::-webkit-calendar-picker-indicator {
    filter: invert(0.6);
  }
  .rpt-refresh-btn   { height: 34px; padding: 0 14px; font-size: 12.5px; }
  .rpt-detail-body   { overflow: auto; flex: 1; }
  .rpt-sortable      { cursor: pointer; user-select: none; }
  .rpt-sort-active   { color: var(--blue-bright); }

  .rpt-loading { color: var(--text-soft); font-size: 14px; padding: 20px 0; display: flex; align-items: center; gap: 6px; }
  .rpt-error   { color: var(--red-bright); font-size: 13.5px; padding: 12px 0; }
  .rpt-error-detail { font-size: 11px; color: var(--text-muted); margin-top: 8px; white-space: pre-wrap; word-break: break-all; }
  .rpt-period  { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }

  .rpt-table-wrap { overflow-x: auto; }
  .rpt-table { width: 100%; border-collapse: collapse; font-size: 13px; }

  .rpt-table thead th {
    text-align: right; color: var(--text-soft); font-weight: 500; font-size: 11.5px;
    padding: 4px 10px 8px; border-bottom: 1px solid var(--border); white-space: nowrap;
  }
  .rpt-table thead th.rpt-label { text-align: left; padding-left: 8px; }

  .rpt-table tbody tr { border-bottom: 1px solid transparent; }
  /* Zebra striping — subtle row alternation makes long P&L scans easier
     on the eye without competing with the data itself. Skipped for section
     headers/sums so groupings still read cleanly. */
  .rpt-table tbody tr.rpt-data:nth-child(even) td { background: rgba(255,255,255,0.018); }
  .rpt-table tbody tr:hover td { background: var(--hover, rgba(255,255,255,0.05)); }

  .rpt-label { text-align: left; color: var(--text); white-space: nowrap; padding: 3px 16px 3px 8px; }
  .rpt-num   { text-align: right; color: var(--text); white-space: nowrap; padding: 3px 10px; font-variant-numeric: tabular-nums; }

  tr.rpt-section-head td {
    font-weight: 600; color: var(--text-soft); font-size: 11px;
    letter-spacing: 0.05em; text-transform: uppercase; padding-top: 12px;
  }

  tr.rpt-section-sum td { font-weight: 600; border-top: 1px solid var(--border); padding-top: 5px; padding-bottom: 8px; }
  tr.rpt-section-sum .rpt-total-num { color: var(--blue-bright); }

  tr.rpt-data td.rpt-label { color: var(--text-soft); }
  tr.rpt-data:hover td.rpt-label { color: var(--text); }

  /* ── Fleet Maintenance view ──────────────────────────────────────────
     Internal CRM view, mirrors the Reports look. List = grid of vehicle
     cards; detail = chronological per-vehicle timeline. The "rollup" tile
     row at the top is a compact KPI strip; the placeholders block out
     where mobile-app inputs (KM, notes) will land. */
  .fleet-meta {
    color: var(--text-muted); font-size: 12px;
    flex: 1;
  }
  .fleet-meta code {
    background: var(--panel-3); border: 1px solid var(--border);
    padding: 1px 6px; border-radius: 4px; font-size: 11.5px; color: var(--text-soft);
  }
  .fleet-list-head {
    display: flex; align-items: center; gap: 12px;
    margin: 4px 0 14px;
  }
  .fleet-head-actions {
    margin-left: auto;
    display: flex; gap: 8px; align-items: center;
  }
  .fleet-stats-btn {
    height: 34px; padding: 0 12px; font-size: 12.5px;
  }
  .fleet-stats-btn-icon {
    display: inline-block;
    font-size: 10px;
    margin-right: 2px;
    opacity: 0.7;
  }

  .fleet-rollup {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px; margin-bottom: 18px;
  }
  .fleet-rollup-card {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 12px 14px;
    display: flex; flex-direction: column; gap: 4px;
  }
  .fleet-rollup-num { font-weight: 600; color: var(--text); font-size: 16px; font-variant-numeric: tabular-nums; }
  .fleet-rollup-lab { font-size: 11.5px; color: var(--text-muted); }

  .fleet-grid {
    display: grid;
    grid-template-columns: 1fr;  /* single column, vertical stack, sorted by oil-due (08-fleet.js) */
    gap: 14px;
  }
  .fleet-card {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 0;
    /* Horizontal layout: thumb on the left as a fixed-width column,
       all the card content on the right. The grid's auto-fit minmax
       sets card width; thumb stays a constant 220px so photos look
       uniform regardless of card width. */
    display: grid;
    grid-template-columns: 220px 1fr;
    transition: border-color 0.15s, transform 0.15s;
    cursor: pointer;
    overflow: hidden;
    min-height: 165px;          /* matches 4:3 thumb height (220*0.75) */
  }
  .fleet-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }
  .fleet-card-unassigned {
    border-style: dashed;
    /* Unassigned bucket has no photo — collapse to a single column */
    grid-template-columns: 1fr;
    padding: 16px 18px;
    min-height: auto;
  }

  /* Vehicle thumbnail — left column of the card. Fixed 4:3 aspect at
     220x165 so every vehicle looks uniformly sized. object-fit cover
     means slight differences in source-photo composition don't bleed
     through. */
  .fleet-card-thumb-wrap {
    width: 220px;
    align-self: stretch;        /* fill full card height */
    background: var(--surface-deep);
    border-right: 1px solid var(--border);
  }
  .fleet-card-thumb {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 60%;
  }
  /* Right-hand content column — restore padding + vertical spacing. */
  .fleet-card-body {
    padding: 14px 18px 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;               /* let flex children shrink rather than blow out */
  }
  /* Narrow screens — stack thumb on top instead of side-by-side. */
  @media (max-width: 700px) {
    .fleet-card {
      grid-template-columns: 1fr;
      min-height: auto;
    }
    .fleet-card-thumb-wrap {
      width: 100%;
      height: 160px;
      border-right: 0;
      border-bottom: 1px solid var(--border);
    }
  }
  .fleet-card-head {
    display: flex; align-items: center; gap: 10px;
  }
  .fleet-card-title { font-weight: 600; color: var(--text); font-size: 15px; flex: 1; }
  /* Last-activity chip in the card head row (was a bottom-stat-grid
     entry before — moved up next to the title per Matt 2026-05-20). */
  .fleet-card-head-meta {
    font-size: 12px; color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    margin-right: 6px;
  }
  /* Card stats grid is still defined in case other surfaces use it
     (Today page roll-up etc.) — but the Fleet vehicle cards no longer
     render it. */
  .fleet-card-stats {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
  }
  .fleet-card-stats-3 { grid-template-columns: repeat(3, 1fr); }
  .fleet-stat { display: flex; flex-direction: column; gap: 2px; }
  .fleet-stat-num {
    font-weight: 600; color: var(--text); font-size: 13.5px;
    font-variant-numeric: tabular-nums;
  }
  .fleet-stat-lab { font-size: 11px; color: var(--text-muted); }
  .fleet-stat-extra { color: var(--text-muted); font-style: italic; opacity: 0.85; }

  /* Activity list on each vehicle card — last 10 entries from the
     unified timeline (KM readings, oil changes, services interleaved
     newest-first), split into two columns of 5 so the card stays
     vertically compact (~matches the 165px thumb height). Matt
     2026-05-20. */
  .fleet-card-activity {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--panel-3);
    overflow: hidden;
  }
  .fleet-card-activity-col {
    display: flex; flex-direction: column;
    min-width: 0;
  }
  .fleet-card-activity-col + .fleet-card-activity-col {
    border-left: 1px solid var(--border);
  }
  .fleet-card-row {
    display: grid;
    /* date | km | badge | headline */
    grid-template-columns: 56px 76px 32px 1fr;
    gap: 6px;
    align-items: center;
    padding: 5px 10px;
    font-size: 12px;
    border-bottom: 1px solid var(--border);
    min-width: 0;
  }
  .fleet-card-row:last-child { border-bottom: 0; }
  .fleet-card-row-num-blank {
    color: var(--text-muted);
    opacity: 0.5;
    font-weight: 400;
  }
  /* On narrow viewports collapse back to one column so rows stay
     readable. */
  @media (max-width: 1100px) {
    .fleet-card-activity {
      grid-template-columns: 1fr;
    }
    .fleet-card-activity-col + .fleet-card-activity-col {
      border-left: 0;
      border-top: 1px solid var(--border);
    }
  }
  .fleet-card-row-date {
    color: var(--text-muted);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  .fleet-card-row-badge {
    display: inline-block;
    text-align: center;
    padding: 1px 0;
    border-radius: 4px;
    font-size: 9.5px; font-weight: 700; letter-spacing: 0.5px;
  }
  .fleet-card-row-body {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0;
  }
  .fleet-card-row-num { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
  .fleet-card-row-src { color: var(--text-muted); font-size: 11.5px; }
  .fleet-card-row-vendor { font-weight: 600; color: var(--text); }
  .fleet-card-row-ref { color: var(--text-muted); font-size: 11.5px; }
  .fleet-card-row-amt {
    color: var(--text); font-weight: 500;
    font-variant-numeric: tabular-nums;
    margin-left: 4px;
  }
  .fleet-card-row-amt.declined {
    color: var(--text-muted); text-decoration: line-through;
    font-style: italic;
  }
  .fleet-card-activity-empty {
    padding: 14px;
    text-align: center;
    color: var(--text-muted);
    font-size: 12px;
    border: 1px dashed var(--border);
    border-radius: var(--radius-md);
  }
  .fleet-card-pending {
    font-size: 11.5px; color: var(--amber-bright, #f59e0b);
    background: rgba(245, 158, 11, 0.08); border: 1px solid rgba(245, 158, 11, 0.18);
    border-radius: 6px; padding: 6px 10px;
  }
  /* Distinct softer tone for "manual entry" — these aren't QBO-lookup-able,
     they're estimate-only / no-receipt events that need Matt to type in $. */
  .fleet-card-pending.fleet-card-pending-manual {
    color: var(--text-muted, #94a3b8);
    background: rgba(148, 163, 184, 0.07);
    border-color: rgba(148, 163, 184, 0.20);
    margin-top: 4px;
  }
  [data-theme="light"] .fleet-card-pending.fleet-card-pending-manual {
    color: #64748b;
    background: rgba(100, 116, 139, 0.08);
  }

  /* Vehicle ops row — odometer + next oil change + insurance. Sits between
     the driver pill row and the financial stats. Status colors mirror the
     alert tier (ok=neutral, soon=amber, overdue=red). Wraps rather than
     overflowing once the third (insurance) cell joined it — a narrow window
     drops it to a second line instead of clipping the expiry date. */
  .fleet-card-ops {
    display: flex; gap: 20px; align-items: flex-start; flex-wrap: wrap;
    row-gap: 10px;
    background: var(--panel-3); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 10px 12px;
  }
  .fleet-ops-stat { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
  /* Each stat sizes to its content (rather than the old 1fr 1fr grid
     that forced them to far-left and far-right of the card). Matt
     2026-05-20 — the "due in N km" sits right next to the odometer
     reading instead of all the way across. */
  .fleet-ops-stat + .fleet-ops-stat {
    padding-left: 20px;
    border-left: 1px solid var(--border);
  }
  .fleet-ops-num {
    font-weight: 600; color: var(--text); font-size: 14px;
    font-variant-numeric: tabular-nums;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .fleet-ops-lab { font-size: 11px; color: var(--text-muted); line-height: 1.4; }
  /* Stale-reading flag on the odometer cell — shown when the last KM
     reading is >30 days old. Amber so it reads as "attention needed"
     without screaming red-overdue. */
  .fleet-ops-stale {
    color: var(--amber-bright, #fbbf24);
    font-weight: 500;
  }
  [data-theme="light"] .fleet-ops-stale { color: #b45309; }

  .fleet-ops-ok       .fleet-ops-num { color: var(--green); }
  .fleet-ops-soon     .fleet-ops-num { color: var(--amber-bright); }
  .fleet-ops-overdue  .fleet-ops-num { color: var(--red-bright); }
  .fleet-ops-none     .fleet-ops-num { color: var(--text-muted); font-style: italic; font-weight: 500; }
  /* Expired-insurance sub-label. Red like the overdue tier, but on the LABEL
     line (the .fleet-ops-num above it already reads "EXPIRED") — an
     out-of-date policy is the one fleet state that is illegal to drive on,
     so it gets colour on both lines. */
  .fleet-ops-expired {
    color: var(--red-bright, #f87171);
    font-weight: 600;
  }
  [data-theme="light"] .fleet-ops-expired { color: #b91c1c; }

  /* Detail-view insurance bar — the full policy record + whether a reminder
     actually exists behind it. Border tint follows the same ops status
     classes as the card cell. */
  .fleet-detail-insurance {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    background: var(--panel-3); border: 1px solid var(--border);
    border-left-width: 3px;
    border-radius: var(--radius-md); padding: 10px 12px;
    margin: 0 0 12px;
  }
  .fleet-detail-insurance.fleet-ops-ok      { border-left-color: var(--green); }
  .fleet-detail-insurance.fleet-ops-soon    { border-left-color: var(--amber-bright); }
  .fleet-detail-insurance.fleet-ops-overdue { border-left-color: var(--red-bright); }
  .fleet-detail-insurance-main {
    display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0;
  }
  .fleet-detail-insurance-lab {
    font-size: 11px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.04em; color: var(--text-muted);
  }
  .fleet-detail-insurance-bits { font-size: 12px; color: var(--text-muted); }

  .fleet-ops-pill {
    display: inline-block; font-size: 12px; font-weight: 600;
    padding: 3px 10px; border-radius: 999px;
    background: var(--panel-3); border: 1px solid var(--border);
    color: var(--text-soft);
  }
  .fleet-ops-pill.fleet-ops-ok      { background: rgba(34,197,94,0.12);  color: var(--green); border-color: rgba(34,197,94,0.28); }
  .fleet-ops-pill.fleet-ops-soon    { background: rgba(245,158,11,0.12); color: var(--amber-bright); border-color: rgba(245,158,11,0.28); }
  .fleet-ops-pill.fleet-ops-overdue { background: rgba(248,113,113,0.12); color: var(--red-bright); border-color: rgba(248,113,113,0.28); }

  /* Card-level inline action buttons (Update KM / Log oil change). */
  .fleet-card-actions {
    display: flex; gap: 6px; flex-wrap: wrap;
  }
  .fleet-mini-btn {
    background: var(--panel-3); border: 1px solid var(--border);
    color: var(--text-soft); font-size: 11.5px; font-family: inherit;
    padding: 4px 10px; border-radius: 6px; cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
  }
  .fleet-mini-btn:hover { border-color: var(--border-strong); color: var(--text); }

  /* Detail-view ops panels (KM history, Oil change log, Notes placeholder) */
  .fleet-panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 12px; margin: 8px 0 18px;
  }
  .fleet-panel {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 12px 14px;
    display: flex; flex-direction: column; gap: 8px;
  }
  .fleet-panel-placeholder { border-style: dashed; }
  .fleet-panel-head {
    display: flex; align-items: center; gap: 10px;
  }
  .fleet-panel-title {
    font-weight: 600; color: var(--text-soft); font-size: 12.5px;
    flex: 1;
  }
  .fleet-panel-headline { display: flex; }
  .fleet-panel-empty { font-size: 12px; color: var(--text-muted); line-height: 1.5; }

  .fleet-log { display: flex; flex-direction: column; gap: 0; }
  .fleet-log-row {
    display: grid; grid-template-columns: 110px 1fr auto; gap: 10px;
    padding: 4px 0; font-size: 12.5px; color: var(--text-soft);
    border-top: 1px solid var(--border);
  }
  .fleet-log-row:first-child { border-top: 0; }
  .fleet-log-date { color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .fleet-log-val  { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 600; }
  .fleet-log-src  { color: var(--text-muted); text-align: right; }

  /* Mobile attention notes — wrap text in the value column instead of
     tabular-nums fixed-width. */
  .fleet-note-row .fleet-note-text {
    color: var(--text); font-weight: 400; line-height: 1.4;
    white-space: normal; word-break: break-word;
  }
  .fleet-note-row-done { opacity: 0.55; }
  .fleet-panel-pill {
    margin-left: auto;
    padding: 2px 9px; border-radius: 999px;
    font-size: 11px; font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  .fleet-panel-pill-amber {
    background: rgba(245, 158, 11, 0.18);
    color: var(--amber-text);
    border: 1px solid rgba(245, 158, 11, 0.35);
  }
  .fleet-note-history { margin-top: 10px; }
  .fleet-note-history summary {
    cursor: pointer; padding: 4px 0; font-size: 12px; color: var(--text-muted);
  }
  .fleet-note-history summary:hover { color: var(--text); }

  /* ─── Unified vehicle activity log ─────────────────────────────────── */
  .fleet-tl-panel { margin-bottom: 14px; }
  .fleet-tl-head {
    display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  }
  .fleet-tl-head .fleet-panel-title { flex: 0 1 auto; }
  .fleet-tl-headline { flex: 0 1 auto; }
  .fleet-tl-actions { margin-left: auto; display: flex; gap: 6px; }

  .fleet-tl-filters {
    display: flex; gap: 6px; flex-wrap: wrap;
    padding: 8px 0 12px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 8px;
  }
  .fleet-tl-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px;
    border-radius: 14px;
    background: rgba(148, 163, 184, 0.06);
    border: 1px solid rgba(148, 163, 184, 0.18);
    font-size: 12px; cursor: pointer;
    user-select: none;
    color: var(--text-muted);
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .fleet-tl-chip input { margin: 0; cursor: pointer; accent-color: #60a5fa; }
  .fleet-tl-chip.is-on { color: var(--text); }
  .fleet-tl-chip-km.is-on    { background: rgba(96, 165, 250, 0.14); border-color: rgba(96, 165, 250, 0.34); }
  .fleet-tl-chip-fuel.is-on  { background: rgba(167, 139, 250, 0.14); border-color: rgba(167, 139, 250, 0.34); }
  .fleet-tl-chip-oil.is-on   { background: rgba(74, 222, 128, 0.14); border-color: rgba(74, 222, 128, 0.34); }
  .fleet-tl-chip-service.is-on { background: rgba(245, 158, 11, 0.14); border-color: rgba(245, 158, 11, 0.34); }
  .fleet-tl-chip-count {
    font-size: 10.5px; padding: 0 6px;
    background: rgba(148, 163, 184, 0.20); border-radius: 999px;
    color: var(--text-soft, #94a3b8);
  }
  .fleet-tl-chip.is-on .fleet-tl-chip-count { color: var(--text); background: rgba(0,0,0,0.18); }

  /* KM rows in the unified timeline (oil/service rows reuse the existing
     .fleet-event styles via renderEventRow). */
  .fleet-tl-row {
    border-top: 1px solid var(--border);
    padding: 8px 0;
  }
  .fleet-tl-row:first-child { border-top: 0; }
  .fleet-tl-row-head {
    display: grid;
    grid-template-columns: 90px 32px 1fr 24px;
    gap: 10px; align-items: center;
  }
  .fleet-tl-date { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
  .fleet-tl-type {
    display: inline-flex; justify-content: center; align-items: center;
    font-size: 10px; font-weight: 700; letter-spacing: 0.5px;
    padding: 2px 0; border-radius: 4px;
    background: rgba(96, 165, 250, 0.14); color: var(--blue-bright);
    border: 1px solid rgba(96, 165, 250, 0.32);
  }
  .fleet-tl-headline { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
  .fleet-tl-km { font-weight: 600; font-variant-numeric: tabular-nums; }
  .fleet-tl-src { font-size: 12px; color: var(--text-muted); }
  .fleet-tl-has-notes { font-size: 11px; color: var(--amber-bright, #fbbf24); }
  /* FUEL badge + row accents (violet — distinct from KM blue, OIL green,
     SERVICE amber). Litres pill renders inline next to the odometer
     number so the "how full / how often" pattern is glance-readable
     without expanding the row. */
  .fleet-tl-type-fuel {
    background: rgba(167, 139, 250, 0.14); color: var(--violet);
    border-color: rgba(167, 139, 250, 0.34);
  }
  .fleet-tl-fuel-litres-pill {
    display: inline-block; padding: 1px 8px; border-radius: 10px;
    font-size: 11px; line-height: 1.6;
    background: rgba(167, 139, 250, 0.12); color: var(--violet);
    border: 1px solid rgba(167, 139, 250, 0.28);
    font-variant-numeric: tabular-nums;
  }
  .fleet-tl-fuel-litres { margin-bottom: 6px; }
  .fleet-tl-receipt-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px; margin: 4px 0 6px;
    border-radius: 6px; cursor: pointer;
    font-size: 12px;
    background: rgba(96, 165, 250, 0.10);
    color: var(--blue, #60a5fa);
    border: 1px solid rgba(96, 165, 250, 0.32);
    transition: background 0.12s;
  }
  .fleet-tl-receipt-btn:hover:not([disabled]) {
    background: rgba(96, 165, 250, 0.20);
  }
  .fleet-tl-receipt-btn[disabled] { opacity: 0.6; cursor: wait; }
  [data-theme="light"] .fleet-tl-fuel-litres-pill { background: #ede9fe; color: #7c3aed; border-color: var(--purple); }
  [data-theme="light"] .fleet-tl-receipt-btn { background: #dbeafe; color: #1d4ed8; border-color: var(--blue-light); }
  [data-theme="light"] .fleet-tl-receipt-btn:hover:not([disabled]) { background: #bfdbfe; }
  .fleet-tl-toggle {
    color: var(--text-muted); font-size: 12px; text-align: center;
    visibility: hidden;
  }
  .fleet-tl-row-expandable { cursor: pointer; }
  .fleet-tl-row-expandable .fleet-tl-toggle { visibility: visible; }
  .fleet-tl-row-expandable:hover { background: rgba(148, 163, 184, 0.04); }
  .fleet-tl-row.expanded .fleet-tl-toggle { transform: rotate(180deg); }

  .fleet-tl-body {
    display: none;
    padding: 6px 0 4px 132px;
    font-size: 12.5px;
    color: var(--text-soft, #cbd5e1);
  }
  .fleet-tl-row.expanded .fleet-tl-body { display: block; }
  .fleet-tl-fluids {
    display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 6px;
  }
  .fleet-tl-fluid-chip {
    display: inline-block; padding: 1px 7px; border-radius: 10px;
    font-size: 11px; line-height: 1.5;
    background: rgba(34, 197, 94, 0.12); color: var(--green);
    border: 1px solid rgba(34, 197, 94, 0.28);
    text-transform: capitalize;
  }
  .fleet-tl-notes {
    padding: 6px 10px; border-radius: 6px;
    background: rgba(148, 163, 184, 0.08);
    border-left: 3px solid rgba(245, 158, 11, 0.5);
    white-space: pre-wrap;
  }

  [data-theme="light"] .fleet-tl-chip {
    background: #f1f5f9; border-color: #cbd5e1; color: #475569;
  }
  [data-theme="light"] .fleet-tl-chip.is-on { color: #0f172a; }
  [data-theme="light"] .fleet-tl-chip-count { background: #cbd5e1; color: #475569; }
  [data-theme="light"] .fleet-tl-row-expandable:hover { background: #f8fafc; }
  [data-theme="light"] .fleet-tl-notes { background: #fef3c7; border-left-color: #f59e0b; }
  [data-theme="light"] .fleet-tl-fluid-chip { background: #dcfce7; color: #15803d; border-color: var(--green-text); }
  .fleet-card-notes {
    font-size: 12px; color: var(--text-soft); line-height: 1.45;
  }

  /* Driver / assignment chips */
  .fleet-card-driver-row { display: flex; gap: 6px; flex-wrap: wrap; }
  .fleet-driver {
    display: inline-flex; align-items: center; gap: 5px;
    background: rgba(96, 165, 250, 0.1); border: 1px solid rgba(96, 165, 250, 0.25);
    color: var(--blue-bright); font-size: 12px; font-weight: 600;
    padding: 3px 9px; border-radius: 999px;
  }
  .fleet-driver-communal {
    background: rgba(148, 163, 184, 0.1); border-color: rgba(148, 163, 184, 0.28);
    color: var(--text-soft);
  }
  .fleet-driver-unassigned {
    background: var(--panel-3); color: var(--text-muted); border: 1px dashed var(--border);
    font-style: italic; font-weight: 500;
  }
  .fleet-card-prior {
    font-size: 11.5px; color: var(--text-muted);
    margin-top: -4px;
  }
  .fleet-detail-history {
    font-size: 12.5px; color: var(--text-soft); line-height: 1.55;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 8px 14px; margin-bottom: 10px;
  }
  .fleet-detail-history strong { color: var(--text); font-weight: 600; }

  .fleet-status {
    display: inline-block; font-size: 10.5px; font-weight: 600;
    padding: 2px 8px; border-radius: 999px;
    text-transform: uppercase; letter-spacing: 0.05em;
    background: var(--panel-3); color: var(--text-soft); border: 1px solid var(--border);
  }
  .fleet-status-in_service {
    background: rgba(34, 197, 94, 0.12); color: var(--green); border-color: rgba(34, 197, 94, 0.28);
  }
  .fleet-status-retired,
  .fleet-status-sold {
    background: var(--panel-3); color: var(--text-muted);
  }

  /* Detail view */
  .fleet-detail { display: flex; flex-direction: column; min-height: 0; }
  .fleet-detail-head {
    display: flex; align-items: center; gap: 12px;
    padding-bottom: 14px; border-bottom: 1px solid var(--border);
    margin-bottom: 16px;
  }
  /* Compact 4:3 vehicle photo in the detail header (same asset as the
     grid card thumb, shrunk). flex:0 0 auto so it keeps its size; the
     title's flex:1 still eats the remaining row width. */
  .fleet-detail-thumb-wrap {
    flex: 0 0 auto;
    width: 72px; height: 54px;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface-deep);
    border: 1px solid var(--border);
  }
  .fleet-detail-thumb {
    display: block; width: 100%; height: 100%;
    object-fit: cover; object-position: center 60%;
  }
  .fleet-detail-title { font-weight: 600; font-size: 17px; flex: 1; color: var(--text); }
  .fleet-detail-notes {
    font-size: 12.5px; color: var(--text-soft); line-height: 1.55;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: var(--radius-md); padding: 10px 14px; margin-bottom: 14px;
  }

  .fleet-placeholders {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 10px; margin: 8px 0 18px;
  }
  .fleet-placeholder {
    background: var(--panel); border: 1px dashed var(--border-strong);
    border-radius: var(--radius-md); padding: 10px 14px;
  }
  .fleet-placeholder-title {
    font-weight: 600; font-size: 12px; color: var(--text-soft);
    text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 4px;
  }
  .fleet-placeholder-body { font-size: 12px; color: var(--text-muted); line-height: 1.5; }

  .fleet-empty { color: var(--text-muted); padding: 20px 0; font-size: 13px; }

  /* Year buckets */
  .fleet-year { margin-bottom: 16px; }
  .fleet-year-head {
    display: flex; align-items: baseline; gap: 12px;
    padding: 6px 4px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 6px;
  }
  .fleet-year-label {
    font-weight: 600; color: var(--text-soft); font-size: 13px;
    letter-spacing: 0.05em;
  }
  .fleet-year-meta { font-size: 11.5px; color: var(--text-muted); }
  .fleet-year-rows { display: flex; flex-direction: column; gap: 0; }

  /* Service event row */
  .fleet-event {
    border-bottom: 1px solid transparent;
    padding: 8px 4px;
    cursor: pointer;
    transition: background-color 0.12s;
  }
  .fleet-event:hover { background: rgba(255,255,255,0.025); }
  .fleet-event-row {
    display: grid;
    grid-template-columns: 110px 1fr auto;
    gap: 14px; align-items: start;
  }
  .fleet-event-date {
    color: var(--text-soft); font-size: 12.5px;
    padding-top: 1px; font-variant-numeric: tabular-nums;
  }
  .fleet-event-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
  .fleet-event-head {
    font-size: 13px; color: var(--text); display: flex; gap: 8px; flex-wrap: wrap; align-items: baseline;
  }
  .fleet-event-vendor { font-weight: 600; }
  .fleet-event-ref {
    color: var(--text-soft); font-size: 12px;
    background: var(--panel-3); padding: 1px 6px; border-radius: 4px;
  }
  .fleet-event-desc {
    font-size: 12px; color: var(--text-soft); line-height: 1.45;
  }
  .fleet-event-meta {
    display: flex; flex-direction: column; align-items: flex-end; gap: 2px;
    text-align: right;
  }
  .fleet-event-amt {
    font-weight: 600; color: var(--text); font-size: 13px;
    font-variant-numeric: tabular-nums;
  }
  .fleet-event-amt-pending { color: var(--text-muted); font-style: italic; }
  .fleet-event-srccount {
    font-size: 11px; color: var(--text-muted);
    user-select: none;
  }
  .fleet-event-tag {
    display: inline-block; font-size: 10px; font-weight: 600;
    padding: 1px 6px; border-radius: 999px;
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  .fleet-event-tag-prepeak {
    background: rgba(99, 102, 241, 0.15); color: var(--purple-soft);
    border: 1px solid rgba(99, 102, 241, 0.28);
  }
  .fleet-event-tag-driver {
    background: rgba(96, 165, 250, 0.12); color: var(--blue-bright);
    border: 1px solid rgba(96, 165, 250, 0.28);
    text-transform: none; letter-spacing: 0;
  }
  .fleet-event-tag-inferred {
    background: rgba(20, 184, 166, 0.12); color: #2dd4bf;
    border: 1px solid rgba(20, 184, 166, 0.28);
  }
  .fleet-event-tag-review {
    background: rgba(245, 158, 11, 0.12); color: var(--amber-bright);
    border: 1px solid rgba(245, 158, 11, 0.28);
  }
  /* Declined-estimate marker (work was quoted but not done).
     Neutral grey so it reads as "closed/inactive" rather than alarming. */
  .fleet-event-tag-declined {
    background: rgba(148, 163, 184, 0.10); color: var(--text-muted, #94a3b8);
    border: 1px solid rgba(148, 163, 184, 0.30);
  }
  .fleet-event-amt-declined {
    color: var(--text-muted, #94a3b8);
    text-decoration: line-through;
    text-decoration-color: rgba(148, 163, 184, 0.55);
    font-style: italic;
  }
  .fleet-event-amt-declined .fleet-event-amt-declined-tag {
    margin-left: 4px;
    font-size: 10px;
    text-decoration: none;
    color: var(--text-muted, #94a3b8);
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }
  [data-theme="light"] .fleet-event-tag-declined {
    background: rgba(100, 116, 139, 0.10); color: #64748b;
    border-color: rgba(100, 116, 139, 0.25);
  }
  [data-theme="light"] .fleet-event-amt-declined { color: #64748b; }

  /* Services performed — inline chips below the event head row.
     One chip per service kind extracted from the PDF (or manually
     added). Color-coded by category so Matt can scan a vehicle's
     timeline and spot oil changes / brake service / recalls etc. at
     a glance without reading every description. */
  .fleet-event-services {
    display: flex; flex-wrap: wrap; gap: 4px;
    margin: 4px 0 2px 0;
  }
  .fleet-event-service {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 10px;
    font-size: 11px;
    line-height: 1.4;
    background: rgba(148, 163, 184, 0.12);
    color: var(--text-soft, #94a3b8);
    border: 1px solid rgba(148, 163, 184, 0.22);
  }
  .fleet-event-service-oil_change {
    background: rgba(34, 197, 94, 0.12); color: var(--green);
    border-color: rgba(34, 197, 94, 0.28);
  }
  .fleet-event-service-brake_service,
  .fleet-event-service-brake_booster {
    background: rgba(239, 68, 68, 0.12); color: var(--red-bright);
    border-color: rgba(239, 68, 68, 0.28);
  }
  .fleet-event-service-tire_rotation,
  .fleet-event-service-alignment {
    background: rgba(59, 130, 246, 0.12); color: var(--blue-bright);
    border-color: rgba(59, 130, 246, 0.28);
  }
  .fleet-event-service-recall {
    background: rgba(245, 158, 11, 0.14); color: var(--amber-bright, #fbbf24);
    border-color: rgba(245, 158, 11, 0.30);
  }
  .fleet-event-service-inspection,
  .fleet-event-service-diagnostics {
    background: rgba(20, 184, 166, 0.10); color: #2dd4bf;
    border-color: rgba(20, 184, 166, 0.24);
  }
  [data-theme="light"] .fleet-event-service { color: #475569; background: #e2e8f0; border-color: #cbd5e1; }
  [data-theme="light"] .fleet-event-service-oil_change { background: #dcfce7; color: #15803d; border-color: var(--green-text); }
  [data-theme="light"] .fleet-event-service-brake_service,
  [data-theme="light"] .fleet-event-service-brake_booster { background: #fee2e2; color: #b91c1c; border-color: var(--red-text); }
  [data-theme="light"] .fleet-event-service-tire_rotation,
  [data-theme="light"] .fleet-event-service-alignment { background: #dbeafe; color: #1d4ed8; border-color: var(--blue-light); }
  [data-theme="light"] .fleet-event-service-recall { background: #fef3c7; color: #b45309; border-color: #fcd34d; }
  [data-theme="light"] .fleet-event-service-inspection,
  [data-theme="light"] .fleet-event-service-diagnostics { background: #ccfbf1; color: #0f766e; border-color: #5eead4; }

  /* Source-email expansion */
  .fleet-event-sources {
    display: none; margin: 8px 0 4px 124px;
    flex-direction: column; gap: 4px;
  }
  .fleet-event.expanded .fleet-event-sources { display: flex; }
  .fleet-event.expanded .fleet-event-srccount { color: var(--text-soft); }
  .fleet-source {
    display: grid; grid-template-columns: 90px 90px 1fr; gap: 10px;
    padding: 5px 10px; border-radius: 6px;
    background: var(--panel-3); border: 1px solid var(--border);
    color: var(--text-soft); font-size: 12px;
    text-decoration: none;
    transition: border-color 0.15s, color 0.15s;
  }
  .fleet-source:hover { border-color: var(--border-strong); color: var(--text); }
  .fleet-source-kind {
    text-transform: uppercase; font-size: 10.5px; letter-spacing: 0.04em;
    color: var(--text-muted); padding-top: 1px;
  }
  .fleet-source-date { font-variant-numeric: tabular-nums; color: var(--text-muted); }
  .fleet-source-subj { color: inherit; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Light-theme overrides for the fleet view (mirror the rpt-* light pass
     further down in this file). */
  [data-theme="light"] .fleet-event:hover { background: rgba(0,0,0,0.025); }
  [data-theme="light"] .fleet-card-pending {
    background: rgba(245, 158, 11, 0.10);
    color: #b45309;
  }

  /* ── Pipeline view (Leads / Jobs / Projects) ─────────────────────────
     Two layout modes:
       - .pipeline-tiles-list  → legacy vertical stack of full-width tiles.
       - .pipeline-tiles-board → CC-style horizontal kanban: each tile is
         a column, columns sit side-by-side, horizontal scroll if needed.
     Mode is chosen by state.pipelineLayout (default 'board'); toggle
     lives in the .pipeline-toolbar above the tiles. Tiles + cards +
     drag-drop wiring are identical between modes — only outer layout
     changes. */
  .pipeline-toolbar {
    display: flex; align-items: center; justify-content: flex-end; gap: 10px;
    margin-bottom: 12px;
  }
  .pipeline-layout-toggle {
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 999px;
    overflow: hidden;
    background: var(--panel);
  }
  .pipeline-layout-btn {
    border: 0; background: transparent;
    color: var(--text-muted);
    font-size: 12px; font-weight: 500;
    padding: 5px 14px;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
  }
  .pipeline-layout-btn:hover { color: var(--text); }
  .pipeline-layout-btn.active {
    background: var(--blue, #2563eb);
    color: #fff;
  }
  .pipeline-layout-btn + .pipeline-layout-btn {
    border-left: 1px solid var(--border);
  }

  /* List mode (legacy) — vertical stack. */
  .pipeline-tiles-list {
    display: flex; flex-direction: column; gap: 0;
  }
  /* Board mode — horizontal columns. Tiles sit side-by-side, horizontal
     overflow scrolls. Each column caps height + scrolls inside so long
     stages don't push the page down. */
  .pipeline-tiles-board {
    display: flex; flex-direction: row;
    gap: 14px;
    overflow-x: auto;
    align-items: flex-start;
    padding-bottom: 12px;
    /* Slight scroll-snap so dragging a column edge into view stops
       cleanly. Doesn't fight free scroll. */
    scroll-snap-type: x proximity;
  }
  .pipeline-tiles-board .pipeline-tile {
    flex: 0 0 360px;
    width: 360px;
    margin-bottom: 0;
    display: flex; flex-direction: column;
    padding: 14px 14px 12px;
    scroll-snap-align: start;
    transition: flex-basis 180ms ease, width 180ms ease, padding 180ms ease;
    /* Per Matt 2026-05-19: don't cap column height — let the column
       grow as tall as it needs and rely on page-level scroll. Beats
       per-column inner scrollbars + crushed cards that overlap their
       thumbnails. */
  }
  /* Collapsed column — shrink to a thin vertical strip so the
     horizontal board scroll doesn't waste 360px on a section the
     user has dismissed. The dot stays at top, the title rotates 90°
     to read top-to-bottom, the count + chevron sit at the bottom.
     Clicking anywhere on the strip expands the column back. */
  .pipeline-tiles-board .pipeline-tile.pt-collapsed {
    flex: 0 0 52px;
    width: 52px;
    padding: 12px 6px;
    cursor: pointer;
  }
  .pipeline-tiles-board .pipeline-tile.pt-collapsed .pipeline-tile-head {
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 10px;
    height: 100%;
    padding: 0;
    min-height: 220px;
  }
  .pipeline-tiles-board .pipeline-tile.pt-collapsed .pipeline-tile-head h3 {
    writing-mode: vertical-rl;
    transform: rotate(180deg);  /* reads top-to-bottom (not bottom-to-top) */
    font-size: 12.5px;
    letter-spacing: 0.04em;
    white-space: nowrap;
    flex: 1 1 auto;
    text-align: center;
  }
  .pipeline-tiles-board .pipeline-tile.pt-collapsed .pt-dot {
    flex: 0 0 auto;
    margin: 0;
  }
  .pipeline-tiles-board .pipeline-tile.pt-collapsed .pt-count {
    flex: 0 0 auto;
    margin: 0;
    font-size: 11px;
    font-weight: 600;
    padding: 2px 6px;
    background: rgba(255,255,255,0.06);
    border-radius: 999px;
  }
  .pipeline-tiles-board .pipeline-tile.pt-collapsed .pt-collapse-arrow {
    flex: 0 0 auto;
    transform: rotate(-90deg);  /* points right when collapsed */
    margin: 0;
  }
  .pipeline-tiles-board .pipeline-tile.pt-collapsed .pipeline-tile-body {
    display: none;
  }
  /* Keep collapsed columns as a drag-drop target — Matt can still
     drop a card onto a collapsed column to move it there, the
     column will pop open on the next render. Re-use the existing
     .pt-drop-target outline. */
  .pipeline-tiles-board .pipeline-tile-body {
    flex: 0 0 auto;
    display: flex; flex-direction: column;
    gap: 8px;
  }
  /* Stack lane for drop-only tiles in board mode. Leads pipeline ends
     with two drop-targets ("Waiting on Project Status" + "Needs
     Scheduling") — instead of giving each a full 360px column we
     stack them vertically in one narrow lane so the real populated-
     cards columns get more horizontal real estate. */
  .pipeline-tiles-board .pipeline-droponly-stack {
    flex: 0 0 220px;
    width: 220px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    scroll-snap-align: start;
  }
  .pipeline-tiles-board .pipeline-droponly-stack .pipeline-tile {
    flex: 0 0 auto;
    width: 100%;
    min-height: 110px;
    padding: 12px;
  }
  .pipeline-tiles-board .pipeline-droponly-stack .pipeline-tile.pt-collapsed {
    /* Inside the narrow lane, collapsed drop-only tiles fold to a
       single horizontal row (no vertical-text rotation needed — the
       lane is already narrow enough that a normal header reads fine). */
    flex: 0 0 auto;
    width: 100%;
    padding: 8px 10px;
    min-height: 0;
  }
  .pipeline-tiles-board .pipeline-droponly-stack .pipeline-tile.pt-collapsed .pipeline-tile-head {
    flex-direction: row;
    align-items: center;
    min-height: 0;
  }
  .pipeline-tiles-board .pipeline-droponly-stack .pipeline-tile.pt-collapsed .pipeline-tile-head h3 {
    writing-mode: horizontal-tb;
    transform: none;
    font-size: 13px;
  }

  /* Board-mode card layout — thumbnail on the left, info column on the
     right (title + sub stack vertically), badges wrap onto their own
     row below. Card grows in height with content; never compressed,
     never overlapping. Action cluster is dropped (click the card body
     to open detail; the same actions are on the detail page). */
  .pipeline-tiles-board .pt-card {
    flex-wrap: wrap;
    align-items: flex-start;
    padding: 10px 12px;
    gap: 10px;
    min-height: 0;
  }
  .pipeline-tiles-board .pt-card-thumb {
    flex: 0 0 72px;
    width: 72px !important;
    height: 54px !important;
    align-self: flex-start;
  }
  .pipeline-tiles-board .pt-card-main {
    /* flex-basis = total card width − thumb (72) − gap (10) − a bit of
       padding cushion, so badges naturally wrap onto the next row
       instead of getting squeezed beside the title. */
    flex: 1 1 calc(100% - 92px);
    min-width: 0;
  }
  /* Title + sub can wrap onto multiple lines so long names like
     "Vanbucholtz Mechanical Heat Pump/Pet Spa" stay readable instead
     of getting clipped or overlapping the thumb. */
  .pipeline-tiles-board .pt-title {
    white-space: normal;
    display: block;
    line-height: 1.3;
  }
  .pipeline-tiles-board .pt-card-sub {
    white-space: normal;
    line-height: 1.35;
    margin-top: 2px;
  }
  /* Board columns are narrow, so let the description wrap to a 2-line clamp
     (matches the All Jobs card desc) rather than the single-line ellipsis
     used in list layout. Full text stays in the title tooltip. */
  .pipeline-tiles-board .pt-card-desc {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    line-height: 1.35;
    margin-top: 2px;
  }
  .pipeline-tiles-board .pt-actions { display: none; }
  /* Badges fall to a third row below thumb+main. Each badge stays inline
     within that row and wraps further if there are many. */
  .pipeline-tiles-board .pt-badges {
    width: 100%;
    flex-wrap: wrap;
    gap: 4px;
  }
  .pipeline-tiles-board .pt-badge {
    font-size: 10px;
    padding: 2px 7px;
  }

  .pipeline-tile {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    padding: 18px 20px; margin-bottom: 16px;
    box-shadow: var(--shadow-card);
  }
  .pipeline-tile.pt-drop-target {
    outline: 2px dashed var(--blue); outline-offset: 2px;
    background: var(--blue-soft);
  }
  /* Active tile highlight in the Scheduling pipeline — Active represents
     "this week's real work" so it gets a subtle green outline + soft glow
     to draw the eye. Identified via data-tile-label, no JS changes needed. */
  .pipeline-tile[data-tile-label="Active"] {
    border-color: rgba(22, 163, 74, 0.55);
    box-shadow: 0 0 0 1px rgba(22, 163, 74, 0.35), 0 4px 14px rgba(22, 163, 74, 0.12);
  }
  .pipeline-tile[data-tile-label="Active"] .pipeline-tile-head h3 {
    color: var(--green);
  }
  /* Needs Scheduling — visual companion to Active. Yellow accent signals
     "queue waiting to be put on the calendar." Same outline + glow shape
     as Active so the two read as a matched pair. */
  .pipeline-tile[data-tile-label="Needs Scheduling"]:not(.pt-tile-droponly) {
    border-color: rgba(234, 179, 8, 0.55);
    box-shadow: 0 0 0 1px rgba(234, 179, 8, 0.35), 0 4px 14px rgba(234, 179, 8, 0.12);
  }
  .pipeline-tile[data-tile-label="Needs Scheduling"]:not(.pt-tile-droponly) .pipeline-tile-head h3 {
    color: var(--amber-bright);
  }

  /* Drop-only tile (empty: true in pipeline def) — softer dashed border so the
     "drop here to promote" affordance is visually distinct from a real tile
     that just happens to have no items today. */
  .pipeline-tile.pt-tile-droponly {
    border-style: dashed;
    border-color: var(--border-strong);
    background: var(--panel-2);
  }
  .pipeline-tile.pt-tile-droponly .pipeline-tile-head h3 {
    color: var(--text-soft);
    font-style: italic;
    font-weight: 500;
  }
  .pipeline-tile.pt-tile-droponly .pt-empty {
    color: var(--text-muted);
    font-style: italic;
  }
  /* Read-only Type badge replaced the old Type dropdown in the row Type cell.
     Color follows the section's dominant category (Leads/Scheduling = green
     Status, Projects = blue Project Status) per the 2026-04-28 v2 restructure.
     Renders as a static pill, not a select. */
  .type-badge {
    display: inline-block;
    padding: 3px 11px;
    border-radius: 100px;
    font-size: 11px; font-weight: 600;
    white-space: nowrap;
    background: rgba(22, 163, 74, 0.15);
    color: var(--green);
    border: 1px solid rgba(22, 163, 74, 0.4);
  }
  .type-badge.projects {
    background: rgba(59, 130, 246, 0.15);
    color: var(--blue);
    border-color: rgba(59, 130, 246, 0.4);
  }
  .type-badge.type-badge-empty {
    background: transparent; color: var(--text-faint); border-color: var(--border);
  }
  .pipeline-tile-head {
    display: flex; align-items: center; gap: 10px;
    padding-bottom: 10px; margin-bottom: 10px;
    border-bottom: 1px solid var(--border-subtle);
    cursor: pointer;
    user-select: none;
  }
  .pipeline-tile-head:hover .pt-collapse-arrow { color: var(--blue-light); }
  .pt-collapse-arrow {
    margin-left: auto;
    color: var(--text-muted);
    font-size: 14px; line-height: 1;
    transition: transform 0.18s ease, color 0.12s;
  }
  /* Collapsed state — hides the body, rotates the arrow, removes the head's
     bottom border so the tile reads as a single bar. State is persisted in
     localStorage so refreshes maintain whatever Matt's collapsed. */
  .pipeline-tile.pt-collapsed .pipeline-tile-body { display: none; }
  .pipeline-tile.pt-collapsed .pipeline-tile-head {
    padding-bottom: 0; margin-bottom: 0; border-bottom: none;
  }
  .pipeline-tile.pt-collapsed .pt-collapse-arrow {
    transform: rotate(-90deg);
  }
  .pipeline-tile-head .pt-dot {
    width: 10px; height: 10px; border-radius: 50%;
  }
  .pipeline-tile-head h3 {
    font-size: 15px; font-weight: 600; color: var(--text-strong); flex: 1; margin: 0;
  }
  .pipeline-tile-head .pt-count {
    background: var(--panel); color: var(--text-soft);
    font-size: 11px; padding: 3px 10px; border-radius: 100px;
  }
  .pipeline-tile-body {
    display: flex; flex-direction: column; gap: 8px; min-height: 30px;
  }
  .pipeline-tile .pt-empty {
    padding: 16px 10px; text-align: center;
    color: var(--text-subtle); font-size: 12px; font-style: italic;
    border: 1px dashed var(--border); border-radius: 8px;
  }
  /* Pipeline cards are condensed single-line rows — name + client/address
     + badges. No buttons, no dropdowns. Clicking opens the job detail where
     all controls live. Drag handle is the whole card. */
  .pt-card {
    background: var(--panel-3); border: 1px solid var(--border-subtle); border-radius: 8px;
    padding: 6px 10px; cursor: grab;
    transition: border-color 0.12s, background 0.12s;
    display: flex; align-items: center; gap: 10px;
    min-height: 32px;
  }
  .pt-card:hover { border-color: var(--border-strong); background: var(--panel); }
  .pt-card.pt-dragging { opacity: 0.4; cursor: grabbing; }
  .pt-card-main {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column; gap: 1px;
  }
  .pt-title {
    font-weight: 600; color: var(--text-strong); font-size: 12.5px;
    text-decoration: none;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .pt-title:hover { color: var(--text); text-decoration: underline; }
  .pt-card-sub {
    font-size: 10.5px; color: var(--text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* Description preview — only shows if the project has a description.
     Slightly indented and italicized so it reads as auxiliary info, not
     more identity data like the client/address row above it. */
  .pt-card-desc {
    font-size: 10px; color: var(--text-soft);
    font-style: italic;
    margin-top: 1px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 100%;
  }
  .pt-badges { display: flex; flex-wrap: nowrap; gap: 4px; flex-shrink: 0; }
  .pt-badge {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 10px; font-weight: 600;
    padding: 2px 8px; border-radius: 100px;
    border: 1px solid;
    letter-spacing: 0.01em;
    white-space: nowrap;
  }
  .pt-badge-dot {
    width: 5px; height: 5px; border-radius: 50%;
  }
  /* Cluster of pill buttons on the right of each pipeline card.
     Pipeline-aware: Leads get Meeting + Estimate + CompanyCam + Archive;
     Jobs/Projects add Schedule. Each button is icon + label side-by-side,
     kept compact so the card stays a single-line row. */
  .pt-actions {
    display: flex; gap: 6px; flex-shrink: 0;
    align-items: center;
  }
  .pt-mini-btn {
    flex-shrink: 0;
    display: inline-flex; flex-direction: row;
    align-items: center; justify-content: center;
    gap: 5px;
    height: 26px;
    padding: 0 9px;
    border-radius: 6px;
    color: var(--text-soft);
    border: 1px solid var(--border); background: var(--panel-3);
    text-decoration: none;
    cursor: pointer; font-family: inherit;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .pt-mini-btn:hover { background: var(--row-hover); border-color: var(--border-strong); color: var(--text); }
  .pt-mini-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 14px; height: 14px; flex-shrink: 0;
  }
  .pt-mini-icon svg { width: 14px; height: 14px; }
  .pt-mini-label {
    font-size: 10.5px; font-weight: 600; line-height: 1;
    letter-spacing: 0.01em;
    white-space: nowrap;
  }
  /* Accent colors per action — subtle so the card stays calm. */
  .pt-mini-meet { color: var(--pink); border-color: rgba(244,114,182,0.28); background: rgba(244,114,182,0.08); }
  .pt-mini-meet:hover { background: rgba(244,114,182,0.18); color: var(--pink); }
  .pt-mini-cal  { color: var(--orange); border-color: rgba(251,146,60,0.28); background: rgba(251,146,60,0.08); }
  .pt-mini-cal:hover  { background: rgba(251,146,60,0.18); color: var(--orange); }
  .pt-mini-invoice, .pt-mini-estimate {
    color: var(--green-text); border-color: rgba(34,197,94,0.28); background: rgba(34,197,94,0.08);
  }
  .pt-mini-invoice:hover, .pt-mini-estimate:hover { background: rgba(34,197,94,0.18); color: var(--green-soft); }
  .pt-mini-cc { color: var(--blue-bright); border-color: rgba(59,130,246,0.28); background: rgba(59,130,246,0.08); }
  .pt-mini-cc:hover { background: rgba(59,130,246,0.18); color: var(--blue-lighter); }
  .pt-mini-archive { color: var(--text-soft); border-color: rgba(148,163,184,0.28); background: rgba(148,163,184,0.08); }
  .pt-mini-archive:hover { background: rgba(251,146,60,0.18); color: var(--orange); border-color: rgba(251,146,60,0.35); }
  /* Mark Completed — solid green, the visual primary on Active/Ongoing
     pipeline tiles. Slight lift on hover to reinforce that this is the
     intentional next step for these jobs. */
  .pt-mini-complete {
    color: var(--text-strong);
    border-color: rgba(16,185,129,0.55);
    background: linear-gradient(180deg, rgba(16,185,129,0.85) 0%, rgba(5,150,105,0.85) 100%);
    box-shadow: 0 0 0 0 rgba(16,185,129,0); /* nothing initially — animates on hover */
    font-weight: 600;
  }
  .pt-mini-complete:hover {
    background: linear-gradient(180deg, rgba(34,197,94,0.95) 0%, rgba(5,150,105,0.95) 100%);
    border-color: rgba(34,197,94,0.7);
    box-shadow: 0 0 0 3px rgba(16,185,129,0.18);
    transform: translateY(-1px);
  }

  @media (max-width: 780px) {
    .pt-card { flex-wrap: wrap; }
    .pt-badges { width: 100%; }
  }

  /* ── Street View thumbnails (peak-thumb) ───────────────────────────────
     Small image of the building at each project's address, shown on
     pipeline cards (Dashboard/Leads/Scheduling/Projects/Today) and
     Project Budgeting + Job Costing rows. Backed by Google's Street View
     Static API with a satellite-map fallback for addresses without
     street-view coverage. Asynchronously upgraded: while the metadata
     check + image fetch are in flight, the element shows a dark shimmer.
     Once resolved, the helper sets background-image with the real URL. */
  .peak-thumb {
    flex-shrink: 0;
    border-radius: 4px;
    background-color: var(--panel-2);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
  }
  .peak-thumb-loading {
    background-image: linear-gradient(
      90deg,
      rgba(255,255,255,0.03) 0%,
      rgba(255,255,255,0.08) 50%,
      rgba(255,255,255,0.03) 100%
    );
    background-size: 200% 100%;
    animation: peak-thumb-shimmer 1.4s ease-in-out infinite;
  }
  @keyframes peak-thumb-shimmer {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
  }
  .peak-thumb-placeholder {
    background-color: var(--panel-2);
    border: 1px dashed var(--border-subtle);
    opacity: 0.55;
  }
  .pt-card-thumb {
    border: 1px solid var(--border-subtle);
  }
  /* Hero-size thumb on the job detail page. Sits beneath the header
     (title + client + actions) and above the address/date info block.
     Click anywhere on the overlay → opens Google Maps in a new tab. */
  /* Hero row: street-view thumbnail on the left, recent permits panel on
     the right. Wraps to stacked on narrow viewports so the thumb keeps
     its full ~480px width as long as possible. */
  .detail-hero-row {
    display: flex; flex-wrap: wrap; gap: 18px;
    align-items: flex-start;
    margin: 0 0 16px 0;
  }
  .detail-hero-side {
    flex: 1 1 280px; min-width: 280px; max-width: 520px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 10px; padding: 12px 14px;
  }
  .detail-hero-side:empty { display: none; }

  .detail-permits-head {
    display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px;
  }
  .detail-permits-head h3 {
    margin: 0; font-size: 15px; font-weight: 600; color: var(--text);
    display: flex; align-items: center; gap: 8px;
  }
  .detail-permits-count {
    padding: 1px 8px; border-radius: 999px;
    background: rgba(96,165,250,0.18); color: var(--blue-light, #60a5fa);
    font-size: 11px; font-weight: 700;
  }
  .detail-permits-sub {
    font-size: 12px; color: var(--text-muted);
  }
  .detail-permits-list {
    display: flex; flex-direction: column; gap: 6px;
  }
  .detail-permits-row {
    padding: 8px 10px;
    background: var(--panel-2, var(--panel));
    border: 1px solid var(--border-subtle, var(--border));
    border-radius: 6px;
  }
  .detail-permits-row-head {
    display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: flex-start;
    gap: 2px 8px;
    font-size: 13px;
  }
  .detail-permits-row-head strong { color: var(--text); font-weight: 600; }
  /* The permit number + issued date own the first line, so the date sits to
     the right of the number (Matt 2026-07-22). On a tile too narrow to fit
     both, the date tucks under the number. The status badge takes the line
     below, right-aligned, so it never crowds the date off the line. */
  .detail-permits-headline {
    flex: 1 1 100%; min-width: 0;
    display: flex; flex-wrap: wrap; align-items: center; gap: 2px 8px;
  }
  .detail-permits-issued {
    font-size: 12px; color: var(--text-muted); white-space: nowrap;
  }
  .detail-permits-status {
    margin-left: auto; flex: none;
    padding: 1px 8px; border-radius: 999px;
    background: rgba(148,163,184,0.16); color: var(--text-muted);
    font-size: 11px; font-weight: 600;
  }
  .detail-permits-meta {
    color: var(--text-muted); font-size: 12px; margin-top: 2px;
  }
  .detail-permits-overflow {
    color: var(--text-muted); font-size: 12px; font-style: italic;
    padding: 6px 4px;
  }
  /* Flash highlight when the View Permit button scrolls the panel into
     view — quick blue glow then fade. */
  @keyframes detail-permits-flash-kf {
    0%   { box-shadow: 0 0 0 3px rgba(96,165,250,0.55); }
    100% { box-shadow: 0 0 0 3px rgba(96,165,250,0);    }
  }
  .detail-permits-flash {
    animation: detail-permits-flash-kf 1.5s ease-out;
  }

  /* Job-tools card — fills the dead space beside the permits panel in the
     hero row (Matt 2026-07-07). Buttons duplicate the More▾ menu's Panel
     Schedule / Load Calculator items; 07-views wires both instances via
     querySelectorAll on the shared data-action. */
  .detail-hero-tools { flex: 0 1 300px; min-width: 240px; height: 256px; }
  .detail-tools-list { display: flex; flex-direction: column; gap: 8px; }
  .detail-tool-btn {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 10px 12px; text-align: left; cursor: pointer;
    background: var(--panel-2, var(--panel));
    border: 1px solid var(--border-subtle, var(--border));
    border-radius: 8px; color: var(--text); font: inherit;
  }
  .detail-tool-btn:hover { border-color: var(--blue-light, #60a5fa); }
  .detail-tool-icon { width: 22px; height: 22px; flex: none; color: var(--blue-light, #60a5fa); }
  .detail-tool-icon svg { width: 100%; height: 100%; }
  .detail-tool-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .detail-tool-text strong { font-size: 13.5px; font-weight: 600; }
  .detail-tool-text span { font-size: 12px; color: var(--text-muted); }

  .detail-hero-thumb-wrap {
    position: relative;
    width: fit-content;
    margin: 0;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 8px rgba(0,0,0,0.18);
  }
  .detail-hero-thumb {
    display: block;
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
  }
  .detail-hero-thumb-overlay {
    position: absolute;
    bottom: 8px;
    right: 8px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    background: rgba(15, 23, 42, 0.78);
    color: #e2e8f0;
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 4px;
    font-size: 11.5px;
    font-weight: 500;
    text-decoration: none;
    backdrop-filter: blur(4px);
    transition: background 0.12s, transform 0.12s;
  }
  .detail-hero-thumb-overlay:hover {
    background: rgba(15, 23, 42, 0.92);
    transform: translateY(-1px);
  }
  .detail-hero-thumb-overlay svg {
    width: 13px;
    height: 13px;
    flex-shrink: 0;
  }
  /* Top-right overlay on the detail-hero thumbnail — single button that
     flips between Street View and Satellite, persisted per-job. Fixes
     the "Street View shows a tree, satellite would be clearer" cases.
     Mirrors the visual style of the "Open in Maps" overlay (bottom-right)
     so both controls feel like a matched pair on top of the image. */
  .detail-hero-thumb-toggle {
    position: absolute;
    top: 8px;
    right: 8px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 10px;
    background: rgba(15, 23, 42, 0.78);
    color: #e2e8f0;
    border: 1px solid rgba(255,255,255,0.15);
    border-radius: 4px;
    font-size: 11.5px;
    font-weight: 500;
    cursor: pointer;
    backdrop-filter: blur(4px);
    transition: background 0.12s, transform 0.12s;
  }
  .detail-hero-thumb-toggle:hover {
    background: rgba(15, 23, 42, 0.92);
    transform: translateY(-1px);
  }
  /* Table-row variants (Project Budgeting, Job Costing). The parent
     cell is flexed so the thumb sits beside the project name without
     a hard-coded margin. */
  .pb-row-thumb,
  .jc-row-thumb {
    border: 1px solid var(--border-subtle);
    border-radius: 4px;
  }

  /* ─────────────────────────────────────────────────────────────────
     All Jobs cards (.aj-card)
     2026-05-18 — replaced the table-row layout. Matches the visual
     language of Leads/Jobs/Projects pipeline tiles (pt-card) but
     keeps the full set of status/billing/permit/inspection/stage
     selectors a Dashboard view needs. One card = one job, stacked
     vertically.
     ───────────────────────────────────────────────────────────────── */
  .aj-card {
    background: var(--panel-3);
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    padding: 12px 14px;
    display: flex;
    align-items: stretch;
    gap: 14px;
    transition: border-color 0.12s, background 0.12s;
    margin: 0;
  }
  /* 2026-08-19 — All Jobs paints ~130 cards at once and only ~5 fit on
     screen, so the browser was laying out and styling every one of them
     (measured: one repaint 115ms → 37ms). contain-intrinsic-size keeps the
     scrollbar honest until a card has been scrolled past once.
     The :has() rule is REQUIRED, not optional: content-visibility turns on
     paint containment and the More menu hangs below the card's bottom edge,
     so without it Call / Email / Archive get clipped. Deliberately NOT
     applied to .pt-card — the pipeline boards' drop-index math walks
     getBoundingClientRect() over every card (03-utils.js) and off-screen
     cards would report the guessed height instead of their real one. */
  .aj-card {
    content-visibility: auto;
    contain-intrinsic-size: auto 168px;
  }
  .aj-card:has(.action-group.is-open) { content-visibility: visible; }
  .aj-card + .aj-card { margin-top: 8px; }
  .aj-card:hover { border-color: var(--border-strong); background: var(--panel); }
  .aj-card-archived { opacity: 0.62; }

  /* Bulk-select checkbox — top-left corner of the card. Hidden by default
     (opacity 0); fades in on card hover so the card stays clean when
     you're not actively bulk-editing. Once any card is selected, ALL
     checkboxes become visible (via .aj-card-selected on the parent) so
     it's easy to add to the selection without hunting. */
  .aj-card-select {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    width: 22px;
    opacity: 0;
    transition: opacity 120ms ease;
    cursor: pointer;
  }
  .aj-card:hover .aj-card-select,
  .aj-card-selected .aj-card-select,
  body:has(.aj-card-selected) .aj-card .aj-card-select { opacity: 1; }
  .aj-card-select input[type="checkbox"] {
    width: 16px; height: 16px;
    accent-color: var(--blue, #2563eb);
    cursor: pointer;
  }
  .aj-card-selected {
    border-color: var(--blue, #2563eb);
    background: rgba(37, 99, 235, 0.06);
  }

  .aj-card-thumb-wrap {
    flex: 0 0 200px;     /* fixed 200px wide to match the bumped thumb dimensions */
    line-height: 0;
    display: flex;
    align-items: stretch;
  }
  .aj-card-thumb {
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    width: 200px;
    height: 140px;
    object-fit: cover;
    display: block;
  }

  .aj-card-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex; flex-direction: column;
    gap: 6px;
  }
  .aj-card-head {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    min-height: 30px;
  }
  /* Address title takes whatever space the action strip leaves; truncates
     with ellipsis when the row is tight rather than wrapping into the
     action buttons. */
  .aj-card-head .aj-title {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .aj-title {
    font-weight: 600; color: var(--text-strong); font-size: 16px;
    text-decoration: none;
    line-height: 1.25;
  }
  .aj-title:hover { text-decoration: underline; }
  /* Inline pencil/edit buttons inside the sub line. Hidden by default
     (opacity 0) so the sub line reads cleanly as "Job name · Client ·
     Updated 4d ago"; revealed on card hover so Matt can still click
     in. Same pattern Notion / Linear use for inline-edit affordances. */
  .aj-title-edit {
    background: transparent; border: 0; color: var(--text-muted);
    cursor: pointer; padding: 0 2px; font-size: 11px;
    border-radius: 3px;
    line-height: 1;
    opacity: 0;
    transition: opacity 120ms ease, color 120ms ease;
  }
  .aj-card:hover .aj-title-edit { opacity: 0.55; }
  .aj-card:hover .aj-title-edit:hover,
  .aj-card .aj-title-edit:focus-visible { opacity: 1; color: var(--text); }
  .aj-card-modified {
    font-size: 11px; color: var(--text-soft); font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  .aj-card-sub {
    /* 2026-07-01 — was --text-muted; one step up for legibility in bright
       shops / truck cabs (client name is load-bearing info). */
    font-size: 12px; color: var(--text-soft);
    display: flex; align-items: center; gap: 6px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* Rematch pencil follows the same hover-reveal pattern as aj-title-edit
     above. The Match-client button (unmatched state) stays visible — it's
     a call to action, not an inline affordance. */
  .aj-rematch-btn {
    background: transparent; border: 0; color: var(--text-muted);
    cursor: pointer; padding: 0 2px; font-size: 11px;
    border-radius: 3px;
    line-height: 1;
    opacity: 0;
    transition: opacity 120ms ease, color 120ms ease;
  }
  .aj-card:hover .aj-rematch-btn { opacity: 0.55; }
  .aj-card:hover .aj-rematch-btn:hover,
  .aj-card .aj-rematch-btn:focus-visible { opacity: 1; color: var(--text); }
  .aj-match-btn {
    background: transparent;
    border: 1px solid var(--border); padding: 3px 8px;
    border-radius: 4px;
    cursor: pointer;
    color: var(--text-soft);
    font-size: 11px;
  }
  .aj-match-btn:hover { color: var(--text); background: var(--row-hover); }

  /* Action row — inline with the title row, pinned to the right side
     via margin-left:auto. Sits on the same horizontal line as the
     address title, so the row stays compact (no full-width band with
     dead space). pt-actions inner styles handle the button pills. */
  .aj-card-actions-row {
    margin-left: auto;
    display: flex; gap: 6px; flex-wrap: wrap;
    flex-shrink: 0;
  }

  /* Status strip — one row of 5 self-labeling pills (Status, Billing,
     Permit, Inspection, Stage). Pills with empty values render their
     category name as placeholder ("Status —", "Stage —") so the strip
     reads at a glance without separate uppercase labels above. Wraps
     on narrow viewports.
     2026-05-21 — switched from "label-above-dropdown" to "self-label-
     ing pills" so the strip stays compact + photo-forward layout has
     enough vertical room for the bigger thumbnail. */
  .aj-status-strip {
    display: flex; gap: 6px; flex-wrap: wrap;
    margin-top: auto;          /* pinned to bottom of the main column so
                                  the thumbnail and the strip line up
                                  visually on tall cards */
  }
  /* Slimmer pill look for select elements inside the All Jobs card.
     Compact padding, no inline-block label, just the pill itself.
     Overrides the generic .status-select sizing within this scope. */
  .aj-status-strip .status-cell {
    margin: 0;
    flex: 0 0 auto;
  }
  .aj-status-strip .status-select {
    padding: 3px 22px 3px 10px;
    font-size: 11.5px;
    border-radius: 999px;
    min-width: 0;
    height: 26px;
    line-height: 1.2;
  }
  /* 2026-07-01 — de-clutter: unfilled placeholder pills ("Inspection —",
     "Stage —") recede to ghost chips so pills carrying real state dominate
     the strip. Hovering the card (or focusing the pill) restores full
     presence, so setting a value stays one click away. background-color
     (not the shorthand) so the dropdown-arrow SVG survives. */
  .aj-status-strip .status-select:not(.has-value) {
    opacity: 0.4;
    background-color: transparent;
    border-style: dashed;
  }
  .aj-card:hover .aj-status-strip .status-select:not(.has-value),
  .aj-status-strip .status-select:not(.has-value):focus {
    opacity: 1;
    background-color: var(--panel-3);
    border-style: solid;
  }

  /* Description row — sits under the sub line, inside the main column.
     Two-line clamp keeps cards from ballooning on long descriptions;
     full text on hover via the title attr. Skipped entirely when
     empty (renderJobs returns ''). */
  .aj-card-desc {
    /* 2026-07-01 — was --text-soft; one step up (12px italic on a dark
       panel needs the extra contrast to stay readable at a glance). */
    font-size: 12px; color: var(--text);
    line-height: 1.45;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    white-space: normal;
    font-style: italic;
  }

  /* Sort bar at the top of the All Jobs list — was a grid column-header
     row when the layout was a table; flexbox of sortable pill-buttons
     now that the rows are cards. Each sortable button keeps its data-sort
     attribute so the existing sort wiring at renderJobs() works
     unchanged. */
  .aj-sortbar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    padding: 10px 14px;
    background: transparent;
    border: 0;
    text-transform: none; letter-spacing: 0;
    font-weight: 500;
  }
  .aj-sortbar-label {
    font-size: 11px; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 0.08em;
    margin-right: 4px;
  }
  .aj-sortbar .col-head {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--panel-3);
    color: var(--text-soft);
    font-size: 11.5px; font-weight: 500;
    cursor: pointer; user-select: none;
    text-transform: none; letter-spacing: 0;
  }
  .aj-sortbar .col-head:hover { color: var(--text); border-color: var(--border-strong); }
  .aj-sortbar .col-head.sorted {
    color: #fff; background: var(--blue, #2563eb); border-color: var(--blue, #2563eb);
  }
  .aj-sortbar .col-head .sort-arrow { font-size: 10px; opacity: 0.7; }
  .aj-sortbar .col-head.sorted .sort-arrow { opacity: 1; }
  /* Visual divider between sort buttons and filter dropdowns. */
  .aj-sortbar-sep {
    display: inline-block;
    width: 1px; height: 18px;
    background: var(--border);
    margin: 0 4px;
  }
  .aj-filters {
    display: inline-flex; flex-wrap: wrap; gap: 6px;
    align-items: center;
  }
  /* Each filter is a <details>/<summary> so click-to-open behavior is
     native and Esc-closes-popover works automatically. Open state
     positions the menu absolutely below the summary. */
  .aj-filter { position: relative; }
  .aj-filter > summary { list-style: none; cursor: pointer; }
  .aj-filter > summary::-webkit-details-marker { display: none; }
  .aj-filter-btn {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--panel-3);
    color: var(--text-soft);
    font-size: 11.5px; font-weight: 500;
    user-select: none;
  }
  .aj-filter-btn:hover { color: var(--text); border-color: var(--border-strong); }
  .aj-filter-active > .aj-filter-btn {
    color: #fff;
    background: var(--blue, #2563eb);
    border-color: var(--blue, #2563eb);
  }
  .aj-filter-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 16px; height: 16px; padding: 0 5px;
    border-radius: 999px;
    background: rgba(255,255,255,0.22);
    font-size: 10px; font-weight: 700;
    line-height: 1;
  }
  .aj-filter-active .aj-filter-count { background: rgba(255,255,255,0.32); color: #fff; }
  .aj-filter-caret { font-size: 9px; opacity: 0.7; }
  .aj-filter-menu {
    position: absolute; top: calc(100% + 6px); left: 0;
    min-width: 220px; max-width: 340px;
    max-height: 320px; overflow-y: auto;
    background: var(--panel);
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    padding: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.35);
    z-index: 30;
    display: flex; flex-direction: column; gap: 2px;
  }
  .aj-filter-opt {
    display: flex; align-items: center; gap: 8px;
    padding: 5px 8px;
    border-radius: 4px;
    font-size: 12.5px; color: var(--text);
    cursor: pointer;
  }
  .aj-filter-opt:hover { background: var(--row-hover); }
  .aj-filter-opt input[type="checkbox"] {
    width: 14px; height: 14px;
    accent-color: var(--blue, #2563eb);
    cursor: pointer;
  }
  .aj-filter-empty {
    padding: 8px 6px;
    font-size: 12px; color: var(--text-muted); font-style: italic;
  }
  .aj-filter-clear,
  .aj-filter-clear-all {
    margin-top: 6px;
    padding: 5px 8px;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-soft);
    font-size: 11px;
    cursor: pointer;
  }
  .aj-filter-clear:hover,
  .aj-filter-clear-all:hover { color: var(--text); border-color: var(--border-strong); }
  .aj-filter-clear-all {
    margin-top: 0; margin-left: 6px;
    border-color: rgba(248,113,113,0.4); color: var(--red-text);
  }
  .aj-filter-clear-all:hover {
    background: rgba(248,113,113,0.1); color: var(--red-text);
  }

  @media (max-width: 900px) {
    .aj-card { flex-wrap: wrap; }
    .aj-card-head { flex-wrap: wrap; }
    .aj-card-actions-row { margin-left: 0; width: 100%; justify-content: flex-end; }
    .aj-card-modified { display: none; }
  }

  /* ─────────────────────────────────────────────────────────────────
     Bulk action bar — floats at the bottom of the viewport when 1+
     job cards are selected. Pill-shaped dark bar with the count, a
     close × , category dropdowns, and Archive. Each dropdown is a
     native <details>/<summary> so click-to-open + click-outside-to-
     close are free; the menu list positions absolutely above the bar.
     ───────────────────────────────────────────────────────────────── */
  .aj-bulk-bar {
    position: fixed;
    bottom: 22px;
    left: 50%;
    transform: translateX(-50%);
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 14px;
    background: var(--panel);
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    box-shadow: 0 12px 36px rgba(0,0,0,0.45);
    z-index: 90;
    max-width: calc(100vw - 32px);
    flex-wrap: wrap;
    justify-content: center;
  }
  .aj-bulk-count {
    font-size: 12.5px; font-weight: 600; color: var(--text);
    padding: 2px 8px;
    background: rgba(37, 99, 235, 0.18);
    border-radius: 999px;
  }
  .aj-bulk-clear {
    background: transparent; border: 0; color: var(--text-muted);
    font-size: 16px; line-height: 1; cursor: pointer;
    padding: 2px 6px; border-radius: 4px;
  }
  .aj-bulk-clear:hover { color: var(--text); background: var(--row-hover); }
  .aj-bulk-sep {
    display: inline-block;
    width: 1px; height: 18px;
    background: var(--border);
  }
  .aj-bulk-btn {
    display: inline-flex; align-items: center; gap: 4px;
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-soft);
    font-size: 12px; font-weight: 500;
    padding: 5px 12px;
    border-radius: 6px;
    cursor: pointer;
    user-select: none;
  }
  .aj-bulk-btn:hover { color: var(--text); border-color: var(--border-strong); }
  .aj-bulk-archive {
    color: var(--red-text); border-color: rgba(248,113,113,0.32);
  }
  .aj-bulk-archive:hover {
    background: rgba(248,113,113,0.10); color: #fecaca;
  }
  /* Each dropdown uses native <details>/<summary>. The list positions
     absolutely ABOVE the summary so it doesn't overflow the viewport
     bottom (the bar itself is at the bottom of the screen). */
  .aj-bulk-menu { position: relative; }
  .aj-bulk-menu > summary { list-style: none; }
  .aj-bulk-menu > summary::-webkit-details-marker { display: none; }
  .aj-bulk-menu-list {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    min-width: 200px;
    max-height: 260px;
    overflow-y: auto;
    background: var(--panel);
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    padding: 6px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
    display: flex; flex-direction: column; gap: 2px;
    z-index: 91;
  }
  .aj-bulk-menu-item {
    background: transparent; border: 0;
    text-align: left;
    padding: 6px 10px;
    border-radius: 4px;
    color: var(--text);
    font-size: 12.5px;
    cursor: pointer;
    white-space: nowrap;
  }
  .aj-bulk-menu-item:hover { background: var(--row-hover); }
  .aj-bulk-menu-clear { color: var(--text-muted); font-style: italic; }
  .pb-name-cell,
  .jc-job-cell {
    display: flex;
    align-items: center;
    gap: 8px;
  }
  .dashboard-card li .dc-job-name {
    font-weight: 600; color: var(--text-strong);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .dashboard-card li .dc-job-sub {
    font-size: 11px; color: var(--text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .dashboard-card .dc-empty {
    padding: 30px 10px; text-align: center;
    color: var(--text-subtle); font-size: 12.5px; font-style: italic;
    border: 1px dashed var(--border); border-radius: 8px;
  }

  @media (max-width: 1100px) {
    .dashboard-grid { grid-template-columns: 1fr; }
  }
  @media (max-width: 980px) {
    .app-shell { flex-direction: column; }
    .sidebar {
      width: auto; position: static; min-height: 0; max-height: none;
      flex-direction: row; flex-wrap: wrap; align-items: center;
      padding: 10px 12px; gap: 6px;
      border-right: none; border-bottom: 1px solid var(--border);
    }
    /* 2026-07-01 — compact top-bar mode. The old rules kept the 88px logo
       on its own full-width row and stretched every nav item to fill
       (flex: 1 0 140px), so the "top bar" ate ~450px of vertical space in
       loose, ragged rows. Now: small inline logo, natural-width chip items,
       theme + account pinned right. Desktop (>980px) untouched. */
    .sidebar .logo-wrap {
      width: auto; padding: 0; margin: 0 8px 0 0; border-bottom: none;
    }
    .sidebar .logo-wrap::after { content: none; }
    .sidebar .logo-wrap a { padding: 2px 4px; border-radius: 8px; }
    .sidebar .logo-wrap img { height: 36px; }
    .nav-item { flex: 0 1 auto; width: auto; height: 36px; padding: 0 10px; font-size: 13px; gap: 8px; }
    .nav-create-wrap { flex: 0 0 auto; }
    .nav-section-label { display: none; }
    .sidebar-footer {
      width: auto; margin: 0 0 0 auto;
      display: flex; align-items: center; gap: 8px;
    }
    .main { padding: 18px 14px 36px; }
    /* The sidebar is a horizontal top bar here, so the collapse tab and the
       reorder grips don't apply — hide them and neutralize any collapsed
       state carried over from a wider viewport. */
    .sidebar-toggle { display: none; }
    .nav-grip { display: none; }
    .sidebar-collapsed .sidebar {
      margin-left: 0; transform: none; pointer-events: auto;
    }
  }

  /* ── Billing view (4-tab structure: Billing / A/R / Job Costing / Project Budgeting) ─ */
  .billing-page { display: flex; flex-direction: column; gap: 16px; }
  .billing-tabs {
    display: flex; align-items: flex-end; gap: 6px;
    border-bottom: 1px solid var(--border); padding-bottom: 0;
  }
  .billing-tabs-spacer { flex: 1 1 auto; }
  .billing-tabs-actions-only { border-bottom: none; }
  .billing-tab-action {
    background: rgba(99,102,241,0.10); color: var(--indigo);
    border: 1px solid rgba(99,102,241,0.30);
    border-radius: 6px; padding: 6px 12px;
    font-size: 12px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap;
    display: inline-flex; align-items: center; gap: 6px;
    margin-bottom: 6px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .billing-tab-action:hover { background: rgba(99,102,241,0.22); color: var(--text-strong); border-color: rgba(99,102,241,0.55); }
  .billing-tab-action .btn-icon { width: 14px; height: 14px; }
  .billing-tab {
    background: transparent; border: 1px solid transparent; border-bottom: none;
    padding: 10px 18px; font-size: 13px; font-weight: 500;
    color: var(--text-soft); cursor: pointer; font-family: inherit;
    border-radius: 8px 8px 0 0; margin-bottom: -1px;
    transition: color 0.15s, background 0.15s, border-color 0.15s;
  }
  .billing-tab:hover { color: var(--text); background: rgba(59,130,246,0.06); }
  .billing-tab.active {
    color: var(--text-strong); background: var(--panel); border-color: var(--border);
    border-bottom: 1px solid var(--panel);
  }
  .billing-tab-body { padding: 4px 0; }

  /* Stub content (Billing + A/R tabs while pending build) */
  .billing-stub {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    padding: 24px 28px; max-width: 920px;
  }
  .billing-stub h3 { color: var(--text-strong); font-size: 18px; margin: 0 0 12px; font-weight: 600; }
  .billing-stub p { color: var(--text); font-size: 13.5px; line-height: 1.6; margin: 0 0 12px; }
  .billing-stub-coming {
    margin-top: 16px; padding: 16px; background: rgba(59,130,246,0.07);
    border: 1px solid rgba(59,130,246,0.20); border-radius: 8px;
  }
  .billing-stub-coming p { color: var(--blue-light); margin-bottom: 10px; font-size: 13px; }
  .billing-stub-coming p:last-child { margin-bottom: 0; }
  .billing-stub code {
    background: var(--surface-deep); padding: 1px 5px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 12px;
    color: var(--purple-soft);
  }

  /* ── Tab 1 active-cycle section (PREVIEW, gated on PEAK_TAB1_ACTIVE) ── */
  .bw-flag-pill {
    margin-left: 8px;
    padding: 1px 7px; border-radius: 100px;
    font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em;
    background: rgba(245,158,11,0.16); color: var(--amber);
    border: 1px solid rgba(245,158,11,0.34);
    text-transform: uppercase;
  }
  .bw-active-wrap {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    /* NOTE: overflow MUST stay visible — `position: sticky` on the
       date-headers below dies the moment any ancestor sets
       overflow: hidden/auto/scroll. */
    overflow: visible; padding: 14px 16px;
  }
  .bw-active-empty {
    padding: 24px; color: var(--text-soft); font-size: 13px; line-height: 1.55;
  }
  .bw-active-empty p { margin: 0 0 8px; }
  .bw-active-empty p:last-child { margin: 0; }
  .bw-active-empty code {
    background: var(--surface-deep); padding: 2px 6px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 11.5px;
    color: var(--purple-soft); word-break: break-all;
  }
  .bwa-meta {
    padding: 10px 12px; margin-bottom: 12px;
    background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px;
    color: var(--text-soft); font-size: 12px;
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  }
  .bwa-meta strong { color: var(--text); font-weight: 600; }
  .bwa-pp { color: var(--text-muted); font-style: italic; }
  .bwa-note {
    padding: 8px 12px; margin-bottom: 14px;
    background: rgba(59,130,246,0.05); border: 1px solid rgba(59,130,246,0.18);
    border-radius: 8px; color: var(--text); font-size: 12px; line-height: 1.5;
  }
  .bwa-note code {
    background: rgba(0,0,0,0.30); padding: 1px 5px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 11px;
    color: var(--purple-soft);
  }
  .bwa-note-dryrun {
    background: rgba(245,158,11,0.10); border-color: rgba(245,158,11,0.36);
    color: var(--amber-text);
  }
  .bwa-note-dryrun code {
    color: var(--amber-text);
  }
  .bwa-note-dryrun strong { color: var(--on-color); }
  /* Costing-staleness banner — fires when state.lastCostingChangeAt is
     newer than jobs.json._built_at. Uses red-ish tone to read as urgent
     without being alarming, since the consequence is just "rerun the
     script", not data loss. */
  .bwa-note-stale {
    background: rgba(239,68,68,0.10); border-color: rgba(239,68,68,0.36);
    color: var(--red-text);
  }
  .bwa-note-stale code  { color: var(--red-text); }
  .bwa-note-stale strong { color: var(--on-color); }

  /* Day grouping — date headers stick to the top of the viewport while
     scrolling so you always know which date the card you're looking at
     belongs to. Port of the same behavior from scripts/qbo-export/widget_v3.html. */
  .bwa-day { margin-bottom: 18px; overflow: visible; }
  .bwa-day-head {
    display: flex; justify-content: space-between; align-items: center;
    padding: 12px 16px;
    background:
      linear-gradient(135deg, rgba(234,179,8,0.06) 0%, transparent 55%),
      var(--panel);
    backdrop-filter: blur(14px) saturate(1.15);
    -webkit-backdrop-filter: blur(14px) saturate(1.15);
    border: 1px solid rgba(234,179,8,0.32);
    border-left: 4px solid var(--amber);
    border-radius: 10px;
    margin-bottom: 10px;
    /* Sticky — stays pinned at the top while scrolling through the day's
       cards. The next day's header pushes it out of the way. */
    position: sticky;
    top: 64px; /* sit just below the CRM's top toolbar */
    z-index: 30;
    box-shadow: var(--shadow-card);
  }
  .bwa-day-label { color: var(--amber-text); font-weight: 600; font-size: 13.5px; }
  .bwa-day-meta { display: flex; gap: 10px; align-items: center; }
  .bwa-day-count {
    color: var(--text-soft); font-size: 11px; padding: 2px 8px; border-radius: 100px;
    background: rgba(148,163,184,0.16); border: 1px solid rgba(148,163,184,0.28);
  }
  .bwa-day-total {
    color: var(--text-strong); font-weight: 700; font-size: 14px;
    font-variant-numeric: tabular-nums;
  }
  .bwa-day-cards { display: flex; flex-direction: column; gap: 10px; }

  /* 2026-07-27 — the card-shaped shimmer skeleton is GONE (Matt: felt
     janky and unlike the rest of the CRM). The active cycle now loads
     with the same .view-loading spinner every other view uses. */
  .bw-sync-stamp {
    margin-left: auto;
    font-weight: 400; font-size: 11.5px;
    text-transform: none; letter-spacing: normal;
    color: var(--text-soft);
  }

  /* Card */
  .bwa-card {
    background: var(--panel-3); border: 1px solid var(--border-subtle); border-radius: 10px;
    overflow: hidden;
    transition: border-color 0.15s, background 0.15s, box-shadow 0.15s, transform 0.15s;
  }
  /* 2026-05-15 — hover lift. Subtle shadow + 1px upward translate so the
     card feels tactile + interactive. Reads as "this is clickable" without
     adding visual chrome. Matches the modern QBO/Stripe/Jobber card pattern. */
  .bwa-card:hover {
    border-color: var(--border-strong);
    box-shadow: 0 2px 10px rgba(0,0,0,0.18);
    transform: translateY(-1px);
  }
  .bwa-card-head {
    display: flex; justify-content: space-between; align-items: flex-start;
    padding: 12px 16px; gap: 12px;
    background: rgba(59,130,246,0.04); border-bottom: 1px solid var(--border-subtle);
  }
  .bwa-card-head-left { flex: 1 1 auto; min-width: 0; }
  .bwa-card-head-right { flex: 0 0 auto; text-align: right; }
  .bwa-card-job { color: var(--text-strong); font-weight: 600; font-size: 13.5px; }
  .bwa-card-job-sub { color: var(--text); font-size: 12px; margin-top: 1px; }
  .bwa-card-cust { color: var(--text-soft); font-size: 11.5px; margin-top: 2px; }
  .bwa-card-flags { margin-top: 6px; display: flex; gap: 5px; flex-wrap: wrap; }
  .bwa-head-picker { margin-top: 5px; }
  /* 2026-05-16 — chips bumped to larger size for easier scan-reading.
     Was: 11px text / 18px avatar / 4×7px padding. Now: ~14px text /
     22px avatar / 5×10px padding. CC + QBO are the primary identifiers
     on each card now (since the title row was dropped) — they deserve
     real estate. */
  .bwa-card-links { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 8px; }
  .bwa-chip-group { display: inline-flex; align-items: stretch; }
  .bwa-chip-group .bwa-link-chip { border-radius: 5px 0 0 5px; }
  .bwa-chip-clear {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0 8px; font-size: 0.9rem; line-height: 1; cursor: pointer;
    border: 1px solid; border-left: none; border-radius: 0 5px 5px 0;
    background: transparent; color: inherit; opacity: 0.5;
    transition: opacity 0.12s;
  }
  .bwa-chip-clear:hover { opacity: 1; }
  .bwa-chip-group:has(.bwa-link-chip-cc) .bwa-chip-clear { border-color: rgba(6,182,212,0.28); }
  .bwa-chip-group:has(.bwa-link-chip-qbo) .bwa-chip-clear { border-color: rgba(34,197,94,0.24); }
  .bwa-link-chip {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 0.85rem; font-weight: 500; letter-spacing: 0.01em;
    padding: 5px 10px; border-radius: 5px; text-decoration: none;
    transition: background 0.12s, color 0.12s;
  }
  .bwa-chip-icon { display: inline-flex; align-items: center; }
  /* 2026-05-15 — customer initial circle inside the QBO chip. Color
     varies by customer name hash so the same client always gets the
     same shade. Adds visual recognition for repeat customers.
     2026-05-16 — bumped from 18px to 22px for the larger chip size. */
  .bwa-chip-avatar {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; border-radius: 50%;
    border: 1px solid; margin-right: 7px;
    font-size: 12px; font-weight: 700; line-height: 1;
    letter-spacing: 0;
    flex-shrink: 0;
  }
  /* 2026-05-15 — confidence pill on CC chip. Shows alongside the chip
     when the match came from learning (🧠) or low-confidence fuzzy (❓).
     Explicit user picks get no pill (correct by construction).
     2026-05-16 — bumped to match the larger chip. */
  .bwa-chip-confidence {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    margin-left: -4px; margin-right: 2px;
    font-size: 13px; opacity: 0.85;
    cursor: help;
  }
  .bwa-chip-confidence-learned { filter: drop-shadow(0 0 2px rgba(96,165,250,0.45)); }
  .bwa-chip-confidence-verify  { filter: drop-shadow(0 0 2px rgba(245,158,11,0.45)); }
  .bwa-chip-icon svg { width: 14px; height: 14px; }
  .bwa-link-chip-cc {
    background: rgba(6,182,212,0.13); color: var(--cyan);
    border: 1px solid rgba(6,182,212,0.28);
  }
  .bwa-link-chip-cc:hover { background: rgba(6,182,212,0.24); color: var(--cyan); }
  .bwa-link-chip-qbo {
    background: rgba(34,197,94,0.11); color: var(--green-text);
    border: 1px solid rgba(34,197,94,0.24);
  }
  .bwa-link-chip-qbo:hover { background: rgba(34,197,94,0.22); color: var(--green-soft); }
  .bwa-cc-select, .bwa-cc-input {
    background: var(--surface-deep); color: var(--text-soft); border: 1px solid var(--border);
    border-radius: 5px; padding: 4px 8px; font-size: 11.5px; font-family: inherit;
    cursor: pointer; max-width: 340px; width: 100%;
  }
  .bwa-cc-input { cursor: text; }
  .bwa-cc-select:focus, .bwa-cc-input:focus {
    outline: none; border-color: rgba(59,130,246,0.5); color: var(--text);
  }
  /* 2026-05-19 — QBO picker styled as a pending-link green tile so the
     client name visually matches the green QBO chip that replaces it
     once a match is locked. Subtle dashed border tells Matt it's an
     "unlinked" state without making it look like a generic input. */
  .bwa-qbo-cust-input {
    background: rgba(34,197,94,0.07); color: var(--green-text);
    border: 1px dashed rgba(34,197,94,0.40);
    border-radius: 5px; padding: 4px 10px; font-size: 12px; font-weight: 500;
    font-family: inherit; max-width: 260px; width: 100%;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
  }
  .bwa-qbo-cust-input::placeholder { color: rgba(74,222,128,0.45); font-weight: 400; }
  .bwa-qbo-cust-input:hover { background: rgba(34,197,94,0.13); border-color: rgba(34,197,94,0.55); }
  .bwa-qbo-cust-input:focus {
    outline: none; background: rgba(34,197,94,0.16);
    border-style: solid; border-color: rgba(34,197,94,0.65); color: var(--green-soft);
  }
  .bwa-card-total {
    color: var(--text-strong); font-weight: 700; font-size: 16px;
    font-variant-numeric: tabular-nums;
  }
  /* "cost" caption on the card total when the card is filed to costing —
     signals the figure is loaded cost, not the customer charge-out total. */
  .bwa-card-total-tag {
    font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    color: var(--amber, #f59e0b); background: rgba(245,158,11,0.13);
    border-radius: 3px; padding: 0 4px; vertical-align: middle;
  }
  .bwa-card-status { margin-top: 4px; }
  .bwa-card-body { padding: 6px 16px 12px; }

  /* Edit controls row between head and body (M2 v1 — approve / target / push) */
  .bwa-card-controls {
    display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
    padding: 8px 16px;
    background: rgba(0,0,0,0.18);
    border-bottom: 1px solid rgba(35,40,56,0.55);
  }
  .bwa-approve-toggle {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--text); font-size: 12px; cursor: pointer;
    padding: 4px 10px; border-radius: 6px;
    background: rgba(148,163,184,0.10);
    border: 1px solid rgba(148,163,184,0.25);
    user-select: none;
  }
  .bwa-approve-toggle:hover { background: rgba(148,163,184,0.18); }
  .bwa-approve-toggle input { margin: 0; cursor: pointer; }
  .bwa-target-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
  .bwa-target-picker {
    background: var(--surface-deep); color: var(--text); border: 1px solid var(--border);
    border-radius: 6px; padding: 5px 10px; font-size: 12px; font-family: inherit;
    cursor: pointer; min-width: 280px; max-width: 460px;
  }
  .bwa-target-picker:focus { outline: none; border-color: rgba(59,130,246,0.55); }
  .bwa-target-picker optgroup { color: var(--text-soft); font-size: 11.5px; font-weight: 600; }
  .bwa-target-picker option { color: var(--text); padding: 4px 0; }
  .bwa-target-btn {
    background: var(--panel-2); color: var(--text-soft); border: 1px solid var(--border);
    border-radius: 6px; padding: 5px 12px; font-size: 12px; font-family: inherit;
    cursor: pointer; white-space: nowrap; transition: background 0.12s, color 0.12s;
  }
  .bwa-target-btn:hover { background: var(--row-hover); color: var(--text); }
  /* Don't bill — visually subtler than New invoice (less-likely action) */
  .bwa-target-btn-unbill {
    background: transparent; border-color: var(--border-subtle);
    color: var(--text-muted); font-size: 11.5px;
  }
  .bwa-target-btn-unbill:hover { background: rgba(239,68,68,0.08); color: var(--red-text); border-color: rgba(239,68,68,0.30); }
  .bwa-target-btn-create.bwa-target-btn-active {
    background: rgba(59,130,246,0.18); border-color: rgba(59,130,246,0.5); color: var(--blue-light);
  }
  .bwa-target-btn-unbill.bwa-target-btn-active {
    background: rgba(239,68,68,0.15); border-color: rgba(239,68,68,0.4); color: var(--red-text);
  }
  .bwa-target-hint {
    color: var(--text-soft); font-size: 11px; font-style: italic;
    padding: 0 4px; opacity: 0.85;
  }
  .bwa-target-hint::before { content: '· '; color: var(--text-subtle); }

  /* Job Costing match chip — sits below the card controls, confirms which
     jobs.json row this card rolls into and the running actual/quote. */
  .bwa-jc-chip {
    margin: 6px 0 0;
    padding: 6px 10px;
    font-size: 12px;
    color: var(--text-soft);
    background: rgba(99,102,241,0.07);
    border: 1px solid rgba(99,102,241,0.18);
    border-radius: 6px;
    line-height: 1.5;
  }
  .bwa-jc-chip strong { color: var(--text); font-weight: 600; }
  .bwa-jc-chip-loading {
    background: transparent; border-style: dashed; opacity: 0.6; font-style: italic;
  }
  .bwa-jc-chip-warn {
    background: rgba(245,158,11,0.08); border-color: rgba(245,158,11,0.30); color: var(--amber-text, #fbbf24);
  }
  .bwa-jc-chip-warn-inline { color: var(--amber-text, #fbbf24); font-style: italic; }
  .bwa-jc-chip-tag {
    display: inline-block; margin-left: 4px; padding: 0 6px;
    font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--text-soft); background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.08); border-radius: 3px;
  }
  .bwa-jc-chip-pct { color: var(--text); font-weight: 600; }
  .bwa-jc-chip-pct.warn { color: var(--amber-text, #fbbf24); }
  .bwa-jc-chip-pct.over { color: var(--red-text); }

  .bwa-push, .bwa-push-stub {
    margin-left: auto;
    font-size: 11.5px; padding: 5px 12px;
    background: rgba(16,185,129,0.18); color: var(--green-soft);
    border: 1px solid rgba(16,185,129,0.36);
    border-radius: 6px; cursor: pointer; font-family: inherit; font-weight: 500;
  }
  .bwa-push:hover:not(:disabled), .bwa-push-stub:hover:not(:disabled) {
    background: rgba(16,185,129,0.28); color: var(--on-color);
  }
  .bwa-push:disabled, .bwa-push-stub:disabled { opacity: 0.35; cursor: not-allowed; }
  /* 2026-05-15 — Push button when approved-but-edited-after-approve.
     Amber dot prefix + slightly amber-tinted background signal "verify
     before pushing — you've changed something since approval." */
  .bwa-push-has-edits {
    background: rgba(245,158,11,0.18);
    border-color: rgba(245,158,11,0.50);
    color: var(--amber);
  }
  .bwa-push-has-edits:hover:not(:disabled) {
    background: rgba(245,158,11,0.28);
    color: var(--text-strong);
  }
  .bwa-push-edits-dot {
    color: var(--amber);
    font-size: 9px;
    margin-right: 3px;
    vertical-align: 1px;
  }

  /* QB Time auth-broken banner (styles were inline in 07-views until the
     2026-07-17 light-theme pass; the dark look is unchanged). */
  .bwa-auth-warn {
    background: #7f1d1d; color: var(--red-text);
    padding: 8px 14px; border-radius: 6px;
    margin-bottom: 10px; font-size: 13px;
  }
  [data-theme="light"] .bwa-auth-warn {
    background: #fef2f2; color: #b91c1c;
    border: 1px solid #fecaca;
  }

  /* "Mark cycle as billed / archive" button in the meta row */
  .bwa-close-cycle {
    background: rgba(167,139,250,0.14); color: var(--purple);
    border: 1px solid rgba(167,139,250,0.32);
    border-radius: 6px; padding: 5px 12px;
    font-size: 11.5px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .bwa-close-cycle:hover { background: rgba(167,139,250,0.26); color: var(--text-strong); border-color: rgba(167,139,250,0.55); }
  .bwa-archive-before-group {
    display: inline-flex; align-items: center; gap: 4px; margin-left: 8px;
  }
  .bwa-archive-before-date {
    background: var(--panel-3); color: var(--text);
    border: 1px solid rgba(167,139,250,0.32); border-radius: 6px;
    padding: 4px 8px; font-size: 11.5px; font-family: inherit;
  }
  .bwa-archive-before-btn {
    background: rgba(167,139,250,0.14); color: var(--purple);
    border: 1px solid rgba(167,139,250,0.32);
    border-radius: 6px; padding: 5px 12px;
    font-size: 11.5px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .bwa-archive-before-btn:hover { background: rgba(167,139,250,0.26); color: var(--text-strong); border-color: rgba(167,139,250,0.55); }
  .bwa-refresh {
    background: rgba(74,222,128,0.10); color: var(--green-text);
    border: 1px solid rgba(74,222,128,0.30);
    border-radius: 6px; padding: 5px 12px;
    font-size: 11.5px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap; margin-right: 8px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .bwa-refresh:hover { background: rgba(74,222,128,0.20); color: var(--text-strong); border-color: rgba(74,222,128,0.55); }
  .bwa-refresh:disabled { opacity: 0.6; cursor: progress; }

  /* Approval progress bar in the meta line */
  .bwa-progress {
    display: inline-block; vertical-align: middle;
    width: 80px; height: 4px;
    background: rgba(148,163,184,0.18);
    border-radius: 2px; overflow: hidden;
    margin: 0 4px;
  }
  .bwa-progress-bar {
    display: block; height: 100%;
    background: rgba(74,222,128,0.65);
    transition: width 0.25s ease;
  }

  /* Approve all ready — primary batch action, distinctive blue */
  .bwa-approve-all {
    background: rgba(59,130,246,0.16); color: var(--blue-light);
    border: 1px solid rgba(59,130,246,0.40);
    border-radius: 6px; padding: 5px 14px;
    font-size: 11.5px; font-weight: 600; font-family: inherit;
    cursor: pointer; white-space: nowrap; margin-right: 8px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .bwa-approve-all:hover { background: rgba(59,130,246,0.30); color: var(--text-strong); border-color: rgba(59,130,246,0.65); }

  /* Reset cycle — destructive but recoverable; styled subtle/orange */
  .bwa-reset-cycle {
    background: rgba(251,146,60,0.08); color: var(--orange);
    border: 1px solid rgba(251,146,60,0.25);
    border-radius: 6px; padding: 5px 12px;
    font-size: 11.5px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap; margin-right: 8px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .bwa-reset-cycle:hover { background: rgba(251,146,60,0.20); color: var(--text-strong); border-color: rgba(251,146,60,0.50); }
  .bwa-reset-cycle:disabled { opacity: 0.6; cursor: progress; }

  /* Group-by segmented toggle in the active-cycle meta line */
  .bwa-groupby {
    display: inline-flex; align-items: center; gap: 4px;
    margin-right: 10px; font-size: 11.5px;
  }
  .bwa-groupby-label {
    color: var(--text-soft); margin-right: 4px;
  }
  .bwa-groupby-btn {
    background: rgba(148,163,184,0.08); color: var(--text);
    border: 1px solid rgba(148,163,184,0.22);
    border-radius: 5px; padding: 4px 10px;
    font-size: 11.5px; font-weight: 500; font-family: inherit;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .bwa-groupby-btn:hover { background: rgba(148,163,184,0.16); color: var(--text-strong); }
  .bwa-groupby-btn-active {
    background: rgba(99,102,241,0.18);
    color: var(--indigo);
    border-color: rgba(99,102,241,0.55);
  }
  .bwa-groupby-btn-active:hover { background: rgba(99,102,241,0.26); color: var(--text-strong); }

  /* Sub-label inside group header (e.g. customer name when grouping by job) */
  .bwa-day-sublabel {
    color: var(--text-soft); font-weight: 400; font-size: 0.92em; margin-left: 4px;
  }

  /* Restore-archived link in the empty state */
  .bwa-restore-link {
    color: var(--purple-soft); text-decoration: none;
    border-bottom: 1px dotted rgba(165,180,252,0.4);
    font-size: 12px;
  }
  .bwa-restore-link:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }

  /* Approved / Unbillable visual washes on the card itself.
     Earlier these used a top-only gradient that faded to transparent at 40%
     of the card height — Matt asked for the whole tile to read as approved
     so it's harder to miss. Now: flat green/orange tint across the entire
     card, plus a slightly stronger band on the header for hierarchy. */
  .bwa-card-approved {
    border-color: rgba(16,185,129,0.45);
    background: rgba(16,185,129,0.10);
  }
  .bwa-card-approved .bwa-card-head { background: rgba(16,185,129,0.16); }
  .bwa-card-quoted {
    border-color: rgba(234,179,8,0.45);
    background: rgba(234,179,8,0.09);
  }
  .bwa-card-quoted .bwa-card-head { background: rgba(234,179,8,0.16); }
  .bwa-card-late-arrival {
    border-color: rgba(244,114,182,0.55);
    background: rgba(244,114,182,0.08);
  }
  .bwa-card-late-arrival .bwa-card-head { background: rgba(244,114,182,0.16); }
  .bwa-late-banner {
    color: #fce4ec; font-size: 12.5px; line-height: 1.5;
    background: rgba(244,114,182,0.14);
    border-left: 3px solid rgba(244,114,182,0.65);
    padding: 8px 12px; margin: 8px 14px;
    border-radius: 4px;
  }
  .bwa-card-unbill {
    border-color: rgba(245,158,11,0.42);
    background: rgba(245,158,11,0.10);
    opacity: 0.78;
  }
  .bwa-card-unbill .bwa-card-head { background: rgba(245,158,11,0.16); }

  /* Yellow tint for cards derive_cards flagged as likely unbillable
     (yard/shop/van-stock-unassigned PO patterns). Doesn't auto-act —
     just visually nudges Matt to double-check then confirm with Don't bill. */
  .bwa-card-suspected-unbill {
    border-color: rgba(251,191,36,0.40);
    background: rgba(251,191,36,0.04);
  }
  .bwa-card-unbill-hint {
    color: var(--amber-text); font-size: 12px; line-height: 1.4;
    background: rgba(251,191,36,0.12);
    border-left: 3px solid rgba(251,191,36,0.65);
    padding: 6px 14px;
    border-top: 1px solid rgba(251,191,36,0.20);
  }
  .bwa-card-unbill-hint strong { color: #fef3c7; }

  /* Late-arrival resurface strip — a filed/pushed card that came back only
     because new supplier lines landed after it was disposed. Explains why
     the card is here, that the disposed lines are hidden, and that acting
     on it cannot double-count. Companion to hasLateArrivals/trimToNewLines
     in 07-views.js, which used to resurface cards silently. Indigo (info)
     family like .bwa-jc-chip — this is reassurance, not a warning. */
  .bwa-card-late-strip {
    color: var(--text-soft); font-size: 12px; line-height: 1.4;
    background: rgba(99,102,241,0.08);
    border-left: 3px solid rgba(99,102,241,0.55);
    padding: 6px 14px;
    border-top: 1px solid rgba(99,102,241,0.18);
  }

  /* Inline create-invoice form — surfaces under the controls when target
     is "Create new invoice". Lets Matt pick the QBO customer + edit the
     job-name before pushing. Customer dropdown is a native <datalist> so
     the browser handles filter-as-you-type. */
  .bwa-create-form {
    padding: 8px 16px 12px;
    border-top: 1px dashed rgba(148,163,184,0.18);
    background: rgba(0,0,0,0.18);
  }
  .bwa-create-row {
    display: flex; align-items: center; gap: 10px;
    margin-top: 6px;
  }
  .bwa-create-row label {
    flex: 0 0 175px;
    font-size: 11.5px; color: var(--text-soft); font-weight: 500;
  }
  .bwa-create-row input[type=text] {
    flex: 1 1 auto;
    background: var(--surface-deep); color: var(--text);
    border: 1px solid rgba(148,163,184,0.30);
    border-radius: 5px; padding: 5px 9px;
    font-size: 12px; font-family: inherit;
  }
  .bwa-create-row input[type=text]:focus {
    outline: none; border-color: rgba(74,222,128,0.55);
    background: var(--surface-deep);
  }
  .bwa-create-resolved {
    flex: 0 0 auto; font-size: 10.5px; color: var(--green-text);
    background: rgba(16,185,129,0.10); padding: 3px 7px; border-radius: 3px;
  }
  .bwa-create-pending {
    flex: 0 0 auto; font-size: 10.5px; color: var(--amber); font-style: italic;
  }
  .bwa-create-row-collapsed { display: none; }
  .bwa-create-summary {
    color: var(--text); font-size: 12.5px; line-height: 1.5;
    padding: 6px 0 2px;
  }
  .bwa-create-summary strong { color: var(--text); font-weight: 600; }
  .bwa-job-edit-link {
    background: transparent; border: none; padding: 4px 0 0 0;
    color: var(--text-soft); font-size: 11.5px; font-family: inherit;
    cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
  }
  .bwa-job-edit-link:hover { color: var(--text); }

  .bwa-section-label {
    color: var(--text-muted); font-size: 10px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.08em;
    margin: 8px 0 4px;
  }
  .bwa-line {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 12px; padding: 5px 0;
    border-bottom: 1px solid rgba(35,40,56,0.55);
  }
  .bwa-line:last-child { border-bottom: none; }
  .bwa-line-desc { flex: 1 1 auto; color: var(--text); font-size: 14px; line-height: 1.5; min-width: 0; }
  .bwa-line-ref { color: var(--text-muted); font-size: 12px; margin-bottom: 2px; }
  .bwa-line-body { color: var(--text); }
  .bwa-line-calc {
    flex: 0 0 auto; color: var(--text-soft); font-size: 14px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; white-space: nowrap;
    display: inline-flex; align-items: center; gap: 8px;
  }
  .bwa-line-cost { color: inherit; }
  /* Compact labor line: "Zack (J) · 5.5h @ $90 = $495.00" */
  .bwa-line-name { color: var(--text); font-weight: 500; }
  .bwa-line-role { color: var(--text-muted); font-size: 12.5px; margin-left: 2px; }
  .bwa-line-at   { color: var(--text-muted); }
  /* Cost-mode labor: the "@ $rate cost = $total" shows loaded cost (wage ×
     burden), not customer charge-out. The tag disambiguates at a glance. */
  .bwa-line-costtag {
    font-family: inherit; font-size: 10px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: var(--amber, #f59e0b);
    background: rgba(245,158,11,0.13); border-radius: 3px; padding: 0 4px; margin-left: 2px;
  }
  .bwa-line-at-warn { color: var(--amber, #f59e0b); }
  /* Material markup chip — explicit indicator between cost and customer total */
  .bwa-line-markup {
    background: rgba(99,102,241,0.14); color: var(--indigo);
    border-radius: 4px; padding: 1px 7px;
    font-size: 11px; font-weight: 600; font-family: inherit;
    letter-spacing: 0.02em;
  }
  .bwa-line-markup-permit {
    background: rgba(251,146,60,0.14); color: var(--orange);
  }
  .bwa-line-markup-zero {
    background: rgba(148,163,184,0.10); color: var(--text-soft); font-weight: 500;
  }
  /* Edited state — user changed markup from the default. Amber wash makes
     it obvious at a glance which lines have a custom markup. */
  .bwa-line-markup-edited {
    background: rgba(245,158,11,0.18); color: var(--amber, #f59e0b);
  }
  /* Inline number input inside the markup chip — minimal styling so it
     reads as part of the chip rather than a separate form control. */
  .bwa-line-markup-input {
    width: 32px; background: transparent; border: none;
    color: inherit; font: inherit; font-weight: 700;
    text-align: right; padding: 0; margin: 0;
    -moz-appearance: textfield;
  }
  .bwa-line-markup-input::-webkit-outer-spin-button,
  .bwa-line-markup-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .bwa-line-markup-input:focus {
    outline: none;
    background: rgba(255,255,255,0.08);
    border-radius: 2px;
  }
  .bwa-line-markup-input:disabled { opacity: 0.45; cursor: not-allowed; }

  /* 2026-05-22 — kind override toggle. Subtle text-only chip next to
     the markup chip. Hover-revealed by default so it doesn't shout —
     only the rare misclassified line needs this. When the override is
     active, the chip becomes brighter + amber so the user knows the
     line's kind has been manually flipped. */
  .bwa-line-kind-toggle {
    background: transparent;
    border: 1px dashed rgba(148, 163, 184, 0.22);
    color: var(--text-soft, #94a3b8);
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 3px;
    cursor: pointer;
    opacity: 0.55;
    transition: opacity 0.12s, color 0.12s, border-color 0.12s;
    white-space: nowrap;
  }
  .bwa-line-kind-toggle:hover {
    opacity: 1;
    color: var(--text, #e2e8f0);
    border-color: rgba(148, 163, 184, 0.55);
  }
  .bwa-line-kind-toggle-active {
    background: rgba(245, 158, 11, 0.12);
    border-color: rgba(245, 158, 11, 0.45);
    border-style: solid;
    color: var(--amber, #f59e0b);
    opacity: 1;
  }
  .bwa-line-kind-toggle-active:hover {
    background: rgba(245, 158, 11, 0.20);
    color: var(--amber, #f59e0b);
  }

  /* Inline edit inputs (hours, body, amount). Values that differ from the
     source-data defaults get a yellow underline so the user can spot edits
     at a glance; clicking the value back to the default removes the override. */
  .bwa-edit-hours, .bwa-edit-amount {
    background: var(--surface-deep); color: var(--text); border: 1px solid var(--border);
    border-radius: 4px; padding: 2px 6px;
    font-size: 14px; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; width: 72px; text-align: right;
  }
  .bwa-edit-amount { width: 92px; }
  .bwa-edit-hours:focus, .bwa-edit-amount:focus {
    outline: none; border-color: rgba(59,130,246,0.55);
  }
  .bwa-edit-hours::-webkit-inner-spin-button,
  .bwa-edit-amount::-webkit-inner-spin-button { opacity: 0.4; }
  .bwa-edit-suffix { color: var(--text-soft); margin-left: 1px; margin-right: 4px; }
  .bwa-edit-arrow  { color: var(--text-subtle); margin: 0 4px; }
  .bwa-edit-amount-wrap { color: var(--text); font-family: ui-monospace, "SF Mono", Consolas, monospace; }
  .bwa-edit-body {
    width: 100%; min-width: 280px;
    background: var(--surface-deep); color: var(--text);
    border: 1px solid var(--border-subtle); border-radius: 4px;
    padding: 4px 8px; margin-top: 2px;
    font: inherit; font-size: 12.5px; line-height: 1.5;
    resize: vertical;
  }
  .bwa-edit-body:focus { outline: none; border-color: rgba(59,130,246,0.55); background: var(--surface-deep); }
  .bwa-edit-dirty {
    border-color: rgba(245,158,11,0.55) !important;
    background: rgba(245,158,11,0.06) !important;
    color: var(--amber-text);
  }
  .bwa-line-omitted .bwa-edit-body,
  .bwa-line-omitted .bwa-edit-hours,
  .bwa-line-omitted .bwa-edit-amount { opacity: 0.4; }

  /* Per-material omit toggle. Click toggles between Omit and Restore states.
     Omitted lines render struck-through with reduced opacity so the user can
     still see what was excluded. The omit drops the line from the QBO push
     AND from the costing ledger (build_lines_for_card + calcCardTotal both
     skip omitted indexes). */
  .bwa-mat-omit-btn {
    background: rgba(248,113,113,0.10); color: var(--red-text);
    border: 1px solid rgba(248,113,113,0.28);
    border-radius: 4px; padding: 2px 8px;
    font-size: 10.5px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap;
    transition: background 0.15s, color 0.15s;
  }
  .bwa-mat-omit-btn:hover { background: rgba(248,113,113,0.22); color: var(--text-strong); }
  .bwa-line-omitted .bwa-mat-omit-btn {
    background: rgba(148,163,184,0.14); color: var(--text);
    border-color: rgba(148,163,184,0.30);
  }
  .bwa-line-omitted .bwa-mat-omit-btn:hover { background: rgba(148,163,184,0.28); color: var(--text-strong); }
  .bwa-line-omitted .bwa-line-desc { text-decoration: line-through; opacity: 0.5; }
  .bwa-line-omitted .bwa-line-cost { text-decoration: line-through; opacity: 0.5; }

  /* PO refs row in the card header — every distinct supplier+PO from the
     card's materials. Lets Matt spot misclassification at a glance (e.g.
     an EECOL PO appearing on a card matched to the wrong CC project).
     Relocated materials are filtered out — the PO follows the bill to its
     orphan card. */
  .bwa-card-pos {
    margin-top: 4px;
    display: flex; flex-wrap: wrap; gap: 4px;
  }
  .bwa-card-po {
    display: inline-block;
    background: rgba(148,163,184,0.10); color: var(--text-soft);
    border: 1px solid rgba(148,163,184,0.22);
    border-radius: 3px; padding: 1px 6px;
    font-size: 10.5px; font-weight: 500; letter-spacing: 0.01em;
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  }

  /* "Change job" replacement for the unlabeled × on the CC chip — labeled,
     visible at a glance so users know they can correct a wrong auto-match. */
  .bwa-chip-change {
    padding: 0 8px; font-size: 0.68rem; font-weight: 500;
    opacity: 0.85; white-space: nowrap;
  }
  .bwa-chip-change:hover { opacity: 1; background: rgba(6,182,212,0.10); }

  /* Three-element chip group (link + Change + ×) — middle elements lose
     their rounded-right so only the final element keeps the corner. */
  .bwa-chip-group .bwa-chip-clear:not(:last-child) { border-radius: 0; }
  .bwa-chip-remove { padding: 0 6px; font-size: 0.85rem; line-height: 1; }
  .bwa-chip-remove:hover { background: rgba(248, 113, 113, 0.15); color: var(--red); }

  /* "+ Link CC project" button — replaces the picker when user has
     explicitly clicked × Remove. Dashed border so it reads as
     opt-in rather than required input. */
  .bwa-cc-relink-btn {
    display: inline-block;
    margin-top: 6px; padding: 3px 10px;
    font-size: 0.72rem; font-weight: 500;
    border-radius: 4px;
    background: rgba(6, 182, 212, 0.08);
    color: var(--cyan, #06b6d4);
    border: 1px dashed rgba(6, 182, 212, 0.4);
    cursor: pointer;
  }
  .bwa-cc-relink-btn:hover {
    background: rgba(6, 182, 212, 0.16);
    border-style: solid;
  }

  /* Per-material "Move to job…" button. Sits next to the existing Omit
     button. When the picker is open, the button switches to "✕ Cancel".
     Picker is a datalist-backed combo box, same shape as the card-level
     CC picker. */
  .bwa-mat-move-btn {
    background: rgba(6,182,212,0.10); color: var(--cyan);
    border: 1px solid rgba(6,182,212,0.28);
  }
  .bwa-mat-move-btn:hover { background: rgba(6,182,212,0.22); color: var(--text-strong); }
  .bwa-mat-move-btn-on {
    background: rgba(6,182,212,0.22); color: var(--text-strong);
  }
  .bwa-mat-move-btn:disabled {
    opacity: 0.4; cursor: not-allowed;
  }
  .bwa-mat-move-picker {
    margin-top: 6px; padding: 6px 8px;
    background: rgba(6,182,212,0.06);
    border: 1px dashed rgba(6,182,212,0.32);
    border-radius: 4px;
    display: flex; flex-direction: column; gap: 4px;
  }
  .bwa-mat-move-picker-label {
    font-size: 11px; color: var(--text-soft);
  }
  .bwa-mat-move-picker-label strong {
    color: var(--text-strong); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  }
  .bwa-mat-move-input {
    background: var(--panel); color: var(--text-strong);
    border: 1px solid var(--border-subtle);
    border-radius: 4px; padding: 4px 6px;
    font-size: 12px; font-family: inherit;
    width: 100%;
  }

  /* Relocated material placeholder — slim row indicating where the bill
     went, with an Undo affordance. Replaces the full material row in the
     source card once a Move is committed. */
  .bwa-line-relocated {
    background: rgba(148,163,184,0.04);
    border: 1px dashed rgba(148,163,184,0.20);
    border-radius: 4px; padding: 6px 10px;
    opacity: 0.78;
  }
  .bwa-relocated-tag {
    display: inline-block; margin-right: 6px;
    background: rgba(6,182,212,0.13); color: var(--cyan);
    border: 1px solid rgba(6,182,212,0.28);
    border-radius: 3px; padding: 1px 6px;
    font-size: 10.5px; font-weight: 500;
  }
  .bwa-relocated-desc { color: var(--text); font-size: 12px; }
  .bwa-relocated-desc strong { color: var(--text-strong); }

  /* Per-line structured panel — ALWAYS visible. Renders below the body
     textarea. One row per parsed line: description left, price right,
     Hide + Remove buttons. Dividers between rows. */
  .bwa-mat-lines {
    margin-top: 8px;
    border-top: 1px dashed rgba(148,163,184,0.22);
    padding-top: 6px;
  }
  .bwa-mat-lines-summary {
    font-size: 10.5px; padding: 0 0 4px 0;
    color: var(--text-muted);
  }
  .bwa-mat-lines-summary-quiet  { opacity: 0.7; }
  .bwa-mat-lines-summary-active { color: var(--amber); font-weight: 500; }
  .bwa-mat-lines-list {
    display: flex; flex-direction: column;
    background: rgba(15,23,42,0.32);
    border-radius: 6px;
    overflow: hidden;
  }
  /* Per-line row: [description] [cost-with-tax-tag] [Hide btn] [Remove btn]
     description takes flexible width, price column right-aligned, buttons
     fixed-width on the far right. Faint border between rows. */
  .bwa-mat-line-row {
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    align-items: center; gap: 10px;
    padding: 6px 10px;
    font-size: 11.5px;
    border-bottom: 1px solid rgba(148,163,184,0.14);
    transition: background 0.12s;
  }
  .bwa-mat-line-row:last-child { border-bottom: none; }
  .bwa-mat-line-row:hover { background: rgba(148,163,184,0.06); }
  .bwa-mat-line-desc {
    color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* Editable per-line description input — fills the description column.
     Borderless to feel like the row itself, with a subtle focus state so
     editing is discoverable. */
  .bwa-mat-line-text {
    background: transparent; color: var(--text);
    border: 1px solid transparent;
    border-radius: 4px;
    padding: 3px 6px; margin: -3px -6px; /* visually edge-to-edge */
    font: inherit; font-size: 11.5px;
    width: 100%;
    transition: background 0.12s, border-color 0.12s;
  }
  .bwa-mat-line-text:hover:not(:disabled) { border-color: rgba(148,163,184,0.20); }
  .bwa-mat-line-text:focus {
    outline: none;
    border-color: rgba(59,130,246,0.55);
    background: var(--surface-deep);
  }
  .bwa-mat-line-text:disabled { color: var(--text-muted); cursor: not-allowed; }
  /* Edited row — subtle blue tint so it's visually distinct from defaults
     without being unreadable. --blue-light (#93c5fd) is used elsewhere for
     this exact pattern; --blue-soft is a 14% alpha background tint, NOT a
     text color. */
  .bwa-mat-line-text-edited {
    color: var(--blue-light);
  }
  /* Excluded / hidden rows: strike through the input value visually */
  .bwa-mat-line-excluded .bwa-mat-line-text,
  .bwa-mat-line-hidden   .bwa-mat-line-text {
    text-decoration: line-through; opacity: 0.55;
  }
  .bwa-mat-line-cost {
    color: var(--text); font-variant-numeric: tabular-nums;
    font-size: 11px; font-weight: 500;
    text-align: right;
    min-width: 160px;
    white-space: nowrap;
    display: inline-flex; align-items: baseline; gap: 4px; justify-content: flex-end;
  }
  .bwa-mat-line-tax-tag {
    /* 2026-05-15 — bumped contrast so tax amounts are easier to scan.
       Was: opacity 0.62 + 400 weight. Now: opacity 0.85 + 500 weight. */
    color: var(--text-soft); opacity: 0.85;
    font-size: 10.5px; margin-left: 4px;
    font-weight: 500;
  }
  /* Inline pretax-price input — editable line cost. Sits flush in the
     cost column with a leading "$" so it looks like the static span it
     replaced when not focused. Highlighted ring when the user has
     overridden the parsed default. */
  .bwa-mat-line-price-prefix {
    color: var(--text-muted); font-size: 11px; opacity: 0.7;
  }
  .bwa-mat-line-price-input {
    width: 68px; text-align: right;
    background: transparent; border: 1px solid transparent;
    color: var(--text); font: inherit;
    font-variant-numeric: tabular-nums;
    padding: 1px 4px; border-radius: 4px;
    -moz-appearance: textfield;
  }
  .bwa-mat-line-price-input::-webkit-outer-spin-button,
  .bwa-mat-line-price-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .bwa-mat-line-price-input:hover:not(:disabled) {
    border-color: rgba(148,163,184,0.32);
    background: rgba(148,163,184,0.08);
  }
  .bwa-mat-line-price-input:focus {
    outline: none;
    border-color: rgba(96,165,250,0.65);
    background: rgba(96,165,250,0.08);
  }
  .bwa-mat-line-price-input:disabled {
    color: var(--text-muted); opacity: 0.55;
  }
  .bwa-mat-line-price-input-edited {
    border-color: rgba(96,165,250,0.55);
    background: rgba(96,165,250,0.10);
    color: var(--blue-text, #60a5fa);
    font-weight: 600;
  }
  .bwa-mat-line-btn {
    background: rgba(148,163,184,0.10); color: var(--text-muted);
    border: 1px solid rgba(148,163,184,0.24);
    border-radius: 4px; padding: 1px 7px;
    font-size: 10px; font-weight: 500; font-family: inherit;
    cursor: pointer; white-space: nowrap;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .bwa-mat-line-btn:hover:not(:disabled) {
    background: rgba(148,163,184,0.22); color: var(--text);
  }
  .bwa-mat-line-btn:disabled { opacity: 0.4; cursor: not-allowed; }
  /* Hidden state — neutral grey, button visibly "on" */
  .bwa-mat-line-btn-on {
    background: rgba(148,163,184,0.30); color: var(--text);
    border-color: rgba(148,163,184,0.46);
  }
  /* Excluded state — red-ish, signals that money is not being charged */
  .bwa-mat-line-btn-on-excl {
    background: rgba(248,113,113,0.18); color: var(--red-text);
    border-color: rgba(248,113,113,0.40);
  }
  /* Hidden line — text struck through, cost stays visible */
  .bwa-mat-line-hidden .bwa-mat-line-desc { text-decoration: line-through; opacity: 0.5; }
  .bwa-mat-line-hidden { background: rgba(148,163,184,0.05); }
  /* Context line — informational only; never goes to customer invoice.
     derive_cards tags these (PO refs, crew notes from van stock emails).
     Rendered visibly so Matt can verify what was in the original email,
     but visually dimmed + tagged "(context)" so he knows it's not billed. */
  .bwa-mat-line-context { background: rgba(96,165,250,0.04); }
  .bwa-mat-line-context .bwa-mat-line-text { color: var(--text-muted); font-style: italic; }
  .bwa-mat-line-context .bwa-mat-line-cost { color: var(--text-muted); opacity: 0.55; }
  /* Excluded line — both desc + cost dimmed, amber wash */
  .bwa-mat-line-excluded .bwa-mat-line-desc,
  .bwa-mat-line-excluded .bwa-mat-line-cost {
    text-decoration: line-through; opacity: 0.42;
  }
  .bwa-mat-line-excluded { background: rgba(245,158,11,0.06); }

  /* Status badges — filled pills (2026-05-15 polish).
     Was: outlined with translucent background. Now: solid filled pill,
     darker text on saturated background. Reads faster at-a-glance
     (matches QBO + Stripe + Linear pattern). */
  .bwa-badge {
    display: inline-block; padding: 3px 10px; border-radius: 999px;
    font-size: 10.5px; font-weight: 700;
    border: 1px solid transparent; white-space: nowrap;
    letter-spacing: 0.02em;
  }
  .bwa-badge-pending  { background: rgba(148,163,184,0.32); color: var(--text-strong); border-color: rgba(148,163,184,0.50); }
  .bwa-badge-approved { background: rgba(16,185,129,0.32);  color: #d1fae5;            border-color: rgba(16,185,129,0.55); }
  .bwa-badge-unbill   { background: rgba(245,158,11,0.34);  color: #fef3c7;            border-color: rgba(245,158,11,0.60); }
  .bwa-badge-quoted   { background: rgba(167,139,250,0.32); color: #ede9fe;            border-color: rgba(167,139,250,0.55); }

  /* Card flags (Quoted / Credit-only) */
  .bwa-flag {
    display: inline-block; padding: 1px 7px; border-radius: 4px;
    font-size: 10px; font-weight: 600;
    border: 1px solid transparent;
  }
  .bwa-flag-quoted { background: rgba(167,139,250,0.16); color: var(--purple); border-color: rgba(167,139,250,0.30); }
  .bwa-flag-credit { background: rgba(248,113,113,0.16); color: var(--red-text); border-color: rgba(248,113,113,0.30); }

  /* ── Tab 1 (Billing workflow) recap section ─────────────────────────── */
  .bw-section-rule {
    font-size: 11px; font-weight: 700; color: var(--blue-light);
    text-transform: uppercase; letter-spacing: 0.08em;
    margin: 22px 0 12px; padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
    display: flex; align-items: center; gap: 8px;
  }
  .bw-section-rule::before {
    content: ''; display: inline-block; width: 3px; height: 12px;
    background: var(--blue); border-radius: 2px; flex-shrink: 0;
  }
  .bw-section-toggle {
    width: 100%; background: none; border: none; cursor: pointer;
    text-align: left; justify-content: space-between;
  }
  .bw-section-toggle:hover { color: var(--blue-lighter); border-bottom-color: var(--blue); }
  .bw-toggle-label { flex: 1 1 auto; }
  .bw-toggle-chevron { font-size: 10px; opacity: 0.6; flex-shrink: 0; }
  .bw-section-toggle-collapsed { margin-bottom: 0; }
  .bw-recap-wrap {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    overflow: hidden;
  }
  .bw-loading, .bw-empty {
    padding: 30px 24px; color: var(--text-soft); font-size: 13px; text-align: center;
  }
  /* ── Pending Mobile Van-Stock widget ──────────────────────────────────
     Lives between Pending Review and Active Billing Cycle. Surfaces
     submissions from the Peak Mobile van-stock form BEFORE the email
     pipeline catches up. Visually distinct from billing cards (lighter
     panel + amber accent) so Matt knows these aren't ready-to-push yet. */
  .bw-mobile-vanstock-wrap:empty { display: none; }
  .bw-mvs-section {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    padding: 14px 16px; margin: 6px 0 18px;
    border-left: 3px solid var(--amber, #f59e0b);
  }
  .bw-mvs-empty { padding: 10px 16px; }
  .bw-mvs-header {
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
    margin-bottom: 10px;
  }
  .bw-mvs-header strong { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text); }
  .bw-mvs-sub { font-size: 11px; color: var(--text-soft); }
  .bw-mvs-sub a { color: var(--blue-light); text-decoration: none; }
  .bw-mvs-sub a:hover { text-decoration: underline; }
  .bw-mvs-cards { display: flex; flex-direction: column; gap: 8px; }
  .bw-mvs-card {
    background: var(--panel-2); border: 1px solid var(--border);
    border-radius: 8px; padding: 10px 12px;
    display: grid; gap: 4px;
  }
  .bw-mvs-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
  }
  .bw-mvs-who { display: flex; align-items: center; gap: 8px; font-size: 13px; flex-wrap: wrap; }
  .bw-mvs-who strong { color: var(--text); }
  .bw-mvs-when { color: var(--text-muted); font-size: 11px; }
  .bw-mvs-tag {
    display: inline-block; padding: 1px 7px; border-radius: 9px;
    font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
    background: rgba(148,163,184,0.16); color: var(--text-soft);
  }
  .bw-mvs-tag-seacan { background: rgba(167,139,250,0.18); color: var(--purple); }
  .bw-mvs-dismiss {
    background: transparent; border: none; cursor: pointer;
    color: var(--text-muted); font-size: 14px; padding: 2px 6px; line-height: 1;
    border-radius: 4px;
  }
  .bw-mvs-dismiss:hover { color: var(--red-text); background: rgba(248,113,113,0.10); }
  .bw-mvs-job {
    font-size: 12px; color: var(--text-soft);
    padding: 2px 0;
  }
  .bw-mvs-job[data-mvs-job]:hover { color: var(--blue-light); }
  .bw-mvs-items {
    font-size: 13px; color: var(--text); line-height: 1.5;
    padding-top: 2px;
  }
  .bw-mvs-notes {
    font-size: 12px; color: var(--text-soft); font-style: italic;
    padding-top: 4px; border-top: 1px dashed var(--border);
    margin-top: 4px;
  }
  /* Generic full-view loading state — used by Today, New Job, Job Costing,
     Active Billing Cycle. Shows a small spinner above (or beside) a label.
     Centered in whatever container it lives in. */
  .view-loading {
    display: flex; align-items: center; justify-content: center; gap: 12px;
    padding: 60px 24px; color: var(--text-soft); font-size: 13px;
    flex-wrap: wrap;
  }
  .view-loading-spinner {
    width: 18px; height: 18px; border-radius: 50%;
    border: 2px solid var(--border-strong);
    border-top-color: var(--blue);
    animation: view-loading-spin 0.9s linear infinite;
    flex-shrink: 0;
  }
  @keyframes view-loading-spin {
    to { transform: rotate(360deg); }
  }
  .new-job-loading {
    position: absolute; inset: 0;
    background: var(--panel);
    z-index: 1;
  }
  .new-job-frame-wrap { position: relative; }
  .bw-recap-meta {
    padding: 12px 16px; background: var(--panel-2); border-bottom: 1px solid var(--border);
    color: var(--text-soft); font-size: 12px;
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  }
  .bw-recap-meta strong { color: var(--text); font-weight: 600; }
  .bw-meta-sep { color: var(--text-subtle); }
  /* ─── Pending review (van stock + Amazon) ─────────────────────────── */
  .bw-pending-empty {
    padding: 12px 16px; color: var(--text-subtle); font-size: 12px; font-style: italic;
  }
  /* Pending Review intro line under the "Unmatched supplier invoices" header.
     Plain prose, no chrome — just sets the row context. */
  .bw-pending-sub {
    color: var(--text-soft); font-size: 12px;
    margin: -6px 0 8px; padding: 0 2px;
  }
  .bw-orphan-hint {
    color: var(--text-subtle); font-weight: 500;
    text-transform: none; letter-spacing: 0;
  }
  .bw-orphan-list {
    display: flex; flex-direction: column; gap: 8px;
    margin-bottom: 14px;
  }
  .bw-orphan-row {
    background: rgba(251,191,36,0.06);
    border: 1px solid rgba(251,191,36,0.30);
    border-radius: 8px; padding: 10px 14px;
    display: flex; flex-direction: column; gap: 6px;
  }
  .bw-orphan-head {
    display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
    font-size: 13px;
  }
  .bw-orphan-ref { font-weight: 600; color: var(--text); }
  .bw-orphan-po  { color: var(--text-soft); font-size: 12px; }
  .bw-orphan-po code {
    font-size: 11.5px; padding: 1px 5px;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 3px; color: var(--text);
  }
  .bw-orphan-sub {
    margin-left: auto; font-weight: 600; color: var(--text);
    font-variant-numeric: tabular-nums;
  }
  .bw-orphan-body {
    color: var(--text-soft); font-size: 12px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .bw-orphan-pick {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin-top: 2px;
  }
  .bw-orphan-label {
    font-size: 11.5px; color: var(--text-soft); text-transform: none;
    letter-spacing: 0; font-weight: 500;
  }
  .bw-orphan-canon {
    flex: 1 1 280px; min-width: 220px; max-width: 460px;
    padding: 5px 10px; font-size: 13px;
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 4px;
  }
  .bw-orphan-canon:focus {
    outline: none; border-color: var(--blue);
    background: rgba(59,130,246,0.04);
  }
  .bw-orphan-save:disabled { opacity: 0.45; cursor: not-allowed; }
  .bw-pending-header {
    color: var(--amber); /* amber — these need attention before approving cycle */
  }
  .bw-pending-header::before { background: var(--amber); }
  .bw-pending-list {
    display: flex; flex-direction: column; gap: 8px;
    margin-bottom: 10px;
  }
  .bw-pending-row {
    background: rgba(251,191,36,0.06);
    border: 1px solid rgba(251,191,36,0.30);
    border-radius: 8px; padding: 10px 14px;
  }
  .bw-pending-row-decided {
    background: var(--panel-2);
    border-color: var(--border);
    padding: 6px 14px;
  }
  .bw-pending-row-decided .bw-pending-row-head { font-size: 12px; color: var(--text-soft); }
  .bw-pending-row-head {
    display: flex; align-items: center; gap: 8px;
    font-size: 13px; color: var(--text); flex-wrap: wrap;
  }
  .bw-pending-icon { font-size: 14px; flex-shrink: 0; }
  .bw-pending-kind-label {
    color: var(--amber); font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em; flex-shrink: 0;
  }
  .bw-pending-row-decided .bw-pending-kind-label { color: var(--text-subtle); }
  .bw-pending-from { font-weight: 600; color: var(--text); }
  .bw-pending-date { color: var(--text-soft); font-size: 12px; }
  .bw-pending-subject { color: var(--text); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bw-pending-summary { color: var(--text-soft); font-style: italic; font-size: 12px; }
  .bw-pending-badge {
    font-size: 10.5px; padding: 2px 7px; border-radius: 3px;
    text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700;
  }
  .bw-pending-badge-assigned { background: rgba(74,222,128,0.16); color: var(--green-text); }
  .bw-pending-badge-unbill   { background: rgba(244,114,182,0.16); color: var(--pink); }
  .bw-pending-annotation {
    color: var(--amber); font-size: 12px; margin: 6px 0 4px;
    padding: 4px 8px; background: rgba(251,191,36,0.10); border-radius: 4px;
  }
  .bw-pending-items {
    margin: 6px 0; padding-left: 22px;
    color: var(--text); font-size: 12px; line-height: 1.5;
    max-height: 200px; overflow-y: auto;
  }
  .bw-pending-items li.bw-pending-more { color: var(--text-subtle); font-style: italic; list-style: none; margin-left: -16px; }
  .bw-pending-orderhead {
    color: var(--text); font-size: 12px; margin: 4px 0;
    font-weight: 600;
  }
  .bw-pending-attachments {
    color: var(--amber); font-size: 11.5px; margin: 4px 0;
    background: rgba(251,191,36,0.10); border-radius: 4px;
    padding: 6px 9px; border-left: 2px solid rgba(251,191,36,0.55);
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  }
  .bw-pending-attachments-label { color: var(--amber); font-weight: 500; }
  .bw-pending-attachments code {
    color: var(--text); font-size: 11px; background: var(--surface-deep);
    padding: 1px 4px; border-radius: 3px; margin: 0 2px;
  }
  /* Clickable receipt thumbnail — links to full-size in a new tab. */
  .bw-pending-thumb {
    display: inline-block;
    border: 1px solid rgba(251,191,36,0.40);
    border-radius: 4px;
    overflow: hidden;
    line-height: 0;
    transition: transform 0.12s, border-color 0.12s, box-shadow 0.12s;
  }
  .bw-pending-thumb:hover {
    border-color: rgba(251,191,36,0.85);
    transform: scale(1.05);
    box-shadow: 0 2px 12px rgba(0,0,0,0.35);
  }
  .bw-pending-thumb img {
    display: block;
    height: 56px; width: 56px;
    object-fit: cover;
    background: var(--surface-deep);
  }
  .bw-pending-suggest {
    color: var(--pink); font-size: 11.5px; line-height: 1.45;
    background: rgba(244,114,182,0.08);
    border-left: 2px solid rgba(244,114,182,0.55);
    border-radius: 4px; padding: 5px 9px; margin: 4px 0;
  }
  .bw-pending-suggest strong { color: var(--pink); }
  .bw-pending-unbill-suggested {
    background: rgba(244,114,182,0.22) !important;
    border-color: rgba(244,114,182,0.65) !important;
    color: #fce4ec !important;
    box-shadow: 0 0 0 1px rgba(244,114,182,0.45) inset;
  }
  .bw-pending-body {
    color: var(--text); font-size: 11.5px; line-height: 1.45;
    background: var(--surface-deep);
    border: 1px solid rgba(35,40,56,0.6); border-radius: 4px;
    padding: 8px 12px; margin: 6px 0;
    white-space: pre-wrap; word-break: break-word;
    max-height: 240px; overflow-y: auto;
    font-family: inherit;
  }
  .bw-pending-hint {
    display: block; color: var(--text-soft); font-size: 11.5px; margin: 4px 0 6px;
  }
  .bw-pending-controls {
    display: flex; gap: 8px; align-items: center; margin-top: 6px;
  }
  .bw-pending-card-pick {
    flex: 1 1 auto; min-width: 200px;
    background: var(--surface-deep); color: var(--text);
    border: 1px solid rgba(35,40,56,0.85); border-radius: 4px;
    padding: 6px 10px; font-size: 12.5px; font-family: inherit;
  }
  .bw-pending-card-pick:focus {
    outline: none; border-color: rgba(74,222,128,0.55);
    background: var(--surface-deep);
  }
  .bw-pending-unbill {
    background: rgba(244,114,182,0.10); color: var(--pink);
    border: 1px solid rgba(244,114,182,0.35); border-radius: 4px;
    padding: 6px 12px; font-size: 12px; cursor: pointer; white-space: nowrap;
    font-family: inherit;
  }
  .bw-pending-unbill:hover { background: rgba(244,114,182,0.18); border-color: rgba(244,114,182,0.55); }
  .bw-pending-billable {
    background: rgba(16,185,129,0.12); color: var(--green-soft);
    border: 1px solid rgba(16,185,129,0.40); border-radius: 4px;
    padding: 6px 12px; font-size: 12px; cursor: pointer; white-space: nowrap;
    font-family: inherit; font-weight: 500;
  }
  .bw-pending-billable:hover { background: rgba(16,185,129,0.22); border-color: rgba(16,185,129,0.65); }
  .bw-pending-reset {
    background: transparent; color: var(--text-subtle);
    border: 1px solid rgba(75,85,99,0.40); border-radius: 4px;
    padding: 3px 9px; font-size: 11px; cursor: pointer;
    font-family: inherit; flex-shrink: 0;
  }
  .bw-pending-reset:hover { color: var(--text); border-color: rgba(148,163,184,0.55); }

  /* ─── Archived cards (tile format, read-only) ─────────────────────── */
  .bwa-arch-card {
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
    padding: 10px 14px; margin-bottom: 8px;
    transition: border-color 0.15s;
  }
  .bwa-arch-card:hover { border-color: var(--border-strong); }
  .bwa-arch-card.bwa-card-quoted {
    border-color: rgba(234,179,8,0.45); background: rgba(234,179,8,0.06);
  }
  .bwa-arch-card.bwa-card-credit {
    border-color: rgba(244,114,182,0.45); background: rgba(244,114,182,0.06);
  }
  .bwa-arch-card-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 6px;
  }
  .bwa-arch-card-title { font-size: 13px; color: var(--text); }
  .bwa-arch-card-cust  { color: var(--text-soft); font-weight: 400; }
  .bwa-arch-card-right {
    display: flex; align-items: center; gap: 10px;
    font-size: 12px; flex-wrap: nowrap;
  }
  .bwa-arch-status {
    background: rgba(74,222,128,0.12); color: var(--green-text);
    padding: 2px 8px; border-radius: 4px;
    font-size: 11px; font-weight: 500;
    text-transform: capitalize;
  }
  .bwa-arch-status-skipped { background: rgba(148,163,184,0.16); color: var(--text); }
  .bwa-arch-status-cost_only { background: rgba(234,179,8,0.16); color: var(--amber-text); }
  .bwa-arch-qbo-link {
    color: var(--blue-light); text-decoration: none;
    border-bottom: 1px dotted rgba(147,197,253,0.4);
    font-size: 12px; padding: 1px 0;
  }
  .bwa-arch-qbo-link:hover { color: var(--text-strong); border-bottom-color: rgba(147,197,253,0.8); }
  .bwa-arch-doc { color: var(--text-soft); font-size: 12px; }
  .bwa-arch-total {
    color: var(--text-strong); font-weight: 600; font-size: 13px;
    min-width: 80px; text-align: right;
  }
  .bwa-arch-body { font-size: 12.5px; }
  .bwa-arch-section-label {
    color: var(--text-soft); font-size: 10.5px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    margin: 6px 0 3px;
  }
  .bwa-arch-line {
    display: flex; justify-content: space-between;
    padding: 2px 0; color: var(--text);
  }
  .bwa-arch-label { color: var(--text); }
  .bwa-arch-meta  { color: var(--text-soft); font-variant-numeric: tabular-nums; }
  .bwa-arch-mat {
    margin: 4px 0 8px; padding-left: 8px; border-left: 2px solid var(--border);
  }
  .bwa-arch-mat-head {
    display: flex; justify-content: space-between;
    color: var(--text-soft); font-size: 11.5px; margin-bottom: 2px;
  }
  .bwa-arch-mat-ref  { color: var(--purple-soft); }
  .bwa-arch-mat-cost { color: var(--text-soft); font-variant-numeric: tabular-nums; }
  .bwa-arch-mat-line { color: var(--text); padding: 1px 0; }
  .bwa-arch-mat-more { color: var(--text-soft); font-style: italic; padding: 1px 0; }

  /* Period selector dropdown in archive section */
  .bwa-arch-period {
    background: rgba(148,163,184,0.08); color: var(--text);
    border: 1px solid rgba(148,163,184,0.22);
    border-radius: 5px; padding: 4px 8px;
    font-size: 11.5px; font-family: inherit;
    cursor: pointer;
  }
  .bwa-arch-period:hover { border-color: rgba(148,163,184,0.45); }

  /* ─── (legacy) recap table — kept for compatibility ───────────────────── */
  .bw-recap-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .bw-recap-table thead th {
    background: var(--panel-2); color: var(--text-soft); font-weight: 600; font-size: 11.5px;
    text-transform: uppercase; letter-spacing: 0.04em;
    text-align: left; padding: 10px 14px;
    border-bottom: 1px solid var(--border);
  }
  .bw-recap-table thead th.num { text-align: right; }
  .bw-recap-table tbody td {
    padding: 10px 14px; color: var(--text); border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
  }
  .bw-recap-table tbody tr:last-child td { border-bottom: none; }
  .bw-recap-table tbody tr:hover { background: rgba(59,130,246,0.04); }
  .bw-recap-table tbody td.num {
    text-align: right; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums;
  }
  .bw-card-id {
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 12px; color: var(--text);
  }
  .bw-badge {
    display: inline-block; padding: 3px 9px; border-radius: 999px;
    font-size: 11px; font-weight: 600; line-height: 1.4;
    border: 1px solid transparent; white-space: nowrap;
  }
  .bw-badge-created  { background: rgba(59,130,246,0.18); color: var(--blue-light); border-color: rgba(59,130,246,0.40); }
  .bw-badge-appended { background: rgba(16,185,129,0.16); color: var(--green-soft); border-color: rgba(16,185,129,0.34); }
  .bw-badge-skipped  { background: rgba(245,158,11,0.16); color: var(--amber); border-color: rgba(245,158,11,0.34); }
  .bw-badge-other    { background: rgba(148,163,184,0.16); color: var(--text); border-color: rgba(148,163,184,0.30); }
  .bw-qbo-link {
    color: var(--blue-light); text-decoration: none;
    border-bottom: 1px dotted rgba(147,197,253,0.4);
  }
  .bw-qbo-link:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }
  .bw-reason {
    font-style: italic; color: var(--text-soft); font-size: 12px;
  }
  .bw-coming-soon {
    margin-top: 18px; padding: 16px 20px; max-width: 920px;
    background: rgba(59,130,246,0.05); border: 1px solid rgba(59,130,246,0.18);
    border-radius: 10px;
  }
  .bw-coming-soon h4 {
    color: var(--text-strong); font-size: 14px; font-weight: 600; margin: 0 0 6px;
  }
  .bw-coming-soon p {
    color: var(--text-soft); font-size: 12.5px; line-height: 1.55; margin: 0;
  }
  .bw-coming-soon code {
    background: var(--surface-deep); padding: 1px 5px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 11px;
    color: var(--purple-soft);
  }

  /* ── A/R tab (Accounts Receivable) ───────────────────────────────────── */
  .ar-page { display: flex; flex-direction: column; gap: 12px; }
  .ar-header {
    display: flex; justify-content: space-between; align-items: center;
    gap: 16px; flex-wrap: wrap;
  }
  .ar-meta { color: var(--text-muted); font-size: 12px; }
  .ar-filters { display: flex; gap: 6px; }
  .ar-chip {
    background: var(--panel); border: 1px solid var(--border); border-radius: 999px;
    padding: 6px 14px; font-size: 12px; font-weight: 500;
    color: var(--text-soft); cursor: pointer; font-family: inherit;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .ar-chip:hover { background: var(--border-subtle); color: var(--text); }
  .ar-chip.active {
    background: rgba(59,130,246,0.18); color: var(--text-strong);
    border-color: rgba(59,130,246,0.45);
  }
  .ar-summary {
    display: flex; gap: 10px; flex-wrap: wrap;
  }
  .ar-summary-tile {
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
    padding: 10px 14px; min-width: 160px; flex: 0 1 auto;
  }
  .ar-summary-label {
    color: var(--text-muted); font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 2px;
  }
  .ar-summary-value {
    color: var(--text-strong); font-size: 18px; font-weight: 600;
    font-variant-numeric: tabular-nums;
  }
  .ar-table-wrap {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    overflow: hidden;
  }
  .ar-loading, .ar-empty, .ar-error {
    padding: 30px 24px; color: var(--text-soft); font-size: 13px; text-align: center;
  }
  .ar-error { color: var(--red-text); }
  .ar-table .ar-old { color: var(--red-text); font-weight: 600; }
  .ar-table .ar-overdue-amt { color: var(--red-text); font-weight: 600; }
  .ar-table .ar-overdue-amt-zero { color: var(--text-muted); }
  /* Overdue summary tile gets a red-ish tint when non-zero so it pops next
     to the neutral "Outstanding" tile. Tooltip on the tile explains the
     relationship between the two numbers. */
  .ar-summary-tile-overdue {
    border-color: rgba(248,113,113,0.40);
    background: rgba(248,113,113,0.06);
  }
  .ar-summary-tile-overdue .ar-summary-value { color: var(--red-text); }
  .ar-gen-stmt {
    font-size: 11.5px; padding: 5px 12px;
  }

  /* ── Bills tab (Billing › Bills) — read-only QBO unpaid-bills mirror.
     2026-07-02. Table idiom matches the A/R tab. ─────────────────────── */
  .bills-page { display: flex; flex-direction: column; gap: 12px; }
  .bills-header {
    display: flex; justify-content: space-between; align-items: center;
    gap: 16px; flex-wrap: wrap;
  }
  .bills-meta { color: var(--text-muted); font-size: 12px; }
  .bills-meta strong { color: var(--text-strong); }
  .bills-meta-overdue { color: var(--red-text); font-weight: 600; }
  .bills-actions { display: flex; gap: 8px; align-items: center; }
  .bills-table-wrap {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    overflow: hidden; overflow-x: auto;
  }
  .bills-empty, .bills-error {
    padding: 30px 24px; color: var(--text-soft); font-size: 13px; text-align: center;
  }
  .bills-error { color: var(--red-text); }
  .bills-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .bills-table th {
    text-align: left; padding: 10px 14px;
    color: var(--text-muted); font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
    border-bottom: 1px solid var(--border);
  }
  .bills-table td {
    padding: 10px 14px; color: var(--text);
    border-bottom: 1px solid var(--border-subtle);
  }
  .bills-table tbody tr:hover td { background: var(--border-subtle); }
  .bills-table th.bills-amt, .bills-table td.bills-amt {
    text-align: right; font-variant-numeric: tabular-nums;
  }
  .bills-amt-overdue { color: var(--red-text); font-weight: 600; }
  .bills-vendor { color: var(--text-strong); font-weight: 500; }
  .bills-doc {
    display: block; color: var(--text-muted); font-size: 11px; font-weight: 400;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
  }
  .bills-table tfoot td {
    border-bottom: none; border-top: 1px solid var(--border);
    color: var(--text-strong); font-weight: 600;
  }
  .bills-total-label { text-align: right; color: var(--text-muted); font-weight: 600; }
  .bills-pill {
    display: inline-flex; align-items: center;
    padding: 2px 9px; border-radius: 100px;
    font-size: 11px; font-weight: 600; white-space: nowrap;
  }
  .bills-pill-overdue { background: rgba(239, 68, 68, 0.14); color: var(--red-bright); }
  .bills-pill-today   { background: rgba(245, 158, 11, 0.16); color: var(--amber); }
  .bills-pill-later   { background: var(--border-subtle); color: var(--text-soft); }
  .bills-hint { color: var(--text-muted); font-size: 11.5px; margin: 0; line-height: 1.5; }

  /* Today A/R Watch bar — neutral cyan/teal, distinct from permit-amber and
     inspection-red. Sits on its own row beneath the date+permit row. */
  .today-header-row-ar { padding: 0 4px; }
  .today-ar-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(6, 182, 212, 0.08);
    border: 1px solid rgba(6, 182, 212, 0.32);
    font-size: 12.5px; min-width: 0;
  }
  .today-ar-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--cyan);
    box-shadow: 0 0 0 3px rgba(6, 182, 212, 0.15);
  }
  .today-ar-label {
    color: var(--cyan); font-weight: 600; flex: 0 0 auto;
  }
  .today-ar-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(6, 182, 212, 0.22); color: var(--cyan);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-ar-money {
    color: var(--text); font-weight: 500; flex: 0 0 auto;
  }
  .today-ar-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .ar-watch-name {
    color: var(--cyan); text-decoration: none; border-bottom: 1px dotted rgba(165, 243, 252, 0.4);
  }
  .ar-watch-name:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }

  /* Billing Watch — outstanding active-cycle cards not yet pushed to QBO.
     Green to signal "money still to come in" (paired with A/R cyan which
     is money already invoiced but unpaid). Click jumps to Billing tab. */
  .today-billing-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(16, 185, 129, 0.08);
    border: 1px solid rgba(16, 185, 129, 0.32);
    font-size: 12.5px; min-width: 0;
    cursor: pointer;
  }
  .today-billing-bar:hover { background: rgba(16, 185, 129, 0.14); }
  .today-billing-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #10b981;
    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.15);
  }
  .today-billing-label { color: #34d399; font-weight: 600; flex: 0 0 auto; }
  .today-billing-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(16, 185, 129, 0.22); color: #34d399;
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-billing-money { color: var(--text); font-weight: 500; flex: 0 0 auto; }
  .today-billing-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .billing-watch-name { color: var(--text); }
  .billing-watch-name + .billing-watch-name::before { content: ", "; }

  /* Bills Watch — open QBO bills overdue or due within 7 days (money going
     OUT — amber, vs Billing green = money coming in / A/R cyan = money
     invoiced). Dot flips red when anything is overdue. Click jumps to
     Billing › Bills. 2026-07-02. */
  .today-bills-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.32);
    font-size: 12.5px; min-width: 0;
    cursor: pointer;
  }
  .today-bills-bar:hover { background: rgba(245, 158, 11, 0.14); }
  .today-bills-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #f59e0b;
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.15);
  }
  .today-bills-dot-overdue {
    background: #ef4444;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.18);
  }
  .today-bills-label { color: var(--amber); font-weight: 600; flex: 0 0 auto; }
  .today-bills-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(245, 158, 11, 0.22); color: var(--amber);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-bills-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Panel-schedule Watch — field-submitted panel schedules awaiting Matt's
     review (violet, distinct from billing green / bills amber). Click opens
     the Panel Schedule tool view, whose embedded inbox is the source tab. */
  .today-panelsched-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(139, 92, 246, 0.08);
    border: 1px solid rgba(139, 92, 246, 0.32);
    font-size: 12.5px; min-width: 0;
    cursor: pointer;
  }
  .today-panelsched-bar:hover { background: rgba(139, 92, 246, 0.14); }
  .today-panelsched-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #8b5cf6;
    box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15);
  }
  .today-panelsched-label { color: var(--violet); font-weight: 600; flex: 0 0 auto; }
  .today-panelsched-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(139, 92, 246, 0.22); color: var(--violet);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-panelsched-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* ═══ Panel Schedule — CRM-native view (js/17-panel-schedule.js) ═════════
     Native rebuild of the Toolbox tool (was a cross-origin iframe). Styled to
     match the other native views — Load Calculator especially. All classes are
     ps- prefixed to stay self-contained. */
  .ps-wrap { max-width: 1040px; display: flex; flex-direction: column; gap: 14px; }
  .ps-card {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    padding: 16px 18px;
  }
  .ps-card-title {
    display: flex; align-items: center; gap: 10px;
    font-size: 15px; font-weight: 700; color: var(--text-strong); margin-bottom: 12px;
  }
  .ps-step {
    flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
    background: var(--blue); color: #fff; font-size: 12px; font-weight: 700;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .ps-meta { font-size: 12px; font-weight: 400; color: var(--text-muted); }
  .ps-right { margin-left: auto; }
  .ps-hint { font-size: 12.5px; color: var(--text-muted); line-height: 1.45; }
  .ps-muted { color: var(--text-muted); font-weight: 400; }
  .ps-link {
    background: none; border: none; color: var(--blue-bright); cursor: pointer;
    font-size: 12.5px; padding: 2px 4px; border-radius: 6px;
  }
  .ps-link:hover { text-decoration: underline; }

  /* segmented button rows */
  .ps-seg { display: flex; flex-wrap: wrap; gap: 8px; }
  .ps-seg-btn {
    flex: 1 1 auto; min-width: 90px; padding: 10px 14px;
    background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px;
    color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
    display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
    transition: background .12s, border-color .12s;
  }
  .ps-seg-btn:hover { background: var(--row-hover); }
  .ps-seg-btn.active { background: var(--blue-soft); border-color: var(--blue); color: var(--text-strong); }
  .ps-seg-sub { font-size: 11px; font-weight: 400; color: var(--text-muted); text-align: center; }
  .ps-seg-btn.active .ps-seg-sub { color: var(--blue-light); }
  .ps-mode-seg .ps-seg-btn { padding: 14px; min-width: 160px; }
  .ps-size-seg .ps-seg-btn { min-width: 46px; flex: 0 0 auto; }

  /* job picker */
  .ps-job-search-wrap { position: relative; margin-top: 10px; }
  #ps-job-search, .ps-manual-job input, #ps-custom-type, .ps-token-row input {
    width: 100%; padding: 10px 12px; background: var(--panel-3);
    border: 1px solid var(--border); border-radius: 8px; color: var(--text); font-size: 13px;
  }
  #ps-job-search:focus, .ps-manual-job input:focus, #ps-custom-type:focus, .ps-token-row input:focus {
    outline: none; border-color: var(--blue);
  }
  .ps-job-results {
    position: absolute; top: 100%; left: 0; right: 0; margin-top: 4px; z-index: 40;
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
    box-shadow: var(--shadow-lg, 0 10px 30px rgba(0,0,0,.4)); max-height: 260px; overflow-y: auto;
  }
  .ps-job-row { padding: 9px 12px; cursor: pointer; border-bottom: 1px solid var(--border-subtle); }
  .ps-job-row:last-child { border-bottom: none; }
  .ps-job-row:hover { background: var(--row-hover); }
  .ps-manual-job { display: grid; gap: 8px; margin-top: 10px; }
  #ps-custom-type { margin-top: 8px; }
  .ps-selected-job, .ps-review-job {
    display: flex; align-items: center; gap: 10px; margin-top: 10px;
    padding: 10px 12px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px;
  }
  .ps-review-job { margin-top: 0; flex: 1 1 auto; min-width: 200px; background: none; border: none; padding: 0; }
  .ps-selected-name { font-weight: 600; color: var(--text-strong); font-size: 13.5px; }
  .ps-selected-addr { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
  .ps-selected-job .ps-link { margin-left: auto; }

  /* dropzones */
  .ps-dz-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  @media (max-width: 720px) { .ps-dz-row { grid-template-columns: 1fr; } }
  .ps-dropzone {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; min-height: 116px; padding: 14px; text-align: center; cursor: pointer;
    background: var(--panel-3); border: 1.5px dashed var(--border-strong); border-radius: 10px;
    position: relative;
  }
  .ps-dropzone:hover, .ps-dropzone.drag { border-color: var(--blue); background: var(--blue-soft); }
  .ps-dropzone.has-file { border-style: solid; }
  .ps-dz-title { font-weight: 600; color: var(--text-strong); font-size: 13px; }
  .ps-dz-sub { font-size: 11.5px; color: var(--text-muted); }
  .ps-thumb { max-width: 100%; max-height: 120px; border-radius: 6px; margin-top: 6px; }

  /* buttons */
  .ps-btn {
    padding: 9px 16px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--panel-2); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
  }
  .ps-btn:hover:not(:disabled) { background: var(--row-hover); }
  .ps-btn.primary { background: var(--blue); border-color: var(--blue); color: #fff; }
  .ps-btn.primary:hover:not(:disabled) { background: var(--blue-hover); }
  .ps-btn:disabled { opacity: .5; cursor: not-allowed; }
  .ps-wide { width: 100%; margin-top: 12px; }

  /* Breaker palette (manual formatting) — a sticky rail to the RIGHT of the
     grid so the type buttons stay in reach however far down a 60-slot panel
     you've scrolled. Always rendered at a fixed width (buttons just enable
     on selection), so selecting a cell never shifts the grid sideways — if
     it shifted, the 2nd click of a double-click would miss the cell it
     started on. Narrow screens flip it to a horizontal bar pinned above the
     grid (media query below). */
  .ps-format-bar-slot { flex: 0 0 176px; width: 176px; position: sticky; top: 12px; z-index: 5; }
  .ps-format-bar {
    display: flex; flex-direction: column; align-items: stretch; gap: 7px;
    padding: 11px 12px; border-radius: 9px;
    border: 1px solid var(--border-strong);
    /* solid base so the bar stays opaque where it overlays the grid when stuck */
    background-color: var(--panel);
  }
  .ps-format-bar.active { border-color: var(--blue); background-image: linear-gradient(var(--blue-soft), var(--blue-soft)); }
  .ps-format-count { font-size: 12px; color: var(--text-muted); line-height: 1.35; }
  .ps-format-bar.active .ps-format-count { font-weight: 600; color: var(--blue-light); }
  .ps-format-spacer { flex: 0 0 auto; height: 1px; background: var(--border); margin: 2px 0; }
  .ps-format-tail { display: flex; gap: 7px; }
  .ps-format-tail .ps-tool-btn.danger { flex: 1 1 auto; }
  .ps-tool-btn {
    padding: 7px 12px; border-radius: 7px; border: 1px solid var(--border-strong);
    background: var(--panel); color: var(--text); font-size: 12.5px; font-weight: 600; cursor: pointer;
    flex: 0 0 auto; white-space: nowrap;
  }
  .ps-tool-btn:hover:not(:disabled) { background: var(--row-hover); border-color: var(--blue); }
  .ps-tool-btn:disabled { opacity: .38; cursor: not-allowed; }
  .ps-tool-btn.danger { color: var(--red); border-color: var(--red); }
  .ps-tool-btn.danger:hover { background: rgba(239,68,68,.12); }

  /* the grid — photo (review only) | grid | breaker rail, as one flex row.
     The grid column caps at the table's 700px; the rail hugs its right edge. */
  .ps-split { display: flex; gap: 16px; align-items: flex-start; }
  .ps-grid-wrap { flex: 0 1 700px; min-width: 0; }
  .ps-photo-panel { flex: 0 1 380px; min-width: 260px; background: var(--panel-3); border: 1px solid var(--border); border-radius: 8px; padding: 10px; position: sticky; top: 10px; }
  @media (max-width: 900px) {
    .ps-split { flex-direction: column; align-items: stretch; }
    .ps-grid-wrap, .ps-photo-panel { flex: none; }
    /* rail → horizontal bar pinned above the grid while you scroll */
    .ps-format-bar-slot { order: -1; width: auto; flex: none; top: 0; }
    .ps-format-bar { flex-direction: row; flex-wrap: nowrap; overflow-x: auto; align-items: center; gap: 8px; }
    .ps-format-count { flex: 0 0 auto; max-width: 150px; }
    .ps-format-spacer { flex: 1 1 auto; height: auto; background: none; margin: 0; }
    .ps-format-tail { flex: 0 0 auto; }
  }
  .ps-photo-block + .ps-photo-block { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
  .ps-review-photo { width: 100%; border-radius: 6px; cursor: zoom-in; display: block; margin-top: 6px; }
  .ps-review-photo.zoomed { position: fixed; inset: 0; z-index: 60; width: 100vw; height: 100vh; object-fit: contain; background: rgba(0,0,0,.92); cursor: zoom-out; border-radius: 0; margin: 0; }
  .ps-grid-wrap { overflow-x: auto; }
  /* Fixed layout so column widths stay put as cells get formatted / typed
     into — otherwise the table reflows and the whole grid jumps around.
     Taller rows give room to type. */
  .ps-grid { border-collapse: collapse; width: 100%; max-width: 700px; table-layout: fixed; }
  .ps-grid td { border: 1px solid var(--border); height: 50px; }
  .ps-slotnum {
    width: 34px; text-align: center; font-size: 12px; font-weight: 700;
    color: var(--text-muted); background: var(--panel-3); user-select: none;
  }
  .ps-cell { padding: 3px 8px; position: relative; vertical-align: middle; }
  .ps-cell.empty {
    text-align: center; color: var(--text-faint); cursor: pointer; background: var(--panel-3);
  }
  .ps-cell.empty:hover { background: var(--row-hover); color: var(--blue-light); }
  .ps-empty-hint { font-size: 15px; opacity: .5; }
  .ps-selmark { color: var(--blue-bright); font-weight: 700; }
  /* Formatted = a placed breaker. Solid, dark 2px outline so each breaker reads
     as one rigid unit — distinct from the faint dashed lines that split a
     tandem/quad inside it. (2px also wins the border-collapse over empty cells.) */
  .ps-cell.formatted { background: var(--panel-2); cursor: pointer; text-align: center; }
  .ps-grid td.ps-cell.formatted { border: 2px solid var(--text-muted); }
  .ps-cell.selected { background: var(--blue-soft) !important; box-shadow: inset 0 0 0 2px var(--blue); }
  .ps-cell.editing-cell { box-shadow: inset 0 0 0 2px var(--blue); } /* Excel-style active cell */
  .ps-cell.flagged { background: rgba(245,158,11,.14); }
  /* Labels: flat text, no bubble. A plain span until you double-click it — then
     it takes a caret and the cell shows the blue active outline above. No
     placeholder text; the borders + dividing lines show the breaker layout. */
  .ps-label-text {
    display: block; width: 100%; min-height: 20px; outline: none; text-align: center;
    font-size: 12.5px; color: var(--text); cursor: default; padding: 2px 4px; box-sizing: border-box;
  }
  .ps-label-text.editing { cursor: text; }
  /* Tandem/quad split one breaker into 2 or 3 stacked circuits — faint DASHED
     dividers so they read as "inside one breaker" vs the solid full-breaker border. */
  .ps-cell-stack { display: flex; flex-direction: column; align-items: stretch; }
  .ps-cell-stack .ps-label-text { border-top: 1px dashed var(--border-strong); }
  .ps-cell-stack .ps-label-text:first-child { border-top: none; }
  /* Right bank: only the flag badge shifts left so it clears the centered text. */
  .ps-cell.formatted.ps-col-d .ps-cell-badges { right: auto; left: 3px; }
  .ps-cell-badges { position: absolute; top: 2px; right: 3px; display: inline-flex; gap: 2px; }
  .ps-badge {
    font-size: 9px; font-weight: 700; padding: 1px 4px; border-radius: 4px; line-height: 1.3;
    background: var(--panel-3); color: var(--text-muted);
  }
  .ps-badge.pole { background: var(--blue-soft); color: var(--blue-light); }
  .ps-badge.flag { background: rgba(245,158,11,.2); color: var(--amber); cursor: pointer; }

  /* output actions */
  .ps-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

  /* pending review inbox */
  .ps-pending-card { border-color: var(--blue); }
  .ps-count-pill {
    font-size: 11px; font-weight: 700; padding: 1px 8px; border-radius: 100px;
    background: var(--blue-soft); color: var(--blue-light);
  }
  .ps-pending-row {
    display: flex; align-items: center; gap: 12px; padding: 11px 13px; margin-top: 8px;
    background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;
  }
  .ps-pending-row:hover { background: var(--row-hover); border-color: var(--blue); }
  .ps-pending-main { flex: 1 1 auto; min-width: 0; }
  .ps-pending-job { font-weight: 600; color: var(--text-strong); font-size: 13.5px; }
  .ps-pending-sub { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
  .ps-chip { flex: 0 0 auto; font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 100px; white-space: nowrap; border: none; cursor: default; }
  .ps-chip.flags { background: rgba(245,158,11,.16); color: var(--amber); cursor: pointer; }
  .ps-chip.photo { background: var(--panel-3); color: var(--text-muted); font-weight: 400; }

  /* review bar */
  .ps-review-bar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }

  /* token prompt */
  .ps-token-card { border-color: var(--amber, #f59e0b); }
  .ps-token-row { display: flex; gap: 8px; margin-top: 10px; }
  .ps-token-row input { flex: 1 1 auto; }

  /* status lines + spinner */
  .ps-status { margin-top: 10px; padding: 9px 12px; border-radius: 8px; font-size: 12.5px; line-height: 1.45; }
  .ps-status.info { background: var(--panel-2); color: var(--text); }
  .ps-status.success { background: rgba(74,222,128,.12); color: var(--green-text); }
  .ps-status.warning { background: rgba(245,158,11,.12); color: var(--amber); }
  .ps-status.error { background: rgba(239,68,68,.12); color: var(--red-text); }
  .ps-spinner {
    display: inline-block; width: 12px; height: 12px; margin-right: 6px; vertical-align: -1px;
    border: 2px solid var(--border-strong); border-top-color: var(--blue-bright);
    border-radius: 50%; animation: ps-spin .7s linear infinite;
  }
  @keyframes ps-spin { to { transform: rotate(360deg); } }

  /* Fleet Watch — surfaces vehicles overdue for oil change or within 300km
     of due. Green when within-300km/days; red when overdue. */
  /* Fleet Watch chip — yellow when any vehicle is "soon" (within 300 km /
     30 days of due), red when any is overdue. The chip only renders when
     there's at least one such vehicle, so green/default never shows. */
  .today-fleet-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    font-size: 12.5px; min-width: 0;
    /* Yellow base — the watch only fires when something needs attention */
    background: rgba(250, 204, 21, 0.08);
    border: 1px solid rgba(250, 204, 21, 0.32);
  }
  .today-fleet-bar-soon {
    background: rgba(250, 204, 21, 0.08);
    border-color: rgba(250, 204, 21, 0.32);
  }
  .today-fleet-bar-overdue {
    background: rgba(248, 113, 113, 0.08);
    border-color: rgba(248, 113, 113, 0.32);
  }
  .today-fleet-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #facc15;
    box-shadow: 0 0 0 3px rgba(250, 204, 21, 0.18);
  }
  .today-fleet-bar-overdue .today-fleet-dot {
    background: #f87171;
    box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.18);
  }
  .today-fleet-label {
    color: var(--amber-bright); font-weight: 600; flex: 0 0 auto;
  }
  .today-fleet-bar-overdue .today-fleet-label { color: var(--red-bright); }
  .today-fleet-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(250, 204, 21, 0.22); color: var(--amber-bright);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-fleet-bar-overdue .today-fleet-count {
    background: rgba(248, 113, 113, 0.22); color: var(--red-bright);
  }
  .today-fleet-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .fleet-watch-name {
    cursor: pointer;
    color: var(--amber-bright); border-bottom: 1px dotted rgba(250, 204, 21, 0.4);
  }
  /* 2026-05-25 — per-vehicle status coloring so only the truly overdue
     vehicle reads red; "soon" vehicles stay yellow. Replaces the old
     bar-level .today-fleet-bar-overdue .fleet-watch-name override that
     painted every name red as soon as ONE was overdue. */
  .fleet-watch-name-soon {
    color: var(--amber-bright); border-bottom-color: rgba(250, 204, 21, 0.4);
  }
  .fleet-watch-name-overdue {
    color: var(--red-bright); border-bottom-color: rgba(248, 113, 113, 0.4);
  }
  .fleet-watch-name:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }

  /* Today "Time entries" watch — unfinished crew days (still clocked in
     or unapproved). Mirrors the fleet watch visual language: amber base,
     red when someone is still clocked in. 2026-06-21. */
  .today-time-entries-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    font-size: 12.5px; min-width: 0;
    background: rgba(250, 204, 21, 0.08);
    border: 1px solid rgba(250, 204, 21, 0.32);
  }
  .today-time-entries-bar-open {
    background: rgba(248, 113, 113, 0.08);
    border-color: rgba(248, 113, 113, 0.32);
  }
  .today-time-entries-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #facc15;
    box-shadow: 0 0 0 3px rgba(250, 204, 21, 0.18);
  }
  .today-time-entries-bar-open .today-time-entries-dot {
    background: #f87171;
    box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.18);
  }
  .today-time-entries-label { color: var(--amber-bright); font-weight: 600; flex: 0 0 auto; }
  .today-time-entries-bar-open .today-time-entries-label { color: var(--red-bright); }
  .today-time-entries-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(250, 204, 21, 0.22); color: var(--amber-bright);
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-time-entries-bar-open .today-time-entries-count {
    background: rgba(248, 113, 113, 0.22); color: var(--red-bright);
  }
  .today-time-entries-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .time-entries-watch-name {
    cursor: pointer;
    color: var(--amber-bright); border-bottom: 1px dotted rgba(250, 204, 21, 0.4);
  }
  .time-entries-watch-name-open {
    color: var(--red-bright); border-bottom-color: rgba(248, 113, 113, 0.4);
  }
  .time-entries-watch-name:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }

  /* Crew tab "Needs attention" panel — source surface for unfinished
     days; the Today "Time entries" watch mirrors this same list. 2026-06-21. */
  .crew-needs-attention {
    margin: 0 0 16px 0; padding: 12px 14px; border-radius: 10px;
    background: rgba(248, 113, 113, 0.06);
    border: 1px solid rgba(248, 113, 113, 0.28);
  }
  .crew-needs-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
  .crew-needs-dot {
    flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%;
    background: #f87171; box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.18);
  }
  .crew-needs-title { font-weight: 700; color: var(--text-strong); }
  .crew-needs-count {
    padding: 1px 8px; border-radius: 100px;
    background: rgba(248, 113, 113, 0.22); color: var(--red-bright);
    font-size: 11px; font-weight: 700;
  }
  .crew-needs-sub { color: var(--text-dim); font-size: 12px; margin-left: 4px; }
  .crew-needs-list { display: flex; flex-direction: column; gap: 6px; }
  .crew-needs-row {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px; border-radius: 8px;
    background: var(--panel, rgba(255,255,255,0.03));
    border: 1px solid var(--border, rgba(255,255,255,0.06));
  }
  .crew-needs-row:hover { border-color: rgba(248, 113, 113, 0.4); }
  .crew-needs-name { font-weight: 600; color: var(--text-strong); flex: 0 0 auto; }
  .crew-needs-date { color: var(--text); flex: 0 0 auto; }
  .crew-needs-job {
    color: var(--text-dim); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .crew-needs-hours { color: var(--text-dim); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
  .crew-needs-pill {
    flex: 0 0 auto; padding: 2px 8px; border-radius: 100px;
    font-size: 11px; font-weight: 700;
  }
  .crew-needs-pill-danger { background: rgba(239,68,68,0.15); color: var(--red, #ef4444); }
  .crew-needs-pill-amber  { background: rgba(184,134,11,0.15); color: var(--amber, #b8860b); }

  /* 2026-06-17 — Crew today: yellow wash on "Done today" rows removed
     (per Matt). The neutral slate clock-in chips + green approved check
     + blue Done badge now carry the finished signal, so the row stays
     plain. One less color per row — calmer at a glance. */
  .today-crew-row-done {
    background: transparent;
  }

  /* ── Job Costing tab ─────────────────────────────────────────────────── */
  .job-costing-page { display: flex; flex-direction: column; gap: 12px; }
  .jc-header {
    display: flex; justify-content: space-between; align-items: flex-end;
    gap: 16px; flex-wrap: wrap;
  }
  .jc-sub-tabs { display: flex; gap: 6px; }
  .jc-sub-tab {
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px;
    padding: 8px 14px; font-size: 12.5px; font-weight: 500;
    color: var(--text-soft); cursor: pointer; font-family: inherit;
    display: inline-flex; align-items: center; gap: 8px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .jc-sub-tab:hover { background: var(--border-subtle); color: var(--text); }
  .jc-sub-tab.active {
    background: rgba(59,130,246,0.14); color: var(--text-strong);
    border-color: rgba(59,130,246,0.40);
  }
  .jc-count {
    display: inline-block; min-width: 22px; padding: 2px 7px;
    background: rgba(148,163,184,0.18); border-radius: 999px;
    font-size: 11px; font-weight: 600; text-align: center;
  }
  .jc-sub-tab.active .jc-count {
    background: rgba(59,130,246,0.30); color: var(--blue-lightest);
  }
  .jc-meta { color: var(--text-muted); font-size: 12px; }

  .jc-table-wrap {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    overflow: hidden;
  }
  .jc-loading, .jc-empty, .jc-error {
    padding: 30px 24px; color: var(--text-soft); font-size: 13px; text-align: center;
  }
  .jc-error { color: var(--red-text); }
  .jc-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .jc-table thead th {
    background: var(--panel-2); color: var(--text-soft); font-weight: 600; font-size: 11.5px;
    text-transform: uppercase; letter-spacing: 0.04em;
    text-align: left; padding: 12px 14px;
    border-bottom: 1px solid var(--border); cursor: pointer;
    user-select: none; transition: color 0.15s, background 0.15s;
  }
  .jc-table thead th:hover { color: var(--text); background: var(--panel-2); }
  .jc-table thead th.num { text-align: right; }
  .jc-table tbody td {
    padding: 11px 14px; color: var(--text); border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
  }
  .jc-table tbody tr:last-child td { border-bottom: none; }
  .jc-table tbody tr:hover { background: rgba(59,130,246,0.04); }
  .jc-table tbody td.num {
    text-align: right; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; font-size: 12.5px;
  }
  /* Client column gets the same emphasis as Invoices / Quotes
     (qbo-col-customer) so the eye lands on who-it's-for fast. */
  .jc-table tbody td.jc-col-client { color: var(--text); font-weight: 600; }
  .jc-pos { color: var(--green-soft); font-weight: 500; }
  .jc-neg { color: var(--red-text); font-weight: 500; }

  /* Status badges in Job Costing */
  .jc-badge {
    display: inline-block; padding: 3px 9px; border-radius: 999px;
    font-size: 11px; font-weight: 600; line-height: 1.4;
    border: 1px solid transparent; white-space: nowrap;
  }
  .jc-badge-tm {
    background: rgba(148,163,184,0.14); color: var(--text);
    border-color: rgba(148,163,184,0.25);
  }
  .jc-badge-on-track {
    background: rgba(16,185,129,0.14); color: var(--green-soft);
    border-color: rgba(16,185,129,0.30);
  }
  .jc-badge-tight {
    background: rgba(234,179,8,0.14); color: var(--amber-text);
    border-color: rgba(234,179,8,0.30);
  }
  .jc-badge-over {
    background: rgba(220,38,38,0.14); color: var(--red-text);
    border-color: rgba(220,38,38,0.35);
  }

  /* Mark-closed / Reopen button — small ghost beside the status badge.
     Stays muted until row hover so the badge keeps the eye. Shipped
     2026-05-16 when Job Costing got proper closed-state derivation. */
  .jc-status-cell {
    display: flex; align-items: center; gap: 8px;
    white-space: nowrap;
  }
  .jc-close-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    padding: 3px 9px;
    border-radius: 6px;
    font-size: 11px; font-weight: 500;
    cursor: pointer;
    opacity: 0.55;
    transition: opacity 120ms ease, color 120ms ease, border-color 120ms ease;
  }
  .jc-row:hover .jc-close-btn { opacity: 1; }
  .jc-close-btn:hover {
    color: var(--text);
    border-color: var(--border-strong, var(--text-muted));
  }

  /* Clickable rows + Quote-cell controls */
  .jc-table tbody tr.jc-row { cursor: pointer; }
  .jc-est-link {
    color: var(--blue-lightest); text-decoration: none;
    font-weight: 500; font-family: inherit;
    border-bottom: 1px dotted rgba(147, 197, 253, 0.45);
  }
  .jc-est-link:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }
  .jc-est-pick {
    background: transparent; border: 1px dashed rgba(148, 163, 184, 0.40);
    color: var(--text-muted); border-radius: 6px; padding: 2px 9px;
    font-size: 12px; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    cursor: pointer; transition: background 0.15s, color 0.15s, border-color 0.15s;
  }
  .jc-est-pick:hover {
    background: rgba(59, 130, 246, 0.10); color: var(--text);
    border-color: rgba(59, 130, 246, 0.45); border-style: solid;
  }

  /* QBO-estimate picker popover */
  .jc-est-popover {
    position: absolute; z-index: 10000;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 10px; box-shadow: 0 14px 40px rgba(0, 0, 0, 0.45);
    padding: 10px; max-height: 480px; display: flex; flex-direction: column;
  }
  .jc-est-popover-header {
    display: flex; gap: 6px; align-items: center; margin-bottom: 6px;
  }
  .jc-est-search {
    flex: 1; background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 6px;
    padding: 6px 9px; font-size: 13px; font-family: inherit;
  }
  .jc-est-search:focus { outline: none; border-color: rgba(59,130,246,0.55); }
  .jc-est-close {
    background: transparent; border: none; color: var(--text-muted);
    font-size: 18px; cursor: pointer; padding: 2px 6px; line-height: 1;
  }
  .jc-est-close:hover { color: var(--text-strong); }
  .jc-est-popover-hint {
    color: var(--text-muted); font-size: 11.5px; padding: 0 2px 6px;
    border-bottom: 1px solid var(--border-subtle); margin-bottom: 4px;
  }
  .jc-est-popover-hint b { color: var(--text); font-weight: 600; }
  .jc-est-list { overflow-y: auto; flex: 1 1 auto; min-height: 0; }
  .jc-est-empty {
    color: var(--text-muted); font-size: 12.5px; padding: 18px 8px; text-align: center;
  }
  .jc-est-row {
    padding: 8px 10px; border-radius: 6px; cursor: pointer;
    border: 1px solid transparent; margin-bottom: 2px;
    transition: background 0.12s, border-color 0.12s;
  }
  .jc-est-row:hover {
    background: rgba(59,130,246,0.10); border-color: rgba(59,130,246,0.30);
  }
  .jc-est-row-recommended {
    background: rgba(16,185,129,0.06);
    border-color: rgba(16,185,129,0.18);
  }
  .jc-est-row-recommended:hover {
    background: rgba(16,185,129,0.14); border-color: rgba(16,185,129,0.35);
  }
  .jc-est-row-top {
    display: flex; justify-content: space-between; gap: 12px; align-items: baseline;
  }
  .jc-est-row-cust {
    color: var(--text-strong); font-weight: 600; font-size: 13px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .jc-est-row-total {
    color: var(--text); font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 12.5px; font-variant-numeric: tabular-nums;
  }
  .jc-est-row-mid {
    display: flex; gap: 10px; align-items: center;
    color: var(--text-muted); font-size: 11.5px; margin-top: 2px;
  }
  .jc-est-row-doc { font-family: ui-monospace, "SF Mono", Consolas, monospace; }
  .jc-est-status {
    padding: 1px 7px; border-radius: 999px; font-size: 10.5px; font-weight: 600;
    background: rgba(148,163,184,0.18); color: var(--text);
  }
  .jc-est-status-acc {
    background: rgba(16,185,129,0.18); color: var(--green-soft);
  }
  .jc-est-row-job, .jc-est-row-addr {
    color: var(--text-soft); font-size: 11.5px; margin-top: 2px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .jc-est-section-head {
    color: var(--text-muted); font-size: 10.5px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
    padding: 8px 4px 4px; margin-top: 2px;
  }
  .jc-est-section-head-all { border-top: 1px solid var(--border-subtle); margin-top: 6px; }

  /* Manual-quote entry inside the picker */
  .jc-est-manual-row {
    display: flex; gap: 10px; align-items: center;
    padding: 8px 10px; margin-bottom: 6px;
    background: rgba(59,130,246,0.06); border: 1px solid rgba(59,130,246,0.20);
    border-radius: 6px; cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
  }
  .jc-est-manual-row:hover {
    background: rgba(59,130,246,0.14); border-color: rgba(59,130,246,0.45);
  }
  .jc-est-manual-icon {
    font-size: 18px; color: var(--blue-lightest); font-weight: 600;
    width: 22px; text-align: center;
  }
  .jc-est-manual-title {
    color: var(--text-strong); font-weight: 600; font-size: 13px;
  }
  .jc-est-manual-sub {
    color: var(--text-muted); font-size: 11px; margin-top: 2px;
  }
  .jc-est-manual-form {
    display: flex; flex-direction: column; gap: 8px; padding: 10px;
    background: var(--panel-2); border: 1px solid var(--border);
    border-radius: 6px; margin-bottom: 8px;
  }
  .jc-est-manual-form label {
    display: flex; flex-direction: column; gap: 3px;
    color: var(--text-soft); font-size: 11.5px; font-weight: 600;
  }
  .jc-est-manual-form input {
    background: var(--panel); color: var(--text);
    border: 1px solid var(--border); border-radius: 5px;
    padding: 5px 8px; font-size: 13px; font-family: inherit;
  }
  .jc-est-manual-form input:focus {
    outline: none; border-color: rgba(59,130,246,0.55);
  }
  .jc-est-manual-total-row { display: flex; gap: 6px; align-items: stretch; }
  .jc-est-manual-total-row > input { flex: 1; }
  .jc-est-manual-pdf-btn {
    display: inline-flex; align-items: center; padding: 5px 10px;
    border: 1px dashed rgba(148,163,184,0.45); border-radius: 5px;
    cursor: pointer; color: var(--text-soft); font-size: 12px;
    background: transparent; flex-direction: row !important;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
  }
  .jc-est-manual-pdf-btn:hover {
    background: rgba(59,130,246,0.10); color: var(--text);
    border-color: rgba(59,130,246,0.45); border-style: solid;
  }
  .jc-est-manual-pdf-status {
    font-size: 11px; color: var(--text-muted); min-height: 14px;
    font-family: inherit !important; font-weight: 400 !important;
    text-transform: none !important; letter-spacing: 0 !important;
  }
  .jc-pdf-busy { color: var(--text-soft); }
  .jc-pdf-ok   { color: var(--green-soft); }
  .jc-pdf-warn { color: var(--amber-text); }
  .jc-est-manual-actions { display: flex; gap: 6px; justify-content: flex-end; }
  .jc-est-manual-cancel, .jc-est-manual-save {
    padding: 5px 12px; border-radius: 5px; font-size: 12px;
    cursor: pointer; font-family: inherit;
  }
  .jc-est-manual-cancel {
    background: transparent; border: 1px solid var(--border); color: var(--text-soft);
  }
  .jc-est-manual-cancel:hover { color: var(--text); }
  .jc-est-manual-save {
    background: rgba(59,130,246,0.20); color: var(--blue-lightest);
    border: 1px solid rgba(59,130,246,0.45);
  }
  .jc-est-manual-save:hover {
    background: rgba(59,130,246,0.30); color: var(--text-strong);
  }

  /* Manual-quote chip in the Quote column + detail header */
  .jc-est-manual {
    background: rgba(234,179,8,0.10); border: 1px solid rgba(234,179,8,0.30);
    color: var(--text); border-radius: 6px;
    padding: 2px 9px; font-size: 12px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
    font-variant-numeric: tabular-nums;
  }
  .jc-est-manual:hover {
    background: rgba(234,179,8,0.20); border-color: rgba(234,179,8,0.55);
  }
  .jc-est-manual-tag {
    font-size: 9.5px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.04em; color: var(--amber-text);
    padding: 1px 5px; border-radius: 4px;
    background: rgba(234,179,8,0.18);
  }
  .jc-detail-qbo-manual {
    background: rgba(234,179,8,0.06);
    border-color: rgba(234,179,8,0.30);
  }
  .jc-detail-qbo-manual-meta {
    color: var(--text); font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: 12px;
  }

  /* Job Costing detail modal — outer .modal.jc-detail-modal acts as the
     fullscreen overlay, .jc-detail-card is the centered popup. The plain
     .modal class higher in this file styles a 560px card; we reset those
     here so the outer wrapper becomes a true overlay instead of an inline
     panel that lays out at the bottom of the document. */
  .jc-detail-modal {
    position: fixed; inset: 0;
    display: flex; align-items: flex-start; justify-content: center;
    background: rgba(0, 0, 0, 0.6);
    z-index: 1000;
    padding: 4vh 24px 24px;
    overflow-y: auto;
    /* Cancel inherited .modal card styles */
    border: none;
    border-radius: 0;
    max-width: none;
    width: auto;
    max-height: none;
    box-shadow: none;
  }
  .jc-detail-modal .jc-detail-card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.7);
    padding: 22px;
    max-width: 980px; width: 92vw;
    max-height: 92vh;
    overflow-y: auto;
  }
  .jc-detail-card .modal-header { align-items: flex-start; }
  .jc-detail-card .modal-header h3 { margin: 0; }
  /* Light-theme overlay tint */
  [data-theme="light"] .jc-detail-modal {
    background: rgba(15, 23, 42, 0.45);
  }
  .jc-detail-customer { color: var(--text-soft); font-weight: 400; }
  .jc-detail-addr {
    color: var(--text-muted); font-size: 12.5px; margin-top: 4px;
  }
  .jc-detail-body { display: flex; flex-direction: column; gap: 14px; }
  .jc-detail-qbo {
    display: flex; align-items: center; gap: 12px;
    background: var(--panel-2); border: 1px solid var(--border);
    border-radius: 8px; padding: 8px 12px; font-size: 12.5px;
  }
  .jc-detail-qbo-empty { color: var(--text-muted); }
  .jc-detail-qbo-label { color: var(--text-soft); font-weight: 600; }
  .jc-detail-qbo-link {
    color: var(--blue-lightest); text-decoration: none; font-weight: 500;
    margin-left: auto;
  }
  .jc-detail-qbo-link:hover { text-decoration: underline; }
  .jc-detail-qbo-pick, .jc-detail-qbo-unlink {
    background: transparent; border: 1px solid var(--border);
    color: var(--text-soft); border-radius: 6px; padding: 4px 10px;
    font-size: 11.5px; cursor: pointer; font-family: inherit;
  }
  .jc-detail-qbo-pick:hover, .jc-detail-qbo-unlink:hover {
    color: var(--text); border-color: rgba(59,130,246,0.45);
  }
  .jc-detail-qbo-pick { margin-left: auto; }

  .jc-detail-summary {
    display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px;
  }
  .jc-summary-cell {
    background: var(--panel-2); border: 1px solid var(--border);
    border-radius: 8px; padding: 10px 12px;
  }
  .jc-summary-k {
    color: var(--text-muted); font-size: 11px; text-transform: uppercase;
    letter-spacing: 0.04em; font-weight: 600; margin-bottom: 4px;
  }
  .jc-summary-v {
    color: var(--text-strong); font-size: 16px; font-weight: 600;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums;
  }

  /* Estimating accuracy panel — Job Costing tab roll-up above the table. */
  .jc-acc {
    background: var(--panel-2); border: 1px solid var(--border);
    border-radius: 10px; padding: 12px 14px; margin-bottom: 14px;
  }
  .jc-acc-head {
    color: var(--text-soft); font-size: 12px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 10px;
  }
  .jc-acc-sub {
    text-transform: none; letter-spacing: 0; font-weight: 500;
    color: var(--text-muted); margin-left: 8px;
  }
  .jc-acc-tiles {
    display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
  }
  .jc-acc-tiles .jc-summary-cell { background: var(--panel); }
  .jc-acc-note {
    color: var(--text-muted); font-size: 11px; margin-top: 4px;
  }
  .jc-acc-excl {
    margin-top: 10px; padding-top: 10px;
    border-top: 1px solid var(--border-subtle);
    color: var(--text-muted); font-size: 12px; line-height: 1.5;
  }
  .jc-acc-excl strong { color: var(--red-text); }
  .jc-acc-excl ul { margin: 6px 0 0; padding-left: 18px; }
  .jc-acc-excl li { margin-bottom: 2px; }
  .jc-acc-era {
    margin-top: 8px; padding-top: 8px;
    border-top: 1px solid var(--border-subtle);
    color: var(--text-muted); font-size: 11.5px;
  }
  .jc-untrusted { color: var(--text-muted); }

  @media (max-width: 900px) {
    .jc-acc-tiles { grid-template-columns: repeat(2, 1fr); }
  }

  .jc-detail-section {
    color: var(--text-soft); font-size: 12px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
    margin: 6px 0 -4px; padding-bottom: 4px;
    border-bottom: 1px solid var(--border-subtle);
  }
  .jc-detail-table {
    width: 100%; border-collapse: collapse; font-size: 12.5px;
  }
  .jc-detail-table thead th {
    background: var(--panel-2); color: var(--text-soft); font-weight: 600;
    font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.04em;
    text-align: left; padding: 7px 10px;
    border-bottom: 1px solid var(--border);
  }
  .jc-detail-table thead th.num { text-align: right; }
  .jc-detail-table tbody td {
    padding: 7px 10px; color: var(--text);
    border-bottom: 1px solid var(--border-subtle);
  }
  .jc-detail-table tbody td.num {
    text-align: right; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; font-size: 12px;
  }
  .jc-detail-table tbody tr.jc-detail-total td {
    font-weight: 600; color: var(--text-strong);
    background: rgba(59,130,246,0.04);
    border-top: 1px solid var(--border);
    border-bottom: none;
  }
  .jc-detail-table tbody tr.jc-credit td { color: var(--text-soft); font-style: italic; }
  .jc-credit-tag {
    background: rgba(234,179,8,0.18); color: var(--amber-text);
    padding: 1px 6px; border-radius: 999px; font-size: 10px;
    font-weight: 600; margin-left: 4px; font-style: normal;
  }
  .jc-dim { color: var(--text-muted); }
  .jc-note {
    color: var(--text-soft); max-width: 320px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .jc-empty-mini {
    padding: 12px; color: var(--text-muted); font-size: 12px;
    text-align: center; background: var(--panel-2);
    border-radius: 6px; border: 1px dashed var(--border);
  }
  .jc-role {
    display: inline-block; min-width: 18px; padding: 1px 6px;
    border-radius: 4px; font-size: 10.5px; font-weight: 600;
    text-align: center; line-height: 1.4;
  }
  .jc-role-j { background: rgba(59,130,246,0.18); color: var(--blue-lightest); }
  .jc-role-a { background: rgba(16,185,129,0.16); color: var(--green-soft); }
  .jc-role-q { background: rgba(148,163,184,0.18); color: var(--text-soft); }

  /* ── Project Budgeting tab ───────────────────────────────────────────── */
  .project-budgeting-page { display: flex; flex-direction: column; gap: 14px; }
  .pb-header {
    display: flex; justify-content: space-between; align-items: flex-end;
    gap: 24px; flex-wrap: wrap;
  }
  .pb-intro { flex: 1 1 420px; }
  .pb-intro h3 {
    color: var(--text-strong); font-size: 17px; margin: 0 0 6px; font-weight: 600;
  }
  .pb-intro p { color: var(--text-soft); font-size: 13px; line-height: 1.55; margin: 0; }
  .pb-filter-block {
    display: flex; flex-direction: column; gap: 6px; flex: 0 0 auto;
  }
  .pb-filter-label {
    color: var(--text-muted); font-size: 11.5px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  /* Project Budgeting stage filter — visually unified with the new QBO
     Billing filter-select pattern (2026-05-18) so all tab-level filter
     dropdowns look the same. Wider min-width retained because stage names
     ("Quoted, awaiting acceptance") are longer than status names. */
  .pb-stage-filter {
    appearance: none; -webkit-appearance: none;
    background: var(--panel-3) url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3e%3cpath d='M1 1l4 4 4-4' stroke='%236f83a8' stroke-width='1.4' fill='none'/%3e%3c/svg%3e") no-repeat right 10px center;
    color: var(--text); border: 1px solid var(--border);
    border-radius: 6px; padding: 7px 30px 7px 12px; font-size: 13px;
    font-family: inherit; min-width: 240px; cursor: pointer;
    transition: border-color 100ms ease, box-shadow 100ms ease;
  }
  .pb-stage-filter:hover { border-color: var(--border-strong); }
  .pb-stage-filter:focus {
    outline: none; border-color: var(--blue);
    box-shadow: 0 0 0 3px rgba(59,130,246,0.15);
  }

  .pb-table-wrap {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    overflow: hidden;
  }
  .pb-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .pb-table thead th {
    background: var(--panel-2); color: var(--text-soft); font-weight: 600; font-size: 11.5px;
    text-transform: uppercase; letter-spacing: 0.04em;
    text-align: left; padding: 12px 14px;
    border-bottom: 1px solid var(--border); cursor: pointer;
    user-select: none; transition: color 0.15s, background 0.15s;
  }
  .pb-table thead th:hover { color: var(--text); background: var(--panel-2); }
  .pb-table thead th.num { text-align: right; }
  .pb-table tbody td {
    padding: 10px 14px; color: var(--text); border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
  }
  .pb-table tbody tr:last-child td { border-bottom: none; }
  .pb-table tbody tr:hover { background: rgba(59,130,246,0.04); }
  /* Client column emphasized like Invoices / Quotes / Job Costing. */
  .pb-table tbody td.pb-col-client { color: var(--text); font-weight: 600; }
  .pb-table tbody td.num {
    text-align: right; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; font-size: 12.5px;
  }

  .pb-link {
    color: var(--blue-light); text-decoration: none; font-weight: 500;
  }
  .pb-link:hover { color: var(--blue-lightest); text-decoration: underline; }

  .pb-stage-pill {
    display: inline-block; padding: 3px 9px; border-radius: 999px;
    font-size: 11px; font-weight: 600; line-height: 1.4;
    background: rgba(99,102,241,0.14); color: var(--indigo);
    border: 1px solid rgba(99,102,241,0.30); white-space: nowrap;
  }

  /* Editable budget input — sits inline in the table cell. */
  .pb-budget-input {
    width: 110px; max-width: 100%;
    background: var(--surface-deep); color: var(--text-strong);
    border: 1px solid var(--border); border-radius: 6px;
    padding: 6px 10px; font-size: 12.5px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums; text-align: right;
    transition: border-color 0.15s, background 0.15s;
  }
  .pb-budget-input::placeholder { color: var(--text-faint); }
  .pb-budget-input:hover {
    background: var(--panel-2); border-color: var(--border-strong);
  }
  .pb-budget-input:focus {
    outline: none; background: var(--panel);
    border-color: rgba(59,130,246,0.55);
  }
  /* Hide spinner arrows in number input — cleaner look. */
  .pb-budget-input::-webkit-outer-spin-button,
  .pb-budget-input::-webkit-inner-spin-button {
    -webkit-appearance: none; margin: 0;
  }
  .pb-budget-input { -moz-appearance: textfield; }

  .pb-billed-stub { color: var(--text-muted); }
  .pb-billed-loading {
    color: var(--text-muted); font-style: italic; opacity: 0.7;
  }
  .pb-inv-count {
    color: var(--text-muted); font-size: 11px; font-weight: 500;
    margin-left: 2px; cursor: help;
  }
  .pb-inv-count-zero { color: var(--amber); }
  .pb-pos { color: var(--green-soft); font-weight: 500; }
  .pb-warn { color: var(--amber-text); font-weight: 500; }
  .pb-neg { color: var(--red-text); font-weight: 500; }
  /* Over-budget row gets a subtle red tint to draw the eye. */
  .pb-row-over {
    background: rgba(220,38,38,0.05);
  }
  .pb-row-over:hover {
    background: rgba(220,38,38,0.10) !important;
  }

  /* Consumed bar — fills as billed approaches budget. Color is set inline
     by the renderer (green / amber / red) based on consumed %. */
  .pb-consumed-cell { min-width: 160px; }
  .pb-bar {
    position: relative; width: 100%; max-width: 200px;
    height: 18px; background: var(--surface-deep);
    border: 1px solid var(--border); border-radius: 999px; overflow: hidden;
  }
  .pb-bar-fill {
    position: absolute; left: 0; top: 0; bottom: 0;
    border-radius: 999px;
    transition: width 0.25s ease;
  }
  .pb-bar-text {
    position: absolute; inset: 0; display: flex;
    align-items: center; justify-content: center;
    font-size: 11px; font-weight: 600; color: var(--text-strong);
    text-shadow: 0 1px 1px rgba(0,0,0,0.55);
    font-variant-numeric: tabular-nums;
  }
  .pb-bar-empty {
    color: var(--text-muted); font-size: 12px; font-style: italic;
  }

  .pb-empty {
    padding: 30px 24px; color: var(--text-soft); font-size: 13px;
    text-align: center; line-height: 1.55;
  }

  .pb-footnote {
    color: var(--text-muted); font-size: 12px; line-height: 1.55;
    padding: 10px 14px; background: rgba(59,130,246,0.05);
    border: 1px solid rgba(59,130,246,0.15); border-radius: 8px;
  }
  .pb-footnote b { color: var(--blue-light); }
  .pb-footnote code {
    background: var(--surface-deep); padding: 1px 5px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 11.5px;
    color: var(--purple-soft);
  }

  /* ── Billing workflow tab ────────────────────────────────────────────── */
  .billing-workflow { display: flex; flex-direction: column; gap: 16px; }
  .billing-actions {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    padding: 16px 18px;
  }
  .billing-actions .button {
    background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
    padding: 9px 16px; border-radius: 8px; font-size: 13px; font-weight: 500;
    display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
    font-family: inherit;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .billing-actions .button:hover { background: var(--row-hover); color: var(--text-strong); border-color: var(--text-faint); }
  .billing-actions .button-primary {
    background: rgba(59,130,246,0.18); color: var(--blue-lightest); border-color: rgba(59,130,246,0.45);
  }
  .billing-actions .button-primary:hover { background: rgba(59,130,246,0.28); }
  .billing-actions .button-primary:disabled {
    opacity: 0.5; cursor: not-allowed; background: rgba(59,130,246,0.10);
  }
  .billing-actions .btn-icon { width: 14px; height: 14px; flex-shrink: 0; }
  .billing-action-hint { color: var(--text-soft); font-size: 12px; flex: 1 1 280px; }

  /* ── Roll-EOM modal ──────────────────────────────────────────────────── */
  .roll-eom-modal {
    position: fixed; inset: 0; background: rgba(0,0,0,0.65);
    display: flex; align-items: center; justify-content: center;
    z-index: 1000; padding: 20px;
  }
  .roll-eom-modal .modal-card {
    background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
    width: min(820px, 100%); max-height: 90vh; overflow: hidden;
    display: flex; flex-direction: column;
    box-shadow: 0 20px 50px rgba(0,0,0,0.6);
  }
  .roll-eom-modal .modal-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: 16px 20px; border-bottom: 1px solid var(--border);
  }
  .roll-eom-modal .modal-header h3 {
    margin: 0; font-size: 16px; color: var(--text-strong); font-weight: 600;
  }
  .roll-eom-modal .modal-close {
    background: transparent; color: var(--text-soft); border: none;
    font-size: 22px; cursor: pointer; padding: 0; line-height: 1; width: 28px; height: 28px;
  }
  .roll-eom-modal .modal-close:hover { color: var(--text-strong); }
  .roll-eom-modal .modal-body {
    padding: 18px 20px; overflow-y: auto; flex: 1 1 auto;
  }
  .roll-eom-modal .modal-footer {
    padding: 14px 20px; border-top: 1px solid var(--border);
    display: flex; justify-content: flex-end; gap: 10px; flex-shrink: 0;
  }
  .roll-eom-modal .modal-footer .button { /* reuse the billing-actions .button style */
    background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
    padding: 9px 16px; border-radius: 8px; font-size: 13px; font-weight: 500;
    cursor: pointer; font-family: inherit;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
  }
  .roll-eom-modal .modal-footer .button:hover { background: var(--row-hover); color: var(--text-strong); }
  .roll-eom-modal .modal-footer .button-primary {
    background: rgba(59,130,246,0.18); color: var(--blue-lightest); border-color: rgba(59,130,246,0.45);
  }
  .roll-eom-modal .modal-footer .button-primary:hover { background: rgba(59,130,246,0.28); }
  .roll-eom-modal .modal-footer .button:disabled { opacity: 0.5; cursor: not-allowed; }

  .roll-summary {
    color: var(--text); font-size: 13px; line-height: 1.6; margin: 0 0 14px;
  }
  .roll-table {
    width: 100%; border-collapse: collapse; font-size: 12.5px;
  }
  .roll-table thead th {
    background: var(--panel-2); color: var(--text-soft); text-align: left;
    padding: 8px 10px; font-size: 11px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
    border-bottom: 1px solid var(--border);
  }
  .roll-table thead th.num { text-align: right; }
  .roll-table tbody td {
    padding: 8px 10px; color: var(--text); border-bottom: 1px solid var(--border-subtle);
  }
  .roll-table tbody tr:last-child td { border-bottom: none; }
  .roll-table tbody td.num {
    text-align: right; font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-variant-numeric: tabular-nums;
  }
  .roll-row-status { color: var(--text-soft); font-size: 12px; }
  .roll-row-status.roll-ok { color: var(--green-soft); font-weight: 500; }
  .roll-row-status.roll-fail { color: var(--red-text); font-weight: 500; }

  /* ─────────────────────────────────────────────────────────────────────
     Light theme — flips every token. Toggled by setting
     <html data-theme="light"> from the sidebar sun/moon button (see
     js/04-actions.js → applyTheme).

     Most rules need NO updates because they use var(--token); only places
     that hardcode rgba(255,255,255,...) for "lighten" overlays or
     rgba(15,19,28,...) for "darken" overlays need their own light overrides
     below the :root block. Keep the override list short — if you find
     yourself adding many here, prefer adding a token instead.
     ───────────────────────────────────────────────────────────────────── */
  [data-theme="light"] {
    /* Surfaces — flat, neutral off-white (de-tinted 2026-07-04 to read calm
       like QBO — was slate/blue-tinted with a blue radial wash). Never pure
       white as page bg (halation); cards are white to lift off the bg. */
    --bg:               #f6f7f8;
    --bg-grad-end:      #f6f7f8;        /* = --bg so the page gradient is flat */
    --bg-grad-1:        transparent;    /* was a blue radial wash */
    --panel:            #ffffff;
    --panel-2:          #f4f5f6;
    --panel-3:          #edeef0;
    --surface-deep:     #e9eaec;
    --row-hover:        #f0f1f2;
    /* Neutral soft-hover (was blue-tinted). */
    --row-hover-soft:   rgba(17, 24, 39, 0.04);

    /* Borders — neutral gray so panels read as cards without a blue cast.
       Subtle stays light for nested separators. */
    --border:           #d7dadf;
    --border-strong:    #9aa1a9;
    --border-subtle:    #e6e8ea;

    /* Text — never pure black; slate-800 reads softer */
    --text:             #1e293b;
    --text-strong:      #0f172a;
    --text-soft:        #475569;
    --text-muted:       #64748b;
    --text-subtle:      #94a3b8;
    --text-faint:       #b8c2cf;

    /* Brand blue — slightly darker variants for better contrast on white */
    --blue:             #2563eb;
    --blue-hover:       #1d4ed8;
    --blue-bright:      #2563eb;
    --blue-light:       #1d4ed8;
    --blue-lighter:     #2563eb;
    --blue-lightest:    #1e40af;
    /* Slightly stronger blue-soft so the active nav state, page-icon
       chip, and empty-state-icon read clearly on white. Was 0.08 —
       under bright light those nearly disappeared. */
    --blue-soft:        rgba(37,99,235,0.12);
    --blue-overlay:     transparent;

    /* Accent text — darker variants so they read on white. The "bright"
       saturated ones stay similar (used as backgrounds). */
    --green:            #16a34a;
    --green-text:       #15803d;
    --green-soft:       #166534;

    --red:              #dc2626;
    --red-text:         #b91c1c;
    --red-bright:       #dc2626;

    --amber:            #d97706;
    --amber-text:       #b45309;
    --amber-bright:     #ca8a04;
    --orange:           #ea580c;

    --purple:           #7c3aed;
    --purple-soft:      #6d28d9;
    --indigo:           #4f46e5;
    --pink:             #db2777;
    --cyan:             #0891b2;
    --violet:           #7c3aed;

    /* Toast — light pastel bgs */
    --toast-error-bg:     #fef2f2;
    --toast-error-border: #fecaca;
    --toast-success-bg:     #f0fdf4;
    --toast-success-border: #bbf7d0;

    /* Card shadow softer in light mode (dark shadows on white can look
       harsh — use a lighter blur). Layered: a tight inner shadow that
       defines the card edge + a wider outer shadow that gives lift. */
    --shadow-card:   0 1px 2px rgba(15,23,42,0.04), 0 4px 14px rgba(15,23,42,0.06);
    --shadow-blue:   0 6px 18px rgba(37,99,235,0.18);
  }

  /* Nav-count badge in active state on light theme: the hardcoded dark-mode
     rgba (96,165,250,0.18) reads weakly on a light active background.
     Override to use blue-soft at slightly higher alpha so the badge has
     definition against the active state. */
  [data-theme="light"] .nav-item.active .nav-count {
    background: rgba(37,99,235,0.18);
    color: var(--blue);
  }

  /* Light-theme overrides for rules that hardcode rgba() with assumptions
     about bg darkness. These flip "lighten with white" to "darken with
     black" so the visual effect lands. Keep this list small. */

  /* Section toggle — inverted alpha overlays */
  [data-theme="light"] .section-block-toggle {
    background: rgba(15,23,42,0.04);
    border-color: rgba(15,23,42,0.08);
  }
  [data-theme="light"] .section-block-toggle:hover {
    background: rgba(15,23,42,0.10);
    border-color: rgba(15,23,42,0.18);
  }
  [data-theme="light"] .section-block:not(.collapsed) .section-block-toggle {
    background: rgba(15,23,42,0.08);
    border-color: rgba(15,23,42,0.14);
  }
  [data-theme="light"] .section-block-count,
  [data-theme="light"] details.category .cat-count,
  [data-theme="light"] .cat-row .label-count {
    background: rgba(15,23,42,0.04);
  }

  /* Hour lines on calendar — original used dark blue alpha (assumed dark bg).
     Switch to neutral darken in light mode. */
  [data-theme="light"] .cal-hour-line {
    border-top-color: rgba(15,23,42,0.10);
  }
  [data-theme="light"] .cal-half-hour-line {
    border-top-color: rgba(15,23,42,0.06);
  }

  /* Calendar past-time shade — flips to a soft gray, not a darken */
  [data-theme="light"] .cal-past-shade {
    background: rgba(148,163,184,0.18);
  }

  /* Weekend shading — was a darken; in light mode that's "less white",
     basically gray. Use an explicit gray instead of alpha-darken. */
  [data-theme="light"] .cal-day-col.cal-day-weekend {
    background: rgba(15,23,42,0.03);
  }

  /* Calendar legend bg */
  [data-theme="light"] .cal-legend {
    background: rgba(15,23,42,0.03);
    border-color: rgba(15,23,42,0.08);
  }

  /* Toast action button — was lightening with white. Now darken. */
  [data-theme="light"] .toast-action {
    background: rgba(15,23,42,0.06);
    border-color: rgba(15,23,42,0.14);
  }
  [data-theme="light"] .toast-action:hover { background: rgba(15,23,42,0.14); }

  /* nav-item.active — blue bg with white text; nav-count was a translucent
     white badge. In light mode, the same blue bg still works with white text
     but the badge needs more opacity to read on saturated blue. */
  [data-theme="light"] .nav-item.active .nav-count {
    background: rgba(255,255,255,0.32);
  }
  /* Light-theme hover on nav items: subtle slate tint with a 1px ring so it
     is visually subordinate to the saturated-blue active state. */
  /* Light theme carries its own .nav-item:hover ~6000 lines from the dark
     one, so wrapping only the dark rule left the iPad two-tap alive in light
     mode. Same (hover: hover) gate — see the note at the dark rule. */
  @media (hover: hover) {
    [data-theme="light"] .nav-item:hover {
      background: rgba(15, 23, 42, 0.05);
      box-shadow: inset 0 0 0 1px rgba(15, 23, 42, 0.08);
    }
    /* 2026-08-14 — UNLIKE the dark theme, where .nav-item.active:hover is
       grouped with .nav-item.active and renders identically, light theme
       overrides the background to saturated var(--blue) on its own and never
       restates color. The base active rule leaves color: var(--blue-bright),
       so this painted blue-on-blue and the label became unreadable. A mouse
       flashes past it; iOS keeps the hover latched after a tap, so on the
       iPad it just sat there illegible on whatever tab you last opened.
       Two fixes: gate it so touch never applies it at all, and give it the
       white label the comment above always claimed it had. */
    [data-theme="light"] .nav-item.active:hover {
      background: var(--blue);
      box-shadow: var(--shadow-blue);
      color: #fff;
    }
    [data-theme="light"] .nav-item.active:hover .nav-count {
      background: rgba(255,255,255,0.32);
    }
  }

  /* Reports zebra striping — flip from white-tint to slate-tint */
  [data-theme="light"] .rpt-table tbody tr.rpt-data:nth-child(even) td {
    background: rgba(15,23,42,0.022);
  }
  [data-theme="light"] .rpt-table tbody tr:hover td {
    background: rgba(15,23,42,0.05);
  }

  /* Pipeline tile open dropdown — was rgba(255,255,255,0.06) lighten */
  [data-theme="light"] .action-group.is-open .action-btn-chevron {
    background: rgba(15,23,42,0.06);
  }

  /* Color-cycle button border — was white-translucent on dark; needs
     darker outline on light to be visible. */
  [data-theme="light"] .cal-event-color-cycle {
    border-color: rgba(15,23,42,0.35);
    box-shadow: 0 0 0 1px rgba(15,23,42,0.20), inset 0 0 0 1px rgba(15,23,42,0.08);
  }
  [data-theme="light"] .cal-event-color-cycle:hover {
    box-shadow: 0 0 0 2px rgba(15,23,42,0.55), inset 0 0 0 1px rgba(15,23,42,0.15);
  }

  /* Calendar event tile — uses color-mix(...,var(--panel)) which flips
     automatically when --panel becomes white. The text color was hardcoded
     to lighten the event color with white; in light mode we want darken. */
  [data-theme="light"] .cal-event-time {
    color: color-mix(in srgb, var(--ev-color) 85%, black);
  }

  /* Pipeline empty-state dashed border in light mode looks washed out;
     bump alpha. */
  [data-theme="light"] .empty-state {
    border-color: var(--border);
  }

  /* Modal overlay — use lighter scrim in light mode so it doesn't feel
     like the page is dimming to black. */
  [data-theme="light"] .modal-overlay,
  [data-theme="light"] .roll-eom-modal {
    background: rgba(15,23,42,0.40);
  }

  /* Theme toggle button (sidebar) — see .theme-toggle styles below */

  /* ─── Tool Inventory tab (2026-05-12) ─────────────────────────────────
     Shipped by master CRM chat — render module 10-tool-inventory.js.
     Mirrors the Fleet table/feed aesthetic. Class prefix .ti- to avoid
     collisions. */
  .ti-shell { display: flex; flex-direction: column; gap: 18px; padding-top: 4px; }

  .ti-section-header {
    display: flex; align-items: baseline; justify-content: space-between;
    border-bottom: 1px solid var(--border); padding-bottom: 8px; margin-top: 8px;
  }
  .ti-section-header h3 { margin: 0; font-size: 16px; font-weight: 600; color: var(--text); }
  .ti-section-actions { display: flex; gap: 8px; }

  .ti-banner {
    padding: 12px 14px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--panel); display: flex; flex-direction: column; gap: 4px;
  }
  .ti-banner-warn { border-color: var(--amber, #b8860b); background: rgba(184,134,11,0.08); }
  .ti-banner-hint { font-size: 13px; color: var(--text-muted, #94a3b8); }

  .ti-empty {
    padding: 28px; border: 1px dashed var(--border); border-radius: 8px;
    background: var(--panel); color: var(--text-muted, #94a3b8); text-align: center;
  }
  .ti-empty-good { border-style: solid; border-color: var(--green, #10b981); color: var(--green, #10b981); }
  .ti-empty-hint { font-size: 13px; margin-top: 6px; }
  .ti-error h3 { color: var(--red, #ef4444); margin-bottom: 8px; }

  .ti-grid {
    width: 100%; border-collapse: collapse;
    background: var(--panel); border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  }
  .ti-grid th, .ti-grid td { padding: 10px 12px; text-align: left; font-size: 14px; vertical-align: middle; }
  .ti-grid thead { background: var(--border-subtle, rgba(255,255,255,0.04)); }
  .ti-grid th { font-weight: 600; color: var(--text-muted, #94a3b8); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
  .ti-grid tbody tr { cursor: pointer; border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04)); }
  .ti-grid tbody tr:hover { background: var(--border-subtle, rgba(255,255,255,0.04)); }
  .ti-row-open { background: var(--border-subtle, rgba(255,255,255,0.04)); }
  .ti-row-drawer td { background: var(--bg-deep, rgba(0,0,0,0.15)); padding: 14px 18px; }
  .ti-drawer-empty { color: var(--text-muted); font-style: italic; }
  .ti-actions-col { width: 96px; text-align: right; }

  .ti-timeline { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
  .ti-timeline-item {
    display: grid;
    grid-template-columns: 90px 130px 110px 1fr;
    gap: 12px; font-size: 13px; align-items: baseline;
    padding: 6px 0; border-bottom: 1px dashed var(--border-subtle);
  }
  .ti-timeline-when  { color: var(--text-muted); }
  .ti-timeline-who   { font-weight: 600; }
  .ti-timeline-what  { color: var(--text-muted); }
  .ti-timeline-where { color: var(--text); }
  .ti-timeline-notes { grid-column: 1 / -1; color: var(--text-muted); font-style: italic; padding-left: 12px; }

  .ti-feed { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 4px; }
  .ti-feed-item {
    display: grid; grid-template-columns: 100px 1fr; gap: 12px;
    padding: 8px 12px; border: 1px solid var(--border-subtle);
    border-radius: 6px; background: var(--panel); font-size: 13px;
  }
  .ti-feed-when { color: var(--text-muted); }
  .ti-feed-signout          { border-left: 3px solid var(--blue, #3b82f6); }
  .ti-feed-return           { border-left: 3px solid var(--green, #10b981); }
  .ti-feed-admin_correction { border-left: 3px solid var(--amber, #b8860b); }
  .ti-feed-day-head {
    font-size: 11px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .06em; color: var(--text-muted, #64748b);
    padding: 12px 0 4px;
  }

  .ti-audit-group { padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); }
  .ti-audit-group h4 { margin: 0 0 8px; font-size: 14px; color: var(--amber, #b8860b); }
  .ti-audit-list { padding-left: 20px; margin: 0; font-size: 13px; }
  .ti-audit-list li { margin: 4px 0; }

  /* Modals reuse the existing .modal-overlay theme but ti-* is namespaced
     so we don't fight any existing layout. */
  .ti-modal-backdrop {
    position: fixed; inset: 0; background: rgba(15,23,42,0.6); z-index: 5000;
    display: flex; align-items: flex-start; justify-content: center; padding-top: 80px;
  }
  .ti-modal {
    background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
    padding: 20px 24px; width: min(520px, 90vw);
    display: flex; flex-direction: column; gap: 10px; box-shadow: 0 10px 40px rgba(0,0,0,0.4);
  }
  .ti-modal h2 { margin: 0; font-size: 18px; }
  .ti-modal-sub { font-size: 13px; color: var(--text-muted); }
  .ti-modal label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--text-muted); }
  .ti-modal input, .ti-modal select {
    background: var(--bg-deep, rgba(0,0,0,0.15));
    border: 1px solid var(--border); border-radius: 6px;
    padding: 8px 10px; color: var(--text); font-size: 14px;
  }
  /* Native <select> dropdown popups on Windows/Chrome inherit the select's
     light --text color but fall back to a near-white system background,
     rendering the options nearly invisible (e.g. the time pickers in this
     modal). Force an opaque themed background on every option list — same
     fix already applied to .status-select option. Global so it covers the
     time/job pickers, quote modals, and sj-field selects in one shot. */
  select option {
    background: var(--panel);
    color: var(--text);
  }
  .ti-modal-actions { display: flex; gap: 8px; justify-content: flex-end; align-items: center; margin-top: 8px; }
  .ti-modal-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .ti-modal-warn {
    background: rgba(184,134,11,0.10); border: 1px solid var(--amber, #b8860b);
    padding: 8px 10px; border-radius: 6px; color: var(--text); font-size: 13px;
  }
  .ti-modal input:disabled, .ti-modal select:disabled {
    opacity: 0.55; cursor: not-allowed;
  }

  /* ─── Per-employee hours breakdown modal ─────────────────────────────
     Triggered from clickable employee names in the Crew tab "Active
     right now" section AND the Billing tab "Active Timesheets" table.
     One job-card per jobId, listing every clock-in/clock-out window
     plus employee notes for that job today. */
  .crew-bd-trigger {
    color: var(--blue, #3b82f6);
    text-decoration: none;
    cursor: pointer;
    border-bottom: 1px dashed transparent;
    transition: border-color 0.12s;
  }
  .crew-bd-trigger:hover {
    border-bottom-color: var(--blue, #3b82f6);
  }
  .crew-bd-list { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
  .crew-bd-job-card {
    border: 1px solid var(--border);
    background: var(--bg-deep, rgba(0,0,0,0.12));
    border-radius: 8px;
    padding: 10px 12px;
    display: flex; flex-direction: column; gap: 6px;
  }
  .crew-bd-job-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px;
  }
  .crew-bd-job-name { font-weight: 600; font-size: 14px; color: var(--text); }
  .crew-bd-job-link {
    color: var(--blue, #3b82f6);
    text-decoration: none;
    border-bottom: 1px dashed transparent;
  }
  .crew-bd-job-link:hover { border-bottom-color: var(--blue, #3b82f6); }
  .crew-bd-job-plain { color: var(--text); }
  .crew-bd-job-hours {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--text);
    font-size: 13px;
  }
  .crew-bd-period {
    display: flex; flex-direction: column; gap: 2px;
    font-size: 13px; color: var(--text-muted);
    padding-left: 4px;
    border-left: 2px solid var(--border-subtle, rgba(255,255,255,0.06));
    padding-block: 2px;
  }
  .crew-bd-period-time { color: var(--text); font-variant-numeric: tabular-nums; }
  .crew-bd-notes {
    font-size: 12px; color: var(--text-muted);
    font-style: italic;
    margin-top: 1px;
  }
  .crew-bd-empty {
    padding: 16px 12px; text-align: center;
    color: var(--text-muted); font-size: 13px;
    border: 1px dashed var(--border); border-radius: 8px;
  }
  /* Scheduled-today section inside the breakdown modal. Surfaces what
     was on the calendar for this employee on this date so management
     can clock them in (Add Entry pre-filled). Visually muted vs the
     logged-entries list — these are intent, not actuals. */
  .crew-bd-sched {
    margin-top: 14px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: rgba(96, 165, 250, 0.04);
    padding: 8px 12px;
  }
  .crew-bd-sched-head {
    font-size: 11px; font-weight: 700;
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--blue-light, #93c5fd);
    margin-bottom: 6px;
  }
  .crew-bd-sched-row {
    display: grid;
    grid-template-columns: minmax(110px, auto) 1fr auto;
    gap: 10px;
    align-items: center;
    padding: 6px 0;
    border-top: 1px solid rgba(255,255,255,0.04);
  }
  .crew-bd-sched-row:first-of-type { border-top: 0; }
  .crew-bd-sched-row-logged { opacity: 0.65; }
  .crew-bd-sched-time {
    color: var(--blue-light, #93c5fd);
    font-variant-numeric: tabular-nums; font-weight: 600;
    font-size: 12px; white-space: nowrap;
  }
  .crew-bd-sched-label {
    color: var(--text); font-size: 13px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .crew-bd-sched-logged {
    font-size: 11px; font-weight: 600;
    color: var(--green, #34d399);
    letter-spacing: 0.03em;
  }
  /* Phase 1.6 — edit affordances inside breakdown modal */
  .crew-bd-modal-head {
    display: flex; align-items: center; gap: 10px;
    flex-wrap: wrap;
  }
  .crew-bd-modal-head h2 { margin: 0; }
  .crew-bd-status-badge {
    display: inline-block;
    padding: 2px 8px; border-radius: 999px;
    font-size: 10.5px; font-weight: 700;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }
  .crew-bd-status-open {
    background: rgba(96, 165, 250, 0.14);
    color: var(--blue-light, #93c5fd);
    border: 1px solid rgba(96, 165, 250, 0.32);
  }
  .crew-bd-status-approved {
    background: rgba(52, 211, 153, 0.15);
    color: var(--green, #34d399);
    border: 1px solid rgba(52, 211, 153, 0.32);
  }
  .crew-bd-status-locked {
    background: rgba(239, 68, 68, 0.12);
    color: var(--red-bright);
    border: 1px solid rgba(239, 68, 68, 0.32);
  }
  .crew-bd-period {
    position: relative;
    display: flex; flex-direction: column;
  }
  .crew-bd-period-actions {
    position: absolute; top: 2px; right: 2px;
    display: inline-flex; gap: 4px;
    opacity: 0; transition: opacity 0.12s;
  }
  .crew-bd-period:hover .crew-bd-period-actions { opacity: 1; }
  .crew-bd-icon-btn {
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 4px;
    width: 22px; height: 22px;
    padding: 0; line-height: 1;
    font-size: 12px;
    color: var(--text-muted);
    cursor: pointer;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
  }
  .crew-bd-icon-btn:hover {
    background: rgba(96, 165, 250, 0.12);
    color: var(--blue-light, #93c5fd);
    border-color: rgba(96, 165, 250, 0.32);
  }
  .crew-bd-icon-btn-danger:hover {
    background: rgba(239, 68, 68, 0.12);
    color: var(--red-bright);
    border-color: rgba(239, 68, 68, 0.32);
  }

  /* ─── Day-detail modal (Phase 2 of calendar+time-entry integration) ──
     Per-day per-job drill-down. Triggered from the "Day" chip on Today
     event rows. Shows crew actuals + materials + day note in one
     scrollable modal. Read-only for now; edit affordances arrive in
     Phase 3 (day note) and Phase 1.6 (crew entries). */
  .dd-modal { max-height: 85vh; overflow-y: auto; }
  .dd-head { padding-bottom: 4px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
  .dd-head h2 { margin: 0; font-size: 17px; color: var(--text); }
  .dd-sub { margin: 4px 0 0; font-size: 12.5px; color: var(--text-muted); }
  .dd-section { margin-top: 14px; }
  .dd-section-head {
    margin: 0 0 8px;
    font-size: 12px; font-weight: 700;
    letter-spacing: 0.06em; text-transform: uppercase;
    color: var(--text-muted);
    display: flex; align-items: center; gap: 8px;
  }
  .dd-section-count {
    display: inline-block;
    padding: 1px 8px; border-radius: 999px;
    background: rgba(96,165,250,0.12);
    color: var(--blue-light, #93c5fd);
    font-size: 11px; font-weight: 700;
    letter-spacing: 0.02em; text-transform: none;
  }
  .dd-section-body { display: flex; flex-direction: column; gap: 8px; }
  .dd-empty {
    padding: 14px 12px; text-align: center;
    color: var(--text-muted); font-size: 12.5px;
    border: 1px dashed var(--border); border-radius: 8px;
  }
  .dd-empty-small { padding: 10px 12px; font-size: 12px; }
  /* Async crew loading state */
  .dd-crew-loading {
    padding: 14px 12px; text-align: center;
    color: var(--text-muted); font-size: 12.5px;
    border: 1px dashed var(--border); border-radius: 8px;
    display: flex; align-items: center; justify-content: center; gap: 8px;
  }
  .dd-spinner {
    display: inline-block;
    width: 12px; height: 12px;
    border: 2px solid var(--border);
    border-top-color: var(--blue-light, #93c5fd);
    border-radius: 50%;
    animation: dd-spin 0.7s linear infinite;
  }
  @keyframes dd-spin { to { transform: rotate(360deg); } }
  /* Crew cards inside day-detail */
  .dd-crew-card {
    border: 1px solid var(--border);
    background: var(--bg-deep, rgba(0,0,0,0.12));
    border-radius: 8px;
    padding: 9px 12px;
    display: flex; flex-direction: column; gap: 4px;
  }
  /* 2026-05-25 — clickable crew card opens the per-employee hours
     breakdown modal where Matt edits start/end/notes/job. */
  .dd-crew-card-clickable { cursor: pointer; transition: border-color 120ms ease, background 120ms ease; }
  .dd-crew-card-clickable:hover { border-color: var(--blue); background: rgba(59,130,246,0.06); }
  .dd-crew-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px;
  }
  .dd-crew-name { font-weight: 600; color: var(--text); font-size: 13px; }
  .dd-crew-hours {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--text);
    font-size: 13px;
  }
  .dd-period {
    font-size: 12px; color: var(--text-muted);
    padding-left: 6px;
    border-left: 2px solid var(--border-subtle, rgba(255,255,255,0.06));
    padding-block: 2px;
  }
  .dd-period-time { color: var(--text); font-variant-numeric: tabular-nums; }
  .dd-period-notes {
    font-size: 11.5px; color: var(--text-muted);
    font-style: italic;
    margin-top: 1px;
  }
  /* Material cards inside day-detail */
  .dd-mat-card {
    border: 1px solid var(--border);
    background: var(--bg-deep, rgba(0,0,0,0.12));
    border-radius: 8px;
    padding: 9px 12px;
    display: flex; flex-direction: column; gap: 4px;
  }
  .dd-mat-card-today {
    border-left: 3px solid var(--green, #34d399);
    background: rgba(52, 211, 153, 0.04);
  }
  .dd-mat-head {
    display: flex; align-items: baseline; gap: 10px;
    flex-wrap: wrap;
  }
  .dd-mat-ref { font-weight: 600; color: var(--text); font-size: 13px; }
  .dd-mat-date {
    font-size: 11px; color: var(--text-muted);
    font-variant-numeric: tabular-nums;
  }
  .dd-mat-total {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-weight: 700; color: var(--text); font-size: 13px;
  }
  .dd-mat-lines { display: flex; flex-direction: column; gap: 2px; padding-left: 4px; }
  .dd-mat-line  { font-size: 11.5px; color: var(--text-muted); }
  .dd-mat-more  { font-size: 11px; color: var(--text-faint); font-style: italic; padding-left: 4px; }
  /* Day note */
  .dd-daynote {
    padding: 12px 14px;
    background: rgba(96,165,250,0.06);
    border-left: 3px solid var(--blue, #3b82f6);
    border-radius: 4px;
    font-size: 13px; color: var(--text);
    white-space: pre-wrap;
  }
  .dd-daynote-actions {
    margin-top: 6px;
    display: flex; justify-content: flex-end;
  }


  /* CRM-addition badge — small pill next to the tool name so Matt can
     spot which tools were added from the CRM (Blob) vs. baked into the
     seed (committed JSON). */
  .ti-badge-crm {
    display: inline-block; margin-left: 6px;
    padding: 1px 6px; border-radius: 4px;
    background: rgba(59,130,246,0.15); color: var(--blue, #3b82f6);
    font-size: 10px; font-weight: 700; letter-spacing: 0.04em;
    vertical-align: middle;
  }

  .ti-add-output {
    background: var(--bg-deep, rgba(0,0,0,0.15)); padding: 10px;
    border-radius: 6px; font-family: 'SF Mono', Consolas, monospace;
    font-size: 12px; max-height: 240px; overflow: auto;
    white-space: pre-wrap; word-break: break-all;
  }

  .button-ghost {
    background: transparent; border: 1px solid var(--border); color: var(--text);
  }
  .button-ghost:hover { background: var(--border-subtle, rgba(255,255,255,0.04)); }
  .button-small { padding: 4px 10px; font-size: 12px; }
  .button-danger {
    background: var(--red, #ef4444); border: 1px solid var(--red, #ef4444);
    color: #fff;
  }
  .button-danger:hover { filter: brightness(1.1); }

  /* ─── Source-email context block on synth-canon billing cards (2026-05-13) ─
     When a van_stock / home_depot / amazon email creates a card before
     it's matched to a job, surface "from <employee>" + raw subject + the
     items list the employee typed in. The address hints render as
     clickable chips that autofill the CC search. */
  .bwa-card-source-ctx {
    display: flex; flex-direction: column; gap: 4px;
    margin: 6px 0 4px;
    padding: 8px 10px;
    background: rgba(59,130,246,0.06);
    border-left: 2px solid var(--blue, #3b82f6);
    border-radius: 4px;
    font-size: 12px;
    color: var(--text);
  }
  .bwa-card-source-meta { color: var(--text-muted, #94a3b8); }
  .bwa-card-source-meta strong { color: var(--text); }
  .bwa-card-source-meta em { font-style: normal; color: var(--text); }
  .bwa-card-source-items, .bwa-card-source-hints {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px;
  }
  .bwa-card-source-label {
    color: var(--text-muted, #94a3b8);
    font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
    margin-right: 2px;
  }
  .bwa-card-source-item {
    display: inline-block;
    padding: 2px 7px;
    background: rgba(255,255,255,0.04);
    border: 1px solid var(--border-subtle, rgba(255,255,255,0.06));
    border-radius: 4px;
    font-family: 'SF Mono', Consolas, monospace;
    font-size: 11px;
  }
  .bwa-card-source-hint {
    display: inline-block;
    padding: 2px 8px;
    background: rgba(59,130,246,0.15);
    border: 1px solid var(--blue, #3b82f6);
    border-radius: 4px;
    color: var(--blue, #3b82f6);
    font-size: 11px; font-weight: 600;
    cursor: pointer;
    transition: background 0.12s;
  }
  .bwa-card-source-hint:hover { background: rgba(59,130,246,0.28); }

  /* ─── Notes from this week (2026-05-13) ───────────────────────────────
     Narrative van-stock emails from crew that aren't billable line items
     — they're heads-up warnings. Sits above Active Timesheets in the
     Billing tab. Each note: date, sender, body, "Mark resolved" button. */
  .bwa-notes-section { margin: 12px 0 14px; }
  .bwa-notes-details {
    background: var(--panel);
    border: 1px solid var(--amber, #b8860b);
    border-left: 3px solid var(--amber, #b8860b);
    border-radius: 8px;
    overflow: hidden;
  }
  .bwa-notes-details > summary {
    padding: 10px 14px; cursor: pointer;
    display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline;
    background: rgba(184,134,11,0.08); list-style: none;
    font-size: 14px;
  }
  .bwa-notes-details > summary::-webkit-details-marker { display: none; }
  .bwa-notes-details > summary::before {
    content: '▸'; color: var(--text-muted); margin-right: 6px;
    transition: transform 0.12s; display: inline-block;
  }
  .bwa-notes-details[open] > summary::before { transform: rotate(90deg); }
  .bwa-notes-count { color: var(--amber, #b8860b); font-weight: 600; }
  .bwa-notes-list { display: flex; flex-direction: column; }
  .bwa-note-row {
    padding: 10px 14px;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .bwa-note-head {
    display: flex; align-items: center; gap: 8px;
    font-size: 12px; color: var(--text-muted); margin-bottom: 4px;
  }
  .bwa-note-date { color: var(--text); font-weight: 600; }
  .bwa-note-from strong { color: var(--text); }
  .bwa-note-subject {
    font-size: 13px; font-weight: 600; color: var(--text);
    margin: 2px 0 4px;
    font-style: italic;
  }
  .bwa-note-body {
    font-size: 14px; color: var(--text); white-space: pre-wrap;
    line-height: 1.4;
  }
  .bwa-note-resolve {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    padding: 3px 10px; border-radius: 4px;
    font-size: 11px; cursor: pointer;
  }
  .bwa-note-resolve:hover {
    border-color: var(--green, #10b981); color: var(--green, #10b981);
  }
  .bwa-notes-count-zero {
    color: var(--text-muted); font-weight: 500; opacity: 0.7;
  }
  .bwa-note-source-tag {
    background: rgba(96,165,250,0.14);
    color: var(--blue-text, #60a5fa);
    border: 1px solid rgba(96,165,250,0.32);
    padding: 0 7px; border-radius: 999px;
    font-size: 10px; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.04em;
  }
  /* + Add note button in the section header — quiet pill that activates
     the composer. Stops <summary> from also toggling the details element
     via stopPropagation in the click handler. */
  .bwa-note-add-btn {
    background: rgba(96,165,250,0.10);
    color: var(--blue-text, #60a5fa);
    border: 1px solid rgba(96,165,250,0.32);
    padding: 3px 12px; border-radius: 4px;
    font-size: 11px; font-weight: 600; cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
  }
  .bwa-note-add-btn:hover {
    background: rgba(96,165,250,0.22);
    border-color: rgba(96,165,250,0.55);
  }
  /* Inline composer for adding a manual note. Lives at the top of the
     notes list so user can see existing notes while composing. */
  .bwa-note-composer {
    padding: 12px 14px;
    background: rgba(96,165,250,0.04);
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
    display: flex; flex-direction: column; gap: 8px;
  }
  .bwa-note-composer-row {
    display: flex; gap: 8px;
  }
  .bwa-note-composer-from,
  .bwa-note-composer-date,
  .bwa-note-composer-subject,
  .bwa-note-composer-body {
    background: var(--panel-2, #1a1f2e);
    border: 1px solid var(--border, #2a3347);
    color: var(--text);
    padding: 6px 10px; border-radius: 5px;
    font: inherit; font-size: 13px;
  }
  .bwa-note-composer-from { flex: 1 1 auto; }
  .bwa-note-composer-date { flex: 0 0 auto; width: 150px; }
  .bwa-note-composer-subject { width: 100%; font-weight: 600; }
  .bwa-note-composer-body { width: 100%; resize: vertical; min-height: 60px; }
  .bwa-note-composer-from:focus,
  .bwa-note-composer-date:focus,
  .bwa-note-composer-subject:focus,
  .bwa-note-composer-body:focus {
    outline: none; border-color: rgba(96,165,250,0.65);
    background: rgba(96,165,250,0.06);
  }
  .bwa-note-composer-actions {
    display: flex; justify-content: flex-end; gap: 8px; margin-top: 2px;
  }
  .bwa-note-composer-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-muted);
    padding: 5px 14px; border-radius: 5px;
    font-size: 12px; font-weight: 600; cursor: pointer;
  }
  .bwa-note-composer-cancel:hover {
    border-color: var(--text); color: var(--text);
  }
  .bwa-note-composer-save {
    background: rgba(96,165,250,0.18);
    border-color: rgba(96,165,250,0.45);
    color: var(--blue-text, #60a5fa);
  }
  .bwa-note-composer-save:hover {
    background: rgba(96,165,250,0.30);
    border-color: rgba(96,165,250,0.65);
  }

  /* ─── Active Timesheets section in Billing tab (2026-05-13, §3) ───────
     Slots between the PP header (.bwa-meta) and the cards list. Renders
     a collapsible <details> with a status table — yellow rows for open
     (crew hasn't approved yet), green for approved (locked in), gray for
     locked. */
  .bwa-ts-section { margin: 12px 0 14px; }
  .bwa-ts-details {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0;
    overflow: hidden;
  }
  .bwa-ts-details > summary {
    padding: 10px 14px;
    cursor: pointer;
    display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline;
    background: rgba(59,130,246,0.04);
    list-style: none;
    font-size: 14px;
  }
  .bwa-ts-details > summary::-webkit-details-marker { display: none; }
  .bwa-ts-details > summary::before {
    content: '▸';
    color: var(--text-muted);
    margin-right: 6px;
    transition: transform 0.12s;
    display: inline-block;
  }
  .bwa-ts-details[open] > summary::before { transform: rotate(90deg); }
  .bwa-ts-summary-open     { color: var(--amber, #b8860b); font-weight: 600; }
  .bwa-ts-summary-approved { color: var(--green, #10b981); font-weight: 600; }

  .bwa-ts-head {
    padding: 10px 14px;
    background: rgba(184,134,11,0.06);
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
    display: flex; gap: 6px; align-items: baseline;
  }
  .bwa-ts-banner {
    padding: 12px 14px;
    color: var(--text-muted);
    font-size: 13px;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
    background: rgba(184,134,11,0.04);
  }
  .bwa-ts-banner code {
    background: rgba(255,255,255,0.06);
    padding: 1px 5px; border-radius: 3px;
    font-size: 12px;
  }
  .bwa-ts-warn { margin-top: 6px; color: var(--amber, #b8860b); font-size: 12px; }

  .bwa-ts-table {
    width: 100%; border-collapse: collapse;
    font-size: 13px;
  }
  .bwa-ts-table th, .bwa-ts-table td {
    padding: 8px 14px;
    text-align: left;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .bwa-ts-table thead th {
    background: rgba(255,255,255,0.02);
    color: var(--text-muted);
    font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
    font-weight: 600;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .bwa-ts-table tbody tr.bwa-ts-row-open {
    background: rgba(184,134,11,0.08);
    border-left: 3px solid var(--amber, #b8860b);
  }
  .bwa-ts-table tbody tr.bwa-ts-row-locked {
    opacity: 0.55;
  }
  .bwa-ts-hours { font-variant-numeric: tabular-nums; font-weight: 600; }
  .bwa-ts-jobs  { color: var(--text-muted); max-width: 320px; }

  .bwa-ts-pill {
    display: inline-block;
    padding: 2px 9px; border-radius: 999px;
    font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.03em;
  }
  .bwa-ts-pill-amber  { background: rgba(184,134,11,0.18); color: var(--amber, #b8860b); }
  .bwa-ts-pill-green  { background: rgba(16,185,129,0.18); color: var(--green, #10b981); }
  .bwa-ts-pill-muted  { background: rgba(255,255,255,0.06); color: var(--text-muted); }
  .bwa-ts-pill-danger { background: rgba(239,68,68,0.18);  color: var(--red, #ef4444); }
  .bwa-ts-pill-empty  { background: transparent; color: var(--text-muted); border: 1px dashed var(--border); }

  .bwa-ts-note {
    padding: 8px 14px;
    font-size: 12px;
    color: var(--text-muted);
    background: rgba(184,134,11,0.04);
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }

  /* ─── Crew tab (2026-05-12) ───────────────────────────────────────────
     Mirror of the .ti-* aesthetic. Class prefix .crew- to avoid clashes
     with .clients-*. */
  .crew-shell { display: flex; flex-direction: column; gap: 18px; padding-top: 4px; }
  .crew-section { display: flex; flex-direction: column; gap: 10px; }
  .crew-section > h3 {
    margin: 8px 0 0; font-size: 16px; font-weight: 600;
    color: var(--text); padding-bottom: 8px; border-bottom: 1px solid var(--border);
  }
  .crew-section-hint { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
  .crew-section-sub { font-size: 13px; font-weight: 400; color: var(--text-muted); margin-left: 8px; }
  /* Collapsible variant — used for Roster admin (rare workflow, hides behind
     a summary by default). Matches details/summary chevron pattern from the
     sidebar hubs. */
  details.crew-section-collapsible { display: block; }
  details.crew-section-collapsible > summary.crew-section-summary {
    list-style: none; cursor: pointer; user-select: none;
    display: flex; align-items: center;
    padding-bottom: 8px; border-bottom: 1px solid var(--border);
    margin: 8px 0 0;
  }
  details.crew-section-collapsible > summary.crew-section-summary::-webkit-details-marker { display: none; }
  details.crew-section-collapsible > summary.crew-section-summary::before {
    content: '▸'; color: var(--text-muted); font-size: 11px;
    margin-right: 8px;
    transition: transform 160ms ease;
    flex: 0 0 auto;
  }
  details.crew-section-collapsible[open] > summary.crew-section-summary::before {
    transform: rotate(90deg);
  }
  details.crew-section-collapsible > summary.crew-section-summary h3 {
    margin: 0; padding: 0; border: 0;
    font-size: 16px; font-weight: 600; color: var(--text);
  }
  details.crew-section-collapsible > *:not(summary) {
    margin-top: 10px;
  }
  .crew-rmb-amount { font-variant-numeric: tabular-nums; text-align: right; font-weight: 600; color: var(--purple); }
  .crew-rmb-paid td { color: var(--text-muted); }
  .crew-rmb-row-actions { display: flex; gap: 6px; justify-content: flex-end; align-items: center; white-space: nowrap; }
  /* Crew tab banner that points to the Reimbursements tab's new home in
     Billing (2026-05-24 move). One-liner pill, low chrome. */
  .crew-reimburse-moved {
    padding: 10px 14px; border: 1px dashed var(--border); border-radius: 6px;
    background: var(--panel-2); color: var(--text-muted); font-size: 13px;
  }
  .crew-reimburse-moved a { color: var(--blue); text-decoration: none; }
  .crew-reimburse-moved a:hover { text-decoration: underline; }
  .crew-reimburse-moved-count { color: var(--amber); font-weight: 600; margin-left: 4px; }
  /* Billing > Reimbursements shell — wraps the renderReimburse output. */
  .billing-reimburse-shell { padding: 16px 20px; }
  /* Inline hint for locked form fields in the Send-to-QBO modal — used when
     a reimbursement receipt forces Payment Account = Chequing. */
  .rcpt-fld-locked-hint { font-size: 11px; color: var(--text-muted); font-style: italic; font-weight: normal; }
  /* Mark-paid modal — QBO primary action + fallback divider + no-receipt note. */
  .rmb-paid-primary { margin-top: 16px; }
  .rmb-paid-primary-hint { font-size: 11px; color: var(--text-muted); margin: 6px 0 0 0; }
  .rmb-paid-divider {
    display: flex; align-items: center; gap: 10px;
    margin: 16px 0 4px 0; color: var(--text-muted); font-size: 11px;
  }
  .rmb-paid-divider::before, .rmb-paid-divider::after {
    content: ''; flex: 1; height: 1px; background: var(--border);
  }
  .rmb-paid-no-receipt {
    margin-top: 14px; padding: 10px 12px; border-radius: 6px;
    background: var(--panel-2); color: var(--text-muted); font-size: 12px; font-style: italic;
  }
  .crew-rmb-history { margin-top: 8px; }
  .crew-rmb-history summary { cursor: pointer; padding: 6px 4px; font-size: 13px; color: var(--text-muted); }
  .crew-rmb-history summary:hover { color: var(--text); }

  /* ── Labor by pay period (Crew tab) ────────────────────────────────
     Shipped 2026-05-19. Per-PP accordion → per-crew-member row
     accordion → per-job drill table. Three nesting levels via
     <details> elements; styled to read as a table without rigid
     grid layout. */
  .crew-pp-block {
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-top: 6px;
    background: var(--panel);
  }
  .crew-pp-block-summary {
    display: flex; align-items: baseline; gap: 12px;
    padding: 10px 14px;
    cursor: pointer; user-select: none;
    font-size: 14px; color: var(--text);
  }
  .crew-pp-block-summary::-webkit-details-marker { display: none; }
  .crew-pp-block-summary::before {
    content: '▸'; color: var(--text-muted); font-size: 11px;
    margin-right: 2px;
    transition: transform 160ms ease;
  }
  .crew-pp-block[open] > .crew-pp-block-summary::before { transform: rotate(90deg); }
  .crew-pp-block-summary strong { color: var(--text); font-weight: 600; }
  .crew-pp-block-meta { color: var(--text-muted); font-size: 13px; margin-left: auto; }
  .crew-pp-tag {
    display: inline-block; padding: 1px 7px; border-radius: 999px;
    background: rgba(96,165,250,0.18); color: var(--blue-light);
    font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em;
    text-transform: uppercase;
  }
  .crew-pp-rows {
    border-top: 1px solid var(--border);
    padding: 4px 10px 8px;
  }
  /* 2026-05-19 — Archived pay periods accordion. Holds every pre-current
     PP block behind a single collapsed button. Click to expand and see
     each historical PP (which is also collapsible individually). */
  .crew-pp-archive {
    margin-top: 14px;
    border: 1px dashed var(--border);
    border-radius: 8px;
    background: rgba(15, 19, 28, 0.4);
  }
  .crew-pp-archive-summary {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 10px 14px;
    cursor: pointer;
    user-select: none;
    font-size: 13.5px;
    color: var(--text-soft);
    list-style: none;
  }
  .crew-pp-archive-summary::-webkit-details-marker { display: none; }
  .crew-pp-archive-chev {
    color: var(--text-muted);
    font-size: 11px;
    transition: transform 160ms ease;
    flex-shrink: 0;
  }
  .crew-pp-archive[open] > .crew-pp-archive-summary .crew-pp-archive-chev {
    transform: rotate(90deg);
  }
  .crew-pp-archive-summary strong {
    color: var(--text);
    font-weight: 600;
  }
  .crew-pp-archive-summary:hover {
    background: rgba(96, 165, 250, 0.05);
  }
  .crew-pp-archive-count {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    background: rgba(148, 163, 184, 0.16);
    color: var(--text-muted);
    font-size: 11px;
    font-weight: 600;
  }
  .crew-pp-archive-meta {
    color: var(--text-muted);
    font-size: 12.5px;
    margin-left: auto;
  }
  .crew-pp-archive-body {
    padding: 6px 12px 10px;
    border-top: 1px solid var(--border);
  }
  .crew-pp-archive-body .crew-pp-block {
    /* Inner blocks: tighter margin so the nested look reads as
       "list of archived PPs" instead of a stacked accordion mess. */
    margin-top: 8px;
    background: var(--panel-2, var(--panel));
  }
  .crew-pp-archive-body .crew-pp-block:first-child { margin-top: 0; }
  .crew-pp-row {
    border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }
  .crew-pp-row:last-child { border-bottom: 0; }
  /* Per-crew row — flex (not grid) so the ::before chevron sits inline
     with the name instead of consuming a grid track and bumping the
     push-pill onto a second row. Name is bumped to 15px / weight 600 so
     "Jackson — 69.0h · 10 days" reads as a clear payroll header. */
  .crew-pp-row-summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 6px;
    cursor: pointer; user-select: none;
    font-size: 13.5px;
  }
  .crew-pp-row-summary::-webkit-details-marker { display: none; }
  .crew-pp-row-summary::before {
    content: '▸'; color: var(--text-muted); font-size: 11px;
    flex: 0 0 auto;
    transition: transform 160ms ease;
  }
  .crew-pp-row[open] > .crew-pp-row-summary::before { transform: rotate(90deg); }
  .crew-pp-row-name {
    color: var(--text); font-weight: 600; font-size: 15px;
    flex: 0 0 auto; min-width: 140px;
  }
  .crew-pp-row-hours {
    color: var(--text); font-variant-numeric: tabular-nums;
    font-weight: 600; font-size: 14px;
    flex: 0 0 auto; min-width: 60px;
  }
  .crew-pp-row-jobs {
    color: var(--text-muted); font-size: 12.5px;
    flex: 0 0 auto;
  }
  .crew-pp-row-push { margin-left: auto; flex: 0 0 auto; }
  .crew-push-pill {
    display: inline-block; padding: 2px 8px; border-radius: 999px;
    font-size: 11px; font-weight: 600;
  }
  .crew-push-pill-pushed  { background: rgba(34,197,94,0.14);  color: var(--green-text); }
  .crew-push-pill-pending { background: rgba(245,158,11,0.14); color: var(--amber-text); }
  .crew-push-pill-mixed   { background: rgba(148,163,184,0.14); color: var(--text); }

  .crew-pp-pick {
    display: flex; align-items: center; gap: 8px;
    margin: 8px 0 6px 14px; padding: 6px 10px;
    background: rgba(148,163,184,0.06);
    border: 1px dashed rgba(148,163,184,0.25);
    border-radius: 6px;
    font-size: 12px;
  }
  .crew-pp-pick-label { color: var(--text-muted); }
  .crew-pp-pick-input {
    background: var(--panel-3); color: var(--text);
    border: 1px solid var(--border); border-radius: 4px;
    padding: 3px 6px; font-size: 12px;
    color-scheme: dark;
  }
  [data-theme="light"] .crew-pp-pick-input { color-scheme: light; }
  .crew-pp-pick-btn {
    background: var(--accent, #3b82f6); color: #fff;
    border: none; border-radius: 4px;
    padding: 4px 12px; font-size: 12px; font-weight: 600;
    cursor: pointer;
  }
  .crew-pp-pick-btn:hover { filter: brightness(1.1); }
  .crew-pp-drill {
    width: 100%; margin: 0 0 6px 14px; border-collapse: collapse;
  }
  .crew-pp-drill td {
    padding: 5px 8px; font-size: 12.5px;
    color: var(--text);
  }
  /* Date header row — sub-heading inside the per-crew drill that
     groups shifts by day. The horizontal rule above (border-top) is the
     primary visual divider between days; subtle but consistent so the
     eye can lock onto each day block when scanning. */
  .crew-pp-drill-dayhead td {
    padding-top: 12px;
    padding-bottom: 4px;
    font-weight: 600;
    font-size: 12px;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border-top: 1px solid var(--border);
  }
  /* First dayhead in the drill has no border-top — the parent <summary>
     already provides the visual break. */
  .crew-pp-drill tbody tr:first-child.crew-pp-drill-dayhead td {
    border-top: 0;
    padding-top: 4px;
  }
  /* Day-total row — italicized small number after each day's shifts. */
  .crew-pp-drill-daysum td {
    padding-top: 2px; padding-bottom: 10px;
    font-size: 11.5px; font-style: italic;
    color: var(--text-muted);
  }
  .crew-pp-drill-row td {
    border-top: 1px solid transparent;
  }
  .crew-pp-drill-spacer { width: 14px; }
  .crew-pp-drill-job { color: var(--text); }
  .crew-pp-drill-hours { font-variant-numeric: tabular-nums; text-align: right; color: var(--text); white-space: nowrap; }
  .crew-pp-drill-role { color: var(--text-muted); font-size: 12px; }
  .crew-pp-drill-status { white-space: nowrap; text-align: right; }
  /* Clickable shift row — opens the per-(employee, date) breakdown modal
     where Matt can edit / delete / un-approve. Hover gives a subtle
     highlight so the affordance is obvious; the QBO invoice <a> inside
     the status cell still gets the underline-on-hover from its own rule. */
  .crew-pp-drill-row-clickable { cursor: pointer; }
  .crew-pp-drill-row-clickable:hover td { background: var(--panel-2, rgba(255,255,255,0.03)); }
  /* Notes preview row — italic muted line directly under each shift
     (when notes exist). Truncated to ~180 chars in JS; full text lives
     in the breakdown modal. */
  .crew-pp-drill-noterow td { border-top: 0; }
  .crew-pp-drill-note {
    padding-top: 0; padding-bottom: 6px;
    color: var(--text-muted);
    font-size: 11.5px;
    font-style: italic;
    line-height: 1.4;
  }
  .crew-job-status { font-size: 12px; font-weight: 500; }
  .crew-job-status-pushed { color: var(--green-text); text-decoration: none; }
  .crew-job-status-pushed:hover { text-decoration: underline; }
  .crew-job-status-pending { color: var(--amber-text); }
  /* Unbillable — payroll-only yard/shop/van-cleanup hours. Crew still gets
     paid but the line never goes to QBO. Muted neutral so it doesn't compete
     with the amber Pending / green Pushed signals. */
  .crew-job-status-unbillable { color: var(--text-muted); font-style: italic; }

  /* Section header layout for Labor by pay period — flex so the sort
     toggle can float right via margin-left: auto. Mirrors the time-off
     section's pattern. */
  .crew-section-labor > h3 {
    display: flex; align-items: center; gap: 8px;
  }
  /* Sort toggle — segmented button group floated to the right side of the
     "Labor by pay period" h3. Two pills (By date / By job) with the active
     one highlighted. Stays inline with the heading so it doesn't push the
     PP accordion blocks down. */
  .crew-labor-sort {
    margin-left: auto;
    display: inline-flex;
    border: 1px solid var(--border);
    border-radius: 999px;
    overflow: hidden;
    background: var(--panel);
  }
  .crew-labor-sort-btn {
    border: 0; background: transparent;
    color: var(--text-muted);
    font-size: 12px; font-weight: 500;
    padding: 4px 12px;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
  }
  .crew-labor-sort-btn:hover { color: var(--text); }
  .crew-labor-sort-btn.active {
    background: var(--blue, #2563eb);
    color: #fff;
  }
  .crew-labor-sort-btn + .crew-labor-sort-btn {
    border-left: 1px solid var(--border);
  }

  /* Fleet — Crew open-issues banner (top of Fleet Maintenance view). */
  .fleet-issues-bar {
    background: rgba(245, 158, 11, 0.08);
    border: 1px solid rgba(245, 158, 11, 0.3);
    border-radius: 10px; padding: 12px 16px; margin-bottom: 16px;
  }
  .fleet-issues-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
  .fleet-issues-head strong { color: var(--amber); }
  .fleet-issues-dot { width: 8px; height: 8px; border-radius: 50%; background: #fbbf24; }
  .fleet-issues-count {
    padding: 1px 8px; border-radius: 999px;
    background: rgba(245, 158, 11, 0.25); color: var(--amber-text);
    font-weight: 600; font-size: 11px;
  }
  .fleet-issues-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 4px; }
  .fleet-issues-list li {
    display: grid; grid-template-columns: 160px 1fr auto;
    align-items: baseline; gap: 12px;
    font-size: 13px; padding: 3px 0;
  }
  .fleet-issues-veh { color: var(--text-strong); font-weight: 600; }
  .fleet-issues-text { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .fleet-issues-age  { color: var(--text-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
  .fleet-issues-more { font-size: 12px; color: var(--text-muted); margin-top: 8px; font-style: italic; }

  .crew-banner {
    padding: 12px 14px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--panel); display: flex; flex-direction: column; gap: 4px;
  }
  .crew-banner-warn { border-color: var(--amber, #b8860b); background: rgba(184,134,11,0.08); }
  .crew-banner-hint { font-size: 13px; color: var(--text-muted); }

  .crew-empty {
    padding: 24px; border: 1px dashed var(--border); border-radius: 8px;
    background: var(--panel); color: var(--text-muted); text-align: center;
  }
  .crew-error h3 { color: var(--red, #ef4444); margin-bottom: 8px; }

  .crew-active-list { display: flex; flex-direction: column; gap: 6px; }
  .crew-active-row {
    display: grid; grid-template-columns: 1.2fr 1.6fr 80px 1.5fr auto;
    gap: 12px; align-items: center;
    padding: 10px 14px;
    background: var(--panel); border: 1px solid var(--border);
    border-left: 3px solid var(--amber, #b8860b);
    border-radius: 6px;
  }
  .crew-active-name { font-weight: 600; }
  .crew-active-job { color: var(--text-muted); }
  .crew-active-elapsed { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--amber, #b8860b); }
  .crew-gps { font-size: 12px; color: var(--blue, #3b82f6); text-decoration: none; }
  .crew-gps:hover { text-decoration: underline; }
  .crew-gps-none { font-size: 12px; color: var(--text-muted); font-style: italic; }

  .crew-table {
    width: 100%; border-collapse: collapse;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 8px; overflow: hidden;
  }
  .crew-table th, .crew-table td { padding: 10px 12px; text-align: left; font-size: 14px; }
  .crew-table thead { background: var(--border-subtle, rgba(255,255,255,0.04)); }
  .crew-table th {
    font-weight: 600; color: var(--text-muted);
    font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em;
  }
  .crew-table tbody tr { border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04)); }
  .crew-table code { font-family: 'SF Mono', Consolas, monospace; font-size: 12px; color: var(--text-muted); }

  .crew-pill {
    display: inline-block; padding: 3px 9px; border-radius: 999px;
    font-size: 12px; font-weight: 600;
  }
  .crew-pill-amber   { background: rgba(184,134,11,0.15); color: var(--amber, #b8860b); }
  .crew-pill-success { background: rgba(16,185,129,0.15); color: var(--green, #10b981); }
  .crew-pill-danger  { background: rgba(239,68,68,0.15);  color: var(--red, #ef4444); }
  .crew-pill-muted   { background: var(--border-subtle, rgba(255,255,255,0.04)); color: var(--text-muted); }
  .crew-pill-empty   { background: transparent; color: var(--text-muted); border: 1px dashed var(--border); }

  /* ── Time off section (Crew tab) ────────────────────────────────────
     Shipped 2026-05-16. Source of truth for crew time-off requests.
     Today view mirrors the Pending subset. Spec: shared/docs/
     MOBILE-TIME-OFF-REQUEST-SPEC.md */
  /* The h3 used to be a direct child of .crew-section-timeoff. Once
     the section was wrapped in <details>/<summary> for collapse-when-
     empty, the h3 nests inside the summary — so the rule needs to
     match both shapes. */
  .crew-section-timeoff > h3,
  .crew-section-timeoff > .crew-section-summary > h3,
  .crew-section-timeoff > summary > h3 {
    display: flex; align-items: center;
  }
  /* Add-request toolbar sits in the expanded body of the Time off section
     (above pending / upcoming lists). Was an inline pill in the summary
     until 2026-05-25; moved out so the collapsed header isn't crowded. */
  .crew-to-toolbar {
    display: flex; justify-content: flex-end;
    margin: 4px 0 8px;
  }
  .crew-to-add-btn { font-size: 13px; }
  .crew-to-subhead {
    font-size: 12px; font-weight: 600; letter-spacing: 0.04em;
    text-transform: uppercase; color: var(--text-muted);
    margin: 8px 0 4px;
  }
  .crew-to-list {
    display: flex; flex-direction: column; gap: 6px;
  }
  .crew-to-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 8px; padding: 10px 14px;
  }
  .crew-to-row-pending {
    border-left: 3px solid var(--amber, #b8860b);
  }
  .crew-to-row-upcoming {
    border-left: 3px solid var(--green, #10b981);
  }
  .crew-to-row-main {
    display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
    flex: 1; min-width: 0;
  }
  .crew-to-row-main > strong {
    color: var(--text); font-weight: 600;
  }
  .crew-to-range {
    color: var(--text); font-variant-numeric: tabular-nums;
  }
  .crew-to-kind {
    display: inline-block; padding: 2px 8px; border-radius: 999px;
    font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
    background: var(--border-subtle, rgba(255,255,255,0.06));
    color: var(--text-muted);
  }
  .crew-to-kind-vacation { background: rgba(59,130,246,0.15);  color: var(--blue-bright); }
  .crew-to-kind-sick     { background: rgba(239,68,68,0.15);   color: var(--red-bright); }
  .crew-to-kind-other    { background: rgba(168,85,247,0.15);  color: #c084fc; }

  /* GCal-sourced time-off marker. Identifies entries that came from
     scanning Google Calendar for the time-off color (not the mobile
     request workflow). These can't be Edit/Cancel'd from the CRM —
     the action is "Open in GCal" instead. */
  .crew-to-gcal-badge {
    display: inline-flex; align-items: center;
    padding: 2px 6px;
    font-size: 10.5px; font-weight: 600;
    background: rgba(52, 211, 153, 0.14);
    color: var(--green-text, #22c55e);
    border-radius: 4px;
    letter-spacing: 0.02em;
  }
  .crew-to-gcal-badge-small {
    padding: 1px 4px;
    font-size: 11px;
    margin-left: 4px;
  }
  .crew-to-row-gcal {
    background: rgba(52, 211, 153, 0.04);
  }
  .crew-to-gcal-link {
    font-size: 11.5px;
    color: var(--blue-light, #60a5fa);
    text-decoration: none;
  }
  .crew-to-gcal-link:hover { text-decoration: underline; }
  .crew-to-reason {
    color: var(--text-muted); font-style: italic; font-size: 13px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    max-width: 280px;
  }
  .crew-to-meta {
    color: var(--text-muted); font-size: 12px;
    margin-left: auto; padding-left: 8px;
  }
  .crew-to-row-actions {
    display: flex; gap: 6px; flex-shrink: 0;
  }
  .crew-empty-soft {
    background: transparent; border: 1px dashed var(--border);
    padding: 12px; text-align: center;
    color: var(--text-muted); font-style: italic; font-size: 13px;
  }
  .crew-to-history {
    margin-top: 12px;
  }
  .crew-to-history > summary {
    cursor: pointer; padding: 6px 0;
    color: var(--text-muted); font-size: 13px; font-weight: 600;
    user-select: none;
  }
  .crew-to-history > summary:hover { color: var(--text); }

  /* ── Today: time-off watch bar ────────────────────────────────────
     Mirrors the visual pattern of permit / inspection / A/R / fleet
     watch bars. Lives in the watch stack at the top of Today. Clicking
     jumps to Crew → Time off where the actions live. Silent empty
     state — chip hides entirely when 0 pending. */
  .today-timeoff-bar {
    display: inline-flex; align-items: center; gap: 8px; flex: 1 1 auto;
    padding: 6px 12px; border-radius: 8px;
    background: rgba(168, 85, 247, 0.08);
    border: 1px solid rgba(168, 85, 247, 0.3);
    font-size: 12.5px; min-width: 0;
    cursor: pointer;
  }
  .today-timeoff-bar:hover {
    background: rgba(168, 85, 247, 0.14);
  }
  .today-timeoff-dot {
    flex: 0 0 auto;
    width: 8px; height: 8px; border-radius: 50%;
    background: #a855f7;
    box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.15);
  }
  .today-timeoff-label { color: #c084fc; font-weight: 600; flex: 0 0 auto; }
  .today-timeoff-count {
    padding: 1px 7px; border-radius: 100px;
    background: rgba(168, 85, 247, 0.2); color: #c084fc;
    font-size: 11px; font-weight: 700; flex: 0 0 auto;
  }
  .today-timeoff-names {
    color: var(--text); flex: 1 1 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .timeoff-watch-name {
    color: var(--text);
  }
  .timeoff-watch-name + .timeoff-watch-name::before { content: ", "; }

  /* ── Today: collapsed Crew tile (when 0 clocked in) ────────────────
     Saves vertical real estate when nobody's on the clock. <details>
     element collapsed by default; click to expand and see the roster. */
  .pipeline-tile-collapsed {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 10px; padding: 0;
  }
  .pipeline-tile-collapsed > summary.pipeline-tile-head-summary {
    display: flex; align-items: center; gap: 8px;
    padding: 10px 14px; margin: 0;
    cursor: pointer; list-style: none;
    user-select: none;
  }
  .pipeline-tile-collapsed > summary.pipeline-tile-head-summary::-webkit-details-marker { display: none; }
  .pipeline-tile-collapsed > summary.pipeline-tile-head-summary::before {
    content: '▸'; color: var(--text-muted); font-size: 11px;
    margin-right: 4px; transition: transform 0.15s ease;
    flex: 0 0 auto;
  }
  .pipeline-tile-collapsed[open] > summary.pipeline-tile-head-summary::before {
    transform: rotate(90deg);
  }
  .pipeline-tile-collapsed > summary.pipeline-tile-head-summary h3 {
    margin: 0; font-size: 15px; color: var(--text-muted);
    font-weight: 600;
  }
  .pt-count-muted {
    margin-left: auto;
    color: var(--text-muted); font-size: 12px; font-weight: 500;
  }
  .pipeline-tile-collapsed > .pipeline-tile-body {
    padding: 4px 14px 12px;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
  }

  /* ── Permits view ─────────────────────────────────────────────────────
     Shipped 2026-05-14. Single table of every open permit across every
     job, derived from CC labels + the BC Address Geocoder. Style language
     mirrors the Project Budgeting table (pb-table) so the two reading
     experiences feel like siblings. */
  .permits-shell {
    display: flex; flex-direction: column; gap: 14px;
    padding: 18px 20px 30px;
  }
  .permits-head .permits-title {
    margin: 0; font-size: 20px; color: var(--text);
  }
  .permits-head .permits-sub {
    color: var(--text-muted); font-size: 13px; margin-top: 4px;
  }
  .permits-filter-bar {
    display: flex; flex-direction: column; gap: 8px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 10px; padding: 10px 14px;
  }
  .permits-filter-group {
    display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  }
  .permits-filter-label {
    color: var(--text-muted); font-size: 11px; text-transform: uppercase;
    letter-spacing: 0.05em; margin-right: 8px; min-width: 70px;
  }
  .permits-chip {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px; border-radius: 999px; cursor: pointer;
    font-size: 12px; font-weight: 500;
    background: var(--surface-deep); color: var(--text-muted);
    border: 1px solid var(--border);
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  }
  .permits-chip:hover { color: var(--text); border-color: var(--blue, #3b82f6); }
  .permits-chip-active {
    background: rgba(59,130,246,0.15); color: var(--blue-light, #60a5fa);
    border-color: rgba(59,130,246,0.45);
  }
  .permits-chip-count {
    background: rgba(0,0,0,0.25); color: inherit;
    padding: 0 6px; border-radius: 999px; font-size: 10px;
    font-variant-numeric: tabular-nums;
  }

  .permits-table-wrap {
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 12px; overflow: hidden;
  }
  .permits-table { width: 100%; border-collapse: collapse; font-size: 13px; }
  .permits-table thead th {
    background: var(--panel-2); color: var(--text-muted);
    font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
    font-weight: 600; text-align: left;
    padding: 10px 12px; border-bottom: 1px solid var(--border);
  }
  .permits-table tbody td {
    padding: 10px 12px; border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.04));
    color: var(--text); vertical-align: middle;
  }
  .permits-table tbody tr:last-child td { border-bottom: none; }
  .permits-table tbody tr:hover { background: rgba(59,130,246,0.04); }

  .permits-addr-cell {
    display: flex; align-items: center; gap: 10px;
    min-width: 280px;
  }
  .permits-addr-link {
    color: var(--blue-light, #60a5fa); text-decoration: none;
    font-weight: 500;
  }
  .permits-addr-link:hover { text-decoration: underline; }
  .permits-row-thumb { flex: 0 0 auto; }

  .permits-auth, .permits-status {
    display: inline-block; padding: 3px 9px; border-radius: 999px;
    font-size: 11.5px; font-weight: 600; white-space: nowrap;
  }
  .permits-auth-tsbc    { background: rgba(168,85,247,0.15); color: #c4a4f7; }
  .permits-auth-cov     { background: rgba(16,185,129,0.15); color: var(--green, #10b981); }
  .permits-auth-unknown { background: var(--border-subtle, rgba(255,255,255,0.04)); color: var(--text-muted); }

  .permits-status-needs-pulled         { background: rgba(239,68,68,0.18);  color: var(--red-text); }
  .permits-status-pulled               { background: rgba(59,130,246,0.18); color: var(--blue-light, #60a5fa); }
  .permits-status-inspection-scheduled { background: rgba(245,158,11,0.18); color: var(--amber); }
  .permits-status-closed               { background: rgba(16,185,129,0.15); color: var(--green, #10b981); }
  .permits-status-no-permit-needed     { background: var(--border-subtle, rgba(255,255,255,0.04)); color: var(--text-muted); }

  .permits-dim { color: var(--text-muted); }

  .permits-action-btn {
    font-size: 12px; padding: 5px 12px; white-space: nowrap;
  }

  .permits-empty {
    padding: 30px 24px; text-align: center;
    color: var(--text-soft); font-size: 13px;
  }

  .permits-footnote {
    color: var(--text-muted); font-size: 12px; line-height: 1.55;
    padding: 10px 14px; background: rgba(59,130,246,0.05);
    border: 1px solid rgba(59,130,246,0.15); border-radius: 8px;
  }
  .permits-footnote code {
    background: var(--surface-deep); padding: 1px 5px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 11.5px;
    color: var(--purple-soft);
  }

  /* v2 — Permit # / Date Filed / Last Inspection columns + Unclaimed permits panel. */
  .permits-permit-num {
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 12px;
    color: var(--text); background: var(--surface-deep);
    padding: 2px 8px; border-radius: 4px;
    white-space: nowrap;
  }

  .permits-banner {
    padding: 8px 14px; border-radius: 8px; font-size: 12.5px;
    border: 1px solid var(--border);
  }
  .permits-banner-loading { background: rgba(59,130,246,0.05);  color: var(--blue-light, #60a5fa); border-color: rgba(59,130,246,0.20); }
  .permits-banner-error   { background: rgba(239,68,68,0.08);   color: var(--red-text); border-color: rgba(239,68,68,0.30); }
  .permits-banner-info    { background: rgba(245,158,11,0.05);  color: var(--amber); border-color: rgba(245,158,11,0.20); }
  .permits-banner code {
    background: rgba(0,0,0,0.25); padding: 1px 5px; border-radius: 3px;
    font-family: ui-monospace, "SF Mono", Consolas, monospace; font-size: 11.5px;
  }

  .permits-unclaimed-section {
    margin-top: 8px; display: flex; flex-direction: column; gap: 8px;
  }
  .permits-unclaimed-title {
    margin: 0; font-size: 14px; color: var(--text);
    display: flex; align-items: center; gap: 8px;
  }
  .permits-unclaimed-sub {
    color: var(--text-muted); font-size: 12px;
  }
  .permits-table-unclaimed thead th { background: rgba(245,158,11,0.06); }
  .permits-row-unclaimed td { vertical-align: top; }

  .permits-claim-suggest {
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
    font-size: 12px;
  }
  .permits-claim-score {
    background: rgba(16,185,129,0.15); color: var(--green, #10b981);
    padding: 2px 7px; border-radius: 999px; font-size: 10.5px; font-weight: 600;
  }
  .permits-claim-accept { font-size: 11.5px; padding: 4px 10px; }
  .permits-claim-toggle { font-size: 11.5px; padding: 4px 10px; }
  .permits-claim-picker {
    display: flex; gap: 6px; align-items: center;
    margin-top: 6px;
  }
  .permits-claim-select {
    flex: 1; min-width: 200px; max-width: 360px;
    background: var(--surface-deep); color: var(--text);
    border: 1px solid var(--border); border-radius: 6px;
    padding: 4px 6px; font-size: 12px;
  }

  /* v3 — inline-row claim UI + unclaimed-row affordance. */
  .permits-row-unclaimed { background: rgba(245,158,11,0.04); }
  .permits-row-unclaimed:hover { background: rgba(245,158,11,0.08); }
  .permits-addr-orphan {
    color: var(--text); font-style: italic;
    border-bottom: 1px dashed var(--text-muted); padding-bottom: 1px;
  }
  /* Inline "Claim NN%" + "…" override toggle, sized to fit a table cell. */
  .permits-row .permits-claim-suggest { gap: 4px; flex-wrap: nowrap; }
  .permits-row .permits-claim-accept { font-size: 11.5px; padding: 4px 9px; white-space: nowrap; }
  .permits-row .permits-claim-toggle { font-size: 11.5px; padding: 4px 8px; }
  .permits-row .permits-claim-picker { flex-direction: column; align-items: stretch; gap: 4px; margin-top: 0; }
  .permits-row .permits-claim-picker .permits-claim-select { min-width: 0; max-width: none; }

  /* v3.1 — sortable column headers + searchable picker (2026-05-15). */
  .permits-th-sort { cursor: pointer; user-select: none; }
  .permits-th-sort:hover { background: rgba(59,130,246,0.10); color: var(--text); }
  .permits-th-sort-active { color: var(--blue-light, #60a5fa); }
  .permits-sort-arrow {
    display: inline-block; margin-left: 4px;
    font-variant-numeric: tabular-nums; opacity: 0.55; font-size: 11px;
  }
  .permits-th-sort-active .permits-sort-arrow { opacity: 1; }

  .permits-claim-input {
    background: var(--surface-deep); color: var(--text);
    border: 1px solid var(--border); border-radius: 6px;
    padding: 4px 6px; font-size: 12px;
    min-width: 0; width: 100%;
  }
  .permits-claim-input:focus {
    outline: none; border-color: var(--blue, #3b82f6);
    box-shadow: 0 0 0 2px rgba(59,130,246,0.20);
  }

  /* v3.2 — granular status colors + expand-history sub-row + chevron. */
  .permits-status-pulled               { background: rgba(59,130,246,0.18); color: var(--blue-light, #60a5fa); }
  .permits-status-rough-in-booked      { background: rgba(245,158,11,0.18); color: var(--amber); }
  .permits-status-rough-in-passed      { background: rgba(132,204,22,0.18); color: #a3e635; }
  .permits-status-partial-booked       { background: rgba(245,158,11,0.18); color: var(--amber); }
  .permits-status-partial-passed       { background: rgba(132,204,22,0.18); color: #a3e635; }
  .permits-status-final-booked         { background: rgba(245,158,11,0.18); color: var(--amber); }
  .permits-status-final-passed         { background: rgba(132,204,22,0.18); color: #a3e635; }
  .permits-status-closed               { background: rgba(16,185,129,0.15); color: var(--green, #10b981); }
  .permits-status-failed-inspection    { background: rgba(239,68,68,0.22);  color: var(--red-text); font-weight: 700; }

  .permits-th-expand { width: 28px; padding: 0 !important; }
  .permits-expand-cell { width: 28px; padding: 0 !important; vertical-align: middle; text-align: center; }
  .permits-expand-toggle {
    background: none; border: none; cursor: pointer; padding: 4px 6px;
    color: var(--text-muted); font-size: 14px; line-height: 1;
    border-radius: 4px;
  }
  .permits-expand-toggle:hover { background: rgba(59,130,246,0.10); color: var(--text); }

  .permits-history-row td { background: rgba(0,0,0,0.18); border-top: 1px dashed var(--border-subtle, rgba(255,255,255,0.06)); }
  .permits-history-shell {
    padding: 12px 16px 16px;
    display: flex; flex-direction: column; gap: 10px;
    font-size: 12.5px;
  }
  .permits-history-meta { color: var(--text-muted); display: flex; flex-wrap: wrap; gap: 4px 12px; }
  .permits-history-meta strong { color: var(--text); font-weight: 600; }
  .permits-history-officer { color: var(--text-muted); font-size: 12px; }
  .permits-history-officer strong { color: var(--text); }
  .permits-history-section-title {
    color: var(--text-muted); font-size: 11px; text-transform: uppercase;
    letter-spacing: 0.05em; margin-bottom: 4px;
  }
  .permits-history-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 3px; }
  .permits-history-event, .permits-history-inspection {
    display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
    color: var(--text); padding: 3px 6px; border-radius: 4px;
  }
  .permits-history-event:hover, .permits-history-inspection:hover { background: rgba(255,255,255,0.03); }
  .permits-history-date    { color: var(--text-muted); font-variant-numeric: tabular-nums; min-width: 105px; }
  .permits-history-kind    { color: var(--blue-light, #60a5fa); font-weight: 600; min-width: 180px; }
  .permits-history-subject { color: var(--text); flex: 1; word-break: break-word; }
  .permits-history-itype   { color: #c4a4f7; font-style: italic; }
  .permits-history-istate  { color: var(--text); font-weight: 500; }
  .permits-history-link {
    color: var(--blue-light, #60a5fa); text-decoration: none; font-size: 11px;
    padding: 1px 5px; border-radius: 4px;
  }
  .permits-history-link:hover { background: rgba(59,130,246,0.15); }

  /* v3.3 — project-grouped rows + archived selectable from picker. */
  .permits-group-header td {
    background: rgba(59,130,246,0.10);
    border-top: 2px solid var(--blue, #3b82f6);
    border-bottom: 1px solid var(--border);
    padding: 9px 14px !important;
    color: var(--text);
    font-size: 13px;
    cursor: pointer;
  }
  .permits-group-header td:hover { background: rgba(59,130,246,0.15); }
  .permits-group-header .permits-group-label {
    font-weight: 700; color: var(--text); margin-right: 12px;
  }
  .permits-group-header .permits-group-client {
    color: var(--text-muted); margin-right: 12px;
  }
  .permits-group-header .permits-group-count {
    background: rgba(0,0,0,0.30); color: var(--text-muted);
    padding: 1px 8px; border-radius: 999px; font-size: 11px; font-weight: 600;
    margin-right: 8px; font-variant-numeric: tabular-nums;
  }
  .permits-group-header .permits-group-status { margin-right: 8px; }
  .permits-group-archived td {
    background: rgba(245,158,11,0.05);
    border-top-color: rgba(245,158,11,0.40);
  }
  .permits-group-archived td:hover { background: rgba(245,158,11,0.10); }
  .permits-group-archived-badge {
    background: rgba(245,158,11,0.20); color: var(--amber);
    padding: 1px 7px; border-radius: 999px; font-size: 10px;
    font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  }
  .permits-group-unclaimed td {
    background: rgba(245,158,11,0.10);
    border-top-color: rgba(245,158,11,0.50);
    cursor: default;
  }
  .permits-group-unclaimed td:hover { background: rgba(245,158,11,0.10); }
  .permits-group-unclaimed .permits-group-icon { margin-right: 8px; color: var(--amber); font-size: 14px; }
  .permits-group-unclaimed .permits-group-label { color: var(--amber); }
  .permits-group-unclaimed .permits-group-hint { color: var(--text-muted); font-style: italic; font-size: 12px; margin-left: 6px; }

  /* v3.4 — permit-type badges (temp construction, operating, commercial, etc.). */
  .permits-type-badge {
    display: inline-block; padding: 2px 7px; border-radius: 4px;
    font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em;
    margin-left: 6px; vertical-align: middle; white-space: nowrap;
  }
  .permits-type-temp        { background: rgba(245,158,11,0.22); color: var(--amber); box-shadow: 0 0 0 1px rgba(245,158,11,0.45) inset; }
  .permits-type-operating   { background: rgba(168,85,247,0.18); color: #c4a4f7; }
  .permits-type-commercial  { background: rgba(20,184,166,0.18); color: #5eead4; }
  .permits-type-multi-unit  { background: rgba(99,102,241,0.18); color: var(--purple-soft); }
  .permits-type-residential { background: rgba(148,163,184,0.18); color: var(--text); }
  .permits-type-install     { background: rgba(59,130,246,0.18); color: var(--blue-light, #60a5fa); }

  /* v3.5 — re-link button for already-claimed rows (Matt 2026-05-15:
     "this permit actually belongs to the unit below"). Compact, sits
     beside the status-driven action button; hover-emphasized. */
  .permits-relink-btn {
    font-size: 13px; padding: 4px 8px; margin-left: 4px;
    line-height: 1; vertical-align: middle;
    opacity: 0.55;
  }
  .permits-row:hover .permits-relink-btn { opacity: 1; }

  /* ═══════════════════════════════════════════════════════════════════
     Map view (js/12-map.js)
     A Leaflet-rendered map of every active CC project, with a live crew
     overlay polled from /.netlify/functions/crew-admin. Two-column
     layout: sidebar list (~340px) + map canvas.
     ═══════════════════════════════════════════════════════════════════ */
  #map-view { height: calc(100vh - 130px); }
  .map-shell {
    display: flex; gap: 12px; height: 100%;
  }
  .map-sidebar {
    width: 340px; min-width: 280px; flex-shrink: 0;
    background: var(--panel); border: 1px solid var(--panel-border, #2a3a52);
    border-radius: 12px; padding: 10px;
    display: flex; flex-direction: column;
    overflow: hidden;
  }
  .map-sidebar-head { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
  .map-search {
    width: 100%; padding: 8px 10px; font-size: 13px;
    background: var(--panel-2); color: var(--text-strong);
    border: 1px solid var(--panel-border, #2a3a52); border-radius: 8px;
    outline: none;
  }
  .map-search:focus { border-color: var(--blue, #3b82f6); }
  .map-result-count { font-size: 11px; color: var(--text-muted); padding-left: 2px; }

  /* Status filter chips — clickable pills, one per canonical Project
     Status label. "Active" is default-on. */
  .map-status-chips {
    display: flex; flex-wrap: wrap; gap: 4px;
    padding: 4px 0 8px;
    border-bottom: 1px solid var(--panel-3, #131c2e);
    margin-bottom: 6px;
  }
  .map-status-chip {
    padding: 4px 9px; font-size: 11px; line-height: 1.2;
    background: var(--panel-2, #182338);
    color: var(--text-soft);
    border: 1px solid var(--panel-border, #2a3a52);
    border-radius: 12px; cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
    white-space: nowrap;
  }
  .map-status-chip:hover { color: var(--text-strong); border-color: var(--blue, #3b82f6); }
  .map-status-chip-on {
    background: var(--blue, #3b82f6); color: #fff;
    border-color: var(--blue, #3b82f6);
  }
  .map-status-chip-on:hover { background: var(--blue-hover, #4f8df7); color: #fff; }

  /* Show / hide archived toggle — sits below the status chips. Reads
     as a quiet outlined pill when OFF; lights up grey-tinted when ON
     so the user remembers archived rows are mixed into the result list. */
  .map-sidebar-controls {
    padding: 0 0 8px;
    border-bottom: 1px solid var(--panel-3, #131c2e);
    margin-bottom: 6px;
  }
  .map-archived-toggle {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px; font-size: 11px;
    background: transparent;
    color: var(--text-soft);
    border: 1px solid var(--panel-border, #2a3a52);
    border-radius: 12px; cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
  }
  .map-archived-toggle:hover { color: var(--text-strong); border-color: var(--text-muted); }
  .map-archived-toggle-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: #64748b;
    box-shadow: 0 0 0 1.5px rgba(0,0,0,0.4);
  }
  .map-archived-toggle-on {
    background: rgba(100,116,139,0.18);
    color: var(--text-strong);
    border-color: rgba(100,116,139,0.6);
  }

  .map-legend {
    display: flex; flex-wrap: wrap; gap: 6px 10px;
    padding: 6px 4px 10px; border-bottom: 1px solid var(--panel-3, #131c2e);
    margin-bottom: 6px;
  }
  .map-legend-item {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 11px; color: var(--text-soft);
  }
  .map-pin-sw {
    width: 9px; height: 9px; border-radius: 50%;
    box-shadow: 0 0 0 1.5px rgba(0,0,0,0.35);
  }
  .map-pin-sw-crew {
    background: #f8fafc;
    box-shadow: 0 0 0 2px var(--blue, #3b82f6);
  }

  .map-results { flex: 1; overflow-y: auto; padding-right: 2px; }
  .map-results-divider {
    font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;
    color: var(--text-faint); padding: 10px 4px 4px;
  }
  .map-row {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 8px; border-radius: 8px; cursor: pointer;
    transition: background 0.12s ease;
  }
  .map-row:hover { background: var(--panel-2, #182338); }
  .map-row-sel  { background: var(--blue-soft, rgba(59,130,246,0.14)); }
  .map-row-sel:hover { background: var(--blue-soft, rgba(59,130,246,0.14)); }
  .map-row-warn .map-row-name { color: var(--text-soft); }
  .map-row-dot {
    width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0;
    box-shadow: 0 0 0 1.5px rgba(0,0,0,0.4);
  }
  .map-row-text { flex: 1; min-width: 0; }
  .map-row-name { font-size: 13px; color: var(--text-strong); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .map-row-meta { font-size: 11px; color: var(--text-muted); display: flex; gap: 8px; }
  .map-row-addr { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; min-width: 0; }
  .map-row-addr-none { color: var(--text-faint); font-style: italic; }
  .map-row-status { color: var(--text-soft); white-space: nowrap; }
  .map-row-warn-tag {
    font-size: 10px; padding: 2px 6px; border-radius: 4px;
    background: rgba(239,68,68,0.18); color: var(--red-text); flex-shrink: 0;
  }
  .map-empty { padding: 16px; color: var(--text-muted); text-align: center; font-size: 13px; }

  .map-canvas-wrap {
    flex: 1; position: relative;
    border-radius: 12px; overflow: hidden;
    border: 1px solid var(--panel-border, #2a3a52);
    background: #0a0f1c;
  }
  .map-canvas { width: 100%; height: 100%; background: #0a0f1c; }
  .map-crew-banner {
    position: absolute; top: 10px; right: 10px; z-index: 500;
    padding: 5px 10px; border-radius: 6px;
    background: rgba(15,23,42,0.85); color: var(--text-soft);
    font-size: 11px; backdrop-filter: blur(6px);
    border: 1px solid rgba(148,163,184,0.18);
  }
  .map-crew-banner-stub { background: rgba(245,158,11,0.18); color: var(--amber); border-color: rgba(245,158,11,0.4); }
  .map-crew-banner-idle { background: rgba(15,23,42,0.65); }

  /* Pin glyph — small coloured dot with a ring; the ring brightens when
     the row in the sidebar is selected. */
  .map-pin-icon { position: relative; }
  .map-pin {
    position: absolute; left: 4px; top: 4px;
    width: 14px; height: 14px; border-radius: 50%;
    box-shadow: 0 0 0 2px rgba(15,23,42,0.7), 0 1px 3px rgba(0,0,0,0.5);
  }
  .map-pin-ring {
    position: absolute; left: 0; top: 0;
    width: 22px; height: 22px; border-radius: 50%;
    box-shadow: 0 0 0 2px transparent;
    transition: box-shadow 0.15s ease;
  }
  .map-pin-ring-on { box-shadow: 0 0 0 2px var(--blue-bright, #60a5fa); }

  /* Crew pin — bigger, white with employee initials, blue ring so it
     stands out against the project pins. Pulse animation makes "live"
     read instantly. */
  .map-crew-icon { position: relative; }
  .map-crew-dot {
    position: absolute; left: 2px; top: 2px;
    width: 24px; height: 24px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: #f8fafc; color: #0f172a;
    font-size: 11px; font-weight: 700;
    box-shadow: 0 0 0 2px var(--blue, #3b82f6), 0 2px 6px rgba(0,0,0,0.5);
  }
  .map-crew-ring {
    position: absolute; left: -2px; top: -2px;
    width: 32px; height: 32px; border-radius: 50%;
    box-shadow: 0 0 0 2px rgba(59,130,246,0.6);
    animation: mapCrewPulse 1.8s ease-out infinite;
  }
  @keyframes mapCrewPulse {
    0%   { box-shadow: 0 0 0 2px rgba(59,130,246,0.6); transform: scale(1);    opacity: 0.9; }
    70%  { box-shadow: 0 0 0 10px rgba(59,130,246,0); transform: scale(1.1);  opacity: 0;   }
    100% { box-shadow: 0 0 0 0 rgba(59,130,246,0);    transform: scale(1);    opacity: 0;   }
  }
  /* Stale ping — amber, slower pulse signals "this isn't really live". */
  .map-crew-ring-stale {
    box-shadow: 0 0 0 2px rgba(245,158,11,0.55);
    animation: mapCrewPulseStale 2.6s ease-out infinite;
  }
  @keyframes mapCrewPulseStale {
    0%   { box-shadow: 0 0 0 2px rgba(245,158,11,0.55); transform: scale(1);    opacity: 0.85; }
    70%  { box-shadow: 0 0 0 8px rgba(245,158,11,0);    transform: scale(1.06); opacity: 0;    }
    100% { box-shadow: 0 0 0 0 rgba(245,158,11,0);      transform: scale(1);    opacity: 0;    }
  }
  /* Clock-in only — no live ping yet. Static gray ring, no pulse, so it
     reads as "we know where they punched in, not where they are right now." */
  .map-crew-ring-clockin {
    box-shadow: 0 0 0 2px rgba(148,163,184,0.45);
    animation: none;
  }
  /* GPS source tag chips inside the crew popup. */
  .map-gps-tag {
    display: inline-block; padding: 1px 5px; margin-right: 4px;
    border-radius: 3px; font-size: 10px; font-weight: 700;
    letter-spacing: 0.4px; vertical-align: middle;
  }
  .map-gps-tag-live    { background: rgba(34,197,94,0.22);  color: var(--green-text); box-shadow: 0 0 0 1px rgba(34,197,94,0.45) inset; }
  .map-gps-tag-stale   { background: rgba(245,158,11,0.22); color: #fcd34d; box-shadow: 0 0 0 1px rgba(245,158,11,0.45) inset; }
  .map-gps-tag-clockin { background: rgba(148,163,184,0.22);color: var(--text); box-shadow: 0 0 0 1px rgba(148,163,184,0.45) inset; }

  /* Google Maps InfoWindow theming — the outer chrome is owned by
     Google (rounded white box, close X) and partially style-able via
     the .gm-style-iw-* internal classes. We override the inner content
     to read as a Peak-themed dark popup by default; light theme reverts
     to Google's default white styling. Dark is the default app state
     (the theme bootstrap only sets data-theme="light" when light is on,
     so the dark popup has to be applied without a [data-theme]
     specifier — using [data-theme="dark"] never matched, which is why
     the popup rendered white-on-white). ──────────────────────────── */
  .gm-style .gm-style-iw-c {
    background: var(--panel) !important; color: var(--text-strong);
    border: 1px solid var(--panel-border, #2a3a52);
    box-shadow: 0 8px 24px rgba(0,0,0,0.5);
    border-radius: 10px;
  }
  .gm-style .gm-style-iw-d  { background: var(--panel) !important; overflow: visible !important; }
  .gm-style .gm-style-iw-tc::after { background: var(--panel) !important; }
  .gm-style .gm-ui-hover-effect > span { background-color: var(--text-soft) !important; }
  /* Light-theme: revert to Google's default popup chrome. */
  [data-theme="light"] .gm-style .gm-style-iw-c {
    background: #fff !important; color: #1f2937;
    border: 1px solid #d1d5db; box-shadow: 0 8px 24px rgba(0,0,0,0.18);
  }
  [data-theme="light"] .gm-style .gm-style-iw-d  { background: #fff !important; }
  [data-theme="light"] .gm-style .gm-style-iw-tc::after { background: #fff !important; }
  [data-theme="light"] .gm-style .gm-ui-hover-effect > span { background-color: #6b7280 !important; }

  .map-popup { font-size: 12px; }
  .map-popup-title { font-size: 14px; font-weight: 600; color: var(--text-strong); margin-bottom: 4px; }
  .map-popup-row { color: var(--text-soft); padding: 2px 0; }
  .map-popup-addr { color: var(--text-muted); }
  .map-popup-muted { color: var(--text-muted); font-size: 11px; }
  .map-popup-status { display: flex; align-items: center; gap: 6px; }
  .map-popup-dot {
    width: 8px; height: 8px; border-radius: 50%;
    box-shadow: 0 0 0 1.5px rgba(0,0,0,0.4);
  }
  .map-popup-btn {
    margin-top: 8px; padding: 5px 10px; font-size: 12px;
    background: var(--blue, #3b82f6); color: #fff;
    border: none; border-radius: 6px; cursor: pointer;
    width: 100%;
  }
  .map-popup-btn:hover { background: var(--blue-hover, #4f8df7); }

  /* Rich popup: Street View thumb at top + "On site now" crew section
     + "Scheduled" events section. Set a fixed width so the thumb has
     room to read. */
  .map-popup-rich { width: 280px; max-width: 280px; }
  .map-popup-thumb-wrap {
    margin: -10px -12px 8px;
    border-radius: 9px 9px 0 0;
    overflow: hidden;
    background: #0a0f1c;
  }
  .map-popup-thumb {
    width: 100%; height: 130px;
    background-size: cover; background-position: center;
    border-radius: 0 !important;
  }

  .map-popup-section {
    margin-top: 9px; padding-top: 8px;
    border-top: 1px solid var(--panel-border, #2a3a52);
  }
  .map-popup-section-head {
    font-size: 10px; letter-spacing: 0.6px; text-transform: uppercase;
    color: var(--text-soft); margin-bottom: 5px;
    display: flex; align-items: center;
  }
  .map-popup-pulse {
    display: inline-block; width: 6px; height: 6px;
    border-radius: 50%; background: #22c55e;
    margin-right: 6px;
    animation: mapPopupPulse 1.6s ease-in-out infinite;
  }
  @keyframes mapPopupPulse { 0%,100% { opacity:1 } 50% { opacity:0.4 } }
  .map-popup-crew-row {
    display: flex; justify-content: space-between; align-items: baseline;
    padding: 2px 0; font-size: 12px;
  }
  .map-popup-crew-name { color: var(--text-strong); font-weight: 500; }
  .map-popup-crew-dur  { color: var(--text-soft); font-size: 11px; font-variant-numeric: tabular-nums; }
  .map-popup-event-row { padding: 3px 0; font-size: 12px; }
  .map-popup-event-time { display: block; color: var(--text-muted); font-size: 10.5px; font-variant-numeric: tabular-nums; }
  .map-popup-event-summary { color: var(--text-soft); }
  .map-popup-event-now .map-popup-event-time { color: var(--green-text); font-weight: 700; }
  .map-popup-event-now .map-popup-event-summary { color: var(--text-strong); }
  .map-popup-event-more { color: var(--text-muted); font-style: italic; font-size: 11px; padding-top: 2px; }

  [data-theme="light"] .map-popup-section { border-top-color: #e5e7eb; }
  [data-theme="light"] .map-popup-section-head { color: #6b7280; }
  [data-theme="light"] .map-popup-crew-name { color: #111827; }
  [data-theme="light"] .map-popup-event-summary { color: #374151; }
  [data-theme="light"] .map-popup-event-now .map-popup-event-summary { color: #111827; }
  [data-theme="light"] .map-popup-event-now .map-popup-event-time { color: #15803d; }

  /* Error banner — shown when the Google Maps JS API fails to load
     (key missing, API not enabled, network). Sits in the canvas-wrap
     above the map area so it can't be missed. */
  .map-error-banner {
    position: absolute; inset: 12px;
    background: rgba(15,23,42,0.92);
    border: 1px solid rgba(239,68,68,0.5);
    color: var(--red-text);
    border-radius: 10px;
    padding: 18px 22px;
    font-size: 13px; line-height: 1.5;
    z-index: 600;
    display: flex; align-items: center; justify-content: center;
    text-align: center;
  }

  /* Light theme — Google Maps default styling already reads light; we
     only need to adjust the popup content + crew dot for contrast. */
  [data-theme="light"] .map-canvas,
  [data-theme="light"] .map-canvas-wrap { background: #e8edf3; }
  [data-theme="light"] .map-popup-title { color: #111827; }
  [data-theme="light"] .map-popup-row { color: #374151; }
  [data-theme="light"] .map-popup-addr,
  [data-theme="light"] .map-popup-muted { color: #6b7280; }
  [data-theme="light"] .map-crew-dot { background: #0f172a; color: #f8fafc; }
  [data-theme="light"] .map-crew-banner { background: rgba(255,255,255,0.9); color: #374151; border-color: #d1d5db; }
  .permits-relink-btn:hover { background: rgba(59,130,246,0.18); color: var(--blue-light, #60a5fa); opacity: 1; }

/* ═══════════════════════════════════════════════════════════════════════
   QBO 2-way sync (2026-05-17) — Billing → Invoices + Quotes sub-tabs +
   detail views + send/convert/void modals.
   Spec: shared/docs/QBO-TWO-WAY-SYNC-SPEC.md
   ═══════════════════════════════════════════════════════════════════════ */

.qbo-list-view, .qbo-detail-view { padding: 4px 0 24px; }

/* Summary cards (Invoices sub-tab only). Sticky so the unpaid/paid totals
   stay visible as Matt scrolls a long list — QBO loses these on scroll,
   easy win to keep them pinned. The pseudo-element bleed below extends
   the page-bg behind the cards so rows scrolling underneath don't peek
   through the 16px gap. */
.qbo-summary-cards {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
  margin-bottom: 16px;
  position: sticky; top: 0; z-index: 5;
  padding: 4px 0 12px;
  background: var(--bg);
}
.qbo-summary-cards::before {
  content: ''; position: absolute;
  left: -16px; right: -16px; top: 0; bottom: 0;
  background: var(--bg); z-index: -1;
}
.qbo-summary-card {
  background: var(--panel); border: 1px solid var(--panel-2);
  border-radius: 8px; padding: 14px 16px;
}
.qbo-sum-label { font-size: 13px; color: var(--text-muted, #94a3b8); margin-bottom: 6px; }
.qbo-sum-label b { color: var(--text, #e2e8f0); font-size: 22px; font-weight: 700; }
.qbo-sum-figures { display: flex; justify-content: space-between; margin: 8px 0 12px; font-size: 12px; gap: 16px; }
.qbo-sum-figures > div { display: flex; flex-direction: column; gap: 2px; }
.qbo-sum-figures > .qbo-sum-figright { align-items: flex-end; text-align: right; }
.qbo-fig-label { color: var(--text-muted, #94a3b8); font-size: 11px; }
.qbo-fig-val   { color: var(--text, #e2e8f0); font-size: 14px; font-weight: 600; }
.qbo-sum-bar { height: 6px; background: var(--panel-3, #131c2e); border-radius: 3px; overflow: hidden; }
.qbo-sum-bar-fill { height: 100%; transition: width 250ms ease-out; }
.qbo-sum-bar-fill-orange { background: #f59e0b; }
.qbo-sum-bar-fill-green  { background: #10b981; }

/* Filter row above each sub-tab table. Replaced single show-paid checkbox
   with proper Status + Date dropdowns 2026-05-18 — makes the view feel
   like a tool, not a debug toggle. */
.qbo-filter-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 12px; padding: 8px 0;
}
.qbo-filter-group { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.qbo-filter-label {
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-muted, #94a3b8);
  margin-right: 4px;
}
.qbo-filter-select {
  appearance: none; -webkit-appearance: none;
  padding: 7px 30px 7px 12px;
  background: var(--panel-3) url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3e%3cpath d='M1 1l4 4 4-4' stroke='%236f83a8' stroke-width='1.4' fill='none'/%3e%3c/svg%3e") no-repeat right 10px center;
  border: 1px solid var(--border); border-radius: 6px;
  color: var(--text); font-size: 13px; cursor: pointer;
  transition: border-color 100ms ease, box-shadow 100ms ease;
  min-width: 150px;
}
.qbo-filter-select:hover { border-color: var(--border-strong); }
.qbo-filter-select:focus {
  outline: none; border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(59,130,246,0.15);
}
.qbo-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--text, #e2e8f0); cursor: pointer;
}
.qbo-toggle input[type="checkbox"] { cursor: pointer; }
.qbo-create-btn { font-size: 13px; }

/* List tables. Lighter row dividers + 14→16px vertical padding (2026-05-18)
   to give rows breathing room and stop the wall-of-data feel. Customer
   column gets weight-600 + full text color; everything else mutes one shade
   so the eye lands on the right thing. */
.qbo-table-wrap { background: var(--panel); border: 1px solid var(--panel-2); border-radius: 8px; overflow: hidden; }
.qbo-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.qbo-table thead th {
  text-align: left; font-weight: 600; font-size: 11px; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-muted, #94a3b8);
  padding: 10px 14px; border-bottom: 1px solid var(--panel-2);
  background: var(--panel-2);
}
.qbo-table tbody td {
  padding: 14px 14px; border-bottom: 1px solid rgba(148,163,184,0.08);
  color: var(--text-soft, #94a3b8); vertical-align: middle;
  font-weight: 400;
}
.qbo-table tbody tr:last-child td { border-bottom: none; }
.qbo-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.qbo-table thead th.num { text-align: right; }

/* Per-column emphasis. Customer = primary focal point on the row; the
   amount is the secondary "headline" number; everything else recedes. */
.qbo-table tbody td.qbo-col-customer { color: var(--text); font-weight: 600; }
.qbo-table tbody td.qbo-col-amount   { color: var(--text); font-weight: 600; }
.qbo-table tbody td.qbo-col-jobname  { color: var(--text-soft, #94a3b8); }
.qbo-table tbody td.qbo-col-date,
.qbo-table tbody td.qbo-col-docnum,
.qbo-table tbody td.qbo-col-address  { color: var(--text-muted, #94a3b8); font-size: 12.5px; }

[data-theme="light"] .qbo-table tbody td { border-color: #f1f3f5; }
[data-theme="light"] .qbo-table tbody td.qbo-col-customer,
[data-theme="light"] .qbo-table tbody td.qbo-col-amount { color: #111827; }
[data-theme="light"] .qbo-table tbody td.qbo-col-jobname,
[data-theme="light"] .qbo-table tbody td.qbo-col-date,
[data-theme="light"] .qbo-table tbody td.qbo-col-docnum,
[data-theme="light"] .qbo-table tbody td.qbo-col-address { color: #6b7280; }

/* Sortable variant — clickable headers with hover state. Arrow glyph
   is baked into the header text by the renderer ("▲" / "▼"); CSS just
   needs to make the click target obvious. */
.qbo-table-sortable thead th[data-sort] {
  cursor: pointer;
  user-select: none;
  transition: color 100ms ease, background 100ms ease;
}
.qbo-table-sortable thead th[data-sort]:hover {
  color: var(--text, #e2e8f0);
  background: var(--panel-3, var(--panel-2));
}
.qbo-row { cursor: pointer; transition: background 100ms ease; position: relative; }
.qbo-row:hover { background: var(--blue-overlay, rgba(96,165,250,0.06)); }

/* Hover-revealed inline row actions (2026-05-18). Hidden by default to
   keep rows visually clean; appear on row hover. Buttons stop click
   propagation so they don't also trigger the row-click → detail-view nav.
   "Mark paid" deliberately omitted per Matt's payments-stay-in-QBO rule —
   the actions are Send / Re-send and Open-in-QBO only. */
.qbo-row-actions-cell {
  padding: 0 8px !important;
  width: 1%;       /* shrink-to-content so the column never steals width */
  white-space: nowrap;
}
.qbo-row-actions {
  display: inline-flex; gap: 4px;
  opacity: 0; transition: opacity 100ms ease;
}
.qbo-row:hover .qbo-row-actions,
.qbo-row:focus-within .qbo-row-actions { opacity: 1; }
.qbo-row-action {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px;
  background: transparent; border: 1px solid transparent;
  border-radius: 6px; cursor: pointer; color: var(--text-muted);
  text-decoration: none;
  transition: background 100ms ease, color 100ms ease, border-color 100ms ease;
}
.qbo-row-action:hover {
  background: var(--panel-2); color: var(--blue-bright);
  border-color: var(--border);
}
.qbo-row-action svg { width: 14px; height: 14px; }
[data-theme="light"] .qbo-row-action:hover { background: #f3f4f6; color: #1d4ed8; border-color: #e5e7eb; }

/* Status chips + sub-line. Severity-tiered overdue chips (2026-05-18):
   tier by days-overdue so a wall of 9-day "overdue" rows doesn't drown
   out the single 35-day row that actually needs attention.
     0-14d  → mild  (muted slate, "this is normal")
     15-30d → warn  (amber, "starting to age")
     31+d   → bad   (red, "go get the cheque")
   `qbo-st-overdue` is kept as a legacy alias = warn so any pre-existing
   callers still render sensibly. */
.qbo-st-cell { display: flex; flex-direction: column; gap: 2px; align-items: flex-start; }
.qbo-st-chip {
  display: inline-flex; align-items: center; padding: 2px 9px;
  border-radius: 10px; font-size: 11px; font-weight: 500;
  white-space: nowrap; width: max-content;
  letter-spacing: 0.01em;
}
.qbo-st-sub  { color: var(--text-muted, #94a3b8); font-size: 11px; }
.qbo-st-pending       { background: rgba(148,163,184,0.16); color: var(--text); }
.qbo-st-accepted      { background: rgba(16,185,129,0.16);  color: #34d399; }
.qbo-st-closed        { background: rgba(96,165,250,0.16);  color: var(--blue-bright); }
.qbo-st-rejected      { background: rgba(239,68,68,0.16);   color: var(--red-bright); }
.qbo-st-expired       { background: rgba(245,158,11,0.16);  color: var(--amber); }
.qbo-st-paid          { background: rgba(16,185,129,0.16);  color: #34d399; }
.qbo-st-open          { background: rgba(96,165,250,0.16);  color: var(--blue-bright); }
.qbo-st-due           { background: rgba(96,165,250,0.16);  color: var(--blue-bright); }
.qbo-st-overdue-mild  { background: rgba(148,163,184,0.16); color: var(--text); }
.qbo-st-overdue-warn  { background: rgba(245,158,11,0.16);  color: var(--amber); }
.qbo-st-overdue-bad   { background: rgba(239,68,68,0.18);   color: var(--red-bright); }
.qbo-st-overdue       { background: rgba(245,158,11,0.16);  color: var(--amber); }  /* legacy alias = warn */

/* Light-mode chip text needs higher-contrast colors than the muted dark
   versions above (which sit on white otherwise). Backgrounds keep the
   same low-opacity tint, text shifts to the saturated 600-shade. */
[data-theme="light"] .qbo-st-pending      { color: #475569; }
[data-theme="light"] .qbo-st-accepted     { color: #047857; }
[data-theme="light"] .qbo-st-closed       { color: #1d4ed8; }
[data-theme="light"] .qbo-st-rejected     { color: #b91c1c; }
[data-theme="light"] .qbo-st-expired      { color: #b45309; }
[data-theme="light"] .qbo-st-paid         { color: #047857; }
[data-theme="light"] .qbo-st-open         { color: #1d4ed8; }
[data-theme="light"] .qbo-st-due          { color: #1d4ed8; }
[data-theme="light"] .qbo-st-overdue-mild { color: #475569; }
[data-theme="light"] .qbo-st-overdue-warn { color: #b45309; }
[data-theme="light"] .qbo-st-overdue-bad  { color: #b91c1c; }
[data-theme="light"] .qbo-st-overdue      { color: #b45309; }

.qbo-loading { padding: 32px 24px; text-align: center; color: var(--text-muted, #94a3b8); font-size: 13px; }
.qbo-empty   { padding: 32px 24px; text-align: center; color: var(--text-muted, #94a3b8); font-size: 13px; }
.qbo-empty-inline { padding: 12px 14px; color: var(--text-muted, #94a3b8); font-size: 12px; font-style: italic; }

/* Detail view. */
.qbo-detail-topbar {
  display: flex; align-items: center; gap: 16px;
  margin-bottom: 16px; padding-bottom: 12px;
  border-bottom: 1px solid var(--panel-2);
}
.qbo-detail-title {
  font-size: 18px; font-weight: 600; color: var(--text, #e2e8f0);
  display: flex; align-items: center; gap: 12px; flex: 1;
}
.qbo-detail-openqbo {
  font-size: 12px; color: var(--blue); text-decoration: none;
  padding: 4px 10px; border: 1px solid var(--blue-soft, rgba(59,130,246,0.14));
  border-radius: 4px;
}
.qbo-detail-openqbo:hover { background: var(--blue-soft, rgba(59,130,246,0.14)); }
.qbo-detail-actions {
  display: flex; gap: 8px; margin-bottom: 20px; flex-wrap: wrap;
}
.qbo-detail-grid {
  display: grid; grid-template-columns: 1fr; gap: 16px;
  margin-bottom: 20px;
}
.qbo-detail-meta {
  background: var(--panel); border: 1px solid var(--panel-2);
  border-radius: 6px; padding: 12px 16px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 6px 24px; font-size: 13px; color: var(--text, #e2e8f0);
}
.qbo-detail-meta b { color: var(--text-muted, #94a3b8); font-weight: 600; margin-right: 4px; }

.qbo-detail-section { margin-bottom: 24px; }
.qbo-detail-section-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted, #94a3b8);
  margin-bottom: 8px;
}
.qbo-detail-note {
  background: var(--panel); border: 1px solid var(--panel-2);
  border-radius: 6px; padding: 10px 14px; font-size: 13px;
  color: var(--text, #e2e8f0); white-space: pre-wrap;
}

/* Totals block under line items. */
.qbo-totals-block {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: 4px; padding: 12px 14px; font-size: 13px;
  border-top: 1px solid var(--panel-2);
  background: var(--panel-2);
}
.qbo-totals-block > div {
  display: grid; grid-template-columns: 120px 100px; gap: 16px;
  color: var(--text, #e2e8f0);
}
.qbo-totals-block > div > span:first-child { color: var(--text-muted, #94a3b8); text-align: right; }
.qbo-totals-block > div > span:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.qbo-totals-final { font-weight: 700; padding-top: 4px; border-top: 1px solid var(--panel-2); }

/* Danger button variant for Void / Delete. */
.qbo-btn-danger {
  background: rgba(239,68,68,0.12); color: var(--red-bright);
  border: 1px solid rgba(239,68,68,0.24);
}
.qbo-btn-danger:hover { background: rgba(239,68,68,0.20); }

/* QBO sync modals — overlay + card styles. Mirrors the .roll-eom-modal
   pattern so qbo-send / qbo-convert / qbo-void / qbo-activity modals
   render as centered overlays instead of in-flow blocks. */
.qbo-modal {
  position: fixed; inset: 0; background: rgba(0,0,0,0.65);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000; padding: 20px;
}
.qbo-modal .modal-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 12px;
  width: min(520px, 100%); max-height: 90vh; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 50px rgba(0,0,0,0.6);
}
.qbo-modal .modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
.qbo-modal .modal-header h3 {
  margin: 0; font-size: 16px; color: var(--text-strong); font-weight: 600;
}
.qbo-modal .modal-close {
  background: transparent; color: var(--text-soft); border: none;
  font-size: 22px; cursor: pointer; padding: 0; line-height: 1;
  width: 28px; height: 28px;
}
.qbo-modal .modal-close:hover { color: var(--text-strong); }
.qbo-modal .modal-body {
  padding: 18px 20px; overflow-y: auto; flex: 1 1 auto;
}
.qbo-modal .modal-footer {
  padding: 14px 20px; border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: 10px; flex-shrink: 0;
}
.qbo-modal .modal-footer .button {
  background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
  padding: 9px 16px; border-radius: 8px; font-size: 13px; font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.qbo-modal .modal-footer .button:hover { background: var(--row-hover); color: var(--text-strong); }
.qbo-modal .modal-footer .button-primary {
  background: rgba(59,130,246,0.18); color: var(--blue-lightest); border-color: rgba(59,130,246,0.45);
}
.qbo-modal .modal-footer .button-primary:hover { background: rgba(59,130,246,0.28); }
.qbo-modal .modal-footer .button:disabled { opacity: 0.5; cursor: not-allowed; }
.qbo-modal-label {
  display: block; margin: 14px 0 6px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-muted, #94a3b8);
}
.qbo-modal-label small { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--text-muted, #94a3b8); margin-left: 6px; }
.qbo-modal-input {
  width: 100%; padding: 8px 12px; font-size: 14px;
  background: var(--panel-2); color: var(--text, #e2e8f0);
  border: 1px solid var(--panel-3, #131c2e); border-radius: 4px;
  box-sizing: border-box;
}
.qbo-modal-input:focus { outline: none; border-color: var(--blue); }
.qbo-modal-body-preview {
  margin-top: 6px; padding: 10px 12px;
  background: var(--panel-3, #131c2e); border: 1px dashed var(--panel-2);
  border-radius: 4px; font-size: 12px; color: var(--text-muted, #94a3b8);
  font-style: italic;
}
.qbo-modal-hint {
  margin-top: 12px; font-size: 12px; color: var(--text-muted, #94a3b8);
}
.qbo-modal-hint-warn {
  padding: 8px 12px; background: rgba(245,158,11,0.08);
  border-left: 3px solid #f59e0b; border-radius: 0 4px 4px 0;
  color: var(--amber); font-style: normal;
}
.qbo-convert-summary {
  background: var(--panel-2); padding: 10px 14px;
  border-radius: 4px; font-size: 13px;
  margin-bottom: 4px; color: var(--text, #e2e8f0);
  display: flex; flex-direction: column; gap: 4px;
}
.qbo-convert-summary b { color: var(--text-muted, #94a3b8); font-weight: 600; margin-right: 4px; }

/* Light-theme tweaks. */
[data-theme="light"] .qbo-summary-card,
[data-theme="light"] .qbo-table-wrap,
[data-theme="light"] .qbo-detail-meta,
[data-theme="light"] .qbo-detail-note {
  background: #ffffff; border-color: #e5e7eb;
}
[data-theme="light"] .qbo-table thead th { background: #f9fafb; color: #6b7280; border-color: #e5e7eb; }
[data-theme="light"] .qbo-table tbody td { color: #111827; border-color: #f3f4f6; }
[data-theme="light"] .qbo-sum-label b,
[data-theme="light"] .qbo-fig-val,
[data-theme="light"] .qbo-detail-title,
[data-theme="light"] .qbo-detail-meta,
[data-theme="light"] .qbo-detail-note { color: #111827; }
[data-theme="light"] .qbo-totals-block { background: #f9fafb; border-color: #e5e7eb; }
[data-theme="light"] .qbo-totals-block > div { color: #111827; }
[data-theme="light"] .qbo-modal-input { background: #ffffff; color: #111827; border-color: #d1d5db; }
[data-theme="light"] .qbo-modal-body-preview { background: #f9fafb; border-color: #e5e7eb; color: #6b7280; }

/* Activity modal timeline (2026-05-17). */
.qbo-activity-modal .modal-card { max-width: 480px; }
.qbo-activity-timeline {
  list-style: none; padding: 4px 0; margin: 0;
  display: flex; flex-direction: column; gap: 14px;
}
.qbo-activity-event { position: relative; padding-left: 24px; }
.qbo-activity-event::before {
  content: ''; position: absolute; left: 5px; top: 14px; bottom: -14px;
  width: 2px; background: var(--panel-2);
}
.qbo-activity-event:last-child::before { display: none; }
.qbo-activity-dot {
  position: absolute; left: 0; top: 4px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--blue);
  border: 2px solid var(--panel);
  box-shadow: 0 0 0 1px var(--panel-2);
}
.qbo-activity-sent .qbo-activity-dot    { background: #10b981; }
.qbo-activity-paid .qbo-activity-dot    { background: #10b981; }
.qbo-activity-status .qbo-activity-dot  { background: #60a5fa; }
.qbo-activity-error .qbo-activity-dot   { background: #ef4444; }
.qbo-activity-pending .qbo-activity-dot { background: #94a3b8; }
.qbo-activity-updated .qbo-activity-dot { background: #94a3b8; }
.qbo-activity-created .qbo-activity-dot { background: #cbd5e1; }
.qbo-activity-body { display: flex; flex-direction: column; gap: 2px; }
.qbo-activity-label { font-size: 13px; font-weight: 600; color: var(--text, #e2e8f0); }
.qbo-activity-ts {
  font-size: 12px; color: var(--text-muted, #94a3b8);
  font-variant-numeric: tabular-nums;
}
.qbo-activity-ts small { opacity: 0.7; margin-left: 2px; }
.qbo-activity-sub { font-size: 12px; color: var(--text, #e2e8f0); opacity: 0.85; }
.qbo-activity-empty {
  padding: 24px; text-align: center;
  color: var(--text-muted, #94a3b8); font-size: 13px;
}
.qbo-activity-footnote {
  margin-top: 18px; padding: 10px 12px;
  background: var(--panel-2); border-radius: 4px;
  font-size: 11px; color: var(--text-muted, #94a3b8); line-height: 1.5;
}
.qbo-activity-footnote a { color: var(--blue); text-decoration: none; }
.qbo-activity-footnote a:hover { text-decoration: underline; }

[data-theme="light"] .qbo-activity-event::before { background: #e5e7eb; }
[data-theme="light"] .qbo-activity-dot { border-color: #ffffff; box-shadow: 0 0 0 1px #e5e7eb; }
[data-theme="light"] .qbo-activity-label,
[data-theme="light"] .qbo-activity-sub { color: #111827; }
[data-theme="light"] .qbo-activity-footnote { background: #f3f4f6; color: #6b7280; }

/* ═══════════════════════════════════════════════════════════════════════
   Global search bar in the page header (2026-05-17)
   Searches across Clients / Jobs+Projects / Invoices / Quotes / Crew /
   Fleet. Cmd/Ctrl-K to focus. Wired in 07-views.js (wireGlobalSearch).
   ═══════════════════════════════════════════════════════════════════════ */

.page-header-search {
  /* Centered between the two flex:1 1 0 side columns, and a bit bigger —
     Matt uses it constantly (2026-07-05). flex:0 1 to hold ~640px but shrink
     on tighter screens; min-width guards against collapse before it wraps. */
  position: relative; flex: 0 1 640px; width: 640px; max-width: 640px; min-width: 260px;
  margin: 0 24px;
  display: flex; align-items: center;
  background: var(--panel-2); border: 1px solid var(--panel-3, #131c2e);
  border-radius: 10px; padding: 0 12px;
  transition: border-color 100ms, background 100ms;
}
/* On mid-width laptops the full account card on the right needs room; trim the
   search's basis so the header stays on ONE row instead of wrapping the
   controls to a second line. Wide screens (Matt's ~1900px) keep the full 640. */
@media (max-width: 1680px) {
  .page-header-search { flex-basis: 540px; width: 540px; }
}
.page-header-search:focus-within {
  border-color: var(--blue);
  background: var(--panel);
}
.ph-search-icon {
  width: 18px; height: 18px;
  color: var(--text-muted, #94a3b8);
  flex-shrink: 0;
}
.ph-search-input {
  flex: 1; min-width: 0;
  background: transparent; border: none; outline: none;
  padding: 11px 12px; font-size: 14.5px;
  color: var(--text, #e2e8f0);
}
.ph-search-input::placeholder { color: var(--text-muted, #94a3b8); }
.ph-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }
.ph-search-hint {
  font-size: 11px; color: var(--text-muted, #94a3b8);
  padding: 2px 6px; border-radius: 3px;
  background: var(--panel-3, #131c2e);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  flex-shrink: 0;
}
.page-header-search:focus-within .ph-search-hint { display: none; }

.ph-search-results {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0;
  background: var(--panel); border: 1px solid var(--panel-2);
  border-radius: 8px; box-shadow: 0 8px 28px rgba(0,0,0,0.32);
  max-height: 480px; overflow-y: auto;
  z-index: 100;
}
.ph-search-empty,
.ph-search-noresults {
  padding: 16px 14px; font-size: 13px;
  color: var(--text-muted, #94a3b8); text-align: center;
}
.ph-search-noresults small { display: block; font-size: 11px; margin-top: 4px; }

.ph-search-group { border-bottom: 1px solid var(--panel-2); }
.ph-search-group:last-child { border-bottom: none; }
.ph-search-group-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted, #94a3b8);
  padding: 8px 14px 4px;
}

.ph-search-result {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; cursor: pointer;
  color: var(--text, #e2e8f0); font-size: 13px;
  transition: background 80ms;
}
.ph-search-result:hover,
.ph-search-result.is-active {
  background: var(--blue-overlay, rgba(96,165,250,0.08));
}
.ph-search-result-icon {
  width: 18px; height: 18px; flex-shrink: 0;
  color: var(--text-muted, #94a3b8);
}
.ph-search-result-body {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
}
.ph-search-result-title {
  font-weight: 500; color: var(--text, #e2e8f0);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ph-search-result-sub {
  font-size: 11px; color: var(--text-muted, #94a3b8);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ph-search-result-side {
  font-size: 11px; color: var(--text-muted, #94a3b8);
  margin-left: auto; flex-shrink: 0;
}
.ph-search-result mark {
  background: var(--blue-soft, rgba(59,130,246,0.24));
  color: inherit;
  padding: 0 1px; border-radius: 2px;
}
.ph-search-loading {
  padding: 6px 14px; font-size: 11px; font-style: italic;
  color: var(--text-muted, #94a3b8);
  border-bottom: 1px solid var(--panel-2);
}

/* Hide the search bar on very narrow viewports to avoid header crowding. */
@media (max-width: 720px) {
  .page-header-search { display: none; }
}

/* Light-theme overrides. */
[data-theme="light"] .page-header-search {
  background: #f3f4f6; border-color: #e5e7eb;
}
[data-theme="light"] .page-header-search:focus-within { background: #ffffff; }
[data-theme="light"] .ph-search-input { color: #111827; }
[data-theme="light"] .ph-search-hint { background: #e5e7eb; color: #6b7280; }
[data-theme="light"] .ph-search-results { background: #ffffff; border-color: #e5e7eb; }
[data-theme="light"] .ph-search-result-title { color: #111827; }
[data-theme="light"] .ph-search-result:hover,
[data-theme="light"] .ph-search-result.is-active { background: #f3f4f6; }
/* ═══════════════════════════════════════════════════════════════════════
   Reviews (Reports > Reviews) — js/13-reviews.js
   ═══════════════════════════════════════════════════════════════════════
   Stats banner at top, optional Add-Review form card below, then a table
   of all reviews. Re-uses .button + the CRM dark-theme variables. The
   reviews-stat numbers are intentionally big so the unmatched count
   reads as a clear call to action from across the room. */

.reviews-page { display: flex; flex-direction: column; gap: 20px; padding: 0; }

.reviews-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr) auto;
  gap: 12px;
  align-items: stretch;
  background: var(--panel-3);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
}
.reviews-stat {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
}
.reviews-stat-num { font-size: 28px; font-weight: 700; color: var(--text-strong); line-height: 1.1; }
.reviews-stat-lbl { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.reviews-stat-matched   .reviews-stat-num { color: #5fb371; }
.reviews-stat-notclient .reviews-stat-num { color: var(--text-soft); }
.reviews-stat-unmatched .reviews-stat-num { color: #f0b25a; }
.reviews-stats-actions { display: flex; align-items: center; gap: 8px; }

/* Sync from Google button — green tint for the authorized + ready state to
   visually separate it from + Add review (neutral). The auth state gets a
   subtle warning tint to draw the eye on first visit. */
.reviews-sync-btn {
  background: rgba(34, 197, 94, 0.10);
  border: 1px solid rgba(34, 197, 94, 0.35);
  color: var(--green);
  font-weight: 500;
}
.reviews-sync-btn:hover:not([disabled]) {
  background: rgba(34, 197, 94, 0.18);
  border-color: rgba(34, 197, 94, 0.55);
}
.reviews-sync-btn[disabled] { opacity: 0.6; cursor: progress; }
.reviews-sync-btn-auth {
  background: rgba(59, 130, 246, 0.10);
  border-color: rgba(59, 130, 246, 0.40);
  color: var(--blue-bright);
}
.reviews-sync-btn-auth:hover {
  background: rgba(59, 130, 246, 0.18);
  border-color: rgba(59, 130, 246, 0.60);
}
body.light-mode .reviews-sync-btn      { color: #16a34a; background: rgba(34,197,94,0.08); border-color: rgba(34,197,94,0.30); }
body.light-mode .reviews-sync-btn-auth { color: #2563eb; background: rgba(59,130,246,0.08); border-color: rgba(59,130,246,0.30); }

/* Empty-state "or" divider between sync CTA and manual fallback */
.reviews-empty-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0 14px;
  color: var(--text-muted); font-size: 11px;
  text-transform: uppercase; letter-spacing: 0.08em;
}
.reviews-empty-divider::before,
.reviews-empty-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.reviews-empty-fallback { font-size: 13px; color: var(--text-soft); margin: 0 0 10px 0; }
.reviews-empty-error {
  margin-top: 12px; padding: 8px 12px;
  background: rgba(239, 68, 68, 0.10);
  border: 1px solid rgba(239, 68, 68, 0.30);
  border-radius: 6px; color: var(--red-text); font-size: 12px;
}
body.light-mode .reviews-empty-error { color: #b91c1c; background: rgba(239,68,68,0.06); border-color: rgba(239,68,68,0.25); }

/* GBP target picker (modal overlay) */
.reviews-picker-overlay {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 9000; padding: 20px;
}
.reviews-picker {
  background: var(--panel-3);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  width: 100%; max-width: 540px;
  max-height: 80vh; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
}
.reviews-picker-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.reviews-picker-head h3 { margin: 0; font-size: 15px; font-weight: 600; color: var(--text-strong); }
.reviews-picker-close {
  background: transparent; border: none; color: var(--text-muted);
  font-size: 22px; line-height: 1; cursor: pointer; padding: 4px 10px;
  border-radius: 6px;
}
.reviews-picker-close:hover { background: var(--panel-2); color: var(--text-strong); }
.reviews-picker-body { padding: 14px 18px; overflow: auto; }
.reviews-picker-loading { color: var(--text-muted); padding: 24px 0; text-align: center; font-size: 13px; }
.reviews-picker-error {
  color: var(--red-text); padding: 12px 14px;
  background: rgba(239, 68, 68, 0.10);
  border: 1px solid rgba(239, 68, 68, 0.30);
  border-radius: 6px; font-size: 13px; line-height: 1.5;
}
body.light-mode .reviews-picker-error { color: #b91c1c; background: rgba(239,68,68,0.06); border-color: rgba(239,68,68,0.25); }
.reviews-picker-section-label {
  font-size: 11px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.04em;
  margin-bottom: 8px;
}
.reviews-picker-list { display: flex; flex-direction: column; gap: 6px; }
.reviews-picker-row {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  text-align: left;
  cursor: pointer;
  display: flex; flex-direction: column; gap: 3px;
  transition: background 120ms, border-color 120ms;
}
.reviews-picker-row:hover {
  background: var(--panel);
  border-color: var(--blue);
}
.reviews-picker-row-main { color: var(--text-strong); font-weight: 500; font-size: 14px; }
.reviews-picker-row-sub  { color: var(--text-muted); font-size: 12px; }

/* ── Tab strip (All Reviews | Ask Queue) ────────────────────────────────── */
.reviews-tabstrip {
  display: flex; gap: 4px;
  border-bottom: 1px solid var(--border);
  margin: 8px 0 16px;
}
.reviews-tab {
  background: transparent; border: none;
  color: var(--text-soft);
  padding: 10px 16px;
  font-size: 13px; font-weight: 500;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  display: inline-flex; align-items: center; gap: 8px;
  transition: color 120ms, border-color 120ms;
}
.reviews-tab:hover { color: var(--text-strong); }
.reviews-tab-active {
  color: var(--blue-light);
  border-bottom-color: var(--blue);
}
body.light-mode .reviews-tab-active { color: var(--blue); }
.reviews-tab-badge {
  background: rgba(59, 130, 246, 0.18);
  color: var(--blue-light);
  padding: 1px 8px;
  border-radius: 10px;
  font-size: 11px; font-weight: 600;
}
body.light-mode .reviews-tab-badge { background: rgba(59,130,246,0.12); color: var(--blue); }

/* ── Setup banner (review URL not set) ──────────────────────────────────── */
.reviews-setup-banner {
  display: flex; gap: 14px; align-items: flex-start;
  background: rgba(245, 158, 11, 0.08);
  border: 1px solid rgba(245, 158, 11, 0.30);
  border-radius: 10px;
  padding: 14px 18px;
  margin-bottom: 14px;
}
.reviews-setup-banner-icon { font-size: 18px; line-height: 1.3; }
.reviews-setup-banner-body { flex: 1; }
.reviews-setup-banner-body strong { color: var(--text-strong); font-size: 14px; }
.reviews-setup-banner-body p { color: var(--text-soft); font-size: 13px; margin: 6px 0 10px; line-height: 1.5; }
.reviews-setup-banner-body code {
  background: var(--panel-2); padding: 1px 6px; border-radius: 4px;
  font-size: 12px; color: var(--text-strong);
}
.reviews-setup-banner-body a { color: var(--blue-light); text-decoration: underline; }
body.light-mode .reviews-setup-banner-body a { color: var(--blue); }

/* ── Ask Queue table ──────────────────────────────────────────────────────── */
.ask-queue-wrap { display: flex; flex-direction: column; gap: 12px; }
.ask-queue-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.ask-queue-header-actions { display: flex; gap: 8px; }
.ask-queue-filter {
  background: var(--panel-3);
  border: 1px solid var(--border);
  color: var(--text-strong);
  padding: 7px 28px 7px 12px;
  border-radius: 6px;
  font-size: 13px;
  min-width: 220px;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M2 4l4 4 4-4z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
}
.ask-queue-loading, .ask-queue-empty, .ask-queue-error {
  padding: 24px 18px;
  background: var(--panel-3);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text-soft);
  font-size: 13px;
  text-align: center;
  line-height: 1.5;
}
.ask-queue-error {
  color: var(--red-text);
  background: rgba(239, 68, 68, 0.08);
  border-color: rgba(239, 68, 68, 0.30);
}
body.light-mode .ask-queue-error { color: #b91c1c; background: rgba(239,68,68,0.06); border-color: rgba(239,68,68,0.25); }
.ask-queue-error button { margin-top: 10px; }

.ask-queue-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel-3);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  font-size: 13px;
}
.ask-queue-table thead th {
  background: var(--panel-2);
  color: var(--text-muted);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 10px 14px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.ask-queue-table tbody td {
  padding: 12px 14px;
  border-bottom: 1px solid rgba(148,163,184,0.08);
  vertical-align: middle;
  color: var(--text-soft);
}
body.light-mode .ask-queue-table tbody td { border-bottom-color: #f1f3f5; }
.ask-queue-table tbody tr:last-child td { border-bottom: none; }
.ask-queue-table tbody tr:hover { background: rgba(148,163,184,0.04); }
.ask-queue-amt { text-align: right; font-variant-numeric: tabular-nums; }
.ask-queue-actions-th { text-align: right; }
.ask-queue-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.ask-queue-sortable:hover { color: var(--text-soft); }
.ask-queue-sort-active { color: var(--text-strong); }
.ask-queue-actions { text-align: right; white-space: nowrap; }
.ask-queue-cust-name { color: var(--text-strong); font-weight: 500; }
.ask-queue-cust-contact { font-size: 11px; color: var(--text-muted); margin-top: 2px; display: flex; gap: 6px; }
.ask-queue-cust-contact-none { font-style: italic; opacity: 0.7; }

.ask-queue-btn {
  display: inline-flex; align-items: center;
  padding: 4px 10px;
  margin-left: 4px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text-soft);
  border-radius: 5px;
  font-size: 12px;
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.ask-queue-btn:hover:not([disabled]) {
  background: var(--panel);
  color: var(--text-strong);
  border-color: var(--blue);
}
.ask-queue-btn[disabled] { opacity: 0.4; cursor: not-allowed; }
.ask-queue-btn-text  { color: var(--green); border-color: rgba(34, 197, 94, 0.35); }
.ask-queue-btn-email { color: var(--blue-bright); border-color: rgba(59, 130, 246, 0.35); }
.ask-queue-btn-defer { color: #f0b25a; }
.ask-queue-btn-never { color: var(--red-text); font-weight: 700; }
.ask-queue-btn-undo  { color: var(--text-muted); }
body.light-mode .ask-queue-btn-text  { color: #16a34a; border-color: rgba(34,197,94,0.30); }
body.light-mode .ask-queue-btn-email { color: #2563eb; border-color: rgba(59,130,246,0.30); }
body.light-mode .ask-queue-btn-defer { color: #d97706; }
body.light-mode .ask-queue-btn-never { color: #b91c1c; }

.ask-queue-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px; font-weight: 500;
  background: rgba(148,163,184,0.12);
  color: var(--text-muted);
  white-space: nowrap;
}
.ask-queue-badge-ready    { background: rgba(34, 197, 94, 0.12); color: var(--green); }
.ask-queue-badge-asked    { background: rgba(59, 130, 246, 0.12); color: var(--blue-bright); }
.ask-queue-badge-deferred { background: rgba(245, 158, 11, 0.12); color: #f0b25a; }
.ask-queue-badge-never    { background: rgba(239, 68, 68, 0.12); color: var(--red-text); }
.ask-queue-badge-scheduled { background: rgba(168, 85, 247, 0.14); color: #c4a3f5; }
.ask-queue-badge-reviewed  { background: rgba(250, 204, 21, 0.14); color: var(--amber-bright); }
.ask-queue-reviewed-note   { color: var(--text-faint); }
body.light-mode .ask-queue-badge-ready    { color: #16a34a; }
body.light-mode .ask-queue-badge-reviewed { color: #a16207; }
body.light-mode .ask-queue-badge-asked    { color: #2563eb; }
body.light-mode .ask-queue-badge-deferred { color: #d97706; }
body.light-mode .ask-queue-badge-never    { color: #b91c1c; }
body.light-mode .ask-queue-badge-scheduled { color: #7c3aed; }

/* "Schedule for morning" toggle in the send modal */
.ask-queue-sched-toggle {
  display: flex; align-items: flex-start; gap: 9px;
  background: rgba(168, 85, 247, 0.08);
  border: 1px solid rgba(168, 85, 247, 0.25);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px; line-height: 1.45;
  color: var(--text-soft); cursor: pointer;
}
.ask-queue-sched-toggle input { margin-top: 2px; cursor: pointer; flex: 0 0 auto; }
.ask-queue-sched-toggle strong { color: var(--text-strong); }
.ask-queue-btn-cancelsched { color: #c4a3f5; border-color: rgba(168, 85, 247, 0.35); }
body.light-mode .ask-queue-btn-cancelsched { color: #7c3aed; border-color: rgba(168, 85, 247, 0.30); }

/* ── Send + settings modals ────────────────────────────────────────────── */
.ask-queue-send-modal, .ask-queue-settings-modal { max-width: 600px; }
.ask-queue-send-modal .reviews-picker-body,
.ask-queue-settings-modal .reviews-picker-body { display: flex; flex-direction: column; gap: 14px; }
.ask-queue-send-actions {
  display: flex; gap: 8px; justify-content: flex-end;
  margin-top: 6px;
}
.ask-queue-send-hint { color: var(--text-muted); font-size: 12px; line-height: 1.5; }
.ask-queue-send-hint a { color: var(--blue-light); }
body.light-mode .ask-queue-send-hint a { color: var(--blue); }

.reviews-empty {
  background: var(--panel-3);
  border: 1px dashed var(--border-strong);
  border-radius: 12px;
  padding: 24px 28px;
  color: var(--text-soft);
  line-height: 1.55;
  max-width: 780px;
}
.reviews-empty h2 { color: var(--text-strong); font-size: 18px; margin: 0 0 10px 0; }
.reviews-empty p { margin: 0 0 12px 0; font-size: 14px; }
.reviews-empty p strong { color: var(--text-strong); }
.reviews-empty p em { color: var(--blue-light); font-style: normal; padding: 0 4px; }
.reviews-empty-cta { margin-top: 6px; }

.reviews-form-card {
  background: var(--panel-3);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  padding: 18px 20px 20px;
  box-shadow: 0 4px 18px rgba(0,0,0,0.18);
}
.reviews-form-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 14px;
}
.reviews-form-head h3 { margin: 0; font-size: 15px; font-weight: 600; color: var(--text-strong); }
.reviews-form-close {
  background: transparent; border: none; color: var(--text-muted);
  font-size: 22px; line-height: 1; cursor: pointer; padding: 4px 10px;
  border-radius: 6px;
}
.reviews-form-close:hover { background: var(--panel-2); color: var(--text-strong); }

.reviews-form-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 12px 14px;
}
.reviews-fld { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.reviews-fld-wide   { grid-column: 1 / -1; }
.reviews-fld-narrow { }
.reviews-fld-lbl    { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
.reviews-fld-req    { color: #f0b25a; }
.reviews-fld-hint   { text-transform: none; letter-spacing: 0; color: var(--text-muted); opacity: 0.7; font-weight: 400; margin-left: 6px; }
.reviews-input {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text-strong);
  font-size: 14px; padding: 8px 10px;
  font-family: inherit;
}
.reviews-input:focus { outline: none; border-color: var(--blue-bright); box-shadow: 0 0 0 3px var(--blue-soft); }
.reviews-textarea { resize: vertical; min-height: 40px; }

.reviews-stars { display: flex; gap: 2px; padding-top: 4px; }
.reviews-star {
  background: transparent; border: none; cursor: pointer;
  font-size: 22px; line-height: 1; padding: 2px 4px; color: var(--text-faint);
  transition: color 80ms ease;
}
.reviews-star-on { color: #f0b25a; }
.reviews-star:hover { color: #f0b25a; }

.reviews-match-panel {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px dashed var(--border);
}
.reviews-match-empty .reviews-match-hint { font-size: 12px; color: var(--text-muted); font-style: italic; }
.reviews-match-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 8px; }
.reviews-match-list { display: flex; flex-direction: column; gap: 6px; }
.reviews-match-row {
  display: flex; align-items: center; gap: 10px;
  text-align: left; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px;
  color: var(--text-strong); padding: 10px 12px; font-size: 14px;
  transition: border-color 80ms ease, background 80ms ease;
}
.reviews-match-row:hover { border-color: var(--blue-bright); }
.reviews-match-row-sel { border-color: var(--blue-bright); background: var(--blue-soft); }
.reviews-match-name { flex: 1; }
.reviews-match-company { color: var(--text-soft); font-size: 12px; }
.reviews-match-score {
  padding: 2px 8px; border-radius: 999px; font-size: 11px;
  background: rgba(255,255,255,0.06); color: var(--text-muted);
}
.reviews-match-score-strong { background: rgba(95,179,113,0.18); color: #5fb371; }
.reviews-match-score-medium { background: var(--blue-soft); color: var(--blue-light); }

.reviews-form-actions {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--border);
}
.button.button-primary {
  background: var(--blue-bright);
  border-color: var(--blue-bright);
  color: #0b1424;
  font-weight: 600;
}
.button.button-primary:hover:not(:disabled) { background: var(--blue-hover); border-color: var(--blue-hover); }
.button.button-primary:disabled { opacity: 0.4; cursor: not-allowed; }
.button.button-ghost {
  background: transparent; color: var(--text-soft);
}
.button.button-ghost:hover { background: var(--panel-2); color: var(--text-strong); }

.reviews-list-wrap { background: var(--panel-3); border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; }
.reviews-list-wrap h3 { margin: 0 0 14px 0; font-size: 14px; color: var(--text-soft); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }

.reviews-table { width: 100%; border-collapse: collapse; }
.reviews-table thead th {
  text-align: left; font-size: 11px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 6px 10px; border-bottom: 1px solid var(--border);
}
.reviews-table tbody td {
  padding: 12px 10px; border-bottom: 1px solid var(--border);
  color: var(--text-strong); font-size: 14px; vertical-align: top;
}
.reviews-table tbody tr:last-child td { border-bottom: none; }
.reviews-row-name { font-weight: 500; }
.reviews-row-text { font-size: 12px; color: var(--text-soft); margin-top: 4px; line-height: 1.4; max-width: 480px; }
.reviews-row-stars { color: #f0b25a; font-size: 14px; letter-spacing: 1px; }
.reviews-row-stars-empty { color: var(--text-faint); }
.reviews-th-actions { width: 80px; }
.reviews-row-actions { text-align: right; }
.reviews-action-btn {
  background: transparent; border: 1px solid var(--border); color: var(--text-soft);
  font-size: 12px; padding: 5px 10px; border-radius: 6px; cursor: pointer;
}
.reviews-action-btn:hover { background: var(--panel-2); color: var(--text-strong); border-color: var(--border-strong); }

.reviews-status { font-size: 12px; padding: 3px 9px; border-radius: 999px; display: inline-block; }
.reviews-status-matched   { background: rgba(95,179,113,0.16); color: #5fb371; }
.reviews-status-notclient { background: rgba(148,163,184,0.16); color: var(--text-soft); }
.reviews-status-unmatched { background: rgba(240,178,90,0.16); color: #f0b25a; }

/* Matched-client suffix after the Google reviewer name, e.g. "Daisy May (Donna Baird)" */
.reviews-row-client { font-weight: 400; color: var(--text-soft); font-size: 13px; }

/* Read-only review block in the match modal — review data is a Google sync; only matching is editable */
.reviews-form-readonly {
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 14px;
}
.reviews-form-readonly .reviews-row-name { font-size: 15px; }
.reviews-readonly-meta { font-size: 12px; color: var(--text-soft); margin-top: 4px; }
.reviews-readonly-meta .reviews-row-stars { font-size: 13px; }
.reviews-form-readonly .reviews-row-text { max-width: none; margin-top: 8px; }
.reviews-readonly-note { font-size: 11px; color: var(--text-faint); margin-top: 10px; font-style: italic; }

/* Clickable sortable headers on the All Reviews table */
.reviews-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.reviews-sortable:hover { color: var(--text-soft); }
.reviews-sort-active { color: var(--text-strong); }

@media (max-width: 900px) {
  .reviews-stats { grid-template-columns: repeat(2, 1fr); }
  .reviews-stats-actions { grid-column: 1 / -1; }
  .reviews-form-grid { grid-template-columns: 1fr; }
}

/* ─── Receipts tab — two-panel match UI ────────────────────────────────────── */
.receipts-page { display: flex; flex-direction: column; height: calc(100vh - 56px); overflow: hidden; }

/* ── Toolbar ── */
.receipts-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px 13px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  gap: 16px;
  flex-wrap: wrap;
}
.receipts-toolbar-left { display: flex; flex-direction: column; gap: 2px; }
.receipts-toolbar-title { font-size: 15px; font-weight: 600; color: var(--text-strong); }
.receipts-toolbar-hint  { font-size: 12px; color: var(--text-muted); }
.receipts-toolbar-right { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }

.receipts-show-matched-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-soft);
  cursor: pointer;
  user-select: none;
}
.receipts-show-matched-toggle input[type="checkbox"] { accent-color: var(--blue); cursor: pointer; }

/* ── Match hint bar (appears when a receipt is selected) ── */
.receipts-match-hint {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  background: rgba(59,130,246,0.10);
  border-bottom: 1px solid rgba(59,130,246,0.25);
  font-size: 13px;
  color: var(--blue-light);
  flex-shrink: 0;
}
.receipts-match-hint svg { flex-shrink: 0; }
.receipts-match-hint-text { flex: 1; }
.receipts-deselect-btn {
  background: transparent;
  border: 1px solid rgba(59,130,246,0.40);
  color: var(--blue-light);
  border-radius: 6px;
  padding: 4px 12px;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
}
.receipts-deselect-btn:hover { background: rgba(59,130,246,0.14); }

/* ── Inline confirm banner ── */
.rcpt-confirm-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 20px;
  background: rgba(240,178,90,0.10);
  border-bottom: 1px solid rgba(240,178,90,0.30);
  flex-shrink: 0;
  flex-wrap: wrap;
}
.rcpt-confirm-body {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text-strong);
  flex: 1;
}
.rcpt-confirm-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

/* ── Two-panel container ── */
.receipts-panels {
  display: flex;
  flex: 1;
  min-height: 0;
  gap: 0;
}

/* ── Individual panels ── */
.receipts-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--border);
}
.receipts-panel-left  { flex: 0 0 360px; }
.receipts-panel-right { flex: 1; border-right: none; }

.receipts-panel-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 12px 16px 11px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  background: var(--panel-3);
}
.receipts-panel-title { font-size: 13px; font-weight: 600; color: var(--text-strong); }
.receipts-panel-count {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  background: var(--panel-2);
  border: 1px solid var(--border);
  padding: 1px 7px;
  border-radius: 999px;
}
.receipts-panel-sub { font-size: 11.5px; color: var(--text-muted); margin-left: auto; }

.receipts-panel-body { flex: 1; overflow-y: auto; min-height: 0; }

.receipts-panel-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 60px 24px;
  text-align: center;
  color: var(--text-muted);
  font-size: 13.5px;
}
.receipts-panel-empty svg { width: 36px; height: 36px; opacity: 0.4; }
.receipts-panel-empty p { margin: 0; }
.receipts-error       { color: var(--text-soft); }
.receipts-error-detail{ font-size: 12px; color: var(--text-muted); font-family: monospace; margin-top: 4px; }

/* ── Receipt queue cards ── */
.rcpt-card {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border-subtle);
  cursor: pointer;
  transition: background 0.12s;
  position: relative;
}
.rcpt-card:hover { background: var(--row-hover-soft); }
.rcpt-card-selected {
  background: rgba(59,130,246,0.10) !important;
  border-bottom-color: rgba(59,130,246,0.20);
}
.rcpt-card-selected::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  background: var(--blue);
  border-radius: 0 2px 2px 0;
}
.rcpt-card-matched { opacity: 0.55; }
.rcpt-card-matched:hover { opacity: 0.75; }

.rcpt-card-icons { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; padding-top: 1px; }
.rcpt-source-icon { width: 15px; height: 15px; color: var(--text-muted); }
.rcpt-file-icon   { width: 15px; height: 15px; }

.rcpt-card-body { flex: 1; min-width: 0; }
.rcpt-card-name {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-strong);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 3px;
}
.rcpt-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text-muted);
}
.rcpt-card-amount { color: var(--text); font-weight: 600; }
.rcpt-card-matched-tag {
  display: inline-block;
  margin-top: 4px;
  font-size: 11px;
  font-weight: 600;
  color: #5fb371;
  background: rgba(95,179,113,0.14);
  padding: 2px 8px;
  border-radius: 999px;
}

.rcpt-dismiss-btn {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
  border-radius: 4px;
  flex-shrink: 0;
  align-self: flex-start;
  transition: color 0.12s, background 0.12s;
}
.rcpt-dismiss-btn:hover { color: var(--text); background: var(--row-hover); }

/* ── QBO transaction table (right panel) ── */
.rcpt-txn-table-wrap { overflow-x: auto; }
.rcpt-txn-table { width: 100%; }  /* inherits .qbo-table styles */

/* Read-only reference rows — nothing here is clickable or droppable, so no
   pointer cursor (2026-07-30). The drag-to-match wiring these styles served
   was removed as dead code; see the note in _renderReceiptsTxns. */
.rcpt-txn-row {
  cursor: default;
  transition: background 0.12s;
}
.rcpt-txn-row:hover { background: var(--row-hover-soft); }
.rcpt-txn-matched { opacity: 0.5; }
.rcpt-txn-matched:hover { background: inherit !important; }

/* ── Shared utility ── */
.receipts-badge-ok      { background: rgba(95,179,113,0.16); color: #5fb371; }
.receipts-badge-missing { background: rgba(240,178,90,0.16);  color: #f0b25a; }

/* ── Pending / Posted section headers ── */
.rcpt-section-header td {
  padding: 4px 10px 3px;
  background: var(--bg-subtle, rgba(255,255,255,0.04));
  border-bottom: 1px solid var(--border-subtle, rgba(255,255,255,0.08));
  position: sticky;
  top: 0;
  z-index: 1;
}
.rcpt-section-header--divider td {
  border-top: 2px solid var(--border-subtle, rgba(255,255,255,0.12));
  margin-top: 4px;
}
.rcpt-section-label {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted, #9ca3af);
}

/* ═══════════════════════════════════════════════════════════════════════
   Receipts tab — OUTSIDE-IN workflow (rebuilt 2026-05-24)
   Replaces drag-drop matching UI with account tabs + per-row Send button.
   ═══════════════════════════════════════════════════════════════════════ */

.receipts-panels-single .receipts-panel-full { width: 100%; }

/* Account tabs strip */
.receipts-tabs {
  display: flex; gap: 4px; flex-wrap: wrap;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.rcpt-tab {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 4px 4px 0 0;
  padding: 6px 12px;
  font-size: 12px; font-weight: 500;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  position: relative; top: 1px;
}
.rcpt-tab:hover { background: var(--row-hover-soft); color: var(--text); }
.rcpt-tab-active {
  background: var(--bg);
  color: var(--text);
  border-bottom-color: var(--bg);
  font-weight: 600;
}
.rcpt-tab-count {
  display: inline-block;
  min-width: 18px; padding: 0 5px;
  background: var(--border); color: var(--text-muted);
  border-radius: 9px; font-size: 10px; font-weight: 600;
  text-align: center; line-height: 18px;
}
.rcpt-tab-active .rcpt-tab-count { background: var(--blue); color: #fff; }

/* Card layout (queue rows). Bigger thumbnails (140px) + suggestion chips
   row so each receipt shows its proposed QBO fields at a glance. */
.rcpt-card {
  display: grid;
  grid-template-columns: 160px 1fr 220px;
  align-items: stretch;
  gap: 16px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 10px;
  background: var(--bg);
  cursor: pointer;
  position: relative;
  min-height: 160px;
}
.rcpt-card:hover { background: var(--row-hover-soft); }
.rcpt-card-matched { opacity: 0.85; }

.rcpt-card-thumb {
  width: 160px; height: 160px;
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: #0a0a0a;
  flex-shrink: 0;
}
.rcpt-card-thumb-img { width: 100%; height: 100%; object-fit: cover; }
.rcpt-card-thumb-pdf-embed {
  width: 100%; height: 100%;
  border: 0; background: #fff;
  pointer-events: none;  /* don't let the embed steal clicks from the card */
}
.rcpt-card-thumb-pdf-loading {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(239,68,68,0.04);
}
.rcpt-card-thumb-empty { color: var(--text-muted); font-size: 24px; }
/* Thumb with a viewable file opens the fullscreen lightbox on click —
   read-only view, works even when the reimburse e-transfer gate blocks
   the card's own click. */
.rcpt-card-thumb-viewable { cursor: zoom-in; transition: border-color 0.12s ease, box-shadow 0.12s ease; }
.rcpt-card-thumb-viewable:hover { border-color: var(--blue); box-shadow: 0 0 0 2px var(--blue-soft); }
[data-theme="light"] .rcpt-card-thumb { background: #f5f5f5; }

.rcpt-card-body { min-width: 0; display: flex; flex-direction: column; gap: 6px; padding: 4px 0; }
.rcpt-card-name { font-size: 14px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rcpt-card-meta { font-size: 12px; color: var(--text-muted); display: flex; gap: 10px; flex-wrap: wrap; }
.rcpt-card-amount { font-weight: 600; color: var(--text); }
.rcpt-card-job { font-size: 12px; color: var(--text-muted); margin: 1px 0 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rcpt-card-job-addr { color: var(--text); font-weight: 500; margin-left: 6px; }
.rcpt-card-job-addr::before { content: '·'; margin-right: 6px; color: var(--text-muted); font-weight: 400; }
.rcpt-send-jobline { font-size: 12.5px; color: var(--text-muted); margin-bottom: 10px; padding: 6px 10px; background: var(--bg-subtle, rgba(0,0,0,0.04)); border-radius: 6px; }

/* In-CRM Calendar Event Create / Duplicate modal — keeps Matt in the
   CRM instead of opening Google Calendar's quick-create in a new tab.
   Uses overlay pattern shared with other modals. */
.cal-event-create-backdrop {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(0,0,0,0.65);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.cal-event-create-modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  width: min(540px, 100%);
  max-height: 90vh;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 50px rgba(0,0,0,0.6);
  overflow: hidden;
}
.cal-event-create-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.cal-event-create-header h3 {
  margin: 0; font-size: 15px; font-weight: 600; color: var(--text-strong);
}
.cal-event-create-close {
  background: transparent; border: 0; color: var(--text-soft);
  font-size: 22px; cursor: pointer; line-height: 1; padding: 0; width: 28px; height: 28px;
}
.cal-event-create-close:hover { color: var(--text-strong); }
.cal-event-create-body {
  padding: 16px 18px;
  display: flex; flex-direction: column; gap: 12px;
  overflow-y: auto;
}
.cal-event-create-row {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted);
}
.cal-event-create-row input[type="text"],
.cal-event-create-row input[type="date"],
.cal-event-create-row input[type="time"],
.cal-event-create-row select {
  padding: 8px 10px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--border); border-radius: 4px;
  font-size: 13px; font-weight: 400; text-transform: none; letter-spacing: normal;
  font-family: inherit;
}
.cal-event-create-row input:focus,
.cal-event-create-row select:focus {
  outline: 2px solid var(--blue); outline-offset: -1px; border-color: var(--blue);
}
.cal-event-create-row input:disabled { opacity: 0.45; cursor: not-allowed; }
.cal-event-create-hint {
  display: inline-block;
  font-size: 12px; font-weight: 500;
  text-transform: none; letter-spacing: normal;
  color: var(--text); line-height: 1.4;
  padding: 6px 10px;
  background: rgba(255, 255, 255, 0.04);
  border-radius: 4px;
}
.cal-event-create-hint strong { color: var(--text); }
.cal-event-create-hint-muted { color: var(--text-muted); font-style: italic; }
.cal-event-create-checkbox {
  flex-direction: row; align-items: center; gap: 8px;
  text-transform: none; letter-spacing: normal; color: var(--text);
  font-size: 13px; font-weight: 500;
}
.cal-event-create-checkbox input { width: auto; }
.cal-event-create-when { gap: 4px; }
.cal-event-create-datetime { display: flex; gap: 8px; }
.cal-event-create-datetime input { flex: 1; }
.cal-event-create-footer {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 12px 18px;
  border-top: 1px solid var(--border);
}
.cal-event-create-cancel, .cal-event-create-submit {
  padding: 8px 16px; border-radius: 6px;
  font-size: 13px; font-weight: 500;
  cursor: pointer; font-family: inherit;
  border: 1px solid var(--border-strong);
  background: var(--panel); color: var(--text);
  transition: background 0.12s, border-color 0.12s;
}
.cal-event-create-cancel:hover { background: var(--row-hover); }
.cal-event-create-submit {
  background: rgba(59,130,246,0.18); color: var(--blue-lightest); border-color: rgba(59,130,246,0.45);
}
.cal-event-create-submit:hover { background: rgba(59,130,246,0.28); }
.cal-event-create-submit:disabled { opacity: 0.5; cursor: not-allowed; }

/* Source badge — "Peak Mobile" vs "Email" pill in card meta line */
.rcpt-source-badge {
  display: inline-block;
  font-size: 9px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 3px;
}
.rcpt-source-badge-mobile { background: rgba(99,102,241,0.18); color: #818cf8; border: 1px solid rgba(99,102,241,0.35); }
.rcpt-source-badge-email  { background: rgba(59,130,246,0.18); color: var(--blue-bright); border: 1px solid rgba(59,130,246,0.35); }
/* Classifier-derived badges: Statement = monthly account statement (Bill flow);
   Billable = also surfaces in the Billing tab. */
.rcpt-source-badge-statement { background: rgba(251,191,36,0.18); color: var(--amber); border: 1px solid rgba(251,191,36,0.35); }
.rcpt-source-badge-billable  { background: rgba(34,197,94,0.18);  color: var(--green);   border: 1px solid rgba(34,197,94,0.35); }

/* Suggestion chips row — shows the auto-populated QBO fields inline */
.rcpt-card-chips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.rcpt-chip {
  display: inline-flex; align-items: center;
  padding: 3px 9px;
  font-size: 11px; font-weight: 500;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--row-hover-soft);
  color: var(--text);
  white-space: nowrap;
  max-width: 260px; overflow: hidden; text-overflow: ellipsis;
}
.rcpt-chip-vendor   { border-color: rgba(99,102,241,0.4);  background: rgba(99,102,241,0.10); color: #818cf8; }
.rcpt-chip-payment  { border-color: rgba(59,130,246,0.4);  background: rgba(59,130,246,0.10); color: var(--blue-bright); }
.rcpt-chip-category { border-color: rgba(34,197,94,0.4);   background: rgba(34,197,94,0.10);  color: var(--green); }
.rcpt-chip-tax      { border-color: rgba(240,178,90,0.4);  background: rgba(240,178,90,0.10); color: #f0b25a; }
.rcpt-chip-empty    { border-style: dashed; color: var(--text-muted); background: transparent; }

.rcpt-card-action { display: flex; align-items: stretch; gap: 8px; flex-shrink: 0; justify-content: flex-end; }
.rcpt-card-actions {
  display: flex; flex-direction: column; gap: 6px; justify-content: center;
  width: 100%;
}
.rcpt-card-actions-reimburse { gap: 4px; }
.rcpt-card-actions-reimburse .rcpt-coast-btn { text-align: center; }
.rcpt-et-sent-pill {
  display: inline-block; text-align: center;
  padding: 5px 10px; font-size: 11px; font-weight: 600;
  color: #34d399; background: rgba(52, 211, 153, 0.12);
  border: 1px solid rgba(52, 211, 153, 0.35); border-radius: 4px;
}
.rcpt-send-btn { padding: 10px 14px; font-size: 13px; font-weight: 600; }
.rcpt-send-btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.rcpt-not-bank-btn {
  font-size: 11px; padding: 5px 10px;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border);
}
.rcpt-not-bank-btn:hover {
  color: var(--red); border-color: rgba(239,68,68,0.4); background: rgba(239,68,68,0.06);
}
.rcpt-card-status {
  display: flex; flex-direction: column;
  align-items: flex-end;
  font-size: 12px; font-weight: 500;
  gap: 4px;
  justify-content: center;
}
.rcpt-card-status-sent { color: var(--success, #22c55e); }
.rcpt-card-status-meta { color: var(--text-muted); font-size: 10px; font-weight: 400; }
.rcpt-undo-btn { font-size: 11px; padding: 4px 10px; margin-top: 4px; }
/* USD-vendor reprice control on matched cards — type the bank's posted CAD */
.rcpt-usd-reprice { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
.rcpt-usd-reprice-label { color: var(--warning, #f59e0b); font-size: 10px; font-weight: 600; }
.rcpt-usd-reprice-row { display: flex; align-items: center; gap: 4px; }
.rcpt-usd-reprice-row input { width: 76px; font-size: 11px; padding: 3px 6px; }
.rcpt-reprice-btn { font-size: 11px; padding: 4px 10px; }

/* Send-to-QBO modal — full-page overlay (matches .roll-eom-modal pattern;
   the base .modal class is just a card with max-width:560px / padding:22px /
   overflow-y:auto / border-radius:14px — all of those need explicit
   overrides so position:fixed + inset:0 actually fills the viewport). */
.rcpt-send-modal, .rcpt-preview-modal {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.65);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000; padding: 20px;
  /* Override base .modal so we're a true full-page overlay, not a card */
  max-width: none; width: auto; max-height: none;
  border: 0; border-radius: 0; box-shadow: none; overflow: visible;
}
/* Fullscreen attachment lightbox — opens above the Send-to-QBO modal so the
   user can zoom into the receipt without losing the form context behind it. */
.rcpt-lightbox {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.9);
  z-index: 1100;
  display: flex; flex-direction: column;
  padding: 12px;
}
.rcpt-lightbox-close {
  align-self: flex-end;
  background: rgba(255,255,255,0.12); color: #fff;
  border: 1px solid rgba(255,255,255,0.25); border-radius: 6px;
  padding: 6px 14px; font-size: 13px; cursor: pointer;
  margin-bottom: 8px;
}
.rcpt-lightbox-close:hover { background: rgba(255,255,255,0.22); }
.rcpt-lightbox-content {
  flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  overflow: auto;
}
.rcpt-lightbox-img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  cursor: zoom-in;
}
.rcpt-lightbox-pdf {
  width: 100%; height: 100%;
  border: 0; background: #fff;
}
.rcpt-lightbox-empty { color: #ccc; font-size: 14px; }
.rcpt-send-card, .rcpt-preview-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  width: min(1100px, 100%);
  max-height: 92vh;
  display: flex; flex-direction: column;
  box-shadow: 0 20px 50px rgba(0,0,0,0.6);
  overflow: hidden;
}
.rcpt-send-card .modal-header, .rcpt-preview-card .modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px; border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.rcpt-send-card .modal-header h3, .rcpt-preview-card .modal-header h3 {
  margin: 0; font-size: 16px; color: var(--text-strong); font-weight: 600;
}
.rcpt-send-card .modal-close, .rcpt-preview-card .modal-close {
  background: transparent; color: var(--text-soft); border: none;
  font-size: 22px; cursor: pointer;
  padding: 0; line-height: 1; width: 28px; height: 28px;
}
.rcpt-send-card .modal-close:hover, .rcpt-preview-card .modal-close:hover { color: var(--text-strong); }
.rcpt-send-card .modal-body, .rcpt-preview-card .modal-body {
  padding: 18px 20px; overflow-y: auto; flex: 1 1 auto;
}
.rcpt-send-card .modal-footer, .rcpt-preview-card .modal-footer {
  padding: 14px 20px; border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: 10px; flex-shrink: 0;
}
.rcpt-send-card .modal-footer .button, .rcpt-preview-card .modal-footer .button {
  background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
  padding: 9px 16px; border-radius: 8px; font-size: 13px; font-weight: 500;
  cursor: pointer; font-family: inherit;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.rcpt-send-card .modal-footer .button:hover, .rcpt-preview-card .modal-footer .button:hover {
  background: var(--row-hover); color: var(--text-strong);
}
.rcpt-send-card .modal-footer .button-primary, .rcpt-preview-card .modal-footer .button-primary {
  background: rgba(59,130,246,0.18); color: var(--blue-lightest); border-color: rgba(59,130,246,0.45);
}
.rcpt-send-card .modal-footer .button-primary:hover, .rcpt-preview-card .modal-footer .button-primary:hover { background: rgba(59,130,246,0.28); }
.rcpt-send-card .modal-footer .button:disabled, .rcpt-preview-card .modal-footer .button:disabled { opacity: 0.5; cursor: not-allowed; }
.rcpt-send-body {
  display: grid;
  grid-template-columns: minmax(440px, 1.4fr) minmax(280px, 1fr);
  gap: 18px;
  max-height: calc(92vh - 140px);
  overflow: hidden;
}
.rcpt-send-form, .rcpt-send-preview { min-width: 0; overflow: auto; }

.rcpt-send-banner {
  padding: 10px 14px;
  border-radius: 4px;
  margin-bottom: 14px;
  font-size: 12px;
  display: flex; flex-direction: column; gap: 2px;
}
.rcpt-send-banner-success { background: rgba(34,197,94,0.08); border: 1px solid rgba(34,197,94,0.3); color: var(--success, #22c55e); }

.rcpt-send-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 16px;
}
.rcpt-send-grid label {
  display: flex; flex-direction: column;
  font-size: 11px; font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  gap: 4px;
}
.rcpt-send-grid label input,
.rcpt-send-grid label select {
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 13px;
  font-weight: 400;
  color: var(--text);
  text-transform: none;
  letter-spacing: normal;
}
.rcpt-send-grid label input:focus,
.rcpt-send-grid label select:focus {
  outline: 2px solid var(--blue);
  outline-offset: -1px;
  border-color: var(--blue);
}
.rcpt-send-grid label input:disabled,
.rcpt-send-grid label select:disabled {
  opacity: 0.6; cursor: not-allowed;
}
.rcpt-send-grid-full { grid-column: span 2; }

.rcpt-send-footer { display: flex; justify-content: flex-end; gap: 10px; align-items: center; }
.button-danger { background: #ef4444; color: #fff; border-color: var(--red); }
.button-danger:hover { background: #dc2626; border-color: #dc2626; }

.rcpt-preview-meta { font-size: 11px; color: var(--text-muted); margin-top: 6px; text-align: center; }

/* Receipts drag & drop visuals REMOVED 2026-07-30. This block was already
   marked "deprecated, kept for any leftover dead code"; that leftover code
   (the orphaned .rcpt-txn-row drop wiring) is now gone, so every selector
   here was unmatchable — no .rcpt-card carries draggable, and none of
   .rcpt-card-dragging / .rcpt-txn-drop-target / .rcpt-txn-drop-over is
   referenced anywhere in js/ or *.html. */

/* ── Receipt preview / match modal ── */
.rcpt-preview-card { max-width: 1000px; width: 92vw; max-height: 92vh; display: flex; flex-direction: column; }
.rcpt-preview-body {
  display: grid;
  grid-template-columns: minmax(280px, 360px) 1fr;
  gap: 18px;
  max-height: calc(92vh - 140px);
  overflow: hidden;
}
.rcpt-preview-left, .rcpt-preview-right { display: flex; flex-direction: column; gap: 10px; min-height: 0; }
.rcpt-preview-right { min-width: 0; }
.rcpt-preview-section-label {
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 2px;
}
.rcpt-preview-info, .rcpt-preview-txn-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--row-hover-soft);
}
.rcpt-preview-info-row, .rcpt-preview-txn-row {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: 12px; line-height: 1.4;
}
.rcpt-preview-info-row span, .rcpt-preview-txn-row span { color: var(--text-muted); flex-shrink: 0; }
.rcpt-preview-info-row strong, .rcpt-preview-txn-row strong {
  text-align: right; word-break: break-word; max-width: 60%;
}
.rcpt-preview-attachment {
  flex: 1; min-height: 320px; max-height: 100%;
  border: 1px solid var(--border); border-radius: 6px;
  background: #0a0a0a; display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  cursor: zoom-in;
  transition: border-color 120ms ease;
}
.rcpt-preview-attachment:hover { border-color: var(--blue, #4a8cff); }
.rcpt-preview-img { max-width: 100%; max-height: 60vh; object-fit: contain; pointer-events: none; }
/* pointer-events: none on inner img/iframe so clicks bubble to the wrapper
   (.rcpt-preview-attachment) which opens fullscreen. Inline PDF preview
   is read-only by design — interaction happens in the fullscreen view. */
.rcpt-preview-pdf { width: 100%; height: 60vh; border: 0; background: #fff; pointer-events: none; }
.rcpt-preview-hint {
  display: inline-flex; align-items: center;
  font-size: 12px; color: var(--text-muted);
  padding: 4px 8px; border-radius: 4px;
  background: rgba(255,255,255,0.04);
}
.rcpt-preview-empty { color: var(--text-muted); font-size: 12px; padding: 20px; text-align: center; }
.rcpt-preview-footer { display: flex; justify-content: flex-end; gap: 10px; align-items: center; }
.rcpt-preview-success {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 8px 12px; border-radius: 6px;
  background: rgba(34,197,94,0.10); border: 1px solid rgba(34,197,94,0.35);
  font-size: 13px; font-weight: 500;
}

[data-theme="light"] .rcpt-preview-attachment { background: #f5f5f5; }

/* ── Pending row + badge ── */
.rcpt-txn-pending-row { background: rgba(240,178,90,0.04); }
.rcpt-pending-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 10px;
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: rgba(240,178,90,0.18);
  color: #f0b25a;
  vertical-align: middle;
  line-height: 1.5;
}

/* ── Light-theme overrides ── */
[data-theme="light"] .receipts-panel-head { background: #f8fafc; }
[data-theme="light"] .receipts-panel-count { background: #f1f5f9; border-color: #d1d5db; }
[data-theme="light"] .rcpt-card-selected { background: rgba(59,130,246,0.07) !important; }
[data-theme="light"] .receipts-match-hint { background: rgba(59,130,246,0.06); border-color: rgba(59,130,246,0.18); }
[data-theme="light"] .rcpt-confirm-banner { background: rgba(240,178,90,0.07); border-color: rgba(240,178,90,0.22); }
[data-theme="light"] .rcpt-section-header td { background: #f8fafc; border-color: #e2e8f0; }
[data-theme="light"] .rcpt-section-header--divider td { border-top-color: #d1d5db; }
[data-theme="light"] .rcpt-txn-pending-row { background: rgba(240,178,90,0.05); }
[data-theme="light"] .rcpt-pending-badge { background: rgba(240,178,90,0.15); color: #b45309; }

  /* ── Needs-Scheduling rail ───────────────────────────────────────────── */
  /* Collapsible drawer beside the calendar. Closed by default; toggled from
     the calendar topbar. When closed the calendar keeps full width. Wrapped
     around .cal-wrap in a .cal-shell flex row by mountSchedulingRail(). */
  .cal-shell { display: flex; gap: 14px; align-items: flex-start; }
  .cal-shell > .cal-wrap { flex: 1 1 auto; min-width: 0; }
  .cal-rail {
    display: none;
    flex: 0 0 300px;
    flex-direction: column;
    align-self: flex-start;
    position: sticky; top: 12px;
    max-height: calc(100vh - 40px);
    overflow-y: auto;
    margin: 14px 0;
    padding: 12px 14px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
  }
  .cal-shell.cal-rail-open .cal-rail { display: flex; }
  /* Bucket header + search box, pinned to the top of the scrolling rail.
     top:-12px with a matching negative margin/padding pair covers .cal-rail's
     own 12px padding-top, so cards scroll UNDER the header instead of peeking
     above it. Full-bleed sideways (-14px) so the backdrop reaches both edges.
     Without this, "All" runs hundreds of cards long and the search box you'd
     have to scroll back up to reach is a search box that stops getting used. */
  .cal-rail-sticky {
    position: sticky; top: -12px; z-index: 2;
    margin: -12px -14px 8px; padding: 12px 14px 8px;
    background: var(--panel); border-bottom: 1px solid var(--border);
  }
  .cal-rail-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px;
  }
  .cal-rail-search {
    display: block; width: 100%; box-sizing: border-box; margin-top: 8px;
    appearance: none; -webkit-appearance: none;
    background: var(--panel-3); color: var(--text-strong);
    border: 1px solid var(--border); border-radius: 7px;
    font-family: inherit; font-size: 12.5px; padding: 6px 9px;
  }
  .cal-rail-search::placeholder { color: var(--text-muted); }
  .cal-rail-search:hover { border-color: rgba(96,165,250,0.5); }
  .cal-rail-search:focus {
    outline: none; background: var(--panel-2);
    border-color: rgba(96,165,250,0.75);
  }
  /* Keep WebKit's clear (×) but draw it in the CRM's grey — appearance:none on
     the field alone leaves it as a black blob that reads wrong in dark mode. */
  .cal-rail-search::-webkit-search-cancel-button {
    -webkit-appearance: none; appearance: none;
    width: 12px; height: 12px; cursor: pointer;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M3 3l6 6M9 3l-6 6' stroke='%2394a3b8' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center / contain;
  }
  /* "N matches in other statuses" — the escape hatch when a search finds
     nothing because the job sits in a bucket the rail isn't showing. */
  .cal-rail-widen-note { margin: -4px 0 8px; }
  .cal-rail-widen { color: var(--blue-light); text-decoration: none; font-size: 11px; }
  .cal-rail-widen:hover { text-decoration: underline; }
  .cal-rail-title { font-size: 13px; font-weight: 700; color: var(--text-strong); }
  .cal-rail-bucket {
    flex: 1 1 auto; min-width: 0;
    appearance: none; cursor: pointer;
    background: var(--panel-3); color: var(--text-strong);
    border: 1px solid var(--border); border-radius: 7px;
    font-family: inherit; font-size: 12.5px; font-weight: 700;
    padding: 4px 8px;
  }
  .cal-rail-bucket:hover { border-color: rgba(96,165,250,0.5); }
  .cal-rail-status {
    flex: 0 1 auto; min-width: 0; max-width: 152px;
    appearance: none; cursor: pointer;
    background: var(--panel-3); color: var(--text);
    border: 1px solid var(--border); border-radius: 7px;
    font-family: inherit; font-size: 10.5px; font-weight: 600;
    padding: 3px 6px;
  }
  .cal-rail-status:hover { border-color: rgba(96,165,250,0.5); color: var(--text-strong); }
  /* Per-card status chevron (top-right corner) + its popup menu. */
  .cal-rail-card { position: relative; }
  .cal-rail-card-title { padding-right: 24px; }   /* room for the chevron */
  .cal-rail-status-btn {
    position: absolute; top: 7px; right: 7px;
    appearance: none; cursor: pointer; padding: 0;
    width: 22px; height: 22px; line-height: 1;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid transparent; border-radius: 6px;
    background: transparent; color: var(--text-muted); font-size: 12px;
  }
  .cal-rail-status-btn:hover { background: var(--panel-3); border-color: var(--border); color: var(--text-strong); }
  /* Inline-editable description: blends in as text, reveals itself as an
     editable field on hover/focus. */
  .cal-rail-card-desc {
    display: block; width: 100%; box-sizing: border-box; margin-top: 6px;
    resize: none; overflow-y: auto; max-height: 66px;
    border: 1px solid transparent; border-radius: 6px;
    background: transparent; color: var(--text-muted);
    font-family: inherit; font-size: 11px; line-height: 1.45; padding: 3px 5px;
  }
  .cal-rail-card-desc::placeholder { color: var(--text-muted); opacity: 0.5; }
  .cal-rail-card-desc:hover { background: var(--panel-3); }
  .cal-rail-card-desc:focus {
    outline: none; background: var(--panel-3);
    border-color: rgba(96,165,250,0.55); color: var(--text-strong);
  }
  .cal-rail-status-dot { flex: 0 0 8px; width: 8px; height: 8px; border-radius: 50%; }
  .cal-rail-status-menu {
    position: fixed; z-index: 10000; min-width: 200px;
    background: var(--panel); border: 1px solid var(--border);
    border-radius: 10px; padding: 5px; box-shadow: 0 12px 32px rgba(0,0,0,0.45);
  }
  .cal-rail-status-item {
    display: flex; align-items: center; gap: 6px; width: 100%;
    appearance: none; cursor: pointer; text-align: left;
    border: 0; border-radius: 7px; background: transparent;
    color: var(--text); font-family: inherit; font-size: 12.5px; font-weight: 600;
    padding: 7px 9px;
  }
  .cal-rail-status-item:hover { background: var(--panel-3); color: var(--text-strong); }
  .cal-rail-status-item.is-current { color: var(--text-strong); }
  .cal-rail-status-check { flex: 0 0 14px; width: 14px; color: var(--green); font-weight: 800; }
  /* Down-chevron indicator on the header bucket <select> (appearance:none hid
     the native arrow, so draw our own). */
  .cal-rail-bucket {
    padding-right: 22px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath d='M2 3.5 5 6.5 8 3.5' fill='none' stroke='%23cbd5e1' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 7px center;
  }
  .cal-rail-count {
    display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 4px;
    border-radius: 9px; background: rgba(234,179,8,0.18); color: #eab308;
    font-size: 11px; font-weight: 700; text-align: center;
    /* Reads "12 / 87" while a search narrows the bucket — never let that wrap
       or squeeze the bucket <select> beside it. */
    flex: 0 0 auto; white-space: nowrap;
  }
  .cal-rail-close {
    appearance: none; border: 0; background: transparent; cursor: pointer;
    color: var(--text-muted); font-size: 18px; line-height: 1;
    padding: 2px 6px; border-radius: 6px;
  }
  .cal-rail-close:hover { background: var(--row-hover); color: var(--text-strong); }
  .cal-rail-hint { font-size: 11px; color: var(--text-muted); margin-bottom: 10px; line-height: 1.4; }
  .cal-rail-empty { font-size: 12px; color: var(--text-muted); line-height: 1.5; padding: 8px 2px; }
  .cal-rail-list { display: flex; flex-direction: column; gap: 8px; }
  .cal-rail-card {
    border: 1px solid var(--border); border-left: 3px solid rgba(234,179,8,0.7);
    border-radius: 10px; background: var(--panel-3);
    padding: 9px 10px; cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
  }
  .cal-rail-card:hover { background: rgba(96,165,250,0.08); border-color: rgba(96,165,250,0.4); }
  .cal-rail-card-dragging { opacity: 0.45; }
  .cal-rail-card-title { font-size: 12.5px; font-weight: 600; color: var(--text-strong); }
  .cal-rail-card-sub { font-size: 11px; color: var(--text-muted); margin-top: 2px; }
  .cal-rail-card-foot {
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px; margin-top: 8px;
  }
  .cal-rail-grip { font-size: 10px; color: var(--text-muted); user-select: none; }
  .cal-rail-card-schedule {
    appearance: none; cursor: pointer;
    border: 1px solid rgba(34,197,94,0.5); border-radius: 7px;
    background: rgba(22,163,74,0.14); color: var(--green);
    font-family: inherit; font-size: 11px; font-weight: 700; padding: 4px 10px;
  }
  .cal-rail-card-schedule:hover { background: rgba(22,163,74,0.26); }
  .cal-rail-toggle {
    appearance: none; cursor: pointer;
    display: inline-flex; align-items: center; gap: 6px;
    border: 1px solid var(--border); border-radius: 8px;
    background: var(--panel); color: var(--text);
    font-family: inherit; font-size: 12px; font-weight: 600; padding: 6px 10px;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
  }
  .cal-rail-toggle:hover { border-color: rgba(234,179,8,0.5); color: var(--text-strong); }
  .cal-rail-toggle[aria-pressed="true"] {
    border-color: rgba(234,179,8,0.6); background: rgba(234,179,8,0.12); color: #eab308;
  }
  .cal-rail-toggle-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: #eab308; box-shadow: 0 0 0 3px rgba(234,179,8,0.18);
  }
  .cal-rail-toggle-count {
    display: inline-block; min-width: 16px; padding: 0 4px;
    border-radius: 8px; background: rgba(234,179,8,0.22); color: #eab308;
    font-size: 10.5px; font-weight: 700; text-align: center;
  }
  /* Month-cell drop highlight (week columns reuse .cal-day-col-drop-target). */
  .cal-month-cell-drop-target {
    background: rgba(59,130,246,0.14) !important;
    box-shadow: inset 0 0 0 2px rgba(59,130,246,0.5);
  }
  /* Mobile — stack the drawer above the calendar; drag-to-day isn't
     practical on touch but tap-to-schedule still works. */
  @media (max-width: 860px) {
    .cal-shell { flex-direction: column; }
    .cal-shell.cal-rail-open .cal-rail {
      flex: none; width: auto; position: static; max-height: 46vh;
    }
  }

/* ═══ Web Leads queue (js/16-web-leads.js, 2026-07-04) ═══════════════════ */
.wl-wrap { max-width: 860px; display: flex; flex-direction: column; gap: 12px; }
.wl-toolbar { display: flex; justify-content: space-between; align-items: center;
  color: var(--text-muted); font-size: 13px; padding: 2px 2px 4px; }
.wl-card { background: var(--panel); border: 1px solid var(--border);
  border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column; gap: 8px; }
.wl-card.is-spam { opacity: 0.75; }
.wl-card.is-compact { padding: 10px 14px; }
.wl-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wl-head strong { color: var(--text-strong); font-size: 15px; }
.wl-chip { background: var(--panel-3); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: 1px 9px; font-size: 11.5px; color: var(--text-soft); }
.wl-chip-dim { color: var(--text-faint); }
.wl-when { margin-left: auto; color: var(--text-faint); font-size: 12px; }
.wl-contact { font-size: 13px; color: var(--text-soft); }
.wl-contact a { color: var(--blue-light); text-decoration: none; }
.wl-desc { font-size: 13.5px; color: var(--text); white-space: pre-wrap;
  background: var(--panel-2); border-radius: 8px; padding: 8px 10px; }
.wl-meta { font-size: 12px; color: var(--text-muted); }
.wl-photos { display: flex; gap: 8px; flex-wrap: wrap; }
.wl-photos img { width: 84px; height: 84px; object-fit: cover; border-radius: 8px;
  border: 1px solid var(--border); }
.wl-spam-note { font-size: 12px; color: #f59e0b; }
.wl-decided { font-size: 12.5px; color: var(--text-muted); }
.wl-decided a { color: var(--blue-light); }
.wl-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.wl-btn { background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px 13px; font-size: 12.5px; cursor: pointer; }
.wl-btn:hover { border-color: var(--border-strong); }
.wl-btn:disabled { opacity: 0.55; cursor: default; }
.wl-btn.btn-primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.wl-empty { color: var(--text-muted); font-size: 13.5px; padding: 26px 4px; text-align: center;
  border: 1px dashed var(--border); border-radius: 10px; }
.wl-fold summary { cursor: pointer; color: var(--text-muted); font-size: 13px; padding: 6px 2px; }
.wl-fold .wl-card { margin-top: 10px; }

/* Web Leads visual pass (2026-08-05): status accent + company chip + hover. */
.wl-card { border-left: 3px solid var(--blue); transition: border-color 0.12s, box-shadow 0.12s; }
.wl-card:hover { border-color: var(--border-strong); box-shadow: 0 4px 16px rgba(0,0,0,0.18); }
.wl-card.is-spam { border-left-color: #f59e0b; }
.wl-card.is-approved { border-left-color: #5fb371; }
.wl-card.is-discarded { border-left-color: var(--border-strong); opacity: 0.8; }
.wl-chip-co { background: rgba(59,130,246,0.12); border-color: rgba(59,130,246,0.35); color: var(--blue-light); }
.wl-head { margin-bottom: 2px; }
.wl-desc { border-left: 2px solid var(--border-subtle); }

/* ═══ Inbox — unified comms threads (js/21-comms.js, 2026-08-12) ═════════ */
.cx-wrap { max-width: 760px; display: flex; flex-direction: column; gap: 10px; }
.cx-toolbar { display: flex; justify-content: space-between; align-items: center;
  color: var(--text-muted); font-size: 13px; padding: 2px 2px 4px; }
.cx-btn { background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px 13px; font-size: 12.5px; cursor: pointer;
  text-decoration: none; display: inline-block; }
.cx-btn:hover { border-color: var(--border-strong); }
.cx-btn:disabled { opacity: 0.55; cursor: default; }
.cx-empty { color: var(--text-muted); font-size: 13.5px; padding: 26px 12px; text-align: center;
  border: 1px dashed var(--border); border-radius: 10px; line-height: 1.55; }
.cx-empty code { background: var(--panel-2); border-radius: 4px; padding: 1px 5px; font-size: 12px; }
.cx-sub { color: var(--text-faint); font-size: 12px; font-weight: 400; margin-left: 6px; }
.cx-when { margin-left: auto; color: var(--text-faint); font-size: 12px; white-space: nowrap; }
.cx-chip { background: var(--panel-3); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: 1px 9px; font-size: 11.5px; color: var(--text-soft); }
.cx-chip-wait { background: rgba(245,158,11,0.14); border-color: rgba(245,158,11,0.4); color: #f59e0b; }
.cx-chip-auto { color: var(--text-faint); }

/* Thread list cards */
.cx-card { background: var(--panel); border: 1px solid var(--border);
  border-left: 3px solid var(--border-strong); border-radius: 10px; padding: 12px 14px;
  display: flex; flex-direction: column; gap: 6px; text-align: left; width: 100%;
  cursor: pointer; color: var(--text); font: inherit;
  transition: border-color 0.12s, box-shadow 0.12s; }
.cx-card:hover { border-color: var(--border-strong); box-shadow: 0 4px 16px rgba(0,0,0,0.18); }
.cx-card.is-waiting { border-left-color: #f59e0b; }
.cx-card-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cx-card-top strong { color: var(--text-strong); font-size: 14.5px; }
.cx-card-preview { color: var(--text-muted); font-size: 13px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }

/* Thread detail */
.cx-thread-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cx-thread-title { font-size: 15px; font-weight: 600; color: var(--text-strong); }
.cx-thread-actions { margin-left: auto; display: flex; gap: 8px; }
.cx-wait-banner { background: rgba(245,158,11,0.1); border: 1px solid rgba(245,158,11,0.35);
  border-radius: 8px; padding: 7px 12px; font-size: 12.5px; color: #f59e0b; }
.cx-messages { display: flex; flex-direction: column; gap: 10px; padding: 6px 0; }
.cx-msg { display: flex; flex-direction: column; max-width: 78%; }
.cx-msg.is-in  { align-self: flex-start; align-items: flex-start; }
.cx-msg.is-out { align-self: flex-end;   align-items: flex-end; }
.cx-bubble { background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 12px; padding: 8px 12px; font-size: 13.5px; white-space: pre-wrap;
  word-break: break-word; }
.cx-msg.is-out .cx-bubble { background: rgba(59,130,246,0.12); border-color: rgba(59,130,246,0.3); }
.cx-msg-meta { display: flex; align-items: center; gap: 6px; margin-top: 3px; }
.cx-msg-meta .cx-when { margin-left: 0; }
.cx-ch-note { color: var(--text-soft); font-style: italic; }
.cx-ch-note a { color: var(--blue-light); }
.cx-media a { color: var(--blue-light); font-size: 12.5px; }
.cx-reply-note { color: var(--text-faint); font-size: 12px; text-align: center;
  border-top: 1px dashed var(--border); padding-top: 10px; margin-top: 4px; }

/* Reply box */
.cx-btn-primary { background: var(--blue); border-color: var(--blue); color: #fff; }
.cx-reply { border-top: 1px solid var(--border); padding-top: 10px; margin-top: 4px;
  display: flex; flex-direction: column; gap: 6px; }
.cx-reply-text { width: 100%; box-sizing: border-box; resize: vertical;
  background: var(--panel-2); color: var(--text); border: 1px solid var(--border);
  border-radius: 10px; padding: 9px 12px; font: inherit; font-size: 13.5px;
  line-height: 1.45; }
.cx-reply-text:focus { outline: none; border-color: var(--blue); }
.cx-reply-foot { display: flex; align-items: center; gap: 10px; }
.cx-count { color: var(--text-faint); font-size: 12px; }
.cx-count-warn { color: #f59e0b; }
.cx-reply-hint { color: var(--text-faint); font-size: 11.5px; margin-left: auto; }

/* Attribution bar */
.cx-attr-set { font-size: 12.5px; color: var(--text-muted); display: flex;
  align-items: center; gap: 8px; }
.cx-attr-set strong { color: var(--text-strong); }
.cx-attr-unknown { color: #f59e0b; }
.cx-linkbtn { background: none; border: none; padding: 0; cursor: pointer;
  color: var(--blue-light); font: inherit; font-size: 12.5px; text-decoration: underline; }
.cx-attr { background: var(--panel-2); border: 1px solid var(--border);
  border-radius: 10px; padding: 10px 12px; display: flex; align-items: center;
  gap: 8px; flex-wrap: wrap; }
.cx-attr label { font-size: 12.5px; color: var(--text-soft); }
.cx-attr-input { flex: 1; min-width: 200px; background: var(--panel);
  color: var(--text); border: 1px solid var(--border); border-radius: 8px;
  padding: 6px 10px; font: inherit; font-size: 13px; }
.cx-attr-input:focus { outline: none; border-color: var(--blue); }
.cx-attr-note { flex-basis: 100%; color: var(--text-faint); font-size: 11.5px; }


  /* ── Light-theme overrides for near-white accent text (2026-07-17 sweep).
     These hexes have no exact dark-token twin, so the dark values stay
     hardcoded above and only light mode remaps them. ── */
  [data-theme="light"] .today-crew-badge-unapproved { color: var(--orange); }
  [data-theme="light"] .bwa-late-banner { color: var(--pink); }
  [data-theme="light"] .bwa-card-unbill-hint strong { color: var(--amber-text); }
  [data-theme="light"] .bw-pending-unbill-suggested { color: var(--pink) !important; }
  [data-theme="light"] .bwa-badge-unbill { color: var(--amber-text); }
  [data-theme="light"] .bwa-badge-quoted { color: var(--purple); }
  [data-theme="light"] .today-reimburse-count { color: var(--purple); }
  [data-theme="light"] .permits-auth-tsbc,
  [data-theme="light"] .permits-history-itype,
  [data-theme="light"] .permits-type-operating { color: var(--purple); }
  [data-theme="light"] .map-gps-tag-stale { color: var(--amber); }
  [data-theme="light"] .cal-rail-count,
  [data-theme="light"] .cal-rail-toggle[aria-pressed="true"],
  [data-theme="light"] .cal-rail-toggle-count { color: var(--amber-bright); }

/* ═══ Photos stream (js/18-photos.js, 2026-07-18) ═══════════════════════
   Company-wide media feed from Peak's R2 archive — CC-style date-grouped
   grid. Tokens only; follows the CRM light/dark theme automatically. */
#photos-view { padding: 18px 22px 40px; }
.photos-head h1 { margin: 0 0 12px; font-size: 22px; color: var(--text-strong); }
.photos-toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 16px; }
.photos-select, .photos-btn {
  background: var(--panel); color: var(--text); border: 1px solid var(--border);
  border-radius: 8px; padding: 6px 10px; font: inherit; font-size: 13px; cursor: pointer;
}
.photos-btn { text-decoration: none; display: inline-block; }
.photos-btn:hover, .photos-select:hover { border-color: var(--border-strong); }
/* Job filter is a type-to-search input (datalist), not a select — it carries
   "<job name> — <address>", so it needs the room a bare name didn't. */
.photos-jobpick { cursor: text; min-width: 300px; flex: 0 1 480px; }
.photos-jobpick::-webkit-search-cancel-button { cursor: pointer; }
.photos-jobpick:focus { outline: none; border-color: var(--blue); }
.photos-meta { color: var(--text-muted); font-size: 12.5px; margin-left: 4px; }
.photos-date-head {
  font-weight: 600; color: var(--text-strong); font-size: 15px;
  margin: 22px 0 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border);
}
.photos-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(172px, 1fr)); gap: 12px;
}
.photo-tile {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  overflow: hidden; cursor: pointer; transition: border-color .12s;
}
.photo-tile:hover { border-color: var(--blue); }
.photo-tile-img { aspect-ratio: 4 / 3; background: color-mix(in srgb, var(--panel) 70%, #000 30%); }
.photo-tile-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.photo-tile-meta { padding: 7px 9px 9px; }
.photo-tile-line1 { font-size: 12px; color: var(--text-muted); }
.photo-tile-line2 {
  font-size: 12.5px; color: var(--text); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.photo-tile-cap {
  font-size: 12px; color: var(--text-soft); margin-top: 3px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.photos-empty { color: var(--text-muted); padding: 40px 0; text-align: center; }
.photos-dim { color: var(--text-muted); font-size: 12px; }
.photos-foot { margin-top: 18px; text-align: center; }

/* Lightbox */
.photos-lightbox { position: fixed; inset: 0; z-index: 1200; }
.photos-lb-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.78); }
.photos-lb-panel {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; padding: 28px; pointer-events: none;
}
.photos-lb-panel > * { pointer-events: auto; }
.photos-lb-img {
  max-width: min(92vw, 1400px); max-height: 72vh; object-fit: contain;
  border-radius: 8px; box-shadow: 0 8px 40px rgba(0,0,0,.5);
}
.photos-lb-x {
  position: absolute; top: 14px; right: 18px; font-size: 26px; line-height: 1;
  background: none; border: none; color: #fff; cursor: pointer; opacity: .8;
}
.photos-lb-x:hover { opacity: 1; }
.photos-lb-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  font-size: 34px; line-height: 1; padding: 10px 14px; border-radius: 10px;
  background: rgba(0,0,0,.35); border: none; color: #fff; cursor: pointer;
}
.photos-lb-nav:disabled { opacity: .25; cursor: default; }
.photos-lb-prev { left: 16px; }
.photos-lb-next { right: 16px; }
.photos-lb-meta {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 14px; max-width: min(92vw, 760px); text-align: center;
}
.photos-lb-title { font-weight: 600; color: var(--text-strong); font-size: 14px; }
.photos-lb-sub { color: var(--text-muted); font-size: 12.5px; margin-top: 2px; }
.photos-lb-cap { color: var(--text); font-size: 13px; margin-top: 6px; }
.photos-lb-actions { display: flex; gap: 8px; justify-content: center; margin-top: 8px; }

/* ═══ Photos: Job Detail feed + lightbox zoom (2026-07-18 v2) ═══════════ */
.detail-photos { margin-top: 18px; }
.detail-photos-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.detail-photos-head h3 { margin: 0; font-size: 15px; color: var(--text-strong); }
.detail-photos-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px;
}
.detail-photo-tile {
  aspect-ratio: 1; border-radius: 8px; overflow: hidden; cursor: pointer;
  border: 1px solid var(--border); background: var(--panel);
}
.detail-photo-tile:hover { border-color: var(--blue); }
.detail-photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.detail-photo-more {
  aspect-ratio: 1; border-radius: 8px; border: 1px dashed var(--border-strong);
  background: var(--panel); color: var(--text-soft); font: inherit; font-size: 13px; cursor: pointer;
}
.detail-photo-more:hover { border-color: var(--blue); color: var(--text); }

.photos-lb-imgwrap {
  max-width: min(92vw, 1400px); max-height: 68vh; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
}
.photos-lb-imgwrap .photos-lb-img {
  max-width: 100%; max-height: 68vh; border-radius: 8px;
  transition: transform .05s linear; will-change: transform; touch-action: none;
  user-select: none;
}
.photos-lb-zoombar { display: flex; gap: 6px; }

/* Photos tile — site address line (Matt 2026-07-18) */
.photo-tile-addr {
  font-size: 11.5px; color: var(--text-muted); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ═══ Photos lightbox v2 — CC-style: big stage + right info pane
   (Matt's spec 2026-07-18 afternoon) ═════════════════════════════════════ */
.photos-lightbox { background: rgba(0,0,0,.92); }
.photos-lb-shell { position: absolute; inset: 0; display: flex; }
.photos-lb-stage {
  flex: 1; position: relative; display: flex;
  align-items: center; justify-content: center; min-width: 0;
}
.photos-lb-stage .photos-lb-imgwrap {
  max-width: calc(100% - 40px); max-height: calc(100vh - 40px);
}
.photos-lb-stage .photos-lb-img { max-height: calc(100vh - 40px); }
.photos-lb-tools {
  position: absolute; top: 14px; left: 14px; z-index: 3;
  display: flex; gap: 2px; padding: 4px;
  background: #fff; border-radius: 10px; box-shadow: 0 2px 14px rgba(0,0,0,.35);
}
.photos-lb-tool {
  width: 34px; height: 34px; display: flex; align-items: center; justify-content: center;
  border: none; background: none; border-radius: 8px; cursor: pointer; color: #1c2b3a;
}
.photos-lb-tool svg { width: 18px; height: 18px; }
.photos-lb-tool:hover { background: rgba(0,0,0,.08); }
.photos-lb-tool[disabled] { opacity: .35; cursor: default; }
.photos-lb-tool[disabled]:hover { background: none; }
.photos-lb-count {
  position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%);
  color: rgba(255,255,255,.75); font-size: 12.5px;
}

.photos-lb-side {
  width: 340px; flex: 0 0 340px; background: var(--panel);
  border-left: 1px solid var(--border); padding: 18px 18px 14px;
  position: relative; overflow-y: auto; display: flex; flex-direction: column;
}
.photos-lb-side .photos-lb-x {
  position: absolute; top: 10px; right: 12px; font-size: 24px; line-height: 1;
  background: none; border: none; color: var(--text-muted); cursor: pointer;
}
.photos-lb-side .photos-lb-x:hover { color: var(--text-strong); }
.photos-lb-job {
  background: none; border: none; padding: 0; margin: 2px 24px 2px 0;
  font: inherit; font-size: 17px; font-weight: 700; color: var(--text-strong);
  text-align: left; cursor: pointer;
}
.photos-lb-job:hover { text-decoration: underline; color: var(--blue-bright); }
.photos-lb-addr2 { color: var(--text-muted); font-size: 13px; margin-bottom: 12px; }
.photos-lb-who {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 0 12px; border-bottom: 1px solid var(--border); margin-bottom: 12px;
}
.photos-lb-avatar {
  width: 36px; height: 36px; border-radius: 50%; flex: 0 0 36px;
  display: flex; align-items: center; justify-content: center;
  background: var(--blue); color: #fff; font-size: 13px; font-weight: 600;
}
.photos-lb-who-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.photos-lb-who-name { font-size: 13.5px; font-weight: 600; color: var(--text-strong); }
.photos-lb-who-date { font-size: 12px; color: var(--text-muted); margin-top: 1px; }
.photos-lb-mapbtn {
  width: 36px; height: 36px; border-radius: 9px; flex: 0 0 36px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--border); color: var(--text); cursor: pointer;
}
.photos-lb-mapbtn svg { width: 18px; height: 18px; }
.photos-lb-mapbtn:hover { border-color: var(--blue); color: var(--blue-bright); }
.photos-lb-desc-head {
  font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 6px;
}
.photos-lb-desc { font-size: 13.5px; color: var(--text); white-space: pre-wrap; }
.photos-lb-desc-empty { color: var(--text-muted); font-style: italic; }
.photos-lb-side-actions {
  margin-top: auto; padding-top: 14px; display: flex; flex-direction: column; gap: 8px;
}
.photos-lb-side-actions .photos-btn { text-align: center; }

@media (max-width: 900px) {
  .photos-lb-shell { flex-direction: column; }
  .photos-lb-side { width: auto; flex: 0 0 auto; max-height: 45vh; border-left: none; border-top: 1px solid var(--border); }
  .photos-lb-stage .photos-lb-imgwrap, .photos-lb-stage .photos-lb-img { max-height: 52vh; }
}

/* Rotate-save states (persisted rotation, 2026-07-18) */
.photos-lb-tool.is-saving { animation: photos-rot-spin 1s linear infinite; }
.photos-lb-tool.is-error { color: var(--red-text, #c0392b); }
@keyframes photos-rot-spin { to { transform: rotate(360deg); } }

/* ═══ Photos markup editor (Matt's locked 10-tool list, 2026-07-18) ═════ */
.photos-lb-shell.is-editing .photos-lb-tools,
.photos-lb-shell.is-editing .photos-lb-nav,
.photos-lb-shell.is-editing .photos-lb-count,
.photos-lb-shell.is-editing .photos-lb-side { display: none; }
/* Photo markup editor styling moved to css/photo-markup.css (mirrored from
   shared/tool-engines/photo-markup/) when the CRM adopted the shared editor,
   2026-07-29. The .photos-lb-shell.is-editing rule above stays here: that is
   lightbox chrome, not part of the editor. */

/* Description click-to-edit (overlay store, 2026-07-18) */
.photos-lb-desc-hint { font-weight: 400; text-transform: none; letter-spacing: 0; opacity: .6; margin-left: 6px; font-size: 11px; }
.photos-lb-desc[data-act="desc-edit"] { cursor: pointer; border-radius: 6px; padding: 4px 6px; margin: -4px -6px; }
.photos-lb-desc[data-act="desc-edit"]:hover { background: color-mix(in srgb, var(--blue) 12%, transparent); }
.photos-lb-desc-input {
  width: 100%; resize: vertical; font: inherit; font-size: 13.5px;
  background: var(--panel); color: var(--text); border: 1px solid var(--border-strong);
  border-radius: 8px; padding: 8px;
}
.photos-lb-desc-btns { display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px; }
.photos-btn-primary { background: var(--blue); border-color: var(--blue); color: #fff; }
/* Lightbox "Delete photo" — quiet red until armed, solid red once armed. */
.photos-btn-danger { color: #e05252; border-color: rgba(224, 82, 82, 0.45); }
.photos-btn-danger:hover { border-color: #e05252; }
.photos-btn-danger.is-armed { background: #c73f3f; border-color: #c73f3f; color: #fff; }
.photos-btn-danger svg { width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; }

/* ────────────────────────────────────────────────────────────────────
   Job Detail layout pass (2026-07-21, Matt's CC-comparison screenshots):
   address + dates joined the header, label dropdowns moved up under it,
   description sits below the hero row, and the Photos / Notes / Files
   sections became CC-style content tabs with count chips. */
/* Middle column of the hero row: Permits + BC Hydro side by side with the
   Description slotted into the dead space directly beneath them (Matt's
   follow-up screenshot — not below the whole row). */
.detail-hero-mid {
  flex: 1 1 520px; min-width: 320px;
  height: 256px;                 /* lock to the Street View thumb (384×256) so the description bottom sits flush with the thumbnail (Matt 2026-07-22) */
  display: flex; flex-direction: column; gap: 12px;
}
/* Permits + BC Hydro fill the strip above the description. The parent is a
   locked height, so each tile is a fixed size and scrolls INTERNALLY when its
   inspection list runs long — most-recent-first is already the sort order. */
.detail-hero-mid-panels {
  flex: 1 1 auto; min-height: 0;
  display: flex; gap: 18px; align-items: stretch; flex-wrap: nowrap;
}
.detail-hero-mid-panels .detail-hero-side {
  flex: 1 1 0; min-width: 0; max-width: none;
  height: 100%; overflow-y: auto;
  scrollbar-width: none;         /* Firefox: hide the scrollbar; wheel/drag still scroll (Matt 2026-07-22) */
  -ms-overflow-style: none;      /* legacy Edge */
}
.detail-hero-mid-panels .detail-hero-side::-webkit-scrollbar { width: 0; height: 0; display: none; }
/* Permits + BC Hydro headers read inline: title on the left, the sub note
   ("Verified from … portal" / "Connection requests") to its right (Matt
   2026-07-22). Scoped to the hero panels so the Job tools header is untouched. */
.detail-hero-mid-panels .detail-permits-head {
  flex-direction: row; align-items: baseline; flex-wrap: wrap; gap: 4px 8px;
}
/* Description takes the remaining strip and is slightly shrunk. resize is off
   so the locked layout can't be dragged out of alignment. */
.detail-hero-mid .detail-description { margin: 0; flex: 0 0 auto; gap: 4px; }
.detail-hero-mid .detail-description-textarea {
  flex: 0 0 auto; height: 60px; min-height: 0; resize: none;
}

.detail-subtitle-addr { margin-top: 3px; font-size: 13px; }
.detail-subtitle-addr a {
  color: var(--text); text-decoration: none;
  border-bottom: 1px dotted rgba(158, 176, 207, 0.35);
  transition: color 0.15s, border-color 0.15s;
}
.detail-subtitle-addr a:hover { color: var(--text-strong); border-bottom-color: rgba(230, 238, 252, 0.7); }
.detail-meta-line { margin-top: 4px; font-size: 12px; color: var(--text-muted); }

.detail-tabs {
  display: flex; gap: 2px; align-items: stretch;
  margin: 4px 0 0 0;
  border-bottom: 2px solid var(--border);
}
.detail-tab {
  appearance: none; background: none; border: none;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 14px 8px; margin-bottom: -2px;
  font: inherit; font-size: 13.5px; font-weight: 600;
  color: var(--text-muted); cursor: pointer;
  border-bottom: 2px solid transparent;
}
.detail-tab:hover { color: var(--text); }
.detail-tab.is-active { color: var(--text-strong, var(--text)); border-bottom-color: var(--blue-light, #60a5fa); }
.detail-tab-count {
  padding: 1px 8px; border-radius: 999px;
  background: rgba(148,163,184,0.16); color: var(--text-muted);
  font-size: 11px; font-weight: 700;
}
.detail-tab.is-active .detail-tab-count { background: rgba(96,165,250,0.18); color: var(--blue-light, #60a5fa); }
.detail-tab-count:empty { display: none; }

.detail-tab-panel { display: none; }
.detail-tab-panel.is-active { display: block; }
/* Inside a panel the tab bar already separates content — drop the
   sections' standalone top borders/margins. */
.detail-tab-panel.detail-photos,
.detail-tab-panel.detail-job-notes,
.detail-tab-panel.detail-crew-scope,
.detail-tab-panel.detail-cc-files { margin-top: 0; padding-top: 14px; border-top: none; }
/* Photos panel hosts its own drag-drop mask (reuses the CC-files mask
   classes, which anchor to the nearest positioned ancestor). */
.detail-photos { position: relative; }

.detail-panel-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
.detail-panel-sub { font-size: 12px; color: var(--text-muted); line-height: 1.45; }
.detail-panel-sub a { color: inherit; }
.detail-panel-actions { display: flex; gap: 8px; flex: none; align-items: center; }

/* ═══ Today watch stack — unified list redesign (2026-07-27) ═════════════
   The watch section had grown to 13 possible bars, each a full-width
   tinted banner in its own hue (amber/blue/red/green/cyan/violet/yellow/
   purple), and the injected "Awaiting results" bar's name links had NO
   rule at all — browser-default blue/visited-purple anchors, unreadable
   on the dark theme. New shape: ONE quiet contained list. Category hue
   lives only in the row dot; labels, counts, and names are neutral;
   severity (vehicle overdue, crew still clocked in) keeps its red on the
   dot, count, and the specific name.
   This is a pure override layer: it sits at the END of the file so its
   equal-specificity rules beat the per-bar blocks above by cascade. No
   markup or wiring changes — every bar class and click target is
   untouched, including the post-render-injected .pp-today-wait-bar from
   20-permits-portal.js. A future bar added to the stack inherits this
   treatment for free if it follows the dot/label/count/names span
   convention. */
.today-watch-stack {
  gap: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
/* Quiet day = zero bars. Hide the empty shell entirely — the template
   leaves whitespace text nodes between the holes, so :empty can never
   match; :has(> *) checks for element children only. */
.today-watch-stack:not(:has(> *)) { display: none; }
.today-watch-stack > div {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 7px 12px;
  gap: 10px;
}
.today-watch-stack > div + div { border-top: 1px solid var(--border-subtle); }
.today-watch-stack > div:hover { background: var(--row-hover-soft); }
/* Category dot — the one place the category keeps its hue. Uniform size,
   halo glows off. Background colors flow through from the per-bar rules
   above, including the red overdue / still-clocked-in flips. */
.today-watch-stack [class*="-dot"] {
  width: 7px; height: 7px;
  box-shadow: none;
}
/* Label column: fixed minimum so counts and names align down the list. */
.today-watch-stack [class*="-label"] {
  flex: 0 0 auto;
  min-width: 118px;
  color: var(--text);
  font-weight: 600;
}
.today-watch-stack [class*="-count"] {
  flex: 0 0 auto;
  min-width: 20px; text-align: center;
  padding: 1px 7px; border-radius: 100px;
  background: var(--panel-3);
  color: var(--text-strong);
  font-size: 11px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.today-watch-stack [class*="-names"],
.today-watch-stack [class*="-meta"] {
  color: var(--text-soft);
}
.today-watch-stack [class*="-money"] {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}
/* One link treatment for every clickable name in every bar. This is also
   THE fix for the previously unstyled .pp-wait-link (Awaiting results)
   anchors. (.billing-watch-name / .timeoff-watch-name are plain spans —
   whole-bar click — so they stay out of the underline group.) */
.today-watch-stack .permit-watch-name,
.today-watch-stack .ar-watch-name,
.today-watch-stack .fleet-watch-name,
.today-watch-stack .time-entries-watch-name,
.today-watch-stack .pp-wait-link {
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px dotted var(--text-subtle);
  cursor: pointer;
}
/* Severity survives the neutral flattening: red count pill + red name.
   (Declared after the neutral rules above — same specificity tier, so
   source order is what keeps these alive.) */
.today-watch-stack .today-fleet-bar-overdue .today-fleet-count,
.today-watch-stack .today-time-entries-bar-open .today-time-entries-count {
  background: rgba(248, 113, 113, 0.16);
  color: var(--red-bright);
}
.today-watch-stack .fleet-watch-name-overdue,
.today-watch-stack .time-entries-watch-name-open {
  color: var(--red-bright);
  border-bottom-color: rgba(248, 113, 113, 0.4);
}
.today-watch-stack .permit-watch-name:hover,
.today-watch-stack .ar-watch-name:hover,
.today-watch-stack .fleet-watch-name:hover,
.today-watch-stack .time-entries-watch-name:hover,
.today-watch-stack .pp-wait-link:hover {
  color: var(--text-strong);
  border-bottom-color: var(--text-strong);
}
/* Awaiting-results dot: the injected #2563eb (blue-600) reads muddy on
   the dark panel — use the theme blue so it flips per theme. Higher
   specificity than the injected .pp-today-wait-bar .today-permit-dot
   rule, so this wins regardless of stylesheet order. */
.today-watch-stack .pp-today-wait-bar .today-permit-dot { background: var(--blue); }

/* ═══════════════════════════════════════════════════════════════════════
   Today top row (2026-08-11 redesign)
   ═══════════════════════════════════════════════════════════════════════
   Watch mini-cards (left third) beside the Crew today tile (right two-
   thirds) — same 1fr/2fr split as .today-cal-rem-row below it so the two
   bands read as aligned columns. align-items:stretch pins both tiles to
   whichever is taller (Matt: no internal scrolling, ever). */
.today-top-row {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 16px;
  align-items: stretch;
  margin-bottom: 16px;
}
/* Grid children default to min-width:auto, so a crew row's no-wrap chip
   strip (Jackson: 4 chips) inflates the 2fr track past its share and the
   whole band overflows the pane — hours/badges clipped at the viewport
   edge (caught on prod 2026-08-11). min-width:0 lets the tracks hold
   their 1fr/2fr split and the chip strip clip inside its row instead. */
.today-top-row > * { min-width: 0; }

/* Round-2 consistency polish (Matt 2026-08-11 evening) */
/* Reminders header matches the pipeline-tile h3 type. */
.today-reminders-head h3 {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-strong);
}
/* Photos strip: thumbnails big enough to read without opening; title
   type matches the other tile headers. Wraps to extra rows instead of a
   horizontal scrollbar (Matt 2026-08-11). */
.today-photos-strip .today-photo-tile { width: 132px; height: 132px; }
.today-photos-strip .today-photos-row {
  flex-wrap: wrap;
  overflow-x: visible;
  padding-bottom: 0;
}
.today-photos-title { font-size: 15px; font-weight: 600; color: var(--text-strong); }
/* Pipeline tiles below the fold (Active jobs / Needs Scheduling / both
   Leads): show ~10 cards, scroll for the rest. */
.pipeline-tile-body.pt-capped {
  max-height: 540px;
  overflow-y: auto;
  scrollbar-width: thin;
}
.today-top-row .today-watch-col > .pipeline-tile,
.today-top-row .today-crew-col > .pipeline-tile {
  height: 100%;
  margin: 0;
}
@media (max-width: 980px) {
  .today-top-row { grid-template-columns: 1fr; }
  .today-top-row .today-watch-col > .pipeline-tile { height: auto; }
}

/* Watch Items tile (2026-08-11 round 2): back to the classic one-row-per-
   category divider list, now inside pipeline-tile chrome so it matches the
   other tiles. Rows keep to ONE line; when the item names overflow, the
   .wi-track span (wrapped in by renderToday) shuttle-scrolls slowly and
   pauses while the mouse is over the row. Bar builders untouched. */
.today-watch-tile { display: flex; flex-direction: column; }
.today-watch-tile .pipeline-tile-body.today-watch-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 0;
}
/* The stack's standalone panel chrome is redundant inside the tile. */
.today-watch-tile .today-watch-stack {
  border: none;
  background: transparent;
  border-radius: 0;
  box-shadow: none;
}
/* Quiet day: no bars → hide the whole tile, not just the inner stack. */
.today-watch-tile:not(:has(.today-watch-stack > *)) { display: none; }
.today-watch-tile .today-watch-stack > div {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  /* Top-align so a row whose names wrap to a second line keeps its dot,
     label, and count pinned to the first line. */
  align-items: flex-start;
}
.today-watch-tile .today-watch-stack [class*="-dot"] { margin-top: 5px; }
/* Names wrap to as many lines as they need — no scroll, no marquee
   (marquee removed same-day 2026-08-11 per Matt: moving text + the other
   scrollbars read as scrolling in every direction). */
.today-watch-tile .today-watch-stack [class*="-names"],
.today-watch-tile .today-watch-stack [class*="-meta"] {
  flex: 1 1 auto;
  min-width: 0;
  white-space: normal;
  line-height: 1.45;
}
/* A/R + Reimburse have a two-part body (money summary + names). As flex
   siblings the names got squeezed into a skinny wrapping column beside
   the money (Matt's 2026-08-11 report) — the -body wrapper makes them ONE
   flowing text line that wraps inside the content column like every other
   row. Inner spans forced inline so the generic -names flex rule above
   can't re-split them. */
.today-watch-tile .today-ar-body,
.today-watch-tile .today-reimburse-body {
  flex: 1 1 auto;
  min-width: 0;
  white-space: normal;
  line-height: 1.45;
}
.today-watch-tile .today-ar-body > span,
.today-watch-tile .today-reimburse-body > span {
  display: inline;
}

/* Crew today, compact (top-row placement). One line per crew member:
   dot · name · event chips (one strip, never wrapped) · hours/jobs · badge.
   display:contents dissolves the old two-line wrappers so the row's
   children can be re-ordered into a single flex line; the chips strip
   absorbs the leftover width and scrolls sideways when the day outgrows
   it (Matt 2026-08-17 — was clip-quietly; now every chip stays reachable
   without opening the breakdown modal). */
.today-crew-compact .today-crew-row {
  display: flex;
  /* Explicit row — the base .today-crew-row is a flex COLUMN (name line
     over chips line); without this the compact row stacked its pieces
     vertically, centered. Caught on prod 2026-08-11. */
  flex-direction: row;
  align-items: center;
  flex-wrap: nowrap;
  gap: 6px 8px;
  padding: 5px 10px;
}
.today-crew-compact .today-crew-row-top { display: contents; }
.today-crew-compact .today-crew-dot  { order: -3; flex: 0 0 auto; }
/* Fixed name column so every row's chips start at the same x — chip
   times line up vertically instead of ragged-right of each name
   (Matt 2026-08-11 round 2). Wide enough for the longest roster name. */
.today-crew-compact .today-crew-name {
  order: -2;
  flex: 0 0 76px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.today-crew-compact .today-crew-events {
  order: 0;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  /* Keep the strip's edge-scroll from chaining into iPad back-swipe. */
  overscroll-behavior-x: contain;
  gap: 4px;
  margin: 0;
}
/* Slimmer than the global 8px bar — this sits inside a 5px-padded row.
   No scrollbar-width here: setting the standard property makes Chrome
   ignore ::-webkit-scrollbar styling and rows grew 10px, not 4. */
.today-crew-compact .today-crew-events::-webkit-scrollbar { height: 4px; }
.today-crew-compact .today-crew-events::-webkit-scrollbar-track { background: transparent; }
.today-crew-compact .today-crew-events::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 2px;
}
.today-crew-compact .today-crew-events > * { flex: 0 0 auto; }
/* Right-side stats as aligned columns: the live elapsed tick (active rows
   only) sits LEFTMOST so hours + jobs keep one vertical line across rows
   whether or not a tick exists; hours right-align on a fixed column. */
.today-crew-compact .today-crew-stats {
  order: 1;
  flex: 0 0 auto;
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}
.today-crew-compact .today-crew-tick  { order: -1; min-width: 56px; text-align: right; }
.today-crew-compact .today-crew-hours { min-width: 42px; text-align: right; }
.today-crew-compact .today-crew-jobs  { min-width: 44px; text-align: right; }
/* Status badges + the END button are visual noise here — the live chip,
   green/blue dots, and checkmarks already say it (Matt 2026-08-11 r2).
   Ending an entry still works from the row's breakdown modal / Crew tab. */
.today-crew-compact .today-crew-badge-cell { display: none; }
/* Tile-head dots off for the top/calendar tiles — noise reduction. */
.today-crew-col .pt-dot,
.today-cal-twothirds .pt-dot { display: none; }

/* ═══════════════════════════════════════════════════════════════════════
   PeakDrag — touch drag support (2026-07-30)
   ═══════════════════════════════════════════════════════════════════════
   Companion styling for the PeakDrag transport in js/03-utils.js. Every
   drag surface in the CRM was mouse-only until now: HTML5 drag-and-drop
   (pipeline cards, rail, crew chips, tasks, sidebar) is not implemented
   for touch in iPadOS Safari at all, and the raw mouse handlers (calendar,
   Panel Schedule) never see a mousemove from a finger.

   Note there is deliberately NO blanket `touch-action: none` here. That
   would hand every gesture to us and make the calendar unscrollable on an
   iPad. Scroll-vs-drag is resolved in JS by the long press instead, so
   touch-action stays default and the page keeps scrolling normally until
   a drag actually arms. */

/* A long press on iOS otherwise raises the text-selection callout and the
   share sheet right as the drag is arming. Draggable surfaces opt out. */
.cal-event,
.pt-card,
.cal-rail-card,
.cal-crew-chip,
.reminder-row-draggable,
.nav-grip,
.ps-grid td.ps-cell {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
/* The card description is a real textarea — it has to stay selectable
   and editable, so it opts back in out of the blanket rule above. */
.cal-rail-card-desc {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

/* Lift feedback. The 400ms hold is invisible without it — you cannot tell
   a drag armed until you have already moved, which reads as lag. */
.peakdrag-lifted,
.peakdrag-armed {
  transform: scale(1.03);
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  z-index: 60;
}
.peakdrag-ghost {
  opacity: 0.88;
  box-shadow: 0 8px 28px rgba(0,0,0,0.40);
  transform: rotate(1deg);
  pointer-events: none;
}

/* Drop-line — where a drag-to-REORDER would land (2026-08-12). Used by the
   Calendar rail and the pipeline tiles via showDropLine() in 03-utils.js.

   A box-shadow, not a border or a spacer element: the line has to appear
   BETWEEN two cards without moving either of them, because the pointer is
   already hovering the gap and any reflow would slide the target out from
   under the finger mid-drag. Offset 6px with -4px spread paints a 2px bar
   just outside the card edge; the rest of the shadow rect sits behind the
   card's own background, which is why nothing else shows. */
.drop-line-before { box-shadow: 0 -6px 0 -4px var(--blue); }
.drop-line-after  { box-shadow: 0  6px 0 -4px var(--blue); }

/* any-pointer (not pointer) on purpose: a touchscreen laptop reports its
   trackpad as the PRIMARY pointer, so `pointer: coarse` misses it and the
   finger targets stay mouse-sized on exactly the hybrid device this work
   is meant to serve. any-pointer matches if ANY attached input is coarse. */
@media (any-pointer: coarse) {
  /* 7px is a mouse-sized edge. Apple's own guidance is 44pt; 20px is the
     practical floor for an edge you drag rather than tap, and it stays
     inside a 27px half-hour tile without swallowing the whole thing. */
  .cal-event-resize-handle { height: 20px; }
  /* Make the grab edges visible — with no hover state on touch there is
     otherwise nothing at all indicating a tile can be resized. */
  .cal-event-resize-handle-top,
  .cal-event-resize-handle-bottom {
    background: linear-gradient(to bottom, rgba(255,255,255,0.16), transparent);
  }
  .cal-event-resize-handle-bottom {
    background: linear-gradient(to top, rgba(255,255,255,0.16), transparent);
  }
  /* Hover-revealed controls never reveal on touch without a first "hover"
     tap, which makes them read as broken. Show them outright. */
  .job-row .job-title-edit,
  .jc-row .jc-close-btn,
  .permits-row .permits-relink-btn,
  .qbo-row .qbo-row-actions,
  .crew-bd-period .crew-bd-period-actions,
  .crm-jn-row-del,
  .cal-assign-badge .cal-assign-badge-x,
  /* 2026-08-14 — second sweep. Active Jobs was the worst offender: the card
     select checkbox only appeared on hover, and while selecting ONE card
     reveals the rest (body:has(.aj-card-selected)), the first one was
     invisible — so multi-select was unreachable from a tablet entirely.
     The rematch buttons on list rows were hover-only too; Job Detail and
     Client Detail already use .rematch-btn-always, the rows never did. */
  .aj-card .aj-card-select,
  .aj-card .aj-title-edit,
  .aj-card .aj-rematch-btn,
  .aj-status-strip .status-select:not(.has-value),
  .rematch-btn,
  .section-block-toggle,
  .section-block-clear {
    opacity: 1;
  }
  /* Sidebar reorder grip: hover-revealed on desktop, so without this it is
     invisible on touch and nav can't be reordered from the iPad at all.
     0.5 matches what a mouse user sees on hover rather than shouting. */
  .nav-grip { opacity: 0.5; }
  /* The ⠿ grip is the instant-drag shortcut on touch (no hold needed), so
     it needs to be big enough to hit deliberately. */
  .reminder-drag-handle {
    padding: 6px 10px;
    margin: -6px -4px;
    font-size: 15px;
  }
}

/* Touch route into the calendar event menu. Rendered on every tile but
   hidden for mouse users, where right-click already opens the same menu
   and a permanent ⋯ would just be clutter on a 27px tile. */
.cal-event-menu-btn {
  display: none;
  position: absolute;
  top: 1px; right: 1px;
  width: 26px; height: 22px;
  padding: 0; margin: 0;
  border: 0; border-radius: 5px;
  background: rgba(0,0,0,0.22);
  color: var(--text);
  font-size: 15px; line-height: 20px;
  cursor: pointer;
  z-index: 3;
}
.cal-event-menu-btn:active { background: rgba(0,0,0,0.38); }
@media (any-pointer: coarse) {
  .cal-event-menu-btn { display: block; }
  /* Keep the button clear of the colour dot, which also lives top-right. */
  .cal-event-color-cycle { right: 30px; }
}

/* Panel Schedule sweep-select on touch (2026-07-30).
   A sweep is always a VERTICAL run within one column, and the grid itself
   is what scrolls HORIZONTALLY when the panel is wide. pan-x hands the
   browser exactly the axis it needs and reserves the other for the sweep,
   which beats `touch-action: none` (kills table scrolling entirely) and
   beats leaving it default (browser claims the drag, sweep never runs). */
.ps-grid td.ps-cell { touch-action: pan-x; }

/* ── All-day bar horizontal resize (2026-08-05) ──────────────────────
   Left/right grab zones on each all-day bar; drag across day columns to
   change From/To. Horizontal twin of the timed tiles' top/bottom
   handles (.cal-event-resize-handle). Clipped edges (bar continues past
   the visible week) and stat holidays render no handle — wired in
   _buildAlldaySection / renderCalendar (07-views.js). */
.cal-allday-event { position: relative; }
.cal-allday-resize-handle {
  position: absolute;
  top: 0; bottom: 0;
  width: 10px;
  cursor: ew-resize;
  background: transparent;
  transition: background 0.12s;
  touch-action: none;
  z-index: 2;
}
.cal-allday-resize-handle-l { left: 0; }
.cal-allday-resize-handle-r { right: 0; }
.cal-allday-resize-handle:hover,
.cal-allday-resize-handle:active { background: rgba(255,255,255,0.22); }
.cal-allday-event.cal-allday-resizing {
  filter: brightness(1.2);
  outline: 1px dashed rgba(255,255,255,0.55);
  outline-offset: -1px;
}

  /* ═══ Today — visual pass (2026-08-15, rev 2) ════════════════════════════
     Scoped to #today-view. Delete this block to revert Today exactly.

     TYPE SIZES ARE UNCHANGED FROM LIVE. An earlier revision of this block
     enlarged them; Matt reviewed it on the branch and preferred the original
     scale, so nothing here sets a font-size except where a value was flat-out
     wrong. The improvements are grouping, colour and alignment.

     Panel borders and radii are also left alone for the same reason.
     ══════════════════════════════════════════════════════════════════════ */

  /* ── Watch items: action group, then status group ──────────────────────
     Ordering is done with flex `order`, NOT by reordering the DOM, so
     20-permits-portal.js can keep injecting its "Awaiting results" bar
     directly after .today-permit-bar without knowing groups exist.
     Rule (Matt): an action item is something he can do right now from this
     desk. Everything else is status. */
  #today-view .today-watch-stack { display: flex; flex-direction: column; }

  /* can-do-now */
  #today-view .today-watch-stack > .today-time-entries-bar { order: 1; }
  #today-view .today-watch-stack > .today-inspection-bar   { order: 2; }
  #today-view .today-watch-stack > .today-timeoff-bar      { order: 3; }
  #today-view .today-watch-stack > .today-permit-bar       { order: 4; }
  #today-view .today-watch-stack > .today-billing-bar      { order: 5; }
  #today-view .today-watch-stack > .today-quote-bar        { order: 6; }
  #today-view .today-watch-stack > .today-panelsched-bar   { order: 7; }
  #today-view .today-watch-stack > .today-reimburse-bar    { order: 8; }
  #today-view .today-watch-stack > .today-receipts-bar     { order: 9; }

  /* The JS emits this only when both groups are non-empty, so no
     hide-when-lonely rule is needed here — and none is POSSIBLE:
     :first-child/:last-child test DOM order, and this element is always
     DOM-last while flex `order` places it visually mid-list. border-top is
     suppressed so the gap reads as space, not as a doubled hairline against
     the next row's own divider. */
  #today-view .today-watch-stack > .today-watch-split {
    order: 15; height: 0; margin: 7px 0 0; border-top: none;
  }

  /* just-so-you-know. NOTE: .pp-today-wait-bar also carries
     .today-permit-bar, so this rule must come AFTER the permit rule above —
     equal specificity, later wins. */
  #today-view .today-watch-stack > .pp-today-wait-bar { order: 20; }
  #today-view .today-watch-stack > .today-ar-bar      { order: 21; }
  #today-view .today-watch-stack > .today-bills-bar   { order: 22; }
  #today-view .today-watch-stack > .today-fleet-bar   { order: 23; }
  /* Apprentice raise-due rides the fleet-bar chrome but is an ACTION (key the
     raise, then mark it applied) — must come AFTER the fleet rule above for
     the same equal-specificity later-wins reason as .pp-today-wait-bar. */
  #today-view .today-watch-stack > .today-appr-bar    { order: 10; }

  /* Category dots retired (Matt 2026-08-15). Amber/blue/green/cyan/red/green
     down the left edge was the first thing the eye hit, and it encoded a
     category the label beside it already stated. */
  #today-view .today-watch-stack [class*="-dot"] { display: none; }

  /* Counts LEFT-align in their column so the 1 of "19" sits under every other
     single digit (Matt: "the 1 should be in line with all the other single
     digits instead of the 9"). Fixed column, tabular figures. */
  #today-view .today-watch-stack [class*="-count"] {
    background: none !important; border: none; padding: 0;
    min-width: 24px; text-align: left;
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
  }
  #today-view .today-watch-stack [class*="-label"] { min-width: 112px; }

  /* ONE colour, and it means one thing: you can action this from your desk.
     Everything else — including Fleet, which used to be red — is neutral,
     because being in the watch list is already the signal (Matt). */
  #today-view .today-watch-stack > .today-time-entries-bar [class*="-label"],
  #today-view .today-watch-stack > .today-time-entries-bar [class*="-count"],
  #today-view .today-watch-stack > .today-inspection-bar   [class*="-label"],
  #today-view .today-watch-stack > .today-inspection-bar   [class*="-count"],
  #today-view .today-watch-stack > .today-timeoff-bar      [class*="-label"],
  #today-view .today-watch-stack > .today-timeoff-bar      [class*="-count"],
  #today-view .today-watch-stack > .today-permit-bar       [class*="-label"],
  #today-view .today-watch-stack > .today-permit-bar       [class*="-count"],
  #today-view .today-watch-stack > .today-billing-bar      [class*="-label"],
  #today-view .today-watch-stack > .today-billing-bar      [class*="-count"],
  #today-view .today-watch-stack > .today-quote-bar        [class*="-label"],
  #today-view .today-watch-stack > .today-quote-bar        [class*="-count"],
  #today-view .today-watch-stack > .today-panelsched-bar   [class*="-label"],
  #today-view .today-watch-stack > .today-panelsched-bar   [class*="-count"],
  #today-view .today-watch-stack > .today-reimburse-bar    [class*="-label"],
  #today-view .today-watch-stack > .today-reimburse-bar    [class*="-count"],
  #today-view .today-watch-stack > .today-receipts-bar     [class*="-label"],
  #today-view .today-watch-stack > .today-receipts-bar     [class*="-count"] {
    color: var(--amber-text);
  }
  /* Status rows, including the wait bar which rides the permit class — must
     come after the amber block for the same later-wins reason. */
  #today-view .today-watch-stack > .pp-today-wait-bar [class*="-label"],
  #today-view .today-watch-stack > .today-ar-bar      [class*="-label"],
  #today-view .today-watch-stack > .today-bills-bar   [class*="-label"],
  #today-view .today-watch-stack > .today-fleet-bar   [class*="-label"] {
    color: var(--text);
  }
  #today-view .today-watch-stack > .pp-today-wait-bar [class*="-count"],
  #today-view .today-watch-stack > .today-ar-bar      [class*="-count"],
  #today-view .today-watch-stack > .today-bills-bar   [class*="-count"],
  #today-view .today-watch-stack > .today-fleet-bar   [class*="-count"] {
    color: var(--text-muted);
  }
  /* Fleet loses its red entirely (Matt: "I will give it attention if it's in
     the watch section"). NOTE the vehicle is a <span class="fleet-watch-name">,
     NOT an anchor — an earlier revision targeted `a` and missed it completely,
     which is why the truck stayed red on the branch. Cover the spans and both
     severity modifiers. */
  #today-view .today-watch-stack .fleet-watch-name,
  #today-view .today-watch-stack .fleet-watch-name-overdue,
  #today-view .today-watch-stack .fleet-watch-name-soon,
  #today-view .today-watch-stack > .today-fleet-bar [class*="-names"],
  #today-view .today-watch-stack > .today-fleet-bar [class*="-names"] a {
    color: var(--text-soft);
  }
  #today-view .today-watch-stack > .today-fleet-bar-overdue [class*="-count"],
  #today-view .today-watch-stack > .today-fleet-bar-soon    [class*="-count"] {
    color: var(--text-muted);
  }
  /* Raise-due is in the action group, so it takes the action amber — and it
     also carries .today-fleet-bar, so this must sit AFTER every fleet status
     rule above (equal specificity, later wins). */
  #today-view .today-watch-stack > .today-appr-bar [class*="-label"],
  #today-view .today-watch-stack > .today-appr-bar [class*="-count"] {
    color: var(--amber-text);
  }
  #today-view .today-watch-stack .appr-watch-name { cursor: pointer; }
  #today-view .today-watch-stack .appr-watch-name:hover { text-decoration: underline; }
  #today-view .appr-watch-reason { color: var(--text-muted); }
  /* The reason ("overdue 89 km · 2d") now renders as text beside the vehicle
     instead of hiding in a title attribute, so the row explains itself. */
  #today-view .fleet-watch-reason { color: var(--text-muted); }

  /* Names stop being underlined blue — a lot of blue for text you read more
     often than you click. Still links, underline on hover. */
  #today-view .today-watch-stack [class*="-names"] a {
    color: var(--text-soft); border-bottom-color: transparent;
  }
  #today-view .today-watch-stack [class*="-names"] a:hover {
    color: var(--text-strong); border-bottom-color: currentColor;
  }

  /* ── Reminders ─────────────────────────────────────────────────────────
     Drag grip hidden (drag still works by grabbing the row); Snooze fades in
     on hover instead of sitting under every reminder on its own line. */
  #today-view .reminder-snooze-btn {
    background: none; border: none; padding: 0;
    color: var(--text-muted);
  }
  /* Hide-until-hover ONLY where hover exists. On the iPad there is no hover,
     so an unconditional opacity:0 makes Snooze unreachable and the grip
     invisible — same class of bug as the sidebar two-tap fix (2026-08-14).
     Touch devices keep both permanently visible. */
  @media (hover: hover) {
    #today-view .reminder-drag-handle { visibility: hidden; width: 0; margin: 0; padding: 0; }
    #today-view .reminder-row:hover .reminder-drag-handle { visibility: visible; }
    #today-view .reminder-snooze-btn { opacity: 0; transition: opacity 120ms ease; }
    #today-view .reminder-row:hover .reminder-snooze-btn,
    #today-view .reminder-snooze-btn:focus-visible { opacity: 1; }
    #today-view .reminder-snooze-btn:hover { color: var(--text-strong); }
  }

  /* Inline edit — the text becomes the field IN PLACE, at the same size and
     position, so the words do not jump when you start typing. The date sits
     directly beneath. Replaces the old .reminder-edit-panel that opened below
     the row; that element no longer exists. */
  #today-view .rem-inline-edit { width: 100%; }
  #today-view .rem-inline-edit .rem-edit-title {
    width: 100%; box-sizing: border-box;
    font: inherit; font-size: 13px;          /* matches .reminder-summary */
    padding: 4px 8px;
    color: var(--text-strong); background: var(--panel-3);
    border: 1px solid var(--blue); border-radius: 6px;
    box-shadow: 0 0 0 3px var(--blue-soft);
    outline: none;
  }
  #today-view .rem-edit-date-row {
    display: flex; align-items: center; gap: 8px; margin-top: 6px;
    flex-wrap: wrap;
  }
  #today-view .rem-edit-date-row .rem-edit-date {
    font: inherit; font-size: 12px;
    padding: 4px 7px;
    color: var(--text); background: var(--panel-3);
    border: 1px solid var(--border); border-radius: 6px;
    color-scheme: dark;
  }
  [data-theme="light"] #today-view .rem-edit-date-row .rem-edit-date { color-scheme: light; }
  #today-view .rem-edit-clear-date {
    background: none; border: none; padding: 0;
    font: inherit; font-size: 12px; color: var(--text-muted);
    text-decoration: underline; text-underline-offset: 2px; cursor: pointer;
  }
  #today-view .rem-edit-clear-date:hover { color: var(--text-strong); }
  #today-view .rem-edit-hint { font-size: 11px; color: var(--text-subtle); }
  /* While the PATCH is in flight — inputs are disabled by the handler, this
     just makes that visible. On failure the editor stays open with the text
     intact rather than closing and losing it. */
  #today-view .rem-inline-edit.is-saving { opacity: 0.6; }

  /* ═══ Inbox — visual pass (2026-08-15) ═══════════════════════════════════
     Design approved from shared/docs/design/peak-inbox-visual.html, Option B.
     Scoped to #comms-view. Delete this block to revert the Inbox exactly.

     Rows were bordered, radiused, left-railed cards stacked with a gap — four
     boxes for four conversations. Apple reserves cards for grouped content and
     uses inset hairline dividers for lists; a list of boxes is the loudest
     web-dashboard tell there is. Type sizes are LEFT ALONE, same as Today.
     ══════════════════════════════════════════════════════════════════════ */

  /* One continuous list, not a stack of objects. */
  #comms-view .cx-wrap { gap: 0; }
  #comms-view .cx-card {
    background: none;
    border: none;
    border-radius: 0;
    box-shadow: none;
    padding: 11px 4px;
    display: grid;
    grid-template-columns: 42px 1fr;
    column-gap: 13px;
    align-items: start;
    position: relative;
  }
  /* Divider inset to start after the avatar, so the eye reads one column
     rather than four separate rows. */
  /* Inset = 4px card padding + 42px avatar + 13px column gap, so the line
     starts exactly where the text does. */
  #comms-view .cx-card + .cx-card::before {
    content: ''; position: absolute; left: 59px; right: 0; top: 0;
    height: 1px; background: var(--border-subtle);
  }
  #comms-view .cx-card:hover {
    background: var(--row-hover-soft);
    border: none; box-shadow: none;
  }
  /* The amber left rail is gone — the timestamp carries "waiting" now. */
  #comms-view .cx-card.is-waiting { border-left: none; }

  #comms-view .cx-avatar {
    width: 42px; height: 42px; border-radius: 50%;
    display: grid; place-items: center;
    font-size: 15px; font-weight: 600; color: #fff;
    letter-spacing: .01em; flex: none; user-select: none;
  }
  #comms-view .cx-card-body { min-width: 0; display: block; }
  #comms-view .cx-card-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: nowrap; }
  #comms-view .cx-name {
    flex: 1; min-width: 0;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* Waiting is the ONLY coloured thing on a row, and it sits on the one value
     that answers "how long has this person been ignored". */
  #comms-view .cx-when { margin-left: 0; flex: none; }
  #comms-view .cx-when-wait { color: var(--amber); font-weight: 600; }

  /* Address · company. Quiet, one line, ellipsised. */
  #comms-view .cx-meta {
    display: block; margin-top: 1px;
    font-size: 12.5px; color: var(--text-faint);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #comms-view .cx-card-preview { display: block; margin-top: 2px; }
  /* "You:" instead of the ↗ glyph — readable without a legend. */
  #comms-view .cx-you { color: var(--text-faint); }

  /* The toolbar loses its box; it is a count, not a control panel. */
  #comms-view .cx-toolbar { padding: 2px 4px 10px; }

  /* ═══ Inbox — split pane (2026-08-16, Matt-approved 8-decision spec) ═════
     Threads left (fixed 340px), conversation right, iOS Messages styling:
     blue outbound / grey inbound bubbles, centred time separators, calls as
     system notes, rounded compose with a round send. Below 900px the split
     collapses to the pre-split flow: full-width list, open replaces it, the
     back button appears. Scoped to #comms-view; delete to revert.
     ══════════════════════════════════════════════════════════════════════ */

  #comms-view .cx-split {
    display: grid; grid-template-columns: 340px 1fr;
    background: var(--panel);
    border-radius: var(--radius-lg, 18px);
    overflow: hidden;
    height: calc(100vh - 230px);
    min-height: 460px;
    box-shadow: var(--shadow-card);
  }
  #comms-view .cx-list {
    border-right: 1px solid var(--border-subtle);
    display: flex; flex-direction: column; min-width: 0;
  }
  #comms-view .cx-rows { overflow-y: auto; flex: 1; }
  #comms-view .cx-toolbar { padding: 12px 14px 8px; }

  /* List rows: the shipped Option-B design, re-inset for the 14px list
     padding (divider = 14 padding + 42 avatar + 13 gap = 69). */
  #comms-view .cx-card { padding: 11px 14px; }
  #comms-view .cx-card + .cx-card::before { left: 69px; }
  #comms-view .cx-card.is-open { background: var(--blue-soft); }
  #comms-view .cx-card.is-open::before,
  #comms-view .cx-card.is-open + .cx-card::before { display: none; }

  /* ── Conversation pane ── */
  #comms-view .cx-conv {
    display: flex; flex-direction: column; min-width: 0;
    background: var(--panel-2);
  }
  #comms-view .cx-conv-empty {
    margin: auto; color: var(--text-muted); font-size: 13.5px;
  }
  #comms-view .cx-head {
    display: flex; align-items: center; gap: 11px;
    padding: 10px 16px; border-bottom: 1px solid var(--border-subtle);
    flex: none;
  }
  #comms-view .cx-head-avatar { width: 34px; height: 34px; font-size: 12.5px; }
  #comms-view .cx-head-id { min-width: 0; }
  #comms-view .cx-head-name {
    font-size: 14.5px; font-weight: 650; color: var(--text-strong);
    letter-spacing: -0.01em;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #comms-view .cx-head-sub {
    font-size: 11.5px; color: var(--text-muted); margin-top: 1px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  #comms-view .cx-thread-actions { margin-left: auto; flex: none; }
  /* Waiting folds into the one control that clears it. */
  #comms-view .cx-btn-wait { color: var(--amber); }
  /* The back button belongs to the collapsed flow only. */
  #comms-view .cx-back { display: none; }

  /* Attribution — the quiet line under the header. The editing state keeps
     its input + datalist + Save/Cancel untouched, just tightened. */
  #comms-view .cx-attr-set {
    padding: 6px 16px; font-size: 12px; color: var(--text-muted);
    border-bottom: 1px solid var(--border-subtle); flex: none;
  }
  #comms-view .cx-attr {
    padding: 8px 16px; border-bottom: 1px solid var(--border-subtle); flex: none;
  }

  /* ── Messages ── */
  #comms-view .cx-messages {
    flex: 1; overflow-y: auto;
    padding: 16px 16px 6px;
    display: flex; flex-direction: column;
  }
  #comms-view .cx-tstamp {
    text-align: center; font-size: 11px; color: var(--text-muted);
    margin: 10px 0 6px; flex: none;
  }
  #comms-view .cx-syscall {
    text-align: center; font-size: 12px; color: var(--text-muted);
    margin: 8px 0; flex: none;
  }
  #comms-view .cx-syscall a { color: var(--blue-bright); text-decoration: none; }
  #comms-view .cx-msg {
    display: flex; flex-direction: column; max-width: 72%; flex: none;
  }
  #comms-view .cx-msg + .cx-msg { margin-top: 5px; }
  #comms-view .cx-msg.is-in  { align-self: flex-start; align-items: flex-start; }
  #comms-view .cx-msg.is-out { align-self: flex-end;   align-items: flex-end; }
  #comms-view .cx-bubble {
    padding: 8px 13px; border-radius: 18px;
    font-size: 13.5px; line-height: 1.4;
    overflow-wrap: anywhere;
  }
  #comms-view .cx-msg.is-in .cx-bubble {
    background: var(--panel-3); color: var(--text);
    border-bottom-left-radius: 5px;
  }
  #comms-view .cx-msg.is-out .cx-bubble {
    background: var(--blue); color: var(--on-color);
    border-bottom-right-radius: 5px;
  }
  #comms-view .cx-msg.is-out .cx-bubble a { color: var(--on-color); }
  [data-theme="light"] #comms-view .cx-msg.is-in .cx-bubble {
    background: #e9eaee; color: var(--text-strong);
  }
  #comms-view .cx-msg-meta {
    font-size: 10.5px; color: var(--text-muted); margin-top: 3px;
  }
  /* Auto-reply always reads — the customer got a robot, that changes meaning.
     Human sender stamps stay in the DOM but only surface on hover; WHEN CREW
     LOGINS CAN SEND, delete the hover gate below so names show permanently. */
  #comms-view .cx-stamp-auto { color: var(--amber-text); }
  @media (hover: hover) {
    #comms-view .cx-stamp-human { opacity: 0; transition: opacity 120ms ease; }
    #comms-view .cx-msg:hover .cx-stamp-human { opacity: 1; }
  }

  /* ── Compose ── */
  #comms-view .cx-reply {
    padding: 10px 14px 12px; border-top: 1px solid var(--border-subtle); flex: none;
  }
  #comms-view .cx-reply-row { display: flex; gap: 9px; align-items: flex-end; }
  #comms-view .cx-reply-text {
    flex: 1; resize: none; min-height: 38px; max-height: 120px;
    background: var(--panel-3); color: var(--text);
    border: 1px solid var(--border-subtle); border-radius: 18px;
    padding: 9px 14px; font: 13.5px/1.4 inherit;
  }
  #comms-view .cx-reply-text:focus { outline: none; border-color: var(--blue); }
  #comms-view .cx-send {
    width: 34px; height: 34px; border-radius: 50%; border: none; flex: none;
    background: var(--blue); color: var(--on-color);
    font-size: 16px; line-height: 1; cursor: pointer;
    display: grid; place-items: center;
  }
  #comms-view .cx-send:disabled { opacity: 0.35; cursor: default; }
  #comms-view .cx-reply-foot {
    display: flex; gap: 10px; margin-top: 5px; padding: 0 4px;
    font-size: 11px; color: var(--text-muted);
  }
  #comms-view .cx-reply-foot .cx-reply-hint { margin-left: auto; }

  /* ── Collapse below 900px: exactly the pre-split flow ── */
  @media (max-width: 899px) {
    #comms-view .cx-split { display: block; height: auto; min-height: 0; }
    #comms-view .cx-list { border-right: none; }
    #comms-view .cx-split.cx-has-open .cx-list { display: none; }
    #comms-view .cx-split:not(.cx-has-open) .cx-conv { display: none; }
    #comms-view .cx-conv { min-height: 70vh; }
    #comms-view .cx-back { display: inline-flex; }
  }

  /* ═══ Billing — visual pass (2026-08-16, Matt-approved 7-decision spec) ══
     Aesthetics only: same layout, same controls, same handlers. Scoped to the
     billing-only bwa-/bw- class families. Delete this block to revert.
     Spec + mockup: shared/docs/design/peak-billing-visual.html
     ══════════════════════════════════════════════════════════════════════ */

  /* 1 ── Title drops the caps costume; toolbar keeps ONE primary. */
  .bw-section-rule {
    text-transform: none; letter-spacing: -0.012em;
    font-size: 15px; font-weight: 650; color: var(--text-strong);
    border-bottom: none;
  }
  .bw-section-rule::before { display: none; }

  .bwa-meta .bwa-refresh,
  .bwa-meta .bwa-close-cycle,
  .bwa-meta .bwa-archive-before-btn {
    background: var(--panel-2); color: var(--text);
    border: 1px solid var(--border-subtle); border-radius: 8px;
  }
  .bwa-meta .bwa-refresh:hover,
  .bwa-meta .bwa-close-cycle:hover,
  .bwa-meta .bwa-archive-before-btn:hover {
    background: var(--row-hover); border-color: var(--border-strong);
    color: var(--text-strong);
  }
  .bwa-meta .bwa-approve-all {
    background: var(--blue); color: var(--on-color);
    border: 1px solid transparent; border-radius: 8px; font-weight: 650;
  }
  .bwa-meta .bwa-approve-all:hover { background: var(--blue-hover); }
  /* Reset clears every per-card decision — a quiet ghost at the end, not a
     red alarm sitting mid-toolbar. */
  .bwa-meta .bwa-reset-cycle {
    background: none; border: 1px solid transparent; color: var(--text-muted);
  }
  .bwa-meta .bwa-reset-cycle:hover { color: var(--red-text); }
  .bwa-meta .bwa-groupby-btn {
    background: var(--panel-2); border: 1px solid var(--border-subtle);
    color: var(--text-soft); border-radius: 8px;
  }
  .bwa-meta .bwa-groupby-btn-active {
    background: var(--blue-soft); border-color: transparent;
    color: var(--text-strong); font-weight: 600;
  }

  /* 2 ── Amber stops being furniture. */
  /* Notes banner: one quiet line unless a note actually exists. The amber
     chrome belonged to "all caught up", which needs none. */
  .bwa-notes-section .bwa-notes-details,
  .bwa-notes-section .bwa-notes-details summary {
    border: none; background: none; box-shadow: none;
  }
  .bwa-notes-section .bwa-notes-details summary { padding: 4px 2px; }
  .bwa-notes-section summary strong {
    font-size: 12.5px; font-weight: 600; color: var(--text-soft);
  }
  .bwa-notes-section .bwa-notes-count-zero {
    color: var(--text-muted); font-size: 12px;
  }
  /* Unresolved notes DO earn the colour. */
  .bwa-notes-section .bwa-notes-count:not(.bwa-notes-count-zero) {
    color: var(--amber-text); font-weight: 600;
  }
  .bwa-notes-section .bwa-note-add-btn {
    background: none; border: none; color: var(--blue-bright);
    font-weight: 500; padding: 2px 4px;
  }

  /* Date group heads: a date is not a warning. Sticky behaviour is kept —
     the flat page background still masks content scrolling beneath. */
  .bwa-day-head {
    background: var(--bg);
    border: none; border-left: none; border-radius: 0;
    box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none;
    padding: 10px 2px 8px;
  }
  .bwa-day-label { color: var(--text-strong); font-size: 13px; font-weight: 650; }
  .bwa-day-count {
    background: none; border: none; padding: 0;
    color: var(--text-muted); font-size: 12px; font-weight: 500;
  }
  .bwa-day-total { font-variant-numeric: tabular-nums; }

  /* 3 ── Card head: identity, not chip salad. */
  .bwa-card-head { background: none; }
  .bwa-link-chip {
    background: none; border: none; padding: 2px 0;
    font-weight: 600; font-size: 13px;
  }
  .bwa-link-chip-cc  { color: var(--blue-bright); }
  .bwa-link-chip-qbo { color: var(--green-text); }
  .bwa-link-chip:hover { text-decoration: underline; text-underline-offset: 2px; }
  .bwa-chip-clear, .bwa-chip-change {
    background: none; border: none; color: var(--text-muted);
    font-size: 11.5px; padding: 2px 4px;
  }
  .bwa-chip-clear:hover, .bwa-chip-change:hover { color: var(--text-strong); }
  /* The dark band under every header goes; a hairline does the separating. */
  .bwa-card-controls {
    background: transparent;
    border-top: 1px solid var(--border-subtle);
    border-bottom: 1px solid var(--border-subtle);
  }

  /* Status badge -> status text (same treatment Matt approved app-wide). */
  .bwa-badge {
    background: none !important; border: none !important; padding: 0;
    border-radius: 0; text-transform: none; letter-spacing: 0;
    font-size: 11.5px; font-weight: 600;
  }
  .bwa-badge-pending  { color: var(--text-muted); }
  .bwa-badge-approved { color: var(--green-text); }
  .bwa-badge-unbill   { color: var(--amber-text); }
  .bwa-badge-quoted   { color: var(--purple); }

  /* 6 ── Quoted cards: the wash becomes a labelled state by the amount.
     Approved/late/unbillable header tints are KEPT — they are genuine state,
     and with the base blue wash gone they finally read cleanly. */
  .bwa-card-quoted .bwa-card-head { background: none; }
  .bwa-card-total-tag {
    background: none; border: none; padding: 0;
    text-transform: none; letter-spacing: 0;
    color: var(--amber-text); font-weight: 650; font-size: 11px;
  }

  /* 5 ── Section labels lose the caps; markup reads as arithmetic. */
  .bwa-section-label {
    text-transform: none; letter-spacing: 0;
    font-size: 12px; font-weight: 600; color: var(--text-muted);
  }
  .bwa-line-markup {
    background: none; border: none; color: var(--text-muted);
  }
  .bwa-line-markup-input { background: transparent; border-color: transparent; }
  .bwa-line-markup:hover .bwa-line-markup-input,
  .bwa-line-markup-input:focus { border-color: var(--border); background: var(--panel-3); }

  /* 4/7 ── Per-line actions surface on the row you're on. Touch devices keep
     everything visible (same @media(hover:hover) rule as Reminders — an iPad
     has no hover, and opacity:0 there means unreachable).
     Exceptions that must stay visible even off-hover:
       · an ACTIVE kind override (it is state, not an affordance)
       · the dirty-edit inputs (an edited value must keep its flag)          */
  .bwa-mat-omit-btn, .bwa-line-kind-toggle {
    background: none; border: 1px solid transparent;
    color: var(--text-muted); border-radius: 6px;
  }
  .bwa-mat-omit-btn:hover, .bwa-line-kind-toggle:hover {
    color: var(--text-strong); background: var(--row-hover);
  }
  .bwa-line-kind-toggle-active { color: var(--amber-text); }
  @media (hover: hover) {
    .bwa-line .bwa-mat-omit-btn,
    .bwa-line .bwa-line-kind-toggle:not(.bwa-line-kind-toggle-active) {
      opacity: 0; transition: opacity 120ms ease;
    }
    .bwa-line:hover .bwa-mat-omit-btn,
    .bwa-line:focus-within .bwa-mat-omit-btn,
    .bwa-line:hover .bwa-line-kind-toggle,
    .bwa-line:focus-within .bwa-line-kind-toggle { opacity: 1; }
  }
  /* Inputs: boxed only when you engage them — except edited ones, which keep
     their dirty flag styling at all times. */
  .bwa-line .bwa-edit-hours:not(.bwa-edit-dirty),
  .bwa-line .bwa-edit-amount-wrap input:not(.bwa-edit-dirty) {
    background: transparent; border-color: transparent;
  }
  .bwa-line:hover .bwa-edit-hours,
  .bwa-line:hover .bwa-edit-amount-wrap input,
  .bwa-line .bwa-edit-hours:focus,
  .bwa-line .bwa-edit-amount-wrap input:focus {
    background: var(--panel-3); border-color: var(--border);
  }

  /* Follow-up (Matt, 2026-08-16): the native number-input spinner sits right
     against the digits, so "6" was hard to read. Spinner is invisible at rest
     and returns on hover/focus. It keeps its layout space, so the digits do
     not shift when it appears; typing and arrow keys are unaffected. */
  .bwa-edit-hours::-webkit-inner-spin-button,
  .bwa-edit-hours::-webkit-outer-spin-button,
  .bwa-line-markup-input::-webkit-inner-spin-button,
  .bwa-line-markup-input::-webkit-outer-spin-button,
  .bwa-edit-amount-wrap input::-webkit-inner-spin-button,
  .bwa-edit-amount-wrap input::-webkit-outer-spin-button { opacity: 0; }
  .bwa-edit-hours:hover::-webkit-inner-spin-button,
  .bwa-edit-hours:focus::-webkit-inner-spin-button,
  .bwa-line-markup-input:hover::-webkit-inner-spin-button,
  .bwa-line-markup-input:focus::-webkit-inner-spin-button,
  .bwa-edit-amount-wrap input:hover::-webkit-inner-spin-button,
  .bwa-edit-amount-wrap input:focus::-webkit-inner-spin-button { opacity: 1; }
/* ═══ Licenses & Insurance (2026-08-16) ═════════════════════════════════════
   The #licenses-view section (js/22-licenses.js) plus its Today watch-bar
   name spans. The Today bar itself reuses the today-fleet-bar chrome, so
   only the name/reason spans need rules here — neutral like the post-08-15
   fleet names (being in the watch list is the signal; the reason text
   carries the urgency). Scoped; delete this block to revert the styling. */
#licenses-view .lic-pane { display: flex; flex-direction: column; gap: 14px; max-width: 860px; }
#licenses-view .lic-tile-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
#licenses-view .lic-add-btn {
  background: none; border: 1px solid var(--border); color: var(--text-soft);
  border-radius: 6px; padding: 3px 10px; font-size: 12px; cursor: pointer;
}
#licenses-view .lic-add-btn:hover { color: var(--text-strong); border-color: var(--text-soft); }
#licenses-view .lic-tile-note { font-size: 12px; color: var(--text-muted); padding: 2px 2px 8px; }
#licenses-view .lic-row {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 2px; border-top: 1px solid var(--border); cursor: pointer;
}
#licenses-view .lic-row:first-child { border-top: none; }
#licenses-view .lic-tile-note + .lic-row { border-top: none; }
#licenses-view .lic-row:hover .lic-row-name { color: var(--text-strong); }
#licenses-view .lic-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
#licenses-view .lic-row-name { color: var(--text); font-weight: 600; font-size: 13.5px; }
#licenses-view .lic-row-sub {
  color: var(--text-muted); font-size: 12px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#licenses-view .lic-row-right {
  flex: 0 0 auto; font-size: 12.5px; text-align: right;
  font-variant-numeric: tabular-nums; color: var(--text-soft);
}
#licenses-view .lic-status-expired  { color: var(--red-bright); font-weight: 600; }
#licenses-view .lic-status-expiring { color: var(--amber-bright); font-weight: 600; }
#licenses-view .lic-status-none     { color: var(--text-muted); font-style: italic; }
/* Renewed but last term's document still attached (docStale, 22-licenses.js) */
#licenses-view .lic-status-stale    { color: var(--amber-bright); font-weight: 600; margin-right: 10px; }
#licenses-view .lic-doc-chip-stale  { color: var(--amber-bright); border-color: var(--amber-bright); }
#licenses-view .lic-empty { color: var(--text-muted); font-size: 12.5px; padding: 8px 2px; }

/* Today "Licenses" bar name spans — same neutral treatment the visual pass
   gives .fleet-watch-name (those rules name that class literally, so this
   sibling class carries its own copy). */
#today-view .today-watch-stack .lic-watch-name {
  cursor: pointer; color: var(--text-soft); border-bottom: 1px dotted transparent;
}
#today-view .today-watch-stack .lic-watch-name:hover {
  color: var(--text-strong); border-bottom-color: var(--text-strong);
}
#today-view .lic-watch-reason { color: var(--text-muted); }

/* ── Policy documents (2026-08-17, phase 2) ────────────────────────────────
   Row paperclip chip, the modal's document cell (body-appended, so these
   are NOT scoped to #licenses-view), and the full-screen viewer. Viewer
   z-index 1200 sits above the edit modal (1000) so its View button works
   without closing anything; the 401-unlock overlay stays on top of all. */
#licenses-view .lic-row-right { display: inline-flex; align-items: center; }
#licenses-view .lic-doc-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 6px; margin-right: 10px;
  color: var(--text-soft); border: 1px solid var(--border); cursor: pointer;
}
#licenses-view .lic-doc-chip:hover { color: var(--text-strong); border-color: var(--text-soft); }
#licenses-view .lic-doc-chip svg { display: block; }

.licm-doc-cell { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.licm-doc-name {
  max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12.5px; color: var(--text);
}
.licm-doc-size, .licm-doc-status { font-size: 12px; color: var(--text-muted); }
.licm-doc-stale-note { flex-basis: 100%; font-size: 12px; color: var(--amber-bright); }
.licm-doc-btn {
  background: none; border: 1px solid var(--border); color: var(--text-soft);
  border-radius: 6px; padding: 3px 10px; font-size: 12px; cursor: pointer;
}
.licm-doc-btn:hover { color: var(--text-strong); border-color: var(--text-soft); }

.licdv-backdrop {
  position: fixed; inset: 0; z-index: 1200;
  background: rgba(8, 12, 18, 0.78);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.licdv-panel {
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px;
  width: min(960px, 96vw); height: min(88vh, 1100px);
  display: flex; flex-direction: column; overflow: hidden;
}
.licdv-head {
  display: flex; align-items: center; gap: 14px;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
}
.licdv-title {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 600; font-size: 13.5px; color: var(--text);
}
.licdv-link { flex: 0 0 auto; font-size: 12.5px; color: var(--text-soft); text-decoration: none; border-bottom: 1px dotted var(--text-soft); }
.licdv-link:hover { color: var(--text-strong); border-bottom-color: var(--text-strong); }
.licdv-close {
  flex: 0 0 auto; background: none; border: none; color: var(--text-soft);
  font-size: 20px; line-height: 1; cursor: pointer; padding: 2px 6px;
}
.licdv-close:hover { color: var(--text-strong); }
.licdv-body {
  flex: 1 1 auto; min-height: 0; background: rgba(0, 0, 0, 0.28);
  display: flex; align-items: center; justify-content: center;
}
.licdv-img { max-width: 100%; max-height: 100%; object-fit: contain; }
.licdv-frame { width: 100%; height: 100%; border: 0; }
.licdv-loading { color: var(--text-muted); font-size: 13px; padding: 30px; text-align: center; }
