:root {
  --active-item: #1E40AF;
  --sidebar-bg: #0F172A;
  --sidebar-text: #94A3B8;
  --sidebar-text-active: #ffffff;
  --bg: #0F172A;
  --card-bg: #1E293B;
  --card-border: #334155;
  --text: #E2E8F0;
  --text-muted: #94A3B8;
  /* Semantic colors ported exactly from JavaScript.html's APP_COLORS (the
     legacy app's single source of truth for dynamically-assigned status
     colors) plus each color's class-based dark-mode swap from Styles.html
     (.u-success/.u-danger/.u-c-d97706 etc). Previously these three were
     flat, invented hex values (#22C55E/#F59E0B/#EF4444) that matched
     nothing in legacy and never swapped for dark mode. */
  --success: #34D399;
  --warning: #FBBF24;
  --danger: #F87171;
  /* Styles.html .u-faint - the inverse pair of --text-muted (u-muted):
     faint is the *lighter* gray in light mode but the *darker* gray in
     dark mode, unlike every other swapping color in this file. */
  --text-faint: #64748B;
  /* Styles.html .u-label-text */
  --label-text: #CBD5E1;
  --bullet-track: #334155;
  /* Accent-on-text/fill/stroke color pair (Styles.html: .u-c-1e40af,
     .sparkline-dot, .market-tab-active, .mortgage-trend-line-30, etc.) -
     legacy swaps #1E40AF (light) for the lighter #60A5FA in dark mode
     specifically for contrast (the darker navy reads poorly as text/a
     thin line against a dark background, unlike as a solid button fill,
     which is why --active-item itself does NOT swap). Every one of these
     elements had been wired to --active-item directly, so it never got
     the swap and stayed the low-contrast light-mode navy in dark mode. */
  --accent-text: #60A5FA;
  /* "Soft box" secondary card tint (Styles.html: .u-soft-box) - a
     distinct third tier from --bg (page) and --card-bg (primary card),
     used for nested cards like the market metric mini-cards and the
     Market Insight callout. Was wired to --bg directly, which made these
     blend flat into the page instead of reading as a separate card. */
  --soft-bg: #243044;
  --soft-border: #334155;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #F8FAFC;
    --card-bg: #ffffff;
    --card-border: #E5E7EB;
    --text: #0F172A;
    --text-muted: #64748B;
    --bullet-track: #E2E8F0;
    --accent-text: #1E40AF;
    --soft-bg: #F8FAFC;
    --soft-border: #E5E7EB;
    --success: #059669;
    --warning: #D97706;
    --danger: #DC2626;
    --text-faint: #94A3B8;
    --label-text: #475569;
  }
}

/* Manual dark-mode override (task #83) - wins over the OS-preference media
   queries above via attribute-selector specificity (0,2,0 vs 0,1,0), not
   source order, so it holds regardless of which one is declared first or
   what the OS actually prefers. Set on <html> by applyTheme()/toggleDarkMode()
   in app.js once Kenny has an explicit dark_mode setting saved - absence of
   the attribute (no manual choice made yet) leaves the two @media blocks
   above as the only signal, i.e. OS preference is still the default. Values
   are the exact same pair already defined above, just made attribute-
   addressable instead of purely media-query-addressable. */
:root[data-theme="dark"] {
  --bg: #0F172A;
  --card-bg: #1E293B;
  --card-border: #334155;
  --text: #E2E8F0;
  --text-muted: #94A3B8;
  --success: #34D399;
  --warning: #FBBF24;
  --danger: #F87171;
  --text-faint: #64748B;
  --label-text: #CBD5E1;
  --bullet-track: #334155;
  --accent-text: #60A5FA;
  --soft-bg: #243044;
  --soft-border: #334155;
}
:root[data-theme="light"] {
  --bg: #F8FAFC;
  --card-bg: #ffffff;
  --card-border: #E5E7EB;
  --text: #0F172A;
  --text-muted: #64748B;
  --bullet-track: #E2E8F0;
  --accent-text: #1E40AF;
  --soft-bg: #F8FAFC;
  --soft-border: #E5E7EB;
  --success: #059669;
  --warning: #D97706;
  --danger: #DC2626;
  --text-faint: #94A3B8;
  --label-text: #475569;
}

/* Component-specific rules below use literal hex/rgba values instead of
   the CSS variables above (drag-shadow intensity, badge tints, toggle-pill
   fills) and each already has its own scattered @media(prefers-color-
   scheme:dark) block elsewhere in this file. Those media blocks only
   respond to the OS setting, not the manual data-theme attribute - mirrored
   here so every one of them also respects a manual override. Kept as one
   consolidated block (rather than editing each occurrence in place) so the
   full set added for the manual toggle is visible together. */
:root[data-theme="dark"] .drag-handle { background: rgba(255, 255, 255, 0.08); }
:root[data-theme="light"] .drag-handle { background: rgba(15, 23, 42, 0.05); }
:root[data-theme="dark"] .dashboard-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
:root[data-theme="light"] .dashboard-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18); }
:root[data-theme="dark"] .settings-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
:root[data-theme="light"] .settings-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18); }
:root[data-theme="dark"] .training-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
:root[data-theme="light"] .training-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18); }
:root[data-theme="dark"] .toggle-onoff.toggle-onoff-accent.toggle-onoff-active { background: #3B82F6; }
:root[data-theme="light"] .toggle-onoff.toggle-onoff-accent.toggle-onoff-active { background: #1E40AF; }
:root[data-theme="dark"] .badge.live { background: #1e3a5f; color: #93C5FD; }
:root[data-theme="light"] .badge.live { background: #E0E7FF; color: #4338CA; }
:root[data-theme="dark"] .badge.escrow { background: #3b2a00; color: #FCD34D; }
:root[data-theme="light"] .badge.escrow { background: #FEF3C7; color: #92400E; }
:root[data-theme="dark"] .badge.month { background: #14290f; color: #86EFAC; }
:root[data-theme="light"] .badge.month { background: #DCFCE7; color: #166534; }
:root[data-theme="dark"] .u-bg-fef3c7 { background: #451A03; }
:root[data-theme="light"] .u-bg-fef3c7 { background: #FEF3C7; }
:root[data-theme="dark"] .u-c-92400e { color: #FCD34D; }
:root[data-theme="light"] .u-c-92400e { color: #92400E; }
:root[data-theme="dark"] .warning-banner { color: #FCD34D; background: #451A03; border-color: #92400E; }
:root[data-theme="light"] .warning-banner { color: #B45309; background: #FFFBEB; border-color: #FDE68A; }
:root[data-theme="dark"] .toggle-pill { background: #334155; color: #94A3B8; }
:root[data-theme="light"] .toggle-pill { background: #E5E7EB; color: #6B7280; }
:root[data-theme="dark"] .toggle-pill.active { background: #1E3A5F; color: #60A5FA; }
:root[data-theme="light"] .toggle-pill.active { background: #DBEAFE; color: #1E40AF; }
:root[data-theme="dark"] .contact-row-summary.is-expanded { background: #1e3a5f; }
:root[data-theme="light"] .contact-row-summary.is-expanded { background: #EFF6FF; }

/* No global box-sizing reset - Styles.html has none either (relies on
   the browser's content-box default everywhere, applying border-box only
   to specific elements that need it: .brand, a couple of overflow-fix
   containers, and its own mobile card overrides). Matching that exactly:
   border-box is added explicitly below on every element here that
   combines an explicit width with padding/border, instead of applying it
   universally. */

/* Base button - most buttons in this app are plain <button> tags with no
   class. Scoped rules (.row-actions button, .reorder-btns button, etc.)
   and explicit classes (.btn-secondary, .btn-danger) are more specific
   and win over this by CSS specificity, so this only fills in buttons
   that would otherwise fall back to the unstyled browser default (plain
   white/gray, breaking dark mode) - see MISTAKE_LOG.md #15. */
button {
  background: var(--active-item);
  color: #fff;
  border: none;
  border-radius: 6px;
  padding: 8px 16px;
  font-size: 14px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}
button:hover { opacity: 0.9; }
button:disabled { opacity: 0.4; cursor: not-allowed; }
/* Matches Styles.html .u-btn-outline exactly: solid card-tint fill (not
   transparent), label-text color (not full-strength text), card-border. */
.btn-secondary, button[data-action="cancel-delete"] {
  background: var(--card-bg);
  color: var(--label-text);
  border: 1px solid var(--card-border);
  font-weight: 500;
}
/* Matches Styles.html .u-btn-danger exactly: solid red fill, white text,
   no border - a real destructive-action button, not an outline. Doesn't
   swap for dark mode (legacy's u-btn-danger has no body.dark-mode
   override), so this uses the literal hex rather than var(--danger),
   which does swap for the text-color use case elsewhere in this file. */
.btn-danger { background: #DC2626; color: #fff; border: none; font-weight: 500; }

body {
  margin: 0;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
}

.material-icons-round { font-size: 18px; line-height: 1; user-select: none; }

#app { display: flex; min-height: 100vh; }

.sidebar {
  width: 260px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  padding: 10px 0 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  transition: width 0.2s;
}

/* Manual sidebar collapse (Index.html toggleSidebar/#toggle-icon,
   Styles.html:23-26,49-50) - same icon-only treatment already used at
   the mobile breakpoint (:974-978 below), just user-toggled at any width
   instead of forced by viewport. Group items always show flat when
   collapsed (group headers hide, so there's nothing to expand/collapse
   into) - matches legacy's .sidebar.collapsed .nav-group-body{display:
   flex!important} exactly. */
.sidebar.collapsed { width: 70px; }
.sidebar.collapsed .sidebar-brand-text { display: none; }
.sidebar.collapsed .nav-group-label { display: none; }
.sidebar.collapsed .nav-item { justify-content: center; padding: 15px 10px; gap: 0; display: flex !important; }
.sidebar.collapsed .nav-item .menu-text { display: none; }

/* applyNavGroups() in app.js toggles this class (not an inline style -
   see that function's comment) on a nav-item whose group is currently
   collapsed. Icon-only mode (manual collapse above, or the mobile
   breakpoint below) has no group header left to expand/collapse into, so
   both force every item back to visible regardless of its group's state. */
.nav-item-group-hidden { display: none; }
.sidebar.collapsed .nav-item-group-hidden { display: flex !important; }

.sidebar-brand {
  color: #fff;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.02em;
  padding: 20px;
  height: 60px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
}

.sidebar-brand-icon {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  flex-shrink: 0;
}

/* 2026-08-06, per Kenny: dark-mode + collapse toggles need to stay
   reachable even when .sidebar-brand hides (mobile/narrow viewports) -
   deliberately a separate element from .sidebar-brand, not just moved
   inside it and exempted, so nothing here can accidentally get caught by
   a future ".sidebar-brand *" style rule. */
.sidebar-toolbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 6px 0;
}

.nav-group-label {
  color: #64748B;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 12px 20px 8px;
  /* 2026-08-06: moved here from applyNavGroups()'s per-element inline
     style - an inline style="display:flex" beats any external stylesheet
     rule regardless of specificity, so .sidebar.collapsed .nav-group-label
     {display:none} above could never actually hide these once JS had set
     them. Kenny: "when the sidebar collapses all text should go away
     including the group headers." */
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 15px;
  background: transparent;
  color: var(--sidebar-text);
  border: none;
  border-radius: 6px;
  padding: 15px 20px;
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  width: 100%;
  box-sizing: border-box;
}

.nav-item.active {
  background: var(--active-item);
  color: var(--sidebar-text-active);
  border-left: 4px solid #60A5FA;
}

.content {
  flex: 1;
  min-width: 0;
  padding: 32px;
}

/* Legacy's page heading (<h1 id="current-view-title">) has no font-size
   override at all in Styles.html - it renders at the browser's plain
   default h1 size (2em = 32px at the default 16px root), not a custom
   value. Matching that explicitly here since this class always applies
   (unlike legacy's unclassed h1), rather than leaving my own guessed 28px. */
.page-title {
  font-size: 32px;
  font-weight: 700;
  margin: 0 0 24px;
}

.metric-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-bottom: 20px;
}

.metric-card, .card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 20px;
  min-width: 0;
}

.card { padding: 24px; margin-bottom: 20px; }

/* Two-column grid layout system for the Dashboard's customizable widget
   section (Styles.html: .two-col-grid/.col-span-full, ported exactly).
   Cards inside become equal-width columns; .col-span-full spans both. */
.two-col-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
.two-col-grid .card { margin-bottom: 0; }
#dashboard-widgets-container { margin-top: 4px; }
.col-span-full { grid-column: 1 / -1; }

/* Dashboard widget cards - drag handle (top-left) + refresh (top-right)
   header row, matching the legacy card chrome exactly. */
.dashboard-widget-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}
.dashboard-widget-header-left { display: flex; align-items: center; gap: 12px; }
.drag-handle {
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  cursor: grab;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  font-size: 18px;
  border-radius: 8px;
  background: rgba(15, 23, 42, 0.05);
  color: var(--text-muted);
  flex-shrink: 0;
}
.drag-handle:active { cursor: grabbing; }
@media (prefers-color-scheme: dark) {
  .drag-handle { background: rgba(255, 255, 255, 0.08); }
}
.widget-refresh-btn { background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 4px; display: flex; }
/* Styles.html .dashboard-widget.is-dragging - a scale+shadow "lift" effect,
   not a plain opacity fade. */
.dashboard-widget.is-dragging {
  touch-action: none;
  transform: scale(1.02);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  z-index: 10;
  position: relative;
}
@media (prefers-color-scheme: dark) {
  .dashboard-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
}
body.dashboard-drag-active { cursor: grabbing; }
body.dashboard-drag-active,
body.dashboard-drag-active * {
  -webkit-user-select: none !important;
  user-select: none !important;
  -webkit-touch-callout: none !important;
}

/* Settings tab drag-and-drop (Styles.html) - same drag-handle/lift
   treatment as Dashboard, scoped to .settings-widget/body.settings-drag-
   active so the two systems stay independent. Each card's handle is
   absolutely positioned top-right (padding-top:50px reserves room) since
   Settings cards have too many different header shapes to restructure
   uniformly. */
.settings-widget { position: relative; padding-top: 50px; }
.settings-widget .drag-handle { position: absolute; top: 10px; right: 14px; }
.settings-widget.is-dragging {
  touch-action: none;
  transform: scale(1.01);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  z-index: 10;
}
@media (prefers-color-scheme: dark) {
  .settings-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
}
body.settings-drag-active,
body.settings-drag-active * {
  -webkit-user-select: none !important;
  user-select: none !important;
  -webkit-touch-callout: none !important;
}

/* Training tab drag-and-drop (JavaScript.html attachScheduleDragListeners_)
   - same drag-handle/lift treatment as Settings above, including the
   absolute-positioned handle (Training's cards have as many different
   header shapes as Settings' do, so no uniform flex-header restructure). */
.training-widget { position: relative; padding-top: 50px; }
.training-widget .drag-handle { position: absolute; top: 10px; right: 14px; }
.training-widget.is-dragging {
  touch-action: none;
  transform: scale(1.01);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  z-index: 10;
}
@media (prefers-color-scheme: dark) {
  .training-widget.is-dragging { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); }
}
body.training-drag-active,
body.training-drag-active * {
  -webkit-user-select: none !important;
  user-select: none !important;
  -webkit-touch-callout: none !important;
}

/* Customize Your Dashboard panel + per-widget Pin/Visible toggle pills */
.widget-toggle-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 8px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--bg);
  border: 1px solid var(--card-border);
}
.toggle-onoff {
  min-width: 80px;
  padding: 6px 12px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  background: var(--card-border);
  color: var(--text);
}
/* Styles.html .toggle-onoff-active: solid #059669, does not swap for dark
   mode (body.dark-mode .toggle-onoff-active still says #059669 !important)
   - literal hex rather than var(--success), which does swap. */
.toggle-onoff.toggle-onoff-active { background: #059669; color: #fff; }
.toggle-onoff.toggle-onoff-accent.toggle-onoff-active { background: var(--active-item); }
@media (prefers-color-scheme: dark) {
  /* Styles.html: this one accent variant DOES get a distinct (brighter)
     dark-mode value, #3B82F6, unlike the plain accent toggle elsewhere
     which stays the fixed #1E40AF in both modes. */
  .toggle-onoff.toggle-onoff-accent.toggle-onoff-active { background: #3B82F6; }
}

.card-title {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 15px;
}

/* Dashboard card titles that link out to the corresponding app/OS page
   (2026-08-06, Kenny) - reads like a plain title, gets an underline only
   on hover so it doesn't look like a generic link everywhere else does. */
.card-title-link {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}
.card-title-link:hover {
  text-decoration: underline;
}

/* Styles.html .action-grid/.action-card (Quick Launch Actions, Vendor
   library folders). Color/decoration set explicitly here rather than left
   to inheritance - several widgets wrap this in an <a>, whose UA-default
   link color otherwise wins over whatever the card happened to inherit,
   which is exactly how the Calendar/ClickUp/Unread-Emails title color bug
   happened. One rule, applies everywhere .action-card is used. */
.action-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; margin-top: 15px; }
.action-card { border: 1px solid var(--card-border); padding: 20px; border-radius: 8px; cursor: pointer; transition: 0.2s; color: var(--text); text-decoration: none; }
.action-card:hover { border-color: var(--active-item); background: var(--soft-bg); }
.action-card h3 { margin: 10px 0 5px; font-size: 14px; color: var(--text); }
.action-card p { font-size: 12px; color: var(--text-muted); margin: 0; }

.section-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  margin: 20px 0 8px;
}

.metric-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
  flex-wrap: wrap;
  gap: 6px;
}

.metric-icon { color: var(--text-muted); }

.badge {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 4px 10px;
  border-radius: 12px;
  text-transform: uppercase;
}
.badge-blue { background: rgba(59, 130, 246, 0.15); color: #60A5FA; }
.badge-amber { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.badge-green { background: rgba(34, 197, 94, 0.15); color: #4ADE80; }

/* Styles.html .live/.escrow/.month - the top metric row's real badge
   classes (Dashboard's Active Clients/Under Contract cards, Contacts'
   Total/By Type/Stages cards), found in Views.html/JavaScript.html's
   METRIC_CARD_POOL. Distinct palette from the badge-blue/amber/green
   invented above - not interchangeable with them. */
.badge.live { background: #E0E7FF; color: #4338CA; }
.badge.escrow { background: #FEF3C7; color: #92400E; }
.badge.month { background: #DCFCE7; color: #166534; }
@media (prefers-color-scheme: dark) {
  .badge.live { background: #1e3a5f; color: #93C5FD; }
  .badge.escrow { background: #3b2a00; color: #FCD34D; }
  .badge.month { background: #14290f; color: #86EFAC; }
}
.u-bg-fef3c7 { background: #FEF3C7; }
.u-c-92400e { color: #92400E; }
@media (prefers-color-scheme: dark) {
  .u-bg-fef3c7 { background: #451A03; }
  .u-c-92400e { color: #FCD34D; }
}

/* Status text (Webinars/Open Houses Scheduled-Completed-Cancelled,
   webinar roster Attended/No-Show) - JavaScript.html renders these as
   plain colored uppercase text (statusColors/WEBINAR_ROSTER_STATUS_COLORS_
   keyed off APP_COLORS), never as a background-filled badge chip. Color is
   set inline per status by the caller (e.g. style="color:var(--active-item)"). */
.status-text { font-size: 11px; font-weight: 700; text-transform: uppercase; }

/* Solid mini-tag (Mileage "ROUND TRIP" label) - Styles.html's actual
   markup for this is class="u-bg-1e40af u-c-fff" with an inline
   font-size:10px/font-weight:700/padding/border-radius:4px - a small
   solid-fill rectangular tag, not a rounded .badge pill. */
.tag-solid { background: var(--active-item); color: #fff; font-size: 10px; font-weight: 700; border-radius: 4px; }

/* Webinar/Open House status badge (Scheduled/Completed/Cancelled) -
   2026-08-05, per Kenny: needs a real pill background (was color-only
   text) and the font must be CSS-driven, not set inline per instance.
   Only the background color is parameterized per status, via the
   --badge-color custom property - everything else lives here once. */
.event-status-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #fff;
  background: var(--badge-color, var(--text-muted));
  padding: 3px 10px;
  border-radius: 12px;
}

/* Legacy's actual .u-warn-box values (Styles.html:705 light, :706 dark) -
   not invented, ported exactly per STYLE_GUIDE.md. */
.warning-banner {
  color: #B45309;
  background: #FFFBEB;
  border: 1px solid #FDE68A;
  border-radius: 6px;
  font-size: 13px;
  padding: 10px 12px;
  margin-bottom: 14px;
}
@media (prefers-color-scheme: dark) {
  .warning-banner { color: #FCD34D; background: #451A03; border-color: #92400E; }
}

.metric-number { font-size: 24px; font-weight: 700; line-height: 1.1; }
.metric-number-sm { font-size: 15px; font-weight: 600; line-height: 1.4; }
.metric-label { color: var(--text-muted); font-size: 14px; margin-top: 5px; }

.pipeline-row { display: flex; justify-content: space-between; padding: 4px 0; font-size: 14px; }
.pipeline-row .count { color: var(--text-muted); }

ul { list-style: none; margin: 0; padding: 0; }
ul li { font-size: 14px; padding: 4px 0; display: flex; justify-content: space-between; }
ul li .days-out { color: var(--text-muted); }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--card-border); font-size: 14px; }
th { color: var(--text-muted); font-weight: 600; }

/* Styles.html .tier-badge exactly: small uppercase pill, not the larger
   999px-radius/12px-font/600-weight chip previously invented here. */
.tier-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.3px;
  text-transform: uppercase;
  vertical-align: middle;
  margin-left: 8px;
}
.tier-badge-customer { background: var(--card-border); color: var(--label-text); }
.tier-badge-client { background: var(--active-item); color: #fff; }
/* 2026-08-06, per Kenny: Client/Customer got pill badges, Lead/SOI didn't -
   inconsistent across the OS. Legacy itself never had these two (grepped
   Styles.html - only tier-badge-customer/-client ever existed), so this is
   a deliberate improvement beyond legacy, not a ported value. Same rgba-alpha
   pattern as .badge-blue/.badge-amber/.badge-green above, not the
   solid-background customer/client pair, since those two colors are
   already reserved for the Client/Customer tiers specifically. */
.tier-badge-lead { background: rgba(245, 158, 11, 0.15); color: #FBBF24; }
.tier-badge-soi { background: rgba(139, 92, 246, 0.15); color: #A78BFA; }

#signin-container { display: flex; justify-content: center; align-items: center; min-height: 100vh; }
.hidden { display: none !important; }
.muted { color: var(--text-muted); font-size: 14px; }

/* Toggle pill groups (THIS MO / NEXT / +2, Gross/Net, Training week nav) -
   Styles.html .toggle-pill/.toggle-pill-active exactly: solid gray fill
   (not an outline), no border at all, and the active state is a soft
   tinted pill (light blue bg + navy text light mode, dark navy bg + light
   blue text dark mode) - NOT a solid navy-fill/white-text button, which
   was this file's previous (invented) treatment. */
.toggle-group { display: flex; gap: 4px; }
.toggle-pill {
  background: #E5E7EB;
  color: #6B7280;
  border: none;
  border-radius: 10px;
  padding: 2px 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  cursor: pointer;
}
@media (prefers-color-scheme: dark) {
  .toggle-pill { background: #334155; color: #94A3B8; }
}
.toggle-pill.active { background: #DBEAFE; color: #1E40AF; }
@media (prefers-color-scheme: dark) {
  .toggle-pill.active { background: #1E3A5F; color: #60A5FA; }
}
.toggle-pill:disabled { opacity: 0.4; cursor: not-allowed; }

/* Market Update card (Dashboard) - market tabs, Snapshot/Trend toggle,
   sparklines, mortgage rate history chart. Matches the legacy screenshots
   exactly per Kenny (2026-08-02): green active Snapshot/Trend toggle,
   blue-underline market tabs, hand-rolled SVG sparklines/line chart. */
.market-tab {
  padding: 8px 16px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 14px;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  white-space: nowrap;
  flex-shrink: 0;
}
.market-tab-active { color: var(--accent-text); font-weight: 600; border-bottom-color: var(--accent-text); }

.market-view-toggle {
  border: none;
  border-radius: 6px;
  padding: 6px 14px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  background: var(--card-border);
  color: var(--text);
}
.market-view-toggle.active { background: var(--success); color: #fff; }

.market-metric-card { background: var(--soft-bg); border: 1px solid var(--soft-border); border-radius: 8px; padding: 16px; min-width: 0; }
.market-metric-trend-up { color: var(--success); }
.market-metric-trend-down { color: var(--danger); }
.market-metric-trend-flat { color: var(--text-muted); }

.sparkline-dot { fill: var(--accent-text); }
.sparkline-hit:hover ~ .spark-tooltip,
.sparkline-hit { cursor: pointer; }

.spark-tooltip {
  position: fixed;
  display: none;
  background: var(--sidebar-bg);
  color: var(--sidebar-text-active);
  font-size: 11px;
  padding: 5px 8px;
  border-radius: 5px;
  white-space: nowrap;
  z-index: 50;
  pointer-events: none;
}

.mortgage-trend-tooltip {
  background: var(--sidebar-bg);
  color: var(--sidebar-text-active);
  font-size: 11px;
  padding: 5px 8px;
  border-radius: 5px;
  white-space: nowrap;
}

.u-success { color: var(--success); }
.u-accent { color: var(--accent-text); }
.u-muted { color: var(--text-muted); }
.u-faint { color: var(--text-faint); }
.u-strong { color: var(--text); font-weight: 600; }
.u-label-text { color: var(--label-text); }
.u-danger { color: var(--danger); }
.u-border-left-danger { border-left: 3px solid var(--danger); }
.u-border-bottom { border-bottom: 1px solid var(--card-border); }
.u-border-bottom-soft { border-bottom: 1px solid var(--soft-border); }
/* Styles.html .u-btn-primary - solid fill, no swap (same non-swapping
   pattern as .u-btn-danger/.toggle-onoff-active elsewhere in this file). */
.u-btn-primary { background: var(--active-item); color: #fff; border: none; border-radius: 6px; cursor: pointer; font-weight: 500; }
/* Styles.html .u-soft-box - the reusable nested-card tint, used throughout
   Log an Interaction/Checklist/Webinars-Open-Houses list rows. */
.u-soft-box { background: var(--soft-bg); border-radius: 8px; border: 1px solid var(--soft-border); }

/* Styles.html 9.10/9.11 (2026-07-16) - #report-output must render as a
   fixed soft-light "paper" card regardless of app theme, so on-screen
   report output matches the PDF export instead of falling back to bare
   table defaults or picking up the app's own dark-mode zebra-striping.
   Per Kenny: not pure white, not app-dark-mode-adaptive either - reads as
   a native card ("part of the system"), same #F8FAFC/#E5E7EB soft-card
   tone .u-soft-box uses in light mode specifically, stays that tone in
   both app light and dark mode. Values hardcoded (not var(--soft-bg)/
   var(--soft-border), which swap for dark mode) - that's the entire
   point of this fix. */
#report-output:not(:empty) { background: #F8FAFC; border: 1px solid #E5E7EB; border-radius: 8px; color: #0F172A; padding: 16px; }
#report-output h1 { font-size: 22px; margin: 0 0 4px; color: #0F172A; }
#report-output h2 { font-size: 15px; margin: 20px 0 8px; font-weight: 600; color: #1E40AF; border-bottom: 1px solid #E5E7EB; padding-bottom: 4px; }
#report-output p { color: #334155; }
#report-output .report-subtitle { font-size: 13px; color: #64748B; margin-bottom: 4px; }
#report-output .report-generated { font-size: 11px; color: #94A3B8; margin-bottom: 20px; }
#report-output table { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 12px; }
#report-output td, #report-output th { text-align: left; padding: 6px 8px; border-bottom: 1px solid #E5E7EB; vertical-align: top; color: #0F172A; }
#report-output th { color: #64748B; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
#report-output .report-empty { color: #94A3B8; font-style: italic; font-size: 13px; }
#report-output tr:nth-child(even), #report-output tr:nth-child(odd) { background: transparent; }
#report-output .report-banner { width: 100%; max-height: 160px; object-fit: cover; display: block; margin-bottom: 16px; border-radius: 6px; }
#report-output .report-banner-fallback { text-align: center; padding: 16px 0; border-bottom: 2px solid #1E40AF; margin-bottom: 16px; }
#report-output .report-banner-fallback .agent-name { font-size: 20px; font-weight: 800; color: #0F172A; }
#report-output .report-banner-fallback .agent-brokerage { font-size: 13px; color: #64748B; }

/* border-left deliberately stays var(--active-item) (fixed #1E40AF), NOT
   --accent-text - legacy's own dark-mode override for this exact element
   (body.dark-mode .u-soft-box.u-border-left-accent) keeps the accent bar
   at #1E40AF in both modes, unlike the text-color swap everywhere else. */
.market-insight-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border-radius: 8px;
  background: var(--soft-bg);
  border-left: 3px solid var(--active-item);
}

.mortgage-trend-grid { stroke: var(--card-border); }
.mortgage-trend-axis-text { fill: var(--text-muted); }
.mortgage-trend-line-30, .mortgage-trend-dot-30 { stroke: var(--accent-text); fill: var(--accent-text); }
.mortgage-trend-line-15, .mortgage-trend-dot-15 { stroke: var(--warning); fill: var(--warning); }
.mortgage-legend-dot-30 { background: var(--accent-text); }
.mortgage-legend-dot-15 { background: var(--warning); }

/* IGA % Trend (Training tab) - single-series line chart, same hand-rolled
   SVG pattern as the mortgage rate history chart above, plus a dashed
   80% target reference line legacy doesn't use elsewhere. */
.schedule-trend-grid { stroke: var(--card-border); }
.schedule-trend-axis-text { fill: var(--text-muted); }
.schedule-trend-line, .schedule-trend-dot { stroke: var(--active-item); fill: var(--active-item); }
.schedule-trend-target-line { stroke: var(--text-muted); fill: none; }
.schedule-trend-tooltip {
  background: var(--sidebar-bg);
  color: var(--sidebar-text-active);
  font-size: 11px;
  padding: 5px 8px;
  border-radius: 5px;
  white-space: nowrap;
}

select {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 14px;
}

/* All text-like input types - not just [type="text"] - see MISTAKE_LOG.md
   #15 (global button style gap): date/datetime-local/number/etc. inputs
   were left unstyled here the same way buttons were, falling back to the
   browser's native white input chrome on a dark page. color-scheme below
   also fixes the native date/time picker popup itself (calendar icon,
   picker panel) rendering in light-on-dark otherwise. */
input[type="text"], input[type="date"], input[type="datetime-local"],
input[type="time"], input[type="month"], input[type="week"],
input[type="number"], input[type="email"], input[type="tel"],
input[type="url"], input[type="password"], input:not([type]) {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 14px;
  color-scheme: dark;
}

@media (prefers-color-scheme: light) {
  input[type="text"], input[type="date"], input[type="datetime-local"],
  input[type="time"], input[type="month"], input[type="week"],
  input[type="number"], input[type="email"], input[type="tel"],
  input[type="url"], input[type="password"], input:not([type]) {
    color-scheme: light;
  }
}
:root[data-theme="dark"] input[type="text"], :root[data-theme="dark"] input[type="date"],
:root[data-theme="dark"] input[type="datetime-local"], :root[data-theme="dark"] input[type="time"],
:root[data-theme="dark"] input[type="month"], :root[data-theme="dark"] input[type="week"],
:root[data-theme="dark"] input[type="number"], :root[data-theme="dark"] input[type="email"],
:root[data-theme="dark"] input[type="tel"], :root[data-theme="dark"] input[type="url"],
:root[data-theme="dark"] input[type="password"], :root[data-theme="dark"] input:not([type]) { color-scheme: dark; }
:root[data-theme="light"] input[type="text"], :root[data-theme="light"] input[type="date"],
:root[data-theme="light"] input[type="datetime-local"], :root[data-theme="light"] input[type="time"],
:root[data-theme="light"] input[type="month"], :root[data-theme="light"] input[type="week"],
:root[data-theme="light"] input[type="number"], :root[data-theme="light"] input[type="email"],
:root[data-theme="light"] input[type="tel"], :root[data-theme="light"] input[type="url"],
:root[data-theme="light"] input[type="password"], :root[data-theme="light"] input:not([type]) { color-scheme: light; }

/* Plain <textarea> outside .reflection-grid had no rule at all (each
   caller was inline-styling its own copy - Contact Notes, Vendor notes -
   third time hitting this gap, so a real rule now instead of a fourth
   duplicate). Same box as the text input rule above. */
textarea {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 14px;
  font-family: inherit;
  min-height: 60px;
  resize: vertical;
  color-scheme: dark;
}
@media (prefers-color-scheme: light) {
  textarea { color-scheme: light; }
}
:root[data-theme="dark"] textarea { color-scheme: dark; }
:root[data-theme="light"] textarea { color-scheme: light; }

/* Schedule week grid */
.schedule-grid-table { border-collapse: collapse; font-size: 11px; white-space: nowrap; }
.schedule-grid-table th, .schedule-grid-table td { border: 1px solid var(--card-border); padding: 3px 4px; }
.schedule-grid-table th { background: var(--card-bg); position: sticky; top: 0; z-index: 2; font-weight: 600; color: var(--text-muted); }
.schedule-grid-table td:first-child, .schedule-grid-table th:first-child {
  position: sticky; left: 0; z-index: 3; background: var(--card-bg); font-weight: 600;
}
.schedule-grid-table select { width: 92px; box-sizing: border-box; font-size: 11px; padding: 3px; }
/* The anchor cell (plain-clicked) keeps real browser focus so its native
   dropdown still opens normally; Shift+Click range cells never get focus
   (their mousedown is intercepted specifically to avoid popping the
   dropdown open). That made the anchor cell show an extra native focus
   ring on top of .bulk-selected that range cells never got, so the same
   highlight looked like two different things. Removing the ring here makes
   .bulk-selected the only visual signal for both, with zero JS change. */
.schedule-grid-table select:focus { outline: none; }
.schedule-grid-table input[type="text"] { width: 100px; box-sizing: border-box; font-size: 11px; padding: 3px; }
/* Legacy used APP_COLORS.selectedBg (#DBEAFE) - a solid, fully OPAQUE
   background (JavaScript.html:228,10245), not a translucent overlay, and
   never swapped it for dark mode at all (APP_COLORS has no dark variant).
   That fixed light color still read clearly in dark mode purely because
   it was opaque - a translucent rgba() overlay (this file's original
   version) blends into a dark background almost invisibly. Using
   --accent-text solid keeps it opaque like legacy while actually being
   dark-mode-aware, swapping per-theme via the vars already defined above. */
.schedule-grid-table td.bulk-selected { background: var(--accent-text); }

/* Cycle Progress bullet-graph rows */
.schedule-bullet-track { background: var(--bullet-track); }
.schedule-bullet-tick { background: var(--text); opacity: 0.6; }
.schedule-type-filter-toggle { display: flex; gap: 6px; margin-bottom: 10px; }
.schedule-type-filter-toggle button {
  padding: 4px 12px; font-size: 12px; border-radius: 6px; cursor: pointer;
  background: transparent; color: var(--text); border: 1px solid var(--card-border);
}
.schedule-type-filter-toggle button.active { background: var(--active-item); color: #fff; border-color: var(--active-item); }

/* Reflection card */
.reflection-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.reflection-grid textarea {
  width: 100%; box-sizing: border-box; min-height: 70px; resize: vertical; font-family: inherit; font-size: 13px;
  background: var(--bg); color: var(--text); border: 1px solid var(--card-border); border-radius: 6px; padding: 8px 10px;
}

/* Past Cycles list */
.past-cycle-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 4px; border-bottom: 1px solid var(--card-border); font-size: 13px;
}
.past-cycle-row:last-child { border-bottom: none; }

/* Click-to-expand contact rows */
.contact-row { border-bottom: 1px solid var(--card-border); }
.contact-row:last-child { border-bottom: none; }

/* Polish pass, per Kenny: collapsed summary now carries the same
   at-a-glance richness the SOI row used to (name/badges line + contact
   line + a type-specific status line), not a single-line "name + badge"
   strip - top-aligned so the chevron sits level with the name instead of
   vertically centering against a now-multi-line block. */
.contact-row-summary {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 12px 8px;
  font-size: 14px;
  cursor: pointer;
}
.contact-row-summary:hover { background: rgba(255, 255, 255, 0.03); }
/* APP_COLORS.highlightBg (#EFF6FF light / #1e3a5f dark) - the expanded
   row's own highlight, distinct from the plain hover tint above. */
.contact-row-summary.is-expanded { background: #EFF6FF; }
@media (prefers-color-scheme: dark) {
  .contact-row-summary.is-expanded { background: #1e3a5f; }
}
.contact-row-summary-name { font-weight: 500; }
.contact-row-chevron { color: var(--text-faint); font-size: 18px; margin-top: 2px; }

/* .u-soft-box.u-border-top - the expanded detail area reads as its own
   nested card, not plain/transparent inline content. */
.contact-row-detail {
  padding: 16px;
  background: var(--soft-bg);
  border-top: 1px solid var(--soft-border);
}
.contact-detail-fields { font-size: 13px; color: var(--label-text); line-height: 1.8; margin-bottom: 12px; }
.detail-line { font-size: 13px; color: var(--text-muted); margin-bottom: 12px; }

/* Icon-only pin toggles (push_pin / dashboard_customize) - accent when
   pinned, faint when not, matching buildClientRowHtml_'s listPinColor/
   dashPinColor exactly. */
.pin-icon-btn { background: none; border: none; cursor: pointer; padding: 4px; display: flex; }
.pin-icon-btn .material-icons-round { font-size: 22px; }
.pin-icon-btn.pinned .material-icons-round { color: var(--accent-text); }
.pin-icon-btn:not(.pinned) .material-icons-round { color: var(--text-faint); }

.row-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* Matches Styles.html .u-btn-outline (same fix as .btn-secondary above) -
   solid card-tint fill and label-text color, not transparent/full-text. */
.row-actions button {
  background: var(--card-bg);
  color: var(--label-text);
  border: 1px solid var(--card-border);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 12px;
  cursor: pointer;
}
.row-actions button.active-toggle { background: var(--active-item); color: #fff; border-color: var(--active-item); }
/* .row-actions button's higher specificity would otherwise override plain
   .btn-danger, so this needs restating here rather than just relying on
   the global rule (previously restated it back to the WRONG outline-red
   style - matching .u-btn-danger's actual solid fill/no-border now). */
.row-actions button.btn-danger { background: #DC2626; color: #fff; border: none; }
/* Same fix, same reason - the row-unification polish pass put Start
   Intake (.u-btn-primary) inside .row-actions for the first time, which
   would otherwise silently render it as a plain gray/card-tint button. */
.row-actions button.u-btn-primary { background: var(--active-item); color: #fff; border: none; }
.row-actions label.strategy-toggle { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }

.portal-panel, .delete-confirm { margin-top: 10px; display: flex; gap: 8px; align-items: center; }
.portal-panel input { flex: 1; }

/* Scrollable list containers (max-height set per-instance inline; this
   class governs the scroll behavior itself). scrollbar-gutter:stable
   reserves the scrollbar's track space in the box model instead of
   letting a classic (non-overlay) scrollbar render on top of row/field
   content at the container's right edge - real complaint (Kenny,
   2026-08-03/04), not a hypothetical: without this, list rows and
   inputs that extend to the container's edge get their rightmost text
   visually covered by the scrollbar thumb/track. */
.scroll-list { overflow-y: auto; scrollbar-gutter: stable; }

/* Settings orderable rows */
.settings-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 4px; border-bottom: 1px solid var(--card-border);
  font-size: 14px;
}
.settings-row:last-child { border-bottom: none; }
.settings-row .reorder-btns { display: flex; flex-direction: column; gap: 1px; }
.settings-row .reorder-btns button { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0; line-height: 1; }
.settings-row .reorder-btns button:disabled { opacity: 0.3; cursor: not-allowed; }
.settings-row .settings-row-name { min-width: 160px; font-weight: 600; }
.settings-row .settings-row-fields { display: flex; gap: 8px; align-items: center; flex: 1; flex-wrap: wrap; }
.settings-row input, .settings-row select { width: auto; }

/* Modal */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex; align-items: center; justify-content: center;
  z-index: 100;
}
.modal {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 8px;
  padding: 24px;
  width: 420px;
  box-sizing: border-box;
  max-height: 85vh;
  overflow-y: auto;
}
.modal-field { margin-bottom: 12px; }
.modal-field label { display: block; font-size: 12px; color: var(--text-muted); margin-bottom: 4px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }

/* Mobile responsive (Styles.html:73-122, ported exactly) - sidebar forces
   to icon-only width, nav labels/group headers hide, content padding
   shrinks, and every grid/card gets explicit overflow protection so
   narrow viewports show one properly-sized card per row instead of a
   smushed/overflowing desktop layout. Deliberately placed last in this
   file - equal-specificity rules cascade by source order, and every base
   rule this overrides (.metric-row, .card, .two-col-grid, etc.) must be
   declared earlier than this block or it silently wins on mobile anyway
   (exactly the bug this fixes: this block used to sit before .metric-row's
   base rule, so the base rule always won regardless of viewport width). */
@media (max-width: 768px) {
  .sidebar { width: 70px; }
  .sidebar-brand { display: none; }
  .nav-group-label { display: none; }
  .nav-item { justify-content: center; padding: 15px 10px; gap: 0; }
  .nav-item .menu-text { display: none; }
  /* Same reasoning as .sidebar.collapsed .nav-item-group-hidden above -
     no group header left to expand/collapse into at this width, so a
     group left collapsed from a wider viewport can't hide its icons here. */
  .nav-item-group-hidden { display: flex !important; }

  /* 2026-08-29, per Kenny: the collapse toggle used to be a no-op on
     mobile - .sidebar{width:70px} above applied unconditionally regardless
     of the .collapsed class, so tapping the toggle changed the chevron
     icon but nothing ever visibly expanded. Real fix is a proper overlay
     drawer (not just letting the sidebar widen in-flow, which would
     otherwise squeeze page content down to almost nothing on a real
     phone) - toggleSidebarCollapse() in app.js applies a SEPARATE
     .mobile-nav-open class at this breakpoint instead of the desktop
     .collapsed class, since the two need opposite default states
     (mobile defaults to icon-only/closed; desktop defaults to expanded)
     and don't share the same persisted preference. */
  .sidebar.mobile-nav-open {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 260px;
    z-index: 1000;
    box-shadow: 4px 0 32px rgba(0, 0, 0, 0.4);
  }
  .sidebar.mobile-nav-open .sidebar-brand { display: flex; }
  .sidebar.mobile-nav-open .nav-group-label { display: flex; }
  .sidebar.mobile-nav-open .nav-item { justify-content: flex-start; padding: 12px 20px; gap: 12px; }
  .sidebar.mobile-nav-open .nav-item .menu-text { display: inline; }
  /* Drawer has room for group headers again, so let real per-group
     collapse state apply instead of the icon-rail force-visible rule
     above. */
  .sidebar.mobile-nav-open .nav-item-group-hidden { display: none; }

  #sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 999;
  }
  .sidebar.mobile-nav-open ~ #sidebar-backdrop { display: block; }

  .content { padding: 16px; max-width: 100%; }

  .metric-row, .two-col-grid { grid-template-columns: 1fr !important; }

  /* Market metrics - 2 columns on mobile instead of the desktop auto-fill
     count (Styles.html:96-98, exact match - the auto-fill/minmax(160px)
     math that works on desktop only fits 1 column in a mobile card's
     narrower content width, missed on the first mobile pass). */
  #market-metrics-grid { grid-template-columns: repeat(2, 1fr) !important; }

  /* Deliberately NOT reducing .card/.metric-card/.market-metric-card
     padding or .metric-number font-size here - Styles.html's mobile block
     (73-118) only ever touches width/box-sizing/overflow/word-break on
     cards, never padding or font-size. An earlier pass here guessed a
     padding/font reduction on its own; removed - keep the desktop values,
     let column-collapse be the only mobile adaptation, matching source. */
  .two-col-grid, .metric-row, .card, .metric-card, .market-metric-card {
    width: 100%;
    box-sizing: border-box;
    max-width: 100%;
    overflow-x: hidden;
  }
  .card *, .metric-card *, .market-metric-card * {
    word-break: break-word;
    overflow-wrap: break-word;
    max-width: 100%;
  }

  /* Prevent any inline links or URLs from overflowing (Styles.html:114-116,
     exact match - missed on the first mobile pass along with the two
     grid containers above, which were also absent from the overflow
     protection list here even though legacy explicitly includes them,
     not just the cards inside them). */
  a { word-break: break-all; }
}

/* Deliberately no <480px single-column override here. Styles.html:119-121
   has one, but real-device testing (2026-08-02, iframe-isolated viewport
   at 386px - matchMedia confirmed true, sidebar confirmed 70px, grid still
   collapsed to 1 column) proved that rule fires on effectively every real
   phone (~360-430px is the norm), permanently defeating the 2-column rule
   above it. Kenny's own current live legacy app shows 2 columns at that
   same width, so the static code snapshot's <480px rule doesn't reflect
   what's actually deployed - removed rather than followed blindly. */
