/* ═══════════════════════════════════════════════════════════
   ODIN ENTERPRISE STYLESHEET v4
   Component-based, token-driven, dark-mode-ready
═══════════════════════════════════════════════════════════ */

/* ─── Reset & Base ────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  overflow: hidden;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-primary);
  background: var(--bg-app);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

button { cursor: pointer; font: inherit; border: none; background: none; }
input, select { font: inherit; }
a { color: inherit; text-decoration: none; }

/* ─── App Shell ──────────────────────────────────────── */
.app-shell {
  display: flex;
  height: 100vh;
  overflow: hidden;
  background: var(--bg-app);
}

/* ─── Sidebar ────────────────────────────────────────── */
.sidebar {
  width: var(--sidebar-w);
  min-width: 200px;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  flex-shrink: 0;
  transition: width var(--ease-normal);
  overflow: hidden;
  position: relative;
  z-index: 10;
}

/* ─── Collapsed View with First-Letter Badges ────────── */
.sidebar.collapsed {
  width: 72px !important;
  min-width: 72px !important;
  padding-left: 6px !important;
  padding-right: 6px !important;
}

/* Hide detailed arrows, badges, submenus, meta text, and brand title */
.sidebar.collapsed .arrow-box,
.sidebar.collapsed .nav-badge,
.sidebar.collapsed .sidebar-meta-text,
.sidebar.collapsed .brand span,
.sidebar.collapsed .submenu {
  display: none !important;
}

/* Center and scale logo in header; stack the expand button below it
   so it stays visible and clickable while collapsed */
.sidebar.collapsed .sidebar-header {
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 14px 4px !important;
  justify-content: center !important;
}

.sidebar.collapsed .toggle-sidebar-btn {
  display: grid !important;
}

.sidebar.collapsed .toggle-sidebar-btn svg {
  transform: rotate(180deg);
}

.sidebar.collapsed .brand {
  justify-content: center !important;
  width: 100% !important;
}

.sidebar.collapsed .brand img {
  height: 28px !important;
  width: 28px !important;
  margin: 0 auto !important;
}

/* Format nav text to show initials when collapsed */
.sidebar.collapsed .nav-item {
  justify-content: center !important;
  padding: 10px 0 !important;
  text-align: center !important;
}

.sidebar.collapsed .nav-text {
  font-size: 11px !important;
  font-weight: 700 !important;
  letter-spacing: 0.05em !important;
  color: var(--primary) !important;
  background: var(--primary-light) !important;
  border: 1px solid rgba(195,80,43,0.2) !important;
  padding: 4px 8px !important;
  border-radius: var(--radius-sm) !important;
  max-width: 44px !important;
  overflow: hidden !important;
  white-space: nowrap !important;
}

.sidebar.collapsed .nav-item.active .nav-text {
  background: var(--primary) !important;
  color: #ffffff !important;
  border-color: var(--primary) !important;
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 16px 12px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.brand { color: var(--text-primary); }

.toggle-sidebar-btn {
  width: 28px; height: 28px;
  border-radius: var(--radius-sm);
  display: grid; place-items: center;
  color: var(--text-muted);
  transition: background var(--ease-fast), color var(--ease-fast);
}
.toggle-sidebar-btn:hover {
  background: var(--sidebar-hover);
  color: var(--text-primary);
}

/* ─── Nav Menu ───────────────────────────────────────── */
.nav-menu {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 10px 8px;
  scrollbar-width: thin;
  scrollbar-color: rgba(0,0,0,0.12) transparent;
}
.nav-menu::-webkit-scrollbar { width: 4px; }
.nav-menu::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.12); border-radius: 2px; }

.nav-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.005em;
  transition: background var(--ease-fast), color var(--ease-fast);
  text-align: left;
  position: relative;
  white-space: nowrap;
  overflow: hidden;
}
.nav-item:hover {
  background: var(--sidebar-hover);
  color: var(--text-primary);
}
.nav-item.active {
  background: var(--sidebar-active);
  color: var(--primary);
  font-weight: 600;
}
.nav-item.active::before {
  content: '';
  position: absolute;
  left: 0; top: 20%; bottom: 20%;
  width: 3px;
  background: var(--primary);
  border-radius: 0 2px 2px 0;
}

.nav-item .nav-text { flex: 1; }
.nav-item .arrow-box {
  display: flex;
  align-items: center;
  transition: transform var(--ease-normal);
  color: var(--text-dim);
}
.nav-item.active .arrow-box,
.nav-item.open .arrow-box { color: var(--primary); }
.submenu.active ~ .nav-item .arrow-box,
.nav-item.menu-open .arrow-box { transform: rotate(180deg); }

.nav-badge {
  background: var(--danger);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 10px;
  line-height: 16px;
  min-width: 18px;
  text-align: center;
}

.nav-group { margin-bottom: 2px; }
.nav-hidden { display: none !important; }

/* Submenus */
.submenu {
  display: none;
  flex-direction: column;
  gap: 1px;
  padding: 2px 0 2px 10px;
  border-left: 1px solid var(--border);
  margin: 2px 0 2px 16px;
}
.submenu.active { display: flex; }

.sub-item {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 500;
  text-align: left;
  transition: background var(--ease-fast), color var(--ease-fast);
  white-space: nowrap;
}
.sub-item:hover {
  background: rgba(0,0,0,0.04);
  color: var(--text-primary);
}
.sub-item.active {
  background: rgba(195,80,43,0.12);
  color: var(--primary-hover);
  font-weight: 600;
}
.sub-item.active::before {
  content: '•';
  font-size: 10px;
  margin-right: 2px;
  color: var(--primary);
}

.sidebar-footer {
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.status-dot-live {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--success);
  animation: pulse-live 2s ease-in-out infinite;
  flex-shrink: 0;
}
@keyframes pulse-live {
  0%, 100% { box-shadow: 0 0 0 0 rgba(70,156,132,0.4); }
  50%       { box-shadow: 0 0 0 4px rgba(70,156,132,0); }
}
.sidebar-meta-text { color: var(--text-muted); font-size: 11px; }

/* ─── Sidebar Resizer ────────────────────────────────── */
.sidebar-resizer {
  width: 4px;
  cursor: col-resize;
  background: transparent;
  flex-shrink: 0;
  transition: background var(--ease-fast);
  position: relative;
  z-index: 5;
}
.sidebar-resizer::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 1px;
  background: var(--border);
  transition: background var(--ease-fast), width var(--ease-fast);
}
.sidebar-resizer:hover::after,
.sidebar-resizer.resizing::after {
  width: 3px;
  background: var(--primary);
}

/* ─── Main Panel ─────────────────────────────────────── */
.main-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
  position: relative; /* containing block for .loading-overlay — keeps it scoped to the report area, not the whole viewport */
}

/* ─── Top Bar ────────────────────────────────────────── */
.top-bar {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  gap: 12px;
}

.top-bar-left {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.breadcrumb-root {
  font-family: var(--font-head);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  letter-spacing: 0.02em;
}
.breadcrumb-sep { color: var(--text-dim); font-size: 12px; }
.breadcrumb-current {
  font-family: var(--font-head);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.01em;
  max-width: 200px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Platform segment pills */
.segment-bar {
  display: flex;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 3px;
  gap: 2px;
}
.segment-btn {
  padding: 4px 11px;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-secondary);
  transition: all var(--ease-fast);
  letter-spacing: 0.01em;
}
.segment-btn:hover { color: var(--text-primary); }
.segment-btn.active {
  background: var(--bg-surface);
  color: var(--primary);
  box-shadow: var(--shadow-xs);
}
.segment-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.segment-btn:disabled:hover { color: var(--text-secondary); }
/* Icon-only segment buttons (Campaign Performance's Tabular/Heatmap
   toggle) — same pill container/active-state as the text segment-btns
   above, just square and centered around an SVG instead of padded text. */
.icon-toggle-btn {
  padding: 5px 7px;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Numbered badge on an active View As pill (Campaign Performance) —
   shows its position in the click-order nesting (1 = outermost level
   under Source, 2 = nested inside that, etc). */
.pivot-dim-order {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--primary); color: #fff;
  font-size: 9px; font-weight: 700; margin-right: 4px;
}
/* Active View As pill (Campaign Performance) — draggable to reorder the
   pivot's nesting order (see campaignDimDragStart/Over/Drop in app.js). */
.pivot-dim-pill { cursor: grab; }
.pivot-dim-pill:active { cursor: grabbing; }

.top-bar-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Date Range */
.date-range-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 5px 10px;
  color: var(--text-secondary);
}
.date-range-bar input[type="date"] {
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: 12px;
  font-weight: 500;
  outline: none;
  cursor: pointer;
  padding: 0;
}
.date-sep { color: var(--text-muted); font-size: 11px; }

/* ─── Date Range Dropdown (presets + dual calendar) ───────────── */
.daterange-container { position: relative; }
.daterange-trigger {
  display: flex;
  align-items: center;
  gap: 7px;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 6px 10px;
  color: var(--text-primary);
  font-size: 12px;
  font-weight: 600;
  transition: border-color var(--ease-fast);
}
.daterange-trigger:hover { border-color: var(--text-dim); }
.daterange-chevron { color: var(--text-muted); transition: transform var(--ease-fast); flex-shrink: 0; }
.daterange-container.open .daterange-chevron { transform: rotate(180deg); }

.daterange-dropdown {
  /* position: fixed, positioned via inline top/right set in
     bindDateRangePicker's trigger click handler — .main-panel (an
     ancestor of .top-bar, which contains #daterange-container) has
     overflow: hidden, so an absolutely-positioned dropdown anchored here
     was being clipped, especially the taller 560px calendar-grid
     sub-view (the short presets list mostly fit, so this could look like
     only the calendar itself was "not working"). Same fix as
     .multiselect-panel above — fixed positioning escapes ancestor
     overflow clipping entirely. */
  position: fixed;
  width: 260px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: all var(--ease-normal);
  z-index: 200;
  overflow: hidden;
}
.daterange-container.open .daterange-dropdown { opacity: 1; visibility: visible; transform: translateY(0); }

.daterange-presets { padding: 6px; display: flex; flex-direction: column; }
.daterange-preset-btn {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  text-align: left;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-primary);
  transition: background var(--ease-fast);
}
.daterange-preset-btn:hover { background: var(--bg-hover); }
.daterange-preset-btn.active { background: var(--primary); color: #fff; font-weight: 600; }
.daterange-calendar-btn { justify-content: space-between; font-weight: 600; }
.daterange-chevron-right { flex-shrink: 0; color: var(--text-muted); }
.daterange-divider { height: 1px; background: var(--border-subtle); margin: 6px 4px; }

/* Calendar sub-panel */
.daterange-dropdown.calendar-open { width: 560px; }
.daterange-calendar { flex-direction: column; }
.daterange-calendar-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-secondary);
}
.daterange-calendar-header strong { color: var(--primary); font-weight: 700; }
.daterange-months { display: flex; gap: 4px; padding: 14px; }
.daterange-month { flex: 1; min-width: 0; }
.daterange-month-header {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-bottom: 10px;
}
.daterange-month-header select {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-surface-2);
  color: var(--text-primary);
  font-size: 12px;
  font-weight: 600;
  padding: 3px 6px;
  cursor: pointer;
}
.daterange-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 4px;
}
.daterange-weekdays span {
  text-align: center;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--text-muted);
  letter-spacing: 0.03em;
}
.daterange-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  row-gap: 2px;
}
.daterange-day {
  position: relative;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-primary);
  cursor: pointer;
}
.daterange-day.outside { color: var(--text-dim); }
.daterange-day.disabled { color: var(--text-dim); cursor: default; pointer-events: none; }
.daterange-day.today::after {
  content: '';
  position: absolute;
  bottom: 3px; left: 50%;
  transform: translateX(-50%);
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--primary);
}
.daterange-day.in-range { background: var(--primary-light); }
.daterange-day.range-start, .daterange-day.range-end {
  background: var(--primary);
  color: #fff;
  font-weight: 700;
  border-radius: 999px;
}
.daterange-day.range-start.in-range { border-radius: 999px 0 0 999px; }
.daterange-day.range-end.in-range { border-radius: 0 999px 999px 0; }
.daterange-calendar-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 14px;
  border-top: 1px solid var(--border-subtle);
}
.btn-icon-text {
  padding: 8px 14px;
  border-radius: var(--radius-md);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-secondary);
  transition: background var(--ease-fast);
}
.btn-icon-text:hover { background: var(--bg-hover); }

/* Data freshness indicator — reflects the DataCache state */
.sync-indicator {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 5px;
}
.sync-indicator::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--success);
  flex-shrink: 0;
}
.sync-indicator.stale::before { background: var(--warning); }

/* Centered loading overlay — replaces the old thin top-bar-plus-corner-
   text indicator (too small/easy to miss). Non-blocking: no backdrop dim,
   pointer-events:none on the wrapper so the page underneath stays fully
   interactive while it's up — this is purely a prominent visual signal,
   not a modal. See index.html for the markup, startSyncTicker/
   stopSyncTicker in app.js for what drives it. */
.loading-overlay {
  position: absolute;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}
.loading-overlay.active { opacity: 1; }
/* No card/box — just the emoji + text + bar floating directly over the
   blurred report (see .content-canvas.is-loading), on brand tokens
   (--primary etc.) instead of an invented palette so it reads as part of
   this site, not a generic spinner. */
.loading-card {
  text-align: center;
}
.loading-emoji {
  display: inline-block;
  font-size: 40px;
  line-height: 1;
  margin-bottom: 12px;
  filter: drop-shadow(0 4px 10px rgba(0,0,0,0.18));
  animation: loading-bounce 0.9s ease-in-out infinite;
}
@keyframes loading-bounce {
  0%, 100% { transform: translateY(0) rotate(0deg) scale(1); }
  50% { transform: translateY(-10px) rotate(-6deg) scale(1.06); }
}
.loading-text {
  font-size: 15px;
  font-weight: 800;
  color: var(--primary);
  margin-bottom: 16px;
  min-height: 20px;
  letter-spacing: 0.01em;
  text-shadow: 0 1px 12px var(--bg-app), 0 1px 12px var(--bg-app);
}
.loading-bar-track {
  position: relative;
  width: 220px;
  max-width: 60vw;
  height: 6px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--text-muted) 30%, transparent);
  overflow: hidden;
  margin: 0 auto 10px;
}
.loading-bar-fill {
  position: relative;
  height: 100%;
  width: 0%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--primary), var(--primary-hover));
  transition: width 0.3s ease, background 0.4s ease;
  overflow: hidden;
}
/* Shimmer sweeping across the filled portion — the one bit of polish kept
   from the boxed version, since it lives on the bar itself, not the
   window that got removed. */
.loading-bar-fill::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.55), transparent);
  transform: translateX(-100%);
  animation: loading-shimmer 1.1s ease-in-out infinite;
}
@keyframes loading-shimmer {
  100% { transform: translateX(100%); }
}
.loading-bar-fill.almost-there {
  background: linear-gradient(90deg, var(--success), var(--success));
}
.loading-pct {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  transition: color 0.3s ease;
  text-shadow: 0 1px 10px var(--bg-app);
}
.loading-pct.almost-there {
  color: var(--success);
}

.select-sm {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-surface-2);
  color: var(--text-primary);
  font-size: 12px;
  font-weight: 500;
  padding: 5px 8px;
  outline: none;
  cursor: pointer;
  transition: border-color var(--ease-fast);
}
.select-sm:hover, .select-sm:focus { border-color: var(--primary); }

.filter-lane {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 20px;
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.filter-lane::-webkit-scrollbar { display: none; }

.filter-group {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.filter-label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.filter-select {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-surface-2);
  color: var(--text-primary);
  font-size: 12px;
  font-weight: 600;
  padding: 5px 10px;
  outline: none;
  cursor: pointer;
  transition: border-color var(--ease-fast), box-shadow var(--ease-fast);
}
.filter-select:hover, .filter-select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px var(--primary-glow);
}
.filter-divider {
  width: 1px;
  height: 16px;
  background: var(--border);
  flex-shrink: 0;
}

/* Multi-select filter (Product Category, Source) */
.multiselect { position: relative; }
.multiselect-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 150px;
  text-align: left;
}
.multiselect-trigger::after {
  content: '';
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: 0.55;
  margin-left: auto;
}
.multiselect-panel {
  /* position: fixed (not absolute) and positioned via inline top/left set
     in initMultiSelectFilter's trigger click handler — .filter-lane needs
     overflow-x: auto for horizontal chip scrolling, and per the CSS spec
     an ancestor can't mix overflow-x: auto with overflow-y: visible (the
     visible value gets forced to auto too), so an absolutely-positioned
     panel anchored inside .filter-lane was being clipped by that
     ancestor's computed overflow-y for ALL FOUR multiselects, not just
     one. Fixed positioning escapes ancestor overflow clipping entirely. */
  position: fixed;
  width: 240px;
  max-height: 320px;
  overflow-y: auto;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: all var(--ease-normal);
  z-index: 200;
  padding: 6px 0;
}
.multiselect-panel.show { opacity: 1; visibility: visible; transform: translateY(0); }

/* Modifier for panels built as header (search/Select All/Clear) + a
   scrolling option list + a footer Apply button (Campaign Performance's
   Source/Campaign/Basket Size/Cohort Type dropdowns) — NOT applied to
   the plain global filter-lane panels (Product Category/Source), which
   have no header/footer and still rely on the base .multiselect-panel
   scrolling itself. Without this split, the base panel's own
   max-height+overflow-y:auto scrolled the ENTIRE panel as one block —
   header, option list, AND the Apply button footer together — so on a
   long list the Apply button scrolled off screen along with the last
   few options instead of staying reachable. Flex column + hidden
   overflow on the panel itself, with only the middle list scrolling
   (flex:1 + min-height:0, set on .multiselect-options-list below),
   keeps the header and Apply button always in view.  */
.multiselect-panel-flex {
  display: flex;
  flex-direction: column;
  max-height: min(420px, calc(100vh - 96px));
  overflow: hidden;
}
.multiselect-panel-header { flex-shrink: 0; padding: 8px; }
.multiselect-panel-footer {
  flex-shrink: 0;
  padding: 8px;
  background: var(--bg-surface-2, var(--bg-hover));
  border-top: 1px solid var(--border);
}
.multiselect-options-list { flex: 1 1 auto; min-height: 60px; overflow-y: auto; }

.multiselect-apply-btn {
  width: 100%;
  padding: 9px;
  background: var(--primary);
  color: #fff;
  border-radius: var(--radius-md);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  transition: background var(--ease-fast), transform var(--ease-fast);
}
.multiselect-apply-btn:hover { background: var(--primary-hover); transform: translateY(-1px); }
.multiselect-apply-btn:active { transform: translateY(0); }

.multiselect-option {
  padding: 8px 14px;
  font-size: 12.5px;
  color: var(--text-secondary);
  border-radius: var(--radius-sm);
  margin: 1px 6px;
  transition: background var(--ease-fast), color var(--ease-fast);
}
.multiselect-option:hover { background: var(--bg-hover); color: var(--text-primary); }
/* A checked row stays visually distinct even after the hover ends —
   without this every option looked identical at rest (the "lazy list"
   read), so scanning which ones were actually selected meant reading
   every checkbox individually instead of seeing it at a glance. */
.multiselect-option:has(input:checked) { background: color-mix(in srgb, var(--primary) 8%, transparent); color: var(--text-primary); font-weight: 600; }
.multiselect-option label {
  display: flex;
  align-items: center;
  gap: 9px;
  cursor: pointer;
}
.multiselect-option input[type="checkbox"] {
  cursor: pointer;
  width: 15px;
  height: 15px;
  accent-color: var(--primary);
}
.multiselect-divider { height: 1px; background: var(--border); margin: 4px 0; flex-shrink: 0; }

/* Icon button */
.btn-icon {
  width: 30px; height: 30px;
  border-radius: var(--radius-md);
  display: grid; place-items: center;
  color: var(--text-secondary);
  border: 1px solid var(--border);
  background: var(--bg-surface-2);
  transition: all var(--ease-fast);
}
.btn-icon:hover {
  background: var(--bg-surface);
  color: var(--primary);
  border-color: var(--primary);
}

/* Profile */
.profile-container { position: relative; }
.profile-avatar {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--primary) 0%, #E8935C 100%);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: grid; place-items: center;
  letter-spacing: 0.05em;
  cursor: pointer;
  transition: opacity var(--ease-fast);
  border: 2px solid var(--border);
}
.profile-avatar:hover { opacity: 0.85; }

/* ─── Notification Bell (topbar) ──────────────────────── */
.notif-bell-container { position: relative; }
.notif-bell-btn, #notif-bell-btn { position: relative; }
.notif-bell-badge {
  position: absolute;
  top: 2px; right: 2px;
  min-width: 14px; height: 14px;
  padding: 0 3px;
  border-radius: 7px;
  background: var(--danger);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  display: grid; place-items: center;
  line-height: 1;
}
.notif-bell-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 320px;
  max-height: 420px;
  overflow-y: auto;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: all var(--ease-normal);
  z-index: 100;
}
.notif-bell-dropdown.show { opacity: 1; visibility: visible; transform: translateY(0); }
.notif-bell-header {
  padding: 12px 14px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-primary);
  border-bottom: 1px solid var(--border-subtle);
}

.profile-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 220px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: all var(--ease-normal);
  z-index: 100;
  overflow: hidden;
}
.profile-dropdown.show {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.profile-info { padding: 14px 16px 12px; }
.profile-name {
  font-family: var(--font-head);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary);
}
.profile-email { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.dropdown-divider { height: 1px; background: var(--border); }
.dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 10px 16px;
  font-size: 12.5px;
  color: var(--text-secondary);
  transition: background var(--ease-fast);
  text-align: left;
}
.dropdown-item:hover { background: var(--bg-hover); }
.theme-row { justify-content: space-between; }
.logout-btn { color: var(--danger); }
.logout-btn:hover { background: var(--danger-bg); }

/* Toggle switch */
.switch { position: relative; display: inline-block; width: 32px; height: 18px; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider {
  position: absolute; cursor: pointer;
  inset: 0;
  background: var(--border);
  border-radius: 10px;
  transition: background var(--ease-normal);
}
.slider::before {
  content: '';
  position: absolute;
  height: 12px; width: 12px;
  left: 3px; bottom: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform var(--ease-spring);
}
input:checked + .slider { background: var(--primary); }
input:checked + .slider::before { transform: translateX(14px); }

/* ─── Content Canvas ─────────────────────────────────── */
.content-canvas {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 20px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
  background: var(--bg-app);
  filter: blur(0);
  transition: filter 0.2s ease;
}
/* Toggled alongside #loading-overlay (see startSyncTicker/stopSyncTicker
   in app.js) — a soft blur on the report itself, reinforcing that a
   refresh is in flight without hiding the numbers already on screen. */
.content-canvas.is-loading {
  filter: blur(3px);
}
/* Same treatment for the pincode map's full-screen takeover — targets
   #pincode-map-container itself, NOT its parent #pincode-fullscreen-body
   (which #loading-overlay is also appended into as a SIBLING while full
   screen is open — see openPincodeMapFullscreen in app.js). CSS filter
   blurs an element's own descendants too, so blurring the shared parent
   blurred the loading text/overlay right along with the map underneath
   it — blurring just the map container leaves the overlay legible. */
#pincode-map-container.is-loading {
  filter: blur(3px);
}
.content-canvas::-webkit-scrollbar { width: 5px; }
.content-canvas::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* ─── Page Layout ────────────────────────────────────── */
.page-section { display: flex; flex-direction: column; gap: 16px; }

.section-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}
.section-title {
  font-family: var(--font-head);
  font-size: 17px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.section-sub {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 500;
  margin-top: 3px;
}
.section-actions { display: flex; align-items: center; gap: 8px; }

/* ─── KPI Grid ───────────────────────────────────────── */
.kpi-grid {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}
.kpi-grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.kpi-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.kpi-grid.cols-5 { grid-template-columns: repeat(5, 1fr); }
.kpi-grid.cols-6 { grid-template-columns: repeat(6, 1fr); }

.kpi-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px;
  position: relative;
  overflow: hidden;
  transition: box-shadow var(--ease-fast), transform var(--ease-fast);
  cursor: default;
  box-shadow: var(--shadow-card);
}
.kpi-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--kpi-accent, var(--primary));
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.kpi-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
.kpi-card.accent-blue   { --kpi-accent: var(--primary); }
.kpi-card.accent-green  { --kpi-accent: var(--success); }
.kpi-card.accent-red    { --kpi-accent: var(--danger); }
.kpi-card.accent-amber  { --kpi-accent: var(--warning); }
.kpi-card.accent-purple { --kpi-accent: var(--purple); }
.kpi-card.accent-info   { --kpi-accent: var(--info); }

.kpi-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 8px;
}
.kpi-value {
  font-family: var(--font-head);
  font-size: 22px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: -0.03em;
  line-height: 1;
  margin-bottom: 6px;
}
.kpi-value.mono { font-variant-numeric: tabular-nums; }
.kpi-delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 20px;
}
.kpi-delta.up {
  color: var(--success);
  background: var(--success-muted);
}
.kpi-delta.down {
  color: var(--danger);
  background: var(--danger-muted);
}
.kpi-delta.neutral {
  color: var(--text-muted);
  background: var(--bg-hover);
}
.kpi-meta {
  font-size: 10.5px;
  color: var(--text-dim);
  margin-top: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ─── Orders KPI cards: driver line + sparkline + click-through ──── */
.kpi-card-clickable { cursor: pointer; }
.kpi-card-clickable:hover { border-color: var(--kpi-accent, var(--primary)); }
.kpi-card-clickable:focus-visible { outline: 2px solid var(--kpi-accent, var(--primary)); outline-offset: 2px; }
.kpi-driver {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kpi-driver strong { color: var(--text-secondary); font-weight: 700; }
.kpi-spark {
  display: block;
  width: 100%;
  height: 28px;
  margin-top: 10px;
}
.kpi-spark path {
  fill: none;
  stroke: var(--kpi-accent, var(--primary));
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.kpi-detail-spark-wrap svg { display: block; width: 100%; height: 60px; }
.kpi-detail-spark-wrap path {
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ─── KPI drill-down modal: "what's driving this change" ─────────── */
.kpi-mover-block {
  background: var(--bg-hover);
  border: 1px solid var(--border-subtle);
  border-radius: 12px;
  padding: 12px 14px 4px;
}
.kpi-mover-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 10px;
}
.kpi-mover-tab {
  font-size: 11px;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 20px;
  border: 1px solid var(--border);
  background: var(--bg-surface);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--ease-fast), color var(--ease-fast), border-color var(--ease-fast);
}
.kpi-mover-tab:hover { color: var(--text-primary); border-color: var(--kpi-accent, var(--primary)); }
.kpi-mover-tab.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}
.kpi-mover-panel {
  display: flex;
  flex-direction: column;
  max-height: 30vh;
  overflow-y: auto;
}
/* A class selector's `display` beats the UA stylesheet's `[hidden]{display:none}`
   by origin, not just specificity — without this, every panel stayed
   visible at once regardless of the `hidden` attribute the tab-switch JS
   toggles. */
.kpi-mover-panel[hidden] { display: none; }
.mover-row {
  padding: 9px 6px;
  border-bottom: 1px solid var(--border-subtle);
}
.mover-row:last-child { border-bottom: none; }
.mover-row-clickable { cursor: pointer; border-radius: 8px; margin: 0 -6px; padding-left: 6px; padding-right: 6px; }
.mover-row-clickable:hover { background: var(--bg-surface); }
/* Label — dotted leader — value, receipt-style: on a wide card a short
   label ("Bing") next to a short value ("-₹43") left a big dead gap
   between them when they sat at opposite grid edges. The leader fills
   that gap on purpose instead of leaving it blank. */
.mover-row-top {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.mover-label {
  flex: 0 1 auto;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.mover-leader {
  flex: 1 1 16px;
  min-width: 16px;
  align-self: flex-end;
  height: 2px;
  margin-bottom: 6px;
  /* A repeating-gradient dash, not border-style:dotted — a 1px dotted
     BORDER renders inconsistently (often near-invisible) across
     browsers/displays at this thinness; a gradient paints exact, solid
     2px dots we control directly, against var(--border) (too faint on
     this block's tinted --bg-hover background) so var(--text-muted) is
     used instead for real contrast. */
  background-image: repeating-linear-gradient(to right, var(--text-muted) 0 3px, transparent 3px 7px);
  border-radius: 1px;
}
.mover-delta {
  flex: 0 0 auto;
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.mover-delta.up { color: var(--success); }
.mover-delta.down { color: var(--danger); }
.mover-delta.neutral { color: var(--text-muted); }
.mover-sub {
  font-variant-numeric: tabular-nums;
  font-size: 11.5px;
  color: var(--text-secondary);
  margin-top: 2px;
}
.mover-sub strong { color: var(--text-primary); font-weight: 700; }
.mover-chevron {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--primary);
  margin-top: 3px;
}

/* ─── Mover drill-down (click a row → its own DoD/WoW/MoM) ────────── */
.mover-drilldown-back {
  background: none;
  border: none;
  padding: 4px 0;
  color: var(--primary);
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
}
.mover-drilldown-back:hover { text-decoration: underline; }

/* ─── Card Box ───────────────────────────────────────── */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-subtle);
}
.card-title {
  font-family: var(--font-head);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.01em;
}
.card-subtitle {
  font-size: 11.5px;
  color: var(--text-muted);
  font-weight: 500;
}
.card-body { padding: 18px; }
.card-body.no-pad { padding: 0; }

/* ─── Chart Container ────────────────────────────────── */
.chart-wrap {
  position: relative;
  width: 100%;
}
.chart-wrap canvas { display: block; }

/* ─── Campaign Performance: row-chart picker (data-modal) ─────────── */
/* Single column, not a multi-column grid — campaign names run 60-70+
   chars with no spaces, and a narrow grid track meant either truncating
   them (the actual bug: openCampaignRowChart's row template had an
   inline overflow:hidden;text-overflow:ellipsis;white-space:nowrap that
   silently beat this stylesheet) or wrapping unevenly across columns.
   Full width + explicit wrap guarantees the whole name is always
   readable without hunting for a tooltip. */
.campaign-chart-picker {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 26vh;
  overflow-y: auto;
}
.campaign-chart-picker-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
}
.campaign-chart-picker-row:hover { background: var(--bg-hover); }
.campaign-chart-picker-row input[type="checkbox"] { flex-shrink: 0; cursor: pointer; margin-top: 2px; }
.campaign-chart-picker-row span {
  min-width: 0;
  white-space: normal;
  word-break: break-word;
  line-height: 1.35;
}

/* ─── Data Tables ────────────────────────────────────── */
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}
.data-table thead th {
  padding: 10px 14px;
  text-align: left;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  background: var(--bg-surface-2);
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}
.data-table thead th:first-child { border-radius: var(--radius-sm) 0 0 0; }
.data-table thead th:last-child  { border-radius: 0 var(--radius-sm) 0 0; }
.data-table tbody tr {
  border-bottom: 1px solid var(--border-subtle);
  transition: background var(--ease-fast);
}
.data-table tbody tr:last-child { border-bottom: none; }
.data-table tbody tr:hover { background: var(--bg-hover); }
.data-table tbody tr.table-total-row {
  background: var(--bg-surface-2);
  border-top: 2px solid var(--border);
  border-bottom: none;
}
.data-table tbody tr.table-total-row:hover { background: var(--bg-surface-2); }
.data-table td {
  padding: 10px 14px;
  color: var(--text-primary);
  vertical-align: middle;
}
.data-table .rank-cell {
  color: var(--text-muted);
  font-weight: 700;
  font-size: 11.5px;
  width: 36px;
  text-align: center;
}
.data-table .mono { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.data-table .dim { color: var(--text-muted); }

/* Sortable table headers */
th.sortable-th, .cohort-table th.sortable-th {
  cursor: pointer;
  user-select: none;
}
th.sortable-th:hover { color: var(--text-secondary); background: var(--bg-hover); }
.sort-arrow {
  display: inline-block;
  margin-left: 4px;
  opacity: 0.35;
  font-size: 9px;
}
.sort-arrow.active { opacity: 1; color: var(--primary); }

/* Table scroll wrapper */
.table-scroll { overflow-x: auto; }
.table-scroll::-webkit-scrollbar { height: 4px; }
.table-scroll::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }

/* Vertical cap for long tables (Daily Summary, Geographic Performance,
   etc.) — ~10 data rows visible (header ~36px + 10 * ~36px row height),
   then scroll. .data-table thead th is already position:sticky, so the
   header stays visible while scrolling within this container. */
.table-scroll.rows-10 { max-height: 420px; overflow-y: auto; }
.table-scroll.rows-15 { max-height: 590px; overflow-y: auto; }
/* Campaign Performance specifically — a much bigger report (nested
   Source/Campaign/Product/Basket Size groups, not a flat list), so it
   gets noticeably more room on the main page before scrolling kicks in. */
.table-scroll.rows-20 { max-height: 800px; overflow-y: auto; }

/* ─── Inline Bar (for table cells) ───────────────────── */
.bar-cell { display: flex; align-items: center; gap: 8px; }
.mini-bar-bg {
  flex: 1;
  height: 5px;
  border-radius: 3px;
  background: var(--bg-surface-2);
  overflow: hidden;
  min-width: 60px;
  max-width: 100px;
}
.mini-bar-fill {
  height: 100%;
  border-radius: 3px;
  background: var(--primary);
  transition: width 0.6s cubic-bezier(0.4,0,0.2,1);
}

/* ─── Badges & Pills ─────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  line-height: 18px;
  white-space: nowrap;
}
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-danger  { background: var(--danger-bg);  color: var(--danger);  }
.badge-warning { background: var(--warning-bg); color: var(--warning); }
.badge-info    { background: var(--info-bg);    color: var(--info);    }
.badge-purple  { background: var(--purple-bg);  color: var(--purple);  }
.badge-neutral { background: var(--bg-surface-2); color: var(--text-secondary); border: 1px solid var(--border); }

/* Source tag */
.source-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 6px;
  border-radius: var(--radius-xs);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.source-meta    { background: #e8f0fe; color: #1a56db; }
.source-google  { background: #fce8e6; color: #d93025; }
.source-ga4     { background: #e6f4ea; color: #137333; }
.source-clarity { background: #fef3c7; color: #92400e; }
.source-ch      { background: #f3e8ff; color: #6d28d9; }
.source-organic { background: var(--bg-surface-2); color: var(--text-secondary); border: 1px solid var(--border); }

/* ─── Funnel Visualization ────────────────────────────── */
.funnel-container { display: flex; flex-direction: column; gap: 6px; }
.funnel-step { display: flex; align-items: center; gap: 10px; }
.funnel-label-col { width: 180px; flex-shrink: 0; font-size: 12px; color: var(--text-secondary); font-weight: 500; }
.funnel-bar-col { flex: 1; position: relative; }
.funnel-bar-bg {
  height: 28px;
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  position: relative;
}
.funnel-bar-fill {
  height: 100%;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--primary) 0%, rgba(195,80,43,0.7) 100%);
  transition: width 0.7s cubic-bezier(0.4,0,0.2,1);
  position: relative;
}
/* Warm terracotta → amber → sage progression, echoing the brand palette
   instead of a generic cool blue-to-purple ramp. */
.funnel-bar-fill.step-1 { background: linear-gradient(90deg, #A64425, #C3502B); }
.funnel-bar-fill.step-2 { background: linear-gradient(90deg, #C3502B, #D97A4A); }
.funnel-bar-fill.step-3 { background: linear-gradient(90deg, #D97A4A, #E0A458); }
.funnel-bar-fill.step-4 { background: linear-gradient(90deg, #E0A458, #D4900A); }
.funnel-bar-fill.step-5 { background: linear-gradient(90deg, #6FA88F, #469C84); }
.funnel-bar-fill.step-6 { background: linear-gradient(90deg, #469C84, #2F7A63); }

.funnel-value-col { width: 80px; flex-shrink: 0; text-align: right; font-size: 12.5px; font-weight: 700; color: var(--text-primary); font-variant-numeric: tabular-nums; }
.funnel-drop-col  { width: 90px; flex-shrink: 0; }
.funnel-drop { font-size: 11px; font-weight: 600; color: var(--danger); background: var(--danger-muted); padding: 2px 6px; border-radius: 10px; display: inline-flex; align-items: center; gap: 2px; }
.funnel-drop.first { opacity: 0; }

/* ─── Cohort Heatmap Table ─────────────────────────────── */
.cohort-table { width: 100%; border-collapse: collapse; }
.cohort-table th {
  padding: 8px 12px;
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  background: var(--bg-surface-2);
  border: 1px solid var(--border);
  text-align: center;
  white-space: nowrap;
}
.cohort-table td {
  padding: 8px 12px;
  border: 1px solid var(--border);
  text-align: center;
  font-size: 12.5px;
  font-weight: 600;
  transition: background var(--ease-fast);
}
.cohort-table .cohort-label {
  text-align: left;
  color: var(--text-primary);
  font-weight: 600;
  font-size: 12px;
}
.heat-hot    { background: rgba(5,150,105,0.20); color: var(--success); }
.heat-warm   { background: rgba(5,150,105,0.10); color: #047857; }
.heat-mild   { background: rgba(217,119,6,0.10); color: var(--warning); }
.heat-cold   { background: rgba(220,38,38,0.08); color: var(--danger); }
.heat-none   { background: transparent; color: var(--text-dim); }

/* ─── Alert Rows ─────────────────────────────────────── */
.alert-item { margin-bottom: 4px; }
.alert-strip {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 14px;
  border: none;
  border-left: 3px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-surface);
  font: inherit;
  font-size: 12px;
  text-align: left;
  cursor: pointer;
  transition: background var(--ease-fast);
}
.alert-strip:hover { background: var(--bg-hover); }
.alert-strip.crit { border-left-color: var(--danger); background: var(--danger-bg); }
.alert-strip.warn { border-left-color: var(--warning); background: var(--warning-bg); }
.alert-strip.info { border-left-color: var(--info); background: var(--info-bg); }
.alert-strip.expanded { border-radius: var(--radius-md) var(--radius-md) 0 0; }
.alert-time { color: var(--text-muted); font-size: 11px; width: 80px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.alert-msg  { flex: 1; color: var(--text-primary); font-weight: 500; }
.alert-src  { flex-shrink: 0; }
.alert-chevron {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  color: var(--text-muted);
  transition: transform var(--ease-fast);
}
.alert-strip.expanded .alert-chevron { transform: rotate(180deg); }

/* Evidence panel — collapsed by default, expands on click */
.alert-evidence {
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  border-left: 3px solid var(--border-subtle);
  background: var(--bg-surface-2);
  transition: max-height var(--ease-normal), opacity var(--ease-normal);
}
.alert-evidence.open { max-height: 260px; opacity: 1; }
.alert-evidence-inner { padding: 14px 16px 16px; }
.alert-evidence-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 14px;
}
.alert-evidence-label { font-size: 10.5px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 2px; }
.alert-evidence-value { font-size: 12.5px; font-weight: 600; color: var(--text-primary); }
.alert-evidence-note {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  font-size: 11.5px;
  color: var(--text-secondary);
  line-height: 1.5;
}

/* Evidence sparkline */
.spark-row { display: flex; align-items: flex-start; gap: 6px; }
.spark-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.spark-track { width: 100%; height: 50px; display: flex; align-items: flex-end; justify-content: center; }
.spark-bar { width: 100%; max-width: 22px; border-radius: 3px 3px 0 0; background: var(--primary); opacity: 0.8; transition: opacity var(--ease-fast); }
.spark-col:last-child .spark-bar { opacity: 1; }
.spark-label { font-size: 9.5px; color: var(--text-muted); white-space: nowrap; }

/* ─── Funnel Layer Dividers (Traffic page) ────────────── */
.funnel-layer-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 8px;
  padding-top: 16px;
  border-top: 1px solid var(--border-subtle);
}
.funnel-layer-badge {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.funnel-layer-title {
  font-family: var(--font-head);
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
}
.funnel-layer-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  margin-top: 1px;
}

/* ─── Funnel Visualization ─────────────────────────────── */
.funnel { display: flex; flex-direction: column; gap: 10px; padding: 16px; }
.funnel-row {
  display: grid;
  grid-template-columns: minmax(120px, 170px) 1fr minmax(64px, 84px) minmax(120px, 160px);
  align-items: center;
  gap: 12px;
}
.funnel-label { font-size: 12px; font-weight: 600; color: var(--text-secondary); }
.funnel-track {
  height: 20px;
  background: var(--bg-surface-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.funnel-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--primary), var(--purple));
  border-radius: var(--radius-sm);
  transition: width var(--ease-normal);
}
.funnel-value { font-size: 12.5px; font-weight: 700; color: var(--text-primary); text-align: right; }
.funnel-pct { font-size: 11px; color: var(--text-muted); text-align: right; white-space: nowrap; }
.funnel-drop { color: var(--danger); font-weight: 600; }

/* Clickable drill-down table rows */
.data-table tbody tr.clickable-row { cursor: pointer; }
.data-table tbody tr.row-active { background: var(--primary-light); }
.data-table tbody tr.row-active:hover { background: var(--primary-light); }

/* ─── Two-column Layout ───────────────────────────────── */
.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.two-col.left-heavy { grid-template-columns: 2fr 1fr; }
.two-col.right-heavy { grid-template-columns: 1fr 2fr; }

/* ─── Login Modal ─────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(7,10,18,0.85);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
.login-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 36px;
  width: 380px;
  box-shadow: 0 24px 64px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.05);
}
.login-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-bottom: 16px;
}
.login-logo { width: 32px; height: 32px; border-radius: 8px; object-fit: contain; }
.login-brand-name {
  font-family: var(--font-head);
  font-size: 18px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: -0.02em;
}
.login-title {
  font-family: var(--font-head);
  font-size: 22px;
  font-weight: 800;
  text-align: center;
  color: var(--text-primary);
  letter-spacing: -0.03em;
  margin-bottom: 4px;
}
.login-subtitle {
  font-size: 12.5px;
  color: var(--text-muted);
  text-align: center;
  margin-bottom: 24px;
}
.form-field { margin-bottom: 14px; }
.form-field label {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 5px;
}
.form-field input {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-surface-2);
  color: var(--text-primary);
  font-size: 13px;
  outline: none;
  transition: border-color var(--ease-fast), box-shadow var(--ease-fast);
}
.form-field input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-glow);
}
.login-error {
  font-size: 12px;
  font-weight: 600;
  color: var(--danger);
  background: var(--danger-bg);
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
  display: none;
}
.btn-login {
  width: 100%;
  padding: 10px;
  background: var(--primary);
  color: #fff;
  border-radius: var(--radius-md);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.01em;
  transition: background var(--ease-fast), transform var(--ease-fast);
}
.btn-login:hover { background: var(--primary-hover); transform: translateY(-1px); }
.btn-login:active { transform: translateY(0); }
.btn-login:disabled { opacity: 0.6; cursor: default; transform: none; }

.link-btn {
  display: block;
  width: 100%;
  text-align: center;
  margin-top: 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  transition: color var(--ease-fast);
}
.link-btn:hover { color: var(--primary); }

.login-success {
  font-size: 12px;
  font-weight: 600;
  color: var(--success);
  background: var(--success-bg);
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
}

/* ─── Notifications (Settings modal) ──────────────────── */
.notifications-list {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.notification-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--bg-surface);
}
.notification-item:last-child { border-bottom: none; }
.notification-item.unread { background: var(--primary-light); }
.notification-item-body { flex: 1; min-width: 0; }
.notification-item-msg { font-size: 12px; color: var(--text-primary); font-weight: 500; }
.notification-item-time { font-size: 10.5px; color: var(--text-muted); margin-top: 2px; }
.notification-item-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.notification-item-actions button {
  font-size: 11px;
  font-weight: 700;
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  background: var(--primary);
  color: #fff;
}
.notification-item-actions button.copied { background: var(--success); }
.notification-empty { padding: 16px; text-align: center; font-size: 12px; color: var(--text-muted); }

.btn-revoke, .btn-restore, .btn-edit {
  font-size: 10.5px;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  margin-right: 4px;
}
.btn-revoke { background: var(--danger-bg); color: var(--danger); }
.btn-restore { background: var(--success-bg); color: var(--success); }
.btn-edit { background: var(--bg-surface-2); color: var(--text-secondary); border: 1px solid var(--border); }

/* ─── Settings Modal (admin: invites + team) ──────────── */
.settings-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  width: 560px;
  max-width: calc(100vw - 32px);
  max-height: calc(100vh - 64px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 24px 64px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.05);
}
.settings-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 20px;
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}
.settings-header h2 { font-family: var(--font-head); font-size: 16px; font-weight: 800; color: var(--text-primary); }
.settings-body { padding: 20px; overflow-y: auto; }

/* ─── Generic data modal (state → city drill-down, etc.) ────── */
.data-modal-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  width: 960px;
  max-width: calc(100vw - 32px);
  max-height: calc(100vh - 40px);
  /* Flex items default to min-width:auto (content-based), which wins
     over max-width when a descendant's intrinsic content is wider — see
     .mover-row's comment for the exact case that hit this. min-width:0
     lets max-width actually be the hard cap it looks like. */
  min-width: 0;
  display: flex;
  flex-direction: column;
  box-shadow: 0 24px 64px rgba(0,0,0,0.3), 0 0 0 1px rgba(255,255,255,0.05);
}
.data-modal-header {
  /* Grid, not flex+space-between — a title left-aligned opposite a small
     corner close button reads lopsided. 1fr / auto / 1fr with the title
     pinned to the middle column puts it on the bar's true center line
     (the two empty 1fr columns balance each other) regardless of the
     close button's width, with no HTML change needed. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 18px 20px;
  border-bottom: 1px solid var(--border-subtle);
  flex-shrink: 0;
}
.data-modal-header h2 {
  grid-column: 2;
  text-align: center;
  font-family: var(--font-head);
  font-size: 16px;
  font-weight: 800;
  color: var(--text-primary);
}
.data-modal-header .btn-icon { grid-column: 3; justify-self: end; }
/* 20px on every side, matching the header's own padding — content was
   previously flush against the card edges (padding: 0) with nothing but
   the header bar giving any breathing room. */
.data-modal-body { padding: 20px; overflow-y: auto; }
.settings-section { margin-bottom: 24px; }
.settings-section:last-child { margin-bottom: 0; }
.settings-section h3 { font-size: 12.5px; font-weight: 700; color: var(--text-secondary); margin-bottom: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
.settings-row { display: flex; gap: 12px; }
.settings-row .form-field { flex: 1; }

.form-field select {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-surface-2);
  color: var(--text-primary);
  font-size: 13px;
  outline: none;
}

.permission-groups {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  max-height: 220px;
  overflow-y: auto;
  background: var(--bg-surface-2);
}
.permission-group { margin-bottom: 10px; }
.permission-group:last-child { margin-bottom: 0; }
.permission-group-title {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 4px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.permission-group-title button {
  font-size: 10px;
  font-weight: 600;
  color: var(--primary);
  text-transform: none;
  letter-spacing: normal;
}
.permission-check {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 0;
  font-size: 12px;
  color: var(--text-secondary);
  cursor: pointer;
}
.permission-check input { cursor: pointer; }

.invite-link-result {
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  background: var(--success-bg);
  border: 1px solid var(--success);
  border-radius: var(--radius-md);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--success);
}
.invite-link-result span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: monospace; }

/* ─── Empty State ─────────────────────────────────────── */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 24px;
  text-align: center;
  color: var(--text-muted);
}
.empty-state-icon { font-size: 36px; margin-bottom: 12px; opacity: 0.4; }
.empty-state-title { font-family: var(--font-head); font-size: 14px; font-weight: 700; color: var(--text-secondary); margin-bottom: 4px; }
.empty-state-desc  { font-size: 12px; }

/* ─── Utility ─────────────────────────────────────────── */
.text-right  { text-align: right; }
.text-left   { text-align: left; }
.text-center { text-align: center; }
.text-mono   { font-variant-numeric: tabular-nums; }
.fw-700 { font-weight: 700; }
.fw-600 { font-weight: 600; }
.text-success { color: var(--success); }
.text-danger  { color: var(--danger);  }
.text-warning { color: var(--warning); }
.text-muted   { color: var(--text-muted); }
.text-dim     { color: var(--text-dim); }

/* ─── Animations ──────────────────────────────────────── */
@keyframes fade-in-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.page-section { animation: fade-in-up 0.2s ease forwards; }

/* ─── Scrollbar global ────────────────────────────────── */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }

/* ─── Pincode Map (Geography page, Leaflet + markercluster) ───
   Basemap is plain, full-color OpenStreetMap raster tiles (app.js) — the
   classic Google Maps roadmap palette (tan landmass, green terrain, blue
   water, visible roads) the user asked to match against a reference
   screenshot. A flat desaturated version was tried first for a "Google
   Analytics" look, and CartoDB's free "Positron" tiles before that
   (turned out to silently watermark "API KEY REQUIRED" for
   unauthenticated requests) — full-color OSM is both the right look now
   and the one truly-free-forever tile source. */
/* height/width live here (not inline in app.js's template) specifically
   so the full-screen override below — a more specific descendant
   selector — can actually win. An inline style on the element would beat
   any CSS rule regardless of specificity, which is exactly what silently
   broke full-screen sizing the first time (container stayed pinned at
   560px, leaving a large blank gap under the map in the takeover view). */
#pincode-map-container { height: 560px; width: 100%; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); background: #e6ecf0; }
/* Dark mode only: full-color tiles left as-is in light mode (that's the
   actual look being matched), but a bright cream/green/blue map would be
   jarring dropped into an otherwise dark UI, so invert+hue-rotate
   approximates a dark map instead. bindTheme() (app.js) always sets
   data-theme explicitly to "dark" or "light" on load — no "system" mode
   to account for, so a plain attribute selector is enough. */
:root[data-theme="dark"] #pincode-map-container .leaflet-tile-pane {
  filter: invert(1) hue-rotate(180deg) brightness(0.95) contrast(0.9) saturate(0.7);
}
#pincode-map-container .leaflet-control-attribution { font-size: 9px; background: var(--bg-surface); color: var(--text-muted); }
#pincode-map-container .leaflet-bar a { background: var(--bg-surface); color: var(--text-primary); border-color: var(--border); }
#pincode-map-container .leaflet-popup-content-wrapper { background: var(--bg-surface); color: var(--text-primary); border-radius: 6px; }
#pincode-map-container .leaflet-popup-content { font-size: 12px; line-height: 1.6; }
#pincode-map-container .leaflet-popup-tip { background: var(--bg-surface); }

/* Hover tooltip — Orders/Revenue/AOV, shown on both individual pincode
   dots and cluster bubbles (see pincodeTooltipHtml in app.js). Leaflet
   tooltips are hover-triggered by default (unlike popups, which need a
   click), which is what this needs. */
.pincode-tooltip.leaflet-tooltip {
  background: var(--bg-surface); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.18);
  padding: 0; opacity: 1;
}
.pincode-tooltip.leaflet-tooltip::before { display: none; }
.pincode-tooltip-inner { padding: 8px 10px; font-size: 12px; min-width: 150px; }
.pincode-tooltip-inner strong { display: block; margin-bottom: 5px; font-size: 11.5px; color: var(--text-primary); }
.pincode-tooltip-inner div { display: flex; justify-content: space-between; gap: 14px; padding: 1px 0; color: var(--text-secondary); }
.pincode-tooltip-inner div span:last-child { font-weight: 700; color: var(--text-primary); }

.pincode-dot-icon { background: transparent; border: none; }
.pincode-dot {
  display: block; width: 100%; height: 100%; border-radius: 50%;
  background: color-mix(in srgb, var(--primary) 80%, #ff8f5c 20%);
  border: 1.5px solid rgba(255,255,255,0.9);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent), 0 1px 3px rgba(0,0,0,0.25);
  opacity: 0.88;
  transition: opacity 0.15s, transform 0.15s;
}
.pincode-dot-icon:hover .pincode-dot { opacity: 1; transform: scale(1.15); }
.pincode-cluster-icon { background: transparent; border: none; }
.pincode-cluster-bubble {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--primary) 70%, #ff9d6c 30%), color-mix(in srgb, var(--primary) 88%, black 8%));
  color: #fff; font-weight: 700; font-size: 11px; letter-spacing: 0.2px;
  border: 2px solid rgba(255,255,255,0.85);
  box-shadow: 0 2px 10px rgba(0,0,0,0.3);
}

/* ─── Pincode Map — Full-Screen Takeover ───
   Covers the whole viewport (sidebar included — see the HTML comment in
   index.html for why that's load-bearing, not just cosmetic) while the
   real Product Category/Source filter controls are parked in its
   toolbar. z-index sits below the login modal (1000) so an expired
   session can still surface over this, and above everything else
   (highest other z-index in this file is 400). */
.pincode-fullscreen-overlay {
  position: fixed; inset: 0; z-index: 500;
  background: var(--bg-app);
  display: flex; flex-direction: column;
}
.pincode-fullscreen-overlay[hidden] { display: none; }
.pincode-fullscreen-toolbar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 20px; border-bottom: 1px solid var(--border);
  background: var(--bg-surface); flex-shrink: 0;
}
.pincode-fullscreen-title { font-family: var(--font-head); font-size: 15px; font-weight: 700; flex-shrink: 0; }
.pincode-fullscreen-filters { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-left: auto; }
/* position:relative — the containing block #loading-overlay's inset:0
   needs once it's moved in here (openPincodeMapFullscreen), so the
   "crunching numbers" indicator scopes to just the map area instead of
   the whole fixed-position full-screen overlay (toolbar included). */
.pincode-fullscreen-body { flex: 1; min-height: 0; padding: 12px 20px 20px; position: relative; }
/* Leaflet's own chrome reaches z-index 1000 (zoom controls) — without
   this the loading indicator's usual z-index (400, style.css elsewhere)
   would render partly behind the map's markers/controls instead of
   cleanly covering it while a fetch is in flight. */
#pincode-fullscreen-body #loading-overlay { z-index: 1200; }
.pincode-fullscreen-body #pincode-map-container { height: 100%; width: 100%; }
/* .multiselect-panel's/.daterange-dropdown's usual z-index (200,
   style.css elsewhere) is fine against the rest of the page, but once
   these controls are parked inside the full-screen overlay, its local
   stacking context puts them in direct competition with Leaflet's own
   internal layers — Leaflet's zoom-control chrome (.leaflet-top/
   .leaflet-bottom) sits at z-index 1000, well above 200, so the dropdown
   panel rendered behind the map instead of over it. Scoped high enough
   to clear that. */
#pincode-fullscreen-filters .multiselect-panel,
#pincode-fullscreen-filters .daterange-dropdown { z-index: 1100; }

.card-fullscreen-btn {
  width: 28px; height: 28px; border-radius: 7px; border: none; cursor: pointer;
  background: var(--text-primary); color: var(--bg-surface);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  opacity: 0.82; transition: opacity 0.15s;
}
.card-fullscreen-btn:hover { opacity: 1; }
#pincode-fullscreen-exit-btn, #campaign-fullscreen-exit-btn { flex-shrink: 0; }

/* Campaign Performance's full-screen body: a real flex-fill chain down to
   .table-scroll, NOT "the whole body scrolls as one page" (tried first —
   see git history/conversation — but that broke position:sticky twice
   over: .campaign-pivot-toolbar's sticky-to-body needed .card's own
   overflow:hidden relaxed to even reach that containing block, AND
   .data-table thead th's EXISTING sticky-within-.table-scroll (used
   correctly everywhere else on this page, e.g. rows-10/rows-20) went
   inert once .table-scroll's own max-height/overflow was removed, since
   overflow-x:auto's computed overflow-y (auto, per spec — a scroll axis
   can't sit next to a plain 'visible' one) still made .table-scroll ITS
   OWN scroll boundary, just one with nothing to scroll since it now
   grew to fit all content instead of the outer body scrolling it).
   Instead: .card/.card-body/.table-scroll all get flex:1;min-height:0
   down the chain, so .table-scroll ends up with a real bounded height
   again (fills whatever's left below the toolbar) and its OWN existing
   overflow-y:auto + sticky thead just works, unmodified — the toolbar
   row above it needs no sticky positioning at all, since it's simply
   outside the one element that scrolls. */
#campaign-fullscreen-body {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 16px 20px;
}
#campaign-fullscreen-body .card {
  box-shadow: none;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
#campaign-fullscreen-body .card-body.no-pad {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
/* The inner .card-body (inline style="display:flex;flex-direction:column;
   gap:12px" from renderCampaignPivotCard) — adding flex-fill properties
   here, not touching `display`/`flex-direction`/`gap` already set inline. */
#campaign-fullscreen-body .card-body:not(.no-pad) {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}
#campaign-fullscreen-body .table-scroll {
  flex: 1;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
}

/* ─── Campaign Performance: frozen "group by" column ──────────────
   Source/Campaign/Product/Basket Size labels stay put horizontally
   while only the date columns scroll — applies in-page too (this table
   already scrolls horizontally there via .table-scroll's overflow-x),
   not just full-screen. Needs an opaque background (matching whatever
   that row already uses) since sticky doesn't clip what scrolls
   underneath by default — without it, date-column text would show
   through the "frozen" cell as it scrolls past. The thead corner cell
   is sticky on BOTH axes (top from the existing .data-table thead th
   rule, left from here) so it needs a higher z-index than the tbody's
   sticky-left cells, which only fight the horizontal scroll. */
.campaign-pivot-table th:first-child,
.campaign-pivot-table td:first-child {
  position: sticky;
  left: 0;
}
.campaign-pivot-table td:first-child {
  z-index: 2;
  background: var(--bg-surface);
}
.campaign-pivot-table thead th:first-child { z-index: 3; }
/* NOT var(--bg-hover) here — it's a deliberately near-transparent tint
   (rgba(...,0.05), meant to sit OVER a row's existing background) so on
   a normal row it barely shows. On this frozen cell it's the ONLY thing
   standing between the label and whatever date-column text has scrolled
   underneath — at 5% opacity that text visibly bled through the label on
   hover. --bg-surface-2 is an actual opaque color, so it fully covers. */
.campaign-pivot-table tbody tr:hover td:first-child { background: var(--bg-surface-2); }

/* ─── Campaign Performance: highlight the Total row + column ────── */
.campaign-pivot-table tbody tr.table-total-row {
  background: var(--bg-surface-2);
  border-top: 2px solid var(--primary);
}
.campaign-pivot-table tbody tr.table-total-row:hover { background: var(--bg-surface-2); }
.campaign-pivot-table tbody tr.table-total-row td { font-weight: 700; color: var(--text-primary); }
.campaign-pivot-table tbody tr.table-total-row td:first-child { background: var(--bg-surface-2); }
/* The Total COLUMN (last cell of every row, header included) — a
   running summary the eye should be able to track down the whole
   table, not just at the bottom. */
.campaign-pivot-table th:last-child,
.campaign-pivot-table td:last-child {
  font-weight: 700;
  background: var(--bg-surface-2);
}
.campaign-pivot-table tbody tr:hover td:last-child { background: var(--bg-hover); }
.campaign-pivot-table tbody tr.table-total-row td:last-child {
  background: var(--primary);
  color: #fff;
}

/* ─── Campaign Performance: drag-to-resize group-by column ────────
   Long campaign names (70+ chars, no spaces) get ellipsis-truncated at a
   FIXED width by default — a drag handle on the header cell's right edge
   lets the user widen it to read the full string instead of relying on
   the title-attribute hover tooltip alone. One CSS var, set on the
   .table-scroll ancestor by the drag handler (bindCampaignColumnResize
   in app.js) so every row's label cell picks it up at once without a
   per-row re-render. */
.campaign-pivot-table .campaign-row-label {
  max-width: var(--campaign-label-col-width, 300px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
.campaign-col-resize-handle {
  position: absolute;
  top: 0; right: -4px; bottom: 0;
  width: 8px;
  cursor: col-resize;
  z-index: 4;
  transition: background var(--ease-fast);
}
.campaign-col-resize-handle:hover,
.campaign-col-resize-handle.dragging {
  background: var(--primary);
  opacity: 0.5;
}

/* ─── Responsive Adjustments ─── */
@media (max-width: 900px) {
  .kpi-grid.cols-4, .kpi-grid.cols-5, .kpi-grid.cols-6 { grid-template-columns: repeat(2, 1fr); }
  .two-col { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
  .sidebar { width: 72px !important; }
  .sidebar .nav-text, .sidebar .arrow-box, .sidebar .nav-badge, .sidebar .sidebar-meta-text, .sidebar .brand span { display: none !important; }
  .sidebar .sub-item, .sidebar .submenu { display: none !important; }
  .sidebar .sidebar-header { flex-direction: column; align-items: center; gap: 8px; padding: 14px 4px !important; justify-content: center !important; }
  .sidebar .toggle-sidebar-btn { display: grid !important; }
  .sidebar .toggle-sidebar-btn svg { transform: rotate(180deg); }
  .kpi-grid.cols-3, .kpi-grid.cols-4 { grid-template-columns: 1fr; }
}