/* ========================================
   CloudOverture Design System v7
   ======================================== */

:root {
  /* ========================================
     Brand (Green)
     ======================================== */
/* >>> BEGIN GENERATED TOKENS (scripts/sync-tokens.py) — do not edit by hand */
--brand-50:  #F0FBF5;
--brand-100: #D8F3E8;
--brand-200: #A8E4C8;
--brand-300: #6FD0A4;
--brand-400: #41B983;   /* Primary — CTAs, active states, focus rings */
--brand-500: #2E9B6E;   /* Hover state */
--brand-600: #1E7A54;   /* Active/pressed */
--brand-700: #155A3E;   /* Dark-mode primary */
--neutral-950: #18181A;  /* Primary text */
--neutral-800: #38383C;  /* Body text, input values */
--neutral-700: #505055;  /* Secondary labels */
--neutral-600: #6B6B70;  /* Body copy, descriptions, metadata */
--neutral-500: #8A8A90;  /* Icons, decorative fills, disabled/inactive labels — NOT body/label text (3.43:1 fails AA; use neutral-600) */
--neutral-400: #A3A3A8;  /* NON-TEXT ONLY — borders, icon strokes, placeholders */
--neutral-300: #C8C8CC;  /* Subtle dividers */
--neutral-200: #E4E4E7;  /* Default border */
--neutral-100: #F0F0F2;  /* Table row hover, disabled backgrounds */
--neutral-50:  #F9F9FA;  /* Page background */
--white:       #FFFFFF;  /* Card/sidebar surface */
--success-500: #0C7A6E;  --success-100: #DFF5F2;
--warning-500: #A85D00;  --warning-100: #FEF0D6;
--danger-500:  #C42032;  --danger-100:  #FDEAED;
--info-500:    #1D5FCC;  --info-100:    #D6E8FF;
--warning-400: #E8A33D;  --info-400:    #5C8DEF;
--bark-500:    #6F4E37;  --bark-100:    #F0E8DF;   /* brown — shipping default badge; 7.4:1 on white */
--cyan-surface: #ECF8FB;  --cyan-border: #7FCADB;  --cyan-title: #0A6B85;  /* cyan H193° cash-flow report tile — between success-teal (P&L) and info-blue (Balance sheet), #374 */
--success-surface: #EEFAF8;  --success-border: #68C7BB;
--success-icon:    #0D9B87;  --success-title:  #0A7B6C;
--warning-surface: #FFFBEF;  --warning-border: #FBD07C;
--warning-icon:    #D97706;  --warning-title:  #92400E;  /* 6.8:1 on --warning-surface; #C46800 read 3.8:1 and failed AA (#1032) */
--danger-surface:  #FFF2F4;  --danger-border:  #F4A3AE;
--danger-icon:     #E0334A;  --danger-title:   #C42032;
--info-surface:    #EEF4FF;  --info-border:    #90B5F5;
--info-icon:       #2868D6;  --info-title:     #1A52B8;
--alert-body: #38383C;  /* Always neutral for alert body text */
--av-forest:  #1E7A54;  /* brand green H153°   5.29:1 */
--av-teal:    #0C7A6E;  /* success teal H174°  5.22:1 */
--av-amber:   #A85D00;  /* warning amber H33°  4.96:1 */
--av-rust:    #A04020;  /* orange-red H18°     6.46:1 */
--av-crimson: #C42032;  /* danger red H352°    5.83:1 */
--av-berry:   #A02D5E;  /* magenta-rose H330°  6.93:1 */
--av-cobalt:  #1D5FCC;  /* info blue H221°     5.90:1 */
--av-violet:  #4840B8;  /* blue-violet H245°   7.77:1 */
--av-plum:    #6B3FA0;  /* purple H270°        7.38:1 */
--av-slate:   #505055;  /* neutral — overflow "+N" only */
/* <<< END GENERATED TOKENS */

  --neutral-900: #27272A;
  --shimmer-sheen: rgba(255, 255, 255, 0.6);

  /* App-only email provider brand marks (TeamInboxSettings). Not part of the
     canonical export, so they stay outside the generated block; GH-700 moved
     them here after the first regeneration clobbered them in-marker. */
  --provider-google: #EA4335; --provider-outlook: #0078D4;

  /* Surface — opaque raised-panel fill (dropdowns, popover sticky heads, map
     cards). Aliases --white so the dark-mode remap of --white carries through;
     previously var(--surface) referenced an undefined token and rendered
     transparent (e.g. the Location typeahead list, the meeting-time week head). */
  --surface: var(--white);
  --surface-primary: var(--white);

  /* Brand ink: brand-green text on a surface (CoButton link and brand-ghost). Light keeps
     --brand-600 (5.29:1 on white). Both dark blocks remap it to --brand-400 (6.64:1 on the dark
     card surface), the design system's link colour (GH-1377). --brand-600 now takes the same
     dark value (GH-1381, --brand-fill below), so the two agree in both themes; --brand-ink stays
     the named text role. */
  --brand-ink: var(--brand-600);

  /* GH-1521: the Home card links (AgingCard / ProfitLossCard / PipelineCard .card-link,
     AttentionRail .rail-foot-link) and the form-designer "+ Add Related Field" text button.
     --brand-ink is the design system's link colour, but its dark value (#41B983) would darken
     the Home links from the #6FD0A4 they shipped with (QA reopened GH-1521 to keep it), so the
     card-link role carries its own token. Light reads --brand-600 (#1E7A54, 5.29:1 on white;
     the --brand-500 they had read 3.48:1) and hovers --brand-700 (#155A3E, 8.19:1, still the
     distinct darker step). Both dark blocks keep the shipped pairing: base --brand-500
     (#6FD0A4, 8.79:1) and hover --brand-600 (#41B983, 6.64:1). */
  --brand-link: var(--brand-600);
  --brand-link-hover: var(--brand-700);

  /* Keyboard focus indicator: the global :focus-visible ring, CoButton's ring, the form-control
     focus border and the components' own focus rules (a few keep a colour that already passes,
     --brand-500 or --brand-600). Design system sec. 19 names --brand-400, which reads
     2.47:1 on white and 2.35:1 on the page background, below the 3:1 WCAG 1.4.11 asks of a focus
     indicator; --brand-600 reads 4.51-5.29:1 on every light surface. Both dark blocks keep
     --brand-400 (6.4-7.6:1 on the dark surfaces), so dark draws exactly what it drew before
     (GH-1407). */
  --focus-ring: var(--brand-600);

  /* Fills behind a literal white label (Tailwind text-white), the same in every theme. Both dark
     blocks lighten --brand-600, --brand-700 and --danger-600 for text on the dark surface
     (GH-1381), and white on those dark values reads 2.47:1, 1.44:1 and 2.77:1. A fill labelled
     var(--white) keeps the token: --white is the dark surface colour in dark, which reads better
     on the lighter value. --brand-fill-hover is the primary button's hover fill. The brand fills
     repeat the generated --brand-600 / --brand-700 values because an alias would follow the dark
     remap; a spec keeps them equal. */
  --brand-fill: #1E7A54;
  --brand-fill-hover: #155A3E;
  --danger-fill: #A81828;

  /* Scrim: the semi-transparent overlay behind modals/dialogs. Fixed (not
     remapped per mode) — a scrim dims whatever sits behind it, which a
     neutral-950-tinted value does in both themes. Canonicalized here from
     CoModal's .modal-overlay so crypto dialogs share the exact value. */
  --scrim: rgba(24, 24, 26, 0.45);

  /* AI veil: the LIGHT backdrop behind the slide-in AI assistant panel (mockup
     approval-card--pending.html L11, impl §6). Deliberately ~4.5x lighter than
     --scrim — the panel is a quiet overlay, not a blocking dialog. Fixed like
     --scrim: a neutral-tinted veil reads the same in both themes. */
  --ai-veil: rgba(24, 24, 26, 0.10);
  /* -600 stops are app-only additions (the canonical block carries -500/-100 only).
     Entry 186: the verbatim re-declarations of the canonical -100 tokens that used
     to sit here are gone — they shadowed the generated block, so a canonical regen
     would have been silently overridden by stale copies. */
  --success-600: #0A6B60;
  --danger-600:  var(--danger-fill);
  /* -400 stops are app-only additions too (the canonical block carries
     -500/-100, plus -400 for warning/info only). Values mirror the light-theme
     -icon stops, the mid fill-grade step of each hue: monotonic between -100
     and -500, and readable on dark surfaces like the other fixed -400s.
     Consumed by the Home P&L bars/legend dots and the Who-owes-you aging bar. */
  --success-400: #0D9B87;
  --danger-400:  #E0334A;

  /* ========================================
     Categorical Colors (non-semantic)
     e.g. address default badges: shipping = bark
     ======================================== */
  /* bark anchors (-100/-500) mirror canonical colors_and_type.css (#6F4E37 /
     #F0E8DF, decision #057) and are generated inside the markers; the intermediate
     stops are an app-only gradation — CoBadge's --bark-200 border + the tailwind
     bark scale consume them — so they are kept (not dropped) and remain monotonic
     between the canonical anchors. */
  --bark-50:  #F7F3EE;
  --bark-200: #D8C2A8;
  --bark-300: #C0A07C;
  --bark-400: #A47E55;
  --bark-600: #6A4A2F;
  --bark-700: #4E3622;

  /* ========================================
     Payment brand marks (third-party brands
     use their own color, per decision #116)
     ======================================== */
  --pay-stripe:         #635BFF;
  --pay-stripe-surface: #EFEEFF;
  --pay-zelle:          #6D1ED4;
  --pay-zelle-surface:  #F1E8FB;
  --pay-venmo:          #3D95CE;
  --pay-venmo-surface:  #E4F1F9;

  /* Activity channel tones — icon backgrounds in the activity timeline.
     Only email and meeting lack a brand/neutral mapping of their own. */
  --activity-tone-email:   #8b5cf6;
  --activity-tone-meeting: #06b6d4;

  /* Badge border tints (token-driven so dark mode can remap them) */
  --badge-success-border: #8ED8D0;
  --badge-warning-border: #F5C882;
  --badge-danger-border:  #F5A8B4;
  --badge-info-border:    #93BBFF;

  /* ========================================
     Typography
     ======================================== */
  --font-display: 'Instrument Serif', Georgia, serif;
  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono:    'SFMono-Regular', Consolas, monospace;

  /* Type Scale */
  --text-xs:   13px;
  --text-sm:   15px;
  --text-base: 17px;
  --text-lg:   20px;
  --text-xl:   24px;
  --text-2xl:  30px;
  --text-3xl:  38px;
  --text-4xl:  48px;
  --text-5xl:  60px;
  --text-6xl:  76px;

  /* Line Heights */
  --line-height-tight: 1.25;
  --line-height-normal: 1.6;
  --line-height-relaxed: 1.75;

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

  /* ========================================
     Radius
     ======================================== */
  --r-sm:   4px;
  --r-md:   8px;
  --r-lg:   12px;
  --r-xl:   16px;
  --r-2xl:  24px;
  --r-full: 9999px;

  /* ========================================
     Border
     ======================================== */
  --border-default: 1px solid var(--neutral-200);
  --border-strong:  1px solid var(--neutral-300);
  --border-brand:   1px solid var(--brand-400);

  /* ========================================
     Elevation (Shadows)
     ======================================== */
  --shadow-xs: 0 1px 2px rgba(24,24,26,0.05);
  --shadow-sm: 0 1px 4px rgba(24,24,26,0.06), 0 1px 2px rgba(24,24,26,0.04);
  --shadow-md: 0 4px 12px rgba(24,24,26,0.08), 0 2px 4px rgba(24,24,26,0.04);
  --shadow-lg: 0 8px 24px rgba(24,24,26,0.10), 0 3px 8px rgba(24,24,26,0.05);
  --shadow-xl: 0 16px 48px rgba(24,24,26,0.12), 0 6px 16px rgba(24,24,26,0.06);
  --shadow-focus: 0 0 0 3px var(--brand-50);
  /* Edge fade: the soft veil QuoteLinesGrid paints beside its pinned name/total
     columns when the body scrolls (a box-shadow colour, not a full shadow). Remapped
     heavier in both dark blocks like the shadows above — the light 12% near-black
     veil would vanish on a dark card. */
  --edge-fade: rgba(24,24,26,0.12);

  /* ========================================
     Transitions
     ======================================== */
  --transition-fast: 100ms ease;
  --transition-normal: 150ms ease;
  --transition-slow: 300ms ease;

  /* ========================================
     Z-Index
     ======================================== */
  --z-dropdown: 10;
  --z-sticky: 20;
  --z-fixed: 30;
  --z-modal-backdrop: 9000;
  --z-modal: 10000;
  --z-popover: 10010;
  --z-tooltip: 10020;
  --z-notification: 10100;

  /* ========================================
     Layout
     ======================================== */
  --sidebar-width: 220px;
  --sidebar-collapsed-width: 64px;
  --topbar-height: 56px;
  --content-max-width: 1400px;
  --content-padding: 24px;
  /* Label column for a field whose label sits beside its control. One width, so fields stacked
     under each other start their controls at the same left edge. A short label fits on one line
     at --text-xs; a longer one wraps inside the column instead of pushing its control right. */
  --inline-label-width: 120px;
}

/* ========================================
   Base Styles
   ======================================== */

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis: none;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--line-height-normal);
  color: var(--neutral-950);
  background-color: var(--neutral-50);
}

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}

/* Global keyboard focus ring (design system sec. 19), in --focus-ring (see :root). It paints
   every element that does not draw its own indicator: raw <a>, <button> and friends,
   CoCheckbox, CoRadio and CoSwitch. CoButton (focus-visible:ring) and the form controls
   (control.ts focus border) draw their own in the same token and set outline:none.
   Legacy .inputs opt out below (.input:focus-visible) to keep their border and glow
   without a double indicator. */
:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* ========================================
   Scrollbar (Thin + Hover Darken)
   ======================================== */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: rgba(24,24,26,0.12);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: rgba(24,24,26,0.25);
}

::-webkit-scrollbar-corner {
  background: transparent;
}

/* Firefox */
* {
  scrollbar-width: thin;
  scrollbar-color: rgba(24,24,26,0.12) transparent;
}

/* ========================================
   Typography Classes
   ======================================== */

.text-xs { font-size: var(--text-xs); }
.text-sm { font-size: var(--text-sm); }
.text-base { font-size: var(--text-base); }
.text-lg { font-size: var(--text-lg); }
.text-xl { font-size: var(--text-xl); }
.text-2xl { font-size: var(--text-2xl); }
.text-3xl { font-size: var(--text-3xl); }
.text-4xl { font-size: var(--text-4xl); }

.font-normal { font-weight: 400; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-bold { font-weight: 700; }

/* ========================================
   Semantic Type Styles
   Ported (collision-aware subset) from the canonical design system
   (docs/ehsan/design-system/colors_and_type.css §Semantic Type Styles) so page
   titles and display headings render in Instrument Serif (var(--font-display))
   instead of every view hand-rolling an Inter heading. Only classes NOT already
   used as generic hooks in the app are ported here: .body (75 sites),
   .label (101), .section-title (25), .mono (20) are intentionally OMITTED until
   their per-view uses are audited. .page-title is the headline font fix — it
   has 17 scoped redefinitions across views that Phase 1 removes so this rule
   wins. Never bold the display font (font-synthesis guard above, decision #143)
   — emphasize with size + color.
   ======================================== */

/* Display headings — Instrument Serif */
.h1 { font-family: var(--font-display); font-size: var(--text-5xl); letter-spacing: -0.025em; line-height: 1.0; color: var(--neutral-950); }
.h2 { font-family: var(--font-display); font-size: var(--text-4xl); letter-spacing: -0.025em; line-height: 1.05; color: var(--neutral-950); }
.h3 { font-family: var(--font-display); font-size: var(--text-3xl); letter-spacing: -0.020em; line-height: 1.1; color: var(--neutral-950); }
.h4 { font-family: var(--font-display); font-size: var(--text-2xl); letter-spacing: -0.015em; line-height: 1.2; color: var(--neutral-950); }
.h5 { font-family: var(--font-display); font-size: var(--text-xl); letter-spacing: -0.015em; line-height: 1.25; color: var(--neutral-950); }

/* Page title — Instrument Serif (the mockup's .page-title, app.css:170) */
.page-title { font-family: var(--font-display); font-size: 22px; letter-spacing: -0.01em; color: var(--neutral-950); }

/* Body text variants — Inter (the canonical .body is deferred: 75 collision sites) */
.body-lg { font-family: var(--font-body); font-size: var(--text-lg); font-weight: 400; line-height: 1.6; color: var(--neutral-800); }
.body-sm { font-family: var(--font-body); font-size: var(--text-sm); font-weight: 400; line-height: 1.5; color: var(--neutral-600); }

/* Small label — Inter (the canonical .label is deferred: 101 collision sites) */
.label-sm { font-family: var(--font-body); font-size: var(--text-xs); font-weight: 500; color: var(--neutral-800); }

/* ========================================
   Button Styles
   ======================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-family: var(--font-body);
  font-weight: 500;
  cursor: pointer;
  border: none;
  transition: all 0.15s;
  white-space: nowrap;
  text-decoration: none;
  line-height: 1;
}

.btn:disabled, .btn[disabled] {
  background: var(--neutral-100);
  color: var(--neutral-300);
  cursor: not-allowed;
  box-shadow: none;
  pointer-events: none;
}

.btn-sm {
  font-size: 13px;
  padding: 7px 14px;
  border-radius: var(--r-md);
}

.btn-md {
  font-size: 13px;
  padding: 9px 18px;
  border-radius: var(--r-md);
}

.btn-lg {
  font-size: 15px;
  padding: 12px 24px;
  border-radius: var(--r-lg);
}

.btn-xl {
  font-size: 17px;
  padding: 16px 32px;
  border-radius: var(--r-lg);
}

.btn-primary {
  background: var(--brand-400);
  color: var(--white);
  box-shadow: 0 1px 3px rgba(65,185,131,0.25), 0 1px 2px rgba(65,185,131,0.15);
}

.btn-primary:hover:not(:disabled) {
  background: var(--brand-500);
  transform: translateY(-1px);
}

.btn-primary:active:not(:disabled) {
  transform: translateY(0);
  box-shadow: none;
}

.btn-secondary {
  background: var(--white);
  color: var(--neutral-800);
  border: var(--border-strong);
  box-shadow: var(--shadow-xs);
}

.btn-secondary:hover:not(:disabled) {
  background: var(--neutral-50);
  border-color: var(--neutral-400);
  transform: translateY(-1px);
}

.btn-ghost {
  background: transparent;
  color: var(--neutral-700);
  border: 1px solid transparent;
}

.btn-ghost:hover:not(:disabled) {
  background: var(--neutral-100);
  color: var(--neutral-950);
}

.btn-brand-ghost {
  background: var(--brand-50);
  color: var(--brand-600);
  border: 1px solid var(--brand-100);
}

.btn-brand-ghost:hover:not(:disabled) {
  background: var(--brand-100);
}

.btn-danger {
  background: var(--danger-500);
  color: var(--white);
  box-shadow: 0 1px 3px rgba(196,32,50,0.25);
}

.btn-danger:hover:not(:disabled) {
  background: var(--danger-600);
  transform: translateY(-1px);
}

/* ========================================
   Icon Button
   ======================================== */

.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--neutral-200);
  background: var(--white);
  color: var(--neutral-600);
  cursor: pointer;
  transition: all 0.12s;
  box-shadow: var(--shadow-xs);
}

.btn-icon:hover {
  background: var(--neutral-50);
  border-color: var(--neutral-300);
  color: var(--neutral-950);
}

.btn-icon-sm { width: 30px; height: 30px; border-radius: var(--r-md); }
.btn-icon-md { width: 36px; height: 36px; border-radius: var(--r-md); }
.btn-icon-lg { width: 44px; height: 44px; border-radius: var(--r-lg); }

/* ========================================
   Input Styles
   ======================================== */

.input {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--neutral-950);
  background: var(--white);
  border: 1px solid var(--neutral-200);
  border-radius: var(--r-md);
  padding: 9px 12px;
  width: 100%;
  outline: none;
  transition: border-color 0.12s, box-shadow 0.12s;
  box-shadow: var(--shadow-xs);
}

.input::placeholder {
  color: var(--neutral-300);
}

.input:hover {
  border-color: var(--neutral-300);
}

.input:focus {
  border-color: var(--focus-ring);
  box-shadow: 0 0 0 3px var(--brand-50);
}

.input:disabled {
  background: var(--neutral-50);
  color: var(--neutral-300);
  cursor: not-allowed;
}

.input-label { font-size: var(--text-sm); font-weight: 500; color: var(--neutral-800); }
.input-hint  { font-size: var(--text-xs); color: var(--neutral-600); }
.input-error { font-size: var(--text-xs); color: var(--danger-500); }

.input.error { border-color: var(--danger-500); }
.input.error:focus { box-shadow: 0 0 0 3px var(--danger-100); }

/* Legacy .input keeps its own box-shadow focus ring (.input:focus above);
   suppress the global :focus-visible outline so keyboard focus does not
   double-indicate. (Co* controls via control.ts already do focus:outline-none.) */
.input:focus-visible {
  outline: none;
}

/* Native date/time controls do not automatically follow the app's token-based
   theme. Declare their light baseline here so the browser paints both the
   picker indicator and its popup with the matching system palette. */
.ui-datepicker-input {
  color-scheme: light;
}

.ui-datepicker-input::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.8;
}

.ui-datepicker-input::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}

/* ========================================
   Card Styles
   ======================================== */

.card {
  background: var(--white);
  border: 1px solid var(--neutral-200);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.card:hover {
  box-shadow: var(--shadow-md);
}

.card-header {
  padding: 20px 24px 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.card-title { font-size: var(--text-base); font-weight: 600; color: var(--neutral-950); }
.card-subtitle { font-size: var(--text-sm); color: var(--neutral-600); margin-top: 2px; }

.card-body { padding: 20px 24px 24px; }

.card-footer {
  padding: 14px 24px;
  border-top: 1px solid var(--neutral-200);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  background: var(--neutral-50);
}

.card-hover {
  transition: all 0.15s;
}

.card-hover:hover {
  border-color: var(--brand-400);
  box-shadow: var(--shadow-md);
}

/* ========================================
   Stat Card
   ======================================== */

.stat-card {
  background: var(--white);
  border: 1px solid var(--neutral-200);
  border-radius: var(--r-xl);
  padding: 20px 22px;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow 0.15s, transform 0.15s;
}

.stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }

.stat-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 3px;
}

.stat-card.status-green::before { background: var(--success-500); }
.stat-card.status-red::before   { background: var(--danger-500); }
.stat-card.status-amber::before { background: var(--warning-500); }
.stat-card.status-brand::before { background: var(--brand-400); }

.stat-label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--neutral-600);
}

.stat-value {
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--neutral-950);
  margin-bottom: 8px;
  line-height: 1;
}

.stat-trend {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-size: 12px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: var(--r-full);
}

.stat-trend-up {
  color: var(--success-500);
  background: var(--success-100);
}

.stat-trend-down {
  color: var(--danger-500);
  background: var(--danger-100);
}

/* ========================================
   Badge Styles
   ======================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--text-xs);
  font-weight: 600;
  padding: 3px 8px;
  border-radius: var(--r-full);
  white-space: nowrap;
  border: 1px solid transparent;
}

/* Semantic badges use the banner surface tokens (decision #145) so a badge
   matches its same-color .alert-* on the same screen. */
.badge-success {
  background: var(--success-surface);
  color: var(--success-title);
  border-color: var(--success-border);
}

.badge-warning {
  background: var(--warning-surface);
  color: var(--warning-title);
  border-color: var(--warning-border);
}

.badge-error, .badge-danger {
  background: var(--danger-surface);
  color: var(--danger-title);
  border-color: var(--danger-border);
}

.badge-info {
  background: var(--info-surface);
  color: var(--info-title);
  border-color: var(--info-border);
}

.badge-neutral {
  background: var(--neutral-100);
  color: var(--neutral-700);
  border-color: var(--neutral-200);
}

.badge-brand {
  background: var(--brand-50);
  color: var(--brand-600);
  border-color: var(--brand-100);
}

.badge-square {
  border-radius: var(--r-sm);
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 600;
}

.badge-dot {
  width: 5px;
  height: 5px;
  border-radius: var(--r-full);
  background: currentColor;
  display: inline-block;
}

/* ========================================
   Alert Styles
   ======================================== */

.alert {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  border: 1px solid;
  border-left-width: 3px;
}

.alert-icon { flex-shrink: 0; margin-top: 1px; }
.alert-title { font-size: var(--text-sm); font-weight: 600; margin-bottom: 2px; }
.alert-body  { font-size: var(--text-sm); line-height: 1.5; color: var(--alert-body); }

.alert-success { background: var(--success-surface); border-color: var(--success-border); border-left-color: var(--success-icon); }
.alert-success .alert-title { color: var(--success-title); }

.alert-warning { background: var(--warning-surface); border-color: var(--warning-border); border-left-color: var(--warning-icon); }
.alert-warning .alert-title { color: var(--warning-title); }

.alert-danger  { background: var(--danger-surface);  border-color: var(--danger-border);  border-left-color: var(--danger-icon); }
.alert-danger .alert-title { color: var(--danger-title); }

.alert-info    { background: var(--info-surface);    border-color: var(--info-border);    border-left-color: var(--info-icon); }
.alert-info .alert-title { color: var(--info-title); }

.alert-success .alert-icon svg { stroke: var(--success-icon); }
.alert-warning .alert-icon svg { stroke: var(--warning-icon); }
.alert-danger .alert-icon svg  { stroke: var(--danger-icon); }
.alert-info .alert-icon svg    { stroke: var(--info-icon); }

.alert-neutral {
  background: var(--neutral-50);
  border-color: var(--neutral-200);
  border-left-color: var(--neutral-400);
}
.alert-neutral .alert-icon svg { stroke: var(--neutral-600); }
.alert-neutral .alert-title { color: var(--neutral-800); }

/* ========================================
   Avatar
   ======================================== */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  flex-shrink: 0;
  border-radius: var(--r-full);
  font-family: var(--font-body);
  letter-spacing: 0.02em;
  color: var(--white);
}

.avatar-xs  { width: 24px; height: 24px; font-size: 9px; }
.avatar-sm  { width: 30px; height: 30px; font-size: 11px; }
.avatar-md  { width: 36px; height: 36px; font-size: 13px; }
.avatar-lg  { width: 44px; height: 44px; font-size: 16px; }
.avatar-xl  { width: 56px; height: 56px; font-size: 20px; }

.avatar-forest  { background: var(--av-forest); }
.avatar-teal    { background: var(--av-teal); }
.avatar-amber   { background: var(--av-amber); }
.avatar-rust    { background: var(--av-rust); }
.avatar-crimson { background: var(--av-crimson); }
.avatar-berry   { background: var(--av-berry); }
.avatar-cobalt  { background: var(--av-cobalt); }
.avatar-violet  { background: var(--av-violet); }
.avatar-plum    { background: var(--av-plum); }
.avatar-slate   { background: var(--av-slate); }

.avatar-stack {
  display: flex;
}

.avatar-stack .avatar {
  border: 2px solid var(--white);
  margin-left: -8px;
}

.avatar-stack .avatar:first-child {
  margin-left: 0;
}

/* ========================================
   Toggle
   ======================================== */

.toggle {
  width: 40px;
  height: 22px;
  border-radius: var(--r-full);
  background: var(--neutral-200);
  position: relative;
  transition: background 0.2s;
  flex-shrink: 0;
  cursor: pointer;
}

.toggle::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 16px; height: 16px;
  border-radius: var(--r-full);
  background: var(--white);
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
  transition: transform 0.2s;
}

.toggle.on { background: var(--brand-400); }
.toggle.on::after { transform: translateX(18px); }

/* ========================================
   Checkbox
   ======================================== */

.check-box {
  width: 18px; height: 18px; flex-shrink: 0;
  border: var(--border-strong);
  border-radius: var(--r-sm);
  background: var(--white);
  display: flex; align-items: center; justify-content: center;
  transition: all 0.12s;
  box-shadow: var(--shadow-xs);
}

.check-box.checked {
  background: var(--brand-400);
  border-color: var(--brand-400);
}

/* ========================================
   Utility Classes (supplementary — not duplicated by Tailwind)
   ======================================== */

.truncate {
  min-width: 0;               /* lets a flex/grid child shrink below content (canonical) */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

/* ========================================
   Data Table
   ======================================== */

.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--text-sm);
  background: var(--white);
  border: 1px solid var(--neutral-200);
  border-radius: var(--r-xl);
  overflow: hidden;
}

.data-table th {
  padding: 10px 14px;
  text-align: left;
  font-weight: 600;
  color: var(--neutral-600);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-bottom: 1px solid var(--neutral-200);
  background: var(--neutral-50);
  white-space: nowrap;
}

.data-table td {
  padding: 13px 14px;
  color: var(--neutral-800);
  border-bottom: 1px solid var(--neutral-100);
  vertical-align: middle;
}

.data-table tbody tr:last-child td {
  border-bottom: none;
}

/* Hover row highlight */
.data-table tbody tr:hover td {
  background: var(--neutral-50);
}

/* Row actions: hidden by default, shown on row hover */
.data-table .row-actions {
  display: flex;
  gap: 2px;
  justify-content: flex-end;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.data-table tbody tr:hover .row-actions {
  opacity: 1;
}

/* Kebab dropdown: always subtly visible */
.data-table .row-actions-dropdown {
  display: inline-flex;
}

/* Empty state */
.data-table .empty-cell {
  text-align: center;
  color: var(--neutral-600);
  padding: var(--sp-8) !important;
}

/* Cell type variants */
.td-primary { font-weight: 500; color: var(--neutral-950); }
.td-muted   { color: var(--neutral-600); }
.td-mono    { font-family: var(--font-mono); font-size: 12px; }

/* ========================================
   Action Button
   ======================================== */

.action-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: transparent;
  border-radius: var(--r-md);
  cursor: pointer;
  color: var(--neutral-600);
  transition: all 0.12s;
}

.action-btn:hover {
  background: var(--neutral-50);
  color: var(--neutral-950);
}

.action-btn-danger:hover {
  background: var(--danger-100);
  color: var(--danger-500);
}

/* ========================================
   Empty State
   ======================================== */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-12) var(--sp-6);
  text-align: center;
  color: var(--neutral-600);
}

.empty-state-icon {
  color: var(--neutral-300);
}

/* ========================================
   Navigation Pattern
   ======================================== */

.sidebar {
  width: var(--sidebar-width);
  background: var(--white);
  border-right: 1px solid var(--neutral-200);
  display: flex;
  flex-direction: column;
}

.sidebar-section-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--neutral-600);
  padding: 18px 18px 6px;
}

.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 18px;
  font-size: 13px;
  color: var(--neutral-800);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: all 0.12s;
}

.sidebar-nav a:hover {
  background: var(--neutral-50);
  color: var(--neutral-950);
}

.sidebar-nav a.active {
  color: var(--brand-600);
  background: var(--brand-50);
  border-left-color: var(--brand-400);
  font-weight: 500;
}

.sidebar-nav a svg {
  width: 15px;
  height: 15px;
  opacity: 0.7;
}

.sidebar-nav a.active svg {
  opacity: 1;
}

.topbar {
  height: var(--topbar-height);
  background: var(--white);
  border-bottom: 1px solid var(--neutral-200);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--content-padding);
  position: sticky;
  top: 0;
  z-index: 10;
}

.topbar-title {
  font-family: var(--font-display);
  font-size: 22px;
  letter-spacing: -0.01em;
  color: var(--neutral-950);
}

.sidebar-logo .logo-wordmark {
  font-family: var(--font-display);
  font-size: 21px;
  letter-spacing: -0.015em;
}

/* ========================================
   Dark Mode — System Preference
   ======================================== */

@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
/* >>> BEGIN GENERATED DARK TOKENS (scripts/sync-tokens.py) - do not edit by hand */
--neutral-950: #EEEEF0;
--neutral-800: #C8C8CC;
--neutral-700: #A3A3A8;
--neutral-600: #86868C;
--neutral-500: #6E6E74;  /* dark-mode pairing for --neutral-500 */
--neutral-400: #56565C;
--neutral-300: #3A3A3F;
--neutral-200: #2C2C30;
--neutral-100: #222225;
--neutral-50:  #18181A;
--white:       #1F1F23;
--brand-50:  #0D2318;
--brand-100: #143320;
--brand-400: #41B983;
--brand-500: #6FD0A4;
--success-surface: #0D2420;  --success-border: #1E6B60;
--success-icon:    #41C4B0;  --success-title:  #6FD4C4;
--warning-surface: #221A06;  --warning-border: #7A5000;
--warning-icon:    #F59E0B;  --warning-title:  #FBBF24;
--danger-surface:  #240A0E;  --danger-border:  #7A1020;
--danger-icon:     #F87171;  --danger-title:   #FCA5A5;
--info-surface:    #0A1530;  --info-border:    #1E3A8A;
--info-icon:       #60A5FA;  --info-title:     #93C5FD;
--cyan-surface:    #08222A;  --cyan-border:    #1E5A6E;  --cyan-title:  #78CFE0;  /* categorical report-tile cyan (#374) */
--alert-body:      #C8C8CC;
--success-500: #41C4B0;  --success-100: #0D2420;
--warning-500: #FBBF24;  --warning-100: #221A06;
--danger-500:  #FCA5A5;  --danger-100:  #240A0E;
--info-500:    #93C5FD;  --info-100:    #0A1530;
--bark-500:    #C9A27A;  --bark-100:    #241A10;
/* <<< END GENERATED DARK TOKENS */

    /* App-only dark additions, kept outside the generated block (hand-maintained):
       the -900 stop, the brand and danger text stops, the focus ring, shimmer, pay-* surfaces,
       activity tones, and badge border aliases. The shadow values below also live in the canonical export but use
       multi-part values scripts/sync-tokens.py does not parse, so they stay
       hand-maintained too. */
    --neutral-900: #D4D4D8;
    --brand-ink: var(--brand-400);  /* brand-green text; see :root */
    --brand-link: var(--brand-500);  /* GH-1521 card links keep the shipped dark pair; see :root */
    --brand-link-hover: var(--brand-600);
    --focus-ring: var(--brand-400);  /* keyboard focus indicator; see :root */
    --brand-600: var(--brand-400);  /* text on the dark surface; white-label fills use --brand-fill */
    --brand-700: var(--brand-200);  /* the next, lighter step: hovers and strong text; see :root */
    --danger-600: var(--danger-icon);  /* red text, stronger than -500; white-label fills use --danger-fill */
    --shimmer-sheen: rgba(255, 255, 255, 0.08);
    --pay-stripe-surface: #1E1B3A;
    --pay-zelle-surface:  #241038;
    --pay-venmo-surface:  #0E2738;
    --activity-tone-email:   #A78BFA;
    --activity-tone-meeting: #22D3EE;
    --badge-success-border: var(--success-border);
    --badge-warning-border: var(--warning-border);
    --badge-danger-border:  var(--danger-border);
    --badge-info-border:    var(--info-border);

    /* Shadows — heavier opacity on dark backgrounds */
    --shadow-xs:  0 1px 2px rgba(0,0,0,0.30);
    --shadow-sm:  0 1px 4px rgba(0,0,0,0.36), 0 1px 2px rgba(0,0,0,0.24);
    --shadow-md:  0 4px 12px rgba(0,0,0,0.40), 0 2px 4px rgba(0,0,0,0.24);
    --shadow-lg:  0 8px 24px rgba(0,0,0,0.48), 0 3px 8px rgba(0,0,0,0.28);
    --shadow-xl:  0 16px 48px rgba(0,0,0,0.56), 0 6px 16px rgba(0,0,0,0.32);
    --edge-fade:  rgba(0,0,0,0.32);

    /* Backward-compat tokens */
    --border-default: 1px solid var(--neutral-200);
    --border-strong:  1px solid var(--neutral-300);
    --border-brand:   1px solid var(--brand-400);
    --shadow-focus:   0 0 0 3px var(--brand-50);
  }

  html:not([data-theme="light"]) .ui-datepicker-input {
    color-scheme: dark;
  }
}

/* ========================================
   Dark Mode — Manual Override
   ======================================== */

html[data-theme="dark"] {
/* >>> BEGIN GENERATED DARK TOKENS (scripts/sync-tokens.py) - do not edit by hand */
--neutral-950: #EEEEF0;
--neutral-800: #C8C8CC;
--neutral-700: #A3A3A8;
--neutral-600: #86868C;
--neutral-500: #6E6E74;  /* dark-mode pairing for --neutral-500 */
--neutral-400: #56565C;
--neutral-300: #3A3A3F;
--neutral-200: #2C2C30;
--neutral-100: #222225;
--neutral-50:  #18181A;
--white:       #1F1F23;
--brand-50:  #0D2318;
--brand-100: #143320;
--brand-400: #41B983;
--brand-500: #6FD0A4;
--success-surface: #0D2420;  --success-border: #1E6B60;
--success-icon:    #41C4B0;  --success-title:  #6FD4C4;
--warning-surface: #221A06;  --warning-border: #7A5000;
--warning-icon:    #F59E0B;  --warning-title:  #FBBF24;
--danger-surface:  #240A0E;  --danger-border:  #7A1020;
--danger-icon:     #F87171;  --danger-title:   #FCA5A5;
--info-surface:    #0A1530;  --info-border:    #1E3A8A;
--info-icon:       #60A5FA;  --info-title:     #93C5FD;
--cyan-surface:    #08222A;  --cyan-border:    #1E5A6E;  --cyan-title:  #78CFE0;  /* categorical report-tile cyan (#374) */
--alert-body:      #C8C8CC;
--success-500: #41C4B0;  --success-100: #0D2420;
--warning-500: #FBBF24;  --warning-100: #221A06;
--danger-500:  #FCA5A5;  --danger-100:  #240A0E;
--info-500:    #93C5FD;  --info-100:    #0A1530;
--bark-500:    #C9A27A;  --bark-100:    #241A10;
/* <<< END GENERATED DARK TOKENS */

  /* App-only dark additions, kept outside the generated block (hand-maintained):
     the -900 stop, the brand and danger text stops, the focus ring, shimmer, pay-* surfaces,
     and the var()-based compat tokens.
     The shadow values below also live in the canonical export but use multi-part
     values scripts/sync-tokens.py does not parse, so they stay hand-maintained. */
  --neutral-900: #D4D4D8;
  --brand-ink: var(--brand-400);  /* brand-green text; see :root */
  --brand-link: var(--brand-500);  /* GH-1521 card links keep the shipped dark pair; see :root */
  --brand-link-hover: var(--brand-600);
  --focus-ring: var(--brand-400);  /* keyboard focus indicator; see :root */
  --brand-600: var(--brand-400);  /* text on the dark surface; white-label fills use --brand-fill */
  --brand-700: var(--brand-200);  /* the next, lighter step: hovers and strong text; see :root */
  --danger-600: var(--danger-icon);  /* red text, stronger than -500; white-label fills use --danger-fill */
  --shimmer-sheen: rgba(255, 255, 255, 0.08);
  --pay-stripe-surface: #1E1B3A;
  --pay-zelle-surface:  #241038;
  --pay-venmo-surface:  #0E2738;

  /* Shadows — heavier opacity on dark backgrounds */
  --shadow-xs:  0 1px 2px rgba(0,0,0,0.30);
  --shadow-sm:  0 1px 4px rgba(0,0,0,0.36), 0 1px 2px rgba(0,0,0,0.24);
  --shadow-md:  0 4px 12px rgba(0,0,0,0.40), 0 2px 4px rgba(0,0,0,0.24);
  --shadow-lg:  0 8px 24px rgba(0,0,0,0.48), 0 3px 8px rgba(0,0,0,0.28);
  --shadow-xl:  0 16px 48px rgba(0,0,0,0.56), 0 6px 16px rgba(0,0,0,0.32);
  --edge-fade:  rgba(0,0,0,0.32);

  /* Backward-compat tokens */
  --border-default: 1px solid var(--neutral-200);
  --border-strong:  1px solid var(--neutral-300);
  --border-brand:   1px solid var(--brand-400);
  --shadow-focus:   0 0 0 3px var(--brand-50);
}

html[data-theme="dark"] .ui-datepicker-input {
  color-scheme: dark;
}

/* ========================================
   Light Mode — Manual Override
   (restores light tokens on dark-system devices)
   ======================================== */

html[data-theme="light"] {
  --neutral-950: #18181A;
  --neutral-900: #27272A;
  --neutral-800: #38383C;
  --neutral-700: #505055;
  --neutral-600: #6B6B70;
  --neutral-500: #8A8A90;
  --neutral-400: #A3A3A8;
  --neutral-300: #C8C8CC;
  --neutral-200: #E4E4E7;
  --neutral-100: #F0F0F2;
  --neutral-50:  #F9F9FA;
  --white:       #FFFFFF;

  --brand-50:  #F0FBF5;
  --brand-100: #D8F3E8;
  --brand-400: #41B983;
  --brand-500: #2E9B6E;

  --pay-stripe-surface: #EFEEFF;
  --pay-zelle-surface:  #F1E8FB;
  --pay-venmo-surface:  #E4F1F9;

  --success-500: #0C7A6E; --success-100: #DFF5F2;
  --warning-500: #A85D00; --warning-100: #FEF0D6;
  --danger-500:  #C42032; --danger-100:  #FDEAED;
  --info-500:    #1D5FCC; --info-100:    #D6E8FF;

  --badge-success-border: #8ED8D0;
  --badge-warning-border: #F5C882;
  --badge-danger-border:  #F5A8B4;
  --badge-info-border:    #93BBFF;

  --success-surface: #EEFAF8; --success-border: #68C7BB;
  --success-icon:    #0D9B87; --success-title:  #0A7B6C;
  --warning-surface: #FFFBEF; --warning-border: #FBD07C;
  --warning-icon:    #D97706; --warning-title:  #92400E;
  --danger-surface:  #FFF2F4; --danger-border:  #F4A3AE;
  --danger-icon:     #E0334A; --danger-title:   #C42032;
  --info-surface:    #EEF4FF; --info-border:    #90B5F5;
  --info-icon:       #2868D6; --info-title:     #1A52B8;
  --alert-body:      #38383C;

  --shadow-xs:  0 1px 2px rgba(24,24,26,0.05);
  --shadow-sm:  0 1px 4px rgba(24,24,26,0.06), 0 1px 2px rgba(24,24,26,0.04);
  --shadow-md:  0 4px 12px rgba(24,24,26,0.08), 0 2px 4px rgba(24,24,26,0.04);
  --shadow-lg:  0 8px 24px rgba(24,24,26,0.10), 0 3px 8px rgba(24,24,26,0.05);
  --shadow-xl:  0 16px 48px rgba(24,24,26,0.12), 0 6px 16px rgba(24,24,26,0.06);

  --border-default: 1px solid var(--neutral-200);
  --border-strong:  1px solid var(--neutral-300);
  --border-brand:   1px solid var(--brand-400);
  --shadow-focus:   0 0 0 3px var(--brand-50);
}

/* Stripe.js "testing assistant" — a dev widget (internal codename "easel") Stripe.js injects
   as a body-level iframe under pk_test. It bleeds across SPA routes because route changes don't
   reload the page. Scope the hide to the easel iframe ONLY: the card Payment Element is a
   different stripe.com iframe (elements-inner-card) and must stay visible. A no-op when the
   widget is absent (local, pk_live, or when the init-disable in utils/stripe.ts is honoured). */
iframe[src*="elements-inner-easel"] { display: none !important; }
