:root {
  /* ========================================================================
     PWA brand convergence to marketing green palette (Day 22 — repaint
     batch). Token values match mobile/styles-marketing.css byte-identically
     for shared concepts:
       --bg          = --mkt-bg-cream  (#faf7f1)
       --card        = --mkt-card-light (#ffffff)
       --brand       = --mkt-bg-dark    (#0e1d18)   ← forest green
       --accent      = --mkt-accent     (#34d680)   ← lime
       --accent-on-light = --mkt-accent-strong (#29b86b) — readable lime
                            on cream/white surfaces
       --hero-bg     = --mkt-bg-dark    (#0e1d18)
       --ink         = #0e1d18 (matches marketing text-on-light)
     Severity tokens (--success / --warning / --danger) UNCHANGED — they
     carry semantic meaning. Severity-green #15803d (deep forest) is
     visually distinct from brand-accent #34d680 (bright lime) so the
     two coexist without conflict on Insights cards / AR aging tile.
     ======================================================================== */

  /* Cream foundation — matches marketing site's body bg */
  --bg: #faf7f1;
  --bg-2: #f0ebe2;
  --card: #ffffff;
  --border: #e8e2d4;
  --border-2: #d4cdb8;

  /* Forest-green ink ladder — matches marketing's --mkt-text-on-light
     family. WCAG AA verified at 4.5:1 against --bg cream. */
  --ink: #0e1d18;
  --ink-2: #3e4d47;
  --ink-3: #6a7570;
  --ink-4: #a4ada8;
  --ink-5: #d4d4d8;

  /* Brand: forest green (matches marketing dark hero bg) */
  --brand: #0e1d18;
  --brand-2: #1a2f29;
  --brand-soft: rgba(52, 214, 128, 0.12);
  --brand-soft-2: rgba(52, 214, 128, 0.20);
  --brand-fg: #f6f3ee;

  /* Accent: lime (matches marketing CTA fills + lime DB logo block) */
  --accent: #34d680;
  --accent-2: #29b86b;
  --accent-soft: rgba(52, 214, 128, 0.12);
  /* Accent variant for small text on light surfaces. Marketing's
     #29b86b passes contrast as link text on cream at 14px+, but PWA
     consumers include 12px nav links + card-title links where
     #29b86b lands at ~2.4:1 — below the WCAG AA 4.5:1 body-text bar.
     #178350 (Tailwind emerald-700 region) lands at ~4.7:1 against
     #faf7f1 cream. Reads as brand-family green; tonally close to
     severity-green #15803d but visually disambiguated by context
     (severity = circular dots / left borders / pill bg; brand-on-
     light = link text within heading rows). Documented in CLAUDE.md
     under PWA brand convergence. */
  --accent-on-light: #178350;

  /* Themable surfaces (Dark theme below overrides for the dark variant) */
  --topbar-bg: rgba(250, 247, 241, 0.92);
  --tabbar-bg: rgba(255, 255, 255, 0.94);

  /* Active tab — lime tint */
  --tab-active-bg: var(--accent-soft);
  --tab-active-fg: var(--accent-on-light);

  /* Hero card surface — forest green matches marketing's .mkt-hero */
  --hero-bg: var(--brand);
  --hero-text: var(--brand-fg);
  --hero-caption: rgba(246, 243, 238, 0.7);

  /* Status — restrained. Unchanged from pre-convergence — these carry
     semantic meaning per the v1.11 visual quality bar. Severity-green
     #15803d is visually distinct from brand-accent #34d680 (deep
     forest vs bright lime) so no shift needed. */
  --success: #15803d;
  --success-soft: #f0fdf4;
  --success-border: #bbf7d0;

  --warning: #b45309;
  --warning-soft: #fffbeb;
  --warning-border: #fde68a;

  --danger: #b91c1c;
  --danger-soft: #fef2f2;
  --danger-border: #fecaca;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bot: env(safe-area-inset-bottom, 0px);

  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Helvetica Neue", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--ink);
  letter-spacing: -0.005em;
  font-feature-settings: "ss01", "cv11", "cv09";
}
body {
  padding-top: var(--safe-top);
  padding-bottom: calc(108px + var(--safe-bot));
}
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
select { font: inherit; color: inherit; }

/* Tabular numbers everywhere they belong */
.num, .hero-value, .cat-amount, .vendor-amount, .hero-mini-value, .stat-value {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* ===== Theme classes =====
   Dark swaps neutrals; the 8 accent themes only swap brand/accent. */
:root.theme-dark, body.theme-dark {
  /* Dark theme repainted to marketing's forest-green dark surface
     (mkt-bg-dark / mkt-card-dark) so the PWA's dark mode reads as
     "dark version of the marketing site," not "generic Material dark."
     Lime accent + forest-green bg combo matches the
     mkt-section-dark blocks. */
  --bg: #0e1d18;
  --bg-2: #142823;
  --card: #142823;
  --border: rgba(255, 255, 255, 0.08);
  --border-2: rgba(255, 255, 255, 0.14);
  --ink: #f6f3ee;
  --ink-2: #d3d8d5;
  --ink-3: #a4ada8;
  --ink-4: #7a847f;
  --ink-5: rgba(255, 255, 255, 0.18);
  --brand-soft: rgba(52, 214, 128, 0.16);
  --brand-soft-2: rgba(52, 214, 128, 0.24);
  --topbar-bg: rgba(14, 29, 24, 0.92);
  --tabbar-bg: rgba(20, 40, 35, 0.94);
  /* Dark mode active tab — lime accent on subtle translucent pill */
  --tab-active-bg: rgba(52, 214, 128, 0.16);
  --tab-active-fg: #34d680;
}
/* --accent-on-light override: every accent theme needs to set this to
   its own --accent value so brand-tinted text reads as that theme's
   brand, not as the default green palette's #29b86b lime. Gold already
   ships a custom darker-gold override for its specific contrast need. */
:root.theme-crimson, body.theme-crimson      { --brand: #9E1B32; --brand-2: #7E1626; --brand-soft: #FBEEF1; --brand-soft-2: #F2D4DA; --accent: #9E1B32; --accent-2: #BE3A50; --accent-soft: #FBEEF1; --accent-on-light: #9E1B32; --brand-fg: #ffffff; --hero-bg: #9E1B32; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-burnt-orange, body.theme-burnt-orange { --brand: #BF5700; --brand-2: #8C3F00; --brand-soft: #FBEFE0; --brand-soft-2: #F2DBB8; --accent: #BF5700; --accent-2: #D97706; --accent-soft: #FBEFE0; --accent-on-light: #BF5700; --brand-fg: #ffffff; --hero-bg: #9C3F00; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-maroon, body.theme-maroon       { --brand: #500000; --brand-2: #380000; --brand-soft: #F2E5E5; --brand-soft-2: #E5C7C7; --accent: #500000; --accent-2: #7A1F1F; --accent-soft: #F2E5E5; --accent-on-light: #500000; --brand-fg: #ffffff; --hero-bg: #500000; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-forest, body.theme-forest       { --brand: #154734; --brand-2: #0F3325; --brand-soft: #E5EFEB; --brand-soft-2: #C7DACE; --accent: #154734; --accent-2: #2A6F54; --accent-soft: #E5EFEB; --accent-on-light: #154734; --brand-fg: #ffffff; --hero-bg: #154734; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-royal-blue, body.theme-royal-blue   { --brand: #003594; --brand-2: #00266B; --brand-soft: #E0E8F4; --brand-soft-2: #BCCBE5; --accent: #003594; --accent-2: #1E5FBE; --accent-soft: #E0E8F4; --accent-on-light: #003594; --brand-fg: #ffffff; --hero-bg: #003594; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-navy, body.theme-navy         { --brand: #001F3F; --brand-2: #00152B; --brand-soft: #E0E5EC; --brand-soft-2: #BCC4D2; --accent: #001F3F; --accent-2: #1E4068; --accent-soft: #E0E5EC; --accent-on-light: #001F3F; --brand-fg: #ffffff; --hero-bg: #001F3F; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-purple, body.theme-purple       { --brand: #4B2E83; --brand-2: #38215F; --brand-soft: #EDE7F4; --brand-soft-2: #D5C8E5; --accent: #4B2E83; --accent-2: #6E4DAD; --accent-soft: #EDE7F4; --accent-on-light: #4B2E83; --brand-fg: #ffffff; --hero-bg: #4B2E83; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }
:root.theme-gold, body.theme-gold         { --brand: #FFB81C; --brand-2: #8B6508; --brand-soft: #FFF7E0; --brand-soft-2: #FCE9B5; --accent: #8B6508; --accent-2: #B5841F; --accent-soft: #FFF7E0; --accent-on-light: #6E5108; --brand-fg: #1a1a1a; --hero-bg: #B8860B; --hero-text: #ffffff; --hero-caption: rgba(255, 255, 255, 0.78); }

/* ===== Top bar ===== */
.topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--topbar-bg);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  padding: calc(var(--safe-top) + 14px) 20px 14px;
  border-bottom: 1px solid var(--border);
}
.topbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.topbar-btn {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  background: var(--card);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  color: var(--ink-2);
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.04);
}
.topbar-btn svg { width: 18px; height: 18px; }
.topbar-btn:active { background: var(--bg-2); }
/* Settings (tile customize) button shows on tabs in EDITABLE_TILE_TABS
   (#269 Phase 1B Part 2 generalized this from home-only to home +
   practice-health). Class name kept as -overview-only for back-compat
   with the existing button markup in index.html.

   UX expert (Day 29) — gear icon alone was non-obvious. Inline
   "Customize" label sits next to the SVG when visible, so users can
   parse the button's affordance without relying on aria-label/tooltip.
   The display:flex override (vs the base .topbar-btn display:grid)
   lets the label flow inline with the icon. Auto width + tighter
   padding keeps the button compact at 412px viewport. ≥44×44 effective
   touch target via the existing height: 36px + the typical tappable
   pattern (16px padding around the row gives the surrounding hit area
   well above the 44px Apple HIG minimum). */
.topbar-btn-overview-only { display: none; }
body.is-cog-visible .topbar-btn-overview-only {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: auto;
  padding: 0 10px;
}
.topbar-btn-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  letter-spacing: -0.005em;
}

/* Top-bar slimming per tab (task #131 Commit 1, retired Day 31 follow-up
   #362). The per-tab practice-name hide rule went away when the
   .brand-sub wordmark row was retired and the practice name moved into
   .brand-title (always-on across all tabs). The Settings-tab FY-hide
   rule went away in the follow-up when the FY picker itself was moved
   out of the topbar into Settings → Practice Info. .fy-select CSS rule
   below stays — same dropdown chrome reused for the Settings home
   of the picker. */

/* Settings tab — Robinhood-style menu list (task #131 Commit 2.5).
   Each row is a tap target that opens a bottom sheet with that
   section's content; sign-out is an independent destructive button
   below the menu. Visual: clean list rows separated by subtle
   borders, optional right-aligned hint text per row, chevron at
   the far right. Coming-soon group has a slightly softer label
   styling. */
.settings-menu-wrapper {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.settings-menu-card {
  padding: 0;
  overflow: hidden;
}
.settings-menu-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 16px 18px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border-2);
  font-family: inherit;
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background 0.12s;
}
.settings-menu-row:last-child { border-bottom: none; }
.settings-menu-row:hover,
.settings-menu-row:active { background: var(--bg-2); }
.settings-menu-label {
  flex: 1;
  letter-spacing: -0.005em;
  /* Day 37 Bug #D (Edwin onboarding test) — was wrapping to 2 lines
     when paired with a long hint ("Open Dental · 3 days ago" pre-#E
     fix). Single-line with ellipsis if needed; the hint's flex-shrink:0
     below keeps it from compressing the label below readability. */
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.settings-menu-hint {
  font-size: 14px;
  color: var(--ink-3);
  font-weight: 500;
  flex-shrink: 0;
  white-space: nowrap;
}
.settings-menu-hint-soft {
  color: var(--ink-4);
  font-size: 13px;
  font-style: italic;
}
.settings-menu-chev {
  font-size: 22px;
  color: var(--ink-4);
  line-height: 1;
  font-weight: 300;
  margin-left: 4px;
}
.settings-menu-card-placeholders .settings-menu-label {
  color: var(--ink-3);
}
.settings-signout-btn {
  margin-top: 14px;
}

/* ----- Settings line icons + nested-nav chrome (Day 25) ----- */
/* Lucide-style 24x24 stroke-2 line icon to the LEFT of every row label.
   Muted by default; row hover/active doesn't change the icon color (the
   row background shift carries the affordance). */
.settings-menu-icon {
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-3);
  margin-right: 2px;
}
.settings-menu-icon svg {
  width: 24px;
  height: 24px;
  stroke: currentColor;
}
/* Sub-page header — back arrow + title + invisible right spacer so the
   title is visually centered between the two 32px end caps. */
.settings-subpage-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 4px 14px;
}
.settings-subpage-back {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--ink);
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s;
}
.settings-subpage-back:hover,
.settings-subpage-back:active { background: var(--bg-2); }
.settings-subpage-back svg { width: 22px; height: 22px; }
.settings-subpage-title {
  flex: 1;
  text-align: center;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.settings-subpage-spacer {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
}

/* ----- Submit a ticket form (Day 25) ----- */
.ticket-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 4px;
}
.ticket-input,
.ticket-textarea {
  width: 100%;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  box-sizing: border-box;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.ticket-input:focus,
.ticket-textarea:focus {
  outline: none;
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 3px rgba(52, 214, 128, 0.18);
}
.ticket-textarea {
  resize: vertical;
  min-height: 120px;
  line-height: 1.5;
}
.ticket-status {
  font-size: 13px;
  color: var(--ink-3);
  min-height: 18px;
}
.ticket-status-success { color: var(--success); }
.ticket-status-error { color: var(--danger); }
.ticket-submit-btn {
  align-self: stretch;
  margin-top: 4px;
}
.ticket-submit-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* ----- Practice Management section (Phase 2 entry-point) ----- */
.pms-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pms-status-block {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pms-status-label {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.pms-status-detail {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.4;
}
.pms-status-active       { color: #15803d; }
.pms-status-disconnected { color: var(--ink-3); }
.pms-status-error        { color: #b91c1c; }
.pms-status-pending      { color: var(--accent-on-light); }

/* PMS picker strip — Open Dental live, Dentrix/Eaglesoft coming-soon
   (Day 25 ship batch). Stacked-card layout at <412px; 3-column grid
   at wider viewports. Disabled entries keep tap-target ≥44px so the
   "Coming soon" tooltip can fire on touch + don't visually advertise
   tappable affordance via hover lift. */
.pms-picker {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}
@media (min-width: 540px) {
  .pms-picker { grid-template-columns: repeat(3, 1fr); }
}
.pms-picker-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 56px;
  padding: 10px 14px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s, box-shadow 0.12s;
}
.pms-picker-option:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}
.pms-picker-active {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.pms-picker-disabled {
  color: var(--ink-3);
  background: var(--bg-2);
}
.pms-picker-disabled:hover {
  border-color: var(--border);
}
.pms-picker-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.pms-picker-disabled .pms-picker-name { color: var(--ink-3); }
.pms-picker-tag {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.pms-picker-tag-live {
  background: var(--accent-on-light);
  color: var(--card);
}
.pms-picker-tag-soon {
  background: color-mix(in srgb, var(--ink-3) 14%, var(--card));
  color: var(--ink-3);
  border: 1px solid var(--border);
}
/* admin_items #88 wire-up — PMSes with shipped CSV-import support
   (currently Archy) get the lime "CSV import" pill instead of grey
   "Coming soon". */
.pms-picker-tag-csv {
  background: color-mix(in srgb, var(--accent) 18%, var(--card));
  color: var(--accent-on-light);
  border: 1px solid color-mix(in srgb, var(--accent) 36%, var(--border));
  font-weight: 700;
}
.pms-coming-soon-note {
  padding: 10px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 6%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border));
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.5;
}

/* ----- CSV upload flow (admin_items #88, Phase 3 Step E skeleton) ------ */
/* Unreachable in v1 — PMS_CSV_IMPORT_SUPPORT[archy] flips true when
   Step D adapter ships. Layout intent: tall stacked sections inside
   the existing sheet chrome. */
.csv-upload-flow { display: flex; flex-direction: column; gap: 18px; }
.csv-upload-header { display: flex; flex-direction: column; gap: 6px; }
.csv-upload-title { font-size: 18px; font-weight: 700; letter-spacing: -0.015em; color: var(--ink); margin: 0; }
.csv-upload-sub { font-size: 13px; font-weight: 500; line-height: 1.5; color: var(--ink-2); margin: 0; }
.csv-upload-guide-link {
  font-size: 13px; font-weight: 600; color: var(--accent-on-light);
  text-decoration: underline;
}
.csv-upload-dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 180px; padding: 24px;
  border: 2px dashed color-mix(in srgb, var(--accent) 38%, var(--border));
  border-radius: 14px;
  background: color-mix(in srgb, var(--accent) 4%, var(--card));
  cursor: pointer;
  transition: background 160ms ease-out, border-color 160ms ease-out;
}
.csv-upload-dropzone[data-state="hover"] {
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  border-color: var(--accent);
}
.csv-upload-dropzone:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.csv-upload-dropzone-prompt { display: flex; flex-direction: column; align-items: center; gap: 8px; text-align: center; }
.csv-upload-dropzone-icon { font-size: 28px; color: var(--accent-on-light); }
.csv-upload-dropzone-headline { font-size: 15px; font-weight: 700; color: var(--ink); }
.csv-upload-dropzone-sub { font-size: 12px; font-weight: 500; color: var(--ink-3); }

.csv-upload-staging { display: flex; flex-direction: column; gap: 8px; }
.csv-upload-staging-title { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); margin: 0; }
.csv-upload-staging-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 4px; }
.csv-upload-staging-list li {
  padding: 8px 12px; border-radius: 8px;
  background: var(--bg-2); color: var(--ink-2);
  font-size: 13px; font-variant-numeric: tabular-nums;
}

.csv-upload-preview {
  padding: 14px; border-radius: 10px;
  background: var(--bg-2); color: var(--ink-2); font-size: 13px;
}
.csv-upload-preview-title { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 8px; }

.csv-upload-actions { display: flex; gap: 10px; }
.csv-upload-submit-btn[disabled],
.csv-upload-preview-btn[disabled],
.csv-upload-apply-btn[disabled] { opacity: 0.55; cursor: not-allowed; }

/* admin_items #88 Step D — anchor month picker + preview summary + status block */
.csv-upload-month-row { display: flex; align-items: center; gap: 12px; }
.csv-upload-month-label { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.csv-upload-month-input {
  padding: 8px 12px; border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card); color: var(--ink);
  font-size: 14px; font-family: inherit;
}

.csv-upload-preview-summary {
  display: grid; gap: 6px;
  padding: 12px; border-radius: 10px;
  background: var(--bg-2); color: var(--ink);
  font-size: 13px; line-height: 1.5;
}
.csv-upload-preview-summary strong {
  font-variant-numeric: tabular-nums;
  color: var(--accent-on-light);
}
.csv-upload-preview-details {
  margin-top: 8px; padding: 8px 12px;
  border-radius: 8px; background: var(--bg-2);
  font-size: 12px; color: var(--ink-2);
}
.csv-upload-preview-details summary {
  cursor: pointer; font-weight: 600; color: var(--ink);
}
.csv-upload-preview-details ul {
  margin: 8px 0 0 16px; padding: 0;
}
.csv-upload-preview-details li { padding: 2px 0; }
.csv-upload-preview-actions {
  display: flex; gap: 10px; margin-top: 12px;
}

.csv-upload-status {
  padding: 10px 12px; border-radius: 8px;
  background: var(--bg-2); color: var(--ink-2);
  font-size: 13px; font-weight: 500; line-height: 1.5;
}
.csv-upload-status[data-kind="info"] {
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--border));
}
.csv-upload-status[data-kind="success"] {
  background: color-mix(in srgb, var(--success) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--success) 28%, var(--border));
}
.csv-upload-status[data-kind="error"] {
  background: color-mix(in srgb, #b91c1c 10%, transparent);
  border: 1px solid color-mix(in srgb, #b91c1c 30%, transparent);
  color: #991b1b;
}
.csv-upload-status[data-kind="warn"] {
  background: color-mix(in srgb, var(--warning) 14%, var(--card));
  border: 1px solid color-mix(in srgb, var(--warning) 28%, var(--border));
  color: var(--ink);
}
.csv-upload-success-cta {
  display: flex; gap: 10px; margin-top: 12px;
}
.csv-upload-view-ph-btn { min-height: 44px; }

.pms-error {
  padding: 10px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, #b91c1c 10%, transparent);
  border: 1px solid color-mix(in srgb, #b91c1c 30%, transparent);
  color: #991b1b;
  font-size: 12px;
  line-height: 1.4;
}
.pms-viewer-note {
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
}
.pms-connect-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pms-help-text {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0;
}
.pms-help-text-small {
  font-size: 11px;
  color: var(--ink-3);
  line-height: 1.4;
  margin: 0;
  font-style: italic;
}
.pms-input-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pms-input-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.pms-input {
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--ink);
  font-size: 14px;
  font-family: -apple-system, BlinkMacSystemFont, "SF Mono", "Segoe UI Mono", monospace;
  letter-spacing: 0;
}
.pms-input:focus {
  outline: none;
  border-color: var(--accent);
}
.pms-env-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}
.pms-radio {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.pms-radio input { margin: 0; }
.pms-submit-btn {
  margin-top: 4px;
  min-height: 44px;
}
.pms-connected-actions {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pms-month-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pms-month-select {
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--ink);
  font-size: 14px;
  min-height: 44px;
}
.pms-month-select:focus {
  outline: none;
  border-color: var(--accent);
}
.pms-action-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.pms-sync-btn,
.pms-disconnect-btn {
  flex: 1;
  min-height: 44px;
  min-width: 130px;
}

/* ----- Day 25 — Autonomous setup flow (4-step) ----- */
.pms-setup-flow {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.pms-setup-intro .pms-help-text {
  margin: 0;
}
.pms-step {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg-2);
}
.pms-step-header {
  display: flex;
  align-items: center;
  gap: 10px;
}
.pms-step-num {
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: var(--accent-on-light);
  color: var(--card);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: -0.005em;
  flex-shrink: 0;
}
.pms-step-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.pms-step-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.pms-step-body .pms-help-text {
  margin: 0;
}
.pms-instructions {
  margin: 0;
  padding-left: 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.pms-instructions li strong {
  color: var(--ink);
  font-weight: 700;
}

/* Key display + copy. Uses the same monospace look as input fields so
   the customer reads it as "a code to paste" not "label text". */
.pms-key-display {
  display: flex;
  align-items: stretch;
  gap: 8px;
  flex-wrap: wrap;
}
.pms-key-code {
  flex: 1;
  min-width: 180px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "SF Mono", "Segoe UI Mono", monospace;
  font-size: 13px;
  letter-spacing: 0.02em;
  word-break: break-all;
  user-select: all;
  -webkit-user-select: all;
  line-height: 1.4;
}
.pms-copy-btn {
  min-width: 92px;
  min-height: 44px;
  padding: 10px 14px;
  border-radius: 8px;
}
.pms-regenerate-link {
  align-self: flex-start;
  background: none;
  border: none;
  padding: 6px 0;
  font-size: 12px;
  color: var(--accent-on-light);
  text-decoration: underline;
  cursor: pointer;
  font-family: inherit;
  min-height: 32px;
}
.pms-regenerate-link:hover,
.pms-regenerate-link:focus-visible {
  color: var(--ink);
}
.pms-regenerate-link:disabled {
  color: var(--ink-3);
  cursor: default;
  text-decoration: none;
}

/* Step 3 — confirm checkbox + test button. */
.pms-confirm-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
  line-height: 1.5;
  padding: 4px 0;
}
.pms-confirm-row input[type="checkbox"] {
  margin-top: 2px;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}
.pms-test-btn {
  min-height: 44px;
}

/* Failed-state callout above the test button on Step 3. */
.pms-failed-note {
  padding: 10px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, #b91c1c 8%, transparent);
  border: 1px solid color-mix(in srgb, #b91c1c 25%, transparent);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.5;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.pms-failed-note strong {
  color: #991b1b;
  font-weight: 700;
}
.pms-failed-note p {
  margin: 0;
}

/* Cancel-setup tertiary link at the bottom of the flow. */
.pms-cancel-row {
  display: flex;
  justify-content: center;
  padding-top: 4px;
}
.pms-cancel-link {
  background: none;
  border: none;
  padding: 8px 0;
  font-size: 12px;
  color: var(--ink-3);
  text-decoration: underline;
  cursor: pointer;
  font-family: inherit;
  min-height: 32px;
}
.pms-cancel-link:hover,
.pms-cancel-link:focus-visible {
  color: var(--ink);
}

/* ----- Day 27 — Multi-month backfill UI ----- */
.pms-connected-wrap {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.pms-backfill-block {
  display: flex;
  flex-direction: column;
}
.pms-backfill-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--bg-2);
}
.pms-backfill-card-cta {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  background: color-mix(in srgb, var(--accent) 4%, var(--bg-2));
}
.pms-backfill-cta-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.pms-backfill-cta-desc {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.45;
}
.pms-backfill-start-btn {
  margin-top: 4px;
  min-height: 44px;
}

.pms-backfill-card-progress {
  border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
}
.pms-backfill-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
}
.pms-backfill-card-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.pms-backfill-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent-on-light);
  flex-shrink: 0;
  animation: pms-backfill-pulse 1.4s ease-in-out infinite;
}
@keyframes pms-backfill-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.5; transform: scale(0.85); }
}
@media (prefers-reduced-motion: reduce) {
  .pms-backfill-dot { animation: none; }
}
.pms-backfill-progress-line {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.4;
}
.pms-backfill-progress-bar {
  height: 6px;
  border-radius: 3px;
  background: var(--bg);
  overflow: hidden;
  border: 1px solid var(--border);
}
.pms-backfill-progress-fill {
  height: 100%;
  background: var(--accent-on-light);
  transition: width 0.4s ease-out;
  border-radius: 3px;
}
.pms-backfill-card-help {
  font-size: 11px;
  color: var(--ink-3);
  line-height: 1.45;
  font-style: italic;
}
.pms-backfill-cancel-btn {
  align-self: flex-start;
  padding: 8px 14px;
  border-radius: 8px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  min-height: 36px;
}
.pms-backfill-cancel-btn:hover,
.pms-backfill-cancel-btn:focus-visible {
  background: var(--bg);
  color: var(--ink);
}
.pms-backfill-cancel-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.pms-backfill-card-summary {
  border-color: var(--border);
}
.pms-backfill-summary-line {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.45;
}
.pms-backfill-success { color: #15803d; font-weight: 600; }
.pms-backfill-partial { color: #b45309; font-weight: 600; }
.pms-backfill-failed  { color: #b91c1c; font-weight: 600; }
.pms-backfill-rerun-btn {
  align-self: flex-start;
  padding: 8px 14px;
  border-radius: 8px;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  min-height: 36px;
}
.pms-backfill-rerun-btn:hover,
.pms-backfill-rerun-btn:focus-visible {
  background: var(--bg);
  color: var(--ink);
}
.pms-backfill-rerun-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Practice Health tab top banner — slim status row when backfill is
   in_progress. Same visual register as .indexing-banner (Plaid catching-
   up banner). */
.backfill-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
  margin-bottom: 12px;
}
.backfill-banner-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent-on-light);
  flex-shrink: 0;
  margin-top: 5px;
  animation: pms-backfill-pulse 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .backfill-banner-dot { animation: none; }
}
.backfill-banner-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.backfill-banner-line1 {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.backfill-banner-line2 {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.4;
}

/* Day 28+29 — Auto-refresh toggle row. Sits between the Backfill block
   and the manual Sync month picker on Settings → Practice Management.
   Same visual register as a standard list-item toggle (Settings →
   Practice settings doctors sheet uses similar toggle-switch chrome). */
.pms-auto-refresh-block {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--card);
  padding: 12px 14px;
}
.pms-auto-refresh-row {
  display: flex;
  align-items: center;
  gap: 14px;
}
.pms-auto-refresh-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.pms-auto-refresh-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.pms-auto-refresh-sub {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.45;
}
.pms-auto-refresh-toggle {
  flex-shrink: 0;
}
/* admin_items #60 Pattern 5 (migration 144) — status line under the
   toggle showing the daily cron's last-attempt timestamp or error
   message. Rendered only when auto_refresh_enabled=true AND the cron
   has fired at least once for this practice. */
.pms-auto-refresh-status {
  margin-top: 8px;
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--bg-2);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.pms-auto-refresh-status-error {
  color: var(--danger, #c62828);
  background: rgba(198, 40, 40, 0.06);
}

/* admin_items #60 / #419 (migration 147) — quieter "Daily refresh in
   progress" line replaces the full backfill progress card when
   backfill_trigger_source = 'auto_refresh'. Same chrome shape as the
   .pms-auto-refresh-status line above so the two states (last
   refresh / refresh in progress) feel like one ambient strip below
   the toggle. */
.pms-auto-refresh-running {
  padding: 6px 10px;
  border-radius: 6px;
  background: var(--bg-2);
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Sheet body neutralizes inner card chrome — when a section's
   standalone .card renders inside the openSettingsSheet mount, the
   card's border + padding + background would double up against the
   sheet's own padding. Reset to passthrough so the section content
   sits flush in the sheet. */
.settings-sheet-mount .card {
  padding: 0;
  background: transparent;
  border: none;
  box-shadow: none;
  margin: 0;
}
.settings-sheet-mount .card-title {
  /* The sheet has its own <h2> title; suppress the inner card's
     redundant card-title h3 which would duplicate the heading. */
  display: none;
}
/* Theme-aware form controls inside Settings sheets (task #149).
   Pre-fix the practice-name + doctor-name inputs rendered as stark
   white boxes on dark themes because the only matching style rule
   was scoped to .settings-section — a class that #131 Commit 2.5's
   Robinhood-menu refactor stopped applying (JSX now wraps each
   section in <section class="card"> inside .settings-sheet-mount).
   Scoping to .settings-sheet-mount catches every current input
   (#settings-practice-name, .settings-doctor-name) plus any future
   form control inside a section sheet without per-renderer class
   plumbing. Padding bumped to 12px so the input clears the 44px
   touch-target floor per CLAUDE.md UI design principles. */
.settings-sheet-mount input[type="text"],
.settings-sheet-mount input[type="number"],
.settings-sheet-mount input[type="email"],
.settings-sheet-mount select,
.settings-sheet-mount textarea {
  width: 100%;
  padding: 12px 14px;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.settings-sheet-mount input::placeholder { color: var(--ink-4); }
.settings-sheet-mount input:focus,
.settings-sheet-mount select:focus,
.settings-sheet-mount textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ===== Canonical sheet action bar (#155) =====
   Bottom-of-sheet action surface, used by every Settings section
   sheet (Practice info, Doctors, Banks, Theme, Help, Account,
   Billing, Notifications, Integrations) and reusable for any
   future bottom-sheet that needs primary/secondary/destructive
   actions. All buttons share the same visual frame (height,
   padding, font weight) — semantic difference only via fill color.
   Right-aligned flex; primary action surfaces last so the visual
   weight aligns with the reading-direction "main action" position
   per Apple HIG conventions.
   Pre-fix sheets used inconsistent inline button placements:
   Practice info had Save inline next to the input (.settings-inline-
   edit pattern), Doctors had Save inside a nested .reclassify-actions
   div with different sizing from the sheet-level Close, the rest
   had only Close in .reclassify-actions. The unified .sheet-action-
   bar surface fixes the inconsistency without per-section overrides. */
.sheet-action-bar {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--border-2);
}
.btn-action {
  height: 40px;
  padding: 0 18px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--card);
  color: var(--ink);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, opacity 0.12s;
  flex-shrink: 0;
  min-width: 84px;
}
.btn-action:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn-action-primary {
  background: var(--accent);
  color: var(--hero-text, white);
  border-color: var(--accent);
}
.btn-action-primary:not(:disabled):active {
  background: color-mix(in srgb, var(--accent) 85%, black);
}
.btn-action-secondary {
  background: var(--card);
  color: var(--ink-2);
  border-color: var(--border);
}
.btn-action-secondary:not(:disabled):active {
  background: var(--bg-2);
}
/* Destructive pill — muted grey ("available, opt-out" register, not
   "alert / danger"). Routine user-initiated destructive actions
   (Sign Out, Disconnect, Delete) aren't catastrophic events; confirm()
   dialogs + post-action toasts handle the safety net. Single source
   of truth across the app — same tokens drive .btn-primary.btn-destructive
   below + the topbar / settings / forum / manual-row destructive
   variants. Light + dark theme parity via existing tokens. */
.btn-action-destructive {
  background: var(--bg-2);
  color: var(--ink-2);
  border-color: var(--border);
}
.btn-action-destructive:not(:disabled):hover {
  background: var(--border);
}
.btn-action-destructive:not(:disabled):active {
  background: var(--border-2);
}
/* Defensive narrow-viewport fallback — relax min-width + padding
   so 2-3 buttons stay on one row at 320px (oldest iPhone SE).
   Labels stay full-text since the longest ("Save changes",
   "Sign out") fits in <100px even with reduced padding. */
@media (max-width: 360px) {
  .btn-action { min-width: 64px; padding: 0 12px; }
  .sheet-action-bar { gap: 6px; }
}
/* Topbar sign-out — muted register matching the canonical destructive
   pill treatment across the app. Routine state-changing exit; the
   confirm() dialog (if any) + post-action toast carry the safety
   semantic, button color stays neutral. */
.topbar-btn-signout {
  color: var(--ink-2);
  border-color: var(--border);
}
.topbar-btn-signout:hover,
.topbar-btn-signout:active {
  background: var(--bg-2);
  border-color: var(--border-2);
  color: var(--ink);
}
.topbar-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* Top bar overflow protection (#138, narrowed Day 31). At 412px the
   brand block + FY selector + Customize button + bell run out of
   horizontal room when the practice name is long. .brand gets
   min-width: 0 + flex-shrink: 1 so it shrinks before the right-side
   actions; .brand-title gets text-overflow: ellipsis as a defensive
   second line of defense (truncatePracticeName() in app.js caps
   length at ~18 chars so the CSS ellipsis rarely fires in practice).
   Day 31 — dropped the "DentBooks" wordmark row entirely (brand presence
   anchored by the lime DB tile per Stripe / Linear pattern; practice name
   now occupies the brand-title slot directly). */
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex: 1 1 auto;
  overflow: hidden;
}
.logo {
  /* Lime tile + dark-forest "DB" wordmark — matches mobile/logo.svg +
     marketing nav .mkt-brand-logo. Brand convergence anchor — same
     DB block reads identically across marketing landing, auth pages,
     and PWA topbar. */
  width: 36px; height: 36px;
  background: var(--accent);
  color: #0e1d18;
  display: grid; place-items: center;
  border-radius: 10px;
  font-size: 14px; font-weight: 800;
  letter-spacing: -0.02em;
  flex-shrink: 0;
}
.brand-title {
  font-size: 16px; font-weight: 700; line-height: 1.1; letter-spacing: -0.015em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Narrow viewport (<=375px) — drop brand text a notch so the chrome
   row gives the FY selector + Customize button breathing room. */
@media (max-width: 375px) {
  .brand-title { font-size: 15px; }
  .topbar-row  { gap: 8px; }
}

/* VetBooks vertical (migration 118) — hide dental-specific surfaces.
   Practice Health tab is OD/PMS-driven; VetBooks v1 has no PMS
   integration so the tab has nothing to render. Body class is set
   from app.js load() once PRACTICE_INFO.vertical resolves to 'vet'. */
body.vetbooks-app .tab[data-tab="practice-health"] { display: none; }

/* VetBooks brand palette overrides — recolor PWA chrome to match the
   /vet marketing site (slate navy + sky blue). The .logo block stays
   structurally identical to dental; only the accent color flips. */
body.vetbooks-app {
  --accent: #4a9eff;
  --accent-on-light: #1f6fd6;
}
body.vetbooks-app .logo {
  background: var(--accent);
  color: #ffffff; /* white VB letters on sky-blue tile vs dark forest DB on lime */
}
.fy-select {
  background: var(--card);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  padding: 9px 14px;
  font-size: 13px; font-weight: 600;
  color: var(--ink);
  appearance: none; -webkit-appearance: none;
  padding-right: 30px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path fill='none' stroke='%2371717a' stroke-width='1.5' stroke-linecap='round' d='M2 4l4 4 4-4'/></svg>");
  background-repeat: no-repeat;
  background-position: right 11px center;
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.04);
}

/* ===== Main / cards ===== */
main { padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }

.card {
  background: var(--card);
  border-radius: 16px;
  padding: 16px;
  border: 1px solid var(--border);
  border-top: 2px solid var(--accent-on-light);
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.02);
}
.card-title {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px;
}
.card-title h3 {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-on-light);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.card-title a {
  font-size: 12px; font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}
/* Top Issues tile preview header (task #146) — count + Show all link
   sit together on the right of the card-title row. .card-meta is
   sized to match the sibling .card-title a link (12px / 600) so it
   doesn't dominate the H3 next to it. */
.card-meta-group {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.card-meta {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.insights-show-all {
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.greeting {
  font-size: 30px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.02em;
  line-height: 1.15;
  padding: 4px 2px 8px;
}
@media (min-width: 768px) {
  .greeting { font-size: 38px; }
}

/* ===== Hero ===== */
.hero {
  position: relative;
  border-radius: 18px;
  padding: 18px 20px 16px;
  background: var(--hero-bg);
  color: var(--hero-text);
  border: 1px solid var(--brand-2);
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute; right: -80px; top: -80px;
  width: 240px; height: 240px;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.14) 0%, transparent 60%);
  pointer-events: none;
}
.hero-header {
  position: relative;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
}
.hero-label {
  position: relative;
  font-size: 11px;
  color: var(--hero-caption);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
}
.hero-duo {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-top: 16px;
}
.hero-trio {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 12px;
  align-items: start;
}
.hero-trio-label {
  font-size: 10px;
  color: var(--hero-caption);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}
.hero-trio-value {
  font-size: clamp(20px, 5.6vw, 28px);
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--hero-text);
  line-height: 1.05;
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
}
.hero-trio-sub {
  font-size: 11px;
  color: var(--hero-caption);
  margin-top: 6px;
  font-weight: 500;
}
.hero-duo-label {
  font-size: 11px;
  color: var(--hero-caption);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.hero-duo-value {
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--hero-text);
  line-height: 1;
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
}
.hero-duo-sub {
  font-size: 12px;
  color: var(--hero-caption);
  margin-top: 6px;
  font-weight: 500;
}
.hero-margin {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.1);
}
.hero-margin-label {
  font-size: 11px;
  color: var(--hero-caption);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.hero-margin-value {
  font-size: 18px;
  font-weight: 700;
  color: #fca5a5;
  letter-spacing: -0.01em;
}

/* admin_items #67 W1 — Categorize-owner-draws banner. Sits below the
   hero trio when Dr. Takehome resolves to $0 on an owner-operator
   practice. Surface-only; the takehome-not-categorized info insight
   in Top Issues carries the persistent reminder. */
.hero-takehome-banner {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-top: 18px;
  padding: 14px 16px;
  min-height: 44px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 12px;
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  transition: background 120ms ease-out;
}
.hero-takehome-banner:hover  { background: rgba(255,255,255,0.12); }
.hero-takehome-banner:active { background: rgba(255,255,255,0.16); }
.hero-takehome-banner-title {
  flex: 1 1 auto;
  font-size: 13px;
  font-weight: 700;
  color: var(--hero-text);
  letter-spacing: -0.005em;
}
.hero-takehome-banner-arrow {
  flex: 0 0 auto;
  font-size: 16px;
  font-weight: 700;
  color: var(--hero-text);
  opacity: 0.7;
  line-height: 1;
}
.hero-margin-value.up {
  color: #86efac;
}
.hero-value {
  position: relative;
  font-size: 44px;
  font-weight: 700;
  letter-spacing: -0.03em;
  margin: 6px 0 8px;
  color: var(--hero-text);
  line-height: 1;
}
.hero-delta {
  position: relative;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px;
  color: #fca5a5;
  font-weight: 600;
  background: rgba(239, 68, 68, 0.16);
  padding: 5px 10px;
  border-radius: 6px;
}
.hero-delta.up { color: #86efac; background: rgba(34, 197, 94, 0.16); }

.hero-stats {
  position: relative;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  margin-top: 22px;
  background: rgba(255,255,255,0.08);
  border-radius: 12px;
  overflow: hidden;
}
.hero-stat {
  background: rgba(15, 23, 42, 0.6);
  padding: 14px 12px;
}
.hero-stat-label {
  font-size: 10px;
  color: var(--hero-caption);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.hero-stat-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--hero-text);
  margin-top: 4px;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.hero-stat-pct {
  font-size: 11px;
  color: #cbd5e1;
  margin-top: 2px;
  font-weight: 500;
}

/* ===== Section header ===== */
.section-title {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.03em;
  margin: 4px 4px 0;
  color: var(--ink);
}
.section-sub {
  font-size: 13px;
  color: var(--ink-3);
  margin: 2px 4px 6px;
  font-weight: 500;
}

/* ===== Category row ===== */
.cat-row {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.cat-row:last-child { border-bottom: 0; padding-bottom: 0; }
.cat-row:first-child { padding-top: 2px; }
.icon-box {
  width: 32px; height: 32px;
  background: var(--brand-soft);
  border-radius: 8px;
  display: grid; place-items: center;
  /* Ink-ladder pattern (same fix shape as #157 chart line) — was
     var(--brand-2), which on theme-dark resolves to #1e293b (very dark
     slate) and rendered as near-invisible against the slightly-lighter
     #2a2f3a chip bg. var(--ink) is theme-aware: near-white on dark,
     near-black on light, so icon stays high-contrast vs chip across
     all 10 themes. WCAG AA graphical-object 3:1 threshold passes
     comfortably (~12:1 on dark, ~14-17:1 on light/brand themes). */
  color: var(--ink);
  flex-shrink: 0;
}
.icon-box svg { width: 16px; height: 16px; stroke-width: 2; }
.cat-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.3;
  /* Long category names ("Doctor Pay & Distributions", "Software,
     Utilities & Subscriptions") would push the right column off-screen
     at 412px viewport without truncation. min-width:0 is required for
     a flex/grid child to shrink below its content size. Title attr on
     the row carries the full name for tap-and-hold reveal. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cat-meta {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 3px;
  font-weight: 500;
}
.cat-amount {
  font-size: 15px;
  font-weight: 700;
  text-align: right;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.cat-delta {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 5px;
}
/* Single-line amount + period-change chip on right edge. Baseline
   alignment so the chip sits at the dollar value's text baseline,
   not centered against its full height. */
.cat-amount-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  white-space: nowrap;
}
.delta-up   { background: var(--danger-soft); color: var(--danger); }
.delta-down { background: var(--success-soft); color: var(--success); }
.delta-flat { background: var(--bg-2); color: var(--ink-3); }

.spark-wrap { grid-column: 1 / -1; height: 38px; margin-top: 6px; }

/* ===== Bench bar ===== */
.bench {
  grid-column: 1 / -1;
  position: relative; height: 6px;
  background: var(--border);
  border-radius: 3px;
  margin-top: 8px;
}
.bench-band {
  position: absolute; top: 0; bottom: 0;
  background: var(--success-border);
  border-radius: 3px;
}
.bench-mark {
  position: absolute; top: -10px;
  min-width: 30px; height: 22px;
  border-radius: 11px;
  background: var(--brand);
  border: 2px solid var(--card);
  box-shadow: 0 1px 4px rgba(0,0,0,0.15);
  transform: translateX(-15px);
  color: var(--brand-fg);
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.04em;
  display: grid;
  place-items: center;
  line-height: 1;
}
/* admin_items #79 G2 (2026-06-01) — `.above` flipped from --danger to
   --warning. Edwin's decision table for Top Spend bubbles never asks
   for RED chrome; over-band reads as a soft warning (yellow), not an
   alarm. Visual direction (left vs right of band) still distinguished
   by the YOU marker position; the bubble color itself now signals
   simply "outside band, worth looking at." */
.bench-mark.above { background: var(--warning); }
.bench-mark.below { background: var(--warning); }
.bench-mark.ok    { background: var(--success); }
.bench-meta {
  grid-column: 1 / -1;
  font-size: 10px; color: var(--ink-4);
  margin-top: 6px;
  font-weight: 500;
  letter-spacing: 0.01em;
}

/* ===== Vendor row ===== */
.vendor-row {
  display: grid;
  grid-template-columns: 38px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.vendor-row:last-child { border-bottom: 0; }
/* Day 36 (#7, Hanna feedback) — grid children's min-width defaults to
   `auto` (= content min-content), which means a long ACH descriptor in
   `.vendor-name` ("Online Transfer To CHK ...5911 Transaction#: 2912570…")
   pushes the middle column past its 1fr share + invades the amount
   column on the right, blocking the dollar values. Forcing min-width:0
   on the middle column lets the existing ellipsis truncation in
   `.vendor-name` actually fire. Amount column stays `auto` (flex-shrink
   intent: never shrink — dollars stay readable). Full vendor name
   accessible via the row's title attribute (tap-and-hold on mobile,
   hover on desktop). */
.vendor-row > div:nth-child(2) { min-width: 0; }
.vendor-mono {
  width: 36px; height: 36px;
  background: var(--brand-soft);
  border-radius: 10px;
  display: grid; place-items: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--brand-2);
  letter-spacing: -0.01em;
}
.vendor-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  letter-spacing: -0.005em;
  /* Long vendor names (e.g., "The Christian School") cut mid-word
     pre-task-#127 with no indication. Single-line ellipsis with
     overflow:hidden truncates cleanly; full name accessible via
     the title attribute on the row. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vendor-cat {
  font-size: 11px;
  color: var(--ink-4);
  margin-top: 3px;
  font-weight: 500;
}
.vendor-amount {
  font-size: 14px;
  font-weight: 700;
  text-align: right;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.vendor-txns {
  font-size: 10px;
  color: var(--ink-4);
  margin-top: 3px;
  text-align: right;
  font-weight: 500;
}
.vendor-bar {
  grid-column: 1 / -1;
  height: 3px;
  background: var(--bg-2);
  border-radius: 999px;
  margin-top: 10px;
  overflow: hidden;
}
.vendor-bar-fill {
  height: 100%;
  background: var(--brand);
  border-radius: 999px;
}

/* ===== Insights (alerts renamed) ===== */
/* ===== Insight rows (post-refinement: filled severity icon, title
   inline with metadata, action folded into body — Edwin UI session) ===== */
.insight {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
.insight + .insight { margin-top: 8px; }
.insight-dot {
  width: var(--insight-icon-size, 20px);
  height: var(--insight-icon-size, 20px);
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  /* Optical-centering nudge: align mid-icon with cap-height of title. */
  margin-top: 1px;
}
.insight-dot.red    { background: var(--danger); }
.insight-dot.yellow { background: var(--warning); }
.insight-dot.green  { background: var(--success); }
.insight-dot svg {
  width: 12px;
  height: 12px;
  color: #fff;
}
.insight-content {
  flex: 1;
  min-width: 0;
}
.insight-row1 {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Title fills, metadata pinned right via flex-shrink: 0 on each */
}
.insight-title {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.35;
  /* Allow up to 2 lines before ellipsis instead of single-line nowrap.
     Most titles fit on one line; long ones (spend-trend "<X> spending
     up") wrap to 2. Ellipsis only kicks in if a title goes 3+ lines,
     which the post-shorten copy avoids. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Narrow-viewport: hide the metadata tag pill (~80px) so the title
   has full row width, and top-align the right-side metadata when the
   title wraps to 2 lines. Tag info is recoverable from the colored
   severity icon on these viewports — loss is acceptable. */
@media (max-width: 479px) {
  .insight-tag {
    display: none;
  }
  .insight-row1 {
    align-items: flex-start;
  }
}
.insight-tag {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 400;
  color: var(--ink-4);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  /* No background pill — tag reads as quiet metadata, not a CTA. */
}

/* #339 Phase 2 — AI-framed insights get a subtle sparkle glyph ahead of
   the title so the user can tell at a glance that the copy was rewritten
   by the framing layer vs the deterministic template. Mirrors the
   AI Layer 6 ✨ pattern on vendor categorization (CLAUDE.md v1.7-beta-
   Phase3 patterns "Render-time ✨ glyph"). Opacity 0.6 + accent-on-light
   color keeps it muted — it's a provenance marker, not a CTA. */
.insight.insight-ai .insight-title::before {
  content: "✨ ";
  opacity: 0.7;
  color: var(--accent-on-light);
  font-size: 12px;
  margin-right: 2px;
}
.insight-body {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
  margin-top: 4px;
}
.insight-body br + br { display: none; } /* defensive against doubled <br> */

/* ===== Tab bar ===== */
.tabbar {
  position: fixed; left: 12px; right: 12px;
  bottom: calc(var(--safe-bot) + 12px);
  display: grid; grid-template-columns: repeat(5, 1fr);  /* 5 tabs: Overview / Vendors / Activity / P&L / Settings (#156 dropped Trends — was 6) */
  background: var(--tabbar-bg);
  backdrop-filter: saturate(180%) blur(24px);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  border: 1px solid var(--border-2);
  border-radius: 18px;
  padding: 8px 2px;
  box-shadow:
    0 1px 2px rgba(24, 24, 27, 0.04),
    0 12px 32px -8px rgba(24, 24, 27, 0.16);
  z-index: 20;
}
.tab {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  color: var(--ink-4);
  padding: 8px 0;
  border-radius: 12px;
  transition: color 0.15s, background 0.15s;
}
.tab svg { width: 22px; height: 22px; stroke-width: 1.8; }
.tab label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.tab.active {
  color: var(--tab-active-fg);
  background: var(--tab-active-bg);
}
.tab.active svg { stroke-width: 2.2; }

.empty { padding: 40px 20px; text-align: center; color: var(--ink-4); font-size: 13px; }

.chart-wrap { position: relative; height: 200px; }

/* ===== Search input ===== */
.search-wrap {
  position: relative;
  margin-bottom: 12px;
}
.search-input {
  width: 100%;
  padding: 12px 14px 12px 38px;
  border: 1px solid var(--border-2);
  border-radius: 12px;
  background: var(--card);
  font-size: 14px;
  color: var(--ink);
  font-weight: 500;
  outline: none;
  -webkit-appearance: none;
  transition: border 0.15s, box-shadow 0.15s;
}
.search-input::placeholder { color: var(--ink-4); }
.search-input:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(15, 23, 42, 0.06);
}
.search-icon {
  position: absolute;
  left: 12px; top: 50%;
  transform: translateY(-50%);
  width: 18px; height: 18px;
  color: var(--ink-4);
  pointer-events: none;
}
.filter-pills {
  display: flex; gap: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
  margin-bottom: 12px;
  scrollbar-width: none;
}
.filter-pills::-webkit-scrollbar { display: none; }
.month-pills { margin-bottom: 0; }
.pill {
  flex-shrink: 0;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--card);
  border: 1px solid var(--border-2);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  white-space: nowrap;
}
.pill.active {
  background: var(--brand);
  color: var(--brand-fg);
  border-color: var(--brand);
}
.pills-stack { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.pills-stack .filter-pills { margin-bottom: 0; }
.filter-pills-leaves {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 8px;
  padding: 6px 4px;
}
.filter-pills-leaves .pill {
  font-size: 11px;
  padding: 6px 12px;
  background: var(--card);
}
.filter-pills-leaves .pill.active {
  background: var(--accent);
  color: white;
  border-color: var(--accent);
}
.sort-wrap { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.sort-label { font-size: 12px; font-weight: 600; color: var(--ink-4); }
.sort-select {
  flex: 1; padding: 10px 12px; border: 1px solid var(--border-2);
  border-radius: 12px; background: var(--card); color: var(--ink);
  font-size: 14px; font-weight: 500;
}

/* ===== Doctor split card ===== */
.doctor-row {
  display: grid;
  grid-template-columns: 32px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.doctor-row:last-child { border-bottom: 0; padding-bottom: 0; }
.doctor-row:first-child { padding-top: 2px; }
.doctor-avatar {
  width: 32px; height: 32px;
  background: var(--accent-soft);
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  color: var(--accent-on-light);
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.doctor-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.doctor-meta { font-size: 11px; color: var(--ink-3); margin-top: 3px; font-weight: 500; }
.doctor-amount { font-size: 14px; font-weight: 700; text-align: right; letter-spacing: -0.01em; }
.doctor-pct { font-size: 11px; color: var(--ink-3); margin-top: 3px; text-align: right; font-weight: 500; }

/* ===== YoY pp pill ===== */
.yoy-pill {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 10px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 4px;
  margin-left: 6px;
  background: var(--bg-2);
  color: var(--ink-3);
}
.yoy-pill.up   { background: var(--danger-soft); color: var(--danger); }
.yoy-pill.down { background: var(--success-soft); color: var(--success); }

/* ===== Transactions =====
   Mobile (< 768px): card layout. .txn-row is a 2-row × 2-col grid via
   grid-template-areas; the four flat children (date, vendor, meta,
   amount) place into named areas. Date is hidden, amount spans both
   rows on the right.

   Desktop (>= 768px): switches to a 4-col tabular layout via the
   @media block below — Date | Vendor | Meta | Amount on a single row.
   Day-group headers hide at desktop (per-row date column carries the
   date instead). DOM is unchanged across viewports. */
.txn-row {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "vendor amount"
    "meta   amount";
  column-gap: 12px;
  align-items: start;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.txn-row:last-child { border-bottom: 0; }
.txn-date {
  /* Mobile: hidden. Date lives in the .txn-day-header above each
     day group. Desktop @media block flips this on. */
  display: none;
}
.txn-vendor {
  grid-area: vendor;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.3;
}
.txn-meta {
  grid-area: meta;
  font-size: 11px;
  color: var(--ink-4);
  margin-top: 3px;
  font-weight: 500;
}
/* Uncategorized hint — task #65 vendor-map auto-categorization. Shown
   when t.c is empty (Plaid sync row whose vendor didn't match any
   vendor_map rule). Italic + warning color signals "this needs your
   attention" without screaming. */
.txn-cat-empty {
  font-style: italic;
  color: var(--warning);
  font-weight: 600;
}
/* AI-categorized hint — task #67 Block F. Subtle ✨ next to category
   when the effective vendor_map rule is source='ai_categorized'. 0.7
   opacity, no animation, no color shift — hint only, not a separate
   UX path. Click-to-correct goes through the existing reclass flow.
   Drops automatically across all rows of a vendor when the user uses
   "Apply to all N and remember" (which flips the rule's source to
   user_correction). */
.txn-ai-hint {
  opacity: 0.7;
  cursor: help;
}
/* Source/account prefix in .txn-meta (task #65). Subtle uppercase
   eyebrow so the user can tell at a glance whether a row came from
   Citi vs Chase vs Manual. Lighter than .txn-cat to defer to the
   primary content. */
/* Source chip in .txn-meta (task #75). Subtle pill — light bg, small
   font, rounded — visually separates "where it came from" from the
   category breadcrumb that follows. The chip's right margin replaces
   the old "·" separator so source no longer reads as the first step
   in a hierarchy. Mask suffix ("Citibank Online •••4502") surfaces
   per-account when the row's t.aid resolves a specific account. */
.txn-source {
  display: inline-block;
  padding: 1px 7px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  vertical-align: middle;
  margin-right: 6px;
  line-height: 1.5;
  white-space: nowrap;
}
.txn-amount {
  grid-area: amount;
  font-size: 14px;
  font-weight: 700;
  text-align: right;
  letter-spacing: -0.01em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.txn-amount.income { color: var(--success); }
.txn-amount.transfer { color: var(--ink-3); font-weight: 500; }
/* Refund affordance (#125) — contra-expense rows render the leading
   '+' which on its own reads as "added to spend total." Layered cue:
   green-success amount tint + '(refund)' tag inline in meta. */
.txn-amount.refund { color: var(--success); }
.txn-refund-tag {
  font-size: 11px;
  font-style: italic;
  color: var(--ink-3);
  margin-left: 6px;
  white-space: nowrap;
}
/* #69 Phase 1 — split-parent affordance. A split row renders without
   strikethrough (the row's amount IS in totals via children) and gains
   a "Split into N categories" pill in the meta line. Tap → drill shows
   the child list + Edit/Unsplit. The pill uses the accent tint to
   signal "not a passive state" (vs the .txn-excluded grey strikethrough
   for personal/non-business rows). */
.txn-split-tag {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent-on-light);
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border));
  border-radius: 999px;
  padding: 2px 8px;
  margin-left: 6px;
  white-space: nowrap;
}
.txn-row--split-parent .txn-amount {
  color: var(--ink);
}

/* Drill split-detail — surfaces children under a split parent with
   Edit / Unsplit actions. Sits in place of the reclassify section. */
.split-detail-section {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px 18px;
}
.split-detail-section h3 {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}
.split-detail-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  padding: 4px 0;
}
.split-detail-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.split-detail-row:last-child { border-bottom: none; }
.split-detail-label {
  font-size: 13px;
  color: var(--ink);
  font-weight: 500;
}
.split-detail-amount {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.split-detail-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-top: 4px;
}
.split-detail-actions button {
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--ink-2);
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.split-detail-actions button:hover,
.split-detail-actions button:focus-visible {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.split-detail-actions .btn-split-unsplit {
  background: var(--bg-2);
  color: var(--ink-2);
  border-color: var(--border);
}
.split-detail-actions .btn-split-unsplit:hover,
.split-detail-actions .btn-split-unsplit:focus-visible {
  background: var(--border);
  color: var(--ink);
  border-color: var(--border-2);
}
.split-detail-actions .btn-split-unsplit:active {
  background: var(--border-2);
}
.split-detail-error {
  font-size: 12px;
  color: var(--danger);
  margin-top: 4px;
}

/* Split form — multi-row composer. Each row has amount + category
   + subcategory + remove. Live total shows match/mismatch state via
   the .match / .mismatch class on .split-form-totals. */
.split-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px 18px;
}
.split-form h2 {
  margin: 0 0 4px;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.split-form .sheet-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin: 0 0 6px;
}
.split-form-rows {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.split-form-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) minmax(0, 2fr) auto;
  gap: 6px;
  align-items: center;
}
.split-form-row input,
.split-form-row select {
  padding: 8px 10px;
  font-size: 13px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-family: inherit;
  min-width: 0;
}
.split-form-row .split-form-amount {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.split-form-row input:focus-visible,
.split-form-row select:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent);
  outline-offset: 1px;
  border-color: var(--accent);
}
/* admin_items #77 (2026-06-01) — Doctor-group split rows REQUIRE a
   subcategory naming the doctor. Red border surfaces the required-
   empty state visually while the user types; clears as soon as the
   field has content. Pairs with the placeholder swap "Doctor name
   (required)" applied via refreshSubcategoryUi in openSplitForm.
   Focus-visible style above still wins on focus (specificity); the
   required-empty hint is the resting state when the row needs a
   name. */
.split-form-row .split-form-subcategory.split-form-subcategory-required-empty {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 6%, var(--card));
}
.split-form-row .split-form-subcategory.split-form-subcategory-required-empty::placeholder {
  color: var(--danger);
  opacity: 0.85;
}
/* The subcategory mount holds either the free-text input above OR a
   DoctorPicker select (admin_items #78). Give the mount min-width: 0
   so it shrinks within the split-form-row grid track. */
.split-form-row .split-form-subcategory-mount {
  min-width: 0;
  display: block;
}
.split-form-row .split-form-subcategory-mount > select,
.split-form-row .split-form-subcategory-mount > input {
  width: 100%;
}

/* admin_items #78 (2026-06-01) — Doctor picker inline-add form.
   Renders inside the same mount slot as the dropdown; swaps into view
   when user picks "+ Add new doctor" + back out on Cancel / Save. */
.doctor-picker-add-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.doctor-picker-add-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.doctor-picker-add-name {
  padding: 8px 10px;
  font-size: 13px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-family: inherit;
}
.doctor-picker-add-name:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.doctor-picker-add-roles {
  display: flex;
  gap: 12px;
}
.doctor-picker-add-role {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.doctor-picker-add-role input[type="radio"] {
  margin: 0;
}
.doctor-picker-add-fuzzy {
  font-size: 12px;
  padding: 8px 10px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--warning) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}
.doctor-picker-fuzzy-text { flex: 1 1 auto; min-width: 0; }
.doctor-picker-fuzzy-use {
  padding: 4px 10px;
  font-size: 12px;
  border-radius: 6px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #0e1d18;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.doctor-picker-fuzzy-use:hover,
.doctor-picker-fuzzy-use:focus-visible { opacity: 0.92; }
.doctor-picker-add-error {
  font-size: 12px;
  color: var(--danger);
  padding: 2px 0;
}
.doctor-picker-add-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
.doctor-picker-add-cancel,
.doctor-picker-add-save {
  padding: 8px 14px;
  font-size: 13px;
  border-radius: 8px;
  font-family: inherit;
  cursor: pointer;
  font-weight: 600;
}
.doctor-picker-add-cancel {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--ink-2);
}
.doctor-picker-add-save {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #0e1d18;
}
.doctor-picker-add-save:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.doctor-picker-add-cancel:hover,
.doctor-picker-add-cancel:focus-visible { background: var(--bg-3); }
.doctor-picker-add-save:not(:disabled):hover,
.doctor-picker-add-save:not(:disabled):focus-visible { opacity: 0.92; }
.split-form-row-remove {
  background: transparent;
  border: none;
  font-size: 18px;
  color: var(--ink-3);
  padding: 0 6px;
  cursor: pointer;
  min-width: 24px;
  min-height: 24px;
  border-radius: 4px;
}
.split-form-row-remove:hover,
.split-form-row-remove:focus-visible {
  background: var(--bg-2);
  color: var(--danger);
}
.split-form-add {
  align-self: flex-start;
  background: var(--bg-2);
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.split-form-add:hover,
.split-form-add:focus-visible {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.split-form-add:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.split-form-totals {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  font-weight: 600;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.split-form-totals.match {
  background: color-mix(in srgb, var(--success) 12%, var(--card));
  border-color: color-mix(in srgb, var(--success) 30%, var(--border));
  color: var(--success);
}
.split-form-totals.mismatch {
  background: color-mix(in srgb, var(--warning) 10%, var(--card));
  border-color: color-mix(in srgb, var(--warning) 30%, var(--border));
  color: var(--warning);
}
.split-form-totals-label {
  font-weight: 700;
  margin-right: auto;
}
.split-form-totals-target {
  color: var(--ink-3);
  font-weight: 500;
}
.split-form-error {
  font-size: 12px;
  color: var(--danger);
  margin-top: 4px;
}

/* #69 Phase 2 — save-as-rule prompt chrome. Reuses sheet/action-bar
   surface; .rule-type-row is a 2-column radio pair, .rule-range-row
   stacks a label above two narrow numeric inputs. */
.rule-type-row {
  display: flex;
  gap: 8px;
  padding: 8px 0;
}
.rule-type-opt {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  background: var(--card);
  transition: background 0.12s, border-color 0.12s;
}
.rule-type-opt:has(input:checked) {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.rule-type-opt input[type="radio"] {
  margin: 0;
  accent-color: var(--accent);
}
.rule-range-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 4px 0 8px;
}
.rule-range-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.rule-range-inputs {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-3);
}
.rule-range-inputs input {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  font-size: 13px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  font-family: inherit;
}
.rule-range-inputs input:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent);
  outline-offset: 1px;
  border-color: var(--accent);
}
.rule-error {
  font-size: 12px;
  color: var(--danger);
  margin-top: 4px;
}

.txn-day-header {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 14px 0 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
}

@media (min-width: 768px) {
  /* Tabular row layout. Date | Vendor | Meta | Amount on one row.
     Day-headers hide; .txn-date column carries the per-row date.
     Visual density mirrors P&L tab tables (13px text, 10px padding,
     hover bg). Theme vars carry light/dark automatically. */
  .txn-row {
    grid-template-columns: 7rem minmax(0, 2fr) minmax(0, 2fr) 6rem;
    grid-template-areas: "date vendor meta amount";
    column-gap: 1rem;
    padding: 0.625rem 0.75rem;
    align-items: center;
    border-radius: 6px;
  }
  .txn-row:hover { background: var(--bg-2); }
  .txn-date {
    display: block;
    font-size: 12px;
    color: var(--ink-3);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  .txn-vendor {
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .txn-meta {
    margin-top: 0;
    font-size: 12px;
    color: var(--ink-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .txn-sub-sep, .txn-sub { color: var(--ink-4); }
  /* Hide the duplicate subcategory in the meta column when the row's
     vendor and subcategory are the same string (set by template at
     render time as .txn-row--dup-sub). The collision happens for
     fy_block-fallback rows where Who You Paid was null and vendor
     became Subcategory. Mobile is unaffected. */
  .txn-row--dup-sub .txn-sub-sep,
  .txn-row--dup-sub .txn-sub { display: none; }
  .txn-amount {
    font-size: 13px;
  }
  .txn-day-header {
    /* Per-row .txn-date column carries the date in tabular view. */
    display: none;
  }
}

.summary-bar {
  display: flex;
  justify-content: space-between;
  padding: 12px 0;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  color: var(--ink-3);
  font-weight: 500;
}
.summary-bar b {
  display: block;
  font-size: 16px;
  color: var(--ink);
  font-weight: 700;
  margin-top: 4px;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.period-summary {
  font-size: 12px;
  color: var(--ink-3);
  padding: 10px 4px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}
.period-summary b {
  color: var(--ink);
  font-weight: 700;
}

/* ===== Bottom Sheet ===== */
.sheet-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  z-index: 50;
  backdrop-filter: blur(2px);
}
.sheet-backdrop.open {
  opacity: 1;
  pointer-events: auto;
}
.sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  background: var(--card);
  border-radius: 24px 24px 0 0;
  max-height: 85vh;
  overflow-y: auto;
  transform: translateY(100%);
  transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
  z-index: 60;
  padding: 8px 18px calc(28px + var(--safe-bot));
  box-shadow: 0 -8px 40px -8px rgba(15, 23, 42, 0.2);
}
.sheet.open {
  transform: translateY(0);
}
.sheet-handle {
  width: 38px; height: 4px;
  background: var(--ink-5);
  border-radius: 999px;
  margin: 8px auto 14px;
}
/* Day 36 (#1, Hanna feedback) — sticky X close button on every sheet.
   Sits at top-right, stays visible while the sheet body scrolls.
   Required because long sheets (COA editor) can occupy the full viewport
   when scrolled, leaving no backdrop region available for tap-to-dismiss
   without first scrolling back to the top. ≥44×44 touch target via the
   padded box. position:sticky with top:0 + z-index above sheet content
   so it floats over scrolling rows without overlapping the action bar. */
.sheet-close-x {
  position: sticky;
  top: 8px;
  float: right;
  z-index: 5;
  width: 32px; height: 32px;
  border: none;
  background: var(--bg-2);
  color: var(--ink-2);
  border-radius: 50%;
  font-size: 22px;
  font-family: inherit;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 4px 0 0 8px;
  transition: background 0.15s ease, color 0.15s ease;
}
.sheet-close-x:hover { background: var(--border); color: var(--ink); }
.sheet-close-x:active { background: var(--border-2); }

/* =============================================================================
   Custom Dropdown component (Bug #1, Day 36 — fixes native <select>
   viewport-clipping in bottom sheets). See createDropdown() in app.js.
   ============================================================================= */
.dd-wrap {
  position: relative;
  width: 100%;
}
.dd-hidden-select {
  /* Off-screen but in DOM — preserves the `#rc-category` id selector
     contract + form-submission semantics. Visually hidden via clip-path
     so the native dropdown never opens on focus. */
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
  clip-path: inset(50%);
  clip: rect(0 0 0 0);
  overflow: hidden;
}
.dd-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink);
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  transition: border-color 0.12s ease, background 0.12s ease;
}
.dd-trigger:hover {
  border-color: var(--ink-5);
  background: var(--bg-2);
}
.dd-trigger:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.dd-trigger[aria-expanded="true"] {
  border-color: var(--accent);
}
.dd-trigger-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dd-trigger-caret {
  margin-left: 8px;
  color: var(--ink-3);
  font-size: 12px;
  transition: transform 0.15s ease;
}
.dd-trigger[aria-expanded="true"] .dd-trigger-caret {
  transform: rotate(180deg);
}

/* Popover portal — covers viewport. Z-index above .sheet (60) so the
   dropdown opens ON TOP of the sheet that triggered it. */
.dd-portal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  pointer-events: none;
}
.dd-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.4);
  opacity: 0;
  pointer-events: auto;
  transition: opacity 0.2s ease;
}
.dd-portal-open .dd-backdrop { opacity: 1; }
.dd-popover {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  background: var(--card);
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -8px 40px -8px rgba(15, 23, 42, 0.2);
  max-height: 75vh;
  display: flex;
  flex-direction: column;
  transform: translateY(100%);
  transition: transform 0.25s cubic-bezier(0.32, 0.72, 0, 1);
  pointer-events: auto;
  padding: 6px 0 calc(20px + var(--safe-bot));
}
.dd-portal-open .dd-popover {
  transform: translateY(0);
}
.dd-popover-handle {
  width: 38px; height: 4px;
  background: var(--ink-5);
  border-radius: 999px;
  margin: 8px auto 12px;
  flex-shrink: 0;
}
.dd-popover-list {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 8px 8px;
}
.dd-group-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light, var(--accent));
  padding: 14px 14px 6px;
}
.dd-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: none;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  border-radius: 8px;
  transition: background 0.1s ease;
}
.dd-option:hover { background: var(--bg-2); }
.dd-option-focus { background: var(--bg-2); }
.dd-option-selected {
  background: color-mix(in srgb, var(--accent) 12%, var(--card));
  color: var(--ink);
  font-weight: 600;
}
.dd-option-selected:hover {
  background: color-mix(in srgb, var(--accent) 18%, var(--card));
}
.dd-option-check {
  color: var(--accent-on-light, var(--accent));
  font-weight: 700;
  margin-left: 12px;
  flex-shrink: 0;
}
.dd-option-text {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Desktop tablet — floating popover anchored to trigger instead of
   full-width bottom sheet. min-width: 768px matches the existing
   responsive breakpoints. The portal stays fullscreen, but the popover
   becomes a floating box near the trigger via JS positioning would be
   ideal — for v1, keep the bottom-sheet pattern even on desktop since
   the product is mobile-first. Single CSS adjustment for desktop:
   max-width caps the popover so it doesn't span the entire viewport. */
@media (min-width: 768px) {
  .dd-popover {
    left: 50%;
    right: auto;
    transform: translate(-50%, 100%);
    width: 100%;
    max-width: 480px;
    border-radius: 16px;
    bottom: 32px;
  }
  .dd-portal-open .dd-popover {
    transform: translate(-50%, 0);
  }
}
.sheet h2 {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0 0 4px;
  color: var(--ink);
}
.sheet .sheet-sub {
  font-size: 13px;
  color: var(--ink-3);
  margin-bottom: 18px;
  font-weight: 500;
}
.sheet h3 {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 18px 0 10px;
}

/* ===== Flag group headers ===== */
.flag-header {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.005em;
  padding: 10px 4px 6px;
  margin-top: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.flag-header::before {
  content: "";
  width: 10px; height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.flag-header.red { color: var(--danger); }
.flag-header.red::before { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); }
.flag-header.yellow { color: var(--warning); }
.flag-header.yellow::before { background: var(--warning); box-shadow: 0 0 0 3px var(--warning-soft); }
.flag-header.green { color: var(--success); }
.flag-header.green::before { background: var(--success); box-shadow: 0 0 0 3px var(--success-soft); }

/* ===== Tab fade transition ===== */
main {
  animation: fadeIn 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ===== Skeleton ===== */
.skeleton {
  background: linear-gradient(90deg, var(--bg-2) 0%, #fafaf9 50%, var(--bg-2) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
  border-radius: 8px;
}
@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ===== Tap state ===== */
.tappable { cursor: pointer; transition: background 0.12s; }
.tappable:active { background: var(--bg-2); }

/* ===== Theme picker ===== */
.theme-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  margin-top: 8px;
}
.theme-swatch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 10px 6px;
  border-radius: 14px;
  border: 1px solid transparent;
  background: transparent;
}
.theme-swatch:active { background: var(--bg-2); }
.theme-swatch.active {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.theme-swatch-color {
  width: 56px; height: 56px;
  border-radius: 50%;
  border: 1px solid var(--border-2);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 1px 2px rgba(0,0,0,0.08);
  position: relative;
}
.theme-swatch.active .theme-swatch-color::after {
  content: "";
  position: absolute;
  right: -2px; bottom: -2px;
  width: 20px; height: 20px;
  background: var(--accent);
  border: 2px solid var(--card);
  border-radius: 50%;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='white' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-6'/></svg>");
  background-size: 14px 14px;
  background-position: center;
  background-repeat: no-repeat;
}
.theme-swatch-name {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  text-align: center;
}

/* ===== Inline edit mode (Overview tile customization) ===== */
.overview-tiles {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.tile-edit-shell {
  position: relative;
  border: 2px dashed var(--accent);
  border-radius: 18px;
  padding: 36px 6px 6px;
  background: transparent;
}
.tile-edit-shell > .card,
.tile-edit-shell > section.card {
  border-top-width: 1px; /* suppress accent top border inside shell to avoid double edge */
  border-color: var(--border);
}
.tile-edit-handle {
  position: absolute;
  top: 6px; left: 8px;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  color: var(--ink-3);
  cursor: grab;
  flex-shrink: 0;
  touch-action: none;
  background: transparent;
  z-index: 2;
}
.tile-edit-handle:active { cursor: grabbing; }
.tile-edit-handle svg { width: 18px; height: 18px; }
/* Bump specificity so .toggle-switch's position: relative doesn't override */
.tile-edit-shell > .tile-edit-toggle {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
}
.tile-ghost {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 56px 12px 44px;
  min-height: 50px;
  background: var(--bg-2);
}
.tile-ghost-label {
  flex: 1;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-3);
}
.tile-ghost .tile-edit-handle { top: 50%; transform: translateY(-50%); }
.tile-edit-shell.tile-ghost > .tile-edit-toggle { top: 50%; transform: translateY(-50%); }
.tile-edit-ghost-drag { opacity: 0.4; }

/* Done button replaces gear in edit mode */
#done-btn { display: none; }
.topbar-done {
  height: 36px;
  padding: 0 14px;
  display: inline-flex;
  align-items: center;
  background: transparent;
  color: var(--accent-on-light);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
  border-radius: 10px;
}
.topbar-done:active { background: var(--bg-2); }
body.is-editable-tiles.edit-mode #settings-btn { display: none; }
body.is-editable-tiles.edit-mode #done-btn { display: inline-flex; }

/* Reusable small section label (used by drill breakdowns, etc.) */
.section-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 18px 4px 8px;
}

/* ===== P&L tab ===== */
.pnl-header {
  padding: 4px 4px 14px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
}
.pnl-title {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0;
}
.pnl-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 4px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.pnl-table {
  display: flex;
  flex-direction: column;
}
.pnl-group-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 12px 14px;
  margin-top: 14px;
  margin-bottom: 2px;
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border-radius: 8px;
  border: none;
  text-align: left;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--ink);
  text-transform: uppercase;
  cursor: pointer;
}
.pnl-group-row:first-child { margin-top: 0; }
.pnl-group-row:active { background: color-mix(in srgb, var(--accent) 16%, var(--card)); }
.pnl-group-name { flex: 1; }
.pnl-line {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 10px 14px 10px 28px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  text-align: left;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.pnl-line .pnl-line-name { flex: 1; }
.pnl-line:last-of-type { border-bottom: 0; }
.pnl-line:active { background: var(--bg-2); }
.pnl-line-name {
  flex: 1;
  font-weight: 500;
  color: var(--ink-2);
}
/* Synthetic Uncategorized sub-line on P&L sections (task #76). Italic
   + warning color, matches Activity tab's .txn-cat-empty treatment so
   the user pattern-matches the cue. Drillable to the section's
   excludeCategoryList filter. */
.pnl-line-uncategorized .pnl-line-name {
  font-style: italic;
  color: var(--warning);
  font-weight: 600;
}
.pnl-line-uncategorized .pnl-value {
  color: var(--warning);
}
/* Synth diff row (#142) — visually distinct from canonical
   Uncategorized category rows so the two never read as duplicates.
   Muted ink + italic + lighter weight signals "estimated / synthesized"
   rather than warning-color. The canonical Uncategorized class above
   keeps its warning treatment because explicit-Uncategorized rows
   genuinely warrant attention; the diff row is a math artifact. */
.pnl-line-synth-uncategorized .pnl-line-name {
  font-style: italic;
  color: var(--ink-3);
  font-weight: 500;
}
.pnl-line-synth-uncategorized .pnl-value {
  color: var(--ink-3);
  font-weight: 600;
}
.pnl-value {
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  text-align: right;
}
.pnl-value.negative {
  color: var(--danger);
}
.pnl-computed-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 14px;
  margin-top: 10px;
  background: color-mix(in srgb, var(--accent) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border));
  border-radius: 10px;
  text-align: left;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink);
  text-transform: uppercase;
  cursor: pointer;
}
.pnl-computed-row:active { background: color-mix(in srgb, var(--accent) 18%, var(--card)); }

/* Take-home row — prominent (owner-operator headline number, task #55).
   Brighter background + subtle ring so it visually wins vs. the ordinary
   computed rows. Sits between Doctor Pay and Net Income. */
.pnl-takehome-row {
  background: color-mix(in srgb, var(--accent) 22%, var(--card));
  border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
  box-shadow: 0 1px 0 color-mix(in srgb, var(--accent) 30%, transparent);
}
.pnl-takehome-row:active { background: color-mix(in srgb, var(--accent) 32%, var(--card)); }
.pnl-takehome-row .pnl-icon {
  background: var(--accent);
  color: var(--hero-text, white);
}

/* De-emphasized row — used for "Retained in Practice" when take-home is
   the headline (owner-operator). Lighter ink, no fill, no border ring. */
.pnl-deemphasized {
  background: transparent;
  border: 1px dashed var(--border);
  color: var(--ink-3);
  font-weight: 600;
}
.pnl-deemphasized .pnl-value { color: var(--ink-2); font-weight: 600; }
.pnl-deemphasized .pnl-icon {
  background: var(--bg-2);
  color: var(--ink-3);
}
/* Soft inline qualifier ("(retained)") on the Net Income row when
   take-home is the headline. Lowercase, lighter ink, no letter-spacing. */
.pnl-soft {
  text-transform: none;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--ink-3);
  font-size: 12px;
  margin-left: 6px;
}

/* Breakdown drill — short note row under the math card. Used by the
   take-home breakdown to explain the W-2 + Distribution + Retained split. */
.breakdown-note {
  font-size: 12px;
  color: var(--ink-2);
  padding: 10px 14px;
  margin: 6px 0 12px;
  background: var(--bg-2);
  border-radius: 8px;
  line-height: 1.5;
}
.breakdown-note b { color: var(--ink); font-weight: 700; }
.pnl-computed-name { flex: 1; display: flex; align-items: center; gap: 8px; }
.pnl-icon {
  display: inline-grid;
  place-items: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 18%, var(--card));
  color: var(--accent-on-light);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0;
}
.pnl-pct-line {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px 4px 50px;
  font-size: 11px;
  font-style: italic;
  font-weight: 500;
  color: var(--ink-3);
  margin-bottom: 4px;
}
.pnl-pct-line > span:first-child { flex: 1; }
.pnl-pct-line b {
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  font-style: normal;
}
.pnl-pct-line b.negative { color: var(--danger); }
.pnl-arrow {
  display: inline-block;
  width: 14px;
  text-align: center;
  font-size: 10px;
  line-height: 1;
  flex-shrink: 0;
  font-style: normal;
  color: transparent; /* empty placeholder still occupies the column */
}
.pnl-arrow.trend-good { color: var(--success); }
.pnl-arrow.trend-bad  { color: var(--danger);  }

/* iOS-style toggle switch */
.toggle-switch {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 26px;
  flex-shrink: 0;
}
.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.toggle-slider {
  position: absolute;
  inset: 0;
  background: var(--ink-5);
  border-radius: 26px;
  transition: background 0.2s;
}
.toggle-slider::before {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 22px;
  height: 22px;
  background: var(--card);
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
  transition: transform 0.2s;
}
.toggle-switch input:checked + .toggle-slider {
  background: var(--accent);
}
.toggle-switch input:checked + .toggle-slider::before {
  transform: translateX(18px);
}

.btn-primary {
  /* Day 26 green convergence — lime bg + forest text matches the topbar
     .logo tile (line ~745) byte-identically. Brand anchor: CTAs across
     marketing site (.mkt-btn-primary), auth pages (.auth-form button),
     dashboard sheets, and topbar logo all carry the same lime+forest
     identity. Pre-fix the button used var(--brand) (forest #0e1d18) on
     var(--brand-fg) cream — Edwin read it as "dark navy" on the cream
     auth surfaces. Lime + forest hits ~9.8:1 contrast (AAA) and matches
     the lime DB logo block users see on every other surface. */
  width: 100%;
  margin-top: 18px;
  padding: 14px 18px;
  background: var(--accent);
  color: var(--brand);
  border-radius: 12px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.btn-primary:active { background: var(--accent-2); }

.empty-tiles {
  text-align: center;
  padding: 32px 20px;
}
.empty-tiles-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 6px;
}
.empty-tiles-sub {
  font-size: 13px;
  color: var(--ink-3);
  margin-bottom: 16px;
}
.empty-tiles .btn-primary { margin-top: 0; }

/* ===== Drill-down sheet ===== */
.drill-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 0 12px;
  margin-bottom: 4px;
}
.drill-back, .drill-close {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  color: var(--ink-2);
  border-radius: 8px;
  flex-shrink: 0;
}
.drill-back:active, .drill-close:active { background: var(--bg-2); }
.drill-back svg, .drill-close svg { width: 20px; height: 20px; }
.drill-back-spacer { width: 32px; height: 32px; flex-shrink: 0; }
.sheet h2.drill-title {
  flex: 1;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink);
  text-align: center;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.drill-subtitle {
  font-size: 13px;
  color: var(--ink-3);
  text-align: center;
  margin: -4px 0 16px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.drill-body {
  display: flex;
  flex-direction: column;
}
.drill-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 4px;
  border-bottom: 1px solid var(--border);
  gap: 12px;
}
.drill-row:last-child { border-bottom: 0; }
.drill-row-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.drill-row-meta { font-size: 11px; color: var(--ink-3); margin-top: 3px; font-weight: 500; }
.drill-row-amount {
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.drill-split {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 12px;
}
.drill-split-row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 14px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  background: var(--card);
}
.drill-split-row:last-child { border-bottom: 0; }
.drill-split-row:active { background: var(--bg-2); }
.drill-split-label { font-size: 14px; font-weight: 700; color: var(--ink); }
.drill-split-meta { font-size: 11px; color: var(--ink-3); margin-top: 3px; font-weight: 500; }
.drill-split-amount {
  font-size: 18px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.drill-all-link {
  width: 100%;
  text-align: center;
  padding: 14px;
  margin-top: 10px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 10px;
}
.drill-all-link:active { opacity: 0.7; }
.drill-view-all { margin-top: 14px; }

/* Hero box clickable */
.hero-trio-col {
  text-align: left;
  background: transparent;
  color: inherit;
  padding: 6px;
  margin: -6px;
  border-radius: 10px;
  transition: background 0.12s;
}
.hero-trio-col:active { background: rgba(255, 255, 255, 0.08); }

/* Transaction row tap-to-expand (within drill sheet) */
.drill-txn-row {
  cursor: pointer;
}
.drill-txn-row .txn-detail {
  grid-column: 1 / -1;
  display: none;
  padding: 10px 0 4px;
  margin-top: 8px;
  border-top: 1px dashed var(--border);
  font-size: 12px;
  color: var(--ink-3);
}
.drill-txn-row.open .txn-detail { display: block; }
.drill-txn-row .txn-detail > div {
  display: flex;
  justify-content: space-between;
  padding: 3px 0;
}
.drill-txn-row .txn-detail span { color: var(--ink-4); }
.drill-txn-row .txn-detail b {
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Activity filter chip (when arriving from drill-down) */
.filter-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 6px 6px 6px 14px;
  margin-bottom: 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--accent);
}
.filter-chip-label {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 10px;
}
.filter-chip-value {
  flex: 1;
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.filter-chip-clear {
  width: 24px; height: 24px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--card);
  color: var(--ink-3);
  flex-shrink: 0;
}
.filter-chip-clear svg { width: 14px; height: 14px; }
.filter-chip-clear:active { background: var(--bg-2); }

/* ===== Transaction detail (terminal drill level) ===== */
.txn-detail-card {
  text-align: center;
  padding: 24px 16px 18px;
  background: var(--bg-2);
  border-radius: 14px;
  margin-bottom: 14px;
}
.txn-detail-amount {
  font-size: 36px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.txn-detail-amount.income { color: var(--success); }
.txn-detail-amount.transfer { color: var(--ink-3); }
.txn-detail-date {
  margin-top: 8px;
  font-size: 13px;
  color: var(--ink-3);
  font-weight: 500;
}
.txn-detail-grid {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.txn-detail-grid > div {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.txn-detail-grid > div:last-child { border-bottom: 0; }
.txn-detail-grid span {
  color: var(--ink-3);
  font-weight: 500;
}
.txn-detail-grid b {
  color: var(--ink);
  font-weight: 600;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ===== Breakdown (computed-insight drill level) ===== */
.breakdown-headline {
  text-align: center;
  padding: 24px 16px 18px;
  background: var(--bg-2);
  border-radius: 14px;
  margin-bottom: 14px;
}
.breakdown-headline-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.breakdown-headline-value {
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  margin: 6px 0 4px;
}
.breakdown-headline-value.good { color: var(--success); }
.breakdown-headline-value.bad { color: var(--danger); }
.breakdown-headline-meta {
  font-size: 12px;
  color: var(--ink-3);
  font-weight: 500;
}
.breakdown-math {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 6px;
}
.breakdown-math-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--ink-2);
}
.breakdown-math-row:last-child { border-bottom: 0; }
.breakdown-math-row b {
  color: var(--ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.breakdown-math-result {
  background: var(--brand-soft);
}
.breakdown-math-result b { color: var(--brand-2); }

/* ===== Insight tappable state ===== */
.insight.tappable {
  cursor: pointer;
  position: relative;
}
.insight.tappable:active { background: var(--bg-2); }
.insight-chevron {
  /* Sits to the right of the inline controls in the .insight-row1 flex
     container. Always visible at low opacity so the affordance is never
     phantom; brightens on row hover (desktop). */
  color: var(--ink-4);
  display: inline-flex;
  flex-shrink: 0;
  opacity: 0.4;
  transition: opacity 0.15s;
}
.insight-chevron svg { width: 14px; height: 14px; }
@media (hover: hover) {
  .insight:hover .insight-chevron { opacity: 1; }
}
@media (hover: none) {
  .insight-chevron { opacity: 0.6; }
}

/* ===== 2-level cost taxonomy UI ===== */
.cat-group-tag {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-left: 6px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--bg-2);
  color: var(--ink-3);
  vertical-align: middle;
  white-space: nowrap;
}
.cat-group-tag.direct {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Trends collapsible groups */
.trends-group + .trends-group { margin-top: 12px; }
.trends-group-header {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 4px;
  margin-bottom: 6px;
  background: transparent;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.trends-group-chevron {
  width: 16px; height: 16px;
  color: var(--ink-3);
  flex-shrink: 0;
  transition: transform 0.2s;
}
.trends-group.collapsed .trends-group-chevron { transform: rotate(-90deg); }
.trends-group-title {
  flex: 1;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.trends-group-total {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-2);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.trends-group-body { display: block; }
.trends-group.collapsed .trends-group-body { display: none; }

/* Drill grouped category list */
.drill-group-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 16px 4px 4px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.drill-group-header:first-child { margin-top: 0; }
.drill-group-name {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.drill-group-total {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* ===== Auth screen (pre-login) ===== */
body.auth-pending .topbar,
body.auth-pending .tabbar { display: none; }
body.auth-pending #view { padding: 0; }

.auth-shell {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px 20px calc(var(--safe-bot) + 24px);
}
.auth-card {
  width: 100%;
  max-width: 380px;
  background: var(--card);
  border: 1px solid var(--border);
  border-top: 2px solid var(--accent-on-light);
  border-radius: 16px;
  padding: 28px 24px;
  text-align: center;
  box-shadow: 0 8px 24px -12px rgba(24, 24, 27, 0.16);
}
.auth-logo {
  /* Day 26 green convergence — same lime+forest token pair as the
     topbar .logo and .btn-primary, so the DB tile reads identically
     across marketing landing nav, auth cards, and the topbar after
     sign-in. Pre-fix used var(--brand) forest bg + var(--brand-fg)
     cream text which read as "dark navy + white" on cream and broke
     the brand anchor. */
  width: 56px; height: 56px;
  margin: 0 auto 18px;
  background: var(--accent);
  color: var(--brand);
  display: grid; place-items: center;
  border-radius: 14px;
  font-size: 20px; font-weight: 800;
  letter-spacing: -0.02em;
}
.auth-title {
  margin: 0 0 6px;
  font-size: 22px; font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.02em;
}
.auth-sub {
  margin: 0 0 20px;
  font-size: 14px;
  color: var(--ink-3);
  line-height: 1.45;
}
.auth-error {
  margin: 0 0 14px;
  padding: 10px 12px;
  background: #FEE2E2;
  color: #991B1B;
  border-radius: 10px;
  font-size: 13px;
  text-align: left;
}
.auth-form { display: grid; gap: 12px; }
.auth-input {
  width: 100%;
  padding: 13px 14px;
  background: var(--bg);
  border: 1px solid var(--border-2);
  border-radius: 12px;
  font-size: 15px;
  color: var(--ink);
  font: inherit;
}
.auth-input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.auth-form .btn-primary { margin-top: 0; }
.auth-back { margin-top: 8px; }
.auth-note {
  margin: 12px 0 0;
  font-size: 12px;
  color: var(--ink-4);
  text-align: center;
}
.auth-divider {
  margin: 18px 0 14px;
  height: 1px;
  background: var(--border);
}
.auth-footer {
  margin: 0;
  font-size: 12px;
  color: var(--ink-3);
  text-align: center;
  line-height: 1.45;
}
.auth-link-fallback {
  /* Day 26 — auth links read on cream, which means we need the
     contrast-safe green token (var(--accent-on-light) = #178350,
     ~4.7:1 on #faf7f1 — passes WCAG AA body-text). var(--accent)
     #34d680 is bright lime, fine as a fill but ~2.2:1 as text and
     fails AA. The lime <-> deeper-green disambiguation by context
     is the same pattern documented in styles.css's :root --accent-
     on-light comment. */
  display: inline;
  padding: 0;
  margin: 0;
  color: var(--accent-on-light);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
  background: none;
  border: 0;
}
.auth-link-fallback:active { color: var(--brand); }
/* Phase 3a — sign-in screen toggle / forgot rows. The .auth-note
   wrapper sets center alignment + meta typography; these rules only
   adjust the inner layout. */
.auth-toggle-row {
  margin-top: 14px;
}
.auth-forgot {
  margin-top: 8px;
}
/* Day 22 evening polish item 6 — loading-screen placeholder rendered
   during DEMO_MODE auto-sign-in + future async gates that run BEFORE
   the main app render. Visual chrome converges with verify.html /
   reset.html so cold visitors see one continuous "loading" state. */
.auth-loading-card {
  text-align: center;
  padding-top: 32px;
}
.auth-loading-spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--border-2);
  border-top-color: var(--accent);
  border-radius: 50%;
  margin: 0 auto 18px;
  animation: auth-loading-spin 0.8s linear infinite;
}
@keyframes auth-loading-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .auth-loading-spinner { animation: none; }
}
/* Inline-expanding password-reset form below the sign-in form.
   #30 / Day 22 evening polish item 2 — replaced the mailto-only
   placeholder with a real auth.resetPasswordForEmail flow. */
.auth-forgot-form {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.auth-forgot-status {
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.45;
}

/* ===== Bank Connection tile + consent sheet ===== */
.bank-empty-sub {
  margin: 0 0 14px;
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.45;
}
.bank-connect-btn { margin-top: 0; }
.bank-connected {
  padding: 4px 0 2px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.bank-connected-info { flex: 1; min-width: 0; }
.bank-card-chevron {
  width: 20px; height: 20px;
  color: var(--ink-4);
  flex-shrink: 0;
}
.bank-connected-name {
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.bank-connected-meta {
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-3);
}

/* Multi-bank list (task #64). Each row mirrors the single-bank
   .bank-connected layout but stacks vertically with hairline dividers. */
.bank-list {
  display: flex;
  flex-direction: column;
  margin: 0 -4px 4px;
}
.bank-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 4px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.bank-row:last-child { border-bottom: 0; }
.bank-row:active { background: var(--bg-2); }
.bank-row-info { flex: 1; min-width: 0; }
.bank-row-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.bank-row-meta {
  margin-top: 3px;
  font-size: 12px;
  color: var(--ink-3);
}
.bank-row-meta-warning {
  color: var(--warning);
  font-weight: 600;
}
.bank-row-chevron {
  width: 18px; height: 18px;
  color: var(--ink-4);
  flex-shrink: 0;
}
.bank-add-link {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 10px 12px;
  background: transparent;
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-on-light);
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s, border-color 0.12s;
}
.bank-add-link:hover {
  background: var(--bg-2);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}

/* Bank Connection tile actions row (task #140). When 2+ banks are
   connected, the "Refresh all" button shares space with "+ Connect
   another bank" — flex layout side-by-side. Single-bank case renders
   only the add-link, which keeps its prior full-width display via
   the parent flex defaulting to flex-grow. */
.bank-actions-row {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}
.bank-actions-row .bank-add-link {
  margin-top: 0;
  flex: 1;
}
.bank-refresh-all-link {
  display: block;
  padding: 10px 12px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-on-light);
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s, border-color 0.12s;
  flex: 1;
}
.bank-refresh-all-link:hover {
  background: var(--bg-2);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}
.bank-refresh-all-link:disabled {
  opacity: 0.5;
  cursor: wait;
}
.bank-consent-policy {
  margin: 0 0 16px;
  font-size: 12px;
  color: var(--ink-4);
  text-align: center;
}
.bank-consent-policy a { color: var(--accent); text-decoration: underline; }
.bank-error-msg { color: var(--ink-2); }

/* Full-width primary-pill destructive variant — same muted grey as
   .btn-action-destructive but inherits .btn-primary's full-width
   layout for surfaces like Settings → Sign out, bank disconnect
   confirm sheet, OD Disconnect (constrained to flex:1 inside
   .pms-action-row), auth-screen Sign out. Pre-2026-05-15 polish pass
   the variant was loud red (#DC2626) — replaced with muted grey per
   Edwin's "available, opt-out" framing. */
.btn-primary.btn-destructive {
  background: var(--bg-2);
  color: var(--ink-2);
  border-color: var(--border);
}
.btn-primary.btn-destructive:hover {
  background: var(--border);
}
.btn-primary.btn-destructive:active {
  background: var(--border-2);
  border-color: var(--border-2);
}

.bank-detail-title { margin: 0 0 8px; }
.bank-detail-status-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  font-size: 13px;
  color: var(--ink-3);
}
.bank-status {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 8px;
  font-size: 11px;
  font-weight: 600;
}
.bank-status-active       { background: #DCFCE7; color: #14532D; }
.bank-status-error        { background: #FEE2E2; color: #991B1B; }
.bank-status-expired      { background: #FEF3C7; color: #78350F; }
.bank-status-disconnected { background: #E5E7EB; color: #374151; }

.bank-account-list { margin: 0 0 16px; border-top: 1px solid var(--border); }
.bank-account-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.bank-account-name { flex: 1; min-width: 0; color: var(--ink); font-weight: 600; }
.bank-account-mask { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.bank-account-type {
  color: var(--ink-4);
  font-size: 11px;
  text-transform: capitalize;
}

/* ===== Legal footer (Privacy | Contact | Data Request) ===== */
.legal-footer {
  text-align: center;
  padding: 8px 16px 16px;
  font-size: 12px;
  color: var(--ink-3);
}
.legal-footer a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.legal-footer .footer-sep {
  margin: 0 8px;
  color: var(--border-2);
}

/* ===== Insight dismiss / flag controls (Block E final) =====
   localStorage-backed dismiss + flag stub. Mobile (touch) shows the
   buttons always; desktop fades them in on row hover for a calmer
   default state. Full Supabase backend = task #57. */
.insight-controls-inline {
  display: inline-flex;
  gap: 2px;
  align-items: center;
  flex-shrink: 0;
  /* Persistent low opacity so the affordances never feel phantom.
     Hover brightens to 1 on desktop; mobile compromises around 0.6
     since there's no hover state. */
  opacity: 0.3;
  transition: opacity 0.15s;
}
@media (hover: hover) {
  .insight:hover .insight-controls-inline { opacity: 1; }
}
@media (hover: none) {
  .insight-controls-inline { opacity: 0.6; }
}
.insight-control-btn {
  width: 24px;
  height: 24px;
  display: inline-grid;
  place-items: center;
  border: 0;
  background: transparent;
  color: var(--ink-3);
  border-radius: 5px;
  cursor: pointer;
  padding: 0;
}
.insight-control-btn:hover {
  background: var(--bg-2);
  color: var(--ink);
}
.insight-control-btn svg {
  width: 14px;
  height: 14px;
}
/* Flagged state: bright accent + always full opacity (don't fade with
   the parent .insight-controls-inline rule above). */
.insight-flag-btn.flagged {
  color: var(--accent-on-light);
  opacity: 1;
}

/* Flagged section header (above the green/yellow/red sections). */
.flag-header.flagged {
  color: var(--accent-on-light);
}
.flag-header.flagged::before {
  background: var(--accent-on-light);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* Flagged-pinned insight rows in the Flagged section get an accent
   border so they read as elevated. */
.insight.flagged-pinned {
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 1px var(--accent-on-light);
}

/* Dismissed section (collapsible) at the bottom of Insights tab. */
.insight-dismissed {
  margin-top: 16px;
  font-size: 13px;
}
.insight-dismissed > summary {
  cursor: pointer;
  color: var(--ink-3);
  padding: 8px 0;
  font-weight: 500;
  list-style: none;
  outline: none;
  user-select: none;
}
.insight-dismissed > summary::-webkit-details-marker { display: none; }
.insight-dismissed > summary::before {
  content: '▸';
  display: inline-block;
  margin-right: 6px;
  transition: transform 0.15s;
}
.insight-dismissed[open] > summary::before {
  transform: rotate(90deg);
}
.insight-dismissed-list { margin-top: 4px; }
.insight.dismissed-row {
  opacity: 0.65;
}
.insight.dismissed-row .insight-title {
  text-decoration: line-through;
  text-decoration-color: var(--ink-4);
}
.insight-restore-btn {
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  margin-left: auto;
  align-self: center;
  white-space: nowrap;
}
.insight-restore-btn:hover { background: var(--card); }

/* Empty state for Top Priority tile when everything is dismissed
   or nothing was generated. */
.insight-empty {
  padding: 18px 12px;
  text-align: center;
  color: var(--ink-3);
  font-size: 13px;
}

/* Undo toast — shown for 5 sec after a dismiss. Bottom-anchored so the
   tabbar floating above it isn't covered. */
.undo-toast {
  position: fixed;
  bottom: calc(96px + var(--safe-bot, 0px));
  left: 50%;
  transform: translateX(-50%);
  background: var(--ink);
  color: var(--card);
  padding: 10px 14px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 13px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  z-index: 100;
  max-width: calc(100vw - 32px);
  animation: undo-toast-in 0.2s ease-out;
}
.undo-toast .undo-toast-text {
  flex: 1;
  min-width: 0;
}
.undo-toast .undo-btn {
  background: transparent;
  color: var(--card);
  border: 1px solid rgba(255, 255, 255, 0.3);
  padding: 4px 12px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
}
.undo-toast .undo-btn:hover { background: rgba(255, 255, 255, 0.1); }
@keyframes undo-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(20px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* =============================================================================
   Manual cash entry — FAB + form modal (task #53, v1.7 Phase 1)
   ============================================================================= */

/* Floating action buttons (#153) — search FAB on Vendors + Activity;
   add FAB stacks above search FAB on Activity (when can-create-txns).
   Both 48px to match the compact-chrome scale; the previous single
   56px add-only FAB needed shrinking to fit two on a stack without
   crowding the safe-area + tabbar. Theme-aware via --brand / --brand-fg. */
.add-txn-fab,
.search-fab {
  position: fixed;
  right: 16px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--brand);
  color: var(--brand-fg);
  border: none;
  display: none;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 20px -4px rgba(15, 23, 42, 0.25);
  cursor: pointer;
  z-index: 30;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.12s;
}
.add-txn-fab svg { width: 22px; height: 22px; }
.search-fab svg  { width: 20px; height: 20px; }

/* Stack positioning. Search FAB anchors at the bottom; Add FAB
   stacks above it with 12px vertical gap (48px FAB + 12px gap = 60px
   offset). On Vendors there's no Add FAB so search stays at the
   bottom slot — same anchor either way, no JS needed. */
.search-fab    { bottom: calc(96px + var(--safe-bot, 0px)); }
.add-txn-fab   { bottom: calc(96px + 48px + 12px + var(--safe-bot, 0px)); }

/* Visibility gates — search FAB on Vendors + Activity; add FAB on
   Activity only (existing can-create-txns gate, set by
   applyCashEntryGate when CURRENT_TAB === 'txns' && !demo). */
body.tab-vendors .search-fab,
body.tab-txns    .search-fab    { display: flex; }
body.can-create-txns .add-txn-fab { display: flex; }

.add-txn-fab:hover,
.search-fab:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 28px -4px rgba(15, 23, 42, 0.32);
}
.add-txn-fab:active,
.search-fab:active { transform: translateY(0); box-shadow: 0 4px 14px -4px rgba(15, 23, 42, 0.25); }
.add-txn-fab:focus-visible,
.search-fab:focus-visible { outline: 3px solid var(--accent-soft); outline-offset: 2px; }

/* Active-search visual cue — when the user has typed in the search
   overlay and collapsed it, the FAB tints accent so they know the
   list is being filtered even without the inline row visible. */
.search-fab.has-query { background: var(--accent); color: var(--hero-text, white); }

@media (min-width: 768px) {
  .add-txn-fab,
  .search-fab { right: 24px; }
  .search-fab    { bottom: calc(96px + var(--safe-bot, 0px) + 8px); }
  .add-txn-fab   { bottom: calc(96px + 48px + 12px + var(--safe-bot, 0px) + 8px); }
}

/* ===== Tab chrome row + buttons (#153) =====
   Compact title + control row at the top of Vendors / Activity.
   Title uses the existing .section-title typography (24px / 700);
   chrome buttons sit right-aligned with the sort menu absolutely
   positioned below them. Position: relative on the chrome-btn-row
   so the sort menu's absolute positioning anchors to it. */
.tab-chrome-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 4px 4px 8px;
}
.tab-chrome-title { margin: 0; padding: 0; }
.chrome-btn-row {
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
  flex-shrink: 0;
}
.chrome-btn {
  width: 44px;
  height: 44px;
  display: inline-grid;
  place-items: center;
  border-radius: 10px;
  background: var(--card);
  border: 1px solid var(--border);
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
  position: relative;
  flex-shrink: 0;
}
.chrome-btn svg { width: 18px; height: 18px; }
.chrome-btn:active { background: var(--bg-2); }
.chrome-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Active-filter visual states — .has-filters tints when filters are
   non-default; .active layers an accent border when the filters
   region is currently expanded (visual cue for "the pills below
   correspond to this button"). Both can apply simultaneously. */
.chrome-btn-filter.has-filters {
  color: var(--accent-on-light);
}
.chrome-btn.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.chrome-btn-badge {
  position: absolute;
  top: -4px; right: -4px;
  min-width: 18px;
  height: 18px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--hero-text, white);
  font-size: 10px;
  font-weight: 700;
  display: grid;
  place-items: center;
  padding: 0 4px;
  border: 2px solid var(--bg);
  line-height: 1;
}

/* Sort menu — absolute popover anchored below the Sort button. The
   .sort-menu-backdrop captures stray taps to close (z-index just
   below the menu). Display: none until .open is added. */
.sort-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px -6px rgba(15, 23, 42, 0.18);
  z-index: 25;
  padding: 4px;
  min-width: 200px;
  display: none;
}
.sort-menu.open { display: block; }
.sort-menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 24;
  background: transparent;
  display: none;
}
.sort-menu-backdrop.open { display: block; }
.sort-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-height: 40px;
  padding: 8px 12px;
  background: transparent;
  border: 0;
  border-radius: 8px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: background 0.12s;
}
.sort-menu-item:hover { background: var(--bg-2); }
.sort-menu-item .check {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  display: inline-grid;
  place-items: center;
  color: var(--accent);
  visibility: hidden;
}
.sort-menu-item .check svg { width: 14px; height: 14px; }
.sort-menu-item.active .check { visibility: visible; }

/* Collapsible filters region + inline search row (#153). Display
   none by default; .open class toggles flex/block. No height
   transition — the layout shift is small and instant feels right
   for a filter expand-collapse toggle. */
.filters-region {
  display: none;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 8px;
}
.filters-region.open { display: flex; }
.filters-region .month-pills,
.filters-region .pills-stack { margin-bottom: 0; }

.inline-search-row {
  display: none;
  margin-bottom: 8px;
}
.inline-search-row.open { display: block; }
.inline-search-row .search-wrap { margin-bottom: 0; }

/* Form modal — desktop centers; mobile keeps default bottom-sheet. */
@media (min-width: 768px) {
  .sheet.sheet--form-modal {
    top: 50%;
    bottom: auto;
    left: 50%;
    right: auto;
    width: 460px;
    max-width: calc(100vw - 32px);
    transform: translate(-50%, calc(-50% + 100vh));
    border-radius: 16px;
    max-height: 80vh;
    padding: 18px 22px 22px;
  }
  .sheet.sheet--form-modal.open { transform: translate(-50%, -50%); }
  .sheet.sheet--form-modal .sheet-handle { display: none; }
}

/* Form layout */
.cash-entry-form { display: flex; flex-direction: column; gap: 14px; }
.cash-entry-form .form-row { display: flex; flex-direction: column; gap: 6px; }
.cash-entry-form .form-row-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.cash-entry-form label {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.cash-entry-form label .req { color: var(--danger); margin-left: 2px; }
.cash-entry-form input[type="text"],
.cash-entry-form input[type="number"],
.cash-entry-form input[type="date"],
.cash-entry-form select,
.cash-entry-form textarea {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.cash-entry-form input:focus,
.cash-entry-form select:focus,
.cash-entry-form textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.cash-entry-form textarea {
  min-height: 60px;
  resize: vertical;
}
.cash-entry-form .form-error {
  font-size: 12px;
  color: var(--danger);
  min-height: 14px;
  margin-top: 2px;
}
.cash-entry-form .form-error:empty { display: none; }

/* Amount input prefix ($) */
.cash-entry-form .amount-wrap { position: relative; }
.cash-entry-form .amount-wrap::before {
  content: "$";
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--ink-3);
  font-size: 15px;
  pointer-events: none;
}
.cash-entry-form .amount-wrap input { padding-left: 24px; }

/* Action row */
.cash-entry-form .form-actions {
  display: flex;
  gap: 10px;
  margin-top: 8px;
}
.cash-entry-form .form-actions button {
  flex: 1;
  padding: 12px 16px;
  border-radius: 10px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  border: none;
  transition: background 0.12s;
}
.cash-entry-form .btn-cancel {
  background: var(--bg-2);
  color: var(--ink);
}
.cash-entry-form .btn-cancel:hover { background: var(--border); }
.cash-entry-form .btn-submit {
  background: var(--brand);
  color: var(--brand-fg);
}
.cash-entry-form .btn-submit:hover { background: var(--brand-2); }
.cash-entry-form .btn-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Submit error banner — appears above .form-actions when DB write fails */
.cash-entry-form .form-submit-error {
  background: color-mix(in srgb, var(--danger) 12%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
  color: var(--danger);
  font-size: 13px;
  font-weight: 500;
  padding: 10px 12px;
  border-radius: 8px;
  display: none;
}

/* Edit / Delete affordances on manual_entry transaction-detail drill view */
.manual-row-actions {
  display: flex;
  gap: 10px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}
.manual-row-actions button {
  flex: 1;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.12s;
}
.manual-row-actions button:hover { background: var(--bg-2); }
.manual-row-actions .btn-delete-manual {
  background: var(--bg-2);
  color: var(--ink-2);
  border-color: var(--border);
}
.manual-row-actions .btn-delete-manual:hover { background: var(--border); }
.manual-row-actions .btn-delete-manual:active { background: var(--border-2); }

/* Exclusion toggle button (task #78). Lives INSIDE the bottom action
   bar — .reclassify-actions for imported rows, .manual-row-actions
   for manual entries — left-most via margin-right: auto so the
   primary destructive-style button anchors the left edge while
   Cancel / Save / Edit / Delete stay right-aligned. Per Edwin's
   verify feedback: the standalone .exclusion-row above the
   reclassify section read as weirdly placed; integrating into the
   action bar gives the drill a single bottom-row affordance row. */
.btn-exclusion {
  padding: 9px 14px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
  /* Muted grey "Exclude from totals" — matches the canonical destructive
     pill register across the app. The exclusion toggle is reversible
     ("Include in totals again" flips state); the row's still in the
     ledger, just out of aggregations. Muted treatment communicates
     "available, opt-out" rather than alert/danger. */
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
}
.btn-exclusion:hover,
.btn-exclusion:active {
  background: var(--border);
  color: var(--ink);
}
.btn-exclusion:disabled {
  opacity: 0.6;
  cursor: progress;
}
/* When the row is currently excluded, the button surfaces "Include
   in totals again" — re-inclusion is a positive undo, NOT destructive.
   Accent-soft tint flips the visual signal so the user reads
   "bring back" instead of "destroy further." */
.btn-exclusion-included {
  background: var(--card);
  color: var(--accent-on-light);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
}
.btn-exclusion-included:hover,
.btn-exclusion-included:active {
  background: var(--accent-soft);
  border-color: var(--accent);
}
/* Position rules: leftmost in either bottom action bar.
   - .reclassify-actions: margin-right: auto pushes following siblings
     (Cancel + optional Reset + Save) to the right edge while keeping
     Exclude flush left. Falls back to wrapping cleanly under flex-wrap
     when the bar overflows at <412px.
   - .manual-row-actions: all three buttons share flex: 1 so the row
     reads as an even three-up split (Exclude / Edit / Delete) — the
     left-of-cancel directive doesn't apply here since manual rows
     have no Cancel/Save bar. */
.reclassify-actions .btn-exclusion {
  margin-right: auto;
  flex: 0 0 auto;
}
.manual-row-actions .btn-exclusion {
  flex: 1;
  padding: 10px 14px;
  font-size: 14px;
}

/* Excluded transaction row styling on Activity (#78). Renders only
   under the 'Excluded' pill (default view filters them out upstream).
   Strikethrough on the amount + muted ink on vendor + meta read as
   "this row is set aside from totals." Drill remains tappable so
   users can re-include with one tap. */
.txn-row.txn-excluded {
  opacity: 0.55;
}
.txn-row.txn-excluded .txn-amount {
  text-decoration: line-through;
}

/* Excluded indicator on the transaction-detail drill amount block. */
.txn-detail-amount-excluded {
  text-decoration: line-through;
  opacity: 0.7;
}
.txn-detail-excluded-note {
  margin-top: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Reclassify section in transaction-detail drill (task #54 Phase 1) */
.reclassify-section {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.reclassify-section h3 { margin: 0 0 4px; }
.reclassify-section .form-row { display: flex; flex-direction: column; gap: 6px; }
.reclassify-section label {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.reclassify-section select,
.reclassify-section input[type="text"] {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
/* Reclassify dropdown scroll fix (#145) — on mobile webviews the
   sheet's transform: translateY + overflow-y constraint can clip the
   inline-rendered <select> popup so options past ~5 items don't scroll
   into view. Native iOS/Android pickers open fullscreen and aren't
   affected; this fix targets the in-page popup browsers (Safari
   desktop emulation at 412px, Android Chrome inline-popup mode).
   max-height + overflow-y on the select element scopes the option
   list height to 60vh + lets the user scroll the inner list. */
.reclassify-section select {
  max-height: 60vh;
  overflow-y: auto;
}
.reclassify-section select:focus,
.reclassify-section input[type="text"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.reclassify-subcat-hint {
  /* Plain-language helper below the subcategory field on Doctor Pay rows
     (#249). Surfaces the per-transaction owner-override behavior so
     users discover "type a doctor name to claim this row" without
     hunting in docs. Compact + unobtrusive — italic ink-3 text. */
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  line-height: 1.4;
  margin-top: 2px;
}
/* #254 — "+ Add new doctor in Settings" link below the doctor dropdown.
   Inline-link styling (no button chrome) so it reads as secondary
   navigation, not a primary action. */
.rc-add-doctor-link {
  align-self: flex-start;
  background: none;
  border: none;
  padding: 0;
  margin-top: 4px;
  color: var(--accent-on-light);
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.rc-add-doctor-link:hover,
.rc-add-doctor-link:focus-visible {
  color: var(--accent);
  outline: none;
}
/* #260 — kind-flip preview line beneath the category dropdown. Surfaces
   live whenever the chosen category would also flip transaction kind
   (transfer ↔ expense / revenue ↔ expense). Soft accent-tinted card
   so it reads as informational rather than a warning — the action
   itself isn't risky, just worth surfacing. */
.reclassify-kind-preview {
  font-size: 12px;
  color: var(--accent-on-light);
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border));
  padding: 8px 10px;
  border-radius: 6px;
  line-height: 1.4;
  margin-top: 4px;
}
.reclassify-original-hint {
  font-size: 12px;
  color: var(--ink-3);
  background: var(--bg-2);
  padding: 8px 10px;
  border-radius: 6px;
}
/* Action row at the bottom of the reclassify section. All three buttons
   right-aligned in a single row; Cancel + Reset are secondary, Save is
   primary. Wraps to a new row on narrow viewports if the trio doesn't
   fit. */
.reclassify-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 4px;
}
.reclassify-actions button {
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.btn-cancel-reclassify,
.reclassify-actions .btn-reset-override {
  background: var(--card);
  color: var(--ink-2);
  border: 1px solid var(--border);
}
.btn-cancel-reclassify:hover,
.reclassify-actions .btn-reset-override:hover {
  background: var(--bg-2);
}
.btn-save-reclassify {
  background: var(--accent);
  color: var(--hero-text, white);
  border: 1px solid var(--accent);
}
.btn-save-reclassify:hover:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 85%, black);
}
.btn-save-reclassify:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-reset-override {
  align-self: flex-start;
  padding: 8px 14px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.btn-reset-override:hover { background: var(--bg-2); }
.reclassify-error {
  background: color-mix(in srgb, var(--danger) 12%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
  color: var(--danger);
  font-size: 13px;
  font-weight: 500;
  padding: 10px 12px;
  border-radius: 8px;
}

/* In-app help / FAQ (task #62). Collapsible Q&A list inside the
   sheet — first item open by default so users see something useful
   immediately. Headings stay scannable when collapsed. */
.help-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 12px 0 16px;
}
.help-item {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  overflow: hidden;
}
.help-item summary {
  cursor: pointer;
  padding: 12px 14px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  list-style: none;
  position: relative;
  padding-right: 36px;
}
.help-item summary::-webkit-details-marker { display: none; }
.help-item summary::after {
  content: "+";
  position: absolute;
  right: 14px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 18px;
  font-weight: 400;
  color: var(--ink-3);
  line-height: 1;
}
.help-item[open] summary::after { content: "−"; }
.help-item summary:hover { background: var(--bg-2); }
.help-answer {
  padding: 0 14px 14px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.55;
}
.help-answer a { color: var(--accent-on-light); text-decoration: underline; }
.help-answer b { color: var(--ink); font-weight: 700; }

/* Onboarding empty states (task #61). Shown when the current FY
   has zero transactions and we're not the demo practice. Tab-
   specific copy + CTA buttons (owner|admin only). */
.empty-state {
  margin-top: 12px;
  padding: 32px 22px;
  text-align: center;
}
.empty-state-title {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.empty-state-body {
  margin: 0 0 18px;
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.5;
  max-width: 420px;
  margin-left: auto;
  margin-right: auto;
}
.empty-state-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin-top: 18px;
}
.empty-state-actions .btn-primary {
  margin-top: 0;
  flex: 0 1 auto;
  min-width: 160px;
}
@media (min-width: 768px) {
  .empty-state {
    padding: 48px 24px;
  }
}

/* Indexing banner (#99) — slim status row above tab content while
   Plaid is still indexing historical transactions. Auto-clears when
   HISTORICAL_UPDATE webhook flips bank_accounts.indexing_status to
   'complete'. Subtle by design — informational, not blocking. */
.indexing-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 12px 0 0;
  padding: 10px 14px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
  color: var(--ink-2);
}
.indexing-banner-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .indexing-banner-dot {
    animation: indexing-pulse 1.6s ease-in-out infinite;
  }
}
@keyframes indexing-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}
.indexing-banner-msg {
  flex: 1;
  min-width: 0;
}
.indexing-banner-refresh {
  flex-shrink: 0;
  padding: 6px 12px;
  background: transparent;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent-on-light);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.indexing-banner-refresh:hover,
.indexing-banner-refresh:active {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.indexing-banner-refresh:disabled {
  opacity: 0.6;
  cursor: progress;
}

/* Practice settings modal (task #60). Section-based layout with a
   readonly-style for non-editable fields and inline edit affordances
   for owners. Re-uses .reclassify-actions for the bottom button row. */
.settings-section {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.settings-section:first-of-type { border-top: 0; padding-top: 4px; margin-top: 6px; }
.settings-section h3 {
  margin: 0 0 12px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}
.settings-section .form-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 10px;
}
.settings-section label {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.settings-section input[type="text"] {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.settings-section input[type="text"]:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.settings-readonly {
  padding: 9px 12px;
  font-size: 14px;
  color: var(--ink-2);
  background: var(--bg-2);
  border-radius: 8px;
}
.settings-readonly-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}
.settings-readonly-grid > div { display: flex; flex-direction: column; gap: 6px; }

.settings-doctors {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.settings-doctor-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Day 31 follow-up (#363) — single-line layout per doctor. Old
   .settings-doctor-row-top kept as alias for any external references;
   .settings-doctor-row-main is the new primary container with name
   input + Owner/Associate badge + bank-pattern toggle pill all on
   one row. Old patterns block stays mounted (chips + add affordance
   + suggestions + error) but starts hidden; toggle pill expands. */
.settings-doctor-row-top,
.settings-doctor-row-main {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.settings-doctor-row .settings-doctor-name,
.settings-doctor-row .settings-readonly {
  flex: 1 1 140px;
  min-width: 0;
}
/* Inline bank-pattern indicator pill — muted register so it reads as
   secondary metadata, not a primary control. Tap to expand the
   patterns block below. */
.settings-doctor-patterns-toggle,
.settings-doctor-patterns-readonly {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  line-height: 1.1;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.settings-doctor-patterns-readonly {
  cursor: default;
}
.settings-doctor-patterns-toggle:hover,
.settings-doctor-patterns-toggle:focus-visible {
  background: var(--card);
  border-color: var(--border-2);
  color: var(--ink-2);
}
.settings-doctor-patterns-toggle:active {
  background: var(--bg-2);
}
.settings-doctor-patterns-toggle-caret {
  font-size: 10px;
  opacity: 0.6;
}
/* Auto-matched-on-name muted text inside the chips area — shown when
   no custom patterns exist (i.e., the doctor's name is the implicit
   match). Keeps the patterns block useful even when expanded but
   empty of custom chips. */
.settings-doctor-patterns-auto {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-4);
  font-style: italic;
}
/* Bank-pattern chips (#227) — per-doctor list of substring patterns
   matched against vendor/clean/subcategory in the P&L Doctor Pay
   aggregation. Add via "+ Add pattern" affordance, remove via × on
   each chip. Plain-language hint sits below the doctors list to
   explain what the patterns are for. */
.settings-doctor-patterns {
  padding-left: 0;
}
.settings-doctor-patterns-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  margin-bottom: 6px;
  text-transform: uppercase;
}
.settings-doctor-patterns-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.settings-doctor-pattern-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px 4px 10px;
  background: color-mix(in srgb, var(--accent) 12%, var(--card));
  border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--border));
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent-on-light);
  font-variant-numeric: tabular-nums;
}
.settings-doctor-pattern-chip-text {
  white-space: nowrap;
}
.settings-doctor-pattern-chip-remove {
  background: transparent;
  border: none;
  color: inherit;
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.12s;
  min-width: 18px;
  min-height: 18px;
}
.settings-doctor-pattern-chip-remove:hover,
.settings-doctor-pattern-chip-remove:focus-visible {
  opacity: 1;
}
.settings-doctor-pattern-add {
  background: var(--bg-2);
  border: 1px dashed var(--border-2);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.settings-doctor-pattern-add:hover,
.settings-doctor-pattern-add:focus-visible {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.settings-doctor-pattern-input {
  padding: 4px 10px;
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  background: var(--card);
  color: var(--ink);
  min-width: 160px;
}
.settings-doctor-pattern-input:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent);
  outline-offset: 1px;
}
/* Live-preview pattern editor (#255). Replaces the bare inline input
   with a multi-element block (input + Save + Cancel + preview). The
   block takes its own flex row inside the chips-wrap (width:100%) so
   the existing chips sit on the row above and the preview reads as
   the action surface for the new pattern. */
.settings-doctor-pattern-editor {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
}
.settings-doctor-pattern-editor-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
.settings-doctor-pattern-editor .settings-doctor-pattern-input {
  flex: 1 1 200px;
  min-width: 160px;
}
/* Chip-row scale buttons — override btn-action's 40px height + 0 18px
   padding + 14px font + 84px min-width so the Save / Cancel buttons
   match the input's compact height (≈28px) and don't dominate the
   chip-area aesthetic. min-width unset so Save can grow horizontally
   when it carries the long "attribute N rows to <name>" label. */
.settings-doctor-pattern-save,
.settings-doctor-pattern-cancel {
  height: auto;
  min-width: 0;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
  line-height: 1.2;
}
.settings-doctor-pattern-save:disabled,
.settings-doctor-pattern-cancel:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.settings-doctor-pattern-preview {
  font-size: 12px;
  color: var(--ink-2);
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  line-height: 1.45;
}
.settings-doctor-pattern-preview-summary {
  color: var(--ink);
  font-weight: 500;
}
.settings-doctor-pattern-preview-samples-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-top: 2px;
}
.settings-doctor-pattern-preview-samples {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.settings-doctor-pattern-preview-sample {
  display: flex;
  gap: 10px;
  align-items: baseline;
  font-variant-numeric: tabular-nums;
}
.settings-doctor-pattern-preview-sample-date {
  font-weight: 600;
  color: var(--ink-3);
  flex: 0 0 auto;
  min-width: 50px;
}
.settings-doctor-pattern-preview-sample-vendor {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-2);
}
.settings-doctor-pattern-preview-sample-amount {
  flex: 0 0 auto;
  font-weight: 600;
  color: var(--ink);
}
.settings-doctor-pattern-preview-conflict {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 10%, transparent);
  border-radius: 6px;
  padding: 6px 8px;
}
.settings-doctor-pattern-preview-broad {
  color: var(--ink-3);
  font-style: italic;
}
.settings-doctor-pattern-preview code {
  background: var(--card);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border);
}
.settings-doctor-patterns-error {
  font-size: 12px;
  color: var(--danger);
  margin-top: 4px;
}
.settings-doctor-patterns-hint {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 12px;
  line-height: 1.45;
}
.settings-doctor-patterns-hint code {
  background: var(--bg-2);
  padding: 1px 5px;
  border-radius: 4px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
/* Suggested-mask chips (Day 18 PM2). Surfaces masks scraped from the
   practice's actual Doctor Pay rows that aren't currently covered by
   any doctor's patterns. Tap a chip to add it to that doctor's
   patterns; the chip moves to the active list and disappears from
   suggestions across all rows. Visually distinct from active chips:
   dashed border + accent-tinted background, "+" prefix, count tail. */
.settings-doctor-patterns-suggested {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border-2);
}
.settings-doctor-patterns-suggested-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink-3);
  margin-bottom: 6px;
  text-transform: uppercase;
}
.settings-doctor-patterns-suggested-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.settings-doctor-pattern-chip-suggest {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px 4px 8px;
  background: var(--bg-2);
  border: 1px dashed color-mix(in srgb, var(--accent) 35%, var(--border));
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.settings-doctor-pattern-chip-suggest:hover,
.settings-doctor-pattern-chip-suggest:focus-visible {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.settings-doctor-pattern-chip-suggest-plus {
  font-weight: 700;
  font-size: 14px;
  line-height: 1;
  color: var(--accent-on-light);
  opacity: 0.85;
}
.settings-doctor-pattern-chip-suggest-text {
  white-space: nowrap;
}
.settings-doctor-pattern-chip-suggest-count {
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-3);
  opacity: 0.85;
}
/* Transfer-source suggested chip (#249). Visually distinct from doctor-
   pay-source chips so the user knows tapping triggers a reclassify
   (not just an attribution refinement). Warning-tint border + small
   "in Transfer" badge convey "this surface is for transfer rows you
   never moved into Doctor Pay yet." */
.settings-doctor-pattern-chip-suggest.is-transfer {
  border-color: color-mix(in srgb, var(--warning) 50%, var(--border));
  background: color-mix(in srgb, var(--warning) 8%, var(--bg-2));
}
.settings-doctor-pattern-chip-suggest.is-transfer:hover,
.settings-doctor-pattern-chip-suggest.is-transfer:focus-visible {
  background: color-mix(in srgb, var(--warning) 16%, var(--bg-2));
  border-color: var(--warning);
  color: var(--ink);
}
.settings-doctor-pattern-chip-suggest-badge {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--warning);
  padding: 2px 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--warning) 14%, transparent);
  white-space: nowrap;
}
/* Inline P&L hint line (Day 18 PM2). Sits below a doctor sub-row
   when the row's bucket is $0 BUT the owner has patterns set —
   the actionable "your patterns matched no rows" cue. Compact;
   doesn't break the section's row rhythm. */
.pnl-line-hint {
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  padding: 4px 14px 8px 28px;
  line-height: 1.4;
}
.pnl-doctor-empty-hint {
  /* Slightly tighter than a generic line-hint — sits flush under the
     doctor sub-row to read as that row's continuation. */
  margin-top: -2px;
}
/* Add-doctor inline form (#148) — reveals below the doctor list when
   the trigger button is tapped. Uses the canonical .btn-action /
   -primary / -secondary variants from #155 for Save / Cancel. */
.settings-doctor-add {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-2);
}
.settings-doctor-add-trigger {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.settings-doctor-add-trigger:hover,
.settings-doctor-add-trigger:active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent-on-light);
}
.settings-doctor-add-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.settings-doctor-add-owner-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-2);
  cursor: pointer;
}
.settings-doctor-add-owner-label input[type="checkbox"] {
  width: 18px;
  height: 18px;
  cursor: pointer;
}
.settings-doctor-add-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}

.settings-role-badge {
  flex-shrink: 0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--bg-2);
  color: var(--ink-3);
  border: 1px solid var(--border);
}
.settings-role-badge.owner {
  background: color-mix(in srgb, var(--accent) 15%, var(--card));
  color: var(--accent-on-light);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}

.settings-bank-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.settings-bank-row:last-child { border-bottom: 0; }
.settings-bank-info { flex: 1; min-width: 0; }
.settings-bank-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.settings-bank-meta { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.settings-disconnect {
  flex-shrink: 0;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
}
.settings-disconnect:hover { background: var(--border); }
.settings-disconnect:active { background: var(--border-2); }

/* Per-bank action button cluster (#391, Day 32) — Backfill + Disconnect
   side-by-side. At 320px viewport the cluster wraps below the bank name
   via flex-wrap on .settings-bank-row's parent (existing). */
.settings-bank-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}
.settings-backfill {
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
}
.settings-backfill:hover { background: var(--border); }
.settings-backfill:active { background: var(--border-2); }

.settings-empty {
  margin: 4px 0;
  font-size: 13px;
  color: var(--ink-3);
  font-style: italic;
}

/* Export sheet (#82 Phase 1) — Settings → Export. Three filter sections
   stacked vertically (Period / Source / Type), each with a small caps
   label + a horizontal pill row. Live count line at the bottom updates
   on every pill tap. Download CSV button lives in the sheet's bottom
   action bar via openSettingsSheet's actions array. */
.export-card .sheet-sub {
  margin: 0 0 16px;
}
.export-section {
  margin-top: 16px;
}
.export-section-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: 8px;
}
/* Inherits .filter-pills behaviour (horizontal scroll on overflow,
   gap, pill sizing). The export-specific class is just a hook in case
   we need to tweak spacing without affecting Activity / Vendors. */
.export-pills {
  margin: 0;
}
.export-count {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
}
.settings-demo-banner {
  margin: 0 0 12px;
  padding: 10px 12px;
  background: var(--bg-2);
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-size: 12px;
  color: var(--ink-3);
}
.settings-signout {
  background: var(--danger);
  border: none;
  margin-top: 4px;
}
.settings-error {
  background: color-mix(in srgb, var(--danger) 12%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
  color: var(--danger);
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  margin: 12px 0 0;
}

/* Categorization v2 (Day 25+ / migration 060) — pill-row + per-group
   lists + add form + delete-× button. Replaces the legacy single-list
   + rollup-radio surface (Tier 1 Item D). Owner|admin gating rendered
   client-side via the `canEdit` flag; viewer / Demo see read-only checkbox
   states + no add form / no × buttons. */
.categories-card .sheet-sub { margin: 0 0 14px; font-size: 13px; color: var(--ink-2); }

/* Three-pill group toggle at top of sheet — Revenue / Direct Costs /
   Overhead. Matches .filter-pills visual register used across Activity /
   Vendors / P&L for canonical pill chrome consistency. */
.categories-pill-row {
  display: flex;
  gap: 6px;
  margin: 0 0 14px;
  padding: 4px;
  background: var(--bg-2);
  border-radius: 999px;
  border: 1px solid var(--border);
}
.categories-pill {
  flex: 1;
  min-height: 44px;
  padding: 0 14px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--ink-2);
  background: transparent;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.categories-pill:hover { color: var(--ink); }
.categories-pill:focus-visible {
  outline: 2px solid var(--accent-on-light);
  outline-offset: -2px;
}
.categories-pill.active {
  background: var(--card);
  color: var(--accent-on-light);
  box-shadow: 0 1px 3px rgba(14, 29, 24, 0.08);
}

/* Per-group category list — wraps the toggle rows + add form into a
   single card-like surface. */
.categories-group-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.categories-group-rows {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-2);
  overflow: hidden;
}
.categories-custom-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
  min-height: 44px;
}
.categories-custom-row:last-child { border-bottom: 0; }
.categories-toggle-input {
  width: 20px; height: 20px;
  accent-color: var(--accent-on-light);
  cursor: pointer;
  flex-shrink: 0;
}
.categories-toggle-input:disabled { cursor: not-allowed; }
.categories-toggle-name {
  flex: 1;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  letter-spacing: -0.005em;
}

/* Delete-× button on practice-scoped (custom) rows only. System
   categories don't expose ×. 32×32 button visual + ≥44 effective tap
   target via the surrounding row padding. */
.categories-delete-btn {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 8px;
  color: var(--ink-4);
  font-size: 20px;
  font-weight: 400;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.categories-delete-btn:hover {
  background: var(--bg-2);
  color: var(--danger);
}
.categories-delete-btn:active {
  background: var(--border);
}
.categories-delete-btn:focus-visible {
  outline: 2px solid var(--danger);
  outline-offset: -2px;
}
.categories-delete-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Add-category form — text input + Add button inline below the list. */
.categories-add-form {
  display: flex;
  gap: 8px;
  align-items: stretch;
}
.categories-add-input {
  flex: 1;
  min-height: 44px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  box-sizing: border-box;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.categories-add-input:focus {
  outline: none;
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 3px rgba(52, 214, 128, 0.18);
}
.categories-add-btn {
  min-height: 44px;
  padding: 0 18px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--brand);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.categories-add-btn:hover { background: var(--accent-2); border-color: var(--accent-2); }
.categories-add-btn:active { background: var(--accent-2); }
.categories-add-btn:focus-visible {
  outline: 2px solid var(--accent-on-light);
  outline-offset: 2px;
}
.categories-add-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* Soft re-surface banner on dismissed insights (task #57 Phase 2).
   Renders inside .insight-content after the body when the dismissed
   row's 30-day re_surface_after has elapsed AND severity hasn't
   shifted. Severity-shift cases auto-undismiss instead. */
.insight-resurface-banner {
  margin-top: 8px;
  padding: 8px 10px;
  background: var(--bg-2);
  border: 1px dashed var(--border);
  border-radius: 6px;
  font-size: 12px;
  color: var(--ink-2);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.resurface-text { flex: 1; min-width: 200px; }
.resurface-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}
.resurface-keep,
.resurface-bring-back {
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  border: 1px solid var(--border);
}
.resurface-keep { background: var(--card); color: var(--ink-2); }
.resurface-bring-back {
  background: var(--accent);
  color: var(--hero-text, white);
  border-color: var(--accent);
}
.resurface-keep:hover { background: var(--bg-2); }
.resurface-bring-back:hover { filter: brightness(0.95); }

/* Bulk reclassify prompt (task #54 Phase 2). Shown after a single
   reclassify when there are sibling rows (same vendor, no existing
   override) that could be batch-updated. Preview list is the first 10
   matching rows + a "+N more" hint when there are more. */
.bulk-preview-list {
  margin: 12px 0 16px;
  padding: 10px 14px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13px;
  max-height: 240px;
  overflow-y: auto;
}
.bulk-preview-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 0;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  border-bottom: 1px solid var(--border);
}
.bulk-preview-row:last-child { border-bottom: 0; }
.bulk-preview-date { color: var(--ink-3); }
.bulk-preview-amount { font-weight: 600; color: var(--ink); }
.bulk-preview-more {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  text-align: center;
}
.bulk-error {
  background: color-mix(in srgb, var(--danger) 12%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
  color: var(--danger);
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  margin: 0 0 12px;
}

/* admin_items #463 — Guard B / Guard C info blocks. Rendered between
   the count summary and the matching-rows preview when the mass-
   reclassify pre-flight detects split parents OR bidirectional vendor
   patterns. Warning-tone styling (yellow accent), distinct from the
   error block above (which is red). */
.bulk-guard-info {
  background: color-mix(in srgb, var(--warning) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--warning) 30%, transparent);
  color: var(--ink-2);
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  line-height: 1.45;
  margin: 8px 0;
}
.bulk-guard-info b {
  color: var(--ink);
}

/* Cash entry empty-categories banner — appears when the form opens
   before SB_DATA categories hydrated. Block H edge case. */
.cash-entry-empty {
  margin-top: 6px;
  padding: 14px 16px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--ink-2);
  font-size: 14px;
  line-height: 1.5;
}
.cash-entry-empty p { margin: 0 0 8px; }
.cash-entry-empty p:last-child { margin: 0; }
.cash-entry-empty strong { color: var(--ink); }

/* "edited" chip on transaction rows when user has overridden the category.
   Brand-2 fill (vs. the soft accent it used to have) so the chip wins
   attention on a dense Activity list — re-categorization is rare and
   notable. */
.txn-edited-chip {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: white;
  background: var(--brand-2);
  padding: 2px 7px;
  border-radius: 999px;
  margin-left: 6px;
  vertical-align: middle;
  line-height: 1.4;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--brand-2) 30%, transparent);
}
/* #256 — doctor-attribution chip. Renders ONLY in the doctor-detail
   drill list (gated by lvl.filter.doctor presence in the renderer);
   muted/small to read as secondary metadata, not a callout. Colors
   pull from the bg-2 + ink-3 pair so the chip recedes against the
   row background but stays readable. */
.doctor-attr-chip {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--bg-2);
  border: 1px solid var(--border);
  padding: 2px 7px;
  border-radius: 999px;
  margin-left: 6px;
  vertical-align: middle;
  line-height: 1.4;
  white-space: nowrap;
}

/* Success toast — top-anchored, auto-dismisses after ~3s */
.entry-toast {
  position: fixed;
  top: calc(72px + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  background: var(--success);
  color: white;
  padding: 10px 16px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  z-index: 100;
  box-shadow: 0 8px 24px -4px rgba(15, 23, 42, 0.25);
  animation: entry-toast-in 0.2s ease-out;
  max-width: calc(100vw - 32px);
}
.entry-toast svg { width: 16px; height: 16px; flex-shrink: 0; }
.entry-toast.fade-out { animation: entry-toast-out 0.3s ease-in forwards; }
@keyframes entry-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(-12px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes entry-toast-out {
  from { opacity: 1; transform: translateX(-50%) translateY(0); }
  to   { opacity: 0; transform: translateX(-50%) translateY(-12px); }
}

/* ===== Phase 3c — billing chrome ===== */

/* Topbar trial pill (trial-warning state). Sits between brand
   block and topbar-actions. Tap → opens Settings → Billing.
   Subtle warning tone, not alarming — most users will see this
   for 3 days before transition to active subscription. */
.billing-trial-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 28px;
  padding: 0 12px;
  background: color-mix(in srgb, var(--warning) 14%, var(--card));
  color: var(--warning);
  border: 1px solid color-mix(in srgb, var(--warning) 36%, transparent);
  border-radius: 14px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: -0.01em;
  cursor: pointer;
  transition: background 140ms ease-out, transform 140ms ease-out;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.billing-trial-badge:hover { background: color-mix(in srgb, var(--warning) 20%, var(--card)); }
.billing-trial-badge:active { transform: scale(0.97); }
.billing-trial-badge:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Public demo banner (Day 22) — fixed strip at top of viewport when
   mobile/demo.html is active. Pushes the topbar down with a top margin
   on body.has-demo-banner so the existing PWA chrome layout doesn't
   need restructuring. Forest-green palette matches marketing brand. */
.demo-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  background: #0e1d18;
  color: #f6f3ee;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 13px;
  font-weight: 500;
  padding: 10px 16px;
  text-align: center;
  border-bottom: 2px solid #34d680;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
}
.demo-banner a {
  color: #34d680;
  font-weight: 700;
  text-decoration: none;
  margin-left: 6px;
}
.demo-banner a:hover { text-decoration: underline; }
body.has-demo-banner { padding-top: 44px; }
@media (max-width: 412px) {
  .demo-banner { font-size: 12px; padding: 8px 12px; }
  body.has-demo-banner { padding-top: 40px; }
}

@media (max-width: 380px) {
  .billing-trial-badge { padding: 0 8px; font-size: 11px; }
}

/* Grace banner — read-only mode warning above tab content.
   Inline (not sticky) so it scrolls away once the user is deep
   in their data. The CTA is the primary action; the muted text
   is the explanation. */
.billing-grace-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 12px 12px;
  padding: 12px 16px;
  background: color-mix(in srgb, var(--danger) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 28%, transparent);
  border-radius: 10px;
  font-size: 13px;
  color: var(--ink);
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.04);
}
.billing-grace-text { flex: 1; min-width: 0; line-height: 1.4; }
.billing-grace-text strong { color: var(--danger); font-weight: 700; }
.billing-grace-cta {
  flex-shrink: 0;
  height: 32px;
  padding: 0 14px;
  background: var(--danger);
  color: white;
  border: 1px solid var(--danger);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: background 140ms ease-out, transform 140ms ease-out;
}
.billing-grace-cta:hover { background: color-mix(in srgb, var(--danger) 88%, black); }
.billing-grace-cta:active { transform: scale(0.97); }
.billing-grace-cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.billing-grace-cta:disabled {
  background: var(--bg-2);
  color: var(--ink-3);
  border-color: var(--border);
  cursor: not-allowed;
  transform: none;
}
@media (max-width: 480px) {
  .billing-grace-banner { flex-direction: column; align-items: stretch; }
  .billing-grace-cta { width: 100%; }
}

/* Lockout screen — full-tab replacement when state === 'locked'.
   Shows a centered card with restart CTA. Owner-only — viewer/admin
   distinction is handled by the renderer (passes a different note
   to non-owners). */
.billing-lockout {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - 220px);
  padding: 24px 16px;
}
.billing-lockout-card {
  width: 100%;
  max-width: 420px;
  padding: 32px 24px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 4px 12px -2px rgba(15, 23, 42, 0.08);
  text-align: center;
}
.billing-lockout-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  margin: 0 auto 16px;
  background: color-mix(in srgb, var(--ink-3) 12%, var(--card));
  color: var(--ink-2);
  border-radius: 50%;
}
.billing-lockout-title {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.billing-lockout-sub {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2);
}
.billing-lockout-plan {
  margin: 0 0 20px;
  font-size: 14px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.billing-lockout-cta {
  width: 100%;
  height: 44px;
  margin-bottom: 16px;
}
.billing-lockout-owner-note {
  margin: 0 0 16px;
  padding: 12px;
  background: var(--bg-2);
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.4;
}

/* Settings → Billing card — active subscription view. */
.billing-card .billing-status {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 10px;
  margin-bottom: 12px;
  border-radius: 12px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.billing-status-success {
  background: color-mix(in srgb, var(--success) 14%, var(--card));
  color: var(--success);
  border: 1px solid color-mix(in srgb, var(--success) 32%, transparent);
}
.billing-status-warning {
  background: color-mix(in srgb, var(--warning) 14%, var(--card));
  color: var(--warning);
  border: 1px solid color-mix(in srgb, var(--warning) 32%, transparent);
}
.billing-status-danger {
  background: color-mix(in srgb, var(--danger) 14%, var(--card));
  color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 32%, transparent);
}
.billing-status-neutral {
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
}
.billing-plan {
  margin: 0 0 8px;
  font-size: 14px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.billing-note {
  margin: 0 0 16px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-2);
}
.billing-action {
  width: 100%;
  height: 44px;
  margin-top: 4px;
  margin-bottom: 8px;
}

/* Tier 2 #13 — Weekly nudge engine. Bell icon in topbar + bottom-sheet
   drawer + Settings → Notifications surface with toggle / test trigger /
   history. */
.nudge-bell-btn {
  position: relative;
}
.nudge-bell-badge {
  position: absolute;
  top: 4px; right: 4px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--ink-3);
  border: 1.5px solid var(--card);
  pointer-events: none;
}
.nudge-bell-badge-red    { background: #b91c1c; }
.nudge-bell-badge-yellow { background: #b45309; }
.nudge-bell-badge-green  { background: #15803d; }

.nudge-drawer { padding: 4px 4px 16px; }
.nudge-drawer h2 { margin: 0 0 6px; font-size: 18px; font-weight: 700; }
.nudge-drawer .sheet-sub { margin: 0 0 16px; }
.nudge-drawer-empty { color: var(--ink-3); font-size: 14px; padding: 20px 0; text-align: center; }
.nudge-drawer-list { display: flex; flex-direction: column; gap: 12px; }

.nudge-card {
  border-left: 4px solid var(--border);
  padding: 12px 14px;
  background: var(--bg-2);
  border-radius: 8px;
}
.nudge-card-red    { border-left-color: #b91c1c; }
.nudge-card-yellow { border-left-color: #b45309; }
.nudge-card-green  { border-left-color: #15803d; }
.nudge-card-sev {
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 6px;
}
.nudge-card-red    .nudge-card-sev { color: #b91c1c; }
.nudge-card-yellow .nudge-card-sev { color: #b45309; }
.nudge-card-green  .nudge-card-sev { color: #15803d; }
.nudge-card-title { font-size: 15px; font-weight: 700; color: var(--ink); margin-bottom: 4px; line-height: 1.35; }
.nudge-card-body  { font-size: 13px; color: var(--ink-2); line-height: 1.5; margin-bottom: 10px; }
.nudge-card-actions { display: flex; gap: 8px; align-items: center; }
.nudge-card-view, .nudge-card-dismiss {
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: 6px 14px; font: inherit; font-size: 13px; font-weight: 600;
  color: var(--ink); cursor: pointer; min-height: 36px;
}
.nudge-card-view { background: var(--accent); color: var(--brand); border-color: var(--accent); }
.nudge-card-dismiss { color: var(--ink-3); }
.nudge-card-dismiss:hover { color: var(--ink); }

/* Demo-mode: whole card becomes the tap surface (View/Dismiss buttons
   are hidden on demo since viewer role can't write). Subtle hover state
   gives the user an "I can tap this" affordance without changing the
   resting visual register. */
.nudge-card-tappable {
  cursor: pointer;
  transition: background 0.12s;
}
.nudge-card-tappable:hover,
.nudge-card-tappable:active { background: var(--border); }

/* Settings → Notifications surface */
.notifications-card .sheet-sub { margin: 0 0 16px; }
.notifications-demo-explainer {
  margin: 0 0 16px;
  padding: 12px 14px;
  background: var(--bg-2);
  border: 1px dashed var(--border);
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.notifications-toggle-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-2);
  cursor: pointer;
  margin-bottom: 16px;
}
.notifications-toggle-text { flex: 1 1 auto; }
.notifications-toggle-label { font-size: 14px; font-weight: 600; color: var(--ink); }
.notifications-toggle-sub { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.notifications-toggle-input { width: 20px; height: 20px; accent-color: var(--accent-on-light); cursor: pointer; flex-shrink: 0; }

.notifications-test-row { margin-bottom: 20px; }
.notifications-test-row .btn-primary { width: 100%; }
.notifications-test-note { font-size: 12px; color: var(--ink-3); margin: 8px 0 0; line-height: 1.5; }

/* #340 v2 — admin-only Preview + Criteria buttons block */
.notifications-admin-block {
  margin-top: 16px;
  padding: 12px;
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  background: var(--bg-2);
}
.notifications-admin-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent-on-light); margin-bottom: 8px;
}
.notifications-admin-buttons {
  display: flex; gap: 8px; flex-wrap: wrap;
}
.notifications-admin-btn {
  flex: 1; min-width: 180px;
  padding: 10px 12px;
  font-size: 13px; font-weight: 600;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--border-2); border-radius: 8px;
  cursor: pointer;
}
.notifications-admin-btn:hover { background: var(--bg-2); }
.notifications-admin-btn:disabled { opacity: 0.6; cursor: not-allowed; }
.notifications-admin-hint {
  font-size: 12px; color: var(--ink-3); margin: 8px 0 0; line-height: 1.4;
}

/* Preview sheet — phantom AI rewrites for every template */
.preview-summary {
  font-size: 13px; color: var(--ink-2); margin: 8px 0 16px;
  padding: 10px 12px; background: var(--bg-2); border-radius: 6px;
}
.preview-list {
  max-height: 60vh; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px;
}
.preview-row {
  padding: 10px 12px;
  margin-bottom: 10px;
  background: var(--card); border-left: 4px solid var(--border);
  border-radius: 4px;
}
.preview-row.preview-red    { border-left-color: #b91c1c; }
.preview-row.preview-yellow { border-left-color: #b45309; }
.preview-row.preview-green  { border-left-color: #15803d; }
.preview-row-head {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 6px; font-size: 11px; color: var(--ink-3);
}
.preview-badge {
  display: inline-block; padding: 2px 6px; border-radius: 3px;
  font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  font-size: 10px;
}
.preview-badge-phantom { background: var(--accent-on-light); color: var(--card); }
.preview-badge-status  { background: var(--ink-3); color: var(--card); }
.preview-template-id { font-family: monospace; font-size: 11px; color: var(--ink-3); }
.preview-category    { font-size: 11px; color: var(--ink-3); margin-left: auto; }
.preview-row-headline {
  font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 4px;
  line-height: 1.35;
}
.preview-row-body { font-size: 13px; color: var(--ink-2); line-height: 1.5; margin-bottom: 6px; }
.preview-row-action { font-size: 12px; color: var(--ink); line-height: 1.5; padding: 6px 8px; background: var(--bg-2); border-radius: 4px; }

/* Criteria-list sheet — registry metadata with filters */
.criteria-summary {
  font-size: 13px; color: var(--ink-2); margin: 8px 0 12px;
  padding: 10px 12px; background: var(--bg-2); border-radius: 6px;
}
.criteria-by-cat { font-size: 11px; color: var(--ink-3); }
.criteria-filters {
  display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;
}
.criteria-filters select {
  padding: 6px 10px;
  font-size: 13px;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--border-2); border-radius: 6px;
}
.criteria-list {
  max-height: 60vh; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px;
}
.criteria-empty { font-size: 13px; color: var(--ink-3); padding: 16px; text-align: center; }
.criteria-row {
  padding: 10px 12px;
  margin-bottom: 8px;
  background: var(--card); border: 1px solid var(--border); border-radius: 4px;
}
.criteria-row-head {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 6px;
}
.criteria-template-id { font-family: monospace; font-size: 11px; color: var(--ink); font-weight: 600; }
.criteria-category    { font-size: 11px; color: var(--ink-3); }
.criteria-status {
  display: inline-block; padding: 2px 6px; border-radius: 3px;
  font-weight: 700; letter-spacing: 0.04em; font-size: 10px;
}
.criteria-status-live    { background: #15803d; color: var(--card); }
.criteria-status-phantom { background: var(--ink-3); color: var(--card); }
.criteria-seasonal {
  display: inline-block; padding: 2px 6px; border-radius: 3px;
  font-weight: 700; letter-spacing: 0.04em; font-size: 10px;
  background: #b45309; color: var(--card);
}
.criteria-row-severity { margin-bottom: 6px; }
.criteria-sev-pill {
  display: inline-block; padding: 1px 6px; margin-right: 4px;
  border-radius: 3px; font-size: 10px; font-weight: 600;
  text-transform: uppercase;
}
.criteria-sev-red    { background: #b91c1c; color: var(--card); }
.criteria-sev-yellow { background: #b45309; color: var(--card); }
.criteria-sev-green  { background: #15803d; color: var(--card); }
.criteria-row-trigger { font-size: 13px; color: var(--ink-2); line-height: 1.5; margin-bottom: 6px; }
.criteria-row-meta {
  font-size: 12px; color: var(--ink-3); display: flex; flex-wrap: wrap; gap: 12px;
}

/* #341 v3 — Approve button on phantom preview rows */
.preview-approve-btn {
  margin-left: auto;
  padding: 4px 10px;
  font-size: 11px; font-weight: 700;
  background: var(--accent-on-light); color: var(--card);
  border: none; border-radius: 4px;
  cursor: pointer;
  letter-spacing: 0.02em;
}
.preview-approve-btn:hover { opacity: 0.9; }
.preview-approve-btn:disabled { opacity: 0.6; cursor: not-allowed; }
.preview-approve-btn-done { background: var(--success, #15803d); }

.preview-badge-status-case { background: #15803d; }
.preview-badge-status-ok { background: var(--accent-on-light); }
.preview-badge-status-fallback { background: var(--ink-3); }
.preview-badge-status-skipped { background: var(--ink-4, #6a7570); }
.preview-badge-status-error { background: #b91c1c; }

/* #341 v3 — Cases library sheet */
.cases-summary {
  font-size: 13px; color: var(--ink-2); margin: 8px 0 12px;
  padding: 10px 12px; background: var(--bg-2); border-radius: 6px;
}
.cases-by-sev { font-size: 11px; color: var(--ink-3); }
.cases-filters {
  display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;
}
.cases-filters select {
  padding: 6px 10px;
  font-size: 13px;
  background: var(--card); color: var(--ink);
  border: 1px solid var(--border-2); border-radius: 6px;
}
.cases-list {
  max-height: 60vh; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 6px;
  padding: 8px;
}
.cases-empty { font-size: 13px; color: var(--ink-3); padding: 16px; text-align: center; }
.cases-row {
  padding: 10px 12px;
  margin-bottom: 10px;
  background: var(--card); border-left: 4px solid var(--border);
  border-radius: 4px;
}
.cases-row.cases-red    { border-left-color: #b91c1c; }
.cases-row.cases-yellow { border-left-color: #b45309; }
.cases-row.cases-green  { border-left-color: #15803d; }
.cases-row-head {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin-bottom: 6px;
}
.cases-template-id { font-family: monospace; font-size: 11px; color: var(--ink); font-weight: 600; }
.cases-uses { font-size: 11px; color: var(--ink-3); margin-left: auto; }
.cases-status {
  display: inline-block; padding: 2px 6px; border-radius: 3px;
  font-weight: 700; letter-spacing: 0.04em; font-size: 10px;
}
.cases-status-active  { background: #15803d; color: var(--card); }
.cases-status-retired { background: var(--ink-3); color: var(--card); }
.cases-source-badge {
  display: inline-block; padding: 2px 6px; border-radius: 3px;
  font-size: 10px; color: var(--ink-3); background: var(--bg-2);
}
.cases-row-headline {
  font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 4px;
  line-height: 1.35;
}
.cases-row-body { font-size: 13px; color: var(--ink-2); line-height: 1.5; margin-bottom: 6px; }
.cases-row-action { font-size: 12px; color: var(--ink); line-height: 1.5; padding: 6px 8px; background: var(--bg-2); border-radius: 4px; margin-bottom: 6px; }
.cases-row-meta {
  font-size: 11px; color: var(--ink-3); display: flex; flex-wrap: wrap; gap: 12px;
}
.cases-retire-btn {
  padding: 3px 8px;
  font-size: 11px; font-weight: 600;
  background: var(--card); color: var(--ink-2);
  border: 1px solid var(--border-2); border-radius: 4px;
  cursor: pointer;
}
.cases-retire-btn:hover { background: var(--bg-2); }
.cases-retire-btn:disabled { opacity: 0.6; cursor: not-allowed; }

.notifications-history { border-top: 1px solid var(--border); padding-top: 16px; }
.notifications-history-title {
  font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent-on-light); margin-bottom: 12px;
}
.notifications-history-empty { font-size: 13px; color: var(--ink-3); }
.notifications-history-row {
  border-left: 3px solid var(--border);
  padding: 8px 12px;
  background: var(--bg-2);
  border-radius: 6px;
  margin-bottom: 6px;
}
.notifications-history-red    { border-left-color: #b91c1c; }
.notifications-history-yellow { border-left-color: #b45309; }
.notifications-history-green  { border-left-color: #15803d; }
.notifications-history-row-head { display: flex; gap: 8px; align-items: center; margin-bottom: 4px; }
.notifications-history-date { font-size: 11px; font-weight: 600; color: var(--ink-3); }
.notifications-history-status {
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 2px 6px; border-radius: 999px;
  background: var(--bg); color: var(--ink-3); border: 1px solid var(--border);
}
.notifications-history-status-clicked   { color: #15803d; border-color: color-mix(in srgb, #15803d 30%, var(--border)); }
.notifications-history-status-dismissed { color: var(--ink-3); }
.notifications-history-status-email-sent { color: var(--accent-on-light); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.notifications-history-status-active    { color: var(--accent-on-light); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.notifications-history-row-title { font-size: 13px; font-weight: 600; color: var(--ink); }

/* Tier 2 #19 — Beta feedback forum (Settings → Community).
   Reddit-style in-app surface: category grid → thread list → thread detail
   + comments + compose forms. Moderator chrome toggles via window
   .IS_FORUM_MODERATOR (hydrated at load). */
.forum-card { padding: 0; }
.forum-card #forum-mount { padding: 16px; }
.forum-category-grid {
  display: grid; gap: 10px;
  grid-template-columns: 1fr;
  margin-top: 14px;
}
.forum-category-card {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 6px;
  padding: 14px 16px;
  background: var(--card);
  border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; text-align: left;
  font: inherit; color: inherit;
  transition: border-color 0.12s, background 0.12s;
  min-height: 64px;
}
.forum-category-card:hover, .forum-category-card:focus-visible {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 5%, var(--card));
  outline: none;
}
.forum-category-name { font-size: 15px; font-weight: 700; color: var(--ink); }
.forum-category-desc { font-size: 13px; color: var(--ink-2); line-height: 1.4; }
.forum-category-meta { font-size: 11px; color: var(--ink-3); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }

.forum-back-link {
  background: transparent; border: none;
  color: var(--accent-on-light); cursor: pointer;
  font: inherit; font-size: 13px; padding: 6px 0;
  margin-bottom: 10px;
}
.forum-back-link:hover { text-decoration: underline; }
.forum-category-header { margin-bottom: 14px; }
.forum-category-title { font-size: 18px; font-weight: 700; margin: 0 0 4px; color: var(--ink); }
.forum-category-blurb { font-size: 13px; color: var(--ink-2); margin: 0; line-height: 1.4; }
.forum-new-thread-btn { width: 100%; margin-bottom: 16px; }

.forum-thread-list { display: flex; flex-direction: column; gap: 8px; }
.forum-thread-row {
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px 14px;
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; text-align: left;
  font: inherit; color: inherit;
}
.forum-thread-row:hover, .forum-thread-row:focus-visible {
  border-color: var(--accent); outline: none;
}
.forum-thread-row-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.forum-thread-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.forum-thread-row-meta { font-size: 12px; color: var(--ink-3); display: flex; gap: 4px; flex-wrap: wrap; }
.forum-pin { font-size: 14px; }
.forum-empty { color: var(--ink-3); font-size: 13px; padding: 14px 0; }

.forum-status-badge {
  display: inline-flex; align-items: center;
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px;
  border: 1px solid var(--border);
}
.forum-status-open      { background: color-mix(in srgb, var(--ink-3) 10%, var(--card)); color: var(--ink-2); }
.forum-status-progress  { background: color-mix(in srgb, var(--accent) 16%, var(--card)); color: var(--accent-on-light); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.forum-status-resolved  { background: color-mix(in srgb, #15803d 14%, var(--card)); color: #15803d; border-color: color-mix(in srgb, #15803d 32%, var(--border)); }
.forum-status-wontfix   { background: color-mix(in srgb, #b91c1c 12%, var(--card)); color: #b91c1c; border-color: color-mix(in srgb, #b91c1c 32%, var(--border)); }
.forum-status-shipped   { background: color-mix(in srgb, #6d28d9 14%, var(--card)); color: #6d28d9; border-color: color-mix(in srgb, #6d28d9 32%, var(--border)); }

.forum-locked-tag {
  font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--ink-3) 16%, var(--card));
  color: var(--ink-3); border: 1px solid var(--border);
}

.forum-thread-detail { margin-top: 4px; }
.forum-thread-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.forum-thread-detail-title { font-size: 18px; font-weight: 700; margin: 0; color: var(--ink); }
.forum-thread-meta { font-size: 12px; color: var(--ink-3); margin-bottom: 12px; }
.forum-thread-body { font-size: 14px; line-height: 1.55; color: var(--ink); white-space: pre-wrap; margin-bottom: 14px; }
.forum-thread-actions { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; }
.forum-vote-btn {
  background: var(--bg-2); border: 1px solid var(--border); border-radius: 999px;
  padding: 6px 14px; font: inherit; font-size: 13px; font-weight: 600;
  color: var(--ink-2); cursor: pointer;
  min-height: 36px;
}
.forum-vote-btn.is-voted {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent-on-light);
}
.forum-action-link {
  background: transparent; border: none; cursor: pointer; font: inherit;
  font-size: 12px; color: var(--ink-3); padding: 4px 8px; min-height: 28px;
}
.forum-action-link:hover { color: var(--ink); }
.forum-action-delete:hover { color: var(--danger); }

.forum-mod-chrome {
  padding: 12px;
  border: 1px dashed var(--border); border-radius: 8px;
  background: var(--bg-2);
  margin-bottom: 16px;
}
.forum-mod-chrome-label { font-size: 10px; font-weight: 700; color: var(--ink-3); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 8px; }
.forum-mod-chrome-buttons { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.forum-mod-btn {
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: 6px 12px; font: inherit; font-size: 12px; font-weight: 600;
  color: var(--ink-2); cursor: pointer; min-height: 32px;
}
.forum-mod-btn:hover { border-color: var(--accent); color: var(--ink); }
.forum-mod-btn-danger:hover { background: var(--bg-2); border-color: var(--border-2); color: var(--ink); }
.forum-mod-status {
  font: inherit; font-size: 12px;
  padding: 6px 8px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--card); color: var(--ink);
  min-height: 32px;
}

.forum-comments { margin-top: 12px; }
.forum-comments-h { font-size: 14px; font-weight: 700; margin: 0 0 10px; color: var(--ink); }
.forum-comment { padding: 10px 12px; background: var(--bg-2); border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; }
.forum-comment-meta { font-size: 12px; color: var(--ink-3); margin-bottom: 4px; }
.forum-comment-author { font-weight: 600; color: var(--ink-2); }
.forum-comment-body { font-size: 13px; line-height: 1.5; color: var(--ink); white-space: pre-wrap; }
.forum-comment-actions { margin-top: 4px; display: flex; gap: 6px; }

.forum-comment-form { margin-top: 12px; }
.forum-comment-textarea { width: 100%; min-height: 70px; resize: vertical; box-sizing: border-box; font-family: inherit; }
.forum-comment-form-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 6px; }
.forum-char-counter { font-size: 11px; color: var(--ink-3); }

.forum-compose { padding: 4px; }
.forum-compose-textarea { width: 100%; resize: vertical; box-sizing: border-box; font-family: inherit; }
.forum-compose-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }

/* Tier 1 #7 — Cancel subscription link on Settings → Billing's active
   state. Intentionally low visual weight per Hanna's "make it somewhat
   difficult" spec — primary action stays "Manage subscription"; cancel
   is a small text link below it, surfacing red on hover so the
   destructive intent reads on focus. */
.billing-cancel-link {
  display: block;
  margin: 12px auto 0;
  background: transparent;
  border: none;
  color: var(--ink-3);
  font-size: 13px;
  font-weight: 500;
  text-decoration: underline;
  cursor: pointer;
  padding: 8px 10px;
  min-height: 40px;
}
.billing-cancel-link:hover,
.billing-cancel-link:focus-visible {
  color: var(--danger);
  outline: none;
}
.billing-cancel-link:active { color: var(--danger); }

/* Tier 1 #7 — Cancellation flow sheets (3-screen deactivation friction).
   Shared chrome across Screen 1 / 2 / 3. Reuses the canonical
   .sheet-action-bar at the bottom of each sheet for button layout. */
.cancel-flow-card { padding: 8px 4px 16px; }
.cancel-flow-h {
  margin: 0 0 12px;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.cancel-flow-sub {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-2);
}
.cancel-flow-options {
  display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-2);
  margin-bottom: 16px;
}
.cancel-flow-option {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  cursor: pointer; user-select: none;
  min-height: 44px;
  font-size: 14px;
  color: var(--ink);
}
.cancel-flow-option:last-child { border-bottom: 0; }
.cancel-flow-checkbox {
  width: 18px; height: 18px;
  accent-color: var(--accent-on-light);
  cursor: pointer;
  flex-shrink: 0;
}
.cancel-flow-textarea-label {
  display: block;
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}
.cancel-flow-textarea {
  width: 100%;
  font-family: inherit;
  font-size: 14px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink);
  resize: vertical;
  min-height: 80px;
  box-sizing: border-box;
}
.cancel-flow-textarea:focus-visible {
  outline: none;
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-on-light) 18%, transparent);
}
.cancel-flow-error {
  margin: 12px 0 0;
  padding: 10px 12px;
  background: color-mix(in srgb, var(--danger) 12%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
  color: var(--danger);
  border-radius: 8px;
  font-size: 13px;
}
.cancel-flow-note {
  margin: -4px 0 16px;
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
}
.cancel-flow-card .sheet-action-bar {
  margin-top: 16px;
}

/* =============================================================================
   #269 Phase 1B Part 2 — Practice Health tab styles
   =============================================================================
   Tile renderers: renderReappointmentRateTile, renderVendorsTile.
   Drill renderer: 'reappointment-rate' (period picker + summary stats +
   payer segment breakdown + lost-patient worklist).

   Reappointment rate color tiers:
     - green:  >= 80%  (industry-strong; surface as health signal)
     - yellow: 60-79%  (Hanna's April was 46.92% — surfaces as red)
     - red:    < 60%   (lost-patient outreach actionable)
   ============================================================================= */

/* --- Practice Health tab header strip ----------------------------------- */
.practice-health-header {
  padding: 8px 0 16px;
}
.practice-health-header h2 {
  margin: 0 0 4px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.practice-health-sub {
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.45;
}

/* --- Reappointment Rate tile -------------------------------------------- */
.practice-health-tile .card-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.reappointment-tile-period {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
/* Legacy single-column .reappointment-headline retained for the
   partial-data state (no rate yet — renders bare em-dash). The main
   tile path uses .reappointment-body below. */
.reappointment-headline {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin: 6px 0 4px;
}
.reappointment-rate {
  font-size: 44px;
  font-weight: 700;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
.reappointment-rate-green   { color: #15803d; }
.reappointment-rate-yellow  { color: #b45309; }
.reappointment-rate-red     { color: #b91c1c; }
.reappointment-rate-unknown { color: var(--ink-3); }
/* #283 follow-up #3 — 2-column body. LEFT (40% min): big rate %.
   RIGHT (1fr): segment splits stacked above delta. Compresses tile
   height vs the prior single-column stack (rate / subtitle / segments
   / delta = 4 stacked lines → 2-col with rate ≈ height of stats). */
.reappointment-body {
  display: grid;
  grid-template-columns: minmax(120px, auto) 1fr;
  gap: 16px;
  align-items: center;
  margin: 6px 0 0;
}
.reappointment-body-left {
  display: flex;
  align-items: baseline;
}
.reappointment-body-right {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.reappointment-subline {
  font-size: 13px;
  color: var(--ink-3);
  margin-bottom: 10px;
}
.reappointment-segments {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.reappointment-delta {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
/* #283 follow-up #4 — fallback period qualifier when delta line is
   suppressed (no previous month OR <0.05pp change). Subtle muted
   single-line period label so the tile's anchor is always surfaced. */
.reappointment-period-qualifier {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.02em;
}
.reappointment-delta-up   { color: #15803d; }
.reappointment-delta-down { color: #b91c1c; }

/* Placeholder + partial-data states */
.reappointment-tile-placeholder .reappointment-placeholder {
  padding: 20px 0 8px;
  text-align: center;
}
.reappointment-placeholder-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 6px;
}
.reappointment-placeholder-sub {
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.5;
  max-width: 280px;
  margin: 0 auto;
}

/* Day 28 follow-up — selected-period empty state. Fires when the user
   picks a month via the period selector and that month's snapshot has
   reappointment_rate=null (CSV-imported months had only aggregate
   headlines; pre-OD-API months are NULL entirely). Same visual register
   as the placeholder above but anchored to the selected month. */
.reappointment-empty {
  padding: 18px 0 6px;
  text-align: center;
}
.reappointment-empty-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 6px;
  letter-spacing: -0.005em;
}
.reappointment-empty-sub {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
  max-width: 320px;
  margin: 0 auto;
}

/* --- Reappointment Rate drill sheet ------------------------------------- */
.reappointment-period-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}
.reappointment-period-row .pill.is-disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.reappointment-drill-summary {
  margin-bottom: 14px;
}
.reappointment-drill-headline {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 12px;
}
.reappointment-drill-headline .reappointment-rate {
  font-size: 48px;
}
.reappointment-rate-label {
  font-size: 13px;
  color: var(--ink-3);
  font-weight: 500;
}
.reappointment-drill-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  border-top: 1px solid var(--border);
  padding-top: 14px;
}
.reappointment-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.reappointment-stat-value {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.reappointment-stat-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
@media (min-width: 480px) {
  .reappointment-drill-stats { grid-template-columns: repeat(4, 1fr); }
}

/* Payer segment card */
.reappointment-segments-card {
  margin-bottom: 14px;
}
.reappointment-segments-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
.reappointment-segment {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.reappointment-segment-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.reappointment-segment-rate {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
.reappointment-segment-insight {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.45;
}

/* Lost-patient worklist CSS removed Day 22 evening — Path 1 aggregate-
   only operating mode. The UI surface that consumed these classes
   (per-row lost-patient worklist on the Reappointment Rate drill) no
   longer renders. Per-row data continues to flow into the DB; only
   the UI surfacing was cut. See CLAUDE.md "Aggregate-only operating
   mode (Path 1)" for the decision + re-enable trigger. Restore from
   git history at commit 9618124 (or earlier) when the worklist
   rebuilds post-Supabase-HIPAA-tier-upgrade. */

/* --- Top Vendors tile (renderVendorsTile) -------------------------------- */
.vendors-tile .card-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.vendors-tile .card-meta {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.vendors-tile-list {
  display: flex;
  flex-direction: column;
}
.vendors-tile-viewall {
  /* Day 28 PM polish — typography aligned with the canonical
     tile-footer-link standard (12px / 600 / --accent-on-light) used
     by other "Show all" surfaces (Carrier Performance, Carrier
     Detail Table). Pre-fix bug: `font: inherit` AFTER `font-size: 13px`
     made the shorthand override the explicit size, so the link was
     rendering at the inherited card font (~15-16px) instead of the
     intended 13px. Dropped `font: inherit` entirely — font-family
     still inherits via default cascade. Color also shifted from
     --accent (lime, fails WCAG AA on cream — same issue as auth-
     link-fallback per Day 26 follow-up) → --accent-on-light
     (#178350, 4.7:1 on cream). */
  display: block;
  width: 100%;
  text-align: center;
  background: transparent;
  border: none;
  padding: 12px 8px 4px;
  color: var(--accent-on-light);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.vendors-tile-viewall:hover,
.vendors-tile-viewall:focus-visible { color: var(--brand); }

/* =============================================================================
   #269 Phase 1B Part 2 — Practice Health arena (Tiles 1, 3-11)
   =============================================================================
   Shared tile chrome (.ph-tile, .ph-tile-body) + per-tile-family chrome
   (bar chart wraps, insight cards, KPI pills, payer segment grid,
   AR aging stacked bar, carrier detail table, new-patient growth
   headline). All read from theme tokens so dark themes work.
   ============================================================================= */

.ph-tile .card-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.ph-tile .card-meta {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ph-tile-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ph-chart-wrap {
  position: relative;
  width: 100%;
}
.ph-chart-wrap canvas { width: 100% !important; }
.ph-chart-short  { height: 200px; }
.ph-chart-medium { height: 260px; }
.ph-chart-tall   { height: 340px; }

/* #283 follow-up — KPI Summary locked to 2x2 grid at all viewports
   (Patients pill dropped → 4 tiles). Net Production retains
   visual emphasis via accent-tinted background + border + slightly
   larger value font; sits top-right in the natural source order
   (Gross / Net / Write-offs / Avg net per patient).
   #283 follow-up #3 — grid-template-rows locked to 1fr 1fr so both
   rows equalize to the taller row's max-content (i.e., the row
   containing the emphasis pill propagates its height to the other
   row). All 4 tiles render at identical heights. justify-content:
   space-between on the pill flex column anchors the label to the top
   and the value to the bottom, so the larger emphasis font doesn't
   shift its baseline relative to neighbors. */
.ph-kpi-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-template-rows: 1fr 1fr;
  gap: 8px;
}
.ph-kpi-pill {
  padding: 12px;
  border-radius: 12px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 4px;
  min-width: 0;
  min-height: 68px;
}
.ph-kpi-emphasis {
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
}
.ph-kpi-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ph-kpi-emphasis .ph-kpi-label { color: var(--accent-on-light); }
.ph-kpi-value {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ph-kpi-emphasis .ph-kpi-value {
  font-size: 22px;
  color: var(--accent-on-light);
}
.ph-kpi-sub {
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* #283 — CFO Insights stays 2x2 down to 360px viewport. Below that
   (rare — iPhone SE 1st gen / iPhone 5), single-column fallback. */
.ph-insight-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
@media (max-width: 360px) {
  .ph-insight-grid { grid-template-columns: 1fr; }
}
.ph-insight-card {
  padding: 12px 16px;
  border-radius: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-left-width: 4px;
}
.ph-insight-green   { border-left-color: #15803d; }
.ph-insight-yellow  { border-left-color: #b45309; }
.ph-insight-red     { border-left-color: #b91c1c; }
.ph-insight-neutral { border-left-color: var(--ink-3); }
.ph-insight-headline {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
  margin-bottom: 4px;
}
.ph-insight-body {
  font-size: 12px;
  color: var(--ink-2);
  line-height: 1.5;
}

.ph-segment-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}
.ph-segment-card {
  padding: 16px;
  border-radius: 10px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ph-segment-commercial {
  background: color-mix(in srgb, #4338ca 8%, var(--card));
  border-color: color-mix(in srgb, #4338ca 25%, var(--border));
}
.ph-segment-medicaid {
  background: color-mix(in srgb, #b45309 8%, var(--card));
  border-color: color-mix(in srgb, #b45309 25%, var(--border));
}
.ph-segment-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ph-segment-net {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
}
.ph-segment-meta {
  font-size: 12px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.ph-segment-insight {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
}

.ph-ar-headline {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 4px;
}
.ph-ar-total {
  font-size: 28px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.ph-ar-total-label {
  font-size: 13px;
  color: var(--ink-3);
}
.ph-ar-stacked {
  display: flex;
  width: 100%;
  height: 22px;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--bg-2);
}
.ph-ar-segment { min-width: 0; }
.ph-ar-fresh   { background: #15803d; }
.ph-ar-middle  { background: #b45309; }
.ph-ar-stale   { background: #b91c1c; }
.ph-ar-fresh-dot   { background: #15803d; }
.ph-ar-middle-dot  { background: #b45309; }
.ph-ar-stale-dot   { background: #b91c1c; }
.ph-ar-legend {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 4px;
}
.ph-ar-legend-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
}
.ph-ar-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 auto;
}
.ph-ar-legend-label {
  flex: 1 1 auto;
  color: var(--ink-2);
}
.ph-ar-legend-value {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--ink);
}
.ph-ar-legend-pct {
  color: var(--ink-3);
  font-weight: 500;
  margin-left: 6px;
}
.ph-ar-warning {
  margin-top: 4px;
  padding: 10px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, #b91c1c 10%, transparent);
  border: 1px solid color-mix(in srgb, #b91c1c 30%, transparent);
  color: #991b1b;
  font-size: 13px;
  line-height: 1.5;
}

.ph-carrier-table-wrap {
  overflow-x: auto;
  margin: 0 -4px;
}
.ph-carrier-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.ph-carrier-th {
  padding: 8px 10px;
  text-align: right;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.ph-carrier-th.ph-align-left { text-align: left; }
.ph-carrier-th.is-sorted { color: var(--accent-on-light); }
.ph-carrier-th .ph-sort-arrow {
  font-size: 9px;
  margin-left: 2px;
}
.ph-carrier-row td {
  padding: 8px 10px;
  text-align: right;
  border-bottom: 1px solid var(--border);
  color: var(--ink);
}
.ph-carrier-row td.ph-align-left {
  text-align: left;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.ph-carrier-row:hover { background: var(--bg-2); }
.ph-align-left  { text-align: left; }
.ph-align-right { text-align: right; }

/* #283 follow-up #4 — at 412px primary target, tighten cell padding +
   ellipsis on the Carrier name column so 5 cols fit without horizontal
   scroll. Wrap stays disabled on cell content so column widths don't
   jitter as the user scrolls + sorts. */
@media (max-width: 412px) {
  .ph-carrier-th { padding: 8px 6px; font-size: 10px; letter-spacing: 0.03em; }
  .ph-carrier-row td { padding: 8px 6px; font-size: 12px; }
  .ph-carrier-row td.ph-align-left {
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}
@media (max-width: 360px) {
  .ph-carrier-th { padding: 6px 4px; }
  .ph-carrier-row td { padding: 6px 4px; }
  .ph-carrier-row td.ph-align-left { max-width: 90px; }
}

.ph-growth-headline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 4px;
}
.ph-growth-number {
  font-size: 28px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.ph-growth-label {
  font-size: 13px;
  color: var(--ink-3);
}
.ph-growth-delta {
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  padding: 2px 8px;
  border-radius: 999px;
}
.ph-growth-delta.up {
  background: color-mix(in srgb, #15803d 12%, transparent);
  color: #15803d;
}
.ph-growth-delta.down {
  background: color-mix(in srgb, #b91c1c 12%, transparent);
  color: #b91c1c;
}
.ph-growth-delta.partial {
  background: color-mix(in srgb, var(--ink-4) 12%, transparent);
  color: var(--ink-3);
  font-weight: 500;
}
/* #283 follow-up #4 — fallback footnote when fewer than 12 months of
   data are populated. Surfaces "More history will appear as data
   accumulates" so the user knows the 3-bar surface isn't the final
   state. Disappears automatically once items.length >= 12. */
.ph-growth-footnote {
  margin-top: 8px;
  font-size: 11px;
  font-style: italic;
  color: var(--ink-3);
  text-align: center;
}

.ph-carrier-context {
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: 8px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}

/* =============================================================================
   #269 Phase 1B Part 3 — Hygiene Performance tile + AR Aging rewrite
   =============================================================================
   Hygiene scorecard grid (2-col on wide, 1-col on narrow) + 5-bucket
   AR aging list with severity-tinted left border per row.
   ============================================================================= */

/* ----- Hygiene Performance tile ----- */
/* #283 follow-up — Hygiene Performance cards rebuilt as horizontal
   left/right layout. ~half the prior card height. */
.ph-hygiene-grid {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ph-hygiene-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px;
  background: var(--bg-2);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 16px;
  align-items: center;
}
.ph-hygiene-card-left {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.ph-hygiene-name {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ph-hygiene-net {
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ph-hygiene-context {
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.ph-hygiene-card-right {
  display: flex;
  flex-direction: column;
  gap: 6px;
  text-align: right;
  flex: 0 0 auto;
}
.ph-hygiene-metric {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.ph-hygiene-metric-value {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ph-hygiene-metric-label {
  font-size: 10px;
  color: var(--ink-3);
  font-weight: 500;
  letter-spacing: 0.02em;
}
.ph-hygiene-insight {
  margin-top: 4px;
  padding: 10px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-left: 3px solid var(--accent-on-light);
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}

/* ----- AR Aging — Part 3 rewrite ----- */
/* #283 follow-up #2 — 3-column horizontal summary replaces the prior
   vertical stacked headline.
   #283 follow-up #3 — sub-text dropped (now 2 lines per cell: $ +
   label). Label rendered at 12px / 700 / cell-color so it reads as a
   pairing with the $ number, not detached muted chrome. "Current" →
   "Collectible" rename happens JS-side; styling unchanged. */
.ph-ar-summary {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-2);
}
.ph-ar-summary-cell {
  padding: 12px 10px;
  text-align: center;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.ph-ar-summary-cell:last-child { border-right: none; }
.ph-ar-summary-value {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ph-ar-summary-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
}
.ph-ar-summary-current .ph-ar-summary-value,
.ph-ar-summary-current .ph-ar-summary-label { color: #15803d; }
.ph-ar-summary-risk .ph-ar-summary-value,
.ph-ar-summary-risk .ph-ar-summary-label    { color: #b91c1c; }


/* #283 follow-up #2 — AR Aging 6-column × 4-row table. Leftmost column
   is the row-label gutter (Aging / Balance / Patients / Share); the
   remaining 5 columns are the age buckets (0-30 / 31-60 / 61-90 /
   91-180 / 180+). Severity tint rides on bucket-header top border;
   row-label column stays neutral so it doesn't compete for attention
   with bucket headers. Column-gap: 8px on the .ph-ar-table-row grid
   separates adjacent buckets so 31-60 / 61-90 don't visually crowd
   (was a polish nit on the 5-col variant). Borders between cells
   removed in favor of pure column-gap whitespace — cleaner reading. */
.ph-ar-table {
  display: flex;
  flex-direction: column;
  gap: 2px;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-2);
  padding: 0 8px;
}
.ph-ar-table-row {
  display: grid;
  grid-template-columns: 60px repeat(5, 1fr);
  column-gap: 8px;
}
.ph-ar-table-header { background: color-mix(in srgb, var(--ink) 4%, transparent); margin: 0 -8px; padding: 0 8px; }
.ph-ar-table-cell {
  padding: 8px 4px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  min-width: 0;
}
.ph-ar-table-cell-rowlabel {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  padding-left: 0;
}
.ph-ar-table-cell-header-rowlabel {
  color: var(--ink-2);
  font-size: 12px;
}
.ph-ar-table-rowlabel-text { line-height: 1.15; }
.ph-ar-table-cell-header {
  padding: 8px 2px;
  border-top: 3px solid transparent;
}
.ph-ar-table-cell-header .ph-ar-table-age {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.005em;
  line-height: 1.15;
}
.ph-ar-table-cell-header .ph-ar-table-age-unit {
  font-size: 10px;
  font-weight: 500;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* #283 follow-up #3 — 5-tier severity ramp (green / lime / yellow /
   orange / red) replaces the prior accent-light / accent pair which
   rendered as adjacent purple shades on the default theme. Each step
   is visually distinct at a glance so Hanna can identify the bucket
   by color alone. Hex values picked for high contrast in both light
   and dark themes (no theme tokens — the 5-step semantic ramp doesn't
   map cleanly onto accent / accent-on-light, which carry brand-color
   meaning instead). */
.ph-ar-table-sev-green   { border-top-color: #15803d; }   /* success */
.ph-ar-table-sev-lime    { border-top-color: #84cc16; }   /* early caution */
.ph-ar-table-sev-yellow  { border-top-color: #eab308; }   /* mid caution */
.ph-ar-table-sev-orange  { border-top-color: #f97316; }   /* high caution */
.ph-ar-table-sev-red     { border-top-color: #b91c1c; }   /* danger */
.ph-ar-table-sev-neutral { border-top-color: var(--ink-3); }

.ph-ar-table-cell-balance {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
}
.ph-ar-table-cell-patients {
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-3);
}
.ph-ar-table-cell-share {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
}

/* 412px is the primary target; below that, drop the row-label column
   width + tighten cell padding so the 6 columns still fit without
   horizontal scroll. */
@media (max-width: 412px) {
  .ph-ar-table-row { grid-template-columns: 50px repeat(5, 1fr); column-gap: 6px; }
  .ph-ar-table-cell-rowlabel { font-size: 10px; }
}
@media (max-width: 360px) {
  .ph-ar-table-row { grid-template-columns: 44px repeat(5, 1fr); column-gap: 4px; }
  .ph-ar-table-cell { padding: 6px 2px; }
  .ph-ar-table-cell-balance { font-size: 12px; }
  .ph-ar-table-cell-header .ph-ar-table-age { font-size: 12px; }
  .ph-ar-table-cell-rowlabel { font-size: 9px; }
}

.ph-ar-fallback-note {
  font-size: 11px;
  color: var(--ink-3);
  font-style: italic;
  text-align: center;
  padding-top: 4px;
}

/* =============================================================================
   #283 Practice Health UIUX polish chrome
   ============================================================================= */

/* #283 follow-up — period selector inherits .filter-pills from
   styles.css (Activity / P&L / Vendors share the same chrome).
   .ph-period-pills is an identity hook for any future tile-aware
   adjustments; layout/colors come from .filter-pills + .pill. */
.ph-period-pills { margin-bottom: 4px; }

/* --- Segment control (Carrier Performance tile) -------------------------- */
.ph-segment-control {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  margin-bottom: 12px;
}
.ph-segment-control-btn {
  flex: 1 1 auto;
  min-height: 32px;
  padding: 6px 12px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  background: transparent;
  border: none;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.12s, color 0.12s;
}
.ph-segment-control-btn:hover { color: var(--ink-2); }
.ph-segment-control-btn:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 40%, transparent);
  outline-offset: 1px;
}
.ph-segment-control-btn.active {
  background: var(--card);
  color: var(--accent-on-light);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--ink) 8%, transparent);
}

/* --- Carrier table expand/collapse toggle -------------------------------- */
.ph-carrier-table-toggle {
  display: block;
  margin: 12px auto 0;
  padding: 8px 16px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-on-light);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  min-height: 36px;
}
.ph-carrier-table-toggle:hover,
.ph-carrier-table-toggle:focus-visible {
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border-color: var(--accent);
}

/* Day 28 UX polish — Carrier Performance chart top-8 collapse toggle.
   Identical visual register to .ph-carrier-table-toggle so the
   chart + table side-by-side feel as one coordinated UI. */
.ph-carrier-perf-toggle {
  display: block;
  margin: 10px auto 0;
  padding: 8px 16px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent-on-light);
  background: transparent;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  min-height: 36px;
}
.ph-carrier-perf-toggle:hover,
.ph-carrier-perf-toggle:focus-visible {
  background: color-mix(in srgb, var(--accent) 8%, var(--card));
  border-color: var(--accent);
}

/* --- Day 26+ — Practice Info sub-page inline form -------------------------
   The Practice Info sub-page hybridizes inline form fields (Name, Type, FY
   Start Month) with a Doctors nav row beneath. The form lives in its own
   card; .practice-info-actions positions the Save button at the bottom-
   right of the card body (matches the inline-form pattern used by
   cash-entry-form). */
.practice-info-form .form-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 12px 0;
}
.practice-info-form label {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.practice-info-form input[type="text"],
.practice-info-form select {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.practice-info-form input[type="text"]:focus,
.practice-info-form select:focus {
  outline: none;
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 3px rgba(52, 214, 128, 0.18);
}
.practice-info-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 16px;
}
.practice-info-actions .practice-info-save {
  width: auto;
  min-width: 120px;
  padding: 10px 24px;
}

/* --- CFO Advisory Phase 1 — drip-question card ---------------------------
   Surfaces one passive question per visit in Settings → Practice Info.
   Card sits between the practice-info form and the Doctors nav row.
   Lime accent + brand-anchor "CFO advisor" badge tags it as feature-tier
   content (vs settings-data-entry). Skip is plain button; Save is btn-
   primary. Read-only branch (demo / viewer) hides actions, shows hint
   block. */
.owner-state-card {
  border-left: 3px solid var(--accent);
}
.owner-state-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}
.owner-state-badge {
  display: inline-block;
  padding: 3px 9px;
  background: var(--accent);
  color: var(--brand);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-radius: 4px;
}
.owner-state-title {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.owner-state-question {
  display: block;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink);
  margin: 6px 0 6px 0;
  line-height: 1.4;
  cursor: pointer;
}
.owner-state-hint {
  font-size: 13px;
  color: var(--ink-3);
  margin: 0 0 14px 0;
  line-height: 1.45;
}
.owner-state-input-row {
  margin: 12px 0;
}
.owner-state-select {
  width: 100%;
  padding: 10px 12px;
  font-size: 15px;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.owner-state-select:focus {
  outline: none;
  border-color: var(--accent-on-light);
  box-shadow: 0 0 0 3px rgba(52, 214, 128, 0.18);
}
.owner-state-error {
  color: var(--danger);
  font-size: 13px;
  margin: 6px 0;
}
.owner-state-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  row-gap: 10px;
  margin-top: 14px;
}
.owner-state-skip {
  background: transparent;
  color: var(--ink-3);
  border: none;
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  border-radius: 6px;
  transition: background-color 0.12s, color 0.12s;
}
.owner-state-skip:hover {
  background: var(--bg-2);
  color: var(--ink);
}
.owner-state-skip:active {
  background: var(--border);
}
.owner-state-skip:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.owner-state-card .btn-primary.owner-state-save {
  width: auto;
  min-width: 100px;
  padding: 10px 22px;
}
.owner-state-footer {
  font-size: 11px;
  color: var(--ink-4);
  margin-top: 12px;
  font-style: italic;
}
.owner-state-readonly-hint {
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.5;
  padding: 8px 0;
}

/* --- Day 26+ — Activity drill "← Go up" pill ------------------------------
   Distinguishes the back-navigation pill from category pills via a softer
   background + accent text. Sits at the start of the drill pill row at any
   level > 0. */
.filter-pills .pill-go-up {
  background: var(--bg-2);
  color: var(--accent-on-light);
  border-color: var(--border);
  font-weight: 600;
}
.filter-pills .pill-go-up:hover,
.filter-pills .pill-go-up:focus-visible {
  background: var(--border);
  color: var(--accent-on-light);
}

/* --- Day 26+ — Settings inline toggle row (visual cleanup pass) ------------
   Reuses .settings-menu-row + .settings-menu-label classes byte-for-byte so
   font / padding / hover-bg / border match the sibling navigation rows
   exactly. The .settings-menu-row-toggle modifier neutralizes the row's
   default cursor:pointer (the row itself isn't clickable; only the toggle
   on the right is interactive) and stops the hover background swap so the
   row doesn't visually "respond" to mouse-over the inert label area. */
.settings-menu-row-toggle {
  cursor: default;
}
.settings-menu-row-toggle:hover,
.settings-menu-row-toggle:active {
  background: transparent;
}
.settings-menu-row-disabled { opacity: 0.55; }
.settings-menu-row-toggle .toggle-switch { flex-shrink: 0; }

/* --- Day 26+ — reclassify drill L3/L4 picker (tap-open <select> + custom)
   The new picker wrap holds a <select> and a sibling <input> (text), only
   one visible at a time via inline display swap. Both inherit the existing
   .reclassify-section select / input[type=text] styling above. */
.rc-picker-wrap {
  display: block;
  position: relative;
}
.rc-picker-other {
  /* Inherits .reclassify-section input[type=text] styling for visual parity
     with the select state. Sits in the same wrap; toggled via inline display. */
}

/* --- Phase 6: L3/L4 expansion in Categorization v2 ---------------------- */
/* L2 block wraps the existing categories-custom-row + expand caret +
   lazy-rendered L3 list mount. Backward-compat: when an L2 has no
   hierarchy data (practice-scoped custom categories pre-Phase-6, OR
   system categories whose backfill didn't include defaults), the caret
   is omitted and the block visually matches the pre-Phase-6 single-row
   shape. */
.categories-l2-block {
  display: flex;
  flex-direction: column;
}
.categories-l2-header {
  display: flex;
  align-items: center;
  gap: 4px;
}
.categories-l2-header .categories-custom-row {
  flex: 1;
}
.categories-expand-btn,
.categories-l4-expand-btn {
  min-width: 44px;
  min-height: 44px;
  padding: 0 12px;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink-3);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color 0.12s, background 0.12s;
  border-radius: 8px;
}
.categories-expand-btn:hover,
.categories-expand-btn:focus-visible,
.categories-l4-expand-btn:hover,
.categories-l4-expand-btn:focus-visible {
  color: var(--ink);
  background: var(--bg-2);
  outline: none;
}
.categories-expand-btn:active,
.categories-l4-expand-btn:active {
  background: var(--border);
}

/* L3 list: indented under L2 row. */
.categories-l3-list {
  margin-left: 18px;
  padding: 4px 0 8px;
  border-left: 2px solid var(--border);
  padding-left: 12px;
}
.categories-l3-block {
  display: flex;
  flex-direction: column;
}
.categories-l3-block.is-hidden .categories-sub-name {
  opacity: 0.5;
  font-style: italic;
}
.categories-l3-header {
  display: flex;
  align-items: center;
  gap: 4px;
}
.categories-l3-header .categories-sub-row {
  flex: 1;
}
.categories-sub-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 4px;
  cursor: pointer;
  min-height: 44px;
  border-bottom: 1px solid var(--border);
}
.categories-l3-block:last-child .categories-sub-row,
.categories-l4-block:last-child .categories-sub-row {
  border-bottom: 0;
}
.categories-sub-row input[type="checkbox"] {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  accent-color: var(--accent);
}
.categories-sub-name {
  flex: 1;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.3;
}
.categories-sub-row-l4 .categories-sub-name {
  font-size: 12px;
  color: var(--ink-3);
}
.categories-sub-delete {
  min-width: 44px;
  min-height: 44px;
  padding: 0 10px;
  font-family: inherit;
  font-size: 18px;
  line-height: 1;
  color: var(--ink-3);
  background: transparent;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
  transition: color 0.12s, background 0.12s;
}
.categories-sub-delete:hover,
.categories-sub-delete:focus-visible {
  color: var(--danger);
  background: var(--bg-2);
  outline: none;
}
.categories-sub-delete:active {
  background: var(--border);
}

/* L4 list: indented deeper than L3 (visual nesting). */
.categories-l4-list {
  margin-left: 18px;
  padding: 4px 0 6px;
  border-left: 2px solid var(--border);
  padding-left: 12px;
}
.categories-l4-block {
  display: flex;
  flex-direction: column;
}
.categories-l4-block.is-hidden .categories-sub-name {
  opacity: 0.5;
  font-style: italic;
}

/* Sub-form for adding L3 or L4 — matches the existing .categories-add-form
   visual register but more compact (max-width input, smaller padding). */
.categories-add-sub-form {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  padding: 4px 0;
}
.categories-add-sub-form .categories-add-input {
  font-size: 13px;
  min-height: 40px;
}
.categories-add-sub-form .categories-add-btn {
  min-height: 40px;
  padding: 0 14px;
  font-size: 13px;
}

/* Empty-state copy inside L3/L4 lists. Smaller + italic so it doesn't
   compete with the add form below. */
.categories-l3-list .empty-sub,
.categories-l4-list .empty-sub {
  margin: 4px 0;
  padding: 0;
  font-size: 12px;
  font-style: italic;
  color: var(--ink-4);
}

/* =============================================================================
   Day 29 UX polish — empty state + label clarity + recovery flows
   =============================================================================
   Bundle for the Day 29 UX expert feedback batch:
     - PART A enrichments — tile-level empty state copy that explains
       WHAT surfaces here (Top Spend, Top Issues) + "How DentBooks gets
       your data" Settings → Help & Community sub-row + CTA on the
       Reappointment Rate "Coming soon" placeholder
     - PART C Top Issues — show-dismissed CTA when only dismissed items
       are present (the canonical Insights sheet was reachable but the
       affordance was easy to miss)
     - PART D Top Spend — help icon next to the tile title carrying the
       longer tooltip
     - PART E "transactions" drill — inline search row chrome
   ============================================================================= */

/* Tile-level empty state with title + sub copy (Top Spend, similar
   surfaces). Single-line .empty rule (line 1809) stays the legacy
   surface for surfaces that don't need a title; this is the richer
   variant. */
.empty .empty-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 4px;
}
.empty .empty-sub {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
  max-width: 320px;
  margin: 0 auto;
}

/* Top Issues tile empty state — pairs title + sub copy. */
.insight-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.insight-empty-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-2);
}
.insight-empty-sub {
  font-size: 12px;
  color: var(--ink-3);
  max-width: 280px;
  text-align: center;
  line-height: 1.5;
}

/* Top Issues — "Show dismissed (N) →" CTA at the bottom of the preview
   tile when visibleCount === 0 && dismissed.length > 0. Same green-link
   register as .insights-show-all but blocked element so it stands as a
   recovery target rather than a header chip. ≥44×44 touch target via
   12px vertical padding. */
.insight-dismissed-cta {
  display: block;
  width: 100%;
  margin-top: 8px;
  padding: 12px 14px;
  background: var(--bg-2);
  color: var(--accent-on-light);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.insight-dismissed-cta:hover { background: var(--card); border-color: var(--accent); }
.insight-dismissed-cta:active { background: var(--border); }
.insight-dismissed-cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Tile-level help-icon button — appears next to the tile title (Top
   Spend Categories on Overview). Small circular `?` glyph with a
   title-attribute tooltip carrying the longer explanation. Hover/
   tap-and-hold reveal pattern matches the canonical title-attribute
   convention (#127 vendor-name + #161 carrier-fullLabel). ≥44×44
   touch target via the parent .card-title flex layout. */
.card-title-help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: 6px;
  background: var(--bg-2);
  color: var(--ink-3);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  cursor: help;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
  flex-shrink: 0;
}
.card-title-help:hover {
  background: var(--card);
  color: var(--accent-on-light);
  border-color: var(--accent);
}
.card-title-help:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Reappointment Rate "Coming soon" CTA — owner|admin only. Routes to
   Settings → Integration → Practice Management. Inherits .btn-primary
   shape (canonical accent fill) with extra margin-top above the body
   copy. */
.reappointment-placeholder-cta {
  margin-top: 14px;
}

/* "How DentBooks gets your data" Settings sheet body. 4 source items
   stacked with subtle dividers; each shows a bold label + plain-language
   body. Footer line carries the privacy reassurance. Plain-language
   copy (#56) end-to-end. */
.data-sources-body {
  padding: 4px 4px 10px;
}
.data-source-item {
  padding: 12px 4px;
  border-bottom: 1px solid var(--border-2);
}
.data-source-item:last-of-type { border-bottom: none; }
.data-source-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 4px;
  letter-spacing: -0.005em;
}
.data-source-body {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.data-sources-footer {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-2);
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  line-height: 1.5;
}
/* selector match for the inline `.data-source-footer` class name (kept
   for back-compat alongside the canonical -s suffix). */
.data-source-footer {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-2);
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  line-height: 1.5;
}

/* "transactions" drill — inline search row chrome. Reuses .search-wrap
   + .search-input from the Activity/Vendors inline-search pattern.
   Sits above the per-day group + list. Sticky-ish behavior left out
   for v1 — drill sheets are scroll-contained and the search row stays
   in view via short content sets. */
.drill-search-row {
  margin: 4px 4px 12px;
}
.drill-search-row .search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0 10px 0 8px;
  gap: 6px;
  min-height: 44px;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.drill-search-row .search-wrap:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.drill-search-row .search-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-4);
  flex-shrink: 0;
}
.drill-search-row .search-icon svg { width: 18px; height: 18px; }
.drill-search-row .drill-search-input {
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  padding: 8px 0;
}
.drill-search-row .drill-search-input::placeholder { color: var(--ink-4); }

/* =========================================================================
   Bank statement upload sheet (#391, Day 32)
   ========================================================================= */
.bank-upload-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 4px 0 8px;
}
.bank-upload-body-center {
  align-items: center;
  text-align: center;
  padding: 32px 12px;
}

.bank-upload-context {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.bank-upload-context-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--accent-on-light);
  text-transform: uppercase;
}
.bank-upload-context-value {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}

.bank-upload-intro p {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.bank-upload-intro p:last-child { margin-bottom: 0; }
.bank-upload-help-line {
  font-size: 12px !important;
  color: var(--ink-3) !important;
}

.bank-upload-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 32px 16px;
  border: 2px dashed var(--border);
  border-radius: 12px;
  background: var(--bg-2);
  cursor: pointer;
  transition: background 140ms ease-out, border-color 140ms ease-out;
  min-height: 160px;
  text-align: center;
}
.bank-upload-dropzone:hover {
  background: color-mix(in srgb, var(--accent) 6%, var(--bg-2));
  border-color: var(--accent);
}
.bank-upload-dropzone--over {
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-2));
  border-color: var(--accent);
  border-style: solid;
}
.bank-upload-dropzone-icon {
  color: var(--ink-3);
}
.bank-upload-dropzone-text strong {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.bank-upload-dropzone-meta {
  margin-top: 4px;
  font-size: 12px;
  color: var(--ink-3);
}

.bank-upload-summary-card {
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.bank-upload-summary-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.bank-upload-summary-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}
.bank-upload-link-btn {
  background: none;
  border: none;
  color: var(--accent-on-light);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 2px 4px;
  flex-shrink: 0;
}
.bank-upload-link-btn:hover { text-decoration: underline; }

.bank-upload-summary-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 8px;
  font-size: 12px;
  color: var(--ink-2);
}
.bank-upload-summary-stats div {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.bank-upload-stat-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.bank-upload-summary-stats strong {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  font-size: 13px;
}
.bank-upload-mapping-note {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
}
.bank-upload-mapping-note strong {
  font-weight: 600;
  color: var(--ink-2);
}

.bank-upload-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.bank-upload-field-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--accent-on-light);
  text-transform: uppercase;
}
.bank-upload-field-value {
  font-size: 14px;
  color: var(--ink);
}
.bank-upload-select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit;
  font-size: 14px;
  background: var(--card);
  color: var(--ink);
}
.bank-upload-checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
  cursor: pointer;
}
.bank-upload-checkbox-row input[type="checkbox"] {
  margin-top: 2px;
  flex-shrink: 0;
}

.bank-upload-preview-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.bank-upload-preview-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.bank-upload-preview-table thead {
  background: var(--bg-2);
}
.bank-upload-preview-table th,
.bank-upload-preview-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid var(--border);
}
.bank-upload-preview-table th {
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.bank-upload-preview-table tbody tr:last-child td { border-bottom: 0; }
.bank-upload-preview-table .bank-upload-amount {
  font-variant-numeric: tabular-nums;
  text-align: right;
  font-weight: 600;
  color: var(--ink);
}
.bank-upload-preview-table .bank-upload-amount-neg {
  color: var(--danger);
}
.bank-upload-preview-more {
  padding: 8px 10px;
  font-size: 11px;
  color: var(--ink-3);
  text-align: center;
  font-style: italic;
  border-top: 1px solid var(--border);
  background: var(--bg-2);
}

.bank-upload-dedup-note {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
  padding: 10px 12px;
  background: var(--bg-2);
  border-radius: 8px;
  border-left: 3px solid var(--accent);
}

.bank-upload-error {
  padding: 10px 12px;
  background: color-mix(in srgb, var(--danger) 8%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, var(--border));
  color: var(--danger);
  border-radius: 8px;
  font-size: 13px;
}

.bank-upload-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}
.bank-upload-actions .btn-primary,
.bank-upload-actions .btn-secondary {
  min-width: 100px;
}

.bank-upload-spinner {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  animation: bank-upload-spin 800ms linear infinite;
}
@keyframes bank-upload-spin {
  to { transform: rotate(360deg); }
}
.bank-upload-status-line {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.bank-upload-status-sub {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
}

.bank-upload-done-card {
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
}
.bank-upload-done-card-error {
  background: color-mix(in srgb, var(--danger) 5%, var(--card));
  border-color: color-mix(in srgb, var(--danger) 25%, var(--border));
}
.bank-upload-done-icon {
  color: var(--accent-on-light);
}
.bank-upload-done-card-error .bank-upload-done-icon {
  color: var(--danger);
}
.bank-upload-done-title {
  font-size: 18px;
  font-weight: 700;
  color: var(--ink);
}
.bank-upload-done-body {
  font-size: 14px;
  color: var(--ink-2);
  line-height: 1.5;
}
.bank-upload-done-error-body {
  color: var(--danger);
}
.bank-upload-done-stats {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
  align-items: center;
}
.bank-upload-done-stats strong {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--ink);
  font-size: 15px;
}
.bank-upload-done-stats-total {
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 12px !important;
  color: var(--ink-3) !important;
}
.bank-upload-done-next {
  font-size: 12px;
  color: var(--ink-3);
  line-height: 1.5;
  margin-top: 8px;
}

.drill-txn-list { display: contents; }

/* =========================================================================
   Chart of Account editor (#396 PART 4, Day 33)
   Settings → Advanced Settings → Chart of Account
   ========================================================================= */
.coa-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.coa-helper {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0;
}
.coa-groups {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.coa-group {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  background: var(--card);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.coa-group-title {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: 4px;
}
.coa-active-list {
  display: flex;
  flex-direction: column;
}
.coa-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  min-height: 44px;
}
.coa-row:last-child { border-bottom: 0; }
.coa-name {
  flex: 1;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  cursor: text;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.coa-name-custom { cursor: pointer; }
.coa-name:hover { text-decoration: underline; text-decoration-style: dotted; }
.coa-name.coa-rename-input,
.coa-rename-input {
  flex: 1;
  border: 1px solid var(--accent);
  background: var(--card);
  font-family: inherit;
  font-size: 14px;
  padding: 6px 8px;
  border-radius: 6px;
  color: var(--ink);
  outline: none;
}
.coa-custom-tag,
.coa-orphan-tag {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  margin-left: 6px;
  background: var(--bg-2);
  color: var(--ink-3);
  vertical-align: middle;
}
.coa-orphan-tag {
  color: var(--warning, #b45309);
  background: color-mix(in srgb, var(--warning, #b45309) 12%, var(--card));
}
.coa-row-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}
.coa-hide-btn,
.coa-unhide-btn,
.coa-delete-btn,
.coa-reset-btn {
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
  min-height: 32px;
}
.coa-reset-btn { color: var(--ink-3); }
.coa-reset-btn:hover { background: var(--border); color: var(--ink-2); }

/* PART 8.5 (#396, Day 33) — transaction-count chip rendered next to
   each category name in the COA editor. Parens format per Edwin's
   directive (intuitive over middle-dot; visual collision with the
   expand caret is accepted as a trial). Tabular-nums so digit columns
   line up across rows. Muted color so it doesn't compete with the
   name typography. Zero-count rows render lighter still — visual cue
   that "this is safe to delete or hide." */
.coa-row-count {
  display: inline-block;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  margin-left: 2px;
  vertical-align: baseline;
}
.coa-row-count-zero { color: var(--ink-4, var(--ink-3)); opacity: 0.6; }

/* PART 8.5 — Delete button on system rows (labeled "Delete & reclassify"
   originally; renamed to single-word "Delete" Day 33 evening polish to
   free L2 row width on 412px viewport — confirmation sheet body still
   communicates the reclassify semantic). Same chrome as Hide/Reset
   buttons but with a danger-tinted hover (subtle red wash) to signal
   the destructive intent. Width auto-sizes to content — no min-width
   constraint. Actual confirmation happens in the bottom-sheet. */
.coa-purge-btn {
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
  min-height: 32px;
}
.coa-purge-btn:hover {
  background: color-mix(in srgb, var(--danger, #dc2626) 8%, var(--card));
  border-color: color-mix(in srgb, var(--danger, #dc2626) 30%, var(--border));
  color: var(--danger, #dc2626);
}

/* PART 8.5 — Delete & reclassify confirmation sheet body. The sheet
   chrome (.bottom-sheet, panel, backdrop, action bar) is shared with
   other sheets via the existing pattern; these styles are body-only
   additions for the purge-specific layout. */
.coa-purge-body { display: flex; flex-direction: column; gap: 14px; padding: 4px 0 8px; }
.coa-purge-line { font-size: 14px; line-height: 1.5; color: var(--ink); margin: 0; }
.coa-purge-zero { font-size: 13px; line-height: 1.5; color: var(--ink-2); margin: 0; }
.coa-purge-target {
  font-family: inherit;
  font-size: 14px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink);
  width: 100%;
  min-height: 44px;
  appearance: menulist;
}
.coa-purge-warning {
  font-size: 12px;
  line-height: 1.5;
  color: var(--warning, #b45309);
  background: color-mix(in srgb, var(--warning, #b45309) 8%, var(--card));
  border-left: 3px solid var(--warning, #b45309);
  padding: 10px 12px;
  border-radius: 6px;
  margin: 0;
}
.coa-purge-confirm[data-danger] {
  background: var(--danger, #dc2626) !important;
  color: #fff !important;
  border-color: var(--danger, #dc2626) !important;
}
.coa-purge-confirm[data-danger]:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger, #dc2626) 88%, #000) !important;
}
.coa-purge-confirm:disabled { opacity: 0.65; cursor: not-allowed; }

/* Day 34 — Item 3 polish + alignment follow-up. .btn-secondary has no
   global rule, so the Cancel button in the Delete-confirmation sheet
   inherited user-agent button styling (system font + smaller size)
   while the Confirm button carried .btn-primary's 15px / 600 / Inter
   chrome. Both buttons now share an identical content-box: same
   box-sizing, same border (1px solid — Confirm's danger override
   re-uses border-color so the box is still 1px), same padding,
   same line-height, same border-radius, no margin. Parent
   .sheet-action-bar already centers on the cross-axis. Result:
   identical rendered height + baseline alignment. */
.coa-purge-cancel,
.coa-purge-confirm {
  box-sizing: border-box;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  padding: 14px 18px;
  border-radius: 12px;
  border: 1px solid var(--border);
  margin: 0;
  cursor: pointer;
}
.coa-purge-cancel {
  background: var(--card);
  color: var(--ink-2);
}
.coa-purge-cancel:hover { background: var(--bg-2); }
.coa-purge-cancel:active { background: var(--border); }

/* PART 8.5.1 (#396, Day 33) — scrollable transaction preview inside the
   Delete confirmation sheet body. Renders between the target-dropdown
   and the warning row on the N>0 path; absent on the N=0 path.
   Section label uses the same H3 register as other COA editor labels
   (12px / 700 uppercase / --ink-3 / 0.08em tracking). Container caps
   at ~6-7 rows visible at 412px viewport before scrolling. */
.coa-purge-preview-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  margin: 4px 0 8px;
}
.coa-purge-preview-list {
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  -webkit-overflow-scrolling: touch;
}
.coa-purge-preview-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
}
.coa-purge-preview-row:last-child { border-bottom: none; }
.coa-purge-preview-row-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.coa-purge-preview-row-bottom {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}
.coa-purge-preview-date {
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.coa-purge-preview-amount {
  font-size: 13px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  flex-shrink: 0;
}
.coa-purge-preview-vendor {
  font-size: 12px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}
.coa-purge-preview-sub {
  font-size: 12px;
  color: var(--ink-4, var(--ink-3));
  flex-shrink: 0;
  max-width: 50%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.coa-purge-preview-overflow {
  padding: 8px 12px;
  font-size: 11px;
  font-style: italic;
  color: var(--ink-3);
  text-align: center;
  border-top: 1px dashed var(--border);
}

/* =========================================================================
   Tax Reporting surfaces (#396 PART 6, Day 33)
   Gated by practices.tax_reporting_enabled (default false).
   ========================================================================= */

/* P&L row tax-treatment help icon (T5a). Reuses the .card-title-help
   pattern (Day 30) — small "?" glyph with title-attr tooltip, hover/
   tap-and-hold reveal. Only renders when tax_reporting_enabled = true. */
.pnl-tax-help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  margin-left: 4px;
  border-radius: 50%;
  background: var(--bg-2);
  color: var(--ink-3);
  font-size: 9px;
  font-weight: 700;
  cursor: help;
  vertical-align: middle;
  line-height: 1;
}
.pnl-tax-help:hover { background: var(--border); color: var(--ink-2); }

/* Reclassify drill — per-transaction tax-deductibility pill (T2b).
   Expandable: closed shows just the pill, open reveals 3-radio control.
   Sits below the L3/L4 mount in the .rc-tax-mount form-row. */
.rc-tax-section {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.rc-tax-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 16px;
  border: 1px solid var(--border);
  background: var(--bg-2);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  align-self: flex-start;
  min-height: 32px;
}
.rc-tax-pill:hover { background: var(--border); }
.rc-tax-pill-override {
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
  color: var(--accent-on-light);
}
.rc-tax-pill-caret {
  font-size: 11px;
  color: var(--ink-3);
}
.rc-tax-pill-override .rc-tax-pill-caret { color: var(--accent-on-light); }
.rc-tax-control {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.rc-tax-control[hidden] { display: none; }
.rc-tax-radio-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.rc-tax-radio {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  min-height: 32px;
}
.rc-tax-radio input[type="radio"] {
  margin: 0;
  cursor: pointer;
}
.rc-tax-reset-btn {
  align-self: flex-start;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--card);
  color: var(--ink-3);
  border: 1px solid var(--border);
}
.rc-tax-reset-btn:hover:not(:disabled) {
  background: var(--bg-2);
  color: var(--ink-2);
}
.rc-tax-reset-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* PART 8.2 (#396) — Reorder UI (Up/Down arrows + per-group Reset
   to canonical). Arrows live in .coa-reorder-actions next to Hide/
   Delete buttons inside .coa-row-actions. Stacked vertically (up
   above down) so the touch targets stay 44px without crowding the
   row at 412px viewport. */
.coa-group-title-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}
.coa-reset-order-btn {
  padding: 4px 10px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--card);
  color: var(--accent-on-light);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
}
.coa-reset-order-btn:hover { background: var(--bg-2); }
/* #397 (Day 34) — drag-drop reorder. Replaces PART 8.3's up/down
   arrow buttons. The ⋮ 6-dot glyph is the drag handle. Whole .coa-row
   is draggable=true on active rows. Visual feedback during drag:
   dragged row gets opacity 0.5; drop target row gets a horizontal
   accent-colored separator above (coa-drop-target-before) or below
   (coa-drop-target-after). */
.coa-drag-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 32px;
  margin-right: 4px;
  border-radius: 4px;
  color: var(--ink-4);
  cursor: grab;
  flex-shrink: 0;
  touch-action: none;   /* suppress browser pan/zoom while dragging */
  user-select: none;
  -webkit-user-select: none;
}
.coa-drag-handle:hover  { color: var(--ink-3); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.coa-drag-handle:active { cursor: grabbing; }
.coa-row[draggable="true"] { cursor: default; }
.coa-row-dragging { opacity: 0.5; }
/* Drop-target visual feedback. Pseudo-element sits at the row edge
   as a 2px accent-colored bar — only one of before/after at a time. */
.coa-drop-target-before {
  box-shadow: inset 0 2px 0 0 var(--accent-on-light, var(--accent));
}
.coa-drop-target-after {
  box-shadow: inset 0 -2px 0 0 var(--accent-on-light, var(--accent));
}

.coa-renamed-tag {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  margin-left: 6px;
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  color: var(--accent-on-light);
  vertical-align: middle;
}
.coa-hide-btn:hover,
.coa-unhide-btn:hover,
.coa-delete-btn:hover { background: var(--border); }
.coa-hide-btn:active,
.coa-unhide-btn:active,
.coa-delete-btn:active { background: var(--border-2); }
.coa-unhide-btn {
  color: var(--accent-on-light);
  border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
}
.coa-delete-btn {
  width: 32px;
  padding: 6px;
  font-size: 16px;
  line-height: 1;
  color: var(--ink-3);
}
.coa-delete-btn:hover {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 30%, var(--border));
}
.coa-hidden-toggle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 8px 10px;
  margin-top: 4px;
  background: var(--bg-2);
  border: 1px dashed var(--border);
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.coa-hidden-toggle:hover { background: var(--border); }
.coa-hidden-caret {
  font-size: 14px;
  color: var(--ink-3);
}
.coa-hidden-list {
  display: flex;
  flex-direction: column;
  margin-top: 4px;
  padding: 4px 0;
}
.coa-hidden-list[hidden] { display: none; }
.coa-row-hidden .coa-name {
  color: var(--ink-3);
  font-style: italic;
}

/* PART 8.5.1 follow-up (overnight bundle) — Purged subsection. Same
   chrome family as Hidden but with a warning-tinted border + caret
   to signal the one-way semantic. Rows themselves use the same .coa-row
   layout — only the Restore action button differs from Hidden's Unhide. */
.coa-purged-toggle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 8px 10px;
  margin-top: 4px;
  background: var(--bg-2);
  border: 1px dashed color-mix(in srgb, var(--warning, #b45309) 35%, var(--border));
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.coa-purged-toggle:hover { background: var(--border); }
.coa-purged-caret {
  font-size: 14px;
  color: var(--ink-3);
}
.coa-purged-list {
  display: flex;
  flex-direction: column;
  margin-top: 4px;
  padding: 4px 0;
}
.coa-purged-list[hidden] { display: none; }
.coa-row-purged .coa-name {
  color: var(--ink-3);
  font-style: italic;
}
.coa-restore-btn {
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--bg-2);
  color: var(--ink-2);
  border: 1px solid var(--border);
  min-height: 32px;
}
.coa-restore-btn:hover {
  background: color-mix(in srgb, var(--accent-on-light, var(--accent)) 12%, var(--card));
  border-color: color-mix(in srgb, var(--accent-on-light, var(--accent)) 35%, var(--border));
  color: var(--accent-on-light, var(--accent));
}

/* Day 34 (#396 PART 8.5 Item 3, migration 101) — Undo button. Sits
   FIRST on Purged rows (before Restore + Delete forever). Accent-
   tinted to signal "recoverable + most-thorough action". Surfaces only
   when an active purge_audit_events row exists for the purged name. */
.coa-undo-btn {
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: color-mix(in srgb, var(--accent-on-light, var(--accent)) 8%, var(--card));
  color: var(--accent-on-light, var(--accent));
  border: 1px solid color-mix(in srgb, var(--accent-on-light, var(--accent)) 32%, var(--border));
  min-height: 32px;
}
.coa-undo-btn:hover {
  background: color-mix(in srgb, var(--accent-on-light, var(--accent)) 16%, var(--card));
  border-color: color-mix(in srgb, var(--accent-on-light, var(--accent)) 55%, var(--border));
}

/* Day 34 (#396 PART 8.5 follow-up, migration 099) — Delete-forever
   button. Sits next to Restore on Purged rows. Warning-tinted to signal
   the one-way-with-friction semantic. Slightly smaller padding so the
   two buttons fit comfortably on a 412px viewport. */
.coa-delete-forever-btn {
  padding: 6px 8px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  background: var(--bg-2);
  color: var(--warning, #b45309);
  border: 1px solid color-mix(in srgb, var(--warning, #b45309) 25%, var(--border));
  min-height: 32px;
}
.coa-delete-forever-btn:hover {
  background: color-mix(in srgb, var(--warning, #b45309) 10%, var(--card));
  border-color: color-mix(in srgb, var(--warning, #b45309) 50%, var(--border));
}

.coa-add-form {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}
.coa-add-input {
  flex: 1;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--card);
  outline: none;
  min-height: 36px;
}
.coa-add-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent);
}
.coa-add-btn {
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  background: var(--accent);
  color: var(--brand);
  border: 1px solid var(--accent);
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  flex-shrink: 0;
  min-height: 36px;
}
.coa-add-btn:hover { filter: brightness(0.95); }
.coa-add-btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.coa-empty {
  font-size: 13px;
  color: var(--ink-3);
  margin: 0;
  padding: 8px 0;
  font-style: italic;
}
.coa-error {
  padding: 10px 12px;
  background: color-mix(in srgb, var(--danger) 8%, var(--card));
  border: 1px solid color-mix(in srgb, var(--danger) 30%, var(--border));
  color: var(--danger);
  border-radius: 8px;
  font-size: 13px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}
/* L3 sub-category management inside the COA editor (#396 PART 7).
   Gated by detailedCategorizationEnabled() at render time. Caret on
   the L2 row expands an inline L3 list with the same Hide/Delete/Add
   pattern scoped to L3 children. */
.coa-row-wrap {
  display: flex;
  flex-direction: column;
}
.coa-l3-expand-btn {
  width: 22px;
  height: 22px;
  margin-right: 6px;
  padding: 0;
  background: transparent;
  border: none;
  font-size: 14px;
  color: var(--ink-3);
  cursor: pointer;
  font-family: inherit;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.coa-l3-expand-btn:hover { color: var(--ink-2); }
.coa-l3-mount {
  margin-left: 28px;
  margin-bottom: 8px;
  padding-left: 10px;
  border-left: 2px solid var(--border);
}
.coa-l3-mount[hidden] { display: none; }
.coa-l3-list {
  display: flex;
  flex-direction: column;
}
.coa-l3-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border);
  min-height: 36px;
}
.coa-l3-row:last-child { border-bottom: 0; }
.coa-l3-name {
  flex: 1;
  font-size: 13px;
  color: var(--ink-2);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.coa-l3-row-hidden .coa-l3-name {
  color: var(--ink-3);
  font-style: italic;
}
.coa-hidden-tag-l3 {
  display: inline-block;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  margin-left: 6px;
  background: var(--bg-2);
  color: var(--ink-3);
  vertical-align: middle;
}
.coa-l3-action-btn {
  min-height: 28px;
  padding: 4px 8px;
  font-size: 11px;
}
.coa-l3-add-form {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}

.coa-inline-cta {
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 600;
  background: var(--card);
  color: var(--accent-on-light);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
}
.coa-inline-cta:hover { background: var(--bg-2); }

/* =============================================================================
   Practice Health Phase 1 + 111 — Tile 3 augmentation (Unscheduled Treatment)
   + Task List sub-page + Task detail sheet
   ========================================================================== */
.ph-tx-pipeline { display: flex; flex-direction: column; gap: 16px; }

.ph-tx-headline { display: flex; flex-direction: column; gap: 4px; }
.ph-tx-headline-row { display: flex; align-items: baseline; justify-content: space-between; }
.ph-tx-headline-label { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.ph-tx-headline-amount { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; color: var(--ink); font-variant-numeric: tabular-nums; }
.ph-tx-headline-sublabel { font-size: 13px; font-weight: 500; color: var(--ink-3); }
.ph-tx-headline-sub { margin-top: -4px; }

.ph-tx-aging { display: flex; flex-direction: column; gap: 8px; border-top: 1px solid var(--border); padding-top: 12px; }
.ph-tx-aging-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 14px; }
.ph-tx-aging-row span { color: var(--ink-2); }
.ph-tx-aging-row b { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: 700; }
.ph-tx-aging-row-gte90 { flex-wrap: wrap; }
.ph-tx-aging-pct { flex-basis: 100%; font-size: 12px; font-weight: 600; margin-top: 2px; }
.ph-tx-aging-pct.pct-good { color: var(--success); }
.ph-tx-aging-pct.pct-warn { color: var(--warning); }

.ph-tx-categories { border-top: 1px solid var(--border); padding-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.ph-tx-categories-label { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 4px; }
.ph-tx-category-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 13px; }
.ph-tx-category-name { color: var(--ink-2); }
.ph-tx-category-amount { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: 600; }

.ph-tx-tasks { border-top: 1px solid var(--border); padding-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.ph-tx-tasks-label { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.ph-tx-tasks-headline { font-size: 16px; font-weight: 600; color: var(--ink); }
.ph-tx-tasks-count { font-weight: 700; }
.ph-tx-tasks-meta { color: var(--ink-3); font-weight: 500; margin-left: 4px; }
.ph-tx-tasks-pills { display: flex; gap: 8px; flex-wrap: wrap; }
.ph-tx-tasks-pill { font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: 999px; background: var(--bg-2); color: var(--ink-2); }
.ph-tx-pill-open { background: color-mix(in srgb, var(--warning) 16%, var(--bg-2)); color: var(--ink); }
.ph-tx-pill-progress { background: color-mix(in srgb, var(--accent) 16%, var(--bg-2)); color: var(--ink); }
.ph-tx-pill-done { background: color-mix(in srgb, var(--success) 16%, var(--bg-2)); color: var(--ink); }
.ph-tx-tasks-cta {
  margin-top: 4px; min-height: 44px;
  background: var(--accent); color: var(--brand);
  border: none; border-radius: 10px;
  font-size: 15px; font-weight: 600; cursor: pointer;
  transition: opacity 160ms ease-out;
}
.ph-tx-tasks-cta:hover { opacity: 0.88; }
.ph-tx-tasks-cta:active { opacity: 0.78; }

/* ----- Recall Pipeline tile (admin_items #85) ---------------------------- */
.ph-recall-pipeline { display: flex; flex-direction: column; gap: 16px; }

.ph-recall-funnel { display: flex; flex-direction: column; gap: 8px; }
.ph-recall-funnel-row {
  display: grid;
  grid-template-columns: 80px 1fr 40px;
  align-items: center;
  gap: 8px;
}
.ph-recall-funnel-label {
  font-size: 12px; font-weight: 600; color: var(--ink-3);
}
.ph-recall-funnel-bar-wrap {
  height: 12px; background: var(--bg-2); border-radius: 6px; overflow: hidden;
}
.ph-recall-funnel-bar {
  height: 100%; border-radius: 6px;
  transition: width 220ms ease-out;
}
.ph-recall-bar-due       { background: color-mix(in srgb, var(--warning) 60%, var(--bg-2)); }
.ph-recall-bar-contacted { background: color-mix(in srgb, var(--accent) 55%, var(--bg-2)); }
.ph-recall-bar-booked    { background: var(--success); }
.ph-recall-funnel-count {
  text-align: right; font-size: 13px; font-weight: 700;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.ph-recall-funnel-conv {
  font-size: 12px; font-weight: 600; color: var(--ink-3);
  margin-top: 4px; padding-left: 88px;
}

.ph-recall-money {
  padding: 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--warning) 10%, var(--card));
  border: 1px solid color-mix(in srgb, var(--warning) 22%, var(--border));
}
.ph-recall-money-clear {
  background: color-mix(in srgb, var(--success) 10%, var(--card));
  border-color: color-mix(in srgb, var(--success) 22%, var(--border));
}
.ph-recall-money-amount {
  font-size: 16px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ph-recall-money-detail {
  font-size: 12px; font-weight: 500; color: var(--ink-3); margin-top: 2px;
}

.ph-recall-vm {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--warning) 14%, var(--card));
  border: 1px solid color-mix(in srgb, var(--warning) 28%, var(--border));
}
.ph-recall-vm-icon {
  font-size: 16px; line-height: 1.2; color: var(--warning); flex: 0 0 auto;
}
.ph-recall-vm-text {
  font-size: 13px; font-weight: 500; color: var(--ink-2); line-height: 1.4;
}
.ph-recall-vm-text strong { color: var(--ink); font-weight: 700; }

.ph-recall-toptype {
  font-size: 12px; font-weight: 600; color: var(--ink-3);
  padding-top: 4px;
}

/* ----- Task List sub-page ---------------------------------------------- */
.task-list-header {
  display: flex; align-items: center; gap: 12px;
  margin: 8px 0 16px;
}
.task-list-back {
  width: 44px; height: 44px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 20px; color: var(--ink); cursor: pointer;
}
.task-list-back:active { background: var(--bg-2); }
.task-list-title { font-size: 20px; font-weight: 700; letter-spacing: -0.015em; margin: 0; color: var(--ink); }

.task-list-pills { margin-bottom: 12px; }
.task-list-pills .filter-pill-count {
  margin-left: 4px; padding: 1px 6px;
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  border-radius: 8px;
  font-size: 11px;
}

.task-list-sort-row {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 16px;
}
.task-list-sort-label {
  font-size: 13px; font-weight: 600; color: var(--ink-3);
}
.task-list-sort {
  min-height: 36px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 8px;
  font-family: inherit; font-size: 14px;
  padding: 6px 10px;
  color: var(--ink);
}

.task-list-rows { display: flex; flex-direction: column; gap: 8px; }
.task-list-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 64px;
  padding: 12px 14px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
  transition: background 160ms ease-out;
}
.task-list-row:hover { background: var(--bg-2); }
.task-list-row:active { background: var(--bg-3, var(--bg-2)); }
.task-list-row.task-status-done { opacity: 0.7; }
.task-list-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.task-list-row-title { font-size: 14px; font-weight: 600; color: var(--ink); line-height: 1.4; }
.task-list-row-meta { display: flex; gap: 8px; flex-wrap: wrap; }
.task-list-row-chevron { font-size: 24px; color: var(--ink-3); flex: 0 0 auto; }

.task-assignee-chip {
  font-size: 11px; font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg-2); color: var(--ink-2);
}
.task-assignee-chip-unassigned { background: color-mix(in srgb, var(--warning) 16%, var(--bg-2)); color: var(--ink); }
.task-assignee-chip-assigned { background: color-mix(in srgb, var(--success) 12%, var(--bg-2)); color: var(--ink); }

.task-status-pill {
  font-size: 11px; font-weight: 600;
  padding: 2px 8px; border-radius: 999px;
  background: var(--bg-2); color: var(--ink-2);
}
.task-pill-open { background: color-mix(in srgb, var(--warning) 18%, var(--bg-2)); }
.task-pill-in_progress { background: color-mix(in srgb, var(--accent) 18%, var(--bg-2)); }
.task-pill-done { background: color-mix(in srgb, var(--success) 18%, var(--bg-2)); }

.task-list-empty {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 40px 24px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 12px;
  text-align: center;
}
.task-list-empty-icon { font-size: 32px; opacity: 0.6; }
.task-list-empty-title { font-size: 15px; font-weight: 600; color: var(--ink); }
.task-list-empty-sub { font-size: 13px; color: var(--ink-3); line-height: 1.55; max-width: 360px; }

/* ----- Task detail sheet ----------------------------------------------- */
.task-detail-sheet { display: flex; flex-direction: column; gap: 18px; }
.task-detail-header { display: flex; flex-direction: column; gap: 8px; }
.task-detail-title { font-size: 16px; font-weight: 600; line-height: 1.4; color: var(--ink); }
.task-detail-meta { display: flex; gap: 6px; flex-wrap: wrap; }
.task-detail-meta-pill {
  font-size: 11px; font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--bg-2); color: var(--ink-2);
}
.task-detail-meta-pill-muted { color: var(--ink-3); background: transparent; border: 1px solid var(--border); }
.task-detail-od-hint {
  font-size: 12px; color: var(--ink-3); line-height: 1.55;
  padding: 8px 10px;
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 8px;
  border-left: 3px solid var(--accent);
}

.task-detail-form { display: flex; flex-direction: column; gap: 14px; }
.task-detail-field { display: flex; flex-direction: column; gap: 6px; }
.task-detail-field-label { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.task-detail-field select,
.task-detail-field textarea {
  font-family: inherit; font-size: 14px;
  min-height: 44px;
  padding: 10px 12px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--ink);
}
.task-detail-field textarea { resize: vertical; min-height: 80px; }

.task-detail-activity { border-top: 1px solid var(--border); padding-top: 14px; }
.task-detail-activity-label { font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 8px; }
.task-detail-activity-list { display: flex; flex-direction: column; gap: 8px; }
.task-detail-activity-loading,
.task-detail-activity-empty { font-size: 13px; color: var(--ink-3); }
.task-activity-entry { font-size: 13px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.task-activity-entry:last-child { border-bottom: none; }
.task-activity-action { font-weight: 600; color: var(--ink-2); text-transform: capitalize; }
.task-activity-meta { font-size: 12px; color: var(--ink-3); margin-top: 2px; }

/* =============================================================================
   Migration 112 — Practice Profiles + Daily Duties
   ========================================================================== */

/* ---- Profile avatar (shared circle used everywhere) ---- */
.profile-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: #fff;
  font-weight: 700;
  font-family: inherit;
  line-height: 1;
  flex-shrink: 0;
}
.profile-avatar-placeholder {
  background: var(--ink-3);
  color: var(--card);
}

/* ---- Profile Picker overlay (Netflix-style entry) ---- */
.profile-picker-overlay {
  position: fixed;
  inset: 0;
  background: var(--bg);
  z-index: 9000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  overflow-y: auto;
}
.profile-picker-inner {
  width: 100%;
  max-width: 720px;
  text-align: center;
}
.profile-picker-heading {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 8px;
}
.profile-picker-subhead {
  font-size: 14px;
  color: var(--ink-3);
  margin: 0 0 32px;
}
.profile-picker-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin: 0 auto;
  max-width: 480px;
}
@media (min-width: 600px) {
  .profile-picker-grid { grid-template-columns: repeat(3, 1fr); max-width: 720px; }
}
.profile-picker-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 20px 12px 16px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  cursor: pointer;
  transition: transform 120ms ease-out, box-shadow 120ms ease-out, border-color 120ms ease-out;
  min-height: 44px;
}
.profile-picker-card:hover {
  border-color: var(--accent-on-light);
  box-shadow: 0 4px 12px rgba(24, 24, 27, 0.08);
  transform: translateY(-1px);
}
.profile-picker-card:active { transform: translateY(0); background: var(--bg-2); }
.profile-picker-avatar {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 24px;
  font-weight: 700;
}
.profile-picker-name {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.profile-picker-role {
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-3);
}
.profile-picker-manage-link {
  margin-top: 32px;
  background: none;
  border: none;
  color: var(--accent-on-light);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 12px 16px;
  border-radius: 8px;
  min-height: 44px;
}
.profile-picker-manage-link:hover { background: var(--bg-2); }

/* ---- Topbar avatar button ---- */
.topbar-profile-avatar-btn {
  padding: 6px !important;
}
.topbar-profile-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}

/* ---- Profile switch bottom sheet ---- */
.profile-switch-sheet { padding: 16px 0 8px; }
.profile-switch-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 16px;
}
.profile-switch-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.profile-switch-row {
  display: flex;
  align-items: center;
  gap: 12px;
  background: none;
  border: none;
  border-radius: 12px;
  padding: 12px;
  cursor: pointer;
  text-align: left;
  min-height: 44px;
  transition: background 120ms ease-out;
}
.profile-switch-row:hover { background: var(--bg-2); }
.profile-switch-row.is-active { background: var(--bg-2); }
.profile-switch-row-text { flex: 1; }
.profile-switch-row-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.profile-switch-row-role { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.profile-switch-active-dot {
  color: var(--accent-on-light);
  font-weight: 700;
}
.profile-switch-footer { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.profile-switch-manage {
  background: none;
  border: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
  padding: 10px 16px;
  border-radius: 10px;
  cursor: pointer;
  min-height: 44px;
  width: 100%;
}
.profile-switch-manage:hover { background: var(--bg-2); }

/* ---- Practice Health → Duties entry row (above tile grid) ---- */
.ph-duties-entry {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 16px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  cursor: pointer;
  text-align: left;
  margin-bottom: 12px;
  transition: border-color 120ms ease-out, box-shadow 120ms ease-out;
}
.ph-duties-entry:hover {
  border-color: var(--accent-on-light);
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.04);
}
.ph-duties-entry:active { background: var(--bg-2); }
.ph-duties-entry-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-2);
  color: var(--accent-on-light);
}
.ph-duties-entry-text { flex: 1; }
.ph-duties-entry-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.ph-duties-entry-sub { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.ph-duties-entry-chev { font-size: 22px; color: var(--ink-4); line-height: 1; }

/* ---- Duties sub-page ---- */
.duties-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 8px 0 16px;
}
.duties-back {
  background: none;
  border: none;
  font-size: 22px;
  color: var(--ink);
  cursor: pointer;
  padding: 8px 12px;
  border-radius: 8px;
  min-width: 44px;
  min-height: 44px;
}
.duties-back:hover { background: var(--bg-2); }
.duties-header-text { flex: 1; }
.duties-title { font-size: 20px; font-weight: 700; letter-spacing: -0.015em; margin: 0; color: var(--ink); }
.duties-subtitle { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.duties-filter select {
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  min-height: 44px;
}

.duties-progress-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  margin-bottom: 16px;
}
.duties-progress-left {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}
.duties-progress-text { flex: 1; }
.duties-progress-title { font-size: 16px; font-weight: 700; color: var(--ink); }
.duties-progress-count { font-size: 13px; font-weight: 500; color: var(--ink-3); margin-top: 2px; }
.duties-progress-subline { font-size: 12px; color: var(--ink-3); margin-top: 4px; }
.duties-progress-ring {
  position: relative;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
}
.duties-progress-pct {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--ink-2);
}

.duties-section {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 16px;
  margin-bottom: 12px;
}
.duties-section-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.duties-section-glyph { font-size: 18px; color: var(--accent-on-light); }
.duties-section-meta { flex: 1; }
.duties-section-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}
.duties-section-sub { font-size: 11px; color: var(--ink-4); margin-top: 2px; }
.duties-section-count {
  font-size: 12px;
  font-weight: 700;
  color: var(--ink-2);
  background: var(--bg-2);
  padding: 4px 10px;
  border-radius: 12px;
}

.duties-rows { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 4px; }
.duties-row-empty { font-size: 12px; color: var(--ink-4); padding: 8px 12px; }

.duty-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  min-height: 44px;
}
.duty-row.is-done .duty-row-title { text-decoration: line-through; color: var(--ink-3); }
.duty-checkbox {
  width: 24px;
  height: 24px;
  min-width: 24px;
  min-height: 24px;
  border: 2px solid var(--border);
  border-radius: 6px;
  background: var(--card);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  padding: 0;
  transition: background 120ms ease-out, border-color 120ms ease-out;
  /* tap-zone padding via the row's flex gap; min-height enforces target */
}
.duty-checkbox.is-checked {
  background: var(--accent-on-light);
  border-color: var(--accent-on-light);
}
.duty-row-body {
  flex: 1;
  background: none;
  border: none;
  padding: 4px 0;
  text-align: left;
  cursor: pointer;
  color: inherit;
  min-height: 44px;
}
.duty-row-title { font-size: 14px; font-weight: 500; color: var(--ink); line-height: 1.4; }
.duty-row-completed-by { font-size: 11px; color: var(--ink-4); margin-top: 2px; }
.duty-cat-chip {
  display: inline-flex;
  align-items: center;
  padding: 4px 8px;
  border-radius: 12px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
  white-space: nowrap;
}
.duty-cat-ops     { background: #6B7280; color: #fff; }
.duty-cat-sched   { background: #84A98C; color: #fff; }
.duty-cat-ins     { background: #9D8DC9; color: #fff; }
.duty-cat-billing { background: #D4A574; color: #fff; }
.duty-cat-pflow   { background: #E8B197; color: #2D2D2D; }
.duty-cat-comp    { background: #C77E7E; color: #fff; }

.duty-row-assignee {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.duties-empty {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 24px;
  text-align: center;
}
.duties-empty-title { font-size: 16px; font-weight: 700; color: var(--ink); margin-bottom: 4px; }
.duties-empty-body { font-size: 13px; color: var(--ink-3); }

/* ---- Settings → Practice Info → Staff Profiles sub-page ---- */
.settings-profiles-page { padding: 4px 0 16px; }
.settings-sub-intro {
  font-size: 13px;
  color: var(--ink-3);
  margin: 0 0 16px;
  line-height: 1.5;
}
.settings-profiles-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}
.settings-profiles-empty {
  font-size: 13px;
  color: var(--ink-3);
  padding: 16px;
  background: var(--bg-2);
  border-radius: 12px;
  text-align: center;
}
.settings-profile-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  min-height: 44px;
}
.settings-profile-text { flex: 1; }
.settings-profile-name { font-size: 14px; font-weight: 600; color: var(--ink); }
.settings-profile-role { font-size: 12px; color: var(--ink-3); margin-top: 2px; }
.settings-profile-archive {
  background: none;
  border: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 600;
  padding: 8px 12px;
  border-radius: 8px;
  cursor: pointer;
  min-height: 44px;
}
.settings-profile-archive:hover { background: var(--bg-2); }
.settings-profiles-readonly-note {
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
}

.settings-profile-create-form {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.settings-profile-create-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}
.settings-profile-field { display: flex; flex-direction: column; gap: 6px; }
.settings-profile-field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.settings-profile-field input[type="text"] {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink);
  font-size: 14px;
  min-height: 44px;
}
.settings-profile-swatch-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.settings-profile-swatch {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  cursor: pointer;
  border: 2px solid transparent;
}
.settings-profile-swatch input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.settings-profile-swatch-tick {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 700;
  opacity: 0;
  transition: opacity 120ms ease-out;
}
.settings-profile-swatch input:checked + .settings-profile-swatch-tick { opacity: 1; }
.settings-profile-swatch:has(input:checked) {
  border-color: var(--ink);
  box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--accent-on-light);
}
.settings-profile-actions { display: flex; justify-content: flex-end; }
.settings-profile-form-error {
  font-size: 12px;
  color: var(--danger);
  padding: 8px 12px;
  background: rgba(239, 68, 68, 0.08);
  border-radius: 8px;
}

/* =============================================================================
   Migration 114 — Profile PIN protection + Manager View + Assign Task
   ========================================================================== */

/* ---- PIN prompt overlay (Picker / Switch entry gate) ---- */
.profile-pin-overlay {
  z-index: 9100;
}
.profile-pin-inner {
  max-width: 360px;
}
.profile-pin-avatar {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 28px;
  font-weight: 700;
  margin-bottom: 16px;
}
.profile-pin-heading {
  font-size: 22px;
  margin: 0 0 4px;
}
.profile-pin-role {
  font-size: 13px;
  color: var(--ink-3);
  margin: 0 0 24px;
}
.profile-pin-instruction {
  font-size: 13px;
  color: var(--ink-3);
  margin: 0 0 16px;
}
.profile-pin-digit-row {
  display: flex;
  gap: 12px;
  justify-content: center;
  margin: 0 auto 16px;
}
.profile-pin-digit-row.is-shake {
  animation: profile-pin-shake 360ms ease-out;
}
@keyframes profile-pin-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-10px); }
  40% { transform: translateX(10px); }
  60% { transform: translateX(-6px); }
  80% { transform: translateX(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .profile-pin-digit-row.is-shake { animation: none; }
}
.profile-pin-digit {
  width: 56px;
  height: 64px;
  font-size: 28px;
  font-weight: 700;
  text-align: center;
  border: 2px solid var(--border);
  border-radius: 12px;
  background: var(--card);
  color: var(--ink);
  -webkit-text-security: disc;
  text-security: disc;
}
.profile-pin-digit:focus {
  outline: none;
  border-color: var(--accent-on-light);
}
.profile-pin-digit:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}
.profile-pin-status {
  min-height: 18px;
  font-size: 13px;
  color: var(--danger);
  margin-bottom: 16px;
}
.profile-pin-back-link {
  background: none;
  border: none;
  color: var(--accent-on-light);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 12px 16px;
  border-radius: 8px;
  min-height: 44px;
}
.profile-pin-back-link:hover { background: var(--bg-2); }

/* ---- Settings → Profiles PIN indicator + action ---- */
.settings-profile-pin {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 4px;
}
.settings-profile-pin-label {
  font-size: 11px;
  color: var(--ink-4);
  font-weight: 600;
  letter-spacing: 0.04em;
}
.settings-profile-pin-action {
  background: none;
  border: none;
  color: var(--accent-on-light);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: 6px;
  min-height: 24px;
}
.settings-profile-pin-action:hover { background: var(--bg-2); }
.settings-profile-field-helper {
  display: block;
  font-size: 11px;
  color: var(--ink-4);
  font-weight: 400;
  margin-top: -2px;
  margin-bottom: 6px;
}

/* Set / Change / Remove PIN sheet — reused by both Settings → Profiles row
   button and the create-profile form's optional PIN input. */
.set-pin-sheet { padding: 16px 0 8px; }
.set-pin-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 8px;
}
.set-pin-intro {
  font-size: 12px;
  color: var(--ink-3);
  margin: 0 0 20px;
}
.set-pin-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}
.set-pin-field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.set-pin-digit-row {
  display: flex;
  gap: 10px;
}
.set-pin-digit {
  width: 48px;
  height: 56px;
  font-size: 22px;
  font-weight: 700;
  text-align: center;
  border: 2px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  color: var(--ink);
  -webkit-text-security: disc;
  text-security: disc;
}
.set-pin-digit:focus {
  outline: none;
  border-color: var(--accent-on-light);
}
.set-pin-error {
  font-size: 12px;
  color: var(--danger);
  background: rgba(239, 68, 68, 0.08);
  padding: 8px 12px;
  border-radius: 8px;
  margin-bottom: 12px;
}
.set-pin-remove-link {
  display: block;
  margin: 12px auto 0;
  background: none;
  border: none;
  color: var(--danger);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  padding: 10px 14px;
  border-radius: 8px;
  min-height: 44px;
}
.set-pin-remove-link:hover { background: rgba(239, 68, 68, 0.06); }

/* ---- Duties Board — Manager View segmented toggle ---- */
.duties-header-controls {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-end;
}
.duties-view-toggle {
  display: inline-flex;
  background: var(--bg-2);
  border-radius: 12px;
  padding: 2px;
}
.duties-view-seg {
  background: none;
  border: none;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  padding: 8px 12px;
  border-radius: 10px;
  cursor: pointer;
  min-height: 36px;
  transition: background 120ms ease-out, color 120ms ease-out;
}
.duties-view-seg.is-active {
  background: var(--card);
  color: var(--ink);
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.04);
}
.duties-view-seg:hover:not(.is-active) {
  color: var(--ink-2);
}

/* ---- Manager View body ---- */
.duties-manager-view { display: flex; flex-direction: column; gap: 12px; }
.duties-manager-loading,
.duties-manager-error,
.manager-empty-row {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 24px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-3);
}
.duties-manager-error { color: var(--danger); }

.manager-header-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
}
.manager-header-text { flex: 1; }
.manager-header-eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
}
.manager-header-date {
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  margin-top: 2px;
}
.manager-assign-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 44px;
  padding: 10px 14px;
}
.manager-assign-plus {
  font-size: 18px;
  line-height: 1;
  font-weight: 700;
}

/* Per-staff cards row — horizontal scroll on mobile when overflow */
.manager-staff-cards {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding: 4px 4px 4px 0;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.manager-staff-card {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 12px;
  min-width: 230px;
  cursor: pointer;
  text-align: left;
  scroll-snap-align: start;
  transition: border-color 120ms ease-out, box-shadow 120ms ease-out;
}
.manager-staff-card:hover {
  border-color: var(--accent-on-light);
  box-shadow: 0 1px 0 rgba(24, 24, 27, 0.04);
}
.manager-staff-card:active { background: var(--bg-2); }
.manager-staff-card-text { flex: 1; min-width: 0; }
.manager-staff-card-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.manager-staff-card-role {
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-4);
  margin-top: 2px;
}
.manager-staff-card-caption {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  margin-top: 4px;
}
.manager-staff-card-ring {
  position: relative;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
}
.manager-staff-card-pct {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
  color: var(--ink-2);
}

/* Section card (Work in progress, By category) */
.manager-section {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 16px;
}
.manager-section-header {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin-bottom: 12px;
}

/* Work-in-progress rows */
.manager-wip-rows { display: flex; flex-direction: column; gap: 4px; }
.manager-wip-empty {
  font-size: 12px;
  color: var(--ink-3);
  padding: 12px;
  text-align: center;
}
.manager-wip-row {
  display: flex;
  align-items: center;
  gap: 12px;
  background: none;
  border: none;
  text-align: left;
  padding: 10px 8px;
  border-radius: 10px;
  cursor: pointer;
  min-height: 44px;
  transition: background 120ms ease-out;
}
.manager-wip-row:hover { background: var(--bg-2); }
.manager-wip-row-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  flex-shrink: 0;
}
.manager-wip-row-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  flex: 1;
  justify-content: flex-end;
}
.manager-wip-count {
  font-size: 11px;
  font-weight: 600;
  padding: 4px 8px;
  border-radius: 10px;
  background: var(--bg-2);
  color: var(--ink-2);
}
.manager-wip-count-open {
  background: rgba(245, 158, 11, 0.12);
  color: #B45309;
}
.manager-wip-count-progress {
  background: rgba(59, 130, 246, 0.12);
  color: #1D4ED8;
}
.manager-wip-count-done {
  background: rgba(34, 197, 94, 0.14);
  color: #166534;
}
.manager-wip-chev { font-size: 22px; color: var(--ink-4); line-height: 1; }

/* Per-category tiles */
.manager-category-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
@media (min-width: 600px) {
  .manager-category-grid { grid-template-columns: repeat(3, 1fr); }
}
.manager-category-tile {
  background: var(--bg-2);
  border-radius: 14px;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.manager-category-tile-numeric {
  font-size: 24px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.manager-category-tile-sub {
  font-size: 11px;
  color: var(--ink-3);
  font-weight: 500;
}

/* ---- Assign Task modal ---- */
.assign-task-modal {
  padding: 16px 0 8px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.assign-task-title {
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0 0 4px;
}
.assign-task-field { display: flex; flex-direction: column; gap: 6px; }
.assign-task-field-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
}
.assign-task-field input[type="text"],
.assign-task-field input[type="date"],
.assign-task-field select,
.assign-task-field textarea {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  color: var(--ink);
  font-size: 14px;
  font-family: inherit;
  min-height: 44px;
}
.assign-task-field textarea {
  min-height: 60px;
  resize: vertical;
}
.assign-task-error {
  font-size: 12px;
  color: var(--danger);
  background: rgba(239, 68, 68, 0.08);
  padding: 8px 12px;
  border-radius: 8px;
}

/* =============================================================================
   Migration 117 — PPO Write-Off Analysis tile + drill sub-page
   ========================================================================== */

/* ---- Practice Health tile ---- */
.ppo-tile {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.ppo-tile-hero {
  text-align: center;
  padding: 8px 0 4px;
}
.ppo-tile-hero-num {
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--accent-on-light);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ppo-tile-hero-sub {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  margin-top: 4px;
}
.ppo-tile-comparison {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.ppo-tile-comparison-yours { color: var(--ink-2); }
.ppo-tile-comparison-yours.is-above b { color: var(--danger); }
.ppo-tile-comparison-yours.is-ok b { color: var(--accent-on-light); }
.ppo-tile-comparison-sep { color: var(--ink-4); }
.ppo-tile-comparison-median { color: var(--ink-3); }
.ppo-tile-source-note {
  text-align: center;
  font-size: 11px;
  color: var(--ink-4);
  font-style: italic;
}
.ppo-tile-table { display: flex; flex-direction: column; gap: 4px; }
.ppo-tile-table-head {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1.3fr;
  gap: 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
}
.ppo-tile-table-recov,
.ppo-tile-row-recov { text-align: right; }
.ppo-tile-table-rates,
.ppo-tile-row-rates { text-align: right; }
.ppo-tile-row {
  display: grid;
  grid-template-columns: 1.2fr 1fr 1.3fr;
  gap: 8px;
  padding: 8px 4px;
  font-size: 13px;
  align-items: center;
  border-bottom: 1px solid var(--border);
}
.ppo-tile-row:last-child { border-bottom: none; }
.ppo-tile-row-name {
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ppo-tile-row-recov {
  font-weight: 700;
  color: var(--accent-on-light);
  font-variant-numeric: tabular-nums;
}
.ppo-tile-row-rates-cur { color: var(--danger); font-variant-numeric: tabular-nums; }
.ppo-tile-row-rates-bench { color: var(--ink-4); font-size: 11px; }
.ppo-tile-cta {
  background: var(--bg-2);
  border: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
  padding: 12px 16px;
  border-radius: 12px;
  cursor: pointer;
  min-height: 44px;
  margin-top: 4px;
}
.ppo-tile-cta:hover {
  border-color: var(--accent-on-light);
  color: var(--ink);
}

/* "On track" affirming state */
.ppo-tile-ontrack {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 16px;
  background: var(--bg-2);
  border-radius: 12px;
}
.ppo-tile-ontrack-icon {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--accent-on-light);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  font-weight: 700;
  flex-shrink: 0;
}
.ppo-tile-ontrack-text { flex: 1; }
.ppo-tile-ontrack-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.ppo-tile-ontrack-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
}

/* ---- Drill sub-page ---- */
.ppo-drill-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 8px 0 16px;
}
.ppo-drill-back {
  background: none;
  border: none;
  font-size: 22px;
  color: var(--ink);
  cursor: pointer;
  padding: 8px 12px;
  border-radius: 8px;
  min-width: 44px;
  min-height: 44px;
}
.ppo-drill-back:hover { background: var(--bg-2); }
.ppo-drill-header-text { flex: 1; }
.ppo-drill-title {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin: 0;
  color: var(--ink);
}
.ppo-drill-subtitle {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 2px;
}

.ppo-drill-empty {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 24px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-3);
}

.ppo-drill-summary {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 16px;
  margin-bottom: 12px;
}
.ppo-drill-hero {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--accent-on-light);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ppo-drill-hero-sub {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: 4px;
  margin-bottom: 12px;
}
.ppo-drill-summary-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 13px;
  padding: 6px 0;
  border-top: 1px solid var(--border);
}
.ppo-drill-summary-label { color: var(--ink-3); }
.ppo-drill-summary-value {
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ppo-drill-summary-value.is-above { color: var(--danger); }
.ppo-drill-summary-value.is-ok { color: var(--accent-on-light); }
.ppo-drill-summary-source {
  font-weight: 500;
  font-size: 11px;
  color: var(--ink-4);
}

.ppo-drill-table {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}
.ppo-drill-row {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 14px;
  border-left-width: 4px;
}
.ppo-drill-row.priority-high { border-left-color: var(--danger); }
.ppo-drill-row.priority-medium { border-left-color: var(--warning, #d97706); }
.ppo-drill-row.priority-low { border-left-color: var(--ink-4); }
.ppo-drill-row.priority-ontrack { border-left-color: var(--accent-on-light); }
.ppo-drill-row-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}
.ppo-drill-row-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}
.ppo-drill-row-delta {
  font-size: 11px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 10px;
}
.ppo-drill-row-delta.is-above {
  background: rgba(239, 68, 68, 0.12);
  color: var(--danger);
}
.ppo-drill-row-delta.is-ok {
  background: rgba(34, 197, 94, 0.14);
  color: var(--accent-on-light);
}
.ppo-drill-row-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  margin-bottom: 10px;
}
@media (min-width: 600px) {
  .ppo-drill-row-stats { grid-template-columns: repeat(4, 1fr); }
}
.ppo-drill-row-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--bg-2);
  padding: 8px 10px;
  border-radius: 8px;
}
.ppo-drill-row-stat-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.ppo-drill-row-stat-value {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ppo-drill-row-stat-value.is-above { color: var(--danger); }
.ppo-drill-row-recov {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 10px 0;
  border-top: 1px dashed var(--border);
  border-bottom: 1px dashed var(--border);
  margin-bottom: 10px;
}
.ppo-drill-row-recov-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.ppo-drill-row-recov-value {
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.ppo-drill-row-recov-value.is-positive { color: var(--accent-on-light); }
.ppo-drill-row-recov-value.is-zero { color: var(--ink-3); }
.ppo-drill-row-priority {
  font-size: 12px;
  font-weight: 600;
  text-align: center;
  padding: 6px 8px;
  border-radius: 8px;
}
.ppo-drill-row-priority.priority-high {
  background: rgba(239, 68, 68, 0.10);
  color: var(--danger);
}
.ppo-drill-row-priority.priority-medium {
  background: rgba(217, 119, 6, 0.10);
  color: #B45309;
}
.ppo-drill-row-priority.priority-low {
  background: var(--bg-2);
  color: var(--ink-3);
}
.ppo-drill-row-priority.priority-ontrack {
  background: rgba(34, 197, 94, 0.10);
  color: var(--accent-on-light);
}

.ppo-drill-playbook {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 16px;
  margin-top: 8px;
}
.ppo-drill-playbook-title {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  margin: 0 0 12px;
}
.ppo-drill-playbook-list {
  list-style: disc;
  padding-left: 20px;
  margin: 0 0 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ppo-drill-playbook-list li {
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.5;
}
.ppo-drill-cta-help {
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}



/* =============================================================================
   Migration 120 — admin "View as" / read-only impersonation
   ========================================================================== */

/* Sticky orange banner pinned to the very top of the document when an
   admin is impersonating a customer practice. Sits ABOVE the topbar
   header so it can never be hidden by tab switches or scrolling. */
.admin-view-as-banner {
  position: sticky;
  top: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 16px;
  background: #b45309;   /* deep amber — distinct from billing-warning lime */
  color: #ffffff;
  font-size: 13px;
  font-weight: 600;
  min-height: 40px;
  border-bottom: 2px solid #92400e;
}
.admin-view-as-eye {
  font-size: 16px;
}
.admin-view-as-label {
  flex: 1;
  letter-spacing: -0.01em;
}
.admin-view-as-exit-btn {
  background: #ffffff;
  color: #b45309;
  border: none;
  font-size: 12px;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 6px;
  cursor: pointer;
  min-height: 28px;
}
.admin-view-as-exit-btn:hover {
  background: #fef3c7;
}

/* Visual dimming of write controls in admin view-as mode. The toast
   guard at isBillingReadOnly() is the load-bearing safety net; this
   styling makes the read-only state visually obvious so the admin
   never expects a click to do anything. */
body.admin-view-as .btn-primary,
body.admin-view-as button[type="submit"],
body.admin-view-as .toggle-switch input[type="checkbox"]:not([disabled]),
body.admin-view-as .duty-checkbox,
body.admin-view-as .btn-save-reclassify,
body.admin-view-as .settings-doctor-add-trigger,
body.admin-view-as .settings-doctor-add-save,
body.admin-view-as .settings-profile-archive,
body.admin-view-as .settings-profile-pin-action,
body.admin-view-as .ph-duties-entry,
body.admin-view-as .manager-assign-btn,
body.admin-view-as .assign-task-create,
body.admin-view-as .btn-exclusion,
body.admin-view-as #add-txn-fab,
/* Admin view-as Settings sweep (2026-06-06) — extend the dim-visual
   pattern to Settings → Integration (Bank + PMS) + Notifications +
   Advanced Settings (Chart of Account) write controls. Handlers route
   through isBillingReadOnly() which already catches view-as. */
body.admin-view-as .settings-backfill,
body.admin-view-as .settings-disconnect,
body.admin-view-as .bank-refresh-all-link,
body.admin-view-as .bank-add-link,
body.admin-view-as .notifications-toggle-input:not([disabled]),
body.admin-view-as .notifications-admin-btn,
body.admin-view-as .pms-sync-btn,
body.admin-view-as .pms-disconnect-btn,
body.admin-view-as .pms-generate-btn,
body.admin-view-as .pms-regenerate-link,
body.admin-view-as .pms-test-btn,
body.admin-view-as .pms-cancel-link,
body.admin-view-as .pms-auto-refresh-toggle input[type="checkbox"]:not([disabled]),
body.admin-view-as .pms-backfill-start-btn,
body.admin-view-as .pms-backfill-rerun-btn,
body.admin-view-as .pms-backfill-cancel-btn,
body.admin-view-as .coa-hide-btn,
body.admin-view-as .coa-unhide-btn,
body.admin-view-as .coa-delete-btn,
body.admin-view-as .coa-restore-btn,
body.admin-view-as .coa-undo-btn,
body.admin-view-as .coa-delete-forever-btn,
body.admin-view-as .coa-purge-btn,
body.admin-view-as .coa-reset-order-btn,
body.admin-view-as .coa-add-custom-btn,
body.admin-view-as .coa-add-l3-btn,
body.admin-view-as .coa-l3-delete-btn,
body.admin-view-as .coa-rename-save,
body.admin-view-as .coa-rename-reset,
body.admin-view-as .coa-purge-confirm,
body.admin-view-as .coa-add-btn,
body.admin-view-as .coa-reset-btn,
body.admin-view-as .coa-rename-input,
body.admin-view-as .bank-disconnect-confirm,
body.admin-view-as .vendor-rules-edit-save,
body.admin-view-as .vendor-rules-sheet-confirm {
  opacity: 0.55;
  cursor: not-allowed;
}
body.admin-view-as .btn-primary:hover,
body.admin-view-as button[type="submit"]:hover {
  filter: none;
}


/* =============================================================================
   Doctor role badge (OWNER / ASSOCIATE) + inline popover — Edwin product
   call 2026-06-01. Surfaces in P&L Doctor Pay & Distributions per-doctor
   rows + Overview Dr. Takehome tile rows. Tap badge opens
   openDoctorRolePopover with is_owner toggle + confirm + save.
   ========================================================================== */

.doctor-role-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 2px 7px;
  border: 1px solid transparent;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  font-family: inherit;
  cursor: pointer;
  vertical-align: 0.18em;  /* nudges the pill up so it sits aligned with the doctor-name baseline */
  line-height: 1.4;
}
.doctor-role-badge:hover { filter: brightness(0.96); }
.doctor-role-badge:active { transform: translateY(1px); }

.doctor-role-owner {
  background: #FEF3C7;   /* muted amber/gold */
  color: #92400E;
  border-color: #FDE68A;
}
.doctor-role-associate {
  background: #F3F4F6;   /* muted gray */
  color: #4B5563;
  border-color: #E5E7EB;
}

/* Popover bottom-sheet content */
.doctor-role-popover {
  padding: 8px 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.doctor-role-popover-title {
  font-size: 16px;
  font-weight: 700;
  margin: 0;
  color: var(--ink);
}
.doctor-role-popover-name {
  font-size: 18px;
  font-weight: 600;
  color: var(--ink-2);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.doctor-role-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 0;
}
.doctor-role-toggle-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.doctor-role-popover-help {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-3);
  margin: 0;
}
.doctor-role-popover-warning {
  display: none;
  background: #FFFBEB;
  border-left: 3px solid #F59E0B;
  border-radius: 4px;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.45;
  color: #92400E;
}
.doctor-role-popover-readonly {
  font-size: 12px;
  color: var(--ink-3);
  font-style: italic;
  padding: 8px 12px;
  background: var(--bg-2);
  border-radius: 6px;
}

/* =============================================================================
 * Categorization Rules page — admin_items #92 Commit 2
 * =============================================================================
 * Visual register mirrors COA editor row chrome per Edwin's visual
 * constraint #1 (heavier sibling of .coa-row, not a foreign UI
 * element). Reuses existing .pill / .filter-pills / .search-wrap /
 * .search-input / .txn-ai-hint classes byte-identically. Only adds
 * row-specific classes here.
 *
 * Spacing scale per CLAUDE.md UI principles: 4 / 8 / 10 / 12 / 14 /
 * 16 / 20 / 24px rhythm. Font sizes: 14px primary, 12px meta, 11px
 * chip. Colors: var(--ink) for primary, var(--ink-3) for meta + 0
 * states. No new accents.
 */
.vendor-rules-card {
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Controls block — search above, pills below, sort row at the bottom.
   Same 12px stack rhythm as the Activity tab filter chrome. Commit 2.3
   dropped the header subtitle entirely (money-found copy + N-rules
   count); the page title rendered by the parent settings sub-page is
   self-explanatory and the rule list itself communicates count. */
.vendor-rules-controls {
  padding: 12px 16px 4px;
  border-bottom: 1px solid var(--border);
}
.vendor-rules-search-wrap {
  margin-bottom: 8px;
}
.vendor-rules-sort-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0 8px;
}
.vendor-rules-sort-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.vendor-rules-sort-select {
  flex: 1;
  padding: 6px 10px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  outline: none;
  min-height: 36px;
}

/* Rule rows — direct mirror of .coa-row chrome. Two-line layout
   inside .vendor-rules-row-main: pattern line + meta line. */
.vendor-rules-list {
  padding: 4px 16px 16px;
}
.vendor-rules-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
  min-height: 44px;
}
.vendor-rules-row:last-child { border-bottom: 0; }
.vendor-rules-row-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.vendor-rules-pattern-line {
  display: flex;
  align-items: baseline;
  gap: 4px;
  min-width: 0;
}
.vendor-rules-pattern {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
}
/* Commit 3.5 casing fallback — when display_name is null (no matches
   in cache window) the renderer falls back to the raw pattern with
   text-transform: capitalize. Lossy for all-caps merchants (IKEA,
   DentBooks) but only fires for zero-match rules where the fidelity
   loss is moot. */
.vendor-rules-pattern--capitalize {
  text-transform: capitalize;
}
.vendor-rules-meta-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  min-width: 0;
}
.vendor-rules-meta-sep { opacity: 0.5; }
.vendor-rules-category {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

/* Matches chip — same tabular-nums treatment as .coa-row-count, but
   trailing rather than inline so the meta line stays scannable. Zero-
   state lightens to signal "safe to clean up" (mirror of
   .coa-row-count-zero). */
.vendor-rules-matches-chip {
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.vendor-rules-matches-chip-zero {
  color: var(--ink-4, var(--ink-3));
  opacity: 0.6;
}

/* Empty state — single-sentence muted card. Apple-style "All clean."
   per visual constraint #7. */
.vendor-rules-empty {
  padding: 20px 4px;
  text-align: center;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-3);
}

/* Retry affordance inside the error empty body (Commit 2.2). Lives
   inline below the muted explainer so the "Refresh and try again"
   sentence and the tap target read as one unit. */
.vendor-rules-retry-wrap {
  margin-top: 10px;
  display: flex;
  justify-content: center;
}
.vendor-rules-retry-btn {
  min-height: 44px;
  padding: 10px 18px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background 140ms ease-out;
}
.vendor-rules-retry-btn:hover { background: var(--bg-2); }
.vendor-rules-retry-btn:active { background: var(--bg-2); opacity: 0.85; }
.vendor-rules-retry-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Commit 3.1 — cluster banner. Single full-width affordance above the
   rule list when clusters exist; tap toggles into cluster review mode.
   In review mode the banner becomes a "Done reviewing" back-link.
   Hidden entirely when N=0. Replaces the orphan filter pill from
   Commit 3 (a single-pill row read as broken at 412px).
   Commit 3.3 alignment fix: the mount carries 16px horizontal padding
   so the banner's outer edges align with the .vendor-rules-list
   children (which sit inside that list's 16px padding). Pre-fix the
   banner extended to the card_inner edges while rule rows sat 16px
   further in — Edwin's eye caught the misalignment at 412px. */
.vendor-rules-cluster-banner-mount {
  padding: 0 16px;
}
.vendor-rules-cluster-banner-mount:empty {
  display: none;
  padding: 0;
}
.vendor-rules-cluster-banner {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 56px;
  padding: 14px 16px;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: var(--bg-2);
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background 140ms ease-out, color 140ms ease-out;
}
.vendor-rules-cluster-banner:hover { background: var(--card); }
.vendor-rules-cluster-banner:active { background: var(--card); opacity: 0.85; }
.vendor-rules-cluster-banner:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.vendor-rules-cluster-banner-text { flex: 1 1 auto; min-width: 0; }
.vendor-rules-cluster-banner-cta {
  flex: 0 0 auto;
  color: var(--accent-on-light, var(--accent));
  font-size: 13px;
  font-weight: 700;
}
.vendor-rules-cluster-banner-arrow { font-weight: 700; opacity: 0.85; }
.vendor-rules-cluster-banner-active {
  background: var(--card);
  color: var(--ink-2);
}
.vendor-rules-cluster-banner-active:hover { background: var(--bg-2); color: var(--ink); }

/* Commit 3 — rows are tappable for inline-edit. Hover/active states
   for tactile feedback per CLAUDE.md UI design principles. */
.vendor-rules-row {
  cursor: pointer;
  transition: background 120ms ease-out;
}
.vendor-rules-row:hover { background: var(--bg-2); }
.vendor-rules-row:active { background: var(--bg-2); opacity: 0.85; }

/* Inline-edit state — replaces a row's view content with the edit
   form. Commit 3.2 alignment fix: horizontal padding stays 0 (matches
   the .vendor-rules-row { padding: 10px 0 } baseline) so left+right
   edges align with the rows above/below. Bg-2 background extends
   edge-to-edge of the card_inner zone, matching how a regular row's
   hover bg-2 would extend. */
.vendor-rules-row-editing {
  cursor: default;
  background: var(--bg-2);
  padding: 12px 0;
}
.vendor-rules-row-editing:hover { background: var(--bg-2); }
.vendor-rules-row-editing:active { background: var(--bg-2); opacity: 1; }
.vendor-rules-edit-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.vendor-rules-edit-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
}
.vendor-rules-edit-input {
  min-height: 44px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
}
.vendor-rules-edit-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.vendor-rules-edit-error {
  margin: 4px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--danger, #c62828);
}
.vendor-rules-edit-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  justify-content: flex-end;
}

/* Commit 3.2 — Recent-matching-transactions preview inside the edit
   form. Scrollable beyond the first 3 rows. Muted styling so it stays
   secondary to the editable fields above it. */
.vendor-rules-edit-matches {
  display: flex;
  flex-direction: column;
  max-height: 120px;
  overflow-y: auto;
  padding: 4px 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--card);
  font-size: 12px;
  color: var(--ink-3);
}
.vendor-rules-edit-match-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 10px;
  font-variant-numeric: tabular-nums;
}
.vendor-rules-edit-match-row + .vendor-rules-edit-match-row {
  border-top: 1px solid var(--border);
}
.vendor-rules-edit-match-date {
  flex: 0 0 auto;
  color: var(--ink-3);
}
.vendor-rules-edit-match-amount {
  flex: 0 0 auto;
  color: var(--ink-2);
  font-weight: 600;
}
.vendor-rules-edit-match-vendor {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* =============================================================================
   .btn-action-row — canonical action-row button (Commit 3.2, refactored 3.3)
   ============================================================================
   ALL action-row buttons (Cancel/Save/Delete/Confirm rows) MUST use this
   class. Fixed height, padding, font weight, font size, border radius.
   Color/intent variants (.btn-action-row--primary, .btn-action-row--danger)
   are BEM modifiers — they extend without inheriting size from any other
   class. DO NOT compose with `.btn-primary` or `.btn-secondary` — those
   are the global form-CTA classes (e.g., styles.css:3509) which carry
   `width: 100%` + `margin-top: 18px` + 12px border-radius and would
   poison the action-row sizing if combined. See CLAUDE.md "UI design
   principles → Visual polish → Action-row buttons". Codified from
   Commit 3.3 (admin_items #91) when Edwin's smoke caught the specificity
   conflict between Commit 3.2's `.btn-action-row.btn-primary` compound
   and the global `.btn-primary`.
   ========================================================================= */
.btn-action-row {
  /* Layout — owns size + spacing — never overridden by variants. */
  height: 44px;
  width: auto;
  padding: 0 16px;
  margin: 0;
  font-weight: 600;
  font-size: 14px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  min-width: 80px;
  cursor: pointer;
  transition: opacity 120ms ease-out, background 120ms ease-out;
}
.btn-action-row:hover { background: var(--bg-2); }
.btn-action-row:active { opacity: 0.8; }
.btn-action-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.btn-action-row:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}
.btn-action-row--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--brand, #0e1d18);
}
.btn-action-row--primary:hover { background: var(--accent); opacity: 0.92; }
.btn-action-row--danger {
  background: var(--card);
  border-color: var(--danger, #c62828);
  color: var(--danger, #c62828);
}
.btn-action-row--danger:hover { background: rgba(198, 40, 40, 0.08); }

/* Cluster card — distinct chrome from the row list so the "this is a
   group of rules, not a single rule" mental model lands instantly.
   Lives inside .vendor-rules-list so the surrounding card container's
   border-radius + horizontal alignment hold. */
.vendor-rules-cluster-card {
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.vendor-rules-cluster-card:last-child { border-bottom: 0; }
.vendor-rules-cluster-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.vendor-rules-cluster-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}
.vendor-rules-cluster-count-inline { font-weight: 700; }
.vendor-rules-cluster-category { color: var(--ink-2); }
.vendor-rules-cluster-meta {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.vendor-rules-cluster-members {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--bg-2);
  font-size: 13px;
}
.vendor-rules-cluster-member {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  min-height: 24px;
}
.vendor-rules-cluster-member-pattern {
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
.vendor-rules-cluster-member-count {
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  flex: 0 0 auto;
}
.vendor-rules-cluster-actions {
  display: flex;
  justify-content: flex-end;
}
.vendor-rules-cluster-merge-btn {
  min-height: 44px;
  padding: 10px 18px;
  border-radius: 10px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--accent-ink, #0e1d18);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 120ms ease-out;
}
.vendor-rules-cluster-merge-btn:hover { opacity: 0.92; }
.vendor-rules-cluster-merge-btn:active { opacity: 0.8; }
.vendor-rules-cluster-merge-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Bottom sheets — merge confirmation + delete confirmation. Created
   as siblings of the global #sheet via document.body.appendChild so
   they can stack independently. Mirror the COA purge sheet chrome from
   migration 101's frontend (admin_items #396 PART 8.5). */
.vendor-rules-sheet-backdrop {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 950;
}
.vendor-rules-merge-sheet,
.vendor-rules-delete-sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 960;
  background: var(--card);
  border-radius: 16px 16px 0 0;
  max-height: 92vh;
  overflow-y: auto;
  padding: 8px 16px 16px;
  box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.12);
  display: flex;
  flex-direction: column;
}
.vendor-rules-merge-sheet .sheet-handle,
.vendor-rules-delete-sheet .sheet-handle {
  margin: 6px auto 12px;
  width: 36px;
  height: 4px;
  border-radius: 2px;
  background: var(--ink-4, var(--ink-3));
  opacity: 0.4;
}
.vendor-rules-sheet-title {
  margin: 0 0 12px;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.vendor-rules-sheet-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-bottom: 12px;
}
.vendor-rules-sheet-section-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-3);
  margin-top: 4px;
}
.vendor-rules-sheet-rule-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--bg-2);
  font-size: 13px;
}
.vendor-rules-sheet-rule-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  min-height: 24px;
}
.vendor-rules-sheet-rule-pattern {
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
.vendor-rules-sheet-rule-meta {
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  flex: 0 0 auto;
}
.vendor-rules-sheet-input {
  min-height: 44px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
}
.vendor-rules-sheet-input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.vendor-rules-sheet-error {
  margin: 4px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--danger, #c62828);
}
.vendor-rules-sheet-warning {
  margin: 8px 0 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
}
.vendor-rules-sheet-checkbox {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px;
  border-radius: 8px;
  background: var(--bg-2);
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
  min-height: 44px;
}
.vendor-rules-sheet-checkbox input { margin-top: 2px; flex: 0 0 auto; }
.vendor-rules-sheet-checkbox span { flex: 1 1 auto; line-height: 1.4; }
/* Sheet action bar — layout only. Sizing/color of the buttons inside
   comes from .btn-action-row + variants per the Commit 3.2 codification. */
.vendor-rules-sheet-action-bar {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  margin-top: 8px;
}

