/* ============================================================
   PROJECT 2040 — MODERN FINANCIAL DESIGN SYSTEM
   ============================================================ */

/* ------------------------------------------------------------------
   1. Tokens          2. Reset & base      3. Typography
   4. Layout          5. Components        6. Pages
   7. Responsive      8. Themes
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
   FONTS — vendored, see static/fonts/ and README "Vendored assets".
   Both files are variable fonts subset to Latin + Latin Extended
   (covers Brazilian Portuguese diacritics — ç, ã, õ, é, í, ó, ú, â,
   ê, ô, à, ü — plus currency symbols and general punctuation).
   font-display: swap keeps first paint fast; the fallback metrics
   below reduce the reflow when the real face arrives.
   ------------------------------------------------------------------ */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/static/fonts/plus-jakarta-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0100-024F, U+0259, U+1E00-1EFF, U+2000-206F, U+20A0-20BF, U+2122;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 500 800;
  font-display: swap;
  src: url('/static/fonts/outfit-latin-ext.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0100-024F, U+0259, U+1E00-1EFF, U+2000-206F, U+20A0-20BF, U+2122;
}

/* Metric-matched fallbacks so the swap-in doesn't reflow the page —
   size-adjust/ascent/descent tuned against Arial to approximate each
   webfont's box. Referenced from --font-body/--font-title below. */
@font-face {
  font-family: 'Plus Jakarta Sans Fallback';
  src: local('Arial');
  size-adjust: 103%;
  ascent-override: 95%;
  descent-override: 24%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Outfit Fallback';
  src: local('Arial');
  size-adjust: 104%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

:root {
  /* ---- Type ------------------------------------------------------ */
  --font-body:  'Plus Jakarta Sans', 'Plus Jakarta Sans Fallback', system-ui, -apple-system, sans-serif;
  --font-title: 'Outfit', 'Outfit Fallback', system-ui, -apple-system, sans-serif;
  --font-mono:  ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, monospace;

  --text-2xs: 0.6875rem; /* 11px — micro labels, table meta        */
  --text-xs:  0.75rem;   /* 12px — badges, captions, hints          */
  --text-sm:  0.8125rem; /* 13px — dense table cells, chips         */
  --text-md:  0.875rem;  /* 14px — body default, buttons, inputs    */
  --text-lg:  1rem;      /* 16px — card titles, emphasised body     */
  --text-xl:  1.25rem;   /* 20px — section titles                   */
  --text-2xl: 1.5rem;    /* 24px — modal titles, small KPI values   */
  --text-3xl: 2rem;      /* 32px — page titles                      */
  --text-4xl: 2.5rem;    /* 40px — hero KPI values                  */

  --weight-regular: 400;
  --weight-medium:  500;
  --weight-semibold:600;
  --weight-bold:    700;
  --weight-black:   800;

  --leading-tight: 1.15;
  --leading-snug:  1.35;
  --leading-normal:1.55;

  --tracking-tight: -0.02em;
  --tracking-normal: 0;
  --tracking-wide:  0.04em;   /* uppercase eyebrow labels only */

  /* ---- Space (4px base) ------------------------------------------ */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;
  --space-8: 3rem;
  --space-9: 4rem;

  --space-page: var(--space-5);   /* app-container gutter, steps down on mobile */
  --space-card: var(--space-5);   /* card inner padding,   steps down on mobile */
  --stack-section: var(--space-6);/* gap between page sections, steps down too  */

  /* ---- Radius ----------------------------------------------------- */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 9999px;

  /* ---- Border ----------------------------------------------------- */
  --border-width: 1px;
  --border-color: rgba(255,255,255,.08);
  --border-hover: rgba(255,255,255,.18);
  --border-strong: rgba(255,255,255,.28);

  /* ---- Motion ----------------------------------------------------- */
  --duration-fast:  120ms;
  --duration-base:  200ms;
  --duration-slow:  320ms;
  --ease-out:   cubic-bezier(0.16, 1, 0.3, 1);
  --ease-inout: cubic-bezier(0.4, 0, 0.2, 1);

  /* ---- Z-index ladder --------------------------------------------- */
  --z-base:      0;
  --z-raised:    10;   /* cards that must escape a sibling stacking ctx */
  --z-sticky:    100;  /* app header                                    */
  --z-dropdown:  400;  /* multiselects, user menu                       */
  --z-overlay:   800;  /* modal backdrop                                */
  --z-modal:     900;  /* modal card                                    */
  --z-toast:     1000;
  --z-progress:  1100;

  /* ---- Surfaces (dark) --------------------------------------------- */
  --bg-main:    #0b0f19;
  --bg-surface: #111827;
  --bg-card:    #1e293b;
  --bg-card-glass: rgba(30,41,59,.7);
  --bg-input:   #0f172a;
  --bg-subtle:  rgba(255,255,255,.04);   /* replaces every rgba(255,255,255,.0x) literal */
  --bg-hover:   rgba(255,255,255,.07);
  --bg-active:  rgba(255,255,255,.11);

  --text-primary:   #f8fafc;
  --text-secondary: #94a3b8;
  --text-muted:     #64748b;
  --text-inverse:   #ffffff;

  /* ---- Brand ------------------------------------------------------- */
  --primary:        #6366f1;
  --primary-hover:  #4f46e5;
  --primary-active: #4338ca;
  --primary-fg:     #ffffff;
  --primary-soft:   rgba(99,102,241,.15);
  --primary-glow:   rgba(99,102,241,.25);
  /* Same fixed indigo in both themes (not re-derived from the light
     theme's --primary below) — matches the badge/icon tints that already
     relied on this exact value before it was tokenized here. */
  --primary-tint:   rgba(99,102,241,.12);

  /* ---- Auth screen ambient glow ------------------------------------ */
  --auth-glow-1: #1e1b4b;
  --auth-glow-2: rgba(168, 85, 247, 0.05);

  /* ---- Status triplets (fg / bg / border) -------------------------- */
  --status-overdue-fg: #f87171;
  --status-overdue-bg: rgba(239,68,68,.12);
  --status-overdue-border: rgba(239,68,68,.30);
  --status-pending-fg: #fbbf24;
  --status-pending-bg: rgba(245,158,11,.12);
  --status-pending-border: rgba(245,158,11,.30);
  --status-partial-fg: #818cf8;
  --status-partial-bg: rgba(99,102,241,.15);
  --status-partial-border: rgba(99,102,241,.35);
  --status-paid-fg: #34d399;
  --status-paid-bg: rgba(16,185,129,.12);
  --status-paid-border: rgba(16,185,129,.30);
  --status-info-fg: #38bdf8;
  --status-info-bg: rgba(56,189,248,.12);
  --status-info-border: rgba(56,189,248,.30);
  --status-next-fg: #c084fc;
  --status-next-bg: rgba(192,132,252,.12);
  --status-next-border: rgba(192,132,252,.30);

  /* Health grade "D" — same value in both themes (not part of the D-18
     light-theme contrast pass; see dashboard health-strip). */
  --health-grade-d-fg: #fb923c;

  /* ---- Elevation --------------------------------------------------- */
  --shadow-sm: 0 1px 2px rgba(0,0,0,.24);
  --shadow-md: 0 4px 10px -2px rgba(0,0,0,.32);
  --shadow-lg: 0 12px 28px -8px rgba(0,0,0,.45);
  --shadow-xl: 0 24px 56px -16px rgba(0,0,0,.55);
  --shadow-glow: 0 0 20px var(--primary-glow);
  --overlay-scrim: rgba(15,23,42,.65);

  /* ---- Focus ------------------------------------------------------- */
  --focus-ring: 0 0 0 3px var(--primary-glow);
  --focus-outline: 2px solid var(--primary);
}

/* Light Theme Overrides */
[data-theme="light"] {
  --bg-main:    #eef2f7;
  --bg-surface: #ffffff;
  --bg-card:    #ffffff;
  --bg-card-glass: rgba(255,255,255,.95);
  --bg-input:   #f8fafc;
  --bg-subtle:  rgba(15,23,42,.04);
  --bg-hover:   rgba(15,23,42,.06);
  --bg-active:  rgba(15,23,42,.10);

  --text-primary:   #0f172a;
  --text-secondary: #475569;
  --text-muted:     #64748b;
  --text-inverse:   #ffffff;

  --primary:        #4f46e5;
  --primary-hover:  #4338ca;
  --primary-active: #3730a3;
  --primary-soft:   rgba(79,70,229,.10);
  --primary-glow:   rgba(79,70,229,.20);

  --auth-glow-1: #e0e7ff;

  --border-color:  #e2e8f0;
  --border-hover:  #cbd5e1;
  --border-strong: #94a3b8;

  /* Status foregrounds are DARKENED for light backgrounds — this is the D-18 fix */
  --status-overdue-fg: #b91c1c;
  --status-overdue-bg: #fef2f2;
  --status-overdue-border: #fecaca;
  --status-pending-fg: #b45309;
  --status-pending-bg: #fffbeb;
  --status-pending-border: #fde68a;
  --status-partial-fg: #4338ca;
  --status-partial-bg: #eef2ff;
  --status-partial-border: #c7d2fe;
  --status-paid-fg: #15803d;
  --status-paid-bg: #f0fdf4;
  --status-paid-border: #bbf7d0;
  --status-info-fg: #0369a1;
  --status-info-bg: #f0f9ff;
  --status-info-border: #bae6fd;
  --status-next-fg: #7e22ce;
  --status-next-bg: #faf5ff;
  --status-next-border: #e9d5ff;

  --shadow-sm: 0 1px 2px rgba(15,23,42,.06);
  --shadow-md: 0 4px 12px rgba(15,23,42,.08);
  --shadow-lg: 0 12px 28px -8px rgba(15,23,42,.14);
  --shadow-xl: 0 24px 56px -16px rgba(15,23,42,.18);
  --shadow-glow: 0 0 20px var(--primary-glow);
  --overlay-scrim: rgba(15,23,42,.45);
}

@media (max-width: 768px) {
  :root {
    --space-page: var(--space-3);
    --space-card: var(--space-4);
    --stack-section: var(--space-5);
  }
}

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

/* ------------------------------------------------------------------
   FOCUS RING
   Applied with :where() so it never wins a specificity fight with a
   component's own focus style — components draw their own ring and
   win automatically: .checkbox__box / .switch__track (T-08),
   .select > select (T-07), text fields (T-06). [tabindex="-1"] is
   excluded so a dialog that receives programmatic focus on open
   (see the modal focus trap) doesn't paint a ring on itself.
   ------------------------------------------------------------------ */
:where(a, button, [role="button"], input, select, textarea, summary, [tabindex]):not([tabindex="-1"]):focus-visible {
  outline: var(--focus-outline);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* --primary is close to white text on an active tab/nav-item, so the
   default outline colour (--primary) would be nearly invisible there. */
.tab-btn.active:focus-visible,
.nav-item.active:focus-visible {
  outline-color: var(--text-inverse);
}

/* ------------------------------------------------------------------
   SKIP LINK — first focusable element in the document; hidden until
   it receives keyboard focus, so a sighted keyboard user can jump
   past the header nav straight to page content.
   ------------------------------------------------------------------ */
.skip-link {
  position: absolute;
  left: var(--space-3);
  top: var(--space-3);
  z-index: var(--z-progress);
  padding: var(--space-2) var(--space-4);
  background: var(--bg-card);
  color: var(--text-primary);
  border: var(--border-width) solid var(--primary);
  border-radius: var(--radius-sm);
  transform: translateY(-200%);
  transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
}

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

body {
  background-color: var(--bg-main);
  color: var(--text-primary);
  font-family: var(--font-body);
  line-height: var(--leading-normal);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-title);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}

/* ============================================================
   AUTHENTICATION & LOGIN VIEW
   ============================================================ */

.auth-wrapper {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Deliberately --space-5, not --space-page: /login has no .app-container
     and keeps its generous gutter at every width. */
  padding: var(--space-5);
  overflow: hidden;
  background: radial-gradient(circle at 50% 0%, var(--auth-glow-1) 0%, var(--bg-main) 70%);
}

.auth-ambient-glow {
  position: absolute;
  top: 20%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 500px;
  height: 500px;
  background: radial-gradient(circle, var(--primary-soft) 0%, var(--auth-glow-2) 50%, transparent 70%);
  filter: blur(60px);
  pointer-events: none;
}

.auth-container {
  width: 100%;
  max-width: 440px;
  z-index: var(--z-base);
}

.auth-card {
  background: var(--bg-card-glass);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  padding: 2.5rem 2rem;
  box-shadow: var(--shadow-md), 0 0 0 1px var(--bg-subtle);
}

.auth-header {
  text-align: center;
  margin-bottom: 2rem;
}

.brand-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--primary-soft);
  border: var(--border-width) solid var(--primary-glow);
  padding: 0.35rem 0.85rem;
  border-radius: var(--radius-pill);
  margin-bottom: 1.25rem;
}

.brand-icon {
  font-size: var(--text-lg);
}

.brand-title {
  font-family: var(--font-title);
  font-weight: var(--weight-bold);
  font-size: var(--text-md);
  color: var(--status-partial-fg);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.auth-heading {
  font-size: var(--text-2xl);
  margin-bottom: 0.5rem;
}

.auth-subtitle {
  color: var(--text-secondary);
  font-size: var(--text-md);
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.input-with-icon {
  position: relative;
  display: flex;
  align-items: center;
}

.field-icon {
  position: absolute;
  left: 1rem;
  color: var(--text-muted);
  pointer-events: none;
}

.input-with-icon input {
  padding-left: 2.75rem;
}

.auth-form .otp-input {
  font-size: var(--text-xl);
  letter-spacing: 0.25em;
  text-align: center;
  font-weight: var(--weight-bold);
}

/* ------------------------------------------------------------------
   ALERT — .otp-banner and .error-banner were the same component with
   two colour sets; they are now tones.
   ------------------------------------------------------------------ */
.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
}

.alert--danger  { background: var(--status-overdue-bg); color: var(--status-overdue-fg); border-color: var(--status-overdue-border); }
.alert--warning { background: var(--status-pending-bg); color: var(--status-pending-fg); border-color: var(--status-pending-border); }
.alert--success { background: var(--status-paid-bg);    color: var(--status-paid-fg);    border-color: var(--status-paid-border); }
.alert--info    { background: var(--status-info-bg);    color: var(--status-info-fg);    border-color: var(--status-info-border); }

/* The auth banners sit above a form and own their bottom margin. */
.auth-card .alert { margin-bottom: var(--space-5); align-items: center; }

.auth-footer {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border-color);
  text-align: center;
}

.secure-tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.otp-resend {
  margin-top: 1.25rem;
  text-align: center;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.link-resend {
  color: var(--status-partial-fg);
  text-decoration: none;
  font-weight: var(--weight-semibold);
  margin-left: 0.35rem;
}

.link-resend:hover {
  text-decoration: underline;
}

/* ============================================================
   MAIN LAYOUT & HEADER NAVIGATION
   ============================================================ */

/* The single horizontal gutter for the whole app. .dashboard-main sits
   inside it and contributes vertical rhythm only — see the DASHBOARD MAIN
   rule — so the viewport is never double-padded. */
.app-container {
  max-width: 1280px;
  margin-inline: auto;
  padding: var(--space-page);
}

/* Always a direct child of .app-container, which already owns the gutter. */
.dashboard-main {
  padding-block: var(--space-4) var(--space-6);
  padding-inline: 0;
}

.app-header {
  position: relative;
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-card);
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  margin-bottom: var(--stack-section);
}

.header-top-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.header-nav-row {
  display: flex;
  align-items: center;
  width: 100%;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border-color);
}

.app-logo-link {
  text-decoration: none;
  color: inherit;
}

.app-logo {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.logo-mark {
  width: 40px;
  height: 40px;
  background: linear-gradient(135deg, var(--primary), var(--status-next-fg));
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xl);
  box-shadow: var(--shadow-glow);
}

.app-title {
  display: block;
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-black);
  color: var(--text-primary);
  line-height: 1.2;
}

.app-subtitle {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* Header Navigation Bar (Sub-Header Row) */
.app-nav {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  background: var(--bg-input);
  padding: 0.35rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  overflow-x: auto;
  width: 100%;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.5rem 0.85rem;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  white-space: nowrap;
  transition: all 0.2s ease;
}

.nav-item:hover {
  color: var(--text-primary);
  background: var(--bg-subtle);
}

.nav-item.active {
  background: var(--primary);
  color: var(--primary-fg);
  box-shadow: 0 2px 8px var(--primary-glow);
}

.nav-item svg {
  opacity: 0.85;
}

.nav-item.active svg {
  opacity: 1;
}

.header-right {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.header-form {
  margin: 0;
}

.env-tag {
  background: var(--bg-subtle);
  border: var(--border-width) solid var(--border-color);
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  padding: 0.35rem 0.75rem;
  border-radius: var(--radius-pill);
}

/* ============================================================
   DASHBOARD TOP & KPI CARDS
   ============================================================ */

.dashboard-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  margin-bottom: var(--stack-section);
  flex-wrap: wrap;
  gap: var(--space-4);
}

.page-title {
  font-size: var(--text-3xl);
  font-weight: var(--weight-black);
}

.page-subtitle {
  color: var(--text-secondary);
  font-size: var(--text-md);
  margin-top: 0.25rem;
}

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: var(--space-5);
  margin-bottom: var(--stack-section);
}

.kpi-card {
  position: relative;
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-card);
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
  overflow: hidden;
}

.kpi-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
}

.kpi-card:hover {
  transform: translateY(-3px);
  border-color: var(--border-hover);
  box-shadow: var(--shadow-md);
}

.kpi-overdue::before { background: var(--status-overdue-fg); }
.kpi-current::before { background: var(--status-info-fg); }
.kpi-next::before { background: var(--status-next-fg); }
.kpi-budget::before { background: var(--primary); }

.kpi-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
}

.kpi-icon-wrap {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
}

.overdue-icon { background: var(--status-overdue-bg); color: var(--status-overdue-fg); }
.current-icon { background: var(--status-info-bg); color: var(--status-info-fg); }
.next-icon { background: var(--status-next-bg); color: var(--status-next-fg); }

.kpi-value {
  font-family: var(--font-title);
  font-size: var(--text-4xl);
  font-weight: var(--weight-black);
  color: var(--text-primary);
  margin-bottom: 0.75rem;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.kpi-value--sm {
  font-size: var(--text-xl);
  margin-top: var(--space-2);
  margin-bottom: 0;
}

.kpi-sub {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* Label/value row above a progress bar (the KPI execution rate). */
.kpi-meter { margin-top: var(--space-3); }

.kpi-meter-head {
  display: flex;
  justify-content: space-between;
  margin-bottom: var(--space-1);
}

.kpi-meter-value {
  font-weight: var(--weight-bold);
  color: var(--status-paid-fg);
}

/* ------------------------------------------------------------------
   BADGE — one implementation, seven tones. Everything that renders as a
   small pill (status, role, KPI sub-label, installment, code) uses it.
   Tones are chosen in Go via the `statusTone` / `roleTone` helpers so a
   template never string-builds a class name.
   ------------------------------------------------------------------ */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0.15rem var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  line-height: 1.4;
  letter-spacing: var(--tracking-wide);
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.badge--subtle  { background: var(--bg-subtle);         color: var(--text-secondary);    border-color: var(--border-color); }
/* Indigo-tinted variant for read-only method/tag chips (payment history). */
.badge--primary-soft {
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  background: var(--primary-tint);
  color: var(--primary);
  border-radius: var(--radius-sm);
}
.badge--overdue { background: var(--status-overdue-bg); color: var(--status-overdue-fg); border-color: var(--status-overdue-border); }
.badge--pending { background: var(--status-pending-bg); color: var(--status-pending-fg); border-color: var(--status-pending-border); }
.badge--partial { background: var(--status-partial-bg); color: var(--status-partial-fg); border-color: var(--status-partial-border); }
.badge--paid    { background: var(--status-paid-bg);    color: var(--status-paid-fg);    border-color: var(--status-paid-border); }
.badge--info    { background: var(--status-info-bg);    color: var(--status-info-fg);    border-color: var(--status-info-border); }
.badge--next    { background: var(--status-next-bg);    color: var(--status-next-fg);    border-color: var(--status-next-border); }

/* Modifiers */
.badge--upper { text-transform: uppercase; font-weight: var(--weight-bold); }
.badge--code {
  font-family: var(--font-mono);
  letter-spacing: var(--tracking-normal);
  border-radius: var(--radius-sm);
}
.badge--dot::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

.cat-pill-modern {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.3rem 0.75rem;
  border-radius: var(--radius-pill);
  background: var(--bg-subtle);
  border: var(--border-width) solid var(--border-color);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

/* ============================================================
   TABLE CONTAINER & TOOLBAR
   ============================================================ */

.table-card {
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  padding: var(--space-card);
  box-shadow: var(--shadow-md);
}

.table-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.segmented-control {
  display: inline-flex;
  background: var(--bg-input);
  padding: 0.35rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  gap: var(--space-1);
  overflow-x: auto;
  max-width: 100%;
}

.tab-btn {
  background: transparent;
  border: none;
  color: var(--text-secondary);
  padding: 0.6rem 1.15rem;
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: nowrap;
}

.tab-btn:hover {
  color: var(--text-primary);
}

.tab-btn.active {
  background: var(--primary);
  color: var(--primary-fg);
  box-shadow: 0 2px 8px var(--primary-glow);
}

/* Sub Filter Bar & Multiselects */
/* Always a direct child of .table-card. Bleeding it out to the card edges
   is what makes its two rules read as full-width separators instead of
   floating short of the padding box. */
.sub-filter-bar {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-inline: calc(var(--space-card) * -1);
  padding: var(--space-3) var(--space-card);
  background: var(--bg-card);
  border-top: 1px solid var(--border-color);
  border-bottom: 1px solid var(--border-color);
  flex-wrap: wrap;
}

.filter-group {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.custom-multiselect {
  position: relative;
}

.multiselect-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 0.45rem 0.85rem;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  cursor: pointer;
  min-width: 160px;
  /* Shares this height with .switch so the bills sub-filter bar reads as
     peer controls — the switch's track is taller than a text line. */
  min-height: 2.125rem;
  transition: all 0.2s ease;
}

.multiselect-trigger:hover {
  border-color: var(--border-hover);
  background: var(--bg-subtle);
}

.multiselect-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: var(--z-dropdown);
  min-width: 190px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 0.5rem 0;
  max-height: 240px;
  overflow-y: auto;
}

.multiselect-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.45rem 0.85rem;
  font-size: var(--text-sm);
  color: var(--text-primary);
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.multiselect-item:hover {
  background: var(--bg-input);
}

/* Multiselect rows use the flat .checkbox markup (a nested <label> would
   be invalid and would break click-to-toggle), so size the box here. */
.multiselect-item .checkbox__box {
  width: 0.875rem;
  height: 0.875rem;
}

.multiselect-item .checkbox__box::after {
  width: 0.45rem;
  height: 0.25rem;
  border-width: 1.5px;
}

.status-dot-indicator {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}
.status-overdue-dot { background-color: var(--status-overdue-fg); }
.status-pending-dot { background-color: var(--status-pending-fg); }
.status-partially-dot { background-color: var(--status-partial-fg); }
.status-paid-dot { background-color: var(--status-paid-fg); }

.cat-dot-sm {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

/* The category label inside .category-pill. Its one job is to truncate
   rather than push the pill past its cell. */
.cat-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.table-responsive {
  overflow-x: auto;
}

/* For the one table that must stay two-dimensional (the permission
   matrix): an explicit scroller rather than a silent one. The right-edge
   fade lives in the mobile block — at desktop widths the matrix fits, and
   an unconditional mask would fade the last column for no reason. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}

.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  text-align: left;
}

.data-table th {
  background: var(--bg-input);
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border-color);
}

.data-table th:first-child { border-top-left-radius: var(--radius-md); }
.data-table th:last-child { border-top-right-radius: var(--radius-md); }

.data-table td {
  padding: 1.15rem 1.25rem;
  border-bottom: var(--border-width) solid var(--border-color);
  font-size: var(--text-md);
  vertical-align: middle;
}

.data-row td {
  transition: background-color 0.15s ease;
}

/* Dense variant — the settings tables, which were a second table
   implementation (.settings-table) until T-11 folded them in here. */
.data-table--compact th,
.data-table--compact td {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
}

.data-table--compact th {
  background: var(--bg-surface);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
}

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

.data-row:hover td {
  background: var(--bg-input);
}

.row-overdue-highlight td {
  background: var(--status-overdue-bg);
}

.row-overdue-highlight:hover td {
  background: var(--status-overdue-bg);
  opacity: 0.9;
}

.row-excluded td {
  opacity: 0.5;
  text-decoration: line-through;
}

.row-excluded select,
.row-excluded input {
  text-decoration: none;
}

/* ------------------------------------------------------------------
   UTILITIES — CLOSED SET. Do not add to this list.
   If you need a new one, you need a component instead.
   ------------------------------------------------------------------ */
.text-left   { text-align: left; }
.text-center { text-align: center; }
.text-right  { text-align: right; }

.text-muted     { color: var(--text-muted); }
.text-secondary { color: var(--text-secondary); }
.text-danger    { color: var(--status-overdue-fg); }

.is-hidden { display: none !important; }

/* For accessible names on icon-only controls (T-17). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Typographic-scale utilities — use instead of an inline font-size. */
.text-2xs { font-size: var(--text-2xs); }
.text-xs  { font-size: var(--text-xs); }
.text-sm  { font-size: var(--text-sm); }
.text-md  { font-size: var(--text-md); }
.text-lg  { font-size: var(--text-lg); }
.text-xl  { font-size: var(--text-xl); }

/* Money value — always title family + tabular numerals so columns align. */
.amount {
  font-family: var(--font-title);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
}

/* Table Cell Formatting */
.cell-date .date-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

/* ------------------------------------------------------------------
   TABLE CELLS — these apply at every viewport, not only in the mobile
   card transformation. min-width:0 is what lets a cell's content shrink
   inside its grid/flex track instead of stretching the table.
   ------------------------------------------------------------------ */
.title-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  min-width: 0;
}

.bill-title {
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

.cell-title,
.cell-context,
.cell-category,
.cell-method { min-width: 0; }

/* A currency value or a status keyword split across two lines is worse
   than a slightly wider cell; both are short enough never to overflow. */
.cell-status,
.cell-actions { white-space: nowrap; }

/* A long payee in a fixed-width <col> track would otherwise widen the
   whole table and produce a horizontal scrollbar on desktop.
   break-word, not anywhere: `anywhere` also feeds into min-content, which
   makes the auto table-layout algorithm collapse the flexible Context
   column to a few characters. */
.data-table td { overflow-wrap: break-word; }

/* Where a <colgroup> declares widths, honour them: with the default auto
   layout the algorithm overrides them whenever content demands more, so a
   single long value stretched the table past its scroll container. */
.data-table:has(colgroup) {
  table-layout: fixed;
  width: 100%;
}
.data-table .cell-amount,
.data-table .cell-date { overflow-wrap: normal; }

.category-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  padding: 0.3rem 0.75rem;
  border-radius: 9999px;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.cat-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.cell-amount {
  font-family: var(--font-title);
  font-weight: var(--weight-bold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

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

.cell-paid {
  color: var(--status-paid-fg);
}

.cell-date-strong { font-weight: var(--weight-semibold); white-space: nowrap; }

/* Read-only statement/payment-history tables inside a modal — see
   cc_purchases_modal.html and bill_payments_modal.html. */
.data-table-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  border: 1px solid var(--border-color);
  border-radius: 8px;
}

/* Fixed-height variant for a modal that doesn't scroll as a whole card. */
.data-table-scroll--fixed {
  overflow-x: auto;
  overflow-y: auto;
  max-height: 280px;
}

.data-table--sticky-head th {
  position: sticky;
  top: 0;
  background: var(--bg-card);
  z-index: var(--z-raised);
}

.data-table--sticky-foot td {
  position: sticky;
  bottom: 0;
  background: var(--bg-card);
}

.data-table-empty {
  text-align: center;
  padding: 2rem 1rem;
  color: var(--text-muted);
  background: var(--bg-input);
  border-radius: 8px;
  border: 1px dashed var(--border-color);
}
.data-table-empty p { margin: 0; }
.data-table-empty svg { margin-bottom: 0.5rem; opacity: 0.6; }

/* Empty & Loading States */
.empty-state {
  text-align: center;
  padding: 4rem 1.5rem !important;
}

.empty-state-card {
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-9) var(--space-card);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
}

.empty-icon-wrap {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  margin-bottom: 0.25rem;
}

.empty-title {
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  margin: 0;
}

.empty-desc {
  font-size: var(--text-md);
  color: var(--text-secondary);
  max-width: 60ch;
  line-height: var(--leading-snug);
  margin-bottom: 0.5rem;
}

.empty-state-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  color: var(--text-muted);
}

.table-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: 4rem;
  color: var(--text-secondary);
}

.spinner {
  width: 24px;
  height: 24px;
  border: 3px solid var(--primary-soft);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ============================================================
   SKELETON PLACEHOLDERS (lazy-loaded dashboard sections)
   ============================================================ */

.skeleton-block {
  background: linear-gradient(90deg, var(--bg-input) 25%, var(--border-color) 37%, var(--bg-input) 63%);
  background-size: 400% 100%;
  animation: skeleton-shimmer 1.4s ease infinite;
  border-radius: var(--radius-md);
}

.skeleton-text {
  height: 0.85rem;
  width: 60%;
  margin-bottom: 0.6rem;
}

.skeleton-kpi-value {
  height: 2.1rem;
  width: 70%;
  margin-bottom: 0.75rem;
  border-radius: var(--radius-sm);
}

.skeleton-kpi-badge {
  height: 1.4rem;
  width: 45%;
  border-radius: var(--radius-pill);
}

@keyframes skeleton-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* ============================================================
   BUTTONS & ACTIONS
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  min-height: 40px;
  padding-block: 0;
  padding-inline: var(--space-5);
  border-radius: var(--radius-md);
  border: none;
  cursor: pointer;
  transition: all 0.2s ease;
  text-decoration: none;
}

.btn-primary {
  background: linear-gradient(135deg, var(--primary), var(--primary-hover));
  color: var(--primary-fg);
  box-shadow: 0 4px 12px var(--primary-glow);
}

.btn-primary:hover {
  background: linear-gradient(135deg, var(--primary-hover), var(--primary-active));
  transform: translateY(-1px);
  box-shadow: 0 6px 16px var(--primary-glow);
}

.btn-secondary {
  background: var(--bg-subtle);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
}

.btn-secondary:hover {
  background: var(--bg-hover);
  border-color: var(--border-hover);
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
}

.btn-ghost:hover {
  background: var(--bg-subtle);
  color: var(--text-primary);
}

.btn-success {
  background: var(--status-paid-fg);
  color: var(--primary-fg);
  box-shadow: 0 4px 12px var(--status-paid-bg);
}

.btn-success:hover {
  filter: brightness(0.92);
}

.btn-full {
  width: 100%;
}

.action-btn-group {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

/* ------------------------------------------------------------------
   BUTTON SIZES — independent of the parent. The old rule was
   `.action-btn-group .btn-sm`, so a small button only became small
   inside that one container, and it forced a square 32x32 that would
   have clipped any button carrying a label.
   ------------------------------------------------------------------ */
.btn--xs { min-height: 28px; padding-inline: var(--space-2); font-size: var(--text-xs); }
.btn--sm { min-height: 32px; padding-inline: var(--space-3); font-size: var(--text-sm); }
.btn--lg { min-height: 48px; padding-inline: var(--space-6); font-size: var(--text-md); }

.btn--icon { padding-inline: 0; aspect-ratio: 1; width: auto; }
.btn--icon.btn--sm { width: 32px; }
.btn--icon.btn--xs { width: 28px; }

/* ------------------------------------------------------------------
   TINTED BUTTON — the four row-action buttons were four near-identical
   rules differing only in hover colour. One rule plus a data-tone.
   ------------------------------------------------------------------ */
.btn--tinted {
  background: var(--bg-input);
  color: var(--text-secondary);
  border: var(--border-width) solid var(--border-color);
}

.btn--tinted[data-tone="paid"]:hover {
  background: var(--status-paid-bg);
  color: var(--status-paid-fg);
  border-color: var(--status-paid-border);
}

.btn--tinted[data-tone="info"]:hover {
  background: var(--primary-soft);
  color: var(--primary);
  border-color: var(--primary-glow);
}

.btn--tinted[data-tone="pending"]:hover {
  background: var(--status-pending-bg);
  color: var(--status-pending-fg);
  border-color: var(--status-pending-border);
}

.btn--tinted[data-tone="overdue"]:hover {
  background: var(--status-overdue-bg);
  color: var(--status-overdue-fg);
  border-color: var(--status-overdue-border);
}

.btn-warning {
  background: var(--status-pending-bg);
  color: var(--status-pending-fg);
  border: var(--border-width) solid var(--status-pending-border);
}

.btn-warning:hover { background: var(--status-pending-border); }

/* ============================================================
   MODALS & FORMS
   ============================================================ */

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes scaleIn {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0)   scale(1); }
}

.modal-overlay,
.modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--overlay-scrim);
  backdrop-filter: blur(8px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: var(--z-overlay);
  padding: var(--space-5);
  animation: fadeIn var(--duration-base) var(--ease-out);
}

.modal-card {
  background: var(--bg-card);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  padding: var(--space-6);
  width: 100%;
  max-width: 540px;
  box-shadow: var(--shadow-xl);
  animation: scaleIn var(--duration-slow) var(--ease-out);
}

.modal-card--wide { max-width: 960px; }

/* A modal whose body can outgrow the viewport: the card itself scrolls
   internally instead of overflowing the overlay. Header/footer/summary
   stay put; the one child meant to grow uses .data-table-scroll. */
.modal-card--scroll {
  display: flex;
  flex-direction: column;
  max-height: 90vh;
}
.modal-card--scroll > .modal-header,
.modal-card--scroll > .modal-footer,
.modal-card--scroll > .delete-info-card {
  flex-shrink: 0;
}

/* Modern Checkbox Card Container */
.settlement-checkbox-card {
  margin-top: 1rem;
  margin-bottom: 0.5rem;
  grid-column: 1 / -1;
  background: var(--bg-subtle);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  transition: all 0.2s ease;
}

.settlement-checkbox-card:hover {
  background: var(--primary-soft);
  border-color: var(--primary-glow);
}

.checkbox-card-label {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  cursor: pointer;
  width: 100%;
}

.checkbox-card-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.checkbox-card-title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.checkbox-card-sub {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.3;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1.5rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border-color);
}

.modal-title-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.modal-title {
  font-family: var(--font-title);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin: 0;
}

.modal-body { padding-block: var(--space-5); }

.modal-icon {
  width: 42px;
  height: 42px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
}

.icon-primary { background: var(--primary-glow); color: var(--primary); }
.icon-primary-soft { background: var(--primary-soft); color: var(--primary); }
.icon-success { background: var(--status-paid-bg); color: var(--status-paid-fg); }
.icon-danger { background: var(--status-overdue-bg); color: var(--status-overdue-fg); }
.icon-info { background: var(--status-info-bg); color: var(--status-info-fg); }

/* Destructive action. Tinted at rest so it does not out-shout the primary
   CTA in a confirmation dialog; solid on hover to confirm intent.
   (T-03: replaced a second, gradient-based definition that was dead code.) */
.btn-danger {
  background: var(--status-overdue-bg);
  color: var(--status-overdue-fg);
  border: var(--border-width) solid var(--status-overdue-border);
}
.btn-danger:hover {
  background: var(--status-overdue-fg);
  color: var(--text-inverse);
  border-color: var(--status-overdue-fg);
}

/* Delete Modal Info Card */
.delete-info-card {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Extra clearance when a data table follows immediately below. */
.delete-info-card--table-gap { margin-bottom: 1.25rem; }

.delete-info-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: var(--text-sm);
}

.delete-info-label {
  color: var(--text-secondary);
  font-weight: var(--weight-medium);
}

.delete-info-value {
  color: var(--text-primary);
  font-weight: var(--weight-semibold);
}

.delete-info-value--paid {
  color: var(--status-paid-fg);
  font-weight: var(--weight-bold);
}

/* One close-button implementation. Templates previously used three
   names — .modal-close, .btn-close and .btn-close-modal — of which only
   this one had a rule, so two modals rendered a native OS button. */
.modal-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: var(--text-xl);
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.modal-close:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.modal-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* ------------------------------------------------------------------
   CARD — the generic surface. .table-card and .chart-card stay as
   specialised cards with their own semantics.

   backdrop-filter creates a stacking context, so do NOT add --glass to
   a container that hosts a dropdown; it traps the menu.
   ------------------------------------------------------------------ */
.card {
  background: var(--bg-card);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-card);
}

.card--glass {
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-4);
  border-bottom: var(--border-width) solid var(--border-color);
}

.card-title {
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  margin: 0;
}

/* ------------------------------------------------------------------
   FORM PRIMITIVES
   .form-control is deliberately absent: the element selector already
   styles every field, so the class was Bootstrap muscle memory and its
   13 usages were deleted rather than given a rule.
   ------------------------------------------------------------------ */
.form-label {
  font-size: var(--text-2xs);
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
}

.form-hint {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: var(--leading-snug);
}

/* Required-field asterisk next to a <label>. */
.required { color: var(--status-overdue-fg); }

.form-error {
  font-size: var(--text-xs);
  color: var(--status-overdue-fg);
}

/* ------------------------------------------------------------------
   FORM LAYOUT
   .form-row lays fields out in --form-cols columns and collapses to a
   single column at the sm breakpoint. Prefer it over one class per
   column count.

   minmax(0, 1fr) rather than 1fr: `1fr` is `minmax(auto, 1fr)`, so an
   item whose content is wider than its track — a long category name, a
   long payment-method label — expands the track and overflows the modal.
   ------------------------------------------------------------------ */
.form-row {
  display: grid;
  grid-template-columns: repeat(var(--form-cols, 1), minmax(0, 1fr));
  gap: var(--space-4);
}

.form-row--2 { --form-cols: 2; }
.form-row--3 { --form-cols: 3; }

.form-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

/* Uppercase eyebrow/caption styling — form-field labels and section
   micro-titles. Inline controls (checkbox/switch labels) opt out by
   not being a direct .form-group child; see T-08 for their styling. */
.eyebrow,
.form-group > label:not(.checkbox-label),
.filter-group-label,
.kpi-title,
.data-table th,
.tile-label,
.stat-tile-label,
.dropdown-user-title,
.custom-date-title {
  font-size: var(--text-2xs);
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: var(--text-muted);
}

/* ------------------------------------------------------------------
   TEXT-LIKE FIELDS
   The :not() chain exists because a bare `input` selector also matches
   checkboxes, radios, colour, file and range pickers — see
   docs/tasks/ui_overhaul/T-06-scope-input-rules.md.
   Do not simplify it back to `input`.

   The chain is wrapped in :where() so the selector keeps the exact
   specificity of a bare `input` (0,0,1). Every existing override
   (.field--sm, .otp-input, .color-input, .input-with-icon input)
   therefore still wins without needing !important.

   input[type="date"] is deliberately NOT excluded — it is a text-like
   field and keeps the treatment.
   ------------------------------------------------------------------ */
input:where(:not([type="checkbox"], [type="radio"], [type="color"], [type="file"], [type="range"], [type="submit"], [type="button"], [type="image"], [type="reset"])),
select,
textarea {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background-color: var(--bg-input);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-md);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--text-md);
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

select option {
  background: var(--bg-card);
  color: var(--text-primary);
}

input:where(:not([type="checkbox"], [type="radio"], [type="color"], [type="file"], [type="range"], [type="submit"], [type="button"], [type="image"], [type="reset"])):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--focus-ring);
}

/* Types excluded from the text-field treatment above still need sane
   defaults — the browser's own file-picker button must not sit inside a
   bordered text box. (Checkboxes/radios are owned by T-08.) */
input[type="file"] {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

input[type="file"]::file-selector-button {
  margin-right: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
  background: var(--bg-subtle);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

input[type="file"]::file-selector-button:hover {
  border-color: var(--primary);
}

/* ------------------------------------------------------------------
   CHECKBOX
   The native input stays in the DOM (form submission, a11y, :checked)
   but is visually replaced by .checkbox__box. It is NOT display:none —
   that would remove it from the a11y tree in some browsers.
   The input must stay the immediate previous sibling of .checkbox__box
   for the `+` combinator to work; do not insert anything between them.
   ------------------------------------------------------------------ */
.checkbox {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  color: var(--text-primary);
  text-transform: none;
  letter-spacing: var(--tracking-normal);
}

/* .multiselect-item is a second checkbox host: it already supplies the row
   layout (flex, gap, padding), so it opts into the box rather than adding
   a nested <label>, which would be invalid and break click-to-toggle. */
:is(.checkbox, .multiselect-item, .checkbox-card-label) > input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
}

/* The card's text is a two-line stack aligned to flex-start, so nudge the
   box down onto the title's line. */
.checkbox-card-label > .checkbox__box { margin-top: 0.15rem; }

.checkbox__box {
  width: 1.125rem;
  height: 1.125rem;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  background: var(--bg-input);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius-xs);
  transition: background-color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out);
}

.checkbox__box::after {
  content: '';
  width: 0.6rem;
  height: 0.35rem;
  border-left: 2px solid var(--primary-fg);
  border-bottom: 2px solid var(--primary-fg);
  transform: rotate(-45deg) scale(0);
  transform-origin: center;
  transition: transform var(--duration-fast) var(--ease-out);
  /* the tick's own box is offset by the border widths — nudge it back */
  margin-top: -0.15rem;
}

:is(.checkbox, .multiselect-item, .checkbox-card-label):hover .checkbox__box { border-color: var(--primary); }
:is(.checkbox, .multiselect-item, .checkbox-card-label) > input:checked + .checkbox__box { background: var(--primary); border-color: var(--primary); }
:is(.checkbox, .multiselect-item, .checkbox-card-label) > input:checked + .checkbox__box::after { transform: rotate(-45deg) scale(1); }
:is(.checkbox, .multiselect-item, .checkbox-card-label) > input:indeterminate + .checkbox__box { background: var(--primary); border-color: var(--primary); }
:is(.checkbox, .multiselect-item, .checkbox-card-label) > input:focus-visible + .checkbox__box { box-shadow: var(--focus-ring); }
:is(.checkbox, .multiselect-item, .checkbox-card-label) > input:disabled + .checkbox__box { opacity: 0.5; }
:is(.checkbox, .multiselect-item, .checkbox-card-label):has(input:disabled) { cursor: not-allowed; opacity: 0.6; }

/* Dense variant for multiselect menu items */
.checkbox--sm { font-size: var(--text-sm); }
.checkbox--sm .checkbox__box { width: 0.875rem; height: 0.875rem; }
.checkbox--sm .checkbox__box::after { width: 0.45rem; height: 0.25rem; border-width: 1.5px; }

/* ------------------------------------------------------------------
   SWITCH
   For binary filters that take effect immediately (no submit step).
   Deliberately shaped to match .multiselect-trigger so the bills
   sub-filter bar reads as three peer controls.
   ------------------------------------------------------------------ */
/* The sub-filter bar reads as three peer controls only if they share a
   height with .multiselect-trigger; the switch's track is taller than the
   trigger's text line, so both pin to the same min-height explicitly. */
.switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.45rem 0.85rem;
  min-height: 2.125rem;
  cursor: pointer;
  background: var(--bg-input);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-primary);
  text-transform: none;
  letter-spacing: var(--tracking-normal);
  white-space: nowrap;
  line-height: 1;
  transition: border-color var(--duration-fast) var(--ease-out);
}

.switch:hover { border-color: var(--border-hover); }

.switch > input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.switch__track {
  width: 2rem;
  height: 1.125rem;
  flex: 0 0 auto;
  padding: 2px;
  background: var(--bg-active);
  border-radius: var(--radius-pill);
  transition: background-color var(--duration-fast) var(--ease-out);
}

.switch__thumb {
  display: block;
  width: 0.875rem;
  height: 0.875rem;
  background: var(--text-secondary);
  border-radius: 50%;
  transition: transform var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out);
}

.switch > input:checked ~ .switch__track { background: var(--primary); }
.switch > input:checked ~ .switch__track .switch__thumb {
  transform: translateX(0.875rem);
  background: var(--primary-fg);
}
.switch > input:focus-visible ~ .switch__track { box-shadow: var(--focus-ring); }
.switch:has(input:checked) { border-color: var(--primary); }

/* ------------------------------------------------------------------
   SELECT
   The native <select> is kept for accessibility and mobile ergonomics
   (the OS picker beats any custom listbox on touch). Only the closed
   control is restyled; the open list is drawn by the OS and cannot be
   themed — do not attempt a custom listbox.
   ------------------------------------------------------------------ */
.select {
  position: relative;
  display: block;
  width: 100%;
}

.select > select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  padding: var(--space-3) var(--space-7) var(--space-3) var(--space-4);
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  /* No line-height override: the base text-field rule leaves it `normal`,
     and matching it is what keeps a select the same height as the input
     beside it in a .form-row--2 row. */
  color: var(--text-primary);
  background-color: var(--bg-input);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

/* Chevron: a clip-path triangle, so it follows the theme via
   background-color and needs no SVG data URI (which would need one
   variant per theme). */
.select::after {
  content: '';
  position: absolute;
  top: 50%;
  right: var(--space-4);
  width: 10px;
  height: 6px;
  transform: translateY(-50%);
  background-color: var(--text-secondary);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  pointer-events: none;
  transition: background-color var(--duration-fast) var(--ease-out);
}

.select > select:hover { border-color: var(--border-hover); }
.select > select:focus-visible {
  outline: none;
  border-color: var(--primary);
  box-shadow: var(--focus-ring);
}
.select:focus-within::after { background-color: var(--primary); }
.select > select:disabled { opacity: 0.55; cursor: not-allowed; }
.select:has(select:disabled)::after { opacity: 0.55; }

/* Compact variant — table rows and dense toolbars */
.select--sm > select {
  padding: var(--space-2) var(--space-6) var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  border-radius: var(--radius-sm);
}

.select--sm::after { right: var(--space-3); }

/* Inline variant — sits in a flex row, sizes to its content */
.select--inline { display: inline-block; width: auto; }
.select--inline > select { width: auto; }

/* The OS list still gets what little we can give it */
.select > select option {
  background: var(--bg-card);
  color: var(--text-primary);
}

.payment-info-box {
  background: var(--status-paid-bg);
  border: 1px solid var(--status-paid-border);
  border-radius: var(--radius-md);
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.25rem;
}

.info-label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.info-amount {
  font-family: var(--font-title);
  font-size: var(--text-xl);
  font-weight: var(--weight-black);
  color: var(--status-paid-fg);
  font-variant-numeric: tabular-nums;
}

.modal-actions,
.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding-top: var(--space-5);
  border-top: var(--border-width) solid var(--border-color);
}

/* Wider clearance when a data table sits directly above the footer. */
.modal-footer--table-gap { margin-top: 1.25rem; }

/* Moved off an inline style on the <td> in category_breakdown.html. */
.cell-progress { min-width: 140px; }

.category-progress-wrap {
  background: var(--bg-input);
  height: 8px;
  border-radius: 4px;
  overflow: hidden;
}

.category-progress-bar {
  height: 100%;
  border-radius: 4px;
}

/* Custom Date Range Sub-Bar (Dedicated line below top toolbar) */
.custom-date-bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  background: var(--bg-input);
  padding: 0.6rem 1rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
  margin-bottom: 1.25rem;
  animation: fadeIn var(--duration-base) var(--ease-out);
  flex-wrap: wrap;
}

.date-input-group {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.date-input-group label {
  font-size: var(--text-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  font-weight: var(--weight-semibold);
}

.field--sm {
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  border-radius: var(--radius-sm);
}

/* User Menu & Dropdown */
.user-menu-wrap {
  position: relative;
  display: inline-block;
}

.user-avatar-btn {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  padding: 0.3rem 0.55rem;
  border-radius: 9999px;
  cursor: pointer;
  color: var(--text-primary);
  transition: all 0.2s ease;
}

.user-avatar-btn:hover,
.user-avatar-btn[aria-expanded="true"] {
  border-color: var(--primary);
  background: var(--bg-card);
  box-shadow: var(--shadow-sm);
}

.user-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), var(--status-next-fg));
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--primary-fg);
}

.chevron-icon {
  color: var(--text-muted);
  transition: transform 0.2s ease;
}

.user-avatar-btn[aria-expanded="true"] .chevron-icon {
  transform: rotate(180deg);
}

.user-dropdown-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  min-width: 250px;
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  padding: 0.6rem;
  z-index: var(--z-dropdown);
  display: none;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.user-dropdown-menu.show {
  display: block;
  opacity: 1;
  transform: translateY(0);
}

.dropdown-header {
  padding: 0.4rem 0.6rem 0.3rem;
}

.dropdown-section {
  padding: 0.3rem 0.15rem;
}

.theme-toggle-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius-md);
  background: var(--bg-input);
}

.option-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.theme-segmented-control {
  display: flex;
  background: var(--bg-surface);
  padding: 2px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
  gap: var(--space-1);
}

.theme-btn {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  padding: 0.25rem 0.55rem;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.15s ease;
}

.theme-btn:hover {
  color: var(--text-primary);
}

.theme-btn.active {
  background: var(--primary);
  color: var(--primary-fg);
  box-shadow: var(--shadow-sm);
}

.dropdown-divider {
  height: 1px;
  background: var(--border-color);
  margin: 0.4rem 0;
}

.dropdown-logout-form {
  margin: 0;
}

.dropdown-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.55rem 0.65rem;
  border: none;
  background: transparent;
  color: var(--text-primary);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  border-radius: var(--radius-md);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
  text-align: left;
  box-sizing: border-box;
}

.dropdown-item:hover {
  background: var(--bg-input);
  color: var(--primary);
}

.dropdown-logout-btn {
  color: var(--status-overdue-fg);
}

.dropdown-logout-btn:hover {
  background: var(--status-overdue-bg);
  color: var(--status-overdue-fg);
}

/* Dashboard Module Grid */
.dashboard-modules-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-5);
  margin-top: 2rem;
}

.module-card {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-card);
  text-decoration: none;
  color: var(--text-primary);
  transition: all 0.25s ease;
  position: relative;
  overflow: hidden;
}

.module-card:hover {
  transform: translateY(-3px);
  border-color: var(--primary);
  box-shadow: var(--shadow-glow);
}

.module-icon-wrap {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--primary);
  flex-shrink: 0;
}

.module-content {
  flex: 1;
}

.module-title {
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  margin-bottom: 0.25rem;
  color: var(--text-primary);
}

.module-desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: var(--leading-snug);
  max-width: 60ch;
}

.module-arrow {
  font-size: var(--text-xl);
  color: var(--text-muted);
  transition: transform 0.2s ease, color 0.2s ease;
}

.module-card:hover .module-arrow {
  transform: translateX(4px);
  color: var(--primary);
}

/* Categories Management Grid */
.categories-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-5);
}

.category-card {
  background: var(--bg-card-glass);
  backdrop-filter: blur(16px);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--space-card);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-4);
  transition: all 0.2s ease;
}

.category-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-hover);
  box-shadow: var(--shadow-md);
}

.category-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.category-title-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.category-color-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
  flex-shrink: 0;
}

.category-name {
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  margin: 0;
}

.category-hex-badge {
  font-size: var(--text-xs);
  font-family: monospace;
  font-weight: var(--weight-semibold);
  padding: 0.25rem 0.6rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--cat-color, var(--border-color));
  background-color: var(--bg-input);
  color: var(--cat-color, var(--text-primary));
}

.category-card-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding-top: 0.75rem;
  border-top: 1px solid var(--border-color);
}

/* Color Picker & Presets */
.color-picker-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.color-input {
  width: 44px;
  height: 40px;
  padding: 2px;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  cursor: pointer;
}

.hex-input {
  flex: 1;
  font-family: monospace;
  text-transform: uppercase;
}

.form-label-sub {
  display: block;
  font-size: var(--text-xs);
  color: var(--text-muted);
  margin-bottom: 0.4rem;
  font-weight: var(--weight-semibold);
}

.color-presets {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.color-preset-btn {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease;
}

.color-preset-btn:hover {
  transform: scale(1.15);
  border-color: var(--text-primary);
}

/* ============================================================
   GLOBAL UX: PROGRESS BAR, TOASTS & REUSABLE CRUD STYLES
   ============================================================ */

/* Top Loading Progress Bar */
#app-progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--primary), var(--status-partial-fg), var(--status-next-fg));
  z-index: var(--z-progress);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  transform-origin: left;
}

#app-progress-bar.htmx-request,
.htmx-request#app-progress-bar,
#app-progress-bar.active {
  opacity: 1;
  animation: progressPulse 1.2s infinite ease-in-out;
}

@keyframes progressPulse {
  0% { transform: scaleX(0.05) translateX(0); }
  50% { transform: scaleX(0.7) translateX(30%); }
  100% { transform: scaleX(1) translateX(100%); }
}

/* Toast Notifications Container */
#toast-container {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
  max-width: 400px;
}

.toast-notification {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  animation: toastSlideIn 0.3s var(--ease-out);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.toast-notification.toast-out {
  opacity: 0;
  transform: translateY(10px) scale(0.95);
}

.toast-notification.toast-success {
  border-left: 4px solid var(--status-paid-fg);
}

.toast-notification.toast-error {
  border-left: 4px solid var(--status-overdue-fg);
}

.toast-notification.toast-warning {
  border-left: 4px solid var(--status-pending-fg);
}

.toast-notification.toast-info {
  border-left: 4px solid var(--primary);
}

@keyframes toastSlideIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.96);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Keyboard Shortcut Badge Hint */
.keyboard-shortcut-hint {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.1rem 0.35rem;
  font-size: var(--text-2xs);
  font-family: monospace;
  font-weight: var(--weight-bold);
  color: var(--text-muted);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: 4px;
  margin-left: 0.4rem;
}

/* ============================================================
   DASHBOARD ANALYTICS & CHARTS
   ============================================================ */

.analytics-section {
  margin-top: var(--stack-section);
}

.charts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(400px, 100%), 1fr));
  gap: var(--space-5);
  margin-top: 1.25rem;
}

/* The card is a grid item and must be allowed to shrink below its
   content's intrinsic width, or a long payee name widens the track. */
.charts-grid > * { min-width: 0; }

@media (max-width: 768px) {
  .charts-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.chart-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  padding: var(--space-card);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
}

.chart-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.25rem;
}

.chart-title-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.chart-title {
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}

.chart-subtitle {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* ------------------------------------------------------------------
   DASHBOARD PANELS
   Every grid here uses auto-fit + minmax so it reflows by available
   width. The inline `repeat(3, 1fr)` these replace could not be reached
   by any media query, which is why the cash-flow panel overflowed at
   320px while its siblings were rescued by an !important.
   ------------------------------------------------------------------ */
.chart-container {
  position: relative;
  width: 100%;
  height: 280px;
}

.chart-container--tall { height: 340px; }

.cashflow-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-3);
}

.cashflow-card {
  padding: var(--space-3) var(--space-4);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-md);
  min-width: 0;
}

.cashflow-card .amount {
  color: var(--text-primary);
  overflow-wrap: anywhere;
}

/* Bucket tone modifiers, consumed by dashboard_cashflow_analytics.html
   (an independently-swappable fragment, see D-30) as
   cf-card-{{.BucketKey}} / cf-title-{{.BucketKey}} — exact names. */
.cf-card-week  { background: var(--status-pending-bg); border-color: var(--status-pending-border); }
.cf-card-month { background: var(--status-info-bg); border-color: var(--border-color); }
.cf-card-next  { background: var(--status-next-bg); border-color: var(--border-color); }
.cf-title-week  { color: var(--status-pending-fg); }
.cf-title-month { color: var(--status-info-fg); }
.cf-title-next  { color: var(--status-next-fg); }

/* auto-fit, not auto-fill: a single bucket should fill the row rather
   than sit in a narrow track beside two empty ones. */
.kpi-grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(8rem, 100%), 1fr)); }
.kpi-grid > * { min-width: 0; }

.kpi-card--sm { padding: var(--space-4) var(--space-5); }

/* ------------------------------------------------------------------
   LABEL / VALUE ROWS (top payees, payment methods, category breakdown)
   The identity side must carry min-width:0 or it cannot shrink, and the
   row grows instead of the name truncating — which is what pushed the
   amount block past the card's right edge.
   ------------------------------------------------------------------ */
.panel-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.panel-row-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.panel-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-sm);
}

.panel-identity {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  flex: 1 1 auto;
}

.panel-rank {
  flex: 0 0 auto;
  font-size: var(--text-xs);
  font-weight: var(--weight-black);
  color: var(--text-muted);
}

/* ellipsis needs all four of these, plus min-width:0 on the parent */
.panel-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.panel-count {
  flex: 0 0 auto;
  font-size: var(--text-2xs);
  color: var(--text-muted);
  white-space: nowrap;
}

.panel-values {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
  white-space: nowrap;
}

.panel-values .amount { color: var(--text-primary); }

.panel-bar { height: 5px; }
.panel-bar > * { height: 100%; border-radius: var(--radius-pill); }

/* Consumed by dashboard_payees_analytics.html (an independently-swappable
   fragment, see D-30) as payee-bar-{{.StatusClass}} — exact names. */
.payee-bar-paid    { background: var(--status-paid-fg); }
.payee-bar-partial { background: var(--status-pending-fg); }
.payee-bar-unpaid  { background: var(--border-hover); }

/* The banner is a flex row that wraps; the CTA drops to its own line. */
.alert-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* Payment-method rows: same shape as .panel-row, but each side is a
   two-line stack rather than a single baseline. */
.pm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-input);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-md);
}

.pm-label { min-width: 0; }

.pm-values {
  flex: 0 0 auto;
  text-align: right;
  white-space: nowrap;
}

.pm-values .amount { color: var(--text-primary); }

/* Consumed by dashboard_payment_methods_analytics.html (an independently-
   swappable fragment, see D-30) as pm-icon-{{.Method}} — exact names. */
.pm-icon {
  width: 34px; height: 34px; border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--text-xs); font-weight: var(--weight-black); flex-shrink: 0;
}
.pm-icon-PIX         { background: var(--status-paid-bg); color: var(--status-paid-fg); }
.pm-icon-BOLETO      { background: var(--status-info-bg); color: var(--status-info-fg); }
.pm-icon-CREDIT_CARD { background: var(--status-pending-bg); color: var(--status-pending-fg); }
.pm-icon-DEBIT       { background: var(--status-next-bg); color: var(--status-next-fg); }
.pm-icon-CASH        { background: var(--status-partial-bg); color: var(--status-partial-fg); }
.pm-icon-OTHER       { background: var(--bg-input); color: var(--text-muted); }

.overdue-banner { border-color: var(--status-overdue-border); }

.overdue-banner strong { color: var(--text-primary); }

.panel-empty {
  padding: var(--space-6) var(--space-4);
  text-align: center;
  color: var(--text-secondary);
}

/* Section-to-section rhythm. Same token the layout rules use, so a
   dashboard panel and the .dashboard-top of /bills sit the same distance
   from what follows them, at every width. */
.stack-section { margin-bottom: var(--stack-section); }
.stack-section-top { margin-top: var(--stack-section); }

/* Dashboard filter toolbar. .table-card carries backdrop-filter, which
   creates a stacking context and traps the category dropdown — hence the
   explicit raise (was a hard-coded z-index: 20 inline). */
.dash-filter-card {
  position: relative;
  z-index: var(--z-raised);
}

.dash-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.dash-toolbar-controls {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}

.dash-toolbar-row + .dash-toolbar-row {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-color);
}

.variance-label { font-weight: var(--weight-bold); }
.variance-under   { color: var(--status-paid-fg); }
.variance-over    { color: var(--status-overdue-fg); }
.variance-neutral { color: var(--text-muted); }

/* Skeleton geometry — kept as classes so a placeholder and the content
   that replaces it stay the same size and the layout does not jump. */
.skeleton-icon { width: 36px; height: 36px; border-radius: var(--radius-md); }
.skeleton-title { width: 45%; height: 1.1rem; }
.skeleton-label { width: 55%; margin-bottom: 0; }
.skeleton-label-wide { width: 60%; }
.skeleton-value-sm { height: 1.3rem; width: 50%; }
.skeleton-chart { height: 220px; margin-top: var(--space-3); }
.skeleton-chart-tall { height: 340px; }
.skeleton-panel { height: 140px; }
.skeleton-strip { height: 60px; }
.skeleton-cashflow-card { height: 90px; }

/* Health strip: grade badge + score bar. Consumed by dashboard.html and
   dashboard_health_analytics.html (an independently-swappable fragment,
   see D-30) — grade-{{.Health.Grade}} and the bar tone classes are
   string-built from Go data, so the class names below must stay exact. */
.health-strip {
  padding: var(--space-4) var(--space-5);
  display: flex;
  align-items: center;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.health-meter {
  min-width: 160px;
  flex: 1 1 auto;
}

.health-score {
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}

.health-grade {
  font-family: var(--font-title);
  font-size: var(--text-2xl);
  font-weight: var(--weight-black);
  line-height: 1;
  min-width: 2.5rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.grade-A { color: var(--status-paid-fg); }
.grade-B { color: var(--status-info-fg); }
.grade-C { color: var(--status-pending-fg); }
.grade-D { color: var(--health-grade-d-fg); }
.grade-F { color: var(--status-overdue-fg); }

.health-bar-track {
  height: 6px;
  background: var(--bg-input);
  border-radius: var(--radius-pill);
  overflow: hidden;
  min-width: 140px;
}

/* The bar fill sets only its background colour, so it needs its height
   from here now that the inline height:100% is gone. */
.health-bar-track > * { height: 100%; }
.health-bar-good { background: var(--status-paid-fg); }
.health-bar-warn { background: var(--status-pending-fg); }
.health-bar-bad  { background: var(--status-overdue-fg); }

.category-breakdown-list--scroll {
  max-height: 280px;
  overflow-y: auto;
  /* do not chain the inner scroll to the page */
  overscroll-behavior: contain;
}

.category-breakdown-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: 1rem;
}

.category-breakdown-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  background: var(--bg-input);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-color);
}

/* Category row is a full-width unstyled button so the whole row is
   clickable; the visible styling stays on .category-breakdown-item. */
.cat-row-btn {
  all: unset;
  display: block;
  width: 100%;
  cursor: pointer;
}
.cat-row-btn.is-selected .category-breakdown-item {
  border-color: var(--primary);
  background: var(--primary-glow);
}

.cat-item-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

/* Same shrink rule as .panel-identity: without min-width:0 a long
   category name grows the row instead of truncating. */
.cat-item-info {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  flex: 1 1 auto;
}

.cat-item-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--weight-semibold);
  font-size: var(--text-md);
  color: var(--text-primary);
}

.cat-item-values {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
}

.cat-progress-bar-bg {
  width: 100%;
  height: 6px;
  background: var(--bg-hover);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.cat-progress-bar-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  transition: width 0.4s ease;
}

/* Custom Date Wrapper & Utility */
.custom-date-wrapper {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* ============================================================
   ABOUT BUTTON & MODAL STYLING
   ============================================================ */

.btn-about-header {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--bg-subtle);
  border: 1px solid var(--border-color);
  color: var(--text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  padding: 0.35rem 0.85rem;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-about-header:hover {
  background: var(--primary-soft);
  border-color: var(--primary-glow);
  color: var(--status-partial-fg);
}

.about-modal-card {
  max-width: 520px;
  width: 100%;
}

.about-brand-header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.about-modal-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-5) 0;
}

.about-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-4);
}

.about-info-tile {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
}

.tile-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.icon-version { background: var(--primary-soft); color: var(--status-partial-fg); }
.icon-uptime { background: var(--status-paid-bg); color: var(--status-paid-fg); }
.icon-engine { background: var(--status-info-bg); color: var(--status-info-fg); }
.icon-database { background: var(--status-next-bg); color: var(--status-next-fg); }

.tile-content {
  display: flex;
  flex-direction: column;
}

.tile-value {
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}

.tile-value.highlight {
  font-family: var(--font-title);
  color: var(--status-partial-fg);
}

.about-description-box {
  background: var(--bg-subtle);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1.15rem;
}

.about-description-box h3 {
  font-size: var(--text-md);
  margin-bottom: 0.4rem;
  color: var(--text-primary);
}

.about-description-box p {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  line-height: var(--leading-snug);
  max-width: 60ch;
}

.status-indicator-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--status-paid-fg);
  background: var(--status-paid-bg);
  padding: 0.3rem 0.75rem;
  border-radius: var(--radius-pill);
  border: 1px solid var(--status-paid-border);
}

/* Colour always comes from the parent .status-* / .badge--* class. */
.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: 0 0 auto;
}

.status-indicator-pill .status-dot { background: var(--status-paid-fg); }

/* ============================================================
   RESPONSIVE & MOBILE DESIGN SYSTEM (≤ 768px Overrides)
   ============================================================ */

/* ── Global Layout & Body Lock ────────────────────────────── */
body.modal-open {
  overflow: hidden !important;
}

/* Touch targets and form controls */
/* ── Mobile Bottom Navigation ─────────────────────────────── */
.mobile-bottom-nav {
  display: none;
}

@media (max-width: 768px) {
  /* Clear the fixed bottom nav: its own 64px plus whatever the home
     indicator claims, plus a breathing gap. Nothing else pads body. */
  body {
    padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px) + var(--space-2));
  }

  .dashboard-top {
    flex-direction: column !important;
    align-items: flex-start;
    gap: var(--space-4) !important;
  }

  .dashboard-top > div {
    width: 100%;
  }

  .dashboard-top .btn {
    flex: 1;
    min-height: 48px;
    justify-content: center;
  }

  /* Header & Navigation */
  .desktop-nav-row {
    display: none !important;
  }

  .mobile-bottom-nav {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: var(--z-toast); /* fixed viewport chrome — shares the toast layer's level */
    background: var(--bg-surface);
    border-top: 1px solid var(--border-color);
    padding-bottom: env(safe-area-inset-bottom, 0);
    height: 64px;
    align-items: stretch;
    box-shadow: var(--shadow-lg);
  }

  .mobile-nav-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    font-size: var(--text-2xs);
    font-weight: var(--weight-semibold);
    color: var(--text-muted);
    text-decoration: none;
    transition: color 0.15s;
    min-height: 44px;
  }

  .mobile-nav-item.active {
    color: var(--primary);
  }

  .mobile-nav-item svg {
    width: 22px;
    height: 22px;
  }

  /* Toolbar & Segmented Controls */
  .table-toolbar {
    flex-direction: column !important;
    align-items: stretch !important;
    gap: var(--space-3) !important;
  }

  .toolbar-actions {
    width: 100%;
  }

  .segmented-control {
    width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    display: flex;
    justify-content: flex-start;
  }

  .segmented-control::-webkit-scrollbar {
    display: none;
  }

  .tab-btn {
    flex-shrink: 0;
    white-space: nowrap;
  }

  .sub-filter-bar {
    flex-direction: column !important;
    gap: var(--space-2) !important;
  }

  .sub-filter-bar input[type="search"] {
    width: 100% !important;
  }

  /* KPI Grids */
  .kpi-grid {
    grid-template-columns: 1fr !important;
    gap: var(--space-3) !important;
  }

  .analytics-kpi-grid {
    grid-template-columns: 1fr 1fr !important;
  }

  /* ── Responsive Table (Card List Transformation) ────────── */
  .table--cards,
  .table--cards tbody,
  .table--cards tr,
  .table--cards td {
    display: block;
    width: 100%;
  }

  .table--cards thead {
    display: none;
  }

  .table--cards tr {
    background: var(--bg-card);
    border: var(--border-width) solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    margin-bottom: var(--space-3);
    padding: var(--space-3) var(--space-4);
    position: relative;
    overflow: hidden; /* hard stop — nothing escapes the card */
  }

  .table--cards tr.row-overdue-highlight {
    border-left: 4px solid var(--status-overdue-fg);
  }

  .table--cards td {
    display: flex;
    align-items: flex-start; /* a wrapped value aligns to its label */
    justify-content: space-between;
    /* When a nowrap value (a large currency amount) cannot share a line
       with its label, it drops to its own line rather than being clipped
       by the card's overflow:hidden. */
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-4); /* label and value could previously touch */
    padding: var(--space-1) 0;
    border: none;
    font-size: var(--text-sm);
    min-height: 0;
    min-width: 0;
    overflow-wrap: anywhere; /* covers cells holding a bare text node */
  }

  .table--cards td:empty {
    display: none;
  }

  .table--cards td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    max-width: 40%; /* a long label can no longer starve the value */
    font-size: var(--text-2xs);
    font-weight: var(--weight-bold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
    text-align: left;
  }

  /* THE fix: flex children default to min-width:auto, so they could not
     shrink below their content width and rendered past the card edge. */
  .table--cards td > * {
    min-width: 0;
    /* shrink-but-don't-grow: justify-content already pushes the value to
       the right, and growing would stretch inline components (badges,
       pills) to the full card width. */
    flex: 0 1 auto;
    text-align: right;
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* Cells whose value must not wrap internally keep their content width
     so the flex line breaks instead of squeezing the value past the edge. */
  .table--cards td.cell-amount > *,
  .table--cards td.cell-status > * {
    flex: 0 0 auto;
    min-width: auto;
  }

  /* The progress cell's desktop min-width would force the card wide; the
     bar itself is an empty div, so it needs to grow rather than size to
     its (zero) content. */
  .table--cards td.cell-progress { min-width: 0; }
  .table--cards td.cell-progress .category-progress-wrap {
    flex: 1 1 auto;
    min-width: 0;
  }

  /* The inline name editor must not stretch and swallow its save button. */
  .table--cards td .name-edit-wrap { flex: 0 1 auto; }

  /* Bleed the matrix scroller to the card edges so the full viewport
     width is usable, and fade the right edge so it is obvious there is
     more content. Browsers without mask-image degrade to a plain
     scroller, which is the current behaviour. */
  .table-scroll {
    margin-inline: calc(var(--space-card) * -1);
    padding-inline: var(--space-card);
    mask-image: linear-gradient(to right, black calc(100% - 2rem), transparent 100%);
    -webkit-mask-image: linear-gradient(to right, black calc(100% - 2rem), transparent 100%);
  }

  .table--cards td.cell-actions {
    justify-content: flex-end;
    gap: var(--space-2);
    border-top: var(--border-width) solid var(--border-color);
    margin-top: var(--space-2);
    padding-top: var(--space-3);
  }

  .table--cards td.cell-actions::before {
    display: none;
  }

  /* ── Modals: Touch-Optimized Bottom Sheets ─────────────── */
  .modal-overlay {
    align-items: flex-end !important;
    padding: 0 !important;
  }

  .modal-card,
  .modal-box {
    width: 100% !important;
    max-width: 100% !important;
    max-height: 90vh !important;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    animation: slideUpSheet 0.25s ease-out;
  }

  .modal-card {
    padding: var(--space-4);
  }

  @keyframes slideUpSheet {
    from {
      transform: translateY(100%);
    }
    to {
      transform: translateY(0);
    }
  }

  .modal-header::before {
    content: '';
    display: block;
    width: 36px;
    height: 4px;
    background: var(--border-color);
    border-radius: 2px;
    margin: 0 auto 0.75rem;
  }

  /* Form Layouts & Touch Inputs — scoped to text-like fields only, so a
     checkbox is not forced to 48px. See the TEXT-LIKE FIELDS block. */
  input:where(:not([type="checkbox"], [type="radio"], [type="color"], [type="file"], [type="range"], [type="submit"], [type="button"], [type="image"], [type="reset"])),
  select,
  textarea {
    min-height: 48px;
    font-size: 16px; /* Device guard: iOS Safari auto-zooms below 16px */
  }

  .field--sm {
    min-height: 40px;
    font-size: 16px; /* keeps the iOS zoom guard the base rule would lose here */
  }

  /* .select > select outranks the base rule above, so it has to restate
     the zoom guard or focusing a select zooms the page on iOS. */
  .select > select,
  .select--sm > select {
    font-size: 16px;
  }

  .select--sm > select {
    min-height: 44px;
  }

  .form-row {
    --form-cols: 1;
    gap: var(--space-3);
  }

  /* Touch targets. Replaces .btn-touch, which had to be applied by hand
     to every row-action button. */
  .btn:not(.btn--icon) { min-height: 44px; }
  .btn--icon { min-width: 44px; min-height: 44px; aspect-ratio: 1; }
  .modal-close { width: 44px; height: 44px; }

  /* Primary action at the bottom, under the thumb, Cancel above it —
     the standard bottom-sheet ordering. */
  .modal-actions,
  .modal-footer { flex-direction: column-reverse; }
  .modal-actions > .btn,
  .modal-footer > .btn { width: 100%; }

  /* Charts */
  .chart-container { height: 220px; }
  .chart-container--tall { height: 260px; }

  .charts-grid {
    grid-template-columns: minmax(0, 1fr) !important;
  }

  /* The bill count is secondary; dropping it keeps the name and the
     amount on one line. */
  .panel-count { display: none; }

  /* The values side is nowrap and wins the space contest outright, which
     squeezes the name to zero width. Stack instead: the name gets the
     full row and truncates, the values sit beneath it. */
  .panel-row,
  .pm-row,
  .cat-item-top {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-1);
  }

  .panel-values,
  .pm-values,
  .cat-item-values {
    justify-content: flex-end;
    text-align: right;
  }

  /* "Expected: R$ 1.234,56" does not fit on one line at 320px. */
  .pm-values { white-space: normal; }

  /* The meter's desktop floor is wider than the space left beside the
     grade badge on the narrowest phones. */
  .health-meter { min-width: 0; }
  .kpi-meter-head { flex-wrap: wrap; gap: var(--space-1); }

  /* .health-bar-track's own min-width:140px is beaten here purely by the
     extra specificity of this compound selector — not an !important. */
  .health-strip .health-bar-track { min-width: 0; }
}

@media (max-width: 400px) {
  .analytics-kpi-grid {
    grid-template-columns: 1fr !important;
  }

  .table--cards td.cell-context > * {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

/* ============================================================
   ABOUT MODAL TABS & STATS
   ============================================================ */

.about-nav-tabs {
  display: flex;
  gap: var(--space-2);
  margin-bottom: 1.25rem;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 0.5rem;
}

.about-tab-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.55rem 1rem;
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  transition: all 0.2s ease;
}

.about-tab-btn:hover {
  color: var(--text-primary);
  background: var(--bg-input);
}

.about-tab-btn.active {
  background: var(--primary-glow);
  color: var(--primary);
  border-color: var(--primary-glow);
}

.about-tab-panel {
  animation: fadeIn var(--duration-base) var(--ease-out);
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-3);
}

.stat-tile {
  background: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.stat-tile-value {
  font-family: var(--font-title);
  font-size: var(--text-lg);
  font-weight: var(--weight-black);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.stat-tile-value.highlight-success {
  color: var(--status-paid-fg);
}

.stat-tile-value.highlight-warning {
  color: var(--status-pending-fg);
}

/* ==========================================================================
   WORKSPACE SETTINGS MODAL & ROLE BADGES
   ========================================================================== */
.settings-modal-container {
  width: 92%;
  max-width: 820px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  padding: 0;
  animation: scaleIn var(--duration-slow) var(--ease-out);
}

.settings-modal-header {
  padding: 1.25rem 1.5rem;
  background: var(--bg-card);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.header-title-group {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.modal-header-icon {
  width: 42px;
  height: 42px;
  border-radius: var(--radius-md);
  background: var(--primary-glow);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-subtitle {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin: var(--space-1) 0 0;
}

.settings-modal-tabs {
  display: flex;
  gap: var(--space-2);
  padding: 0.75rem 1.5rem 0 1.5rem;
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border-color);
}

.settings-modal-tabs .tab-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.6rem 1rem;
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--text-secondary);
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: all 0.2s ease;
}

.settings-modal-tabs .tab-btn:hover {
  color: var(--text-primary);
}

.settings-modal-tabs .tab-btn.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

.settings-modal-body {
  padding: var(--space-card);
  overflow-y: auto;
  flex: 1;
}

.tab-panel {
  display: none;
}

.tab-panel.active {
  display: block;
  animation: fadeIn var(--duration-base) var(--ease-out);
}

/* Settings Cards */
.settings-card-grid {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.settings-section-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: var(--space-card);
}

.section-card-title {
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  margin: 0 0 1rem 0;
}

.input-with-button {
  display: flex;
  gap: var(--space-2);
}

.input-with-button > input,
.input-with-button > .select {
  flex: 1;
}

/* Property List */
.property-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.property-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border-color);
}

.property-item:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.property-label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.property-value {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--text-primary);
}

.property-value-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Danger Section (Ownership Transfer) */
.danger-section {
  border-color: var(--status-overdue-border);
  background: var(--status-overdue-bg);
}

.danger-header {
  display: flex;
  gap: var(--space-3);
  color: var(--status-overdue-fg);
  margin-bottom: 1rem;
}

.danger-title {
  font-size: var(--text-md);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  margin: 0;
}

.danger-desc {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin: 0.25rem 0 0 0;
}

/* Users Panel */
.users-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1rem;
}

.modal-table-wrap {
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  background: var(--bg-card);
  overflow: hidden;
}

.name-edit-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.input-inline-name {
  max-width: 180px;
}

.btn-icon-save {
  background: var(--primary-glow);
  color: var(--primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 0.2rem 0.4rem;
  cursor: pointer;
  font-weight: var(--weight-bold);
}

.btn-action-delete {
  background: var(--status-overdue-bg);
  color: var(--status-overdue-fg);
  border: 1px solid var(--status-overdue-border);
  border-radius: var(--radius-sm);
  padding: 0.25rem 0.5rem;
  font-size: var(--text-xs);
  cursor: pointer;
  transition: all 0.2s ease;
}

.btn-action-delete:hover {
  background: var(--status-overdue-fg);
  color: var(--text-inverse);
}

.btn-action-copy {
  background: var(--bg-input);
  color: var(--text-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 0.25rem 0.5rem;
  font-size: var(--text-xs);
  cursor: pointer;
}

/* Roles Stats Grid */
.roles-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-4);
  margin-bottom: 1.5rem;
}

.role-stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.stat-role-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.stat-count {
  font-family: var(--font-title);
  font-size: var(--text-xl);
  font-weight: var(--weight-black);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.role-stat-desc {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  margin: 0;
  line-height: var(--leading-snug);
  max-width: 60ch;
}

.matrix-title-wrap {
  margin-bottom: 0.75rem;
}

/* ------------------------------------------------------------------
   WORKSPACE SETTINGS PAGE (workspace/settings.html) — the role
   permission summary grid and the member-list identity cell. The
   settings modal has its own equivalents (.roles-stats-grid,
   inline name markup) and does not use these.
   ------------------------------------------------------------------ */
.role-summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-4);
}

.role-summary {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--bg-input);
  border: var(--border-width) solid var(--border-color);
  border-radius: var(--radius-md);
}

.member-identity {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.avatar {
  width: 2rem;
  height: 2rem;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), var(--status-next-fg));
  color: var(--primary-fg);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
}

.member-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--weight-medium);
}

.form-group--actions {
  justify-content: flex-end;
}

@media (max-width: 768px) {
  .form-group--actions .btn { width: 100%; }
}

.text-success {
  color: var(--status-paid-fg);
  font-weight: var(--weight-bold);
}

/* Custom Danger Confirmation Modal Styles */
.danger-title-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--status-overdue-fg);
}

.danger-title-wrap svg {
  color: var(--status-overdue-fg);
}

.target-email-badge {
  display: flex;
  justify-content: center;
  margin: 0.75rem 0 1.25rem 0;
}

.code-badge-danger {
  font-family: var(--font-mono);
  font-size: var(--text-md);
  background: var(--status-overdue-bg);
  color: var(--status-overdue-fg);
  border: 1px solid var(--status-overdue-border);
  padding: 0.5rem 1rem;
  border-radius: var(--radius-md);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.02em;
}

.confirm-danger-box {
  background: var(--status-overdue-bg);
  border: 1px solid var(--status-overdue-border);
  border-radius: var(--radius-md);
  padding: 1rem 1.15rem;
}

.danger-box-header {
  font-size: var(--text-sm);
  color: var(--status-overdue-fg);
  margin-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.danger-list {
  margin: 0;
  padding-left: 1.2rem;
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.danger-list li {
  margin-bottom: 0.4rem;
  line-height: 1.45;
}

.danger-list code {
  color: var(--status-overdue-fg);
  background: var(--status-overdue-bg);
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  border: 1px solid var(--status-overdue-border);
}





