/* style.css — Mafar Healthcare Dashboard (v2 light theme)
 * Vanilla CSS port of the Manrope/light-theme mockup.
 * All colors via CSS custom properties. */

:root {
  /* Brand */
  --color-primary:        #1A365D;
  --color-secondary:      #0058be;
  --color-secondary-cont: #2170e4;

  /* Mafar corporate identity — the logo mark only. Deliberately separate from
     --color-primary (navy), which is the UI/data palette. Do not use these for
     buttons, links or chart series; they exist so the mark stays on-brand on
     every surface. Dark mode swaps green → gold for contrast (green is 1.7:1
     on the dark sidebar, gold is 7.4:1). */
  --brand-green:    #0F4D4A;
  --brand-gold:     #C8A46A;
  --brand-cream:    #F8F5EF;
  --brand-ink:      #2D2D2D;
  --brand-mark-bg:   var(--brand-cream);
  --brand-mark-fg:   var(--brand-green);
  --brand-mark-ring: rgba(15, 77, 74, 0.22);
  --brand-mark-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='779 314 1785 1785'%3E%3Cpath d='M1301 314L1305.9 316.9L1310.6 321.3L1775.9 786.1L1776.8 790.6L1775.2 794.1L1760.7 811.1L1672 899L1595.9 825L1453 682L1451 989L944 990.9L934 990L928 987.9L922.1 983.8L904.6 965.6L852.9 916.1L790.8 852.8L779 839L850.1 837.9L1301 838L1301 314ZM1892 1427L2001.8 1424.2L2289.5 1419L2366.2 1416.5L2385.3 1417.1L2399.9 1419.1L2411.7 1423L2422.2 1429.2L2433.1 1437.9L2452.5 1455.7L2476.6 1482L2504.1 1515.9L2562.5 1574.3L2564 1578L2043 1578L2041 2099L1993.8 2053.9L1578.6 1638.5L1565 1626L1566.2 1622.2L1568.7 1619L1670 1517L1677.8 1522.6L1889 1734L1890.2 1691.8L1892 1427ZM2042 318L2042 838L2563 839L2560.1 843.9L2555.7 848.6L2090 1314L2083.6 1309.6L2064 1291L1991.3 1218.2L1981 1209L1983.8 1204.2L1987.9 1199.8L2029.2 1160L2198 991L1936.4 989.1L1892 988L1891 465.9L1892.1 462.7L1895.1 458.7L1912.6 443.5L2020.7 336.3L2039.1 318.8L2042 318ZM1254 1102L1262.4 1108.2L1361 1207L1355.8 1214.4L1146 1425L1451 1428L1458.3 1906.3L1457.8 1925.5L1456.2 1939.8L1453.1 1950.6L1448.4 1959.6L1432.6 1978.2L1415.5 1993.5L1387.3 2014.8L1303.3 2098L1301.9 2003L1302 1578L780 1578L782.9 1573.1L787.3 1568.4L1254 1102Z'/%3E%3C/svg%3E");

  /* Semantic */
  --color-success:        #1D9E75;
  --color-error:          #ba1a1a;
  --color-warning:        #f97316;

  /* Surfaces */
  --color-bg:             #f7f9fb;
  --color-surface:        #ffffff;
  --color-surface-low:    #f2f4f6;
  --color-surface-cont:   #eceef0;
  --color-surface-high:   #e6e8ea;
  --color-surface-highest:#e0e3e5;

  /* Text */
  --color-on-surface:     #191c1e;
  --color-on-surface-var: #43474e;
  --color-outline:        #74777f;
  --color-outline-var:    #c4c6cf;

  /* Fonts */
  /* Single-family font strategy locked 2026-07-09 (Phase 2.6a).
     --font-mono and --font-headline deleted. Manrope everywhere.
     Column alignment for numeric cells: use .num-cell utility class
     (font-variant-numeric: tabular-nums). */
  --font-body:     "Manrope", system-ui, sans-serif;

  /* Typography scale — canonical font sizes.
     Introduced 2026-07-09 (Phase 2.5b). Preserves 11/12/13 tight cluster (531
     real declarations across platform); 14/17/22 snap to nearest anchor. */
  --font-size-xs:  11px;  /* meta labels, timestamps, badges */
  --font-size-sm:  12px;  /* secondary body, table cells */
  --font-size-md:  13px;  /* dominant body text */
  --font-size-lg:  16px;  /* sub-headings, larger body */
  --font-size-xl:  20px;  /* KPI values, card titles */
  --font-size-2xl: 24px;  /* page titles, hero numbers */

  /* Radii */
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;

  /* Spacing scale — canonical intervals for padding, margin, gap.
     Introduced 2026-07-09 (Phase 2.5b). See Phase 2.5a audit for hit distribution. */
  --space-2xs: 2px;   /* fine-tuning nudges — badge dots, 1px optical corrections */
  --space-xs:  4px;   /* tight interior gaps — pill padding, dense chip content */
  --space-sm:  8px;   /* icon + label gaps, small component padding */
  --space-md:  12px;  /* related-field gaps, medium component padding */
  --space-lg:  16px;  /* card body padding, section content spacing */
  --space-xl:  20px;  /* section separation, larger container padding */
  --space-2xl: 24px;  /* page-level margins, top-level section breaks */

  /* Effects */
  --shadow-cloud: 0 12px 32px rgba(24, 32, 52, 0.06);
  --ghost-border: inset 0 0 0 1px rgba(196,198,207,0.15);
  --radius-pill: 100px;
  --color-hairline: rgba(196,198,207,0.15);
  --color-divider:  rgba(196,198,207,0.30);
  --color-chart-grid: rgba(196, 198, 207, 0.25);
  /* Removed 2026-07-09 (Phase 2.5b): --color-toast-bg had zero live consumers
     after admin toast was deprecated. */

  /* Layout */
  --sidebar-w:     260px; /* unified 2.7c (was 288; Marketer/Tuesday were already 260, Admin 240) */
  --right-rail-w:  300px;

  /* Table surfaces */
  --color-surface-row-alt:      #fafafa;
  --color-surface-row-expanded: #f1f5f9;

  /* Aliases */
  --color-text-primary:         var(--color-on-surface);
  --color-text-secondary:       var(--color-on-surface-var);
  --color-border:               var(--color-outline-var);
  --color-border-tertiary:      rgba(196, 198, 207, 0.5);
  --color-bg-hover:             rgba(236, 238, 240, 0.5);
  --color-background-tertiary:  var(--color-surface-cont);
  --border-radius-md:           var(--radius-md);

  /* ── Dark-mode prep: new tokens (Block A) ── */

  /* Text on dark/coloured surfaces */
  --color-on-primary: #ffffff;

  /* Brand variants */
  --color-primary-hover:     #142e52;
  --color-error-hover:       #9e1515;
  --color-primary-container: #2e354a;

  /* Alt warn/bad (distinct from --color-warning / --color-error) */
  --color-warn-alt:         #BA7517;
  --color-bad-alt:          #E24B4A;
  --color-warn-alt-bg-soft: rgba(186, 117, 23, 0.08);
  --color-bad-alt-bg-soft:  rgba(226, 75, 74, 0.08);

  /* Tailwind wait-bar palette (visibly distinct from semantic tokens) */
  --color-emerald-500:         #10b981;
  --color-amber-500:           #f59e0b;
  --color-blue-500:            #3b82f6;
  --color-red-500:             #ef4444;
  --color-red-500-bg-soft:     rgba(239, 68, 68, 0.14);
  --color-emerald-500-bg-soft: rgba(34, 197, 94, 0.14);

  /* Hero-card text on dark gradient */
  --color-pace-behind:   #fca5a5;
  --color-pace-on:       #86efac;
  --color-pace-amber:    #fde68a;
  --color-hero-label:    rgba(190, 198, 224, 0.9);
  --color-hero-sublabel: rgba(190, 198, 224, 0.85);

  /* Accents */
  --color-accent-pink:      #e91e8c;
  --color-accent-mix-green: #43a047;

  /* Info (cyan badge / MTD strip) */
  --color-info-bg-faint: #f0f9ff;
  --color-info-bg-soft: #e0f2fe;
  --color-info-text:    #0369a1;

  /* MTD strip */

  /* Maroon */
  --color-maroon:         #72001f;
  --color-maroon-bg-soft: rgba(114, 0, 31, 0.08);

  /* Greys not in surface/outline scale */
  --color-slate-500: #64748b;
  --color-slate-400: #94a3b8;
  --color-gray-500:  #6b7280;
  --color-gray-400:  #999999;
  --color-gray-300:  #cbd5e1;
  --color-gray-200:  #d1d5db;
  --color-gray-800:  #1f2937;

  /* Borders / dividers */
  --color-border-soft: #e8edf3;
  --color-border-cal:  #e2e8f0;

  /* Hover backgrounds */
  --color-hover-soft:   #eef0f4;
  --color-hover-soft-2: #f0f2f5;

  /* Motion tokens */
  --transition-fast: .1s; --transition: .15s; --transition-slow: .2s;
  --ease: ease; --spin-duration: .7s;

  /* Focus ring + modal scrim */
  --color-focus-ring:  rgba(0, 88, 190, 0.2);
  --color-modal-scrim: rgba(0, 0, 0, 0.35);
  /* Canonical keyboard focus ring (keyboard-only via :focus-visible) */
  --focus-ring: 0 0 0 3px rgba(33,112,228,0.35);

  /* Nav hover */
  --color-nav-hover: rgba(148, 163, 184, 0.20);
  --color-nav-active-bg:   #eef2ff;
  --color-nav-active-text: #2563eb;

  /* Brand-at-opacity tints */
  --color-primary-bg-soft:         rgba(33, 112, 228, 0.10);
  --color-primary-bg-faint:        rgba(26, 54, 93, 0.10);
  --color-secondary-bg-soft:       rgba(0, 88, 190, 0.10);
  --color-secondary-bg-faint:      rgba(0, 88, 190, 0.06);
  --color-secondary-cont-bg-soft:  rgba(33, 112, 228, 0.10);
  --color-secondary-cont-bg-faint: rgba(33, 112, 228, 0.08);
  --color-success-bg-soft:         rgba(29, 158, 117, 0.10);
  --color-success-bg-faint:        rgba(29, 158, 117, 0.08);
  --color-error-bg-soft:           rgba(186, 26, 26, 0.08);
  --color-error-bg-faint:          rgba(186, 26, 26, 0.06);
  --color-warning-bg-soft:         rgba(249, 115, 22, 0.10);
  --color-warning-bg-faint:        rgba(249, 115, 22, 0.08);

  /* Status / panel badge pairs */
  --status-active-bg:    #E1F5EE;  --status-active-text:    #085041;
  --status-progress-bg:  #E6F1FB;  --status-progress-text:  #0C447C;
  --status-apply-bg:     #FAEEDA;  --status-apply-text:     #633806;
  --status-reject-bg:    #FCEBEB;  --status-reject-text:    #791F1F;
  --status-issue-bg:     #FAECE7;  --status-issue-text:     #712B13;
  --status-no-need-bg:   #F1EFE8;  --status-no-need-text:   #5F5E5A;

  /* ── Dark-mode prep: topbar tokens ── */
  --color-topbar-bg: rgba(255,255,255,0.88);
  --shadow-topbar:   0 1px 4px rgba(24,32,52,0.05);

  /* ── Token-split: brand as text (light = alias, dark = bright) ── */
  --color-primary-text:   var(--color-primary);
  --color-secondary-text: var(--color-secondary);
  --color-success-text:   var(--color-success);
  --color-error-text:     var(--color-error);
  --color-warning-text:   var(--color-warning);

  /* Color role tokens — semantic aliases resolving the --color-outline overload.
     Introduced 2026-07-09 (Phase 2.5b). Values match the current dominant
     substitutes; zero visual change. */
  --color-border-subtle: rgba(196, 198, 207, 0.30);  /* hairline dividers, subtle borders */
  --color-text-subtle:   #74777f;                    /* de-emphasized labels */

  /* Removed 2026-07-09 (Phase 2.5b): breakpoint tokens are CSS-invalid —
     custom properties cannot be used inside @media conditions. Use literal
     px values in @media rules. */
}

/* ── Light explicit (color-scheme for native controls/scrollbars) ── */
[data-theme="light"] {
  color-scheme: light;
}

/* ── Dark mode overrides ── */
[data-theme="dark"] {
  color-scheme: dark;

  /* Topbar */
  --color-topbar-bg: rgba(22,27,34,0.88);
  --shadow-topbar:   0 1px 4px rgba(0,0,0,0.30);

  /* Corporate mark — the disc stays a muted surface and the mark carries the
     brand colour, but green is unreadable on dark so it becomes gold (6.5:1 on
     the disc; green would be 1.7:1). */
  --brand-mark-bg:   var(--color-surface-cont);
  --brand-mark-fg:   var(--brand-gold);
  --brand-mark-ring: rgba(200, 164, 106, 0.24);

  /* Brand fills — dark enough for white text on top */
  --color-primary:   #1e3a5f;
  --color-secondary: #0058be;
  --color-success:   #1D9E75;
  --color-error:     #ba1a1a;
  --color-warning:   #fb923c;

  /* Brand as text/accent — bright for dark surfaces */
  --color-primary-text:   #e6edf3;
  --color-secondary-text: #4a90e2;
  --color-success-text:   #3fb98b;
  --color-error-text:     #f47174;
  --color-warning-text:   #fb923c;

  --color-secondary-cont: #5fa3ff;

  /* Surfaces */
  --color-bg:              #0d1117;
  --color-surface:         #161b22;
  --color-surface-low:     #1c2128;
  --color-surface-cont:    #21262d;
  --color-surface-high:    #2d333b;
  --color-surface-highest: #373e47;

  /* Table surfaces */
  --color-surface-row-alt:      #1a1f26;
  --color-surface-row-expanded: #232830;

  /* Text */
  --color-on-surface:     #e6edf3;
  --color-on-surface-var: #8b949e;

  /* Borders */
  --color-outline:     #6e7681;
  --color-outline-var: #30363d;
  --color-border-soft: #1c2128;
  --color-border-cal:  #21262d;

  /* Aliases */
  --color-border-tertiary: rgba(139,148,158,0.25);
  --color-bg-hover:        rgba(255,255,255,0.04);

  /* Hover backgrounds */
  --color-hover-soft:   rgba(255,255,255,0.04);
  --color-hover-soft-2: rgba(255,255,255,0.06);
  --color-nav-hover:    rgba(148,163,184,0.12);
  --color-nav-active-bg:   rgba(95,163,255,0.14);
  --color-nav-active-text: #60a5fa;

  /* Effects */
  --shadow-cloud:      0 12px 32px rgba(0,0,0,0.45);
  --ghost-border:      inset 0 0 0 1px rgba(139,148,158,0.20);
  --color-hairline: rgba(139,148,158,0.18);
  --color-divider:  rgba(139,148,158,0.35);
  --color-chart-grid: rgba(196, 198, 207, 0.12);
  /* Removed 2026-07-09 (Phase 2.5b): --color-toast-bg had zero live consumers
     after admin toast was deprecated. */
  --color-focus-ring:  rgba(74,144,226,0.35);
  --color-modal-scrim: rgba(0,0,0,0.65);
  --focus-ring: 0 0 0 3px rgba(95,163,255,0.45);

  /* Brand variants */
  --color-primary-hover:     #2a4f80;
  --color-error-hover:       #c93030;
  --color-primary-container: #2e354a;

  /* Alt warn/bad */
  --color-warn-alt:         #d99443;
  --color-bad-alt:          #f06b6a;
  --color-warn-alt-bg-soft: rgba(217,148,67,0.18);
  --color-bad-alt-bg-soft:  rgba(240,107,106,0.18);

  /* Tailwind palette */
  --color-emerald-500:         #34d399;
  --color-amber-500:           #fbbf24;
  --color-blue-500:            #60a5fa;
  --color-red-500:             #f87171;
  --color-red-500-bg-soft:     rgba(248,113,113,0.20);
  --color-emerald-500-bg-soft: rgba(52,211,153,0.20);

  /* Accents */
  --color-accent-pink:      #f06bb0;
  --color-accent-mix-green: #66bb6a;

  /* Info */
  --color-info-bg-faint:   rgba(56, 189, 248, 0.08);
  --color-info-bg-soft:    rgba(56,189,248,0.16);
  --color-info-text:       #7dd3fc;

  /* Maroon */
  --color-maroon:         #c2425a;
  --color-maroon-bg-soft: rgba(194,66,90,0.18);

  /* Grey scale */
  --color-slate-500: #94a3b8;
  --color-slate-400: #b8c2cf;
  --color-gray-500:  #9ca3af;
  --color-gray-400:  #a8a8a8;
  --color-gray-300:  #4b5563;
  --color-gray-200:  #374151;
  --color-gray-800:  #d1d5db;

  /* Brand-at-opacity tints */
  --color-primary-bg-soft:         rgba(95,163,255,0.18);
  --color-primary-bg-faint:        rgba(91,139,209,0.14);
  --color-secondary-bg-soft:       rgba(74,144,226,0.18);
  --color-secondary-bg-faint:      rgba(74,144,226,0.10);
  --color-secondary-cont-bg-soft:  rgba(95,163,255,0.18);
  --color-secondary-cont-bg-faint: rgba(95,163,255,0.12);
  --color-success-bg-soft:         rgba(63,185,139,0.18);
  --color-success-bg-faint:        rgba(63,185,139,0.12);
  --color-error-bg-soft:           rgba(244,113,116,0.18);
  --color-error-bg-faint:          rgba(244,113,116,0.10);
  --color-warning-bg-soft:         rgba(251,146,60,0.18);
  --color-warning-bg-faint:        rgba(251,146,60,0.12);

  /* Status / panel badge pairs */
  --status-active-bg:   rgba(63,185,139,0.16);  --status-active-text:   #6ee7b7;
  --status-progress-bg: rgba(95,163,255,0.16);  --status-progress-text: #93c5fd;
  --status-apply-bg:    rgba(251,191,36,0.16);  --status-apply-text:    #fcd34d;
  --status-reject-bg:   rgba(244,113,116,0.16); --status-reject-text:   #fca5a5;
  --status-issue-bg:    rgba(251,146,60,0.16);  --status-issue-text:    #fdba74;
  --status-no-need-bg:  rgba(148,163,184,0.16); --status-no-need-text:  #cbd5e1;

  /* Color role tokens — dark-mode overrides (Phase 2.5b, 2026-07-09) */
  --color-border-subtle: rgba(139, 148, 158, 0.35);
  --color-text-subtle:   #6e7681;

  .content-center,
  .content-right { background: var(--color-bg); }
}

/* ── Reset ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--color-on-surface);
  background: var(--color-bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--color-secondary-text); text-decoration: none; }
a:hover { text-decoration: underline; }
button { cursor: pointer; font: inherit; border: none; background: transparent; }
table { border-collapse: collapse; width: 100%; }
input { font: inherit; }

/* ── App shell ── */
.app {
  display: flex;
  height: 100vh;
  overflow: hidden;
}

/* ── Sidebar ── */
.sidebar {
  width: var(--sidebar-w);
  min-width: var(--sidebar-w);
  background: var(--color-surface);
  border-right: 1px solid var(--color-outline-var);
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
  position: sticky;
  top: 0;
  z-index: 50;
}

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 20px 16px;
  border-bottom: 1px solid var(--color-divider);
}

/* Corporate mark. Canonical across every portal — clinic, marketer, inventory,
   tuesday, admin and upload all reach for .brand-mark. The glyph is masked
   rather than inlined so one rule tints it for both themes; the element needs
   no children. The disc is a muted surface and the mark carries the brand
   colour, so the ring is what separates the disc from the sidebar behind it. */
.brand-mark,
.sidebar__brand-icon,
.mkt-logo,
.tue-logo {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--brand-mark-bg);
  box-shadow: inset 0 0 0 1px var(--brand-mark-ring);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 0;           /* neutralises any leftover text node */
}

.brand-mark::before,
.sidebar__brand-icon::before,
.mkt-logo::before,
.tue-logo::before {
  content: '';
  width: 60%;
  height: 60%;
  background: var(--brand-mark-fg);
  -webkit-mask: var(--brand-mark-glyph) center / contain no-repeat;
  mask: var(--brand-mark-glyph) center / contain no-repeat;
}

.brand-mark--sm { width: 32px; height: 32px; }
.brand-mark--lg { width: 48px; height: 48px; }

.sidebar__brand-name {
  font-size: 15px;
  font-weight: 800;
  color: var(--color-primary-text);
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.sidebar__brand-sub {
  font-size: 11px;
  color: var(--color-on-surface-var);
  margin-top: 1px;
}

.sidebar__search-wrap {
  position: relative;
  padding: 12px 16px 8px;
}

.sidebar__nav {
  flex: 1;
  overflow-y: auto;
  padding: 8px 0 8px;
}
.sidebar__nav::-webkit-scrollbar { width: 3px; }
.sidebar__nav::-webkit-scrollbar-thumb { background: var(--color-outline-var); border-radius: 2px; }

/* Sidebar nav item — canonical (Wave 13, 2026-07-08)
   Portal-agnostic sidebar navigation. Migrated from portal-local patterns
   (.tue-nav-item, .nav-clinic-item, .admin-nav__item, .mkt-nav-item) in B8.
   Base shape mirrors Tuesday's original .tue-nav-item; structural context
   handled by --nested / --flat modifiers. */

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border-radius: var(--radius-md);
  font-size: 13px;
  color: var(--color-on-surface-var);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
  user-select: none;
}

.nav-item:hover:not(.nav-item--active) {
  background: var(--color-surface-low);
  color: var(--color-on-surface);
  text-decoration: none;
}

.nav-item:hover {
  text-decoration: none;
}

.nav-item--active {
  background: var(--color-nav-active-bg);
  color: var(--color-nav-active-text);
  font-weight: 600;
  text-decoration: none;
}

.nav-item:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Slots — internal anatomy for leading/label/trailing content */

.nav-item__leading {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: inherit;
}

.nav-item__leading .ti {
  font-size: 18px;
}

.nav-item__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-decoration: inherit;
}

.nav-item__trailing {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: auto;
  text-decoration: inherit;
}

/* Structural modifiers — encode structural context, not portal identity */

.nav-item--nested {
  padding: 7px 16px 7px 24px;
  margin: 1px 8px;
  justify-content: space-between;
  font-weight: 500;
}

.nav-item--nested.nav-item--active {
  font-weight: 600;
}

.nav-item--flat {
  border-radius: 0;
  padding: 10px 20px;
}

/* Status dot — for use inside .nav-item__leading or __trailing */

.nav-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--color-outline-var);
}

.nav-dot--on-target    { background: var(--color-success); }
.nav-dot--warning      { background: var(--color-warning); }
.nav-dot--below-target { background: var(--color-error); }

/* ── Main ── */
.main {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

/* ── Topbar mount (topbar.js injects its own styles) ── */
#topbar-mount { flex-shrink: 0; }

/* Month nav */
.month-nav {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ── Content row (center + right rail) ── */
.content-row {
  flex: 1;
  display: flex;
  min-height: 0;
  overflow-y: auto;
}

.content-center {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  padding: 20px 28px;
  background: rgba(247,249,251,0.5);
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.content-center::-webkit-scrollbar { width: 4px; }
.content-center::-webkit-scrollbar-thumb { background: var(--color-outline-var); border-radius: 2px; }

.content-right {
  width: var(--right-rail-w);
  min-width: var(--right-rail-w);
  overflow-y: auto;
  padding: 28px 20px 28px 0;
  background: rgba(247,249,251,0.5);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.content-right::-webkit-scrollbar { width: 3px; }
.content-right::-webkit-scrollbar-thumb { background: var(--color-outline-var); border-radius: 2px; }

/* ── Page header ── */
.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  background: var(--color-surface);
  padding: 20px 28px 10px;
  flex-shrink: 0;
}
/* Portfolio Overview uses .page-header as an outer two-row wrapper with
   .content-header-top as an inner header row + a second row below for the
   toggle. Without this rule, .content-header-top shrinks to content width
   inside the row-direction .page-header. Phase 2.10 will revisit whether
   .page-header should officially support both single-row and stacked
   layouts, or whether the portfolio needs a different canonical class. */
.page-header > .content-header-top {
  flex: 1;
}

.content-header-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 4px;
}

.header-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.page-header__title {
  font-size: 32px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--color-primary-text);
  margin: 0;
  font-family: inherit;
}

.page-header__sub {
  font-size: 14px;
  font-weight: 500;
  color: var(--color-on-surface-var);
  margin: 8px 0 0 0;
}

.page-header__actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* ── Card base ── */
.card {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-cloud);
  box-shadow: var(--shadow-cloud), var(--ghost-border);
}

/* ── Banner ── */
.banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 24px;
  background: var(--color-surface);
  border-bottom: 0.5px solid var(--color-outline-var);
  font-size: 13px;
  color: var(--color-on-surface);
  flex-shrink: 0;
}

.banner__action {
  margin-left: auto;
  padding: 5px 12px;
  border: 0.5px solid var(--color-outline-var);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
  font-size: 12px;
  font-family: inherit;
  color: var(--color-on-surface);
}

.banner__action:hover { background: var(--color-surface-low); }

.banner > .btn {
  margin-left: auto;
}

.banner__close {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-on-surface-var);
  font-size: 18px;
  line-height: 1;
  padding: 0 0 0 4px;
}

.banner__close:hover { color: var(--color-on-surface); }

.banner--info    { background: var(--color-info-bg-soft); color: var(--color-on-surface); }
.banner--warning { background: var(--color-warning-bg-faint); color: var(--color-warning-text); }
.banner--error   { background: var(--color-error-bg-faint);   color: var(--color-error-text); }
.banner--success { background: var(--color-success-bg-faint); color: var(--color-success-text); }

/* ── KPI grid ── */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

.kpi-card {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-cloud), var(--ghost-border);
  padding: 20px 20px 18px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 120px;
}

.kpi-card__header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 12px;
}

.kpi-card__label {
  font-size: 13px;
  font-weight: 600;
  color: var(--kpi-label-color, var(--color-on-surface-var));
}

.kpi-card__icon {
  font-size: 20px;
  color: var(--color-outline-var);
}

.kpi-card__value {
  font-size: 26px;
  font-weight: 700;
  font-family: var(--font-body);
  color: var(--kpi-value-color, var(--color-primary-text));
  line-height: 1.1;
  letter-spacing: -0.02em;
}

.kpi-card__delta {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 8px;
  font-size: 13px;
  font-weight: 600;
}
.kpi-card__delta .ti { font-size: 15px; }

.kpi-card__delta--up   { color: var(--color-success-text); }
.kpi-card__delta--down { color: var(--color-error-text); }

/* Compact KPI card variant (inline strips, e.g. client dashboard header) */
.kpi-card--compact {
  padding: 10px 16px;
  min-height: auto;
  justify-content: flex-start;
  min-width: 90px;
}
.kpi-card--compact .kpi-card__value {
  font-size: 1.5rem;
  font-family: var(--font-body);
  letter-spacing: 0;
}
.kpi-card--compact .kpi-card__label {
  margin-top: 4px;
}

/* Value color state modifiers (works on any kpi-card, useful for compact strips) */
.kpi-card--error   { background: var(--color-error-bg-faint); }
.kpi-card--success { background: var(--color-success-bg-faint); }
.kpi-card--error   .kpi-card__value { color: var(--color-error-text); }
.kpi-card--success .kpi-card__value { color: var(--color-success-text); }
.kpi-card--warning { background: var(--color-warning-bg-faint); }
.kpi-card--warning .kpi-card__value { color: var(--color-warning-text); }

.kpi-card--clickable,
.kpi-card.is-clickable {
  cursor: pointer;
  transition: transform 0.15s, background 0.15s;
}
.kpi-card--clickable:hover,
.kpi-card.is-clickable:hover {
  transform: translateY(-1px);
  background: var(--color-surface-low);
}

/* Generic clickable-affordance escape hatch — applies to any non-button
   element wired for click. Phase 2.0's KPI-card-scoped grouped selector
   handles hover styling for kpi cards; this generic rule provides the
   cursor across all portals. Added post-B5 shipping-report review. */
.is-clickable { cursor: pointer; }

.kpi-card__sublabel {
  font-size: 11px;
  color: var(--color-on-surface-var);
  margin-top: 4px;
}

.kpi-card__alert {
  margin-top: 8px;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  font-size: 11px;
  font-weight: 500;
}
.kpi-card__alert--info    { background: var(--color-info-bg-soft); color: var(--color-info-text); }
.kpi-card__alert--warning { background: var(--color-warning-bg-faint); color: var(--color-warning-text); }
.kpi-card__alert--error   { background: var(--color-error-bg-faint);   color: var(--color-error-text); }
.kpi-card__alert--success { background: var(--color-success-bg-faint); color: var(--color-success-text); }

.kpi-card__delta--flat { color: var(--color-on-surface-var); }

/* Hero KPI card */
.kpi-card--hero {
  background: linear-gradient(45deg, var(--color-primary), var(--color-primary-container));
  color: var(--color-on-primary);
  position: relative;
  overflow: hidden;
}

.kpi-card--hero::before {
  content: "\eb35"; /* ti-target */
  font-family: "tabler-icons";
  font-size: 72px;
  position: absolute;
  top: 0;
  right: 8px;
  opacity: 0.08;
  line-height: 1;
}

.kpi-card--hero .kpi-card__label { color: var(--color-hero-label); }
.kpi-card--hero .kpi-card__value { color: var(--color-on-primary); }

/* Promoted from clinic.css (2 Sep 2026) — target bar + pace chip are used by
   the clinic MTD hero card AND the marketer GP Sales tab. */
/* ── Target progress bar (KPI cards) ── */
.target-bar { margin-top: 10px; }
.target-bar__track {
  width: 100%;
  height: 4px;
  background: var(--color-outline-var);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.target-bar__fill {
  height: 100%;
  border-radius: var(--radius-sm);
  min-width: 2px;
  transition: width 0.4s ease;
}
.target-bar__fill--red   { background: var(--color-error); }
.target-bar__fill--amber { background: var(--color-warning); }
.target-bar__fill--green { background: var(--color-success); }
.target-bar__meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 11px;
  color: var(--color-on-surface-var);
  margin-top: 4px;
}
.target-bar__pct { font-weight: 700; }
.target-bar__pct--red   { color: var(--color-error-text); }
.target-bar__pct--amber { color: var(--color-warning-text); }
.target-bar__pct--green { color: var(--color-success-text); }

/* Pace chip (MTD hero card) */
.pace-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding: 3px 9px;
  border-radius: 10px;
  margin-top: 7px;
}
.pace-chip--behind { background: var(--color-red-500-bg-soft); color: var(--color-pace-behind); }
.pace-chip--on     { background: var(--color-emerald-500-bg-soft);  color: var(--color-pace-on); }

/* Hero (dark MTD card) overrides */
.kpi-card--hero .target-bar__track { height: 6px; background: rgba(255,255,255,0.10); }
.kpi-card--hero .target-bar__fill  { height: 6px; }
.kpi-card--hero .target-bar__meta  { color: rgba(255,255,255,0.40); }
.kpi-card--hero .target-bar__pct--red   { color: var(--color-pace-behind); }
.kpi-card--hero .target-bar__pct--amber { color: var(--color-pace-amber); }
.kpi-card--hero .target-bar__pct--green { color: var(--color-pace-on); }

/* ── Section card (scoreboard, charts) ── */
.section-card {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-cloud), var(--ghost-border);
  overflow: hidden;
  min-height: fit-content;
}

.section-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--color-divider);
}

.section-card__title {
  font-size: 16px;
  font-weight: 700;
  font-family: var(--font-body);
  color: var(--color-primary-text);
  margin: 0;
}

.section-card__subtitle {
  display: block;
  color: var(--color-on-surface-var);
  font-size: var(--font-size-md);
  font-weight: 400;
  margin-top: var(--space-2xs);
}

.section-card__title-group {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex: 1;
  min-width: 0;
}

.section-card__icon {
  flex-shrink: 0;
  font-size: var(--font-size-xl);
  color: var(--color-on-surface-var);
  line-height: 1;
}

.section-card__body { padding: 16px 20px 20px; }
/* Zero-padding table body modifier — used when a section card's body is a
   full-bleed table that manages its own padding. */
/* -webkit-overflow-scrolling for parity with the other table scrollers
   (.data-table-scroll, .clinic-table-scroll, .mkt-table-wrap) — this one
   is the fallback scroller for tables handed straight to sectionCard's
   bodyHtml, and it was the only one without momentum on older iOS. */
.section-card__body--table {
  padding: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
/* Zero-padding body modifier — used when a section card's body is a
   custom layout that manages its own padding (forms, grids, dashboards).
   Distinct from --table which is specifically for full-bleed table content.
   Introduced 2026-07-09 (Phase 2.5c). */
.section-card__body--flush {
  padding: 0;
}
.section-card__footer {
  padding: 16px 20px;
  border-top: 0.5px solid var(--color-divider);
}

/* ── Scoreboard table ── */
.scoreboard-table {
  width: 100%;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.scoreboard-table thead tr {
  background: var(--color-surface-low);
}

.scoreboard-table th:first-child,
.scoreboard-table td:first-child { width: 40px; text-align: center; }
.scoreboard-table th:nth-child(3),
.scoreboard-table td:nth-child(3) { width: 120px; }
.scoreboard-table th:nth-child(4),
.scoreboard-table td:nth-child(4) { width: 100px; }
.scoreboard-table th:nth-child(5),
.scoreboard-table td:nth-child(5) { width: 100px; }

/* Cell metrics come from canonical .data-table (0,1,2) rules — the
   (0,1,1) padding/typography/border declarations that used to sit here
   were shadowed dead and were removed in Phase 2.7b. Only live
   declarations remain. */
.scoreboard-table th {
  cursor: pointer;
  user-select: none;
  transition: color 0.15s;
}
.scoreboard-table th:hover { color: var(--color-on-surface); }
.scoreboard-table th.sort-active { color: var(--color-primary-text); }

.scoreboard-table th.text-right,
.scoreboard-table td.text-right { text-align: right; }

/* (0,0,1) per the table-cascade flattening contract — bare cell utilities
   (e.g. .inv-name-cell, .tone--strong) outrank this without compounds. */
:where(.scoreboard-table) td {
  font-weight: 500;
}

.scoreboard-table tbody tr {
  cursor: pointer;
  transition: background 0.12s;
}

.scoreboard-table .clinic-name {
  font-weight: 600;
  color: var(--color-primary-text);
}
.scoreboard-table .clinic-name-text {
  display: block;
  max-width: 160px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.scoreboard-table .revenue-val {
  font-weight: 700;
  color: var(--color-on-surface);
  font-family: var(--font-body);
}

.scoreboard-table thead th:first-child,
.scoreboard-table tbody td:first-child { padding-left: 24px; }

.scoreboard-table thead th:last-child,
.scoreboard-table tbody td:last-child  { padding-right: 24px; }

/* Zebra at (0,0,0): any bare row class carrying a background (e.g.
   .inv-total-row) outranks the stripe without a compound. */
:where(.scoreboard-table tbody tr:nth-child(even)) { background: var(--color-surface-row-alt); }

/* Pill badges in table */
.pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  font-size: 11px;
  font-weight: 600;
}
.pill--up   { background: var(--color-primary-bg-soft); color: var(--color-secondary-cont); }
.pill--down { background: var(--color-error-bg-soft); color: var(--color-error-text); }
.pill--success { background: var(--color-success-bg-faint); color: var(--color-success-text); }
.pill--warning { background: var(--color-warning-bg-faint); color: var(--color-warning-text); }
.pill--info    { background: var(--color-info-bg-soft); color: var(--color-info-text); }

/* ── UI.badge shared primitive (.ui-* namespace) ── */
.ui-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 12px;
  white-space: nowrap;
}
.ui-badge--default { background: var(--color-surface-cont);    color: var(--color-on-surface-var); }
.ui-badge--muted   { background: var(--color-surface-low);     color: var(--color-on-surface-var); border-color: var(--color-hairline); }
.ui-badge--success { background: var(--color-success-bg-soft); color: var(--color-success-text);   border-color: var(--color-success-bg-soft); }
.ui-badge--warning { background: var(--color-warning-bg-soft); color: var(--color-warning-text);   border-color: var(--color-warning-bg-soft); }
.ui-badge--error   { background: var(--color-error-bg-soft);   color: var(--color-error-text);     border-color: var(--color-error-bg-soft); }
.ui-badge--info    { background: var(--color-info-bg-soft);    color: var(--color-info-text);      border-color: var(--color-info-bg-soft); }

/* Square shape variant (Phase 2.6h, 2026-08-19). Canonical .ui-badge is a
   12px pill; Inventory's enum badges are squared with a dot slot. Adopted as
   a modifier rather than converging either side, per the 2.7b
   .alert-badge--prominent precedent. */
.ui-badge--square {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
}
.ui-badge--square.ui-badge--bold {
  font-weight: 700;
  padding: 2px 10px;
}
/* Status indicator dot. Inherits the badge's own text colour so a single
   data-driven textColor drives both — no second inline channel. */
.ui-badge__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  background: currentColor;
}
/* Secondary-text slot inside a badge (e.g. a variance's RM amount).
   Rendered via the typed subLabel prop — escaped by the factory; there is
   deliberately no raw-HTML slot on UI.badge (Codex R2). */
.ui-badge__sub {
  font-size: 10px;
  opacity: 0.8;
}

/* Avatar initials use white text for guaranteed WCAG AA contrast against
   any tinted background hue produced by _avatarColor() hash. Font-weight
   500 improves readability of white text on colored fills. Ships as
   HF-2 post-B3 (2026-07-06). */
/* ── Avatar canonical (UI.avatar factory) ── */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-weight: 600;
  color: white;
  background: var(--color-primary);
  text-transform: uppercase;
  flex-shrink: 0;
  overflow: hidden;
}

.avatar img { width: 100%; height: 100%; object-fit: cover; }

.avatar--xs { width: 20px; height: 20px; font-size: 10px; }
.avatar--sm { width: 24px; height: 24px; font-size: 11px; }
.avatar--md { width: 32px; height: 32px; font-size: 12px; }
.avatar--lg { width: 40px; height: 40px; font-size: 14px; }

/* ── Chart container ── */
.chart-wrap {
  position: relative;
  width: 100%;
}

/* Trend toggle buttons — legacy .range-toggle block removed 2026-08-17
   (clinic mobile pass). It predated the Wave 3b canonical segmented
   control (defined later in this file) and its surviving `gap: 4px`
   pushed the per-button hairline dividers away from the buttons,
   rendering a floating line beside the active state on every
   UI.rangeToggle instance. */

/* ── Right rail panels ── */
.rail-panel {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-cloud), var(--ghost-border);
  padding: 18px;
}

.rail-panel__title {
  font-size: 15px;
  font-weight: 700;
  font-family: var(--font-body);
  color: var(--color-primary-text);
  margin-bottom: 14px;
}

/* Alert cards */
.alert-card {
  padding: 10px 12px;
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  margin-bottom: 10px;
}

.alert-card:last-child { margin-bottom: 0; }

.alert-card--critical {
  border-left: 4px solid var(--color-error);
  background: rgba(186,26,26,0.04);
}

.alert-card--warning {
  border-left: 4px solid var(--color-warning);
  background: rgba(249,115,22,0.04);
}

.alert-card--clear {
  border-left: 4px solid var(--color-success);
  background: rgba(29,158,117,0.05);
}

.alert-badge {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.alert-badge--critical { color: var(--color-error-text); }
.alert-badge--warning  { color: var(--color-warning-text); }

/* Larger alert text for rail alert cards (Inventory Needs-attention).
   Canonical size modifier added Phase 2.7b — replaces the three inline
   font-size/font-weight overrides flagged by 2.6d Gate A. */
.alert-badge--prominent {
  font-size: 12px;
  font-weight: 600;
}

/* ── Loading / error / empty ── */
@keyframes pulse {
  0%, 100% { opacity: 0.4; }
  50%       { opacity: 0.8; }
}

.skeleton {
  background: var(--color-surface-cont);
  border-radius: var(--radius-md);
  animation: pulse 1.5s ease-in-out infinite;
}

.skeleton--shimmer {
  background: linear-gradient(90deg,
    var(--skeleton-base, var(--color-surface-cont)) 25%,
    var(--skeleton-highlight, var(--color-surface-low)) 50%,
    var(--skeleton-base, var(--color-surface-cont)) 75%);
  background-size: 200% 100%;
  animation: skeletonShimmer 1.4s ease infinite;
}

@keyframes skeletonShimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

.skeleton--circle {
  border-radius: 50%;
}

/* Skeleton group — compositional loading state */
.skeleton-group {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.skeleton-group--row { flex-direction: row; }

.skeleton-group--gap-sm { gap: 8px; }
.skeleton-group--gap-md { gap: 16px; }
.skeleton-group--gap-lg { gap: 24px; }

.skeleton-group--pad-sm { padding: 8px; }
.skeleton-group--pad-md { padding: 16px; }
.skeleton-group--pad-lg { padding: 24px; }

/* ── Canonical shared components (Batch 1 — kitchen-sink only; Batch 2 migrates live surfaces) ── */

/* Segmented toggle */
.seg-toggle {
  display: inline-flex;
  align-items: center;
  background: var(--color-surface-low);
  border-radius: var(--radius-md);
  padding: 3px;
  gap: 2px;
}

.seg-toggle__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  border-radius: calc(var(--radius-md) - 2px);
  border: none;
  background: transparent;
  color: var(--color-on-surface-var);
  cursor: pointer;
  transition: background var(--transition) var(--ease), color var(--transition) var(--ease);
  white-space: nowrap;
}

.seg-toggle__btn:hover:not(.seg-toggle__btn--active) {
  background: var(--color-hover-soft);
  color: var(--color-on-surface);
}

.seg-toggle__btn--active {
  background: var(--seg-active-bg, var(--color-primary));
  color: var(--color-on-primary);
}

.seg-toggle__btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Seg-toggle: block (fills container width, e.g. narrow sidebar) */
.seg-toggle--block {
  display: flex;
  width: 100%;
}
.seg-toggle--block .seg-toggle__btn {
  flex: 1;
  justify-content: center;
}

/* Seg-toggle: icon-only (tighter padding + icon fill treatment) */
.seg-toggle--icon .seg-toggle__btn {
  padding: 4px 8px;
}
.seg-toggle--icon .seg-toggle__btn .ti {
  font-size: 18px;
}
.seg-toggle--icon .seg-toggle__btn--active .ti {
}

/* Search field */
.search-field {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: var(--color-surface-low);
  border: 0.5px solid var(--color-outline-var);
  border-radius: var(--radius-md);
  transition: border-color 0.15s;
}

.search-field:focus-within {
  border-color: var(--color-primary);
}

.search-field__input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  font-family: inherit;
  font-size: 13px;
  color: var(--color-on-surface);
}

.search-field__input::placeholder { color: var(--color-on-surface-var); }
.search-field__icon { color: var(--color-on-surface-var); font-size: 16px; }

.search-field--block {
  display: flex;
  width: 100%;
}

/* Form field — canonical free-text input (promoted 2026-08-30).
   Scope is the class ON the element (input.form-field / textarea.form-field /
   select.form-field) — the admin-portal wrapper idiom (div.form-field > input)
   is a separate pattern and is deliberately untouched by these rules.
   Recipe matches .search-field so all text entry reads as one family.
   Width/flex sizing stays with the consuming layout, not this component. */
input.form-field,
textarea.form-field,
select.form-field {
  font-family: inherit;
  font-size: var(--font-size-md);
  color: var(--color-on-surface);
  background: var(--color-surface-low);
  border: 0.5px solid var(--color-outline-var);
  border-radius: var(--radius-md);
  padding: 7px 10px;
  box-sizing: border-box;
  outline: none;
  transition: border-color var(--transition), background var(--transition);
}

input.form-field::placeholder,
textarea.form-field::placeholder { color: var(--color-on-surface-var); }

input.form-field:hover,
textarea.form-field:hover,
select.form-field:hover { border-color: var(--color-outline); }

input.form-field:focus,
textarea.form-field:focus,
select.form-field:focus {
  border-color: var(--color-secondary);
  background: var(--color-surface);
}

input.form-field:focus-visible,
textarea.form-field:focus-visible,
select.form-field:focus-visible { box-shadow: var(--focus-ring); }

input.form-field:disabled,
textarea.form-field:disabled,
select.form-field:disabled { opacity: 0.55; cursor: not-allowed; }

textarea.form-field {
  resize: vertical;
  min-height: 60px;
  line-height: 1.5;
}

/* Tab bar */
.tab-bar {
  display: flex;
  gap: 4px;
}

.tab {
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 500;
  color: var(--color-on-surface-var);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  font-family: inherit;
  transition: color 0.15s, border-color 0.15s;
}

.tab:hover { color: var(--color-on-surface); }

.tab--active {
  color: var(--color-on-surface);
  border-bottom-color: var(--color-primary);
}

.tab:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 500;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 0.1s, opacity 0.1s;
  white-space: nowrap;
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--primary {
  background: var(--color-primary);
  color: var(--color-on-primary);
  border-color: var(--color-primary);
}

.btn--primary:hover:not(:disabled) {
  background: var(--color-primary-hover);
}

.btn--secondary {
  background: var(--color-surface);
  color: var(--color-on-surface);
  border-color: var(--color-border);
}

.btn--secondary:hover:not(:disabled) {
  background: var(--color-surface-low);
}

/* Filled blue — a second filled action beside the navy primary (GP Sales
   tab: "Update clinic sales"). --color-secondary, never a brand token. */
.btn--accent {
  background: var(--color-secondary);
  color: var(--color-on-primary);
  border-color: var(--color-secondary);
}

.btn--accent:hover:not(:disabled) {
  background: var(--color-secondary-cont);
}

.btn--secondary.btn--active {
  background: var(--color-surface-cont);
  border-color: var(--color-outline);
}

.btn--danger {
  background: var(--color-error);
  color: var(--color-on-primary);
  border-color: var(--color-error);
}

.btn--danger:hover:not(:disabled) {
  background: var(--color-error-hover);
  border-color: var(--color-error-hover);
}

/* ── Modal canonical family (UI.modal / UI.dangerConfirm) ──
   Moved verbatim from admin.css Phase 3.1 (2026-08-19): it was the de-facto
   shared modal — admin owned it, Tuesday consumed it via its admin.css
   import, and the two reference rules below already lived in this file.
   Now available to every shell that loads style.css (all five). */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: var(--color-modal-scrim);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
}

.modal {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  width: 100%;
  max-width: 560px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 0.5px solid var(--color-outline-var);
}

.modal__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 0.5px solid var(--color-outline-var);
  font-weight: 600;
  font-size: 15px;
}

.modal__close {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 18px;
  color: var(--color-on-surface-var);
  padding: 4px 8px;
  border-radius: var(--radius-sm);
}

.modal__close:hover {
  background: var(--color-surface-low);
}

.modal__body {
  padding: 20px;
  overflow-y: auto;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.modal__footer {
  padding: 14px 20px;
  border-top: 0.5px solid var(--color-outline-var);
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: flex-end;
}
/* Optional subtitle under the header title (Phase 3.1 — planned __sub slot).
   Rendered by UI.modal's escaped `sub` prop. */
.modal__sub {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: var(--color-on-surface-var);
  margin-top: 2px;
}

/* ── selectPicker canonical family (UI.selectPicker) ──
   Moved from tuesday.css Phase 3.3 (2026-08-19), renamed tue-select-* →
   ui-select-* — values verbatim. Also consumed by Tuesday's local
   multi-select picker (same dropdown look, checkbox rows). */
.ui-select-picker {
  position: relative;
}
.ui-select-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: var(--radius-md);
  border: 0.5px solid var(--color-border);
  background: var(--color-surface);
  cursor: pointer;
  user-select: none;
  width: 100%;
  box-sizing: border-box;
}
.ui-select-trigger:hover {
  background: var(--color-bg-hover);
}
.ui-select-trigger__label {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ui-select-trigger--empty .ui-select-trigger__label {
  color: var(--color-text-secondary);
  font-weight: 400;
}
.ui-select-trigger--disabled {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}
.ui-select-trigger__chevron {
  font-size: 16px;
  color: var(--color-text-secondary);
  flex-shrink: 0;
}
.ui-select-dropdown {
  position: fixed;
  min-width: 200px;
  max-height: 320px;
  overflow-y: auto;
  background: var(--color-surface);
  border: 0.5px solid var(--color-border);
  border-radius: var(--radius-md);
  z-index: 1000;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}
.ui-select-search {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: none;
  border-bottom: 0.5px solid var(--color-border-tertiary);
  background: transparent;
  font-family: var(--font-body);
  font-size: 13px;
  color: var(--color-text-primary);
  outline: none;
}
.ui-select-search::placeholder {
  color: var(--color-text-secondary);
}
.ui-select-option-list {
  padding: 4px 0;
}
.ui-select-group-label {
  padding: 8px 14px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-on-surface-var);
  background: var(--color-surface-low);
  border-top: 0.5px solid var(--color-border-tertiary);
  position: sticky;
  top: 0;
  z-index: 1;
}
.ui-select-group-label:first-child,
.ui-select-option--clear + .ui-select-group-label {
  border-top: none;
}
.ui-select-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px 7px 18px;
  font-size: 13px;
  color: var(--color-text-primary);
  cursor: pointer;
}
.ui-select-option:hover,
.ui-select-option--active {
  background: var(--color-bg-hover);
}
.ui-select-option:focus-visible {
  outline: none;
  background: var(--color-bg-hover);
  box-shadow: var(--focus-ring);
}
.ui-select-option--clear {
  color: var(--color-text-secondary);
  border-bottom: 0.5px solid var(--color-border-tertiary);
  margin-bottom: 2px;
}
.ui-select-option__check {
  margin-left: auto;
  font-size: 14px;
  color: var(--color-secondary);
  flex-shrink: 0;
}
.ui-select-empty {
  padding: 12px 10px;
  font-size: 13px;
  color: var(--color-text-secondary);
  text-align: center;
}

.modal__footer .btn--danger,
.modal__footer .btn--danger-outline {
  margin-right: auto;
}

.btn--sm {
  padding: 4px 10px;
  font-size: 12px;
}

.btn--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  font-size: 18px;
  border: none;
  background: none;
  color: var(--color-on-surface-var);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: inherit;
  transition: background 0.1s;
}

.btn--icon:hover:not(:disabled) {
  background: var(--color-surface-low);
  color: var(--color-on-surface);
}

/* Icon-button spin state — for async actions like refresh */
.btn--icon.is-spinning > .ti,
.btn--icon.is-spinning > .ti {
  animation: spin var(--spin-duration, .7s) linear infinite;
}

.row-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.btn--icon--danger:hover:not(:disabled) {
  /* light danger tint; tokens defined in style.css, loaded before admin.css */
  background: var(--color-error-bg-soft);
  color: var(--color-error-text);
}

.btn--danger-outline {
  background: transparent;
  color: var(--color-error-text);
  border-color: var(--color-error);
}

.btn--danger-outline:hover:not(:disabled) {
  background: var(--color-error-bg-faint);
}

.btn--ghost {
  background: none;
  border-color: transparent;
  color: var(--color-on-surface-var);
}

.btn--ghost:hover:not(:disabled) {
  color: var(--color-on-surface);
  background: var(--color-surface-low);
}

.btn--outline {
  background: transparent;
  border: 1px solid var(--color-outline-var);
  color: var(--color-on-surface-var);
}

/* Compact toolbar button — icon + label profile. Combine with a colour modifier
   (e.g. .btn--secondary) and .btn--active for pressed state. */
.btn--toolbar {
  border-width: 0.5px;
  font-size: var(--font-size-md);
  padding: var(--space-xs) var(--space-md);
  gap: var(--space-xs);
  white-space: nowrap;
}

.btn--toolbar strong {
  font-weight: 600;
}

/* Button loading state (additive — only active when .is-loading present) */
@keyframes spin { to { transform: rotate(360deg); } }

.btn.is-loading {
  color: transparent;
  pointer-events: none;
  position: relative;
}

.btn.is-loading::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 14px;
  height: 14px;
  border: 2px solid color-mix(in srgb, var(--color-on-surface-var) 50%, transparent);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin var(--spin-duration, .7s) linear infinite;
}

.btn--primary.is-loading::after,
.btn--danger.is-loading::after,
.btn--danger-outline.is-loading::after {
  border-color: rgba(255,255,255,0.5);
  border-top-color: transparent;
}

/* Keyboard-only focus ring (additive — :focus-visible not shown on mouse click) */
.btn:focus-visible,
.modal__close:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ── Toggle switch ── */
.toggle {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}

.toggle__input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.toggle__slider {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 24px;
  background: var(--color-outline-var);
  border-radius: var(--radius-pill);
  transition: background var(--transition), transform var(--transition);
}

.toggle__slider::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--color-on-primary);
  transition: transform var(--transition);
}

.toggle__input:checked + .toggle__slider {
  background: var(--color-primary);
}

.toggle__input:checked + .toggle__slider::after {
  transform: translateX(20px);
}

.toggle__input:disabled + .toggle__slider {
  opacity: 0.5;
  cursor: not-allowed;
}

.toggle--spaced {
  margin-bottom: 20px;
  gap: 8px;
}

.toggle__input:focus-visible + .toggle__slider {
  outline: none;
  box-shadow: var(--focus-ring);
}

.skeleton-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-bottom: 24px;
}
.pending-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 20px;
  color: var(--color-outline);
  font-size: 13px;
}

.inline-error {
  font-size: 13px;
  color: var(--color-error-text);
  background: var(--color-error-bg-faint);
  border: 1px solid rgba(186,26,26,0.2);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.empty-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--color-on-surface-var);
}

.empty-state__title {
  font-size: 16px;
  font-weight: 700;
  color: var(--color-primary-text);
  margin-bottom: 8px;
}

.empty-state__body { font-size: 13px; line-height: 1.6; }
.empty-state--error .empty-state__title { color: var(--color-error-text); }
.empty-state__actions {
  margin-top: 12px;
  display: flex;
  gap: 8px;
  justify-content: center;
}

/* Italic only. A color half (--color-outline-var) was authored but never
   rendered — every consumer is a .data-table td, where the base cell rule
   outranked it. Removed at the table-cascade flattening (2026-08-20) to keep
   the flatten render-neutral; reviving the muted color is a design decision,
   not a restoration. */
.cell-empty {
  font-style: italic;
}

/* ── Data table canonical ── */
.data-table {
  width: 100%;
  border-collapse: collapse;
}

/* Base cell rules are :where()-wrapped to (0,0,1) so any bare single-class
   utility (0,1,0) on a cell wins outright — no table-context compound needed
   (retires the Rule 28 default; table-cascade flattening, 2026-08-20).
   Contract invariants:
   - The 768px padding pair below MUST keep the identical :where() forms and
     stay later in this file (ties at (0,0,1), wins by order).
   - tr:hover / tr:last-child DELIBERATELY keep elevated specificity: hover
     must outrank portal row-background rules (e.g. .mkt-table zebra at
     (0,1,2), bg-carrying sub-row rules at (0,1,1)) exactly as it does today.
     A row-state background that must survive hover therefore still needs a
     hover-tier selector (see tuesday.css .tue-table-row--selected). */
:where(.data-table thead) th {
  padding: 10px 14px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-outline);
  background: var(--color-surface-low);
  border-bottom: 0.5px solid var(--color-border);
  text-align: left;
  white-space: nowrap;
}

:where(.data-table tbody) td {
  padding: 10px 14px;
  font-size: 13px;
  color: var(--color-on-surface);
  border-bottom: 0.5px solid var(--color-border-tertiary);
  vertical-align: middle;
}

.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr:hover td { background: var(--color-bg-hover); }

.data-table thead th[data-sort-type] {
  cursor: pointer;
  user-select: none;
  transition: color 0.15s;
}
.data-table thead th[data-sort-type]:hover { color: var(--color-on-surface); }
.data-table thead th[data-sort-dir="asc"]::after  { content: ' \2191'; }
.data-table thead th[data-sort-dir="desc"]::after { content: ' \2193'; }

/* Sort indicator uses inline text content so it flows after header text and
   respects th text-align natively. No positional fix needed for .num-cell
   right-aligned numeric headers — introduced 2026-07-09 (Phase 2.6z). */

/* Split primitive (2026-08-20, from the 2.6h §5 recommendation — the rule
   was defined twice: card shell here, scroll at the responsive block):
   - .data-table-scroll = horizontal scroll ONLY, for tables already inside a
     card (e.g. UI.sectionCard bodies) that must not gain a second card shell.
   - .data-table-wrap  = card shell + scroll, for standalone tables.
   overflow-y stays hidden on the wrap so the radius keeps clipping; the
   computed pair (x:auto, y:hidden) is byte-identical to the pre-split
   two-rule cascade. */
.data-table-wrap {
  background: var(--color-surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-cloud);
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
}

/* ── Unmapped manager error ── */
.unmapped-error {
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg);
}

.unmapped-error__box {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-cloud), inset 0 0 0 1px var(--color-divider);
  padding: 40px 48px;
  max-width: 400px;
  text-align: center;
}

.unmapped-error__title {
  font-size: 18px;
  font-weight: 700;
  color: var(--color-primary-text);
  margin-bottom: 12px;
}

.unmapped-error__body {
  font-size: 14px;
  color: var(--color-on-surface-var);
  line-height: 1.7;
}

/* ── Tab-bar shell ──
   Stacks canonical .page-header + .tab-bar-row as one show/hide region
   on portals whose tab bar carries companion controls (Clinic month-nav
   + Day/Month toggle, Inventory month label). Replaces the .clinic-tabs
   compound scaffold. No track border: tab underline is none-for-all
   (Canonical Decisions 2026-08-18, HF-6 made permanent). */
.tab-bar-shell {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  flex-shrink: 0;
}

.tab-bar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 28px;
  background: var(--color-surface);
}

.tab-bar-row__slot {
  display: flex;
  align-items: center;
}

/* ── KPI card subtitle (for "No data yet") ── */
.kpi-card__subtitle {
  font-size: 11px;
  color: var(--kpi-subtitle-color, var(--color-on-surface-var));
  margin-top: 4px;
}

/* ── Section card meta label (e.g. "Last 6 months") ── */
.section-card__meta {
  font-size: 12px;
  color: var(--color-on-surface-var);
  font-weight: 500;
}

/* ── Progress bar canonical (UI.progressBar factory) ── */
.progress-bar-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 4px;
  font-size: 13px;
  color: var(--color-on-surface-var);
}
.progress-bar-label { font-weight: 500; }
.progress-bar-meta-text { color: var(--color-outline); }

.progress-bar-track {
  width: 100%;
  height: 6px;
  background: var(--color-surface-cont);
  border-radius: 3px;
  overflow: hidden;
}

.progress-bar-fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.4s ease;
}
.progress-bar-fill--ok   { background: var(--color-success); }
.progress-bar-fill--warn { background: var(--color-warn-alt); }
.progress-bar-fill--bad  { background: var(--color-bad-alt); }

/* Inline compact bar (60px × 4px, e.g. project group progress) */
.progress-bar-track--inline {
  width: 60px;
  height: 4px;
  border-radius: 2px;
}
.progress-bar-track--inline .progress-bar-fill {
  border-radius: 2px;
  transition: none;
}

/* Clinic-only blocks (tables, tiers, patients tab, panel tab, target
   bars, layout rows) extracted to clinic.css — Phase 2.6g-b, 2026-08-17.
   The .clinic-tabs compound scaffold migrated to canonical
   .tab-bar-shell / .page-header / .tab-bar-row — Phase 2.7a, 2026-08-18. */

/* ── Sortable table headers ── */
.sortable-th {
  cursor: pointer;
  user-select: none;
  transition: color 0.15s;
}
.sortable-th:hover { color: var(--color-on-surface) !important; }

/* ── KPI subtitle ── */
.kpi-card__subtitle {
  font-size: 11px;
  color: var(--color-on-surface-var);
  margin-top: 4px;
}

/* ── Responsive ─────────────────────────────────────────────── */

/* ── Date navigator (Phase 6) ── */
.date-nav {
  display: inline-flex;
  align-items: center;
  background: var(--color-bg);
  border: 1px solid var(--color-outline-var, #e5e7eb);
  border-radius: 8px;
  overflow: hidden;
}
.date-nav button {
  background: none;
  border: none;
  cursor: pointer;
  padding: 7px 10px;
  font-size: 15px;
  color: var(--color-on-surface-var, #6b7280);
  transition: all 0.12s;
  font-family: var(--font-body);
  line-height: 1;
}
.date-nav button:hover { background: var(--color-hover-soft); color: var(--color-on-surface); }
.date-nav button:disabled { opacity: 0.25; cursor: default; pointer-events: none; }
.date-nav button.outer { color: var(--color-primary-text, #1a365d); font-weight: 700; }
.date-nav .dn-date {
  padding: 6px 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-on-surface);
  cursor: pointer;
  min-width: 140px;
  text-align: center;
  user-select: none;
}
.date-nav .dn-sep {
  width: 1px;
  height: 18px;
  background: var(--color-outline-var, #e5e7eb);
  flex-shrink: 0;
}

/* ── Day/Month toggle ── */
.tf-wrap {
  display: flex;
  background: var(--color-surface-low);
  border-radius: 6px;
  padding: 2px;
}
.tf-btn {
  padding: 6px 18px;
  font-size: 12px;
  font-weight: 500;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 5px;
  color: var(--color-on-surface-var, #6b7280);
  transition: all 0.12s;
  font-family: var(--font-body);
}
.tf-btn.active {
  background: var(--color-surface, #fff);
  color: var(--color-on-surface);
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
  font-weight: 600;
}

/* ≤1280px — stack right rail below center content */
@media (max-width: 1280px) {
  .content-row {
    flex-direction: column;
    overflow-y: auto;
  }
  .content-center,
  .content-right {
    overflow-y: visible;
    flex: 0 0 auto;
  }
  .content-right {
    width: 100%;
    min-width: 0;
    flex-direction: row;
    flex-wrap: wrap;
    padding: 0 32px 28px;
    gap: 20px;
  }
  .content-right .rail-panel {
    flex: 1 1 240px;
    min-width: 0;
  }
}

/* ≤900px — 2-column KPI grid, tighter padding */
@media (max-width: 900px) {
  .kpi-grid,
  .skeleton-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .content-center {
    padding: 20px;
    gap: 16px;
  }
  .content-right {
    padding: 0 20px 20px;
  }
  .page-header__title {
    font-size: 26px;
  }
}

/* ≤600px — small-phone adjustments.
   The old icon-strip sidebar rules (--sidebar-w: 72px + label hides)
   and the 1-column .kpi-grid rule were removed 2026-08-17 (clinic
   mobile pass): the ≤768px drawer block below fully superseded them
   (fixed-position 280px overlay + 2-up KPI grid), so they were dead
   declarations that only contradicted the live mobile design. */
@media (max-width: 600px) {
  .content-right {
    flex-direction: column;
  }
  .content-right .rail-panel {
    flex: 1 1 auto;
  }
}

.last-updated {
  font-size: 0.75rem;
  color: var(--color-text-secondary);
  text-align: right;
  margin-top: 4px;
  display: block;
}

/* ─────────────────────────────────────────────────────────────
   Sidebar toggle (hamburger) — always visible (Phase 2.8).
   Desktop click = collapse/expand the sidebar (body.sidebar-collapsed,
   wired in topbar.js). Mobile click = slide-in overlay (portal
   initMobileMenu). Styling lives here at base so both modes share it.
   ───────────────────────────────────────────────────────────── */
#mob-hamburger {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  font-size: 20px;
  line-height: 1;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-on-surface-var, #43474e);
  border-radius: 8px;
  flex-shrink: 0;
  transition: background 0.12s;
  margin-right: 4px;
}
#mob-hamburger:hover {
  background: var(--color-surface-low, #f2f4f6);
}

/* Desktop full-collapse — mobile (≤768px) keeps the overlay pattern,
   so the collapse class only bites above it */
@media (min-width: 769px) {
  body.sidebar-collapsed .sidebar { display: none; }
}

.mob-sidebar-close { display: none; }
.sidebar-backdrop { display: none; }

/* ─────────────────────────────────────────────────────────────
   Mobile layout (≤768px)
   All rules live inside this block so desktop is untouched.
   This block is placed LAST in the file so it cascades after
   the existing ≤600px icon-strip query and overrides conflicts.
   ───────────────────────────────────────────────────────────── */
@media (max-width: 768px) {

  /* ── Sidebar: fixed-position overlay, slides in from left ── */
  .sidebar {
    position: fixed !important;
    top: 0;
    left: 0;
    height: 100%;
    width: 280px;
    z-index: 1000;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    overflow-y: auto;
    /* Keep display:flex (inherited from base rule) so content renders */
  }
  .sidebar.sidebar--mobile-open {
    transform: translateX(0);
  }

  /* Semi-transparent backdrop (created by initMobileMenu in app.js) */
  .sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.3);
    z-index: 999;
  }
  .sidebar-backdrop.sidebar-backdrop--visible {
    display: block;
  }

  /* ── Close (✕) button inside sidebar overlay ── */
  .mob-sidebar-close {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 10px;
    right: 10px;
    width: 32px;
    height: 32px;
    border: none;
    background: none;
    cursor: pointer;
    font-size: 16px;
    color: var(--color-on-surface-var, #43474e);
    border-radius: 6px;
    flex-shrink: 0;
    z-index: 1;
  }
  .mob-sidebar-close:hover {
    background: var(--color-surface-cont, #eceef0);
  }
  /* Sidebar brand needs relative positioning for the close btn */
  .sidebar__brand {
    position: relative;
    padding-right: 48px; /* room for ✕ button */
  }

  /* Hamburger styling now lives at base (Phase 2.8 — always visible) */

  /* ── Sidebar text restoration (overrides ≤600px icon-strip rules) ── */
  /* The ≤600px query hides sidebar labels; on mobile the sidebar is a
     full-width overlay so all labels must remain visible. This block
     is placed AFTER the ≤600px query in the file, so it wins. */
  .sidebar__brand > div:not(.sidebar__brand-icon),
  .sidebar__search-wrap {
    display: block;
  }
  /* ── Content area: full width (sidebar is out of flow via position:fixed) ── */
  .content-center {
    padding: 16px;
    gap: 16px;
  }
  .content-right {
    flex-direction: column;
    padding: 0 16px 16px;
    gap: 12px;
  }
  .content-right .rail-panel {
    flex: 1 1 auto;
  }

  /* ── Page header: stack title above navigator ── */
  .content-header-top {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .header-right {
    width: 100%;
    align-items: stretch; /* children fill full width */
  }
  /* Day/Month toggle: content-width and right-aligned (matching the
     clinic tab-row placement) instead of stretching into a full-width
     grey bar under the date navigator (portfolio header). */
  .header-right .tf-wrap {
    align-self: flex-end;
  }
  .page-header__title {
    font-size: 24px;
  }

  /* ── Date navigator: full width, tap-friendly buttons ── */
  .date-nav {
    width: 100%;
    justify-content: space-between;
  }
  .date-nav .dn-date {
    min-width: 0;
    flex: 1;
  }
  .date-nav button {
    min-height: 44px;
    padding: 0 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* ── Last-updated text: smaller font, right-aligned ── */
  .last-updated {
    font-size: 11px;
    width: 100%;
    text-align: right;
  }

  /* ── Day/Month toggle: 36px tap target ── */
  .tf-btn {
    min-height: 36px;
    padding: 6px 14px;
  }

  /* ── KPI cards: 2×2 grid (reinforce over the ≤900px rule), smaller ── */
  .kpi-grid,
  .skeleton-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
  }
  .kpi-card {
    padding: 12px;
    min-height: 100px;
  }
  .kpi-card__header {
    margin-bottom: 8px;
  }
  .kpi-card__value {
    font-size: 1.5rem;
  }
  .kpi-card__label {
    font-size: 12px;
  }

  /* ── Trend chart range buttons: compact; hide All & Cumulative ── */
  .range-toggle__btn {
    font-size: 10px;
    padding: 3px 8px;
  }
  .range-toggle__btn[data-zoom="All"],
  .range-toggle__btn[data-zoom="Cumulative"] {
    display: none;
  }
  /* 6M becomes the last VISIBLE button once All/Cumulative are hidden —
     drop its divider so it doesn't double up against the group border */
  .range-toggle__btn[data-zoom="6M"] {
    border-right: none;
  }

  /* ── Topbar: reduce padding on mobile (641–768px range)
     Note: topbar.js already does this at ≤640px via its inline <style>.
     For 641–768px we use a more-specific selector to win the cascade
     against the inline style tag (which loads after the stylesheet). ── */
  #topbar-mount .app-topbar {
    padding: 0 12px;
  }

  /* ── General: prevent horizontal overflow ── */
  .app,
  .main,
  .content-row,
  .content-center {
    max-width: 100vw;
    overflow-x: hidden;
  }
}

/* ── .dn-date clickability hint ── */
.date-nav .dn-date:hover {
  text-decoration: underline;
  text-decoration-color: var(--color-outline-var, #c4c6cf);
  text-underline-offset: 3px;
}

/* ── Calendar popup ── */
@keyframes calPopIn {
  from { opacity: 0; transform: translateX(-50%) translateY(-4px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.cal-pop {
  position: absolute;
  background: var(--color-surface);
  border: 1px solid var(--color-border-cal);
  border-radius: 12px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.12);
  z-index: 1000;
  font-family: var(--font-body, "Manrope", system-ui, sans-serif);
  font-size: 13px;
  animation: calPopIn 150ms ease forwards;
  user-select: none;
}
.cal-pop__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px 8px;
  font-weight: 700;
  font-size: 13px;
  color: var(--color-on-surface, #191c1e);
}
.cal-pop__nav {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 15px;
  padding: 4px 8px;
  border-radius: 6px;
  color: var(--color-primary-text, #1A365D);
  font-weight: 700;
  line-height: 1;
  font-family: inherit;
}
.cal-pop__nav:hover:not(:disabled) { background: var(--color-hover-soft); }
.cal-pop__nav:disabled { opacity: 0.25; cursor: default; pointer-events: none; }
.cal-pop__body { padding: 0 10px 10px; }

/* Day grid */
.cal-pop__wdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  margin-bottom: 4px;
}
.cal-pop__wday {
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  color: var(--color-on-surface-var, #43474e);
  padding: 2px 0;
}
.cal-pop__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

/* Month grid */
.cal-pop__mgrid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
}

/* Shared cell base */
.cal-pop__cell {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  width: 32px;
  height: 32px;
  font-size: 12px;
  cursor: pointer;
  background: none;
  border: none;
  font-family: inherit;
  color: var(--color-on-surface, #191c1e);
  margin: auto;
  transition: background 0.1s;
}
.cal-pop__cell:hover:not([disabled]):not(.cal-pop__cell--selected) { background: var(--color-hover-soft); }
.cal-pop__cell--today   { box-shadow: inset 0 0 0 2px var(--color-primary); }
.cal-pop__cell--selected { background: var(--color-primary) !important; color: var(--color-on-primary) !important; box-shadow: none; }
.cal-pop__cell--other,
.cal-pop__cell--future,
.cal-pop__cell[disabled] { color: var(--color-gray-300); cursor: default; pointer-events: none; }

/* Month-mode cell overrides (wider, rounded rect) */
.cal-pop__mcell {
  border-radius: 8px;
  width: auto;
  height: 34px;
  padding: 0 4px;
}

/* ─────────────────────────────────────────────────────────────
   Clinic Dashboard Mobile (≤768px)
   This block is separate from the portfolio mobile block above
   and handles clinic-specific components only. It cascades
   correctly because it appears later in the file.
   ───────────────────────────────────────────────────────────── */
@media (max-width: 768px) {

  /* ── Shell page header: reduce padding ── */
  .tab-bar-shell .page-header {
    padding: 12px 16px 8px;
  }

  /* ── Clinic navigator slot: full width ── */
  #portal-tabs-month-nav {
    width: 100%;
  }
  /* Title size reduction inside the tab-bar shell */
  .tab-bar-shell .page-header__title {
    font-size: 20px;
  }

  /* ── Tab row: reduce padding, clip for fade ── */
  .tab-bar-row {
    padding: 0 12px;
    position: relative;
    overflow: hidden;
  }

  /* Subtle right-edge fade to hint more tabs exist.
     Fades to the tab bar's own background token so it stays correct
     in dark mode (was a hardcoded white rgba — white smear on dark). */
  .tab-bar-row::after {
    content: '';
    position: absolute;
    right: 0;
    top: 0;
    bottom: 0;
    width: 32px;
    background: linear-gradient(to right, transparent, var(--color-surface));
    pointer-events: none;
    z-index: 2;
  }

  /* ── Tabs container: horizontal scroll ── */
  .tab-bar-row .tab-bar {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex: 1;
    min-width: 0;
  }
  .tab-bar-row .tab-bar::-webkit-scrollbar {
    display: none;
  }

  /* ── Individual tab: 44px tap target, no wrap ── */
  .tab-bar-row .tab-bar .tab {
    white-space: nowrap;
    flex-shrink: 0;
    min-height: 44px;
    display: flex;
    align-items: center;
    padding: 0 14px;
  }

  /* ── Chart containers: min and max heights on mobile ── */
  /* Prevents charts from being too short or too tall in stacked layouts */
  .chart-wrap {
    min-height: 150px;
  }

}

/* ─────────────────────────────────────────────────────────────
   Mobile bug fixes (≤768px) — cascades after clinic mobile block
   ───────────────────────────────────────────────────────────── */
@media (max-width: 768px) {

  /* Fix 2: Tab toggle collision — move toggle to its own row below tabs */
  .tab-bar-row {
    flex-wrap: wrap;
  }
  /* Force tabs to full width so toggle wraps below (overrides flex: 1) */
  .tab-bar-row .tab-bar {
    flex: 0 0 100%;
  }
  /* Toggle: own row, right-aligned */
  .tab-bar-row__slot {
    width: 100%;
    display: flex;
    justify-content: flex-end;
    padding: 4px 2px 2px;
  }
  /* Fix fade gradient: limit height to tab row only, not into toggle row */
  .tab-bar-row::after {
    bottom: auto;
    height: 44px;
  }
}

/* ── Toast stack (UI.showToast) ── */
#ui-toast-root {
  position: fixed;
  bottom: 24px;
  right: 24px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 2000;
  pointer-events: none;
  max-width: 320px;
}

.toast {
  padding: 10px 14px 10px 12px;
  border-radius: var(--radius-md);
  font-size: 13px;
  font-weight: 500;
  color: var(--color-on-surface);
  background: var(--color-surface);
  box-shadow: var(--shadow-cloud);
  border: 0.5px solid var(--color-outline-var);
  display: flex;
  align-items: flex-start;
  gap: 10px;
  pointer-events: auto;
  opacity: 0;
  transform: translateX(8px);
  transition: opacity 0.2s, transform 0.2s;
}

.toast--enter {
  opacity: 1;
  transform: translateX(0);
}

.toast--exit {
  opacity: 0;
  transform: translateX(8px);
}

.toast--success { background: var(--color-surface); }
.toast--error   { background: var(--color-surface); }
.toast--info    { background: var(--color-surface); }

.toast__message { flex: 1; line-height: 1.5; }

.toast__action {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: inherit;
  font-size: var(--font-size-md);
  font-weight: 600;
  padding: var(--space-xs) var(--space-sm);
  line-height: 1.5;
  text-decoration: none;
}

.toast__action:hover,
.toast__action:focus-visible { text-decoration: underline; }

.toast__action:focus-visible { box-shadow: var(--focus-ring); outline: none; }

.toast__close {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-on-surface-var);
  font-size: 18px;
  line-height: 1;
  padding: 0 0 0 4px;
  margin-top: -1px;
}

.toast__close:hover { color: var(--color-on-surface); }

/* ──────────────────────────────────────────────────────────────────
 * Phase 1.5 — Mobile primitives
 * Canonical mobile rules for shared CSS classes. Every Phase 1
 * factory and Phase 2 callsite inherits these automatically.
 * Portal-specific mobile work lives in portal CSS files.
 * ────────────────────────────────────────────────────────────────── */

/* Data tables — scroll-only wrapper (see the split note at .data-table-wrap).
   For tables inside an existing card; carries no chrome of its own. */
.data-table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

@media (max-width: 768px) {
  .data-table-wrap > .data-table,
  .data-table-scroll > .data-table {
    min-width: 640px; /* Force horizontal scroll before columns collapse */
  }
  /* Touch-friendly cell padding. Must keep the same :where() forms as the
     desktop cell rules above — ties at (0,0,1) and wins by file order
     (flattened from the (0,1,2) tie-and-win forms, table-cascade 2026-08-20;
     originally shadowed since 2.6z, revived Phase 2.7b). */
  :where(.data-table thead) th,
  :where(.data-table tbody) td {
    padding: 12px;
  }
}

/* Tab bar — horizontal scroll with right-fade indicator on mobile */
@media (max-width: 768px) {
  .tab-bar {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none; /* Firefox */
    /* Right-fade indicator: mask the trailing 24px so users see there's more */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
            mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
  }
  .tab-bar::-webkit-scrollbar { display: none; } /* Chrome/Safari */
  .tab-bar > .tab {
    flex-shrink: 0; /* Tabs keep their width, container scrolls */
    /* 44px tap targets (Marketer mobile pass 2026-08-18) — the
       .tab-bar-row-scoped clinic rule already does this for the
       shell portals; this covers bare .tab-bar (Marketer, Tuesday) */
    white-space: nowrap;
    min-height: 44px;
    display: flex;
    align-items: center;
  }
}

/* Section card — tighter body padding on small phones to reclaim horizontal space */
@media (max-width: 600px) {
  .section-card__body {
    padding: 12px 14px 16px;
  }
}

/* Banner — stack action below message on small phones */
@media (max-width: 600px) {
  .banner {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
  .banner > .banner__action,
  .banner > .btn {
    align-self: stretch; /* Full-width action button */
  }
}

/* Icon button — expand to 40×40 on mobile (closer to 44px floor) */
@media (max-width: 768px) {
  .btn--icon {
    width: 40px;
    height: 40px;
  }
}

/* Toggle — taller slider on mobile for easier thumb tap (width unchanged) */
@media (max-width: 768px) {
  .toggle__slider {
    height: 28px;
  }
  /* Keep the inner circle proportional — knob = slider height − 6px (same convention as base rule) */
  .toggle__slider::after {
    height: 22px;
    width: 22px;
  }
  /* Math: 3px left + 16px translate + 22px knob + 3px right = 44px — exact fit inside 44px slider */
  .toggle__input:checked + .toggle__slider::after {
    transform: translateX(16px);
  }
}

/* ── Wave 3b components (Phase 2.0) ─────────────────────────────────────── */

/* hBar — horizontal proportional bar */
.h-bar {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}
.h-bar__label {
  min-width: 120px;
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var);
}
.h-bar__track {
  position: relative;
  flex: 1;
  height: 20px; /* TODO(design-tokens): component-size sub-scale — deferred */
  background: var(--color-surface-low);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.h-bar__track--stacked {
  display: flex;
  flex-direction: row;
}
.h-bar__fill {
  height: 100%;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: var(--space-sm);
  color: white;
  font-size: var(--font-size-sm);
  font-weight: 500;
  white-space: nowrap;
  transition: width 200ms ease;
}
.h-bar__fill--base { border-radius: var(--radius-md) 0 0 var(--radius-md); }
.h-bar__fill--new  { border-radius: 0 var(--radius-md) var(--radius-md) 0; }
/* Arbitrary-N segments (Phase 3.7): internal edges square — the track's
   overflow:hidden + radius clips the outer corners; per-segment text centers.
   flex-shrink 0 so over-100 totals CLIP at the track edge as documented
   instead of the flex track shrinking segments to fit (Codex R1 finding 4). */
.h-bar__fill--seg {
  border-radius: 0;
  padding-right: 0;
  justify-content: center;
  flex-shrink: 0;
}
.h-bar__value-outside {
  font-size: var(--font-size-md);
  font-weight: 500;
  color: var(--color-on-surface-var);
  padding-left: var(--space-sm);
}

/* inlineError — inline card-body error banner */
.inline-error {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) var(--space-lg);
  background: var(--color-error-bg-soft);
  border: 0.5px solid var(--color-error);
  border-radius: var(--radius-md);
  color: var(--color-error);
  font-size: var(--font-size-md);
}
.inline-error__message { flex: 1; }

/* tableRowSkeleton — 2D skeleton (N rows × M cells) */
.table-row-skeleton {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.table-row-skeleton--gap-sm { gap: 8px; }
.table-row-skeleton--gap-md { gap: 16px; }
.table-row-skeleton--gap-lg { gap: 24px; }
.table-row-skeleton--pad-sm { padding: 8px; }
.table-row-skeleton--pad-md { padding: 16px; }
.table-row-skeleton--pad-lg { padding: 24px; }
.table-row-skeleton__row {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}
.table-row-skeleton__cell {
  display: flex;
  align-items: center;
}
.table-row-skeleton__cell--flex { flex: 1; }

/* chipBar — horizontal filter chip row */
.chip-bar {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  flex-wrap: wrap;
}
.chip-bar__label {
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var);
  margin-right: 4px;
}
.chip-bar__chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: var(--space-xs) var(--space-md);
  border: 0.5px solid var(--color-outline);
  border-radius: 999px;
  background: transparent;
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var);
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
}
.chip-bar__chip:hover { background: var(--color-surface-low); }
.chip-bar__chip--active {
  background: var(--color-primary);
  color: white;
  border-color: var(--color-primary);
}
.chip-bar__count {
  font-size: var(--font-size-xs);
  font-weight: 500;
  padding: 1px 6px;
  background: rgba(255, 255, 255, 0.25);
  border-radius: 999px;
}
.chip-bar__chip:not(.chip-bar__chip--active) .chip-bar__count {
  background: var(--color-divider);
}

/* statRow — label + value pair for card-body stats */
.stat-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-md);
}
.stat-row--column {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xs);
}
.stat-row__label {
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var);
}
.stat-row__value {
  font-size: var(--font-size-lg);
  font-weight: 600;
  font-family: var(--font-body);
  color: var(--color-on-surface);
}

/* chartLegend — colored dot + label per chart series.
   Phase 3.5-amended (2026-08-19): merged from two duplicate .chart-legend
   blocks this file had carried since B1 (the later one silently won
   font-size 13px over 12px; the earlier one's margin-bottom and 500 weight
   survived). This block emits exactly the pre-merge COMPUTED result, so the
   merge is render-neutral on every consumer. */
.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-bottom: 12px;
}
.chart-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-size-md);
  font-weight: 500;
  color: var(--color-on-surface-var);
}
.chart-legend__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.chart-legend__sublabel {
  color: var(--color-outline);
  margin-left: 4px;
}
.chart-legend--compact .chart-legend__item { font-size: 10px; }
.chart-legend--compact .chart-legend__dot { width: 8px; height: 8px; }
/* Square-dot variant (Phase 3.5-amended) — legends whose series render as
   squares/bars rather than lines (stacked-bar legends). */
.chart-legend--square .chart-legend__dot { border-radius: 2px; }
/* Below-content placement (Phase 3.5-amended). The base margin-bottom assumes
   legend-above-chart; a legend rendered under its bar/chart wants the inverse.
   Applied via extraClass. Consumers: inventory expiry alerts, clinic sales
   mix x2 — reproduces each site's pre-migration spacing exactly. */
.chart-legend--below { margin-top: 10px; margin-bottom: 0; }

/* rangeToggle — zoom/range button group */
.range-toggle {
  display: inline-flex;
  border: 0.5px solid var(--color-outline);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.range-toggle__btn {
  padding: var(--space-xs) var(--space-md);
  background: transparent;
  border: none;
  border-right: 0.5px solid var(--color-outline);
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var);
  cursor: pointer;
  transition: background 150ms ease;
}
.range-toggle__btn:last-child { border-right: none; }
.range-toggle__btn:hover { background: var(--color-surface-low); }
.range-toggle__btn--active {
  background: var(--color-primary);
  color: white;
}

/*
 * channel-badge — branded marketing channel pill
 * Light-themed, 0.5px-border design contract. Promoted from .mkt-channel-badge in Wave 7 (2026-07-03).
 * Variants: fb, ig, tt, google, threads, youtube. (The goog alias rules were
 * deleted 2026-08-17, Phase 2.6g-a — the factory maps 'GOOG' input to the
 * literal --google class at emit, so the alias classes never render.)
 * Each variant has a dark-mode counterpart immediately below.
 */
.channel-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: var(--font-size-xs, 11px);
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  background: var(--color-surface-low);
  color: var(--color-on-surface);
  border: 0.5px solid var(--color-border);
}
.channel-badge--neutral { background: var(--color-surface-low); color: var(--color-on-surface); border-color: var(--color-border); }
.channel-badge--fb      { background: #eff6ff; color: #1877f2; border-color: #bfdbfe; }
.channel-badge--ig      { background: #fdf2f8; color: #c026d3; border-color: #f5d0fe; }
.channel-badge--tt      { background: #f5f5f5; color: #010101; border-color: #d4d4d4; }
.channel-badge--google  { background: #eff6ff; color: #4285f4; border-color: #bfdbfe; }
.channel-badge--threads { background: #f5f5f5; color: #010101; border-color: #d4d4d4; }
.channel-badge--youtube { background: #fef2f2; color: #ff0000; border-color: #fecaca; }
[data-theme="dark"] .channel-badge--fb      { background: rgba(77,153,245,0.14);  color: #4d99f5; border-color: rgba(77,153,245,0.28); }
[data-theme="dark"] .channel-badge--ig      { background: rgba(217,70,239,0.14);  color: #e879f9; border-color: rgba(217,70,239,0.28); }
[data-theme="dark"] .channel-badge--tt      { background: rgba(255,255,255,0.08); color: #f5f5f5; border-color: rgba(255,255,255,0.16); }
[data-theme="dark"] .channel-badge--google  { background: rgba(66,133,244,0.14);  color: #6b9dfa; border-color: rgba(66,133,244,0.28); }
[data-theme="dark"] .channel-badge--threads { background: rgba(255,255,255,0.08); color: #f5f5f5; border-color: rgba(255,255,255,0.16); }
[data-theme="dark"] .channel-badge--youtube { background: rgba(255,0,0,0.14);     color: #ff5252; border-color: rgba(255,0,0,0.28); }

/* alertItem — inline severity-styled list-item alert */
.alert-item {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--radius-md);
  font-size: var(--font-size-md);
  border-left: 3px solid transparent;
}
.alert-item--ok {
  background: var(--color-success-bg-soft);
  border-left-color: var(--color-success);
  color: var(--color-on-surface);
}
.alert-item--warn {
  background: var(--color-warning-bg-soft);
  border-left-color: var(--color-warning);
  color: var(--color-on-surface);
}
.alert-item--danger {
  background: var(--color-error-bg-soft);
  border-left-color: var(--color-error);
  color: var(--color-on-surface);
}
.alert-item__prefix {
  font-weight: 600;
  margin-right: 4px;
}

/* barList — ranked horizontal bar list */
.bar-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
}
.bar-list__row {
  display: grid;
  grid-template-columns: 120px 1fr auto;
  align-items: center;
  gap: var(--space-md);
}
.bar-list__label {
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bar-list__track {
  height: 16px; /* TODO(design-tokens): component-size sub-scale — deferred */
  background: var(--color-surface-low);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.bar-list__fill {
  height: 100%;
  background: var(--color-primary);
  border-radius: var(--radius-md);
  transition: width 200ms ease;
}
.bar-list__value {
  font-size: var(--font-size-md);
  font-weight: 500;
  font-family: var(--font-body);
  color: var(--color-on-surface);
  white-space: nowrap;
}

/* Numeric cell utility — proportional Manrope with tabular-num digits for
   column alignment. Use on <td>, <span>, or any element rendering a numeric
   value that needs to align with sibling values across rows.
   Introduced 2026-07-09 (Phase 2.6a) to preserve column alignment after
   --font-mono deletion. */
.num-cell {
  text-align: right;
  font-variant-numeric: tabular-nums;
}


/* ──────────────────────────────────────────────────────────────────
 * Auth pre-app states (Phase 2.6f, 2026-08-17)
 * Consumed by shared auth.js (clinic/marketer/inventory/tuesday).
 * These render before the app shell exists (iframe sign-in overlay,
 * 403 unmapped-account page), so they keep var() fallbacks and must
 * not depend on portal-local CSS or UI factories.
 * ────────────────────────────────────────────────────────────────── */
.auth-overlay {
  position: fixed;
  inset: 0;
  z-index: 2147483647;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-lg);
  background: var(--color-bg, #f5f5f5);
  font-family: var(--font-body, system-ui, sans-serif);
  color: var(--color-on-surface, #1a1a1a);
}
/* 22px: no font-size token between --font-size-xl (20px) and
   --font-size-2xl (24px) — literal kept to preserve shipped size. */
.auth-overlay__brand {
  font-size: 22px;
  font-weight: 500;
  letter-spacing: 1px;
}
.auth-overlay__subtitle {
  font-size: var(--font-size-md);
  color: var(--color-on-surface-var, #666);
}
.auth-overlay__signin-btn {
  margin-top: var(--space-lg);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #2563eb; /* Microsoft sign-in brand blue — deliberate literal, not a theme token */
  color: #fff;
  border: none;
  border-radius: 6px;
  padding: 12px 32px;
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
}
.auth-overlay__signin-btn:disabled { opacity: 0.7; cursor: default; }
.auth-overlay__error {
  color: var(--color-error-text, #b91c1c);
  font-size: var(--font-size-md);
  max-width: 320px;
  text-align: center;
}

/* Full-viewport centred message (auth.js 403 page; inv-app.js carries
   the same hand-rolled pattern and can adopt in its own batch). */
.page-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  gap: var(--space-sm);
  font-family: var(--font-body, sans-serif);
}
.page-center__title { font-size: 14px; font-weight: 500; }
.page-center__sub {
  font-size: var(--font-size-sm);
  color: var(--color-on-surface-var, #888);
}

/* ─────────────────────────────────────────────────────────────
   Horizontal-scroll affordance (≤768px)

   Wide tables scroll sideways inside their card, but phones draw
   OVERLAY scrollbars — invisible until you already know to swipe — so
   a table cropped flush at the card border reads as "cut off". This
   paints a right-edge fade for as long as content is still hidden;
   js/scroll-hint.js owns the .has-xscroll toggle, and drops it the
   moment you reach the end, so the cue is never a lie.

   Same idiom as .tab-bar-row::after / .mkt-subbar::after above — the
   difference is that the fade here is measured, not permanent.
   ───────────────────────────────────────────────────────────── */
/* The shell takes the scroller's place as a flex item in .content-center,
   so it also has to take over its flex-shrink: 0 — otherwise a tall table
   gets squashed vertically by the column's own overflow. Unscoped by
   media query because the wrapper persists across a resize. */
.scroll-shell {
  position: relative;
  flex-shrink: 0;
  min-width: 0;
}

@media (max-width: 768px) {
  .section-card.has-xscroll,
  .scroll-shell.has-xscroll { position: relative; }

  /* Header and footer ride above the fade so the gradient veils the
     table alone, not the card's own chrome. Both are opaque already —
     the background is restated because lifting them out of the natural
     paint order removes the card's backdrop from behind them. */
  .section-card.has-xscroll > .section-card__header,
  .section-card.has-xscroll > .section-card__footer {
    position: relative;
    z-index: 3;
    background: var(--color-surface);
  }

  .section-card.has-xscroll::after,
  .scroll-shell.has-xscroll::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 36px;
    z-index: 2;
    pointer-events: none;
  }

  /* rgba(0,0,0,0), not `transparent`: Safari interpolates the keyword
     through black and smears a grey band across the gradient. */
  .section-card.has-xscroll::after {
    background: linear-gradient(to left, var(--color-surface), rgba(0, 0, 0, 0));
  }
  /* A shelled scroller sits on the page ground, not on a card surface.
     --color-bg is correct in both themes: dark mode assigns it to
     .content-center outright, and light mode's rgba(247,249,251,0.5)
     composites back onto the same #f7f9fb. */
  .scroll-shell.has-xscroll::after {
    background: linear-gradient(to left, var(--color-bg), rgba(0, 0, 0, 0));
  }
}
