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

:root {
  --yellow: #FFD600; --yellow-hover: #F0C800; --yellow-light: #FFFBE6;
  --black: #111111; --white: #FFFFFF; --bg: #F4F5F7;
  --sidebar-bg: #111111; --sidebar-width: 228px;
  /* Three grey tiers, all >=4.5:1 on BOTH --white cards and the --bg page.
     Do not lighten these to "soften" the UI: --text-subtle was #9A9A9A, which
     measured 2.81:1 on white and 2.58:1 on --bg — it carries meta text, stat
     labels and every input placeholder, on a phone used outdoors on job sites. */
  --border: #E4E4E4; --text: #111111; --text-muted: #5A5A5A; --text-subtle: #707070;
  /* Alias in light mode (no visible change here) — dark mode gives this its own,
     stronger value. See the dark block below for why. */
  --border-strong: var(--border);
  --green: #2E7D32; --green-light: #E8F5E9;
  --red: #C62828; --red-light: #FFEBEE;
  /* --orange is the graphics value (bars, dots, icons — 3:1 threshold, passes at
     3.79:1). --orange-text is for TEXT on --orange-light, where the graphics
     value only reaches 3.46:1 and needs 4.5:1. Don't collapse these into one. */
  --orange: #E65100; --orange-light: #FFF3E0; --orange-text: #B34700;
  --blue: #1565C0; --blue-light: #E3F2FD;
  --radius: 10px; --card-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 8px rgba(0,0,0,0.04);
  /* Elevated surfaces layer several transparent shadows instead of one flat drop
     + a hard border: the tight ring reads as the edge, the wide blurs read as
     depth, and the whole stack adapts to whatever background it lands on. */
  --popover-shadow: 0 0 0 1px rgba(0,0,0,0.04), 0 2px 4px rgba(0,0,0,0.04), 0 8px 16px rgba(0,0,0,0.08), 0 16px 32px rgba(0,0,0,0.06);
  --overlay-shadow: 0 0 0 1px rgba(0,0,0,0.04), 0 4px 8px rgba(0,0,0,0.04), 0 12px 24px rgba(0,0,0,0.10), 0 24px 48px rgba(0,0,0,0.10);
  /* Pure black / pure white only — a tinted neutral here picks up the surface
     underneath and reads as dirt on the image edge. */
  --img-outline: rgba(0,0,0,0.1);
  --press: transform 0.12s cubic-bezier(0.2, 0, 0, 1);
  /* Deliberately blue, not the brand yellow/black: focus has to stay legible on
     white cards, on yellow buttons, and on the near-black sidebar, and it must
     not be confusable with the yellow "active/selected" state. */
  --focus-ring: #1565C0;
  --nav-height: 60px;
  /* Fixed regardless of theme — pairs with the brand yellow (text-on-yellow,
     solid "ink" chips) where inverting to light-on-dark would kill contrast. */
  --ink-fixed: #111111; --ink-fixed-text: #FFFFFF;
  --yellow-text: #856A00; --hover-bg: #FAFAFA; --danger-bg: #FFF8F8;
}

/* ===== DARK THEME =====
   Toggled via [data-theme] on <html>, set by the inline script in
   partials/head.ejs and public/js/app.js's setThemePreference(). Only
   properties that need to change are redefined here — anything not
   listed (--yellow, --sidebar-bg, --ink-fixed, etc.) stays constant across
   themes on purpose. See CLAUDE.md-adjacent note: --black/--white keep their
   variable names but invert meaning to "emphasis text/border" and "surface
   background" respectively; --ink-fixed/--ink-fixed-text exist so components
   that pair solid black with white/yellow text (buttons, active chips, the
   impersonation banner) don't invert along with them. */
[data-theme="dark"] {
  --bg: #15161A;
  --white: #1E2024;
  --black: #F0F1F3;
  --border: #2E3036;
  /* --border only clears 1.24:1 against --white here — fine for a divider line
     between --bg and a card, but a --white-on---white form input (modal surface
     and input fill are the same token) then has no visible edge at all; every
     field in a dark-mode form/modal reads as one flat black mass. --border-strong
     is a form-control-only escape hatch: #5A5F6A clears 2.55:1 against --white,
     a clearly perceptible edge without the ~3:1-compliant #6E6E6E reading as a
     loud, out-of-place bright outline against this app's otherwise moody dark
     surfaces. Used by .form-input/.form-select/.form-textarea/.notes-area/
     .search-input/.settings-input/.property-picker-trigger — anything that reads
     as a fillable field, not general-purpose dividers (those keep --border). */
  --border-strong: #5A5F6A;
  /* --text-subtle was #6E7278 here — 3.37:1 on the dark surface, also a fail.
     #878787 clears 4.5:1 while staying a tier below --text-muted's 6.20:1. */
  --text: #F0F1F3; --text-muted: #9BA0A8; --text-subtle: #878787;
  --card-shadow: 0 1px 3px rgba(0,0,0,0.5), 0 1px 8px rgba(0,0,0,0.35);
  --green: #4CAF50; --green-light: rgba(76,175,80,0.16);
  --red: #EF5350; --red-light: rgba(239,83,80,0.16);
  /* In dark mode the tint composites to #423624, where --orange already hits
     6.06:1 as text — so the two tokens can safely be the same value here. */
  --orange: #FFA726; --orange-light: rgba(255,167,38,0.16); --orange-text: #FFA726;
  --blue: #42A5F5; --blue-light: rgba(66,165,245,0.16);
  --yellow-light: rgba(255,214,0,0.14);
  --yellow-text: #FFD54F;
  --hover-bg: rgba(255,255,255,0.05);
  --danger-bg: rgba(239,83,80,0.08);
  --popover-shadow: 0 0 0 1px rgba(255,255,255,0.06), 0 2px 4px rgba(0,0,0,0.30), 0 8px 16px rgba(0,0,0,0.40), 0 16px 32px rgba(0,0,0,0.30);
  --overlay-shadow: 0 0 0 1px rgba(255,255,255,0.06), 0 4px 8px rgba(0,0,0,0.30), 0 12px 24px rgba(0,0,0,0.45), 0 24px 48px rgba(0,0,0,0.40);
  --img-outline: rgba(255,255,255,0.1);
  --focus-ring: #42A5F5;
}
[data-theme="dark"] .half-line { border-top-color: rgba(255,255,255,0.06); }

/* 100dvh, not 100vh. On a phone `vh` is locked to the *largest* viewport (browser
   toolbars retracted), so a 100vh column is taller than what's actually on screen
   whenever the toolbars are showing — and since the panes inside these columns are
   `flex:1; overflow:hidden`, the overhang is clipped rather than scrollable. That
   is what puts the Messages compose box and the bottom of every list panel out of
   reach on first paint. `dvh` tracks the viewport as the toolbars move; the plain
   `vh` line above it stays as the fallback for anything that doesn't support it. */
body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background: var(--bg); color: var(--text); min-height: 100vh; min-height: 100dvh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* ===== SIDEBAR ===== */
.sidebar { position: fixed; top: 0; left: 0; width: var(--sidebar-width); height: 100vh; height: 100dvh; background: var(--sidebar-bg); display: flex; flex-direction: column; z-index: 100; overflow-y: auto; }
.sidebar-logo { padding: 20px 20px 16px; border-bottom: 1px solid rgba(255,255,255,0.08); flex-shrink: 0; }
.sidebar-logo svg { height: 36px; width: auto; }
.sidebar-nav { padding: 12px 0; flex: 1; }
.nav-item { display: flex; align-items: center; gap: 10px; padding: 9px 16px; margin: 1px 8px; border-radius: 8px; cursor: pointer; color: rgba(255,255,255,0.6); font-size: 13.5px; font-weight: 500; transition: background 0.15s, color 0.15s; user-select: none; }
.nav-item:hover { background: rgba(255,255,255,0.07); color: rgba(255,255,255,0.9); }
.nav-item.active { background: var(--yellow); color: var(--ink-fixed); }
.nav-item svg { flex-shrink: 0; opacity: 0.7; }
.nav-item.active svg { opacity: 1; }
.nav-badge { margin-left: auto; background: rgba(255,255,255,0.12); color: rgba(255,255,255,0.7); font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 20px; min-width: 18px; text-align: center; }
.nav-item.active .nav-badge { background: rgba(0,0,0,0.15); color: var(--ink-fixed); }
.sidebar-settings { padding: 6px 0; flex-shrink: 0; }
/* Anchor reset for nav/list items that were always onclick-only <div>s in the legacy app
   and are real <a href> elements in the SvelteKit port (Sidebar.svelte, MobileNav.svelte,
   MobileMoreSheet.svelte, Dashboard's pipeline/action/job rows, Clients detail panel's job
   history rows) — real links for keyboard nav, right-click-open-in-new-tab, and
   crawlability, but without inheriting the browser's default underline/link-color. Harmless
   to legacy: none of these selectors ever matched an <a> there, so this rule was previously
   a no-op for the existing app. Extend this list whenever a port turns another onclick-<div>
   into a real <a href> — .job-history-name/.job-history-date already set explicit `color`,
   so text-decoration is the only reset usually needed; check for that before assuming more. */
.nav-item, .mobile-nav-item, .mobile-more-item, .section-link, .pipeline-card,
.action-item, .job-row-dash, .job-history-item {
  text-decoration: none;
}
.sidebar-footer { padding: 12px 8px; border-top: 1px solid rgba(255,255,255,0.08); flex-shrink: 0; position: relative; }
.user-pill { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; cursor: pointer; transition: background 0.15s; }
.user-pill:hover { background: rgba(255,255,255,0.07); }
.user-avatar-sm { width: 32px; height: 32px; border-radius: 50%; background: var(--yellow); display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800; color: var(--ink-fixed); flex-shrink: 0; }
.user-info { flex: 1; min-width: 0; }
.user-name-text { font-size: 13px; font-weight: 600; color: rgba(255,255,255,0.9); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.user-role-text { font-size: 11px; color: rgba(255,255,255,0.4); margin-top: 1px; }
.user-pill-popup { position: absolute; bottom: calc(100% + 6px); left: 8px; right: 8px; background: var(--white); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--popover-shadow); z-index: 200; overflow: hidden; }
.user-pill-popup-header { display: flex; align-items: center; gap: 12px; padding: 14px; }
.user-avatar-popup { width: 38px; height: 38px; border-radius: 50%; background: var(--yellow); display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 800; color: var(--ink-fixed); flex-shrink: 0; }
.popup-user-name { font-size: 13px; font-weight: 600; color: var(--black); }
.popup-user-role { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.user-pill-popup-divider { height: 1px; background: var(--border); }
.user-pill-popup-item { display: flex; align-items: center; gap: 10px; padding: 11px 14px; cursor: pointer; font-size: 13px; font-weight: 500; color: var(--black); transition: background 0.1s; }
.user-pill-popup-item:hover { background: var(--bg); }
.user-pill-popup-item.danger { color: var(--red); }

/* ===== NOTIFICATIONS ===== */
.notif-bell { position: relative; display: flex; align-items: center; gap: 10px; padding: 8px 10px; margin-bottom: 2px; border-radius: 8px; cursor: pointer; color: rgba(255,255,255,0.6); transition: background 0.15s, color 0.15s; }
.notif-bell:hover { background: rgba(255,255,255,0.07); color: rgba(255,255,255,0.9); }
.notif-bell .nav-label { font-size: 13px; font-weight: 500; }
.notif-badge { position: absolute; top: 4px; left: 20px; background: var(--red); color: white; font-size: 9px; font-weight: 700; min-width: 15px; height: 15px; border-radius: 20px; display: flex; align-items: center; justify-content: center; padding: 0 3px; border: 2px solid var(--sidebar-bg); }
.notif-popup { position: absolute; bottom: calc(100% + 6px); left: 8px; right: 8px; background: var(--white); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--popover-shadow); z-index: 200; overflow: hidden; max-height: 420px; display: flex; flex-direction: column; }
.notif-popup-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--border); font-size: 13px; font-weight: 700; color: var(--black); flex-shrink: 0; }
.notif-mark-all { font-size: 11.5px; font-weight: 600; color: var(--blue); cursor: pointer; }
.notif-mark-all:hover { text-decoration: underline; }
.notif-popup-list { overflow-y: auto; }
.notif-item { display: flex; align-items: flex-start; gap: 10px; padding: 11px 14px; cursor: pointer; transition: background 0.1s; border-bottom: 1px solid var(--border); }
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--bg); }
.notif-item-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--blue); margin-top: 5px; flex-shrink: 0; opacity: 0; }
.notif-item.unread { background: var(--yellow-light); }
.notif-item.unread .notif-item-dot { opacity: 1; }
.notif-item-body { flex: 1; min-width: 0; }
.notif-item-title { font-size: 12.5px; font-weight: 600; color: var(--black); line-height: 1.4; }
.notif-item-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.notif-item-time { font-size: 10.5px; color: var(--text-subtle); margin-top: 4px; }

.toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 1000; display: flex; flex-direction: column; gap: 10px; align-items: flex-end; }
.toast { display: flex; align-items: flex-start; gap: 10px; background: var(--white); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--popover-shadow); padding: 12px 14px; width: 300px; cursor: pointer; animation: toast-in 0.2s cubic-bezier(0.2, 0, 0, 1); }
.toast.toast-out { animation: toast-out 0.18s ease-in forwards; }
.toast-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--blue); margin-top: 5px; flex-shrink: 0; }
.toast-body { flex: 1; min-width: 0; }
.toast-title { font-size: 12.5px; font-weight: 700; color: var(--black); line-height: 1.4; }
.toast-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
/* Exit stays softer than the enter — a 4px drift out, not the 20px sideways
   slide it used to do, which read louder leaving than it did arriving. */
@keyframes toast-out { to { opacity: 0; transform: translateY(4px); } }

/* ===== MAIN ===== */
/* min-height only, never a fixed height: the page-scrolling views (Dashboard,
   Reports, Settings) need .main free to grow past the viewport. The flex:1 +
   overflow:hidden views (Jobs, Clients, Messages, Schedule) resolve their inner
   panes against this min-height, which is exactly why it has to be dvh. */
.main { margin-left: var(--sidebar-width); min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }

/* ===== TOPBAR ===== */
.topbar { background: var(--white); border-bottom: 1px solid var(--border); padding: 0 24px; height: 60px; display: flex; align-items: center; justify-content: space-between; position: sticky; top: 0; z-index: 50; flex-shrink: 0; gap: 12px; }
.topbar-title { font-size: 18px; font-weight: 700; color: var(--black); letter-spacing: -0.3px; }
.topbar-right { display: flex; align-items: center; gap: 8px; }
.btn-primary { display: flex; align-items: center; gap: 6px; background: var(--yellow); border: none; border-radius: 8px; padding: 0 14px; height: 36px; font-size: 13px; font-weight: 700; color: var(--ink-fixed); cursor: pointer; font-family: inherit; transition: background 0.15s, var(--press); white-space: nowrap; }
.btn-primary:hover { background: var(--yellow-hover); }
.btn-secondary { display: flex; align-items: center; gap: 6px; background: var(--white); border: 1.5px solid var(--border); border-radius: 8px; padding: 0 14px; height: 36px; font-size: 13px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; transition: border-color 0.15s, color 0.15s, var(--press); white-space: nowrap; }
.btn-secondary:hover { border-color: #bbb; color: var(--black); }
.icon-btn { position: relative; width: 36px; height: 36px; border-radius: 8px; border: 1.5px solid var(--border); background: var(--white); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-muted); font-family: inherit; transition: border-color 0.15s, color 0.15s, var(--press); }
.icon-btn:hover { border-color: #ccc; color: var(--black); }
.icon-btn:disabled { opacity: 0.5; cursor: default; }
.qbo-icon-btn { background: #2CA01C; border-color: #2CA01C; color: #fff; font-weight: 800; font-size: 11px; font-family: Arial, Helvetica, sans-serif; letter-spacing: -0.3px; }
.qbo-icon-btn:hover { background: #248917; border-color: #248917; color: #fff; }

/* ===== VIEWS ===== */
.view { display: none; flex: 1; flex-direction: column; }
.view.active { display: flex; }

/* ===== COMING SOON ===== */
.coming-soon { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 48px; }
.coming-soon-icon { width: 56px; height: 56px; border-radius: 16px; background: var(--yellow-light); display: flex; align-items: center; justify-content: center; }
.coming-soon h2 { font-size: 18px; font-weight: 700; color: var(--black); }
.coming-soon p { font-size: 14px; color: var(--text-muted); text-align: center; max-width: 300px; line-height: 1.6; }

/* ===== DASHBOARD ===== */
.page-body { padding: 24px 28px 40px; flex: 1; }
.pipeline-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 24px; }
.pipeline-card { background: var(--white); border-radius: var(--radius); padding: 18px 20px; box-shadow: var(--card-shadow); border-top: 3px solid transparent; cursor: pointer; transition: box-shadow 0.15s; }
.pipeline-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
.pipeline-card.scheduled { border-top-color: var(--blue); }
.pipeline-card.in-progress { border-top-color: var(--yellow); }
.pipeline-card.completed { border-top-color: var(--green); }
.pipeline-card.invoiced { border-top-color: #7B1FA2; }
.pipeline-label { font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 10px; }
.pipeline-count { font-size: 32px; font-weight: 800; color: var(--black); letter-spacing: -1px; line-height: 1; margin-bottom: 4px; }
.pipeline-value { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.two-col { display: grid; grid-template-columns: 1fr 340px; gap: 20px; align-items: start; }
.section-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.section-title { font-size: 14px; font-weight: 700; color: var(--black); }
/* position:relative so the ::after hit-area expander (below) can center on it. Only
   surfaced once the SvelteKit port made this a real <a href> — legacy's <span onclick>
   version wasn't in assertTouchTargets' selector list (button, a[href], ...) at all. */
.section-link { position: relative; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; }
.section-link:hover { color: var(--black); }
.actions-card, .jobs-card { background: var(--white); border-radius: var(--radius); box-shadow: var(--card-shadow); overflow: hidden; margin-bottom: 20px; }
.action-item, .job-row-dash { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background 0.12s; }
.action-item:last-child, .job-row-dash:last-child { border-bottom: none; }
.action-item:hover, .job-row-dash:hover { background: var(--hover-bg); }
.action-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.action-icon.red { background: var(--red-light); color: var(--red); }
.action-icon.orange { background: var(--orange-light); color: var(--orange); }
.action-icon.blue { background: var(--blue-light); color: var(--blue); }
.action-icon.yellow { background: var(--yellow-light); color: var(--yellow-text); }
.action-text { flex: 1; }
.action-title { font-size: 13px; font-weight: 600; color: var(--black); margin-bottom: 2px; }
.action-sub { font-size: 12px; color: var(--text-muted); }
.action-arrow { color: #CCC; flex-shrink: 0; }
.job-status-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.job-status-dot.in-progress { background: var(--yellow); }
.job-status-dot.scheduled { background: var(--blue); }
.job-status-dot.completed { background: var(--green); }
.job-info-dash { flex: 1; min-width: 0; }
.job-name-dash { font-size: 13px; font-weight: 600; color: var(--black); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 2px; }
.job-meta-dash { font-size: 11px; color: var(--text-muted); display: flex; align-items: center; gap: 6px; }
.assignee-chip-sm { width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 800; border: 2px solid var(--white); flex-shrink: 0; }
.chip-rj { background: var(--yellow); color: var(--ink-fixed); }
.chip-mk { background: var(--blue); color: white; }
.stat-card { background: var(--white); border-radius: var(--radius); padding: 16px 18px; box-shadow: var(--card-shadow); margin-bottom: 12px; }
.stat-label { font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 6px; }
.stat-value { font-size: 26px; font-weight: 800; color: var(--black); letter-spacing: -0.8px; line-height: 1; margin-bottom: 4px; }
.stat-change { font-size: 11px; font-weight: 600; }
.stat-change.up { color: var(--green); }
.stat-divider { height: 1px; background: var(--border); margin: 10px 0; }
.stat-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.stat-row:last-child { margin-bottom: 0; }
.stat-row-label { font-size: 12px; color: var(--text-muted); font-weight: 500; }
.stat-row-value { font-size: 12px; font-weight: 700; color: var(--black); }

/* ===== JOBS ===== */
.status-tabs { background: var(--white); border-bottom: 1px solid var(--border); padding: 0 20px; display: flex; overflow-x: auto; flex-shrink: 0; }
.status-tab { padding: 14px 16px; font-size: 13px; font-weight: 600; color: var(--text-muted); cursor: pointer; border-bottom: 2px solid transparent; white-space: nowrap; transition: color 0.15s, border-color 0.15s; display: flex; align-items: center; gap: 6px; }
.status-tab:hover { color: var(--black); }
.status-tab.active { color: var(--black); border-bottom-color: var(--black); }
.tab-count { font-size: 11px; font-weight: 700; background: var(--bg); color: var(--text-subtle); padding: 1px 6px; border-radius: 20px; }
.status-tab.active .tab-count { background: var(--ink-fixed); color: var(--ink-fixed-text); }
.search-bar { background: var(--white); border-bottom: 1px solid var(--border); padding: 10px 16px; display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.search-input-wrap { flex: 1; position: relative; }
.search-input-wrap svg { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--text-subtle); pointer-events: none; }
.search-input { width: 100%; height: 36px; border: 1.5px solid var(--border-strong); border-radius: 8px; padding: 0 12px 0 34px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--bg); outline: none; transition: border-color 0.15s; }
.search-input:focus { border-color: var(--black); background: var(--white); }
.search-input::placeholder { color: var(--text-subtle); }
.filter-btn { display: flex; align-items: center; gap: 5px; height: 36px; padding: 0 12px; border: 1.5px solid var(--border); border-radius: 8px; background: var(--white); font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; white-space: nowrap; transition: border-color 0.15s, color 0.15s, var(--press); }
.filter-btn:hover { border-color: #bbb; color: var(--black); }
.filter-btn.active { border-color: var(--black); color: var(--black); background: var(--bg); }
.filter-popover { position: absolute; top: calc(100% + 6px); right: 0; background: var(--white); border-radius: 10px; box-shadow: var(--popover-shadow); z-index: 200; min-width: 200px; overflow: hidden; }
.filter-popover-list { max-height: 240px; overflow-y: auto; }
.filter-popover-row { display: flex; align-items: center; gap: 10px; padding: 9px 14px; cursor: pointer; background: none; border: none; width: 100%; text-align: left; font-family: inherit; }
.filter-popover-row:hover { background: var(--bg); }
.filter-popover-row.selected { background: var(--bg); }
.filter-popover-check { width: 16px; height: 16px; border-radius: 4px; border: 1.5px solid var(--border); flex-shrink: 0; margin-left: auto; }
.filter-popover-row.selected .filter-popover-check { background: var(--black); border-color: var(--black); }
.filter-popover-footer { padding: 8px 12px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; }
.filter-popover-clear { background: none; border: none; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; padding: 4px 8px; border-radius: 6px; }
.filter-popover-clear:hover { color: var(--black); background: var(--bg); }
.filter-popover-date { padding: 12px; display: flex; flex-direction: column; gap: 10px; }
.address-autocomplete { position: relative; }
.address-autocomplete-list {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 4px; z-index: 50;
  background: var(--white); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--overlay-shadow); max-height: 240px; overflow-y: auto;
}
.address-autocomplete-item {
  display: block; width: 100%; text-align: left; padding: 10px 14px; font-size: 13px;
  background: none; border: none; cursor: pointer; color: var(--black); font-family: inherit;
}
.address-autocomplete-item:hover { background: var(--bg); }
.property-picker { position: relative; }
.property-picker-trigger {
  display: block; width: 100%; text-align: left; padding: 10px 14px;
  border: 1.5px solid var(--border-strong); border-radius: 10px; background: var(--white);
  font-size: 14px; font-family: inherit; color: var(--black); cursor: pointer;
}
.property-picker-panel {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 4px; z-index: 50;
  background: var(--white); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--overlay-shadow); padding: 10px; display: flex; flex-direction: column; gap: 8px;
}
.property-picker-list { max-height: 200px; overflow-y: auto; display: flex; flex-direction: column; }
.property-picker-item {
  display: block; width: 100%; text-align: left; padding: 8px 10px; font-size: 13px;
  background: none; border: none; cursor: pointer; color: var(--black); font-family: inherit; border-radius: 6px;
}
.property-picker-item:hover { background: var(--bg); }
.property-picker-clear { color: var(--text-subtle); border-bottom: 1px solid var(--border); border-radius: 0; }
.property-picker-empty { padding: 8px 10px; font-size: 13px; color: var(--text-subtle); }
.property-picker-newbtn {
  text-align: left; padding: 8px 10px; font-size: 13px; font-weight: 600; color: var(--blue);
  background: none; border: none; border-top: 1px solid var(--border); cursor: pointer; font-family: inherit;
}
.property-picker-actions { display: flex; gap: 8px; justify-content: flex-end; }
.crew-pick-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px 5px 4px; border-radius: 20px; cursor: pointer; border: 2px solid var(--border); background: var(--bg); transition: border-color 0.12s; user-select: none; }
.crew-pick-chip.selected { border-color: var(--black); background: var(--white); }
.crew-chip-av { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 800; flex-shrink: 0; }
.crew-pick-chip-name { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.crew-pick-chip.selected .crew-pick-chip-name { color: var(--black); }
.content-split { display: flex; flex: 1; overflow: hidden; }
.list-panel { display: flex; flex-direction: column; flex: 1; min-width: 0; overflow: hidden; }
.item-list { flex: 1; overflow-y: auto; padding: 12px 16px; display: flex; flex-direction: column; gap: 4px; }
.job-row { background: var(--white); border-radius: var(--radius); border: 1.5px solid transparent; padding: 14px 16px; display: flex; align-items: center; gap: 14px; cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s; }
.job-row:hover { border-color: var(--border); box-shadow: var(--card-shadow); }
.job-row.active { border-color: var(--black); box-shadow: var(--card-shadow); }
.job-status-indicator { width: 3px; border-radius: 4px; align-self: stretch; flex-shrink: 0; min-height: 40px; }
.ind-scheduled { background: var(--blue); }
.ind-in_progress { background: var(--yellow); }
.ind-completed { background: var(--green); }
.ind-cancelled { background: var(--border); }
.job-info { flex: 1; min-width: 0; }
.job-title { font-size: 14px; font-weight: 700; color: var(--black); margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.job-meta { font-size: 12px; color: var(--text-muted); display: flex; gap: 6px; align-items: center; }
.job-meta-sep { color: var(--border); }
/* Cost health — color only, no dollar figures. See src/utils/jobCostHealth.js
   for the thresholds this is fed from. */
.job-cost-line { margin-top: 7px; height: 3px; border-radius: 2px; background: var(--bg); overflow: hidden; max-width: 200px; }
.job-cost-line-fill { height: 100%; border-radius: 2px; }
.job-cost-line-fill.zone-good { background: var(--green); }
.job-cost-line-fill.zone-warn { background: var(--orange); }
.job-cost-line-fill.zone-bad { background: var(--red); }
.job-cost-gauge { margin-bottom: 14px; }
.job-cost-gauge-track { height: 8px; border-radius: 999px; background: var(--bg); overflow: hidden; }
.job-cost-gauge-fill { height: 100%; border-radius: 999px; }
.job-cost-gauge-fill.zone-good { background: var(--green); }
.job-cost-gauge-fill.zone-warn { background: var(--orange); }
.job-cost-gauge-fill.zone-bad { background: var(--red); }
.job-cost-gauge-label { margin-top: 6px; font-size: 12px; font-weight: 600; }
.job-cost-gauge-label.zone-good { color: var(--green); }
.job-cost-gauge-label.zone-warn { color: var(--orange-text); }
.job-cost-gauge-label.zone-bad { color: var(--red); }
.job-right { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex-shrink: 0; }
.status-chip { font-size: 10px; font-weight: 700; padding: 3px 8px; border-radius: 20px; text-transform: uppercase; letter-spacing: 0.4px; white-space: nowrap; }
.chip-scheduled { background: var(--blue-light); color: var(--blue); }
.chip-in_progress { background: var(--yellow-light); color: var(--yellow-text); }
.chip-completed { background: var(--green-light); color: var(--green); }
.chip-cancelled { background: var(--bg); color: var(--text-subtle); }
.job-value { font-size: 13px; font-weight: 700; color: var(--black); }
.assignee-chips { display: flex; }
.assignee-chip { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 800; border: 2px solid var(--white); margin-right: -5px; }

/* ===== DETAIL PANEL ===== */
.detail-panel { width: 420px; flex-shrink: 0; background: var(--white); border-left: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; }
.detail-panel.hidden { display: none; }
.detail-topbar { padding: 14px 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
.detail-close { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; background: none; border: none; font-family: inherit; padding: 0; transition: color 0.15s; }
.detail-close:hover { color: var(--black); }
.detail-scroll { flex: 1; overflow-y: auto; }
.detail-hero { padding: 16px 20px; border-bottom: 1px solid var(--border); }
.detail-job-title { font-size: 17px; font-weight: 800; color: var(--black); letter-spacing: -0.3px; margin-bottom: 6px; }
.detail-client-link { font-size: 13px; font-weight: 600; color: var(--blue); cursor: pointer; display: flex; align-items: center; gap: 4px; margin-bottom: 12px; }
.detail-chips-row { display: flex; gap: 6px; flex-wrap: wrap; }
.detail-chip { display: flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; padding: 4px 10px; border-radius: 20px; }
.detail-chip.status-scheduled { background: var(--blue-light); color: var(--blue); }
.detail-chip.status-in_progress { background: var(--yellow-light); color: var(--yellow-text); }
.detail-chip.status-completed { background: var(--green-light); color: var(--green); }
.detail-chip.category { background: var(--bg); color: var(--text-muted); }
.detail-chip.status-draft { background: var(--bg); color: var(--text-muted); }
.detail-chip.status-sent { background: var(--blue-light); color: var(--blue); }
.detail-chip.status-signed { background: var(--green-light); color: var(--green); }
.detail-chip.status-approved { background: var(--green-light); color: var(--green); }
.detail-chip.status-declined { background: var(--bg); color: var(--text-subtle); }
.detail-quick-actions { display: flex; gap: 6px; padding: 12px 20px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.quick-btn { flex: 1; height: 36px; border-radius: 8px; border: 1.5px solid var(--border); background: var(--white); font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; display: flex; align-items: center; justify-content: center; gap: 5px; transition: border-color 0.15s, color 0.15s, var(--press); }
.quick-btn:hover { border-color: #bbb; color: var(--black); }
.quick-btn.primary { background: var(--yellow); border-color: var(--yellow); color: var(--ink-fixed); }
.quick-btn.primary:hover { background: var(--yellow-hover); }
.detail-section { padding: 14px 20px; border-bottom: 1px solid var(--border); }
.detail-section:last-child { border-bottom: none; }
.detail-section-title { font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 12px; }
.detail-field { margin-bottom: 10px; }
.detail-field:last-child { margin-bottom: 0; }
.detail-field-label { font-size: 11px; font-weight: 600; color: var(--text-subtle); margin-bottom: 2px; }
.detail-field-value { font-size: 13px; font-weight: 500; color: var(--black); }
.margin-bar-wrap { margin-top: 6px; }
.margin-bar-labels { display: flex; justify-content: space-between; margin-bottom: 4px; }
.margin-bar-label { font-size: 11px; font-weight: 600; color: var(--text-muted); }
.margin-bar-value { font-size: 11px; font-weight: 700; }
.margin-bar-track { height: 8px; background: var(--bg); border-radius: 4px; overflow: hidden; }
.margin-bar-fill { height: 100%; border-radius: 4px; }
.job-photos-grid-inner { display: flex; flex-wrap: wrap; gap: 8px; }
.job-photo-thumb { width: 76px; height: 76px; object-fit: cover; border-radius: 8px; cursor: pointer; transition: opacity 0.15s, box-shadow 0.15s; }
.job-photo-thumb:hover { opacity: 0.88; box-shadow: var(--card-shadow); }
/* The background is not optional: with no color-scheme declared, a textarea's UA
   default background stays the light `field` white in dark mode while --text
   flips to near-white — white on white. Same reason every other input here
   pins one. */
.notes-area { width: 100%; min-height: 72px; border: 1.5px solid var(--border-strong); border-radius: 8px; padding: 10px 12px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--white); resize: vertical; outline: none; }
.notes-area:focus { border-color: var(--black); }
.notes-area::placeholder { color: var(--text-subtle); }

/* ===== JOB DETAIL — full width, two-column layout ===== */
#jobsSplit.detail-open .list-panel { display: none; }
#jobsSplit.detail-open .job-detail-panel { width: 100%; }
.job-detail-panel .detail-scroll { background: var(--bg); }
.job-detail-panel .detail-hero,
.job-detail-panel .detail-quick-actions { padding-left: 28px; padding-right: 28px; }
.job-detail-panel .detail-job-title { font-size: 20px; }
.job-detail-panel .detail-quick-actions { justify-content: flex-start; }
.job-detail-panel .quick-btn { flex: 0 0 auto; padding: 0 18px; }
.job-detail-body { padding: 20px 28px 40px; }
.job-detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; max-width: 1400px; margin: 0 auto; align-items: start; }
.job-detail-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.job-detail-grid .detail-section { background: var(--white); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--card-shadow); padding: 16px 20px; margin: 0; }
@media (max-width: 1050px) {
  .job-detail-grid { grid-template-columns: 1fr; }
}
@media (max-width: 900px) {
  .job-detail-body { padding: 16px 16px 32px; }
  .job-detail-panel .detail-hero,
  .job-detail-panel .detail-quick-actions { padding-left: 16px; padding-right: 16px; }
  .job-detail-panel .quick-btn { flex: 1 1 0; padding: 0 8px; }
}

/* ===== CLIENTS ===== */
.stats-row { display: flex; gap: 1px; background: var(--border); border-bottom: 1px solid var(--border); flex-shrink: 0; }
.stat-pill { flex: 1; background: var(--white); padding: 10px 16px; }
.stat-pill-value { font-size: 18px; font-weight: 800; color: var(--black); letter-spacing: -0.5px; }
.stat-pill-label { font-size: 11px; font-weight: 600; color: var(--text-subtle); }
.client-row { background: var(--white); border-radius: var(--radius); border: 1.5px solid transparent; padding: 14px 16px; display: flex; align-items: center; gap: 14px; cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s; }
.client-row:hover { border-color: var(--border); box-shadow: var(--card-shadow); }
.client-row.active { border-color: var(--black); }
.client-avatar { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 800; flex-shrink: 0; color: var(--black); }
.client-info { flex: 1; min-width: 0; }
.client-name { font-size: 14px; font-weight: 700; color: var(--black); margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.client-meta { font-size: 12px; color: var(--text-muted); display: flex; gap: 8px; align-items: center; }
.client-right { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
.client-job-count { font-size: 11px; font-weight: 700; background: var(--bg); color: var(--text-muted); padding: 2px 8px; border-radius: 20px; }
.client-last-job { font-size: 11px; color: var(--text-subtle); }
.detail-header { padding: 20px 20px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.detail-close-btn { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; background: none; border: none; font-family: inherit; padding: 0; margin-bottom: 16px; }
.detail-close-btn:hover { color: var(--black); }
.detail-avatar-row { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.detail-avatar { width: 52px; height: 52px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800; color: var(--black); flex-shrink: 0; }
.detail-name { font-size: 18px; font-weight: 800; color: var(--black); letter-spacing: -0.3px; margin-bottom: 3px; }
.detail-company { font-size: 13px; color: var(--text-muted); }
.detail-actions { display: flex; gap: 6px; margin-top: 4px; }
.detail-action-btn { flex: 1; height: 36px; border-radius: 7px; border: 1.5px solid var(--border); background: var(--white); font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; display: flex; align-items: center; justify-content: center; gap: 5px; transition: border-color 0.15s, color 0.15s, var(--press); }
.detail-action-btn:hover { border-color: #bbb; color: var(--black); }
.detail-action-btn.primary { background: var(--yellow); border-color: var(--yellow); color: var(--ink-fixed); }
.job-history-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.job-history-item:last-child { border-bottom: none; }
.job-history-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dot-completed { background: var(--green); }
.dot-scheduled { background: var(--blue); }
.dot-in-progress { background: var(--yellow); }
.job-history-info { flex: 1; min-width: 0; }
.job-history-name { font-size: 13px; font-weight: 600; color: var(--black); margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.job-history-date { font-size: 11px; color: var(--text-muted); }
.job-history-value { font-size: 13px; font-weight: 700; color: var(--black); flex-shrink: 0; }

/* ===== SETTINGS ===== */
.settings-body { display: flex; flex: 1; overflow: hidden; }
.settings-nav { width: 220px; flex-shrink: 0; border-right: 1px solid var(--border); background: var(--white); overflow-y: auto; padding: 16px 0; }
.settings-nav-item { display: flex; align-items: center; gap: 10px; padding: 9px 16px; margin: 1px 8px; border-radius: 8px; cursor: pointer; color: var(--text-muted); font-size: 13px; font-weight: 500; transition: background 0.15s, color 0.15s; }
.settings-nav-item:hover { background: var(--bg); color: var(--black); }
.settings-nav-item.active { background: var(--yellow-light); color: var(--black); font-weight: 600; }
.settings-nav-divider { height: 1px; background: var(--border); margin: 8px 16px; }
.settings-content { flex: 1; overflow-y: auto; padding: 28px 32px; max-width: 680px; }
.settings-section { margin-bottom: 36px; }
.settings-section-title { font-size: 16px; font-weight: 800; color: var(--black); letter-spacing: -0.2px; margin-bottom: 4px; }
.settings-section-desc { font-size: 13px; color: var(--text-muted); margin-bottom: 20px; }
.settings-card { background: var(--white); border-radius: var(--radius); box-shadow: var(--card-shadow); overflow: hidden; }
.settings-row { display: flex; align-items: center; padding: 15px 18px; border-bottom: 1px solid var(--border); gap: 16px; }
.settings-row:last-child { border-bottom: none; }
.settings-row-label { flex: 1; }
.settings-row-label-text { font-size: 13px; font-weight: 600; color: var(--black); margin-bottom: 2px; }
.settings-row-label-sub { font-size: 12px; color: var(--text-muted); }
.settings-input { height: 36px; border: 1.5px solid var(--border-strong); border-radius: 8px; padding: 0 12px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--bg); outline: none; min-width: 200px; }
.settings-input:focus { border-color: var(--black); background: var(--white); }
.toggle { width: 44px; height: 24px; border-radius: 12px; background: var(--border); position: relative; cursor: pointer; transition: background 0.2s; flex-shrink: 0; border: none; }
.toggle.on { background: var(--yellow); }
.toggle::after { content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--white); transition: transform 0.2s; box-shadow: 0 1px 3px rgba(0,0,0,0.2); }
.toggle.on::after { transform: translateX(20px); }
.theme-selector { display: flex; gap: 6px; }
.theme-option { min-height: 40px; padding: 6px 14px; border-radius: 8px; border: 1.5px solid var(--border); background: var(--white); font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; transition: border-color 0.15s, background 0.15s, color 0.15s, var(--press); }
.theme-option.active { border-color: var(--ink-fixed); background: var(--ink-fixed); color: var(--ink-fixed-text); }
.save-bar { display: flex; justify-content: flex-end; margin-top: 12px; }
.employee-row { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--border); }
.employee-row:last-child { border-bottom: none; }
.employee-avatar { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 800; flex-shrink: 0; }
.employee-info { flex: 1; }
.employee-name { font-size: 13px; font-weight: 700; color: var(--black); margin-bottom: 2px; }
.employee-meta { font-size: 12px; color: var(--text-muted); }
.employee-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.employee-status { font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 20px; }
.status-active { background: var(--green-light); color: var(--green); }
.status-inactive { background: var(--bg); color: var(--text-muted); }
.perm-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; margin-bottom: 8px; }
.perm-check { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; }
.perm-check input { margin-top: 3px; }
.perm-check .perm-desc { display: block; color: var(--text-subtle); font-size: 11px; }
.perm-locked { opacity: 0.6; }
.perm-lock-icon { font-size: 12px; margin-top: 2px; }
.integration-row { display: flex; align-items: center; gap: 14px; padding: 15px 18px; border-bottom: 1px solid var(--border); cursor: pointer; }
.integration-row:last-child { border-bottom: none; }
.integration-row:hover { background: var(--hover-bg); }
.integration-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 13px; font-weight: 800; }
.integration-info { flex: 1; }
.integration-name { font-size: 13px; font-weight: 700; color: var(--black); margin-bottom: 2px; }
.integration-desc { font-size: 12px; color: var(--text-muted); }
.integration-status { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: 20px; flex-shrink: 0; }
.int-connected { background: var(--green-light); color: var(--green); }
.int-disconnected { background: var(--bg); color: var(--text-subtle); }
.int-phase2 { background: var(--blue-light); color: var(--blue); }
.danger-zone { border: 1.5px solid rgba(198,40,40,0.2); border-radius: var(--radius); padding: 16px 18px; background: var(--danger-bg); }
.danger-zone-title { font-size: 13px; font-weight: 700; color: var(--red); margin-bottom: 4px; }
.danger-zone-desc { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
.btn-danger { display: flex; align-items: center; gap: 6px; background: var(--white); border: 1.5px solid var(--border); border-radius: 8px; padding: 0 14px; height: 36px; font-size: 13px; font-weight: 600; color: var(--red); cursor: pointer; font-family: inherit; transition: border-color 0.15s, background 0.15s, var(--press); }
.btn-danger:hover { border-color: var(--red); background: var(--red-light); }

.job-dropdown { position: absolute; top: calc(100% + 6px); right: 0; background: var(--white); border-radius: 10px; box-shadow: var(--popover-shadow); z-index: 200; min-width: 160px; overflow: hidden; }
.job-dropdown-item { display: flex; align-items: center; gap: 8px; padding: 10px 14px; font-size: 13px; font-weight: 600; color: var(--text); cursor: pointer; background: none; border: none; width: 100%; text-align: left; font-family: inherit; }
.job-dropdown-item:hover { background: var(--bg); }
.job-dropdown-item.danger { color: var(--red); }
.job-dropdown-item.danger:hover { background: var(--red-light); }

/* ===== MOBILE ===== */
.mobile-nav { display: none; position: fixed; bottom: 0; left: 0; right: 0; height: var(--nav-height); background: var(--white); border-top: 1px solid var(--border); z-index: 100; padding: 0 4px; align-items: center; justify-content: space-around; }
.mobile-nav-item { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 5px 6px; border-radius: 8px; cursor: pointer; color: var(--text-subtle); font-size: 9px; font-weight: 600; transition: color 0.15s; min-width: 0; flex: 1; }
.mobile-nav-item.active { color: var(--black); }
.mobile-nav-dot { width: 4px; height: 4px; border-radius: 50%; background: var(--yellow); margin-top: -2px; }
.mobile-topbar { display: none; background: var(--white); border-bottom: 1px solid var(--border); padding: 10px 12px; align-items: center; justify-content: space-between; gap: 8px; position: sticky; top: 0; z-index: 50; flex-shrink: 0; }
.mobile-topbar > img { height: 24px; width: auto; object-fit: contain; flex-shrink: 0; }
/* min-width:0 + ellipsis is load-bearing: without it a flex:1 item refuses to shrink below
   its text width, so a long action-button label ("New Estimate", "New Write-Off", "Add Team
   Member") pushes #mobileActionBtn off the right edge and the whole page scrolls sideways
   (caught by test/e2e/mobile-invariants). The title truncates instead; the button stays put. */
#mobileViewTitle { font-size: 15px; font-weight: 700; color: var(--black); letter-spacing: -0.3px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#mobileActionBtn { flex-shrink: 0; max-width: 60%; }
#mobileActionBtn #mobileActionLabel { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (max-width: 900px) {
  .sidebar { display: none; }
  .main { margin-left: 0; padding-bottom: var(--nav-height); }
  .topbar { display: none; }
  /* view-property-form is a full-page Add/Edit form, not a modal (see property_form_view.ejs)
     — unlike every other view, its Cancel/Save controls live ONLY in this .topbar, with no
     mobile-topbar/#mobileActionBtn wiring to fall back on (it isn't one of the 15 views in
     app.js's VIEWS/labels map). The blanket .topbar{display:none} above made a property
     completely un-savable on a phone: the form rendered, but there was no way to submit it or
     even cancel back out. Caught by test/e2e/crud-properties. Un-hide just this one topbar and
     restyle it to mobile proportions rather than inventing a second save mechanism. */
  #view-property-form .topbar {
    display: flex; height: auto; min-height: 52px; padding: 10px 12px;
    padding-top: calc(10px + env(safe-area-inset-top));
  }
  #view-property-form .topbar-title { font-size: 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  #view-property-form .topbar .detail-close { min-height: 44px; }
  .mobile-topbar { display: flex; }
  .mobile-nav { display: flex; }
  .pipeline-grid { grid-template-columns: repeat(2, 1fr); }
  .two-col { grid-template-columns: 1fr; }
  .page-body { padding: 16px 16px 32px; }
  /* Full-screen detail overlay. It sits above .mobile-nav (z-index 100), so it also
     owns the bottom edge — hence the safe-area padding on its scroller, which would
     otherwise run its last row under the home indicator. */
  .detail-panel { position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%; z-index: 200; border-left: none; view-transition-name: detail-panel; }
  .detail-panel .detail-topbar { padding-top: calc(14px + env(safe-area-inset-top, 0px)); }
  .detail-scroll { -webkit-overflow-scrolling: touch; padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
  .settings-nav { display: flex; flex-direction: row; flex-wrap: wrap; width: 100%; border-right: none; border-bottom: 1px solid var(--border); padding: 8px 12px; gap: 6px; flex-shrink: 0; }
  .settings-nav-item { flex-shrink: 0; border-radius: 20px; padding: 7px 14px; font-size: 12px; font-weight: 600; white-space: nowrap; margin: 0; gap: 0; }
  .settings-nav-item svg { display: none; }
  .settings-nav-divider { display: none; }
  .settings-body { flex-direction: column; overflow: hidden; }
  .settings-content { padding: 16px 14px 40px; max-width: 100%; overflow-x: hidden; }
  .stats-row { display: none; }
  .search-bar { flex-wrap: wrap; gap: 6px; }
  .search-input-wrap { flex-basis: 100%; }
  .prop-upload-bar { flex-direction: column; }
  .prop-upload-btn { height: 44px; font-size: 14px; }
}

/* ===== VIEW TRANSITIONS (list<->detail slide, mobile only — see
   client/src/lib/twoPaneTransition.js) =====
   Scoped to prefers-reduced-motion:no-preference as defense-in-depth — the JS gate in
   twoPaneTransition.js already never calls startViewTransition when reduced motion is
   set, so this query never actually has to do the work, but it's cheap insurance if that
   gate is ever changed without updating this file. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-group(detail-panel) {
    animation-duration: 0.28s;
    animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1);
  }
  html[data-view-transition-direction="forward"]::view-transition-new(detail-panel) {
    animation-name: slide-in-right;
  }
  html[data-view-transition-direction="back"]::view-transition-old(detail-panel) {
    animation-name: slide-out-right;
  }
  @keyframes slide-in-right {
    from { transform: translateX(100%); }
    to { transform: translateX(0); }
  }
  @keyframes slide-out-right {
    from { transform: translateX(0); }
    to { transform: translateX(100%); }
  }
}

/* ===== SCHEDULE ===== */
.date-nav-btn { position: relative; width: 36px; height: 36px; border: 1.5px solid var(--border); border-radius: 7px; background: var(--white); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-muted); transition: border-color 0.15s, color 0.15s, var(--press); }
.date-nav-btn:hover { border-color: #bbb; color: var(--black); }
.date-label { font-size: 13px; font-weight: 600; color: var(--black); padding: 0 8px; min-width: 100px; text-align: center; font-variant-numeric: tabular-nums; }
.today-btn { position: relative; height: 36px; padding: 0 12px; border: 1.5px solid var(--border); border-radius: 7px; background: var(--white); font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; transition: border-color 0.15s, color 0.15s, var(--press); }
.today-btn:hover { border-color: #bbb; color: var(--black); }
/* Concentric: 3px of padding around a 6px inner radius wants a 9px outer, not 8px. */
.view-switcher { display: flex; background: var(--bg); border-radius: 9px; padding: 3px; gap: 2px; }
.view-btn { padding: 7px 12px; border-radius: 6px; border: none; background: transparent; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; transition: background 0.15s, color 0.15s, var(--press); }
.view-btn.active { background: var(--white); color: var(--black); box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
.time-label { position: absolute; right: 8px; font-size: 10px; font-weight: 600; color: var(--text-subtle); transform: translateY(-50%); white-space: nowrap; }
.hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border); }
.half-line { position: absolute; left: 0; right: 0; border-top: 1px dashed #F0F0F0; }
.now-line { position: absolute; left: 0; right: 0; z-index: 10; pointer-events: none; }
.now-line::before { content: ''; position: absolute; left: -4px; top: -4px; width: 8px; height: 8px; border-radius: 50%; background: var(--red); }
.now-line::after { content: ''; position: absolute; left: 4px; right: 0; top: -1px; height: 2px; background: var(--red); }
.sched-job-block { position: absolute; border-radius: 5px; padding: 4px 7px; cursor: pointer; overflow: hidden; box-sizing: border-box; transition: box-shadow 0.12s, filter 0.12s; }
.sched-job-block:hover { box-shadow: 0 3px 10px rgba(0,0,0,0.15); filter: brightness(0.96); z-index: 10; }
.sched-job-block.sched-block-flash { z-index: 11; animation: schedBlockFlash 1.6s ease-out; }
@keyframes schedBlockFlash {
  0%, 40% { box-shadow: 0 0 0 3px var(--yellow), 0 3px 10px rgba(0,0,0,0.2); }
  100% { box-shadow: none; }
}
.week-day-header { flex: 1; padding: 10px 8px; text-align: center; border-right: 1px solid var(--border); cursor: pointer; transition: background 0.1s; }
.week-day-header:last-child { border-right: none; }
.week-day-header:hover { background: var(--bg); }
.week-day-header.today { background: var(--yellow-light); }
.week-day-name { font-size: 11px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.week-day-num { font-size: 18px; font-weight: 800; color: var(--black); letter-spacing: -0.5px; margin-top: 2px; }
.week-day-num.today { width: 30px; height: 30px; border-radius: 50%; background: var(--ink-fixed); color: var(--yellow); display: inline-flex; align-items: center; justify-content: center; font-size: 15px; margin-top: 2px; }
.list-job-card { background: var(--white); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; display: flex; align-items: center; gap: 14px; cursor: pointer; border-left: 4px solid transparent; transition: box-shadow 0.15s; margin-bottom: 4px; }
.list-job-card:hover { box-shadow: var(--card-shadow); }
.list-job-card.in-progress { border-left-color: var(--yellow); }
.list-job-card.scheduled { border-left-color: var(--blue); }
.list-job-card.completed { border-left-color: var(--green); opacity: 0.75; }
.list-job-time { font-size: 12px; font-weight: 700; color: var(--text-muted); min-width: 56px; flex-shrink: 0; }
.list-job-info { flex: 1; min-width: 0; }
.list-job-name { font-size: 14px; font-weight: 600; color: var(--black); margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list-job-meta { font-size: 12px; color: var(--text-muted); }
.list-date-header { font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.8px; padding: 8px 0 4px; margin-top: 8px; }

/* Per-employee schedule columns (day + "Unassigned" column) */
.sched-emp-header { flex: 1 0 140px; padding: 8px 10px; display: flex; align-items: center; gap: 7px; border-right: 1px solid var(--border); font-size: 12px; font-weight: 600; color: var(--text-muted); }
.sched-emp-column { flex: 1 0 140px; position: relative; height: 960px; border-right: 1px solid var(--border); transition: background 0.1s; }
.sched-emp-column.drag-over { background: var(--yellow-light); }

/* Task blocks — visually distinct from job blocks: dashed border, checkbox, no fill */
.sched-task-block { position: absolute; box-sizing: border-box; display: flex; align-items: flex-start; gap: 5px; border-radius: 5px; border: 1px dashed var(--border); border-left: 3px dashed; padding: 4px 6px; background: var(--white); cursor: pointer; overflow: hidden; transition: box-shadow 0.12s; }
.sched-task-block:hover { box-shadow: 0 3px 10px rgba(0,0,0,0.15); z-index: 10; }
.sched-task-block.done { opacity: 0.55; }
.sched-task-block.done .sched-task-title { text-decoration: line-through; }
.sched-task-check { margin: 1px 0 0; flex-shrink: 0; cursor: pointer; }
.sched-task-title { font-size: 11px; font-weight: 700; color: var(--black); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sched-task-sub { font-size: 10px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Unscheduled-jobs tray above the grid */
.sched-unscheduled-tray { display: flex; align-items: center; gap: 8px; padding: 8px 16px; border-bottom: 1px solid var(--border); background: var(--bg); overflow-x: auto; flex-shrink: 0; }
.sched-unscheduled-label { font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.5px; flex-shrink: 0; }
.sched-unscheduled-chip { flex-shrink: 0; display: flex; flex-direction: column; gap: 1px; padding: 5px 10px; border: 1px dashed var(--border); border-radius: 6px; background: var(--white); cursor: grab; }
.sched-unscheduled-chip-name { font-size: 11px; font-weight: 700; color: var(--black); white-space: nowrap; }
.sched-unscheduled-chip-sub { font-size: 10px; color: var(--text-muted); white-space: nowrap; }

@media (max-width: 900px) {
  .mobile-view-bar { display: flex !important; }
  /* min-width:0 on the bar's own flex items (the date-nav group, the Day/Week/List switcher,
     and the new-task button) is load-bearing: a visible-overflow flex container computes its
     SCROLLABLE overflow from each item's unshrunk min-content size even when it visually
     renders them shrunk to fit — every child's own getBoundingClientRect() sits well inside
     375px, yet document.documentElement.scrollWidth was still 387px. This turned out to be the
     dominant, and only, source of the horizontal-scroll leak on every Schedule sub-view (day,
     week, and list all measured identically), not something specific to the day-grid's
     N-employee columns as originally assumed — see test/e2e/schedule.spec.js, which verified
     this against a real seeded job on all three views before this fix and after. */
  .mobile-view-bar > * { min-width: 0; }
  #view-schedule .topbar { display: none; }
}
/* ===== SIDEBAR COLLAPSE ===== */
:root {
  --sidebar-width: 228px;
  --sidebar-collapsed-width: 60px;
}

.sidebar {
  transition: width 0.25s ease;
  overflow-x: hidden;
}

.sidebar.collapsed {
  width: var(--sidebar-collapsed-width);
}

.sidebar-logo {
  display: flex;
  align-items: center;
  padding: 16px 14px;
  min-height: 60px;
}

.logo-full { display: block; }
.logo-icon { display: none; }

.sidebar.collapsed .logo-full { display: none; }
.sidebar.collapsed .logo-icon { display: block; }

/* Collapse button */
.sidebar-collapse-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 4px 12px 8px;
  background: none;
  border: none;
  cursor: pointer;
  color: rgba(255,255,255,0.3);
  transition: color 0.15s;
  flex-shrink: 0;
}
.sidebar-collapse-btn:hover { color: rgba(255,255,255,0.7); }

.sidebar.collapsed .sidebar-collapse-btn {
  justify-content: center;
  padding: 4px 0 8px;
}

.collapse-icon {
  transition: transform 0.25s ease;
}
.sidebar.collapsed .collapse-icon {
  transform: rotate(180deg);
}

/* Nav items in collapsed state */
.nav-item {
  position: relative;
}

.nav-label {
  transition: opacity 0.2s ease, width 0.2s ease;
  white-space: nowrap;
  overflow: hidden;
}

.sidebar.collapsed .nav-label {
  opacity: 0;
  width: 0;
  pointer-events: none;
}

.sidebar.collapsed .nav-badge {
  position: absolute;
  top: 2px;
  left: calc(50% + 6px);
  margin-left: 0;
  min-width: 15px;
  height: 15px;
  padding: 0 3px;
  font-size: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--white);
  color: var(--black);
  border: 2px solid var(--sidebar-bg);
  box-sizing: content-box;
}

.sidebar.collapsed .nav-item {
  justify-content: center;
  padding: 10px 0;
  margin: 1px 6px;
}

/* Tooltip on hover when collapsed */
.sidebar.collapsed .nav-item::after {
  content: attr(data-label);
  position: absolute;
  left: calc(100% + 12px);
  top: 50%;
  transform: translateY(-50%);
  background: rgba(17,17,17,0.92);
  color: white;
  font-size: 12px;
  font-weight: 600;
  padding: 6px 10px;
  border-radius: 7px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 200;
}

.sidebar.collapsed .nav-item:hover::after {
  opacity: 1;
}

/* Notification bell collapsed */
.sidebar.collapsed .notif-popup {
  left: calc(100% + 8px);
  right: auto;
  width: 280px;
  bottom: 8px;
}
.sidebar.collapsed .notif-bell {
  justify-content: center;
  padding: 8px 0;
  position: relative;
}
.sidebar.collapsed .notif-bell .nav-label {
  display: none;
}
.sidebar.collapsed .notif-badge {
  left: calc(50% + 2px);
}
.sidebar.collapsed .notif-bell::after {
  content: attr(data-label);
  position: absolute;
  left: calc(100% + 12px);
  top: 50%;
  transform: translateY(-50%);
  background: rgba(17,17,17,0.92);
  color: white;
  font-size: 12px;
  font-weight: 600;
  padding: 6px 10px;
  border-radius: 7px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 200;
}
.sidebar.collapsed .notif-bell:hover::after {
  opacity: 1;
}

/* User pill collapsed */
.sidebar.collapsed .user-pill-popup {
  left: calc(100% + 8px);
  right: auto;
  width: 220px;
  bottom: 8px;
}
.sidebar.collapsed .user-info,
.sidebar.collapsed .user-pill svg:last-child {
  display: none;
}

.sidebar.collapsed .user-pill {
  justify-content: center;
  padding: 8px 0;
  position: relative;
}

.sidebar.collapsed .user-pill::after {
  content: attr(data-label);
  position: absolute;
  left: calc(100% + 12px);
  top: 50%;
  transform: translateY(-50%);
  background: rgba(17,17,17,0.92);
  color: white;
  font-size: 12px;
  font-weight: 600;
  padding: 6px 10px;
  border-radius: 7px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s;
  z-index: 200;
}
.sidebar.collapsed .user-pill:hover::after { opacity: 1; }

/* Main content adjusts */
.main {
  transition: margin-left 0.25s ease;
}

/* Persist collapse state */

/* ===== MODALS ===== */
.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.45); z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 16px; animation: modal-overlay-in 0.16s cubic-bezier(0.2, 0, 0, 1); }
.modal { background: var(--white); border-radius: 14px; width: 100%; max-width: 520px; max-height: 90vh; max-height: 90dvh; display: flex; flex-direction: column; box-shadow: var(--overlay-shadow); animation: modal-in 0.22s cubic-bezier(0.2, 0, 0, 1); }
@keyframes modal-overlay-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in { from { opacity: 0; transform: translateY(10px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
.modal-header { padding: 20px 24px 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
.modal-title { font-size: 16px; font-weight: 800; color: var(--black); letter-spacing: -0.2px; text-wrap: balance; }
.modal-close { position: relative; width: 28px; height: 28px; border-radius: 7px; border: 1.5px solid var(--border); background: var(--white); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-muted); font-size: 14px; line-height: 1; transition: border-color 0.15s, color 0.15s, var(--press); }
.modal-close:hover { border-color: #bbb; color: var(--black); }
.modal-body { padding: 20px 24px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 14px; }
.modal-footer { padding: 14px 24px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 8px; flex-shrink: 0; }
.form-group { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; }
.form-row { display: flex; gap: 12px; }
.form-label { font-size: 12px; font-weight: 600; color: var(--text-muted); }
.form-input { height: 36px; border: 1.5px solid var(--border-strong); border-radius: 8px; padding: 0 12px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--white); outline: none; width: 100%; transition: border-color 0.15s; }
.form-input:focus { border-color: var(--black); }
.form-input::placeholder { color: var(--text-subtle); }
.form-select { height: 36px; border: 1.5px solid var(--border-strong); border-radius: 8px; padding: 0 32px 0 12px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--white) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 256 256'%3E%3Cpath fill='%236B6B6B' d='M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E") no-repeat right 12px center; outline: none; width: 100%; cursor: pointer; appearance: none; transition: border-color 0.15s; }
.form-select:focus { border-color: var(--black); }
.form-textarea { border: 1.5px solid var(--border-strong); border-radius: 8px; padding: 10px 12px; font-size: 13px; font-family: inherit; color: var(--text); background: var(--white); outline: none; width: 100%; resize: vertical; min-height: 64px; transition: border-color 0.15s; }
.form-textarea:focus { border-color: var(--black); }
.form-textarea::placeholder { color: var(--text-subtle); }
/* Bottom-sheet modals on phones. Previously `max-height:100vh` + `border-radius:0`,
   which (a) overshot the visible viewport for the same `vh` reason as .main and
   (b) ran the footer's Save/Cancel buttons under the home indicator, because the
   sheet is flush to the bottom edge and nothing reserved the safe-area inset. */
@media (max-width: 560px) {
  .modal-overlay { padding: 0; align-items: flex-end; }
  .modal { max-height: 92vh; max-height: 92dvh; border-radius: 16px 16px 0 0; }
  .modal-footer { padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
  /* One-handed reach: full-width, thumb-sized footer buttons instead of a pair of
     36px chips pinned to the far right corner. */
  .modal-footer > .btn-primary, .modal-footer > .btn-secondary, .modal-footer > .btn-danger { flex: 1; justify-content: center; min-height: 44px; }
}
.modal-lg { max-width: 680px; }
.modal-section-label { font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.8px; padding-bottom: 4px; border-bottom: 1px solid var(--border); margin-top: 4px; }

/* ===== PROPERTIES ===== */
.prop-row { background: var(--white); border-radius: var(--radius); border: 1.5px solid transparent; padding: 12px 16px; display: flex; align-items: center; gap: 12px; cursor: pointer; transition: border-color 0.15s, box-shadow 0.15s; }
.prop-row:hover { border-color: var(--border); box-shadow: var(--card-shadow); }
.prop-row.active { border-color: var(--black); box-shadow: var(--card-shadow); }
.prop-row-icon { width: 36px; height: 36px; border-radius: 9px; background: var(--blue-light); color: var(--blue); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.prop-row-info { flex: 1; min-width: 0; }
.prop-row-address { font-size: 14px; font-weight: 700; color: var(--black); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 2px; }
.prop-row-meta { font-size: 12px; color: var(--text-muted); display: flex; gap: 6px; align-items: center; }
.prop-row-right { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex-shrink: 0; }
.prop-service-chip { display: inline-flex; align-items: center; background: var(--yellow-light); color: var(--yellow-text); font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 20px; white-space: nowrap; }

/* ===== PROPERTY FORM PAGE ===== */
.prop-form-body { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 24px 20px 40px; background: var(--bg); }
.prop-form-inner { max-width: 680px; margin: 0 auto; display: flex; flex-direction: column; gap: 16px; }
.prop-form-card { background: var(--white); border: 1px solid var(--border); border-radius: 12px; padding: 22px 24px; }
.prop-form-card-title { font-size: 17px; font-weight: 700; color: var(--black); margin-bottom: 18px; }
.prop-form-footer { display: flex; justify-content: flex-end; gap: 10px; padding: 4px 0 8px; }

/* ===== LARGE PHOTO CARDS ===== */
.prop-photo-cards { display: flex; flex-direction: column; gap: 14px; margin-top: 4px; }
.prop-photo-card { border: 1px solid var(--border); border-radius: 10px; overflow: hidden; background: var(--white); }
.prop-photo-card-img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; cursor: pointer; background: var(--bg); transition: opacity 0.15s; }
.prop-photo-card-img:hover { opacity: 0.92; }
.prop-photo-card-title { font-size: 14px; font-weight: 700; color: var(--black); padding: 12px 16px 10px; }
.prop-photo-card-desc { font-size: 13px; color: var(--text-muted); line-height: 1.45; padding: 10px 16px 4px; }
.prop-photo-card-job { display: inline-block; font-size: 11px; font-weight: 700; color: var(--blue); background: var(--blue-light); padding: 3px 9px; border-radius: 10px; margin: 8px 16px 0; }
.prop-photo-card-footer { padding: 6px 10px 10px; display: flex; justify-content: flex-end; gap: 6px; }
.prop-photo-card-btn { font-size: 12px; font-weight: 600; color: var(--text-muted); background: none; border: 1.5px solid var(--border); border-radius: 6px; cursor: pointer; min-height: 40px; padding: 5px 12px; font-family: inherit; transition: border-color 0.15s, color 0.15s, var(--press); }
.prop-photo-card-btn:hover { border-color: #bbb; color: var(--black); }
.prop-photo-card-btn.danger { color: var(--red); }
.prop-photo-card-btn.danger:hover { border-color: var(--red); }

/* ===== PROPERTY FORM PHOTO ITEMS ===== */
.prop-form-photo-item { display: flex; flex-direction: column; gap: 10px; padding: 20px 0; border-bottom: 1px solid var(--border); }
.prop-form-photo-item:last-child { border-bottom: none; }
.prop-form-photo-thumb { width: 100%; aspect-ratio: 4/3; object-fit: cover; border-radius: 10px; cursor: pointer; background: var(--bg); display: block; }
.prop-form-photo-remove { background: none; border: 1.5px solid var(--border); border-radius: 6px; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; padding: 5px 12px; font-family: inherit; align-self: flex-end; }
.prop-form-photo-remove.danger { color: var(--red); border-color: transparent; }
.prop-form-photo-add { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; border: 2px dashed var(--border); border-radius: 10px; cursor: pointer; color: var(--text-muted); font-size: 13px; font-weight: 600; margin-top: 4px; transition: border-color 0.15s, color 0.15s; font-family: inherit; }
.prop-form-photo-add:hover { border-color: var(--yellow); color: var(--yellow); }

/* ===== PHOTO REVIEW OVERLAY ===== */
.photo-review-modal { background: var(--white); border-radius: 14px; width: 100%; max-width: 560px; max-height: 88vh; max-height: 88dvh; display: flex; flex-direction: column; overflow: hidden; box-shadow: var(--overlay-shadow); animation: modal-in 0.22s cubic-bezier(0.2, 0, 0, 1); }
.photo-review-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
.photo-review-list { overflow-y: auto; flex: 1; padding: 16px 20px; display: flex; flex-direction: column; gap: 0; -webkit-overflow-scrolling: touch; }
.photo-review-item { display: flex; gap: 14px; padding: 16px 0; border-bottom: 1px solid var(--border); }
.photo-review-item:first-child { padding-top: 0; }
.photo-review-item:last-child { border-bottom: none; }
.photo-review-thumb { width: 88px; height: 88px; object-fit: cover; border-radius: 8px; flex-shrink: 0; background: var(--bg); }
.photo-review-fields { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.photo-review-footer { padding: 12px 20px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; flex-shrink: 0; }

/* ===== TIMECARDS ===== */
.tc-row { display: flex; align-items: center; gap: 12px; padding: 11px 14px; }
.tc-row-avatar { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 800; flex-shrink: 0; }
.tc-avatar-lg { width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800; flex-shrink: 0; }
.tc-row-info { flex: 1; min-width: 0; }
.tc-row-name { font-size: 14px; font-weight: 700; color: var(--black); }
.tc-row-job { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.tc-row-meta { font-size: 11px; color: var(--text-subtle); margin-top: 1px; }
.tc-row-right { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex-shrink: 0; }
.tc-row-hours { font-size: 14px; font-weight: 700; color: var(--black); }
.chip-tc-pending { background: var(--orange-light); color: var(--orange-text); }
.chip-tc-flagged { background: var(--red-light); color: var(--red); }

/* ===== PHOTOS ===== */
.photos-filter-bar { background: var(--white); border-bottom: 1px solid var(--border); padding: 10px 16px; display: flex; align-items: center; gap: 10px; flex-shrink: 0; flex-wrap: wrap; }
.photos-count { font-size: 12px; color: var(--text-muted); margin-left: auto; white-space: nowrap; }
.photo-upload-btn { height: 36px; font-size: 12px; padding: 0 12px; cursor: pointer; display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.photos-search { width: 220px; flex-shrink: 1; min-width: 140px; }
/* No font-size here on purpose: it has the .search-input class (font-size:13px desktop,
   16px under the mobile media query at line ~1193) — an ID-level font-size here would beat
   that class rule by specificity regardless of source order and silently defeat the mobile
   16px rule (caught by test/e2e/mobile-invariants). */
#photoSearchInput { border: 1.5px solid var(--border); border-radius: 8px; padding: 0 12px; height: 36px; font-family: inherit; color: var(--text); outline: none; background: var(--bg); transition: border-color 0.15s; }
#photoSearchInput:focus { border-color: #aaa; background: var(--white); }
.photos-grid-wrap { flex: 1; overflow-y: auto; padding: 16px; }
.photos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.photo-grid-card { position: relative; border-radius: 10px; overflow: hidden; background: var(--white); border: 1px solid var(--border); cursor: pointer; transition: box-shadow 0.15s; }
.photo-grid-card:hover { box-shadow: var(--card-shadow); }
.photo-grid-delete { position: absolute; top: 6px; right: 6px; z-index: 1; width: 26px; height: 26px; border-radius: 50%; border: none; background: rgba(17,17,17,0.55); color: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; opacity: 0; transition: opacity 0.15s, background 0.15s; }
.photo-grid-card:hover .photo-grid-delete { opacity: 1; }
.photo-grid-delete:hover { background: var(--red); }
.photo-grid-checkbox { display: none; position: absolute; top: 6px; left: 6px; z-index: 1; width: 24px; height: 24px; border-radius: 50%; background: rgba(255,255,255,0.85); border: 1.5px solid rgba(0,0,0,0.25); align-items: center; justify-content: center; color: transparent; cursor: pointer; transition: background 0.15s, border-color 0.15s, color 0.15s; }
.photo-grid-checkbox.checked { background: var(--yellow); border-color: var(--yellow); color: #111; }
#photoSelectModeBtn.active { border-color: var(--black); color: var(--black); background: var(--bg); }
#photosGrid.selection-mode .photo-grid-checkbox { display: flex; }
#photosGrid.selection-mode .photo-grid-delete { display: none; }
#photosGrid.selection-mode .photo-grid-card:has(.photo-grid-checkbox.checked) { box-shadow: 0 0 0 3px var(--yellow) inset; }
.photos-bulk-bar { background: var(--white); border-bottom: 1px solid var(--border); padding: 10px 16px; display: flex; align-items: center; gap: 10px; flex-shrink: 0; flex-wrap: wrap; font-size: 13px; color: var(--text-muted); font-weight: 600; }
.photo-grid-img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; background: var(--bg); }
.photo-grid-info { padding: 8px 10px 10px; }
.photo-grid-type { font-size: 12px; font-weight: 700; color: var(--black); text-transform: capitalize; }
.photo-grid-addr { font-size: 11px; color: var(--text-muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.photo-grid-caption { font-size: 11px; color: var(--text-subtle); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.photo-grid-job { display: inline-block; font-size: 10px; font-weight: 700; color: var(--blue); background: var(--blue-light); padding: 2px 7px; border-radius: 10px; margin-top: 5px; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; }
.photo-grid-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }

/* ===== TAGS (read-only chips + editable picker, shared by the photo review
   overlay, the lightbox meta panel, and property/gallery cards) ===== */
.prop-photo-card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 16px 0; }
.photo-tag-chip { display: inline-block; font-size: 10px; font-weight: 700; color: var(--text-muted); background: var(--bg); border: 1px solid var(--border); padding: 2px 7px; border-radius: 10px; white-space: nowrap; }

.tag-picker { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.tag-picker-chip { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; color: var(--text); background: var(--bg); border: 1px solid var(--border); padding: 3px 6px 3px 10px; border-radius: 20px; }
.tag-picker-chip-remove { background: none; border: none; cursor: pointer; color: var(--text-subtle); font-size: 13px; line-height: 1; padding: 2px; display: flex; align-items: center; justify-content: center; font-family: inherit; }
.tag-picker-chip-remove:hover { color: var(--red); }
.tag-picker-input { flex: 1; min-width: 90px; border: 1.5px solid var(--border); border-radius: 8px; padding: 0 10px; height: 30px; font-size: 12px; font-family: inherit; color: var(--text); background: var(--white); outline: none; transition: border-color 0.15s; }
.tag-picker-input:focus { border-color: var(--black); }

/* Dark variant for the lightbox meta panel — matches that panel's existing
   translucent-on-black inline-styled inputs. */
.tag-picker-dark .tag-picker-chip { background: rgba(255,255,255,0.12); border-color: rgba(255,255,255,0.22); color: #fff; }
.tag-picker-dark .tag-picker-chip-remove { color: rgba(255,255,255,0.6); }
.tag-picker-dark .tag-picker-chip-remove:hover { color: #fff; }
.tag-picker-dark .tag-picker-input { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.2); color: #fff; }
.tag-picker-dark .tag-picker-input::placeholder { color: rgba(255,255,255,0.5); }

/* ===== REPORTS ===== */
.reports-body { flex: 1; overflow-y: auto; padding: 20px 24px 40px; }
.reports-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; margin-bottom: 24px; }
.report-card { background: var(--white); border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; }
.report-card-accent { background: var(--ink-fixed); color: var(--ink-fixed-text); border-color: var(--ink-fixed); }
.report-card-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); margin-bottom: 8px; }
.report-card-accent .report-card-label { color: rgba(255,255,255,0.5); }
.report-card-value { font-size: 24px; font-weight: 800; letter-spacing: -0.5px; color: var(--black); }
.report-card-accent .report-card-value { color: var(--yellow); }
.report-card-sub { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.report-card-accent .report-card-sub { color: rgba(255,255,255,0.4); }
.reports-sections { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
.report-section { background: var(--white); border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; }
.report-section-title { font-size: 13px; font-weight: 700; color: var(--black); margin-bottom: 14px; text-transform: uppercase; letter-spacing: 0.3px; }
.report-job-bars { display: flex; flex-direction: column; gap: 10px; }
.report-job-bar-row { display: flex; align-items: center; gap: 10px; }
.report-bar-track { flex: 1; height: 8px; background: var(--bg); border-radius: 4px; overflow: hidden; }
.report-bar-fill { height: 100%; background: var(--yellow); border-radius: 4px; transition: width 0.4s; }
.report-client-row { display: flex; justify-content: space-between; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); }
.report-client-row:last-child { border-bottom: none; }
.report-emp-row { display: flex; justify-content: space-between; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); }
.report-emp-row:last-child { border-bottom: none; }

.reports-range-bar { display: flex; align-items: center; gap: 8px; padding: 12px 24px; background: var(--white); border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.reports-range-custom { display: flex; align-items: center; gap: 6px; }
.reports-range-custom .form-input { height: 32px; width: 140px; padding: 0 8px; }
.reports-block-title { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-subtle); margin: 4px 24px 10px; }

.aging-bucket-row { cursor: pointer; }
.aging-bucket-detail { padding: 4px 0 12px; border-bottom: 1px dashed var(--border); margin-bottom: -2px; }
.aging-bucket-detail:last-child { border-bottom: none; }

.reports-attn-group-label { padding: 12px 20px 6px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px; color: var(--text-subtle); }
.reports-attn-group-label:first-child { padding-top: 0; }

.report-stat-row { display: flex; justify-content: space-between; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text-muted); }
.report-stat-row:last-child { border-bottom: none; }
.report-stat-row strong { color: var(--black); font-size: 14px; }

.profit-rows { display: flex; flex-direction: column; }
.profit-row { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.profit-row:hover { background: var(--hover-bg); }
.profit-row:last-child { border-bottom: none; }
.profit-row-totals { cursor: default; border-top: 2px solid var(--border); margin-top: 4px; padding-top: 14px; }
.profit-row-totals:hover { background: none; }
.profit-row-main { min-width: 0; flex: 1; }
.profit-row-name { font-size: 13px; font-weight: 600; color: var(--black); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.profit-row-sub { font-size: 12px; color: var(--text-muted); }
.profit-row-figures { display: flex; gap: 20px; flex-shrink: 0; }
.profit-row-figure { text-align: right; font-size: 13px; font-weight: 700; color: var(--black); }
.profit-row-figure span { display: block; font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.3px; color: var(--text-subtle); margin-bottom: 2px; }
.profit-row-net { min-width: 110px; }

.trend-legend { display: flex; align-items: center; gap: 16px; margin-bottom: 10px; font-size: 12px; color: var(--text-muted); }
.trend-legend-item { display: flex; align-items: center; gap: 6px; }
.trend-legend-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.trend-table-toggle { margin-left: auto; background: none; border: none; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; text-decoration: underline; font-family: inherit; padding: 0; }
.trend-table-toggle:hover { color: var(--black); }
.trend-chart-wrap { position: relative; }
.trend-chart-svg { width: 100%; height: 220px; display: block; }
.trend-tooltip { position: absolute; top: 8px; transform: translateX(-50%); background: var(--ink-fixed); color: var(--ink-fixed-text); border-radius: 8px; padding: 8px 10px; font-size: 11px; pointer-events: none; white-space: nowrap; box-shadow: 0 4px 12px rgba(0,0,0,0.2); z-index: 5; }
.trend-tooltip-date { font-weight: 700; margin-bottom: 4px; }
.trend-tooltip-row { display: flex; align-items: center; gap: 6px; }
.trend-tooltip-row strong { margin-left: auto; padding-left: 10px; }
.trend-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.trend-table th, .trend-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--border); }
.trend-table th { color: var(--text-muted); font-weight: 600; text-transform: uppercase; font-size: 10px; letter-spacing: 0.3px; }
.trend-table th:not(:first-child), .trend-table td:not(:first-child) { text-align: right; }

@media (max-width: 900px) {
  .reports-sections { grid-template-columns: 1fr; }
  .reports-body { padding: 16px 12px 80px; }
  .reports-range-bar { padding: 10px 12px; }
  .profit-row { flex-wrap: wrap; }
  .profit-row-figures { width: 100%; justify-content: space-between; gap: 10px; }
}

/* ===== INVOICES ===== */
.invoice-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; padding: 12px 14px; }
.invoice-row-left { flex: 1; min-width: 0; }
.invoice-row-num { font-size: 14px; font-weight: 700; color: var(--black); }
.invoice-row-client { font-size: 12px; color: var(--text-muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.invoice-row-due { font-size: 11px; color: var(--text-subtle); margin-top: 2px; }
.invoice-row-right { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex-shrink: 0; }
.invoice-row-amount { font-size: 14px; font-weight: 700; color: var(--black); }

/* Invoice status chips */
.chip-inv-draft { background: var(--bg); color: var(--text-subtle); }
.chip-inv-sent { background: var(--blue-light); color: var(--blue); }
.chip-inv-unpaid { background: var(--orange-light); color: var(--orange-text); }
.chip-inv-overdue { background: var(--red-light); color: var(--red); }
.chip-inv-paid { background: var(--green-light); color: var(--green); }

/* Invoice line items table */
.invoice-items-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 10px; }
.invoice-items-table th { text-align: left; font-size: 11px; font-weight: 700; color: var(--text-muted); padding: 0 8px 8px 0; border-bottom: 1px solid var(--border); text-transform: uppercase; letter-spacing: 0.3px; }
.invoice-items-table td { padding: 8px 8px 8px 0; border-bottom: 1px solid var(--border); color: var(--text); vertical-align: top; }
.invoice-items-table tbody tr:last-child td { border-bottom: none; }

/* Invoice totals */
.invoice-totals { margin-top: 14px; display: flex; flex-direction: column; gap: 5px; }
.invoice-total-row { display: flex; justify-content: space-between; font-size: 13px; color: var(--text-muted); padding: 2px 0; }
.invoice-total-bold { font-weight: 700; color: var(--black); font-size: 15px; border-top: 1px solid var(--border); padding-top: 8px; margin-top: 4px; }
.invoice-balance { font-weight: 800; color: var(--black); font-size: 16px; }

/* Invoice payment row */
.invoice-payment-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--border); }
.invoice-payment-row:last-child { border-bottom: none; }

/* Invoice form line item row */
.invoice-line-item-row { display: flex; gap: 8px; align-items: center; margin-bottom: 6px; }
.inv-item-total { font-size: 13px; font-weight: 600; color: var(--text-muted); min-width: 56px; text-align: right; flex-shrink: 0; }
.inv-item-remove { position: relative; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text-subtle); font-size: 16px; cursor: pointer; padding: 0; line-height: 1; flex-shrink: 0; transition: color 0.15s, var(--press); }
.inv-item-remove:hover { color: var(--red); }
.invoice-add-item-btn { position: relative; background: none; border: none; color: var(--blue); font-size: 13px; font-weight: 600; cursor: pointer; padding: 6px 0; font-family: inherit; }
.invoice-add-item-btn:hover { color: var(--black); }
.invoice-form-totals { border-top: 1px solid var(--border); padding-top: 12px; margin-top: 4px; display: flex; flex-direction: column; gap: 5px; }

@media (max-width: 900px) {
  .prop-form-body { padding: 16px 12px 80px; }
  .prop-form-card { padding: 16px; border-radius: 10px; }
  .prop-form-card-title { font-size: 15px; margin-bottom: 14px; }
}


/* ===== REQUESTS ===== */
.req-filter-btn { background: none; border: 1.5px solid var(--border); border-radius: 20px; min-height: 40px; padding: 5px 14px; font-size: 12px; font-weight: 600; cursor: pointer; color: var(--text-muted); font-family: inherit; white-space: nowrap; transition: background 0.15s, border-color 0.15s, color 0.15s, var(--press); }
.req-filter-btn:hover { border-color: var(--black); color: var(--black); }
.req-filter-btn.active { background: var(--ink-fixed); border-color: var(--ink-fixed); color: var(--ink-fixed-text); }

/* ===== MESSAGES (COMMUNICATIONS INBOX) =====
   Desktop is a two-pane split (thread list beside the open conversation). On a
   phone the two panes CANNOT coexist — a 320px list next to a flex:1 conversation
   leaves the conversation ~70px wide, which renders message bodies one letter per
   line. So below 900px this collapses to the same one-pane-at-a-time pattern the
   rest of the app already uses for list/detail (.content-split + .detail-panel):
   the list is full-width, and opening a thread swaps it out for a full-screen
   conversation with a back button. `.thread-open` on .comm-split is the switch. */
/* These three panes must sit on --white, not the page's --bg: an incoming bubble is
   filled with --bg, so on a --bg pane it was invisible — the message read as bare
   text floating on the page with no bubble at all. */
.comm-filter-bar { display: flex; gap: 6px; padding: 12px 16px; background: var(--white); border-bottom: 1px solid var(--border); flex-shrink: 0; overflow-x: auto; }
.comm-split { display: flex; flex: 1; overflow: hidden; }
.comm-list { width: 320px; flex-shrink: 0; background: var(--white); border-right: 1px solid var(--border); overflow-y: auto; -webkit-overflow-scrolling: touch; }
.comm-empty { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--text-muted); font-size: 13px; padding: 24px; text-align: center; }
.comm-thread { flex: 1; min-width: 0; overflow: hidden; display: none; flex-direction: column; background: var(--white); }
.comm-split.thread-open .comm-thread { display: flex; }
.comm-split.thread-open .comm-empty { display: none; }

/* Thread rows in the list */
.comm-row { padding: 12px 14px; margin: 4px 8px; border-radius: 10px; border: 1px solid transparent; cursor: pointer; transition: background 0.12s; }
.comm-row:hover { background: var(--hover-bg); }
.comm-row.active { background: var(--yellow-light); border-color: var(--yellow); }
.comm-row-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.comm-row-who { font-size: 13.5px; font-weight: 700; color: var(--black); margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.comm-row-unmatched { color: var(--text-muted); font-weight: 400; }
.comm-row-preview { font-size: 12.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.comm-row-time { font-size: 11px; color: var(--text-muted); flex-shrink: 0; font-variant-numeric: tabular-nums; }

/* Conversation header */
.comm-thread-header { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0; }
.comm-thread-who { min-width: 0; flex: 1; }
.comm-thread-name { font-size: 15px; font-weight: 700; color: var(--black); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.comm-thread-phone { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.comm-thread-actions { display: flex; gap: 8px; flex-shrink: 0; }
/* Back only exists on mobile — on desktop the list is still on screen beside you. */
.comm-back { display: none; align-items: center; justify-content: center; width: 40px; height: 40px; margin-left: -8px; flex-shrink: 0; border: none; background: none; border-radius: 8px; color: var(--text-muted); cursor: pointer; font-family: inherit; transition: background 0.12s, color 0.12s, var(--press); }
.comm-back:hover { background: var(--bg); color: var(--black); }
.comm-back:active { transform: scale(0.96); }

/* Message stream */
.comm-messages { flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 16px; display: flex; flex-direction: column; gap: 10px; }
.comm-bubble-wrap { max-width: 76%; min-width: 0; }
.comm-bubble-wrap.mine { align-self: flex-end; }
.comm-bubble-wrap.theirs { align-self: flex-start; }
/* overflow-wrap:anywhere (not word-break:break-all) so ordinary prose still breaks
   at spaces, but a pasted URL or a 40-char part number can't force a horizontal
   scrollbar on a narrow phone. */
.comm-bubble { padding: 9px 13px; border-radius: 16px; font-size: 14px; line-height: 1.45; white-space: pre-wrap; overflow-wrap: anywhere; }
.comm-bubble-wrap.mine .comm-bubble { background: var(--blue); color: #fff; border-bottom-right-radius: 5px; }
.comm-bubble-wrap.theirs .comm-bubble { background: var(--bg); color: var(--text); border-bottom-left-radius: 5px; }
.comm-bubble-time { font-size: 11px; color: var(--text-muted); margin-top: 3px; font-variant-numeric: tabular-nums; }
.comm-bubble-wrap.mine .comm-bubble-time { text-align: right; }
/* Calls render as centred timeline events, not bubbles — they have no body text. */
.comm-event { align-self: center; max-width: 90%; text-align: center; font-size: 12px; color: var(--text-muted); background: var(--bg); padding: 5px 12px; border-radius: 20px; }
.comm-event.missed { color: var(--red); font-weight: 600; }

/* Compose */
.comm-compose { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border); flex-shrink: 0; background: var(--white); }
.comm-compose .form-input { flex: 1; min-width: 0; }

@media (max-width: 900px) {
  .comm-list { width: 100%; border-right: none; }
  /* Full-bleed rows with a hairline between them — on a phone the list IS the
     screen, so inset cards read as floating fragments rather than an inbox. */
  .comm-row { margin: 0; border-radius: 0; border: none; border-bottom: 1px solid var(--border); padding: 14px 16px; }
  .comm-row.active { background: transparent; }
  /* No "Select a conversation" placeholder on a phone — there is no second pane
     for it to live in; the list itself is the resting state. */
  .comm-empty { display: none; }
  .comm-split.thread-open .comm-list { display: none; }
  .comm-back { display: flex; }
  /* Keep Call / Add-as-Client inline with the name (like any messaging app) but
     compact, so the two of them plus the back arrow still leave the name room to
     ellipsize rather than forcing a second row. */
  .comm-thread-actions .btn-secondary { min-height: 44px; padding: 0 12px; font-size: 12px; }
  .comm-bubble-wrap { max-width: 85%; }
  .comm-compose .form-input { height: 44px; }
  .comm-compose .btn-primary { min-height: 44px; padding: 0 16px; }
}

/* ===== MOBILE MORE SHEET ===== */
.mobile-more-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.45); z-index: 300; opacity: 0; pointer-events: none; transition: opacity 0.2s; cursor: pointer; }
.mobile-more-overlay.open { opacity: 1; pointer-events: auto; }
.mobile-more-sheet { position: fixed; left: 0; right: 0; bottom: 0; z-index: 301; background: var(--white); border-radius: 16px 16px 0 0; padding-bottom: env(safe-area-inset-bottom, 0px); transform: translateY(100%); transition: transform 0.28s cubic-bezier(0.34, 1.1, 0.64, 1); }
.mobile-more-sheet.open { transform: translateY(0); }
.mobile-more-handle { width: 40px; height: 4px; background: var(--border); border-radius: 2px; margin: 12px auto 0; }
.mobile-more-title { padding: 12px 20px 6px; font-size: 11px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.7px; }
.mobile-more-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; padding: 4px 12px 20px; }
.mobile-more-item { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 12px 4px; border-radius: 10px; cursor: pointer; color: var(--text-muted); font-size: 11px; font-weight: 600; text-align: center; transition: background 0.12s, color 0.12s; -webkit-tap-highlight-color: transparent; }
.mobile-more-item:active { background: var(--bg); }
.mobile-more-item.active { color: var(--black); }
.mobile-more-icon { width: 48px; height: 48px; border-radius: 14px; background: var(--bg); display: flex; align-items: center; justify-content: center; margin-bottom: 2px; transition: background 0.12s; }
.mobile-more-item.active .mobile-more-icon { background: var(--yellow-light); color: var(--yellow-text); }

/* ===== MOBILE ENHANCEMENTS ===== */
@media (max-width: 900px) {
  /* Safe area insets for notched phones. These only became live once the viewport
     meta gained `viewport-fit=cover` (see partials/head.ejs) — before that every
     env(safe-area-inset-*) below resolved to 0 and this was inert. */
  .mobile-nav { padding-bottom: env(safe-area-inset-bottom, 0px); height: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px)); }
  .main { padding-bottom: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px)); }

  /* Now that content runs edge-to-edge, the sticky top bar has to clear the notch,
     and both bars have to clear the rounded corners / camera cutout in landscape. */
  .mobile-topbar {
    padding-top: calc(10px + env(safe-area-inset-top, 0px));
    padding-left: calc(12px + env(safe-area-inset-left, 0px));
    padding-right: calc(12px + env(safe-area-inset-right, 0px));
  }
  .mobile-nav { padding-left: calc(4px + env(safe-area-inset-left, 0px)); padding-right: calc(4px + env(safe-area-inset-right, 0px)); }
  #impersonationBanner { padding-top: calc(8px + env(safe-area-inset-top, 0px)); }
  /* Toasts sit bottom-right by default — directly on top of the bottom nav. */
  .toast-container { bottom: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px) + 12px); left: 12px; right: 12px; align-items: stretch; }
  .toast { width: auto; }

  /* Prevent iOS auto-zoom on input focus (inputs need font-size >= 16px) */
  .form-input, .form-select, .form-textarea, .search-input, .notes-area, .settings-input { font-size: 16px; }

  /* Settings input: remove min-width that breaks small screens */
  .settings-input { min-width: 0; width: 100%; max-width: 100%; height: 44px; }
  .settings-row { flex-wrap: wrap; gap: 8px; padding: 12px 14px; }
  .settings-row-label { min-width: 0; flex-basis: 100%; }

  /* Touch target minimums (44px) */
  .btn-primary { min-height: 44px; padding: 0 18px; }
  .btn-secondary { min-height: 44px; }
  .quick-btn { height: 44px; }
  .req-filter-btn { height: 36px; padding: 0 14px; }

  /* Scrollable lists — clearance from bottom nav */
  .item-list { padding-bottom: 16px; }
  .photos-grid-wrap { padding-bottom: 16px; }
  .reports-body { padding-bottom: 80px; }

  /* Photos: capture is the whole point of this view in the field, so Photo/Camera
     get the full first row at thumb height, with the filters below them. */
  .photo-upload-btn { flex: 1 1 0; min-height: 44px; font-size: 13px; justify-content: center; }
  .photos-search { flex: 1 1 100%; width: 100%; min-width: 0; }
  .photos-filter-bar .form-select { flex: 1 1 40%; max-width: none !important; min-width: 0; height: 44px; }
  .photos-count { flex-basis: 100%; margin-left: 0; text-align: right; }

  /* Team roster: name + status + 3 action buttons cannot fit one 390px row — the
     buttons were being pushed off the right edge and clipped. Wrap them onto their
     own full-width row instead. */
  .employee-row { flex-wrap: wrap; }
  .employee-info { flex: 1 1 auto; min-width: 0; }
  .employee-actions { display: flex; gap: 6px; width: 100%; }
  .employee-actions .btn-secondary { flex: 1; justify-content: center; min-height: 44px; height: auto !important; }

  /* Invoice line items are a 4-column table; let it scroll sideways inside its own
     box rather than widening the whole detail pane. */
  .invoice-items-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .invoice-items-table { min-width: 380px; }

  /* Request detail panel as full-screen overlay on mobile */
  #requestDetailPanel.mobile-open {
    position: fixed !important;
    top: 0; left: 0; right: 0; bottom: 0;
    z-index: 200;
    background: var(--white);
    display: flex !important;
    flex-direction: column;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  /* Make request detail close button tappable */
  #requestDetailPanel.mobile-open > div:first-child button {
    min-width: 44px; min-height: 44px; padding: 12px; margin: -12px;
  }

  /* Requests list panel — full width on mobile when detail is closed */
  #requestsListPanel { width: 100% !important; border-right: none !important; }
  /* Same reason .comm-empty is hidden on mobile: there's no second pane for a
     "Select a request" placeholder to sit in, so it just squeezed off the edge. */
  #requestsEmptyDetail { display: none !important; }
}

@media (max-width: 480px) {
  /* Smaller photo grid on tiny screens */
  .photos-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
  .photos-grid-wrap { padding: 10px 10px 20px; }

  /* Compact pipeline cards */
  .pipeline-count { font-size: 26px; }
  .pipeline-card { padding: 14px 14px; }
  .page-body { padding: 12px 12px 24px; }

  /* Compact modals */
  .modal-body { padding: 16px; gap: 12px; }
  .modal-header { padding: 16px 16px 12px; }
  .modal-footer { padding: 10px 16px; }
  .form-row { flex-direction: column; gap: 10px; }
}

/* Platform admin "Log in as" banner — shown whenever margin_token holds an
   impersonation token (see exitImpersonation() in app.js). */
#impersonationBanner {
  position: fixed; top: 0; left: 0; right: 0; z-index: 9999;
  background: var(--ink-fixed); color: var(--yellow);
  padding: 8px 16px; font-size: 13px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; gap: 12px;
}
#impersonationBanner button {
  background: var(--yellow); color: var(--ink-fixed); border: none; border-radius: 6px;
  padding: 4px 12px; font-size: 12px; font-weight: 700; cursor: pointer; font-family: inherit;
}
body.impersonating .sidebar { top: 36px; height: calc(100vh - 36px); }
body.impersonating .main { margin-top: 36px; min-height: calc(100vh - 36px); }
/* Stack, don't occlude: when both banners are visible (impersonating + offline),
   shift the offline banner down by the impersonation banner's own height instead
   of letting the higher z-index one fully hide it. See #offlineBanner below.
   36px is only correct on desktop, where #impersonationBanner has no
   safe-area-inset padding and never wraps — on a notched/Dynamic-Island phone
   its real height is commonly 70-95px+. ImpersonationBanner.svelte measures
   the actual rendered height with a ResizeObserver and writes it to
   --impersonation-banner-height; 36px here is only the fallback for the brief
   instant before that observer fires on mount. */
body.impersonating #offlineBanner { top: var(--impersonation-banner-height, 36px); }

/* Read-only offline notice (Jobs/Properties served from service-worker cache —
   see client/src/lib/stores/offline.svelte.js). Deliberately not the same
   stark ink/yellow combination as #impersonationBanner above: that one is a
   cross-tenant severity warning, this is a routine "saved data" notice. Sits
   one z-index below the impersonation banner so that one renders on top of
   the other when both are visible at once (an impersonating platform admin
   viewing a company's Jobs/Properties while offline) — and the
   `body.impersonating #offlineBanner` rule above shifts this one down by the
   impersonation banner's real measured height so it stacks below rather than
   being fully hidden underneath.
   --border/--text are the closest real
   tokens to the brief's suggested --border/--ink — --ink alone isn't defined
   in :root (only --ink-fixed/--ink-fixed-text are), so --text (the default
   body text color token) stands in for it. */
#offlineBanner {
  position: fixed; top: 0; left: 0; right: 0; z-index: 9998;
  background: var(--border); color: var(--text);
  padding: 8px 16px; padding-top: calc(8px + env(safe-area-inset-top, 0px));
  font-size: 13px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
}

/* Express Lane — dashboard hero + guided visit overlay */
.express-lane-hero {
  width: 100%; display: flex; align-items: center; gap: 14px;
  background: var(--ink-fixed); color: var(--ink-fixed-text); border: none; border-radius: var(--radius);
  padding: 16px 20px; margin-bottom: 20px; cursor: pointer; font-family: inherit; text-align: left;
  box-shadow: var(--card-shadow); transition: var(--press);
}
.express-lane-hero-icon { font-size: 26px; flex-shrink: 0; }
.express-lane-hero-text { display: flex; flex-direction: column; gap: 2px; }
.express-lane-hero-title { font-size: 15px; font-weight: 700; color: var(--yellow); text-wrap: balance; }
.express-lane-hero-sub { font-size: 12px; color: rgba(255,255,255,0.65); text-wrap: pretty; }

.express-lane-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 900;
  display: flex; align-items: center; justify-content: center; padding: 16px;
}
.express-lane-panel {
  background: var(--white); border-radius: 14px; width: 100%; max-width: 480px;
  max-height: 90vh; max-height: 90dvh; display: flex; flex-direction: column; overflow: hidden;
  box-shadow: var(--overlay-shadow);
  animation: modal-in 0.22s cubic-bezier(0.2, 0, 0, 1);
}
.express-lane-topbar {
  padding: 14px 16px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; flex-shrink: 0;
}
.express-lane-topbar-title { font-size: 15px; font-weight: 700; }
.express-lane-close { position: relative; background: none; border: none; font-size: 20px; cursor: pointer; color: var(--text-muted); line-height: 1; padding: 4px; transition: color 0.15s, var(--press); }
.express-lane-step { padding: 18px 20px 20px; overflow-y: auto; }

.express-lane-choice-row { display: flex; gap: 10px; margin-bottom: 16px; }
.express-lane-choice-btn {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px;
  background: var(--bg); border: 1.5px solid var(--border); border-radius: var(--radius);
  padding: 16px 8px; cursor: pointer; font-family: inherit; font-size: 12px; font-weight: 600; color: var(--text);
  transition: border-color 0.15s, box-shadow 0.15s;
}
.express-lane-choice-btn:hover { border-color: var(--black); box-shadow: var(--card-shadow); }
.express-lane-choice-icon { font-size: 24px; }

.express-lane-subheading { font-size: 12px; font-weight: 700; color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 6px; }

.express-lane-result-list { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; max-height: 40vh; max-height: 40dvh; overflow-y: auto; }
.express-lane-result-item {
  display: flex; flex-direction: column; gap: 2px; text-align: left;
  background: var(--white); border: 1.5px solid var(--border); border-radius: 8px;
  padding: 10px 12px; cursor: pointer; font-family: inherit; transition: border-color 0.15s;
}
.express-lane-result-item:hover { border-color: var(--black); }
.express-lane-result-title { font-size: 13px; font-weight: 700; color: var(--text); }
.express-lane-result-sub { font-size: 11.5px; color: var(--text-subtle); }

.express-lane-checklist-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; gap: 10px; }
.express-lane-property-label { font-size: 13px; font-weight: 700; color: var(--text); }
.express-lane-edit-checklist { background: none; border: none; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; font-family: inherit; white-space: nowrap; }

.express-lane-checklist-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.express-lane-checklist-row {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  background: var(--bg); border: 1.5px solid var(--border); border-radius: var(--radius);
  padding: 14px 16px; cursor: pointer; font-family: inherit; transition: border-color 0.15s;
}
.express-lane-checklist-row:hover { border-color: var(--black); }
.express-lane-checklist-label { font-size: 13.5px; font-weight: 600; color: var(--text); }
.express-lane-checklist-badge { font-size: 15px; color: var(--text-subtle); }
.express-lane-checklist-badge.captured { font-size: 12px; font-weight: 700; color: var(--green); }

.express-lane-other-row {
  width: 100%; background: none; border: 1.5px dashed var(--border); border-radius: var(--radius);
  padding: 12px 16px; cursor: pointer; font-family: inherit; font-size: 13px; font-weight: 600;
  color: var(--text-muted); margin-bottom: 16px; transition: border-color 0.15s;
}
.express-lane-other-row:hover { border-color: var(--black); color: var(--text); }
.express-lane-finish-btn { width: 100%; }

@media (max-width: 560px) {
  .express-lane-overlay { padding: 0; align-items: flex-end; }
  .express-lane-panel { max-height: 100vh; max-height: 100dvh; border-radius: 0; }
}

/* ===== PHOTO PROCESSING OVERLAY =====
   See client/src/lib/components/PhotoProcessingOverlay.svelte for why this exists. Reuses
   modal-overlay-in for the entrance so it matches every other overlay's timing/easing in
   this app; matches everything else here in having no exit animation either (Modal.svelte's
   own overlay doesn't have one — closing removes the node immediately). */
.photo-processing-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 1000;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  animation: modal-overlay-in 0.16s cubic-bezier(0.2, 0, 0, 1);
}
.photo-processing-panel {
  background: var(--white); border-radius: 14px; padding: 18px 28px;
  font-size: 14px; font-weight: 700; color: var(--black);
  box-shadow: var(--overlay-shadow);
}

/* ===== PHOTO LIGHTBOX =====
   The meta panel (title + description + tags + job select + Save) sits under the
   image. With the image at 68vh and the panel centred, the panel's Save button fell
   off the bottom of a phone screen with nothing scrollable to reach it. The overlay
   now scrolls, and the image yields height on short/narrow screens so the panel has
   somewhere to go. */
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,0.97); z-index: 1000; align-items: center; justify-content: flex-start; flex-direction: column; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 56px 16px calc(24px + env(safe-area-inset-bottom, 0px)); }
.lightbox-img { max-width: 100%; max-height: 68vh; max-height: 68dvh; object-fit: contain; border-radius: 6px; flex-shrink: 0; }
.lightbox-close { position: fixed; top: calc(12px + env(safe-area-inset-top, 0px)); right: 16px; z-index: 2; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,0.12); border: none; border-radius: 50%; color: #fff; font-size: 20px; cursor: pointer; line-height: 1; }
.lightbox-close:hover { background: rgba(255,255,255,0.22); }
.lightbox-meta { width: min(100%, 420px); margin-top: 12px; flex-shrink: 0; }
@media (max-width: 900px) {
  /* Leave room for the meta panel instead of pushing it off-screen. */
  .lightbox-img { max-height: 46vh; max-height: 46dvh; }
  .lightbox-meta input, .lightbox-meta textarea, .lightbox-meta select { font-size: 16px !important; }
  .lightbox-meta button { min-height: 44px; }
}

/* ===== TABULAR NUMBERS =====
   Any figure that re-renders with new data needs fixed-width digits, or the
   glyphs change width under it and the whole row jitters. Proportional numerals
   are only correct for numbers that never change — of which this app has none. */
.pipeline-count, .pipeline-value, .stat-value, .stat-change, .stat-row-value,
.stat-pill-value, .job-value, .job-history-value, .job-history-date,
.client-job-count, .nav-badge, .notif-badge, .tab-count, .list-job-time,
.week-day-num, .tc-row-hours, .margin-bar-value, .job-cost-gauge-label,
.report-card-value, .report-stat-row, .report-stat-row strong,
.profit-row-figure, .invoice-row-amount, .invoice-row-due, .invoice-total-row,
.invoice-total-bold, .invoice-balance, .inv-item-total,
.trend-table td, .trend-tooltip, .invoice-items-table td {
  font-variant-numeric: tabular-nums;
}

/* ===== TEXT WRAPPING =====
   `balance` evens out the lines of a short heading; `pretty` keeps a lone
   orphan word off the last line of body copy. Deliberately not applied to
   anything with `white-space: nowrap` + ellipsis (job/client/property titles) —
   those never wrap, so it would be a no-op. */
.coming-soon h2, .settings-section-title, .report-section-title,
.detail-job-title, .detail-name, .prop-form-card-title, .danger-zone-title,
.notif-popup-header, .express-lane-topbar-title, .modal-section-label {
  text-wrap: balance;
}
.coming-soon p, .settings-section-desc, .settings-row-label-sub,
.prop-photo-card-desc, .notif-item-title, .notif-item-sub, .integration-desc,
.danger-zone-desc, .toast-title, .toast-sub, .perm-check .perm-desc,
.detail-field-value, .action-sub, .empty-state-text {
  text-wrap: pretty;
}

/* ===== IMAGE OUTLINES =====
   A 1px hairline gives a photo a consistent edge against any surface. It must be
   pure black (light) / pure white (dark) — `--border` is a tinted neutral, and
   in dark mode (#2E3036) it picks up the surface colour and reads as grime along
   the image edge. `outline-offset: -1px` draws it inside the box, so it follows
   `border-radius` and costs no layout. */
.photo-grid-img, .prop-photo-card-img, .prop-form-photo-thumb,
.photo-review-thumb, .job-photo-thumb, .mobile-topbar > img {
  outline: 1px solid var(--img-outline);
  outline-offset: -1px;
}

/* ===== HIT AREAS =====
   These controls are drawn smaller than the 40px dense-desktop minimum. Rather
   than inflating them (and breaking the 36px control rhythm), a centred
   pseudo-element extends the *target* to 40px while the painted box stays put.
   Every element below sits >=8px clear of its nearest neighbour, so no two
   targets overlap — check that before adding to this list. */
.icon-btn::after, .modal-close::after, .photo-grid-delete::after,
.inv-item-remove::after, .express-lane-close::after,
.date-nav-btn::after, .today-btn::after, .invoice-add-item-btn::after,
.prop-door-checkbox::after, .section-link::after,
.toggle::before { /* ::after on .toggle is already the knob */
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: max(100%, 40px);
  height: max(100%, 40px);
}

/* ===== SCALE ON PRESS =====
   0.96 — enough to register as a press, not so much it reads as a bounce.
   Skipped on :disabled, which shouldn't respond to a click at all. */
.btn-primary:active:not(:disabled), .btn-secondary:active:not(:disabled),
.icon-btn:active:not(:disabled), .btn-danger:active:not(:disabled),
.quick-btn:active:not(:disabled), .detail-action-btn:active:not(:disabled),
.modal-close:active, .view-btn:active, .today-btn:active, .date-nav-btn:active,
.filter-btn:active, .req-filter-btn:active, .prop-photo-card-btn:active,
.theme-option:active, .inv-item-remove:active, .express-lane-close:active,
.express-lane-hero:active {
  transform: scale(0.96);
}

@media (max-width: 900px) {
  /* Touch wants 44px, not 40px. */
  /* .photo-grid-delete is deliberately excluded: it sits at opacity 0 until the
     card is hovered, so on touch it's an invisible destructive target. Growing
     it here would just make it easier to delete a photo by accident. */
  .icon-btn::after, .modal-close::after, .inv-item-remove::after,
  .express-lane-close::after, .date-nav-btn::after, .today-btn::after,
  .invoice-add-item-btn::after, .prop-door-checkbox::after, .section-link::after,
  .toggle::before {
    width: max(100%, 44px);
    height: max(100%, 44px);
  }
  /* AddressAutocomplete's suggestion rows (10px/14px padding, 13px font) land under
     44px without this — no ::after expander here since these are full-width list
     rows, not icon-sized controls, so grow the box itself via min-height instead. */
  .address-autocomplete-item { min-height: 44px; display: flex; align-items: center; }
  /* PropertyPicker's trigger and list/quick-create rows are the same full-width-row
     shape as AddressAutocomplete's suggestions above — same fix, same reason. */
  .property-picker-trigger { min-height: 44px; display: flex; align-items: center; }
  .property-picker-item, .property-picker-newbtn { min-height: 44px; display: flex; align-items: center; }
  .filter-btn, .detail-action-btn, .theme-option, .prop-photo-card-btn,
  /* 44px, not 40px, for the ordinary action buttons and the report/request filter pills —
     these don't get the ::after expander and were landing at 40px. Enforced by
     test/e2e/mobile-invariants (touch targets). min-height only, so labels/padding are
     unchanged; desktop is unaffected (this is inside the 900px media query). */
  .btn-primary, .btn-secondary, .req-filter-btn, .trend-table-toggle, .view-btn { min-height: 44px; }
}

/* ===== FOCUS STATES =====
   Every input in this file sets `outline: none` and replaces it with nothing but
   a 1.5px border-colour shift; buttons had no focus style at all, so keyboard
   users had no idea where they were across ~225 controls. This block restores a
   real ring. It must stay LAST in the file: it has the same (0,1,0) specificity
   as `.form-input`, so source order is what lets it beat that `outline: none`.

   `:focus-visible` (not `:focus`) means the ring appears for keyboard/AT users
   and stays out of the way on mouse click. */
*:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
/* The sidebar is near-black, where the light-mode ring goes muddy. */
.sidebar *:focus-visible { outline-color: #42A5F5; }
/* Inputs sit flush in their rows — an offset ring would collide with the
   neighbouring field, so draw it tight against the border instead. */
.form-input:focus-visible, .form-select:focus-visible, .form-textarea:focus-visible,
.search-input:focus-visible, .settings-input:focus-visible, .notes-area:focus-visible,
.tag-picker-input:focus-visible, #photoSearchInput:focus-visible {
  outline-offset: 0;
}

/* Honour a reduced-motion preference: keep the state changes, drop the movement. */
@media (prefers-reduced-motion: reduce) {
  .modal, .modal-overlay, .photo-review-modal, .express-lane-panel, .toast { animation: none; }
  .btn-primary:active, .btn-secondary:active, .icon-btn:active, .btn-danger:active,
  .quick-btn:active, .detail-action-btn:active, .modal-close:active, .view-btn:active,
  .today-btn:active, .date-nav-btn:active, .filter-btn:active, .req-filter-btn:active,
  .prop-photo-card-btn:active, .theme-option:active, .inv-item-remove:active,
  .express-lane-close:active, .express-lane-hero:active { transform: none; }
}
