/* Simple CRM — application stylesheet.
   Layered on top of Bootstrap 5.3; overrides live here, never inline. */

/* Two accents, deliberately. --crm-accent is the brand blue and stays on fills,
   borders and chart-adjacent decoration, where WCAG text rules don't apply.
   --crm-accent-text is the same hue darkened for anything that carries text or
   sits behind text: #2a78d6 measures 4.42:1 on white (below the 4.5:1 AA
   minimum) and 3.91:1 on --crm-accent-subtle, while #2266bb measures 5.70:1 and
   5.05:1. Links are the bulk of every list in this app, so this matters.

   Same split for the outcome pair. --crm-teal is the chart/fill colour (also used
   by the MBR charts below); --crm-teal-text is a darkened partner for anything
   carrying text — the raw #0f9b8e measures 3.44:1 on white and fails AA, while
   #0a7a70 measures 5.21:1. --crm-red already measures 4.80:1 on white and passes,
   so it needs no separate text partner and is used directly by both. Teal/red
   (not Bootstrap's green/red) because red/green is indistinguishable to a
   deuteranope — see the MBR chart comment further down for the CVD check. */
:root,
[data-bs-theme="light"] {
  /* Semantic light-theme foundation. These values deliberately mirror the
     application's current Bootstrap 5.3 light appearance; Phase 1 only names
     the contract and does not opt any page into a different presentation. */
  --crm-canvas: #f8f9fa;
  --crm-surface: #fff;
  --crm-surface-elevated: #fff;
  --crm-text: #212529;
  --crm-text-muted: #6c757d;
  --crm-focus: #2266bb;

  /* Brand and semantic states. Positive/negative intentionally match
     Bootstrap success/danger. They do not replace the distinct teal/red
     outcome convention documented above. */
  --crm-accent: #2a78d6;
  --crm-accent-text: #2266bb;
  --crm-accent-subtle: #eaf2fc;
  --crm-positive: #198754;
  --crm-warning: #ffc107;
  --crm-negative: #dc3545;
  --crm-teal: #0f9b8e;
  --crm-teal-text: #0a7a70;
  --crm-red: #d03b3b;

  /* Color-vision-deficiency-safe categorical chart palette. Teal and
     vermillion must not represent unrelated categories beside the fixed
     won/lost teal/red series; use blue, amber and purple in mixed plots. */
  --crm-chart-blue: #2a78d6;
  --crm-chart-teal: #0f9b8e;
  --crm-chart-vermillion: #d55e00;
  --crm-chart-amber: #eda100;
  --crm-chart-purple: #4a3aa7;
  --crm-chart-grid: rgba(11, 11, 11, 0.08);
  --crm-chart-text: #6c757d;
  --crm-chart-tooltip-bg: #212529;
  --crm-chart-tooltip-text: #fff;

  --crm-radius: 0.5rem;
  --crm-border: rgba(11, 11, 11, 0.08);
  --crm-shadow-sm: 0 1px 2px rgba(11, 11, 11, 0.05);
  --crm-shadow: 0 1px 3px rgba(11, 11, 11, 0.07), 0 4px 12px rgba(11, 11, 11, 0.04);
}

[data-bs-theme="dark"] {
  color-scheme: dark;
  --crm-canvas: #15191d;
  --crm-surface: #1d2329;
  --crm-surface-elevated: #252c33;
  --crm-text: #f1f3f5;
  --crm-text-muted: #adb5bd;
  --crm-focus: #8bb9f2;
  --crm-accent: #6ea8fe;
  --crm-accent-text: #8bb9f2;
  --crm-accent-subtle: #24364d;
  --crm-positive: #75b798;
  --crm-warning: #ffda6a;
  --crm-negative: #ea868f;
  /* Outcome values stay semantically distinct from Bootstrap state colors. */
  --crm-teal: #20b7aa;
  --crm-teal-text: #5fd5ca;
  --crm-red: #d95757;
  --crm-chart-blue: #6ea8fe;
  --crm-chart-teal: #20b7aa;
  --crm-chart-vermillion: #ff7a2f;
  --crm-chart-amber: #ffcf5c;
  --crm-chart-purple: #a89bea;
  --crm-chart-grid: rgba(255, 255, 255, 0.14);
  --crm-chart-text: #ced4da;
  --crm-chart-tooltip-bg: #f1f3f5;
  --crm-chart-tooltip-text: #15191d;
  --crm-border: rgba(255, 255, 255, 0.14);
  --crm-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.28);
  --crm-shadow: 0 1px 3px rgba(0, 0, 0, 0.35), 0 4px 12px rgba(0, 0, 0, 0.2);

  --bs-body-color: var(--crm-text);
  --bs-body-bg: var(--crm-canvas);
  --bs-secondary-color: var(--crm-text-muted);
  --bs-tertiary-bg: var(--crm-canvas);
  --bs-border-color: var(--crm-border);
  --bs-link-color: var(--crm-accent-text);
  --bs-link-hover-color: #b8d4f7;
  --bs-dropdown-color: var(--crm-text);
  --bs-dropdown-bg: var(--crm-surface-elevated);
  --bs-dropdown-border-color: var(--crm-border);
  --bs-dropdown-link-color: var(--crm-text);
  --bs-dropdown-link-hover-color: var(--crm-text);
  --bs-dropdown-link-hover-bg: #303942;
  --bs-dropdown-link-active-color: #fff;
  --bs-dropdown-link-active-bg: #295f9e;
  --bs-dropdown-header-color: var(--crm-text-muted);
}

html,
body { min-height: 100%; }
body {
  background-color: var(--crm-canvas);
  color: var(--crm-text);
  font-size: 0.9375rem;
}
h1,
.h1 { font-size: 1.5rem; }

/* Buttons and links pick up the accent. Filled buttons use the text accent too:
   their label is white on that fill, so it is bound by the same 4.5:1 rule.
   Hover/active shift one and two steps darker again to keep the state visible. */
.btn-primary {
  --bs-btn-bg: var(--crm-accent-text);
  --bs-btn-border-color: var(--crm-accent-text);
  --bs-btn-hover-bg: #1d5aa7;
  --bs-btn-hover-border-color: #1d5aa7;
  --bs-btn-active-bg: #174b8b;
  --bs-btn-active-border-color: #174b8b;
}
.btn-outline-primary {
  --bs-btn-color: var(--crm-accent-text);
  --bs-btn-border-color: var(--crm-accent-text);
  --bs-btn-hover-bg: var(--crm-accent-text);
  --bs-btn-hover-border-color: var(--crm-accent-text);
  --bs-btn-active-bg: #1d5aa7;
  --bs-btn-active-border-color: #1d5aa7;
}
a { color: var(--crm-accent-text); }

[data-bs-theme="dark"] .btn-primary {
  --bs-btn-bg: #2266bb;
  --bs-btn-border-color: #2266bb;
  --bs-btn-hover-bg: #2f78ce;
  --bs-btn-hover-border-color: #2f78ce;
  --bs-btn-active-bg: #3d82d5;
  --bs-btn-active-border-color: #3d82d5;
}
[data-bs-theme="dark"] .btn-outline-primary {
  --bs-btn-color: var(--crm-accent-text);
  --bs-btn-border-color: #6ea8fe;
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: #2266bb;
  --bs-btn-hover-border-color: #6ea8fe;
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: #2f78ce;
  --bs-btn-active-border-color: #8bb9f2;
}

/* Outcome badges (won/lost) — see templates/_outcome_badge.html, the single place
   that decides won vs. lost styling app-wide. */
.badge-outcome-won { background-color: var(--crm-teal-text); color: #fff; }
.badge-outcome-lost { background-color: var(--crm-red); color: #fff; }
.text-outcome-won { color: var(--crm-teal-text) !important; }
.text-outcome-lost { color: var(--crm-red) !important; }
[data-bs-theme="dark"] .badge-outcome-won { background-color: #0a7a70; }
.btn-outcome-won {
  --bs-btn-color: #fff;
  --bs-btn-bg: #0a7a70;
  --bs-btn-border-color: #0a7a70;
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: #08675f;
  --bs-btn-hover-border-color: #08675f;
}
.btn-outcome-lost {
  --bs-btn-color: #fff;
  --bs-btn-bg: var(--crm-red);
  --bs-btn-border-color: var(--crm-red);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: #af3030;
  --bs-btn-hover-border-color: #af3030;
}
/* Outline partners for the pair above, for the places where Won/Lost is one action
   among several outline buttons (the opportunity detail header) rather than the
   primary commit button. They carry their label in the outcome colour, so they take
   the text-safe tokens: --crm-teal-text (#0a7a70, 5.21:1 on white) rather than the
   raw --crm-teal (3.44:1, fails AA), and --crm-red (4.80:1, already passes). Same
   fills/text split as .btn-outline-primary above. */
.btn-outline-outcome-won {
  --bs-btn-color: var(--crm-teal-text);
  --bs-btn-border-color: var(--crm-teal-text);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--crm-teal-text);
  --bs-btn-hover-border-color: var(--crm-teal-text);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: #08675f;
  --bs-btn-active-border-color: #08675f;
}
.btn-outline-outcome-lost {
  --bs-btn-color: var(--crm-red);
  --bs-btn-border-color: var(--crm-red);
  --bs-btn-hover-color: #fff;
  --bs-btn-hover-bg: var(--crm-red);
  --bs-btn-hover-border-color: var(--crm-red);
  --bs-btn-active-color: #fff;
  --bs-btn-active-bg: #af3030;
  --bs-btn-active-border-color: #af3030;
}
/* Dark theme: the light-theme text partners are too dark on the dark surfaces, so
   the label takes the lighter --crm-teal-text (#5fd5ca) / --crm-red (#d95757) and
   the hover fill keeps the darker shade with white text. */
[data-bs-theme="dark"] .btn-outline-outcome-won {
  --bs-btn-color: var(--crm-teal-text);
  --bs-btn-border-color: var(--crm-teal);
  --bs-btn-hover-bg: #0a7a70;
  --bs-btn-hover-border-color: var(--crm-teal);
  --bs-btn-active-bg: #08675f;
  --bs-btn-active-border-color: var(--crm-teal-text);
}
[data-bs-theme="dark"] .btn-outline-outcome-lost {
  --bs-btn-color: var(--crm-red);
  --bs-btn-border-color: var(--crm-red);
  --bs-btn-hover-bg: #af3030;
  --bs-btn-hover-border-color: var(--crm-red);
  --bs-btn-active-bg: #932828;
  --bs-btn-active-border-color: var(--crm-red);
}
[data-bs-theme="dark"] .table-light {
  --bs-table-bg: var(--crm-surface-elevated);
  --bs-table-color: var(--crm-text);
  --bs-table-border-color: var(--crm-border);
}

.crm-chart-frame {
  position: relative;
  min-height: 15rem;
}
.crm-report-table {
  font-variant-numeric: tabular-nums;
}
.crm-report-table th,
.crm-report-table td { vertical-align: middle; }
.crm-report-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  white-space: nowrap;
}
.accordion-body:has(.crm-report-table) { overflow-x: auto; }

/* Application shell. Desktop width changes are immediate: animating layout here
   would repeatedly reflow every table and chart on the page. */
.crm-shell { min-height: 100vh; }
.crm-shell-body {
  min-width: 0;
  min-height: 100vh;
  margin-left: 14rem;
}
[data-crm-sidebar="collapsed"] .crm-shell-body { margin-left: 3.5rem; }
.crm-shell-anonymous .crm-shell-body { margin-left: 0; }

.crm-sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 1040;
  width: 14rem;
  overflow: hidden;
  background-color: var(--crm-surface);
  border-right: 1px solid var(--crm-border);
  box-shadow: var(--crm-shadow-sm);
}
[data-crm-sidebar="collapsed"] .crm-sidebar { width: 3.5rem; }
.crm-sidebar-header {
  display: flex;
  align-items: center;
  height: 3.25rem;
  padding: 0.5rem;
  border-bottom: 1px solid var(--crm-border);
}
.crm-sidebar-brand {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 0.6rem;
  color: var(--crm-accent-text);
  font-size: 1rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  text-decoration: none;
}
.crm-brand-mark {
  display: inline-flex;
  flex: 0 0 2.5rem;
  width: 2.5rem;
  height: 2.25rem;
  align-items: center;
  justify-content: center;
  border-radius: calc(var(--crm-radius) - 0.125rem);
  background-color: var(--crm-accent-subtle);
  color: var(--crm-accent-text);
  font-size: 0.72rem;
  font-weight: 750;
  letter-spacing: 0.04em;
}
.crm-sidebar-close {
  display: none;
  margin-left: auto;
}
.crm-sidebar-nav {
  height: calc(100vh - 3.25rem);
  overflow-x: hidden;
  overflow-y: auto;
  padding: 0.65rem 0.5rem 1rem;
}
.crm-sidebar-link {
  display: flex;
  align-items: center;
  min-height: 2.35rem;
  gap: 0.65rem;
  padding: 0.45rem 0.65rem;
  border-radius: calc(var(--crm-radius) - 0.125rem);
  color: var(--crm-text-muted);
  font-size: 0.9rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.crm-sidebar-link:hover {
  color: var(--crm-text);
  background-color: var(--crm-canvas);
}
.crm-sidebar-link.active {
  color: var(--crm-accent-text);
  background-color: var(--crm-accent-subtle);
  font-weight: 650;
}
.crm-sidebar-link .crm-icon { flex: 0 0 auto; }
.crm-nav-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-crm-sidebar="collapsed"] .crm-sidebar .crm-nav-text { display: none; }
[data-crm-sidebar="collapsed"] .crm-sidebar-link {
  justify-content: center;
  padding-inline: 0;
}
[data-crm-sidebar="collapsed"] .crm-sidebar-link .crm-icon {
  width: 1.375rem;
  height: 1.375rem;
}
.crm-sidebar-divider {
  margin: 0.55rem 0.4rem;
  border-top: 1px solid var(--crm-border);
}
.crm-sidebar-section {
  padding: 0.1rem 0.65rem 0.25rem;
  color: var(--crm-text-muted);
  font-size: 0.68rem;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.crm-sidebar-backdrop { display: none; }

.crm-topbar {
  position: sticky;
  top: 0;
  z-index: 1030;
  display: flex;
  min-height: 3.25rem;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.45rem 1rem;
  background-color: var(--crm-surface);
  border-bottom: 1px solid var(--crm-border);
  box-shadow: var(--crm-shadow-sm);
}
.crm-topbar-start,
.crm-topbar-tools,
.crm-global-search,
.crm-theme-selector,
.crm-user-toggle,
.crm-menu-label,
.crm-menu-item {
  display: flex;
  align-items: center;
}
.crm-topbar-start { min-width: 0; }
.crm-topbar-tools {
  min-width: 0;
  gap: 0.65rem;
  margin-left: auto;
}
.crm-topbar-brand {
  display: none;
  margin-left: 0.6rem;
  color: var(--crm-accent-text);
  font-weight: 650;
  text-decoration: none;
  white-space: nowrap;
}
.crm-topbar-brand-anonymous {
  display: inline-block;
  margin-left: 0;
}
.crm-icon-button,
.crm-sidebar-close,
.crm-user-toggle {
  border: 1px solid transparent;
  background: transparent;
  color: var(--crm-text-muted);
}
.crm-icon-button,
.crm-sidebar-close {
  width: 2.25rem;
  height: 2.25rem;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: calc(var(--crm-radius) - 0.125rem);
}
.crm-icon-button { display: inline-flex; }
.crm-icon-button:hover,
.crm-sidebar-close:hover,
.crm-user-toggle:hover {
  color: var(--crm-text);
  background-color: var(--crm-canvas);
  border-color: var(--crm-border);
}
.crm-theme-selector {
  flex: 0 0 auto;
  padding: 0.125rem;
  border: 1px solid var(--crm-border);
  border-radius: var(--crm-radius);
}
.crm-theme-selector .crm-icon-button {
  width: 2rem;
  height: 1.85rem;
}
.crm-theme-selector .crm-icon-button.active {
  color: var(--crm-accent-text);
  background-color: var(--crm-accent-subtle);
}
.crm-sidebar-toggle .crm-toggle-mobile { display: none; }
/* Only the narrow tier collapses search behind a button; above 576px the box is
   inline and this control does not exist. */
.crm-search-toggle { display: none; }
.crm-global-search {
  position: relative;
  min-width: 10rem;
}
.crm-global-search form { width: 100%; }
.crm-global-search #globalSearchInput {
  width: min(22rem, 32vw) !important;
  padding-left: 2rem;
  background-color: var(--crm-canvas);
}
.crm-search-icon {
  position: absolute;
  z-index: 2;
  left: 0.55rem;
  width: 1rem;
  height: 1rem;
  color: var(--crm-text-muted);
  pointer-events: none;
}
.crm-global-search .dropdown-menu {
  width: 100%;
  max-height: min(28rem, calc(100vh - 4.5rem));
  overflow-y: auto;
}
.crm-user-toggle {
  max-width: 15rem;
  gap: 0.4rem;
  padding: 0.35rem 0.45rem;
  border-radius: calc(var(--crm-radius) - 0.125rem);
}
.crm-user-name {
  min-width: 0;
  overflow: hidden;
  color: var(--crm-text);
  font-size: 0.875rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crm-user-menu .dropdown-menu { min-width: 18rem; }
.crm-menu-identity { padding: 0.5rem 1rem; }
.crm-menu-identity-name {
  font-weight: 650;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.crm-menu-identity-meta {
  color: var(--crm-text-muted);
  font-size: 0.8rem;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.crm-menu-form { padding: 0.5rem 1rem; }
.crm-menu-label {
  gap: 0.5rem;
  margin-bottom: 0.45rem;
  color: var(--crm-text-muted);
  font-size: 0.8rem;
}
.crm-menu-item {
  gap: 0.6rem;
  white-space: normal;
}

/* Every shell SVG is a local CSS mask so it follows currentColor. */
.crm-icon {
  display: inline-block;
  width: 1.25rem;
  height: 1.25rem;
  flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
}
.crm-icon-dashboard { -webkit-mask-image: url("../icons/dashboard.afac95b552f5.svg"); mask-image: url("../icons/dashboard.afac95b552f5.svg"); }
.crm-icon-companies { -webkit-mask-image: url("../icons/companies.3aed9c5cc8cc.svg"); mask-image: url("../icons/companies.3aed9c5cc8cc.svg"); }
.crm-icon-contacts { -webkit-mask-image: url("../icons/contacts.5e82beedebde.svg"); mask-image: url("../icons/contacts.5e82beedebde.svg"); }
.crm-icon-opportunities { -webkit-mask-image: url("../icons/opportunities.054cf969a165.svg"); mask-image: url("../icons/opportunities.054cf969a165.svg"); }
.crm-icon-marketing { -webkit-mask-image: url("../icons/marketing.cc288fd1d2dc.svg"); mask-image: url("../icons/marketing.cc288fd1d2dc.svg"); }
.crm-icon-reports { -webkit-mask-image: url("../icons/reports.fbc113a1014b.svg"); mask-image: url("../icons/reports.fbc113a1014b.svg"); }
.crm-icon-red-flags { -webkit-mask-image: url("../icons/red-flags.e892e2644ac6.svg"); mask-image: url("../icons/red-flags.e892e2644ac6.svg"); }
.crm-icon-changes { -webkit-mask-image: url("../icons/changes.81305a1a472e.svg"); mask-image: url("../icons/changes.81305a1a472e.svg"); }
.crm-icon-activity { -webkit-mask-image: url("../icons/activity.9a602e410a48.svg"); mask-image: url("../icons/activity.9a602e410a48.svg"); }
.crm-icon-import-export { -webkit-mask-image: url("../icons/import-export.f6233ade6a97.svg"); mask-image: url("../icons/import-export.f6233ade6a97.svg"); }
.crm-icon-admin { -webkit-mask-image: url("../icons/admin.51bfeef26f5c.svg"); mask-image: url("../icons/admin.51bfeef26f5c.svg"); }
.crm-icon-menu { -webkit-mask-image: url("../icons/menu.6fe8728d16cb.svg"); mask-image: url("../icons/menu.6fe8728d16cb.svg"); }
.crm-icon-sidebar-collapse { -webkit-mask-image: url("../icons/sidebar-collapse.c0979e1a666e.svg"); mask-image: url("../icons/sidebar-collapse.c0979e1a666e.svg"); }
.crm-icon-search { -webkit-mask-image: url("../icons/search.193bc32fdc05.svg"); mask-image: url("../icons/search.193bc32fdc05.svg"); }
.crm-icon-theme-system { -webkit-mask-image: url("../icons/theme-system.3837594b67d3.svg"); mask-image: url("../icons/theme-system.3837594b67d3.svg"); }
.crm-icon-theme-light { -webkit-mask-image: url("../icons/theme-light.ec99e8f0da29.svg"); mask-image: url("../icons/theme-light.ec99e8f0da29.svg"); }
.crm-icon-theme-dark { -webkit-mask-image: url("../icons/theme-dark.c5f9c3dff993.svg"); mask-image: url("../icons/theme-dark.c5f9c3dff993.svg"); }
.crm-icon-user { -webkit-mask-image: url("../icons/user.6807b787f930.svg"); mask-image: url("../icons/user.6807b787f930.svg"); }
.crm-icon-language { -webkit-mask-image: url("../icons/language.721537a2f9ca.svg"); mask-image: url("../icons/language.721537a2f9ca.svg"); }
.crm-icon-feedback { -webkit-mask-image: url("../icons/feedback.07dba42fdf23.svg"); mask-image: url("../icons/feedback.07dba42fdf23.svg"); }
.crm-icon-logout { -webkit-mask-image: url("../icons/logout.aa2872f5c4c1.svg"); mask-image: url("../icons/logout.aa2872f5c4c1.svg"); }
.crm-icon-chevron-down { -webkit-mask-image: url("../icons/chevron-down.75ce04843616.svg"); mask-image: url("../icons/chevron-down.75ce04843616.svg"); }
.crm-icon-close { -webkit-mask-image: url("../icons/close.eef83c156d86.svg"); mask-image: url("../icons/close.eef83c156d86.svg"); }

@media (max-width: 991.98px) {
  .crm-shell-body,
  [data-crm-sidebar="collapsed"] .crm-shell-body { margin-left: 0; }
  .crm-sidebar,
  [data-crm-sidebar="collapsed"] .crm-sidebar {
    z-index: 1050;
    width: min(18rem, calc(100vw - 3rem));
    visibility: hidden;
  }
  [data-crm-sidebar-mobile="open"] .crm-sidebar { visibility: visible; }
  [data-crm-sidebar="collapsed"] .crm-sidebar .crm-nav-text { display: block; }
  [data-crm-sidebar="collapsed"] .crm-sidebar-link {
    justify-content: flex-start;
    padding-inline: 0.65rem;
  }
  [data-crm-sidebar="collapsed"] .crm-sidebar-link .crm-icon {
    width: 1.25rem;
    height: 1.25rem;
  }
  .crm-sidebar-close { display: inline-flex; }
  .crm-sidebar-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1045;
    display: none;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: rgba(0, 0, 0, 0.55);
  }
  [data-crm-sidebar-mobile="open"] .crm-sidebar-backdrop { display: block; }
  [data-crm-sidebar-mobile="open"] body { overflow: hidden; }
  .crm-sidebar-toggle .crm-toggle-mobile { display: inline-block; }
  .crm-toggle-desktop { display: none; }
  .crm-topbar { padding-inline: 0.65rem; }
  .crm-topbar-brand { display: inline-block; }
  .crm-global-search #globalSearchInput { width: min(17rem, 35vw) !important; }
  .crm-user-name { max-width: 8rem; }
}

@media (max-width: 575.98px) {
  .crm-topbar { gap: 0.35rem; }
  .crm-topbar-tools { gap: 0.35rem; }
  .crm-topbar-brand { display: none; }
  .crm-topbar-brand-anonymous { display: inline-block; }

  /* Search collapses to a button and expands into its own full-width row beneath the
     bar. Inline it was ~9.5rem — about twelve characters — while competing with the
     three theme buttons for the same strip. The row is positioned rather than added
     to the flow so opening it never reflows the page behind it. */
  .crm-search-toggle { display: inline-flex; }
  .crm-global-search { display: none; }
  [data-crm-search="open"] .crm-global-search {
    position: absolute;
    display: block;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1035;
    min-width: 0;
    padding: 0.4rem 0.65rem;
    background-color: var(--crm-surface);
    border-bottom: 1px solid var(--crm-border);
    box-shadow: var(--crm-shadow-sm);
  }
  [data-crm-search="open"] .crm-search-icon { left: 1.2rem; }
  [data-crm-search="open"] .crm-global-search #globalSearchInput {
    width: 100% !important;
  }
  .crm-theme-selector .crm-icon-button { width: 1.8rem; }
  .crm-user-toggle { width: 2.25rem; height: 2.25rem; justify-content: center; padding: 0; }
  .crm-user-name,
  .crm-user-toggle .crm-icon-chevron-down { display: none; }
  .crm-user-menu .dropdown-menu { min-width: min(18rem, calc(100vw - 1rem)); }
  .crm-shell-anonymous .crm-theme-selector .crm-icon-button { width: 2rem; }
}

/* Cards */
.card {
  border-color: var(--crm-border);
  border-radius: var(--crm-radius);
  box-shadow: var(--crm-shadow-sm);
}
.stat-card .card-body h6 {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.stat-card .display-6 {
  font-size: 1.75rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* A row of .stat-card siblings is already equal-height (Bootstrap's .row is a flex
   container, and .card/.card-body stretch to fill it) — that part needs no help.
   What doesn't come for free is a card with no subtitle/delta line looking punched
   short next to one that has both: growing .card-body into a flex column lets the
   trailing content (a subtitle, an optional _norm_line.html/_month_delta.html) stack
   for real instead of needing an `invisible` placeholder to fake the line count. */
.stat-card .card-body {
  display: flex;
  flex-direction: column;
}

/* Dashboard funnel widget (marketing → sales).

   The widget renders 2 + N segments (New/Qualified leads, then one per open pipeline
   stage) with a conversion-rate column between each adjacent pair, so its natural
   width is data-driven — which is why it is sized against its own container rather
   than the viewport. It sits full-width on the dashboard today, but nothing
   guarantees it stays there and what matters is the space this card actually has.
   This is the only container query in the app; it is Baseline since early 2023.

   Base rules are the narrow layout: a vertical funnel, one stage per row with a
   proportional bar and the three conversion windows inline on a connector row
   between stages. From 48rem everything moves onto a single row that never wraps —
   segments are `flex: 1 1 0` with `min-width: 0` so labels truncate and columns
   shrink evenly instead of half-wrapping and stranding gap columns mid-funnel, which
   is what the old `flex-wrap` row did. From 72rem there is room for the full window
   labels (TTM / Prev mo / This mo) and roomier padding; below that the short forms
   (12M / PM / MTD) stand in.

   48rem is the knob: the narrowest width at which one row still reads. Raise it if a
   deployment configures unusually many open pipeline stages. */
.funnel-widget {
  container-type: inline-size;
  container-name: funnel;
}
.funnel-row {
  display: flex;
  flex-direction: column;
}
.funnel-segment {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.35rem 0.6rem;
  border-left: 3px solid transparent;
  border-radius: 0 var(--crm-radius) var(--crm-radius) 0;
  /* Proportional bar as a hard-stop gradient: no extra element, and the :hover
     background still shows through the untinted remainder. */
  background-image: linear-gradient(
    to right,
    var(--funnel-bar-tint) var(--funnel-bar, 0%),
    transparent 0
  );
}
.funnel-segment > .small {
  flex: 1 1 auto;
  min-width: 0; /* lets text-truncate engage instead of shoving the count aside */
}
.funnel-segment:hover {
  background-color: var(--crm-accent-subtle);
}
.funnel-segment-marketing {
  border-left-color: var(--crm-teal);
  --funnel-bar-tint: rgba(15, 155, 142, 0.16);
}
.funnel-segment-sales {
  border-left-color: var(--crm-accent);
  --funnel-bar-tint: rgba(42, 120, 214, 0.16);
}
/* Marketing → sales boundary. Vertically the accent colours already mark it, so
   extra whitespace is enough; horizontally it becomes a rule between the columns. */
.funnel-divider { margin-top: 0.75rem; }
.funnel-gap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.2rem;
  /* Continues the segments' 3px spine down the funnel, muted. */
  border-left: 3px solid var(--crm-border);
  padding: 0.2rem 0.6rem 0.2rem 0.9rem;
  font-size: 0.8rem;
}
.funnel-gap .small {
  font-size: 0.65rem;
  line-height: 1;
  margin-left: 0.7rem; /* groups each label with the value that follows it */
}
.funnel-gap .small:first-child { margin-left: 0; }
.funnel-win-long { display: none; }

@container funnel (min-width: 48rem) {
  .funnel-row {
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: stretch;
  }
  .funnel-segment {
    display: block;
    flex: 1 1 0;
    min-width: 0;
    padding: 0.5rem 0.4rem;
    border-left: 0;
    border-top: 3px solid transparent;
    border-radius: 0 0 var(--crm-radius) var(--crm-radius);
    background-image: none;
    /* A backstop, not the mechanism — flex: 1 1 0 with truncating labels is what
       keeps the row intact. If a config ever packs in more stages than 48rem can
       carry, a segment clips at its own edge instead of spilling over its neighbour. */
    overflow: hidden;
  }
  .funnel-segment-marketing { border-top-color: var(--crm-teal); }
  .funnel-segment-sales { border-top-color: var(--crm-accent); }
  .funnel-divider {
    margin-top: 0;
    margin-left: 0.5rem;
    padding-left: 0.9rem;
    border-left: 1px solid var(--crm-border);
  }
  .funnel-gap {
    flex: 0 0 auto;
    flex-direction: column;
    flex-wrap: nowrap;
    /* Base uses baseline alignment for the inline row; stacked, items must stretch
       so text-align actually centres them. */
    align-items: stretch;
    min-width: 2.4rem;
    text-align: center;
    border-left: 0;
    padding: 0.5rem 0.2rem 0;
    font-size: 0.75rem;
  }
  .funnel-gap .small { font-size: 0.6rem; margin-left: 0; }
}

@container funnel (min-width: 72rem) {
  .funnel-segment { padding: 0.5rem 0.75rem; }
  .funnel-divider { padding-left: 1.25rem; }
  /* Wider than the compact tier's columns: the full labels are what set this width,
     and translations run long ("Prev mo" is "Vorige mnd" in Dutch). */
  .funnel-gap { min-width: 4.5rem; padding-inline: 0.25rem; font-size: 0.8rem; }
  .funnel-gap .small { font-size: 0.65rem; }
  .funnel-win-long { display: inline; }
  .funnel-win-short { display: none; }
}

/* Tables */
.table > thead th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bs-secondary-color);
  font-weight: 600;
}
.table-hover > tbody > tr:hover > * {
  background-color: var(--crm-accent-subtle);
  --bs-table-bg-state: var(--crm-accent-subtle);
}
.tabular-nums { font-variant-numeric: tabular-nums; }

/* Inline stage control (opportunity list + detail). Capped so a stage name plus its
   probability doesn't stretch the column past the cells around it. */
.stage-quick-select {
  max-width: 12rem;
  min-width: 8rem;
}

/* Sortable column headers: a muted ⇅ marks a header as clickable; it turns into a
   solid ↑/↓ (via .sort-indicator.active, set in the template) once that column is
   the active sort, and the whole header underlines on hover. */
.sortable-th:hover {
  text-decoration: underline;
}
.sort-indicator {
  opacity: 0.35;
  margin-left: 0.15rem;
}
.sort-indicator.active {
  opacity: 1;
  color: var(--crm-accent-text);
}

/* Reports home: tile grid */
.report-tile {
  transition: box-shadow 150ms ease-in, border-color 150ms ease-in;
}
.report-tile:hover {
  box-shadow: var(--crm-shadow);
  border-color: var(--crm-accent);
}

/* Monthly Business Review — a real slide deck, not a scrolling page.

   Each slide is a fixed 16:9 canvas so what's on screen is exactly what the PNG
   export and the print/PDF pack contain: no "looks fine until you export it".
   Inside, the slide is a flex column — header, KPI strip, and commentary take their
   natural height and the chart area absorbs whatever is left, which is why the chart
   wrappers carry no pixel height (Chart.js runs with maintainAspectRatio:false and
   fills its box). Below the lg breakpoint the aspect ratio is dropped and everything
   stacks; a slide deck on a phone is a scrolling page and pretending otherwise just
   produces unreadable 90px charts.

   Chart colours live here as custom properties rather than hardcoded hex in seven
   templates, and every combination below was checked with a CVD validator:
   teal/red (won/lost, ΔE 11.3 deutan) replaces the red/green pair used elsewhere in
   the app, which is indistinguishable to a deuteranope, and the by-stage series uses
   a single-hue light→dark ramp because pipeline stages are ordered — a categorical
   rainbow implies they aren't. --mbr-teal/--mbr-red alias the app-wide --crm-teal/
   --crm-red tokens above rather than repeating the hex — the outcome badges use the
   same colours, and two names for one colour is how they drift apart. */
:root,
.mbr-document {
  --mbr-blue: #2a78d6;         /* gross / total */
  --mbr-teal: var(--crm-teal); /* weighted / won / increase */
  --mbr-red: var(--crm-red);   /* lost / decrease */
  --mbr-ink: #6c757d;          /* axis, legend and tick text */
  /* Precomputed sRGB token/white blends — literal hex because slide 4's PNG
     export runs the funnel bars through html2canvas 1.4.1, which cannot parse
     newer CSS color functions and otherwise silently breaks that slide's export
     (and, since it is last in the DOM, "Export all"). */
  --mbr-teal-tint-60: #6fc3bb; /* 60% --mbr-teal, 40% white */
  --mbr-blue-tint-55: #8ab5e8; /* 55% --mbr-blue, 45% white */
}

.mbr-document { color-scheme: light; }

.mbr-slide {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
  background-color: #fff;
  border: 1px solid var(--crm-border);
  border-radius: var(--crm-radius);
  box-shadow: var(--crm-shadow);
}
@media (min-width: 992px) {
  .mbr-slide {
    aspect-ratio: 16 / 9;
    min-height: 34rem;
    max-height: 54rem;
    /* A backstop, not the mechanism: the flex rules below are what keep content
       inside the frame. This guarantees that if any of it ever fails, a slide
       clips at its own edge instead of overlapping the next one. */
    overflow: hidden;
  }
}

.mbr-slide-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  border-bottom: 1px solid var(--crm-border);
  padding-bottom: 0.6rem;
}
.mbr-eyebrow {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--crm-accent-text);
}
.mbr-question {
  font-size: 0.9rem;
  color: var(--bs-secondary-color);
}
.mbr-asof {
  font-size: 0.72rem;
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
}

/* The main region absorbs the slack left by the header, KPI strip and commentary.

   `flex: 1 1 0` — a zero basis, not `auto` — throughout, and it has to be zero: with
   `flex-basis: auto` an item's base size comes from its *content*, so a side panel
   listing 17 closing deals sizes its column to 17 rows, that stretches the row, the
   row stretches the chart column, and Chart.js (maintainAspectRatio:false) grows the
   canvas to match — which grows the content again. The slide runs off the bottom and
   over the next one. A zero basis makes these purely proportional divisions of the
   space the 16:9 frame already fixed, with no path from content back to height. */
.mbr-main {
  flex: 1 1 0;
  min-height: 0;
}
.mbr-main > [class*="col-"] {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.mbr-chart {
  position: relative;
  flex: 1 1 0;
  min-height: 8rem;
}
/* Taking the canvas out of flow is the belt to that braces: however Chart.js sizes
   it, an absolutely positioned canvas cannot feed its height back to the flex box. */
.mbr-chart > canvas {
  position: absolute;
  inset: 0;
}
/* Side panels hold lists and tables that can outgrow the canvas; they scroll inside
   the slide rather than stretching it, so the 16:9 frame always holds. */
.mbr-scroll {
  flex: 1 1 0;
  min-height: 0;
  overflow-y: auto;
}
.mbr-panel-title {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bs-secondary-color);
  margin-bottom: 0.4rem;
}

/* KPI strip: always a full row of four, so a slide never shows a half-empty grid
   because an optional norm happens not to be configured. */
.mbr-kpi {
  height: 100%;
  padding: 0.6rem 0.75rem;
  background-color: var(--crm-accent-subtle);
  border-radius: var(--crm-radius);
  border-left: 3px solid transparent;
}
.mbr-kpi-good { border-left-color: var(--mbr-teal); }
.mbr-kpi-warning { border-left-color: var(--bs-warning); }
.mbr-kpi-danger { border-left-color: var(--bs-danger); }
.mbr-kpi-label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bs-secondary-color);
}
.mbr-kpi-value {
  font-size: 1.6rem;
  font-weight: 600;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.mbr-kpi-note {
  font-size: 0.75rem;
  color: var(--bs-secondary-color);
  font-variant-numeric: tabular-nums;
}

/* Slide 4's funnel report (templates/reports/_mbr_funnel.html) — a dense stage/gap
   list, not the dashboard's narrow funnel-widget card (that partial is shared with
   the dashboard and stays untouched). Column widths on the stage row and the gap
   row's leading spacers must match so the gap KPIs land centred under the bars. */
.mbr-funnel-stage, .mbr-funnel-gap {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.mbr-funnel-stage { padding: 0.2rem 0; }
.mbr-funnel-stage.mbr-funnel-divider {
  margin-top: 0.4rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--crm-border);
}
.mbr-funnel-idx {
  width: 1.3rem;
  flex-shrink: 0;
  font-size: 0.62rem;
  color: var(--mbr-ink);
  font-variant-numeric: tabular-nums;
}
.mbr-funnel-label {
  width: 8rem;
  flex-shrink: 0;
  font-size: 0.76rem;
  font-weight: 500;
  color: inherit;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mbr-funnel-label:hover { text-decoration: underline; }
.mbr-funnel-bar-wrap {
  flex: 1 1 0;
  height: 1.7rem;
  background: var(--crm-accent-subtle);
  border-radius: 3px;
}
/* No overflow:hidden here — a segment near the bottom of the funnel can be a few
   percent of the peak, too narrow to hold its own value; centering still holds the
   number on the bar's midpoint and just lets it spill past the fill's edges rather
   than getting clipped or shoved outside the bar entirely. */
.mbr-funnel-bar {
  height: 100%;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.mbr-funnel-bar-marketing { background: var(--mbr-teal-tint-60); }
.mbr-funnel-bar-sales { background: var(--mbr-blue-tint-55); }
.mbr-funnel-value {
  padding: 0 0.35rem;
  font-size: 0.82rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.mbr-funnel-gap { padding: 0.15rem 0; }
.mbr-funnel-gap-kpis {
  flex: 1 1 0;
  display: flex;
  justify-content: center;
  gap: 1.1rem;
}
.mbr-funnel-gap-kpi {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  cursor: default;
}
.mbr-funnel-gap-kpi span {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--mbr-blue);
  font-variant-numeric: tabular-nums;
}
.mbr-funnel-gap-kpi label {
  font-size: 0.58rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--mbr-ink);
}
.mbr-funnel-foot {
  margin-top: 0.5rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--crm-border);
  font-size: 0.62rem;
  color: var(--mbr-ink);
}

/* Generated commentary (reports/mbr_commentary.py). Two columns so four or five
   sentences stay one or two lines tall instead of eating the chart's height. */
.mbr-commentary {
  border-top: 1px solid var(--crm-border);
  padding-top: 0.6rem;
  margin: 0;
  font-size: 0.85rem;
  columns: 2;
  column-gap: 2rem;
}
.mbr-commentary li {
  break-inside: avoid;
  margin-bottom: 0.2rem;
}
.mbr-commentary li::marker { color: currentColor; }

/* Print: the whole four-slide pack in one Ctrl-P, one landscape page per slide.
   The aspect ratio is dropped here on purpose — the page box already fixes the
   proportions, and keeping 16/9 as well overflows onto a blank second sheet. */
@media print {
  @page { size: A4 landscape; margin: 8mm; }
  body { background: #fff; }
  .crm-sidebar,
  .crm-sidebar-backdrop,
  .crm-topbar,
  .mbr-screen-only,
  .mbr-export-btn,
  #messages,
  .alert-dismissible .btn-close {
    display: none !important;
  }
  .crm-shell-body,
  [data-crm-sidebar="collapsed"] .crm-shell-body { margin-left: 0; }
  main.container-fluid { padding: 0 !important; }
  .mbr-slide {
    aspect-ratio: auto;
    min-height: 0;
    max-height: none;
    height: 17.5cm;
    margin: 0;
    padding: 0.5cm;
    border: 0;
    box-shadow: none;
    break-after: page;
    page-break-after: always;
  }
  .mbr-slide:last-of-type {
    break-after: auto;
    page-break-after: auto;
  }
  .mbr-scroll { overflow: hidden; }
}

/* Alerts: the compact `py-2` alerts used throughout the app shrink the bar height, but
   Bootstrap's default .btn-close positioning (top:0 + large fixed padding) assumes the
   taller default alert height, so the X ends up hanging below center — recenter it. */
.alert-dismissible .btn-close {
  top: 50%;
  transform: translateY(-50%);
  padding: 0.5rem 1rem;
}

/* Explicit component states keep Bootstrap controls legible against the dark
   surfaces instead of relying on its generic color-mode fallbacks. */
[data-bs-theme="dark"] .alert-info {
  --bs-alert-color: #b6d4fe;
  --bs-alert-bg: #162b43;
  --bs-alert-border-color: #315a83;
  --bs-alert-link-color: #d7e8fd;
}
[data-bs-theme="dark"] .alert-success {
  --bs-alert-color: #a3cfbb;
  --bs-alert-bg: #19362a;
  --bs-alert-border-color: #3d765c;
  --bs-alert-link-color: #d1e7dd;
}
[data-bs-theme="dark"] .alert-warning {
  --bs-alert-color: #ffe69c;
  --bs-alert-bg: #3d3418;
  --bs-alert-border-color: #806c27;
  --bs-alert-link-color: #fff3cd;
}
[data-bs-theme="dark"] .alert-danger {
  --bs-alert-color: #f1aeb5;
  --bs-alert-bg: #421f23;
  --bs-alert-border-color: #842f38;
  --bs-alert-link-color: #f8d7da;
}
[data-bs-theme="dark"] .alert-secondary {
  --bs-alert-color: #ced4da;
  --bs-alert-bg: #2b3035;
  --bs-alert-border-color: #565e64;
  --bs-alert-link-color: #e9ecef;
}
[data-bs-theme="dark"] .is-invalid,
[data-bs-theme="dark"] .form-control.is-invalid,
[data-bs-theme="dark"] .form-select.is-invalid,
[data-bs-theme="dark"] .form-check-input.is-invalid {
  border-color: #ea868f;
}
[data-bs-theme="dark"] .invalid-feedback,
[data-bs-theme="dark"] .invalid-tooltip,
[data-bs-theme="dark"] .form-check-input.is-invalid ~ .form-check-label {
  color: #ff9ca5;
}
[data-bs-theme="dark"] .dropdown-divider { border-color: var(--crm-border); }
[data-bs-theme="dark"] .btn-close { filter: invert(1) grayscale(100%) brightness(180%); }

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--crm-focus);
  outline-offset: 2px;
}

/* Skip link: off-screen until focused, then pinned over the top bar. Moved rather
   than display:none'd, because a hidden element cannot receive focus at all. <main>
   is the only skip target, and #main-content is never a real scroll anchor, so this
   does not interact with the sticky topbar's own offset. */
.crm-skip-link {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1100;
  transform: translateY(-120%);
  padding: 0.6rem 1rem;
  margin: 0.35rem;
  border-radius: calc(var(--crm-radius) - 0.125rem);
  background-color: var(--crm-surface-elevated);
  color: var(--crm-accent-text);
  font-weight: 650;
  text-decoration: none;
  box-shadow: var(--crm-shadow);
}
.crm-skip-link:focus {
  transform: translateY(0);
}
/* The skip target itself must not draw a focus ring — it is a scroll/focus landing
   point, not a control the user activated. */
main:focus { outline: none; }

/* Shared Phase 3 component composition.

   These deliberately supplement Bootstrap instead of replacing it. Phase 3b page
   templates can compose `.crm-form-field`/`.crm-form-label`/`.crm-form-help`/
   `.crm-field-error` around their hand-rendered controls, and use
   `.crm-inline-actions` for action rows. `.crm-form-summary`, `.crm-message`,
   `.crm-status-badge`, and `.crm-owner-scope-note` are the matching compact shared
   partial treatments. For a company picker, wrap the search include and its real
   select in `.crm-company-picker`, and add `.crm-company-picker-select` to that
   select. Do not replace the select, alter its id/name, or move its caller-owned
   htmx attributes: the component is only a display refinement. The note-card
   family (`.crm-notes-card`, `.crm-note-entry`, `.crm-notes-table`,
   `.crm-note-actions`) keeps a dense, wrapping activity layout. These classes use
   the Phase 1 semantic tokens and allow labels, messages, badges, and actions to
   wrap for Dutch. */
.crm-form-summary {
  margin-bottom: 1rem;
  border-left: 0.25rem solid var(--crm-negative);
  box-shadow: var(--crm-shadow-sm);
}
.crm-form-summary-title {
  margin: 0 0 0.35rem;
  font-weight: 650;
  line-height: 1.3;
}
.crm-form-summary-list {
  margin: 0;
  padding-left: 1.2rem;
}
.crm-form-summary-list li + li { margin-top: 0.2rem; }
.crm-form-field { min-width: 0; }
.crm-form-label {
  margin-bottom: 0.3rem;
  font-weight: 600;
  line-height: 1.3;
}
.crm-required-indicator {
  color: var(--crm-negative);
  font-weight: 700;
}
.crm-form-help,
.crm-field-error {
  margin-top: 0.3rem;
  line-height: 1.35;
}
.crm-form-check { min-height: 1.35rem; }
.crm-inline-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.crm-status-badge {
  max-width: 100%;
  padding: 0.32em 0.55em;
  line-height: 1.25;
  text-align: start;
  white-space: normal;
}
.crm-owner-scope-note {
  color: var(--crm-text-muted);
  white-space: normal;
}
.crm-message-stack {
  display: grid;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.crm-message {
  min-height: 2.5rem;
  margin: 0;
  padding: 0.5rem 2.75rem 0.5rem 0.75rem;
  box-shadow: var(--crm-shadow-sm);
  line-height: 1.35;
}
.crm-company-picker { min-width: 0; }
.crm-company-search {
  min-width: 0;
  margin-bottom: 0.35rem;
}
.crm-company-picker-select { min-width: 0; }
.crm-notes-card { min-width: 0; }
.crm-note-entry .card-body { padding: 0.75rem; }
.crm-note-control { min-width: 0; }
.crm-note-errors { line-height: 1.35; }
.crm-notes-table {
  --bs-table-bg: transparent;
  --bs-table-color: var(--crm-text);
  --bs-table-border-color: var(--crm-border);
}
.crm-notes-table .table-light {
  --bs-table-bg: var(--crm-surface-elevated);
  --bs-table-color: var(--crm-text-muted);
  --bs-table-border-color: var(--crm-border);
}
.crm-note-meta { font-variant-numeric: tabular-nums; }
.crm-note-content { white-space: pre-line; }
.crm-note-actions {
  min-width: 8rem;
  white-space: normal !important;
}
.crm-note-actions > .btn { margin: 0.125rem 0 0.125rem 0.25rem; }
.crm-note-action { display: grid; align-content: start; }

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* Empty states */
.empty-state {
  padding: 3rem 1rem;
  text-align: center;
  color: var(--bs-secondary-color);
}
.empty-state .empty-state-title {
  font-weight: 600;
  color: var(--bs-body-color);
  margin-bottom: 0.25rem;
}

/* htmx loading indicator: hidden until htmx flags the request in flight */
.htmx-indicator { opacity: 0; transition: opacity 150ms ease-in; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }

/* Activity page: per-user summary rows expand to a sibling <tr> showing
   clickpath detail. Bootstrap's .collapse.show sets display:block, which
   breaks a <tr>'s table layout — force table-row display back. The caret
   rotates off aria-expanded, which Bootstrap's collapse plugin already sets
   on the toggle element — no extra JS needed. */
.cursor-pointer { cursor: pointer; }
tr.collapse.show { display: table-row; }
.clickpath-caret {
  display: inline-block;
  transition: transform 150ms ease-in;
}
[aria-expanded="true"] .clickpath-caret {
  transform: rotate(90deg);
}

/* Login page */
.login-wrap {
  min-height: calc(100vh - 12rem);
  display: flex;
  align-items: center;
}
