/* ============================================================================
   MOGUL MACHINE — SHARED DESIGN SYSTEM
   ============================================================================
   This is the ONE real source of truth for tokens and cross-app components,
   for BOTH admin-dashboard/ and ae-portal/. It is NOT directly deployed from
   here -- Cloudflare Pages deploys each app folder as an isolated root, so a
   relative <link> to a sibling shared/ folder 404s in production. Instead,
   .github/workflows/deploy.yml copies this exact file into
   admin-dashboard/design-system.css and ae-portal/design-system.css as a step
   BEFORE each app's `wrangler pages deploy` step runs. Edit ONLY this file --
   the two per-app copies are generated and will be overwritten on next deploy.

   Each app's own styles.css should contain ONLY genuinely page/feature-specific
   rules (e.g. Kanban only exists in ae-portal; Startup Aggregator/Incubator
   card internals only exist in admin). Anything that should look identical in
   both apps belongs here, not duplicated in both stylesheets by hand.
   ============================================================================ */

:root {
  /* === Apple System Colors === */
  --system-blue: #007AFF;
  --system-green: #34C759;
  --system-red: #FF3B30;
  --system-yellow: #FFCC00;
  --system-orange: #FF9500;
  --system-purple: #AF52DE;
  --system-pink: #FF2D55;
  --system-teal: #5AC8FA;
  --system-indigo: #5856D6;

  /* === Dynamic Brand Colors (overridden at runtime from Settings via
     document.documentElement.style.setProperty -- these are just the
     pre-JS/failure-mode defaults) === */
  --primary: var(--system-blue);
  --primary-hover: #0056CC;
  --success: var(--system-green);
  --danger: var(--system-red);
  --warning: var(--system-yellow);
  --info: var(--system-teal);

  /* === Gradient Accent Colors === */
  --accent-cyan: #00D4AA;
  --accent-yellow: #FFB800;
  --accent-teal: #00A8E8;
  --accent-blue: #007AFF;

  /* === Apple Light Mode Grays === */
  --gray-50: #F2F2F7;
  --gray-100: #E5E5EA;
  --gray-200: #D1D1D6;
  --gray-300: #C7C7CC;
  --gray-400: #AEAEB2;
  --gray-500: #8E8E93;
  --gray-600: #636366;
  --gray-700: #48484A;
  --gray-800: #3A3A3C;
  --gray-900: #1C1C1E;

  /* === Surfaces === */
  --bg-primary: #EFF1F5; /* cool-biased neutral ground (was #F5F5F7) -- reads chosen, not default */
  --bg-secondary: #FFFFFF;
  --bg-tertiary: #F2F2F7;
  --surface-elevated: #FFFFFF;
  --surface-hover: rgba(0, 0, 0, 0.02);
  --surface-active: rgba(0, 122, 255, 0.08);

  /* === Text Colors === */
  --text-primary: #1D1D1F;
  --text-secondary: #86868B;
  --text-tertiary: #A1A1A6;
  --text-quaternary: #C1C1C6;
  --text-inverse: #FFFFFF;

  /* === Borders === */
  --border-subtle: rgba(0, 0, 0, 0.04);
  --border-light: rgba(0, 0, 0, 0.08);
  --border-medium: rgba(0, 0, 0, 0.12);
  --border-strong: rgba(0, 0, 0, 0.20);

  /* === Shadows — softer, layered, and blue-tinted (rgba 16,24,40) so depth
     reads as considered hierarchy rather than a hard drop. === */
  --shadow-none: 0 0 0 rgba(0, 0, 0, 0);
  --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.05);
  --shadow-sm: 0 1px 3px rgba(16, 24, 40, 0.08), 0 1px 2px rgba(16, 24, 40, 0.04);
  --shadow-md: 0 8px 24px -8px rgba(16, 24, 40, 0.16), 0 2px 6px rgba(16, 24, 40, 0.05);
  --shadow-lg: 0 20px 48px -16px rgba(16, 24, 40, 0.22);
  --shadow-xl: 0 28px 60px -18px rgba(16, 24, 40, 0.26);

  /* === Animation Curves (Apple-style) === */
  --ease-standard: cubic-bezier(0.4, 0.0, 0.2, 1);
  --ease-enter: cubic-bezier(0.0, 0.0, 0.2, 1);
  --ease-exit: cubic-bezier(0.4, 0.0, 1, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* === Timing === */
  --duration-instant: 0ms;
  --duration-fast: 100ms;
  --duration-normal: 200ms;
  --duration-slow: 350ms;
  --duration-slower: 500ms;

  /* === Border Radius (Apple-style organic curves) === */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;
  --radius-2xl: 24px;
  --radius-full: 9999px;

  /* === Typography Scale (element-level: headings/body) === */
  --font-sans: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;

  /* === Typography Scale (component-level: card titles/subtitles/labels) ===
     This is the scale that was previously missing entirely -- every card
     across every section (Leads, Incubator, Collections, Startup Aggregator,
     Imported, Partners, Files) hardcoded its own one-off font-size/weight/
     letter-spacing instead of referencing shared values. .card-title/
     .card-subtitle below reference these; use them for any future card type. */
  --font-size-card-title: 16px;
  --font-weight-card-title: 700;
  --letter-spacing-card-title: -0.02em;
  --font-size-card-subtitle: 13px;
  --font-weight-card-subtitle: 500;

  /* === Spacing Scale (4px baseline) === */
  --space-0: 0;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;

  /* === Liquid Glass tokens ===
     Previously inlined ad hoc in admin-dashboard/index.html's <head> (with a
     comment explaining shared/liquid-glass.css 404s in production) and only
     PARTIALLY duplicated in ae-portal/styles.css (missing most of these
     variables entirely, which is part of why ae-portal's glass surfaces
     didn't always match admin's). One real copy now. */
  --glass-bg: rgba(255, 255, 255, 0.08);
  --glass-bg-hover: rgba(255, 255, 255, 0.12);
  --glass-bg-active: rgba(255, 255, 255, 0.15);
  --glass-border: rgba(255, 255, 255, 0.15);
  --glass-border-hover: rgba(255, 255, 255, 0.25);
  --glass-glow: rgba(255, 255, 255, 0.1);
  --glass-shadow: rgba(0, 0, 0, 0.3);
  --glass-surface: rgba(28, 28, 30, 0.7);
  --glass-surface-elevated: rgba(44, 44, 46, 0.6);
  --glass-text-primary: rgba(255, 255, 255, 0.95);
  --glass-text-secondary: rgba(255, 255, 255, 0.6);
  --glass-text-tertiary: rgba(255, 255, 255, 0.4);
  --glass-blur-sm: blur(8px);
  --glass-blur-md: blur(16px);
  --glass-blur-lg: blur(24px);
  --glass-blur-xl: blur(40px);
  --glass-radius-sm: 12px;
  --glass-radius-md: 16px;
  --glass-radius-lg: 24px;
  --glass-radius-xl: 32px;

  /* Light Liquid Glass -- for the main (light-themed) dashboard body: cards,
     modals, badges, buttons across every section in both apps. Text on these
     surfaces always stays a fully opaque dark color (var(--text-primary) or
     darker) -- never translucent -- so legibility never depends on how
     strong the blur/tint underneath happens to be. */
  --glass-light-bg: rgba(255, 255, 255, 0.92);
  --glass-light-bg-hover: rgba(255, 255, 255, 0.75);
  --glass-light-bg-solid: rgba(255, 255, 255, 0.92);
  --glass-light-border: rgba(255, 255, 255, 0.8);
  --glass-light-border-subtle: rgba(120, 120, 130, 0.12);
  --glass-light-highlight: rgba(255, 255, 255, 0.9);
  --glass-light-shadow: rgba(60, 60, 70, 0.12);
  --glass-light-shadow-hover: rgba(60, 60, 70, 0.18);
  --glass-blur-light-sm: blur(12px);
  /* Performance: cards/stat-cards using this var scroll, and blur is the
     dominant scroll cost, so the light-glass blur is disabled. The bg alpha
     below is raised to compensate so cards still read as solid. */
  --glass-blur-light: none;
}

/* ============================================================================
   DARK THEME — structural token overrides only. Toggled via a
   html[data-theme="dark"] attribute (set/cleared by app.toggleTheme() in each
   app's own JS, persisted to localStorage). Brand/badge/nav colors
   (--primary, --success, --danger, --warning, --info, --accent-*, --system-*,
   any --badge-*, --nav-*) are DELIBERATELY left unchanged here -- they're
   either runtime-set from Settings via setProperty() (which would beat any
   stylesheet rule anyway) or explicitly meant to look identical in both
   themes, per prior design review.
   ============================================================================ */
html[data-theme="dark"] {
  --bg-primary: #16161A;
  --bg-secondary: #1C1C1E;
  --bg-tertiary: #232326;
  --surface-elevated: #232326;
  --surface-hover: rgba(255, 255, 255, 0.04);
  --surface-active: rgba(10, 132, 255, 0.16);

  --text-primary: #F5F5F7;
  --text-secondary: #98989D;
  --text-tertiary: #7C7C80;
  --text-quaternary: #5C5C5F;
  /* --text-inverse intentionally omitted: it only ever sits on solid
     brand-colored buttons (.btn-primary gradient, var(--primary)), which
     don't change between themes -- so it must keep its light value (#FFFFFF)
     in dark mode too. */

  --border-subtle: rgba(255, 255, 255, 0.06);
  --border-light: rgba(255, 255, 255, 0.10);
  --border-medium: rgba(255, 255, 255, 0.16);
  --border-strong: rgba(255, 255, 255, 0.24);

  --shadow-none: 0 0 0 rgba(0, 0, 0, 0);
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.20);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.28);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.36);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.44);
  --shadow-xl: 0 24px 48px rgba(0, 0, 0, 0.52);

  /* Gray scale inverted -- it's used directly as text/bg (.glc-name, .glc-sub,
     .nav-btn.active, .btn-secondary color: var(--gray-900), etc), so leaving
     it unchanged would put near-black text on a near-black background. */
  --gray-50: #232326;  --gray-100: #2C2C2E; --gray-200: #3A3A3C;
  --gray-300: #48484A; --gray-400: #636366; --gray-500: #8E8E93;
  --gray-600: #AEAEB2; --gray-700: #C7C7CC; --gray-800: #D1D1D6;
  --gray-900: #F5F5F7;

  /* Light Liquid Glass tokens, dark-mode values -- consumed via var() by
     .glass-card/.glass-badge/.glass-btn (admin-dashboard/index.html inline
     <style>) and the .toc-filter-bar select fallback chain. The raw-rgba
     "signed-off" glass recipe below (.glass-surface etc) does NOT use these
     tokens -- it gets its own explicit override block further down. */
  --glass-light-bg: rgba(255, 255, 255, 0.10);
  --glass-light-bg-hover: rgba(255, 255, 255, 0.10);
  --glass-light-bg-solid: rgba(44, 44, 46, 0.92);
  --glass-light-border: rgba(255, 255, 255, 0.14);
  --glass-light-border-subtle: rgba(255, 255, 255, 0.10);
  --glass-light-highlight: rgba(255, 255, 255, 0.08);
  --glass-light-shadow: rgba(0, 0, 0, 0.4);
  --glass-light-shadow-hover: rgba(0, 0, 0, 0.5);
}

/* --- "Signed-off" glass recipe dark overrides (additive only -- the light-mode
   rules in each app's styles.css are never touched). Same current values in
   both apps today, so one shared override covers both. Higher specificity
   ([data-theme="dark"] + the class) plus !important beats the light rules'
   !important in ae-portal and plain specificity in admin, regardless of
   stylesheet load order. --- */
[data-theme="dark"] .glass-surface,
[data-theme="dark"] .lead-card.main-lead-card,
[data-theme="dark"] .startup-lead-card-v2,
[data-theme="dark"] .imported-lead-card,
[data-theme="dark"] .partner-card,
[data-theme="dark"] .glass-card,
[data-theme="dark"] .file-card {
  background: var(--surface-elevated) !important;
  border: 1px solid var(--border-light) !important;
  box-shadow: var(--shadow-sm) !important;
}
[data-theme="dark"] .glass-surface:hover,
[data-theme="dark"] .lead-card.main-lead-card:hover,
[data-theme="dark"] .startup-lead-card-v2:hover,
[data-theme="dark"] .imported-lead-card:hover,
[data-theme="dark"] .partner-card:hover,
[data-theme="dark"] .glass-card:hover,
[data-theme="dark"] .file-card:hover {
  box-shadow: var(--shadow-md) !important;
}
[data-theme="dark"] .action-pill,
[data-theme="dark"] .btn-secondary {
  border: 1px solid rgba(255,255,255,0.14) !important;
  background: rgba(255,255,255,0.06) !important;
  color: var(--gray-900) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08), 0 2px 6px -3px rgba(0,0,0,0.4) !important;
}
[data-theme="dark"] .action-pill:hover,
[data-theme="dark"] .btn-secondary:hover { background: rgba(255,255,255,0.10) !important; }
/* .action-pill-primary/-danger/-warn/-success and .btn-primary use solid
   brand-colored gradients (not white-tinted glass) -- unaffected by theme,
   no override needed. */
[data-theme="dark"] .modal-content {
  background: var(--surface-elevated) !important;
  border: 1px solid var(--border-light) !important;
  box-shadow: 0 40px 80px -24px rgba(0,0,0,0.7) !important;
}

/* === Base Typography === */
h1 { font-size: 28px; font-weight: 700; letter-spacing: -0.021em; line-height: 1.125; }
h2 { font-size: 22px; font-weight: 700; letter-spacing: -0.021em; line-height: 1.181; }
h3 { font-size: 19px; font-weight: 600; letter-spacing: -0.021em; line-height: 1.211; }
h4 { font-size: 17px; font-weight: 600; letter-spacing: -0.021em; line-height: 1.294; }
p, li { font-size: 15px; line-height: 1.5; letter-spacing: -0.016em; }

/* === Section Header (the page title + action-buttons row at the top of
   every section: Leads, Incubator, Collections, Startup Aggregator, Imported,
   Partners, Stats, Files). Every section must use this exact markup:
     <div class="section-header">
       <div class="header-left"><h2>Page Title</h2></div>
       <div class="header-actions-row">...buttons...</div>
     </div>
   === */
.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  gap: var(--space-4);
  flex-wrap: wrap;
}
.section-header .header-left {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
}
.header-actions-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}
.section-header h2 {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.021em;
  margin: 0;
  color: var(--text-primary);
}

/* === Card Grid (the ONE grid container for every card-based list/masonry
   view: Leads, Imported Leads, Startup Aggregator, Incubator, Partners,
   Collections, Files. Previously 3 different minmax breakpoints and 2
   different gap values existed for this same conceptual layout.) === */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--space-5);
}
@media (max-width: 480px) {
  .card-grid { grid-template-columns: minmax(0, 1fr); }
}

/* === Card Title / Subtitle (the ONE typography treatment for every card's
   name + secondary line, regardless of section. Apply alongside whatever
   section-specific class already exists, e.g. class="glc-name card-title" --
   these two classes carry the actual font values so every card converges on
   the same look without renaming every existing selector.) === */
.card-title {
  font-size: var(--font-size-card-title);
  font-weight: var(--font-weight-card-title);
  letter-spacing: var(--letter-spacing-card-title);
  color: var(--gray-900);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.card-subtitle {
  font-size: var(--font-size-card-subtitle);
  font-weight: var(--font-weight-card-subtitle);
  color: var(--gray-600);
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* === Lead Detail Modal Header (shared component -- the header row of the
   lead-detail modal in BOTH apps: company name on its own full-width line,
   then a second row split into [Back/position/Next] on the left and
   [feature buttons] on the right. Previously admin had this as a real
   component and ae-portal rebuilt the same region from scratch with three
   unrelated inline-styled rows and Prev/Next placed BEFORE the name.) === */
.lead-detail-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border-subtle);
}
.lead-detail-header h2 {
  margin: 0;
  font-size: 22px;
  word-break: break-word;
}
.lead-detail-header-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  flex-wrap: wrap;
}
.lead-detail-header-actions .lead-detail-nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-shrink: 0;
}
.lead-detail-header-actions .lead-detail-buttons {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
  flex-wrap: wrap;
}
/* In the modal header the Call pill sits beside the status badge + nav pills,
   so size it up to match their weight (the compact 3px/12px version is for the
   dense card + contact rows). */
.lead-detail-header-actions .lead-detail-buttons .glc-call-btn {
  padding: 6px 14px;
  font-size: 13px;
  line-height: 1.4;
}

/* === Lists (the ONE grid for every card-based list/masonry view -- same
   mechanics as .card-grid above under a second historical name; kept as a
   separate selector rather than merged into .card-grid because its mobile
   collapse breakpoint/gap genuinely differ from .card-grid's and are handled
   locally in each app's own styles.css. Desktop-only, byte-identical in both
   apps, so it's centralized here.) === */
.list-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--space-5);
}
@media (max-width: 768px) {
  .list-container {
    grid-template-columns: minmax(0, 1fr); /* not 1fr (=minmax(auto,1fr)): auto min inflated the track past the container and clipped the card */
    gap: var(--space-3);
  }
}

/* === Filters (desktop base only). Deliberately NOT the full rule: the two
   apps' filter bars already diverge in real, currently-live ways beyond this
   (admin adds width:100%+gap:var(--space-2)+flex-shrink:0 children; ae-portal
   uses gap:var(--space-3); and their mobile @media(max-width:768px) treatment
   is genuinely different -- admin lays out row, ae-portal column). Only the
   properties truly identical in both today live here; each app's own
   styles.css layers its real delta on top via the cascade (loaded after this
   file), so current rendering in both apps is unchanged. === */
.filters {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.filters input,
.filters select {
  width: auto;
  min-width: 200px;
}

/* === Theme Toggle (nav button, both apps -- brand new, so it starts life
   properly centralized instead of hand-duplicated) === */
.nav-btn.theme-toggle {
  padding: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.theme-icon-moon { display: none; }
html[data-theme="dark"] .theme-icon-sun { display: none; }
html[data-theme="dark"] .theme-icon-moon { display: inline; }

/* === Badge (small status pill, both apps -- brand new, centralized from
   the start) === */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 600;
}
.badge-primary { background: var(--primary); color: var(--text-inverse); }
/* Same fix as .channel-badge-email below: --text-secondary is a fairly light
   gray (#86868B) that's legible against a dark page in dark mode but washes
   out against --bg-tertiary's near-white in light mode. Explicit light-mode
   text color here, dark mode's already-fine color kept via the override. */
.badge-secondary { background: var(--bg-tertiary); color: #636366; }
[data-theme="dark"] .badge-secondary { color: var(--text-secondary); }
.badge-success { background: var(--success); color: var(--text-inverse); }

/* === Connected-accounts / key row (both apps: AE Settings + admin Settings) === */
.ext-key-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 12px;
}
.ext-key-row input {
  flex: 1 1 320px;
  font-family: var(--font-mono);
  font-size: 13px;
}

/* Multiple accounts per channel (rate-limit/shadowban avoidance -- spread
   cold outreach across several connected LinkedIn/Instagram accounts). */
.unipile-channel-block { margin-top: 16px; }
.unipile-channel-block:first-child { margin-top: 12px; }
.unipile-channel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.unipile-channel-header > span { font-weight: 600; font-size: 14px; }
.unipile-accounts-list { display: flex; flex-direction: column; gap: 6px; }
.unipile-account-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 12px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  font-size: 13px;
}
.unipile-account-label { font-weight: 500; flex: 1; min-width: 100px; }
.unipile-account-empty { padding: 6px 0; font-size: 13px; color: var(--text-tertiary); }

/* Send-from account dropdown in the compose panel -- hidden by default,
   shown only when a rep has more than one connected account for that
   channel (renderComposeAccountPicker in ae-portal.js/admin.js). */
.compose-account-picker {
  width: 100%;
  margin-bottom: 8px;
  padding: 6px 10px;
  font-size: 13px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text-primary);
}

/* Voicemail follow-up sequence builder (per-rep, in Settings) -- ordered
   list of steps, each channel-specific (email/linkedin/instagram). */
.followup-step-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  margin-bottom: 10px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
}
.followup-step-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 8px;
  margin-bottom: 2px;
  border-bottom: 1px solid var(--border-light);
}
.followup-step-title {
  font-weight: 600;
  font-size: 13px;
  color: var(--text-secondary);
}
.followup-step-header-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}
.followup-step-remove-btn {
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-tertiary);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.followup-step-remove-btn:hover {
  background: var(--danger, #FF3B30);
  color: #fff;
}
.followup-step-row-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.followup-step-row-top select,
.followup-step-row-top input[type="number"] {
  padding: 6px 8px;
  font-size: 13px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text-primary);
}
.followup-step-delay-label {
  font-size: 13px;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  gap: 4px;
}
.followup-step-row input[type="text"],
.followup-step-row textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  font-size: 13px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text-primary);
  font-family: inherit;
  resize: vertical;
}

/* Small on/off pill switch (e.g. the follow-up step header's enabled toggle). */
.toggle-switch {
  position: relative;
  display: inline-block;
  width: 34px;
  height: 20px;
  flex-shrink: 0;
}
.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.toggle-switch .toggle-slider {
  position: absolute;
  inset: 0;
  background: var(--border, #ccc);
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.toggle-switch .toggle-slider::before {
  content: '';
  position: absolute;
  width: 14px;
  height: 14px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.15s ease;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.toggle-switch input:checked + .toggle-slider {
  background: var(--success, #34C759);
}
.toggle-switch input:checked + .toggle-slider::before {
  transform: translateX(14px);
}

/* Voice-drop "Record New Drop" button while actively recording. */
#voice-drop-record-btn.recording { background: #FF453A; }

/* Collapsed-by-default "Legacy" section (e.g. Settings' older Gmail
   extension tools, superseded by newer built-in integrations but kept
   around for reps who haven't migrated yet). Works on a <details> element
   with class "detail-section legacy-section" and a <summary class=
   "legacy-summary"> inside it. */
.legacy-section > summary.legacy-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  cursor: pointer;
  list-style: none;
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-secondary);
  padding-bottom: var(--space-2, 8px);
  border-bottom: 1px solid var(--border-subtle, var(--border-light));
}
.legacy-section > summary.legacy-summary::-webkit-details-marker { display: none; }
.legacy-section > summary.legacy-summary > span:first-child {
  display: flex;
  align-items: center;
  gap: 8px;
}
.legacy-section > summary.legacy-summary > span:first-child::before {
  content: '▸';
  font-size: 11px;
  color: var(--text-tertiary);
  transition: transform 0.15s ease;
}
.legacy-section[open] > summary.legacy-summary > span:first-child::before {
  transform: rotate(90deg);
}
.legacy-section .legacy-body { margin-top: var(--space-3, 12px); }

/* Per-lead voicemail follow-up sequence status banner (Communications section). */
.followup-queue-banner {
  margin-bottom: 10px;
  padding: 8px 12px;
  background: var(--bg-tertiary);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  font-size: 13px;
}
.followup-queue-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-weight: 600;
}
.followup-queue-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}
.followup-queue-list {
  margin: 6px 0 0;
  padding-left: 18px;
  color: var(--text-secondary);
  font-weight: normal;
}
.followup-queue-note {
  color: var(--text-tertiary);
  font-style: italic;
}

/* "/" placeholder picker for follow-up sequence subject/message fields. */
.followup-token-menu {
  position: absolute;
  z-index: 3000;
  background: var(--surface);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-md);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  overflow: hidden;
}
.followup-token-row {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 12px;
  cursor: pointer;
}
.followup-token-row:hover { background: var(--bg-tertiary); }
.followup-token-code {
  font-family: var(--font-mono, monospace);
  font-size: 13px;
  font-weight: 600;
  color: var(--primary);
}
.followup-token-hint {
  font-size: 12px;
  color: var(--text-tertiary);
}

/* === Communications: compose tabs, composer, thread list, channel badges
   (both apps: AE portal + admin dashboard lead modals) === */
.compose-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.compose-tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
  margin-bottom: -1px;
}
.compose-tab:hover { color: var(--text-primary); }
.compose-tab.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}
.email-compose {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.email-compose-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.email-compose-hint {
  font-size: 12px;
  color: var(--text-secondary);
  margin: 2px 0 0;
}

/* Bold/Italic/Underline toolbar above email body fields (compose panel +
   follow-up sequence email steps) -- wraps the textarea selection in the
   markdown-ish syntax formatEmailBodyHtml() parses server-side. */
.email-format-toolbar {
  display: flex;
  gap: 4px;
  margin-bottom: -4px;
}
.email-format-toolbar button {
  width: 28px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm, 6px);
  background: var(--surface);
  color: var(--text-primary);
  font-size: 13px;
  cursor: pointer;
}
.email-format-toolbar button:hover { background: var(--bg-tertiary); }
.email-thread-list {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Cap the feed height so a long history scrolls inside its own box instead
     of stretching the whole Communications card down the page. */
  max-height: 360px;
  overflow-y: auto;
}
.email-thread-list:empty { margin: 0; }
.email-thread-item {
  padding: 10px 12px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-subtle, var(--border));
  border-radius: var(--radius-md);
}
.email-thread-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.email-subject { font-weight: 600; font-size: 14px; }
.email-dir {
  font-size: 11px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: var(--radius-full);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.email-dir-sent { background: var(--surface-active, var(--bg-tertiary)); color: var(--primary); }
/* Scoped under .email-thread-head (the only place this component renders --
   see renderEmailItem in ae-portal.js/admin.js) rather than bare .channel-
   badge: both admin-dashboard/styles.css and ae-portal/styles.css ALSO
   define an unrelated, differently-styled .channel-badge (solid background +
   white text, used for a totally different activity-timeline badge with
   channel-email/channel-linkedin/etc. modifiers -- no "badge-" infix).
   That one loads after design-system.css, so at equal specificity its
   `color: white` silently won over every rule below, no matter what color
   was set here -- the reported bug wasn't really a contrast miscalibration,
   it was this collision. The extra ".email-thread-head" ancestor gives
   these rules higher specificity so they always win regardless of load
   order, without renaming either component's classes. */
.email-thread-head .channel-badge {
  font-size: 11px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: var(--radius-full);
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.email-thread-head .channel-badge-linkedin { background: rgba(10, 102, 194, 0.12); color: #0A66C2; }
.email-thread-head .channel-badge-instagram { background: rgba(214, 41, 118, 0.12); color: #C13584; }
.email-thread-head .channel-badge-phone { background: rgba(52, 199, 89, 0.14); color: #1a8a3e; }
.email-thread-head .channel-badge-email { background: rgba(10, 132, 255, 0.12); color: #0A84FF; }
.glc-call-btn {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 0; padding: 3px 10px;
  font-size: 12px; font-weight: 600; line-height: 1.5;
  color: #2FA84F; background: rgba(52, 199, 89, 0.12);
  border: 1px solid rgba(52, 199, 89, 0.35); border-radius: var(--radius-full);
  cursor: pointer; vertical-align: middle;
}
.glc-call-btn:hover { background: rgba(52, 199, 89, 0.22); }

/* AI call summary block in the Communications feed */
.call-ai-summary {
  margin: 8px 0 4px;
  padding: 10px 12px;
  background: rgba(94, 92, 230, 0.08);
  border: 1px solid rgba(94, 92, 230, 0.22);
  border-radius: 10px;
}
.call-ai-summary p { margin: 6px 0 0; font-size: 13px; line-height: 1.5; white-space: pre-line; }
.call-outcome-chip {
  display: inline-block;
  padding: 2px 9px;
  border-radius: var(--radius-full, 999px);
  font-size: 11px;
  font-weight: 700;
  text-transform: capitalize;
  background: rgba(127, 127, 127, 0.15);
  color: inherit;
}
.call-outcome-interested { background: rgba(52, 199, 89, 0.16); color: #1a8a3e; }
.call-outcome-not_interested { background: rgba(255, 69, 58, 0.14); color: #c62d23; }
.call-outcome-callback { background: rgba(255, 159, 10, 0.16); color: #b06a00; }
.call-outcome-voicemail { background: rgba(94, 92, 230, 0.14); color: #4a48b0; }

.call-recording { width: 100%; height: 34px; margin-top: 8px; }
.call-transcript { margin-top: 6px; }
.call-transcript > summary { font-size: 12px; color: var(--primary); cursor: pointer; list-style: none; }
.call-transcript > summary::-webkit-details-marker { display: none; }
.call-transcript > summary:hover { text-decoration: underline; }
.call-transcript > p { font-size: 13px; line-height: 1.5; margin: 6px 0 0; color: var(--text-secondary); white-space: pre-wrap; }
.email-participants { font-size: 12px; color: var(--text-secondary); margin-top: 3px; }
.email-snippet { font-size: 13px; line-height: 1.45; margin: 6px 0 0; color: var(--text-primary); white-space: pre-wrap; }
.email-open-link { font-size: 12px; color: var(--primary); text-decoration: none; display: inline-block; margin-top: 6px; }
.email-open-link:hover { text-decoration: underline; }
/* Sits at the far right of .email-thread-head (a flex row) -- margin-left:
   auto pushes it to the top-right corner of the thread item regardless of
   how many badges/labels precede it. */
.email-reply-btn {
  margin-left: auto;
  font-size: 12px;
  font-weight: 600;
  color: var(--primary);
  background: var(--surface);
  border: 1px solid var(--primary);
  border-radius: var(--radius-md);
  padding: 4px 10px;
  cursor: pointer;
  white-space: nowrap;
}
.email-reply-btn:hover { background: var(--primary); color: var(--text-inverse, #fff); }

/* Shown above the compose box after clicking "Reply" on a specific logged
   email -- cancelling it (the × button) drops back to sending a new,
   unthreaded email instead. */
.reply-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-md);
  font-size: 12px;
  color: var(--text-secondary);
}
.reply-banner button {
  background: none;
  border: none;
  font-size: 16px;
  line-height: 1;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 0 2px;
}
.reply-banner button:hover { color: var(--text-primary); }

/* ---- Spam-risk linter (email composer + follow-up sequence steps) ---- */
.spam-linter { margin: 6px 0 2px; }
.spam-linter:empty { display: none; }
.spam-lint-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  background: var(--bg-tertiary);
  color: var(--text-secondary);
}
.spam-lint-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-tertiary);
  flex: 0 0 auto;
}
.spam-lint-good .spam-lint-dot { background: var(--success); }
.spam-lint-warn .spam-lint-dot { background: var(--warning); }
.spam-lint-risk .spam-lint-dot { background: var(--danger); }
.spam-lint-good { color: var(--success); }
.spam-lint-warn { color: var(--warning); }
.spam-lint-risk { color: var(--danger); }
.spam-lint-issues {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.spam-lint-issue {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-secondary);
  padding-left: 16px;
  position: relative;
}
.spam-lint-issue::before {
  content: '•';
  position: absolute;
  left: 4px;
  color: var(--text-tertiary);
}
.spam-lint-issue.sev-high::before { content: '⚠'; left: 2px; color: var(--danger); }
.spam-lint-issue.sev-medium::before { content: '•'; color: var(--warning); }
.spam-lint-note {
  font-size: 11px;
  color: var(--text-tertiary);
  margin: 6px 0 0;
  font-style: italic;
}
/* Compact variant inside a follow-up sequence step. */
.spam-linter-compact { margin: 4px 0 0; }
.spam-linter-compact .spam-lint-badge { padding: 2px 8px; font-size: 11px; }
.spam-linter-compact .spam-lint-issue { font-size: 11px; }

/* ---- AI copy rewrite button (composer + sequence steps) ---- */
.ai-rewrite-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.ai-rewrite-btn:not(:disabled):hover {
  border-color: var(--primary);
  color: var(--primary);
}
.ai-rewrite-btn:disabled { opacity: 0.6; cursor: default; }
.followup-step-actions { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 6px; }

/* ---- Spintax variations (follow-up sequence step) ---- */
.followup-variations {
  margin-top: 8px;
  padding: 10px;
  border: 1px dashed var(--border-light);
  border-radius: var(--radius-md);
  background: var(--bg-tertiary);
}
.followup-variations-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 8px;
}
.followup-variation { margin-bottom: 8px; }
.followup-variation:last-child { margin-bottom: 0; }
.followup-variation textarea {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  font-size: 13px;
}

/* "Needs New Contact" badge — a rep flagged this lead's contact info as wrong
   and it's waiting on an admin re-enrichment (admin lead cards). */
.needs-recontact-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: #92400e;
  background: #fef3c7;
  border: 1px solid #fcd34d;
}
[data-theme="dark"] .needs-recontact-badge {
  color: #fcd34d;
  background: rgba(252, 211, 77, 0.12);
  border-color: rgba(252, 211, 77, 0.4);
}

/* --- Dark-mode polish pass, 2026-07-16 (first user visual QA of dark mode).
   Same current values in both apps (verified before centralizing), additive
   only -- light mode is untouched in every rule below. --- */

/* Sticky leads-section header bar: was a raw rgba(245,245,247,...) (near-
   white), not a token, so it stayed bright in dark mode regardless of the
   token layer. Same fixed blur-glass technique, dark-appropriate value. */
[data-theme="dark"] #leads-section .sticky-header-wrapper {
  background: rgba(22, 22, 26, 0.72);
}

/* .glc-score (the "82/100" pill on every lead card, both apps): raw
   rgba(255,255,255,...) background+border, while its text color
   (var(--gray-900)) correctly went light in dark mode -- light text on a
   background that stayed bright white is why it read as "illegible and too
   bright." Border/shadow follow the same dark-glass treatment used
   elsewhere in this file. */
[data-theme="dark"] .glc-score {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06), 0 4px 10px -6px rgba(0,0,0,0.4);
}

/* Body's ambient background wash: 4 soft on-brand-colored (cyan/teal/blue/
   amber) radial blobs at ~6-10% opacity over var(--bg-primary). Barely
   perceptible in light mode, but the same absolute opacity against a
   near-black dark background reads as a visible color tint ("feels a
   little too green") -- swapped to pure white-tinted blobs in dark mode so
   the same soft depth/texture stays, just monochromatic (shades of
   black/gray, matching the rest of the dark theme) instead of hued. */
[data-theme="dark"] body {
  background:
    radial-gradient(circle at 12% -8%,  rgba(255,255,255,0.035), transparent 42%),
    radial-gradient(circle at 88% 8%,   rgba(255,255,255,0.03), transparent 40%),
    radial-gradient(circle at 78% 108%, rgba(255,255,255,0.035), transparent 45%),
    radial-gradient(circle at 20% 100%, rgba(255,255,255,0.02), transparent 42%),
    var(--bg-primary);
  background-attachment: fixed;
}

/* ============================================================
   Voice Copilot widget (mounted by ae-portal/voice-widget.js)
   Sits above the FAB corner; theme-aware via design tokens.
   ============================================================ */
.copilot-panel {
  position: fixed;
  right: 24px;
  bottom: 96px;
  width: 340px;
  max-width: calc(100vw - 32px);
  background: var(--bg-secondary);
  border: 1px solid var(--border-light);
  border-radius: 18px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.28);
  z-index: 1200;
  display: none;
  flex-direction: column;
  overflow: hidden;
  font-family: inherit;
}
.copilot-panel.open { display: flex; }
.copilot-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
}
.copilot-title {
  display: flex; align-items: center; gap: 8px;
  font-weight: 650; font-size: 14px; color: var(--text-primary);
}
.copilot-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--text-tertiary);
  transition: background 0.2s ease, box-shadow 0.2s ease;
}
.copilot-dot[data-state="listening"] { background: #34C759; box-shadow: 0 0 0 4px rgba(52,199,89,0.18); }
.copilot-dot[data-state="thinking"]  { background: var(--accent-yellow); box-shadow: 0 0 0 4px rgba(255,184,0,0.18); }
.copilot-dot[data-state="speaking"]  { background: #5B8DEF; box-shadow: 0 0 0 4px rgba(91,141,239,0.18); }
.copilot-x {
  border: none; background: transparent; cursor: pointer;
  font-size: 20px; line-height: 1; color: var(--text-tertiary);
  width: 28px; height: 28px; border-radius: 8px;
}
.copilot-x:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.copilot-transcript {
  padding: 12px 14px;
  min-height: 96px; max-height: 260px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 8px;
}
.copilot-msg {
  max-width: 85%;
  padding: 8px 11px; border-radius: 13px;
  font-size: 13px; line-height: 1.4; word-wrap: break-word;
}
.copilot-user {
  align-self: flex-end;
  background: linear-gradient(135deg, #7C5CFF, #5B8DEF);
  color: #fff; border-bottom-right-radius: 4px;
}
.copilot-agent {
  align-self: flex-start;
  background: var(--bg-tertiary); color: var(--text-primary);
  border-bottom-left-radius: 4px;
}
.copilot-status {
  padding: 8px 14px; font-size: 12px; color: var(--text-secondary);
  border-top: 1px solid var(--border-subtle);
}
.copilot-controls {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  padding: 12px 14px 16px;
}
.copilot-mic {
  width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer;
  background: linear-gradient(135deg, #7C5CFF, #5B8DEF); color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 18px rgba(124,92,255,0.35);
  transition: transform 0.12s ease, box-shadow 0.2s ease;
}
.copilot-mic svg { width: 24px; height: 24px; }
.copilot-mic:hover { transform: scale(1.05); }
.copilot-mic.recording {
  background: #FF3B30;
  box-shadow: 0 0 0 0 rgba(255,59,48,0.5);
  animation: copilot-pulse 1.6s infinite;
}
@keyframes copilot-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(255,59,48,0.45); }
  70%  { box-shadow: 0 0 0 14px rgba(255,59,48,0); }
  100% { box-shadow: 0 0 0 0 rgba(255,59,48,0); }
}
.copilot-mute {
  border: 1px solid var(--border-medium); background: var(--bg-secondary);
  color: var(--text-secondary); border-radius: 999px;
  padding: 8px 16px; font-size: 13px; cursor: pointer;
  align-items: center;
}
.copilot-mute:hover { background: var(--bg-tertiary); color: var(--text-primary); }

/* Non-callable international phone tag (shown where a Call button can't go —
   Telnyx only completes US/Canada +1 numbers). */
.intl-phone-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px; border-radius: 999px;
  background: var(--bg-tertiary); color: var(--text-secondary);
  border: 1px solid var(--border-light);
  font-size: 12px; font-weight: 600; white-space: nowrap;
}

/* ============================================================
   Moved here verbatim from ae-portal/design-system.css. That file is
   regenerated from this one on every deploy (see deploy.yml's `cp` step),
   so rules authored there are silently dropped. Author them here instead.
   ============================================================ */

/* Local-time pill on lead cards + detail (timezone-aware "callable now"). Kept
   legible on both themes — dark text on a tint in light mode, light text in dark
   mode — instead of the old yellow-text-on-yellow-fill that couldn't be read. */
.lead-localtime-badge {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 8px; padding: 2px 9px;
  font-size: 12px; font-weight: 600; line-height: 1.6;
  border-radius: var(--radius-full); border: 1px solid transparent;
  white-space: nowrap; vertical-align: middle;
}
.lead-localtime-badge.is-callable { color: #16793a; background: rgba(52, 199, 89, 0.14); border-color: rgba(52, 199, 89, 0.32); }
.lead-localtime-badge.is-outside  { color: #8a5200; background: rgba(255, 149, 0, 0.16); border-color: rgba(255, 149, 0, 0.4); }
[data-theme="dark"] .lead-localtime-badge.is-callable { color: #5bd98a; background: rgba(52, 199, 89, 0.18); border-color: rgba(52, 199, 89, 0.42); }
[data-theme="dark"] .lead-localtime-badge.is-outside  { color: #ffc04d; background: rgba(255, 149, 0, 0.2); border-color: rgba(255, 149, 0, 0.46); }
/* "Accept to reveal contact" note shown in the lead-detail modal until accepted. */
.contact-locked-note {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-radius: 10px;
  font-size: 14px; color: var(--text-secondary);
  background: rgba(127, 127, 127, 0.08); border: 1px solid rgba(127, 127, 127, 0.18);
}
.contact-locked-note svg { flex-shrink: 0; }

/* ============================================================================
   CUSTOM DROPDOWN (.mm-select) — enhances a native <select>, which stays in the
   DOM (hidden) so its value + change events keep driving all existing logic. A
   native <select>'s OPEN menu is OS-drawn and unstyleable; this replaces it with
   a themed trigger + menu. Wired up by each app's enhanceSelect() JS.
   ============================================================================ */
.mm-select { position: relative; display: inline-flex; vertical-align: middle; min-width: 130px; }
.mm-select > select { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }
.mm-select-trigger {
  display: inline-flex; align-items: center; gap: 8px; width: 100%; height: 38px; padding: 0 12px;
  font-family: inherit; font-size: 14px; font-weight: 500; color: var(--text-primary);
  background: var(--surface-elevated); border: 1px solid var(--border-medium); border-radius: var(--radius-md);
  cursor: pointer; white-space: nowrap;
  transition: border-color .15s var(--ease-standard, ease), box-shadow .15s ease, background .15s ease;
}
.mm-select-trigger:hover { background: var(--surface-hover); }
.mm-select-trigger .mm-select-label { flex: 1; text-align: left; overflow: hidden; text-overflow: ellipsis; }
.mm-select-trigger .mm-select-chev { flex: none; color: var(--text-tertiary); transition: transform .18s var(--ease-standard, ease); }
.mm-select.open .mm-select-trigger { border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 20%, transparent); }
.mm-select.open .mm-select-trigger .mm-select-chev { transform: rotate(180deg); }
.mm-select-menu {
  position: absolute; top: calc(100% + 6px); left: 0; min-width: 100%; z-index: 1000;
  background: var(--surface-elevated); border: 1px solid var(--border-light); border-radius: var(--radius-md);
  box-shadow: var(--shadow-md); padding: 6px; max-height: 320px; overflow-y: auto;
  opacity: 0; transform: translateY(-4px) scale(.98); transform-origin: top; pointer-events: none;
  transition: opacity .15s ease, transform .16s var(--ease-standard, ease);
}
.mm-select.open .mm-select-menu { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.mm-select-option {
  display: flex; align-items: center; gap: 8px; min-height: 34px; padding: 6px 10px; border-radius: var(--radius-sm);
  font-size: 13.5px; color: var(--text-primary); cursor: pointer; white-space: nowrap; user-select: none;
}
.mm-select-option:hover { background: var(--surface-hover); }
.mm-select-option[aria-selected="true"] { color: var(--primary); font-weight: 600; background: color-mix(in srgb, var(--primary) 8%, transparent); }
.mm-select-option .mm-select-check { margin-left: auto; color: var(--primary); opacity: 0; }
.mm-select-option[aria-selected="true"] .mm-select-check { opacity: 1; }

/* Collapse toggle: a chevron that ROTATES on expand, instead of swapping ▶/▼
   glyphs in JS. Markup carries .open when the section starts expanded. */
.activity-toggle { display: inline-flex; align-items: center; }
.activity-toggle svg { transition: transform .2s var(--ease-standard, ease); }
.activity-toggle.open svg { transform: rotate(90deg); }

/* ============================================================================
   Componentization utilities -- hoisted from repeated inline styles so the rule
   lives once and new markup inherits it. Rendering is identical to the inline
   versions they replace (verified property-for-property).
   ============================================================================ */
.mm-ico { vertical-align: -2px; }
.field-label { display: block; margin-bottom: 8px; font-weight: 500; }
.field-label-sm { font-size: 13px; font-weight: 600; color: var(--text-secondary); display: block; margin-bottom: 6px; }
/* Componentization pass 2 -- more hoisted utilities (identical rendering). */
.u-text-danger { color: var(--danger, #ff3b30); }
.u-text-tertiary { color: var(--text-tertiary); }
.u-text-accent { color: var(--primary); }
.u-row-end { display: flex; gap: 12px; justify-content: flex-end; }
.u-mb-16 { margin-bottom: 16px; }
.u-muted { font-size: 13px; color: var(--text-secondary); font-weight: normal; }
/* Componentization pass 4 -- more hoisted patterns (identical rendering). */
.code-chip { background: #f5f5f5; border: 1px solid #ddd; border-radius: 6px; padding: 4px 10px; font-size: 13px; font-family: monospace; font-weight: 600; }
.info-panel { margin-bottom: 20px; padding: 12px; background: var(--bg-tertiary); border-radius: var(--radius-md); }
.u-icon-inline { display: inline-block; vertical-align: middle; margin-right: 4px; color: var(--gray-500); }
.u-text-14 { font-size: 14px; color: #333; }
.u-sub-list { margin-top: 8px; padding-left: 20px; font-size: 13px; color: var(--text-secondary); }
.u-toggle-row { margin-top: 24px; cursor: pointer; user-select: none; }
/* Componentization pass 5 -- more hoisted patterns (identical rendering). */
.list-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 0; border-bottom: 1px solid #f0f0f0; }
.field-label-dark { font-size: 13px; font-weight: 600; color: #374151; display: block; margin-bottom: 6px; }
.u-text-tertiary-11 { color: var(--text-tertiary); font-size: 11px; }
/* Disabled controls: one rule instead of an inline opacity/cursor on each
   conditional button (they already carry the `disabled` attribute). */
button:disabled, .action-pill:disabled, .btn-secondary:disabled, .btn-primary:disabled, .btn-danger:disabled {
  opacity: 0.5; cursor: not-allowed;
}
