/* =============================================================================
 * HIV/AIDS ANALYTICS SYSTEM — app.css
 * -----------------------------------------------------------------------------
 * Design system + component layer.
 *   - Dark, glassmorphic "clinical console" aesthetic
 *   - Bento-grid responsive layout
 *   - Full print stylesheet for report generation
 * ========================================================================== */

/* ---------------------------------------------------------------------------
 * 1. Tokens
 * ------------------------------------------------------------------------ */
:root {
  /* Surfaces */
  --bg-base: #070b16;
  --bg-deep: #04070f;
  --bg-elevated: rgba(20, 27, 45, 0.72);
  --bg-elevated-solid: #141b2d;
  --bg-input: rgba(9, 14, 26, 0.75);
  --glass-border: rgba(148, 163, 184, 0.16);
  --glass-border-strong: rgba(148, 163, 184, 0.3);
  --glass-highlight: rgba(255, 255, 255, 0.05);

  /* Text */
  --text-primary: #eef2ff;
  --text-secondary: #a7b3cc;
  --text-muted: #6b7893;
  --text-inverse: #060a14;

  /* Accents */
  --violet: #8b5cf6;
  --violet-soft: rgba(139, 92, 246, 0.16);
  --cyan: #22d3ee;
  --cyan-soft: rgba(34, 211, 238, 0.16);
  --emerald: #10b981;
  --emerald-soft: rgba(16, 185, 129, 0.16);
  --amber: #f59e0b;
  --amber-soft: rgba(245, 158, 11, 0.16);
  --rose: #f43f5e;
  --rose-soft: rgba(244, 63, 94, 0.16);
  --slate: #94a3b8;
  --slate-soft: rgba(148, 163, 184, 0.14);
  --indigo: #6366f1;

  /* Semantic */
  --success: var(--emerald);
  --warning: var(--amber);
  --danger: var(--rose);
  --info: var(--cyan);

  /* Geometry */
  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-pill: 999px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.7);
  --shadow-lg: 0 28px 60px -20px rgba(0, 0, 0, 0.8);
  --glow-violet: 0 0 40px -12px rgba(139, 92, 246, 0.55);
  --glow-emerald: 0 0 40px -12px rgba(16, 185, 129, 0.5);

  /* Typography */
  --font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'SFMono-Regular', 'JetBrains Mono', Menlo, Consolas, monospace;

  /* Motion */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --dur: 220ms;

  --header-h: 68px;
}

/* ---------------------------------------------------------------------------
 * 2. Reset & base
 * ------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-primary);
  background: var(--bg-base);
  background-image:
    radial-gradient(1100px 600px at 12% -8%, rgba(139, 92, 246, 0.18), transparent 62%),
    radial-gradient(900px 520px at 88% 4%, rgba(34, 211, 238, 0.14), transparent 60%),
    radial-gradient(800px 700px at 50% 108%, rgba(16, 185, 129, 0.1), transparent 62%);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { margin: 0; font-weight: 650; letter-spacing: -0.015em; }
p { margin: 0; }
button { font-family: inherit; }
a { color: var(--cyan); }

::selection { background: rgba(139, 92, 246, 0.38); }

/* Scrollbars */
* { scrollbar-width: thin; scrollbar-color: rgba(148, 163, 184, 0.3) transparent; }
*::-webkit-scrollbar { width: 9px; height: 9px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: rgba(148, 163, 184, 0.26);
  border-radius: var(--radius-pill);
  border: 2px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: rgba(148, 163, 184, 0.45); background-clip: content-box; }

/* Utilities */
.hidden { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.mono { font-family: var(--font-mono); font-size: 0.92em; }
.nowrap { white-space: nowrap; }
.text-muted { color: var(--text-muted); }
.text-secondary { color: var(--text-secondary); }
.text-center { text-align: center; }
.text-right { text-align: right; }
.mt-0 { margin-top: 0; }

/* ---------------------------------------------------------------------------
 * 3. Layout shell
 * ------------------------------------------------------------------------ */
.app-shell { min-height: 100vh; display: flex; flex-direction: column; }

.container {
  width: 100%;
  max-width: 1520px;
  margin: 0 auto;
  padding: 0 24px;
}

/* --- Header ------------------------------------------------------------- */
.app-header {
  position: sticky;
  top: 0;
  z-index: 60;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: rgba(7, 11, 22, 0.82);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-bottom: 1px solid var(--glass-border);
}

.header-inner { display: flex; align-items: center; gap: 20px; width: 100%; }

.brand { display: flex; align-items: center; gap: 13px; min-width: 0; }

.brand-mark {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  /* siha.svg already carries its own rounded container, so this element is a
     transparent wrapper only — no plate, no gradient, no glow behind it. */
}
.brand-mark img { display: block; width: 34px; height: 34px; }

.brand-text { min-width: 0; }
.brand-title {
  font-size: 15.5px; font-weight: 700; letter-spacing: -0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.brand-sub {
  font-size: 11px; color: var(--text-muted); letter-spacing: 0.06em;
  text-transform: uppercase; white-space: nowrap;
}

.header-spacer { flex: 1 1 auto; }
.header-actions { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
/* Logout is a real form POST to the Pages Function (so it survives JavaScript
   being blocked by the page it is escaping). display:contents keeps the button
   itself as the flex item of .header-actions instead of the form. */
.logout-form { display: contents; }

/* --- Main --------------------------------------------------------------- */
.app-main { flex: 1 1 auto; padding: 26px 0 80px; }

.section { margin-bottom: 30px; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 18px; margin-bottom: 15px; flex-wrap: wrap;
}
.section-title {
  display: flex; align-items: center; gap: 11px;
  font-size: 17px; font-weight: 680;
}
.section-title i {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center; font-size: 13px;
  color: var(--cyan);
  background: var(--cyan-soft);
  border-radius: 9px;
}
.section-desc { font-size: 12.5px; color: var(--text-muted); margin-top: 3px; }

/* ---------------------------------------------------------------------------
 * 4. Glass card / Bento grid
 * ------------------------------------------------------------------------ */
.card {
  position: relative;
  background: var(--bg-elevated);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.card::before {
  content: '';
  position: absolute; inset: 0 0 auto 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--glass-highlight), transparent);
  pointer-events: none;
}

.card-pad { padding: 20px 22px; }

.card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; padding: 17px 20px 0;
}
.card-title { font-size: 14.5px; font-weight: 650; display: flex; align-items: center; gap: 9px; }
.card-title i { font-size: 13px; color: var(--text-muted); }
.card-subtitle { font-size: 11.8px; color: var(--text-muted); margin-top: 2px; }
.card-body { padding: 16px 20px 20px; }

.bento { display: grid; gap: 16px; }
.bento-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.bento-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.bento-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.bento-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.span-2 { grid-column: span 2; }
.span-3 { grid-column: span 3; }
.span-4 { grid-column: span 4; }

/* ---------------------------------------------------------------------------
 * 5. Buttons
 * ------------------------------------------------------------------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 9px 15px;
  font-size: 12.8px; font-weight: 600; letter-spacing: 0.01em;
  color: var(--text-primary);
  background: rgba(148, 163, 184, 0.1);
  border: 1px solid var(--glass-border);
  border-radius: 11px;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), opacity var(--dur);
}
.btn:hover:not(:disabled) {
  background: rgba(148, 163, 184, 0.18);
  border-color: var(--glass-border-strong);
  transform: translateY(-1px);
}
.btn:active:not(:disabled) { transform: translateY(0); }
.btn:disabled { opacity: 0.42; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

.btn-primary {
  color: #fff;
  background: linear-gradient(135deg, var(--violet), #6d4de0);
  border-color: rgba(139, 92, 246, 0.5);
  box-shadow: var(--glow-violet);
}
.btn-primary:hover:not(:disabled) { background: linear-gradient(135deg, #9d70f8, #7c5aef); }

.btn-accent {
  color: var(--text-inverse);
  background: linear-gradient(135deg, var(--cyan), #38bdf8);
  border-color: rgba(34, 211, 238, 0.5);
  font-weight: 700;
}
.btn-accent:hover:not(:disabled) { background: linear-gradient(135deg, #4ce0f5, #5cc9fb); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--text-secondary); }
.btn-ghost:hover:not(:disabled) { background: rgba(148, 163, 184, 0.12); color: var(--text-primary); }

.btn-danger { color: #fda4af; background: var(--rose-soft); border-color: rgba(244, 63, 94, 0.34); }
.btn-danger:hover:not(:disabled) { background: rgba(244, 63, 94, 0.26); }

.btn-sm { padding: 6px 11px; font-size: 11.8px; border-radius: 9px; }
.btn-icon { padding: 8px; width: 34px; height: 34px; }

.btn-set { display: inline-flex; gap: 6px; }

/* ---------------------------------------------------------------------------
 * 6. Form controls
 * ------------------------------------------------------------------------ */
.field { display: flex; flex-direction: column; gap: 6px; }
.field-label {
  font-size: 11px; font-weight: 620; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text-muted);
  display: flex; align-items: center; gap: 6px;
}

.input.is-invalid {
  border-color: rgba(244, 63, 94, 0.62);
  box-shadow: 0 0 0 3px rgba(244, 63, 94, 0.14);
}

.input, .select {
  width: 100%;
  padding: 9px 12px;
  font-size: 13.5px;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--bg-input);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.input:focus, .select:focus {
  outline: none;
  border-color: rgba(34, 211, 238, 0.55);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.14);
}
.input::placeholder { color: var(--text-muted); }
.input[type='date'] { min-height: 38px; }
.input[type='date']::-webkit-calendar-picker-indicator {
  filter: invert(0.72) sepia(0.2) saturate(4) hue-rotate(150deg);
  cursor: pointer;
}

.select {
  appearance: none;
  padding-right: 34px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7893' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 15px;
  cursor: pointer;
}
.select option { background: var(--bg-elevated-solid); color: var(--text-primary); }

.search-wrap { position: relative; }
.search-wrap i {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  font-size: 12.5px; color: var(--text-muted); pointer-events: none;
}
.search-wrap .input { padding-left: 34px; }

/* Segmented control */
.segmented {
  display: inline-flex; padding: 3px;
  background: var(--bg-input);
  border: 1px solid var(--glass-border);
  border-radius: 11px;
  gap: 2px;
}
.segmented button {
  padding: 6px 12px;
  font-size: 12px; font-weight: 600;
  color: var(--text-secondary);
  background: transparent; border: 0; border-radius: 8px;
  cursor: pointer;
  transition: color var(--dur), background var(--dur);
}
.segmented button:hover { color: var(--text-primary); }
.segmented button.is-active {
  color: #fff;
  background: linear-gradient(135deg, rgba(139, 92, 246, 0.92), rgba(99, 102, 241, 0.92));
  box-shadow: var(--shadow-sm);
}

/* ---------------------------------------------------------------------------
 * 7. Badges & chips
 * ------------------------------------------------------------------------ */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  font-size: 10.8px; font-weight: 680; letter-spacing: 0.03em;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge i { font-size: 9.5px; }
.badge-success { color: #6ee7b7; background: var(--emerald-soft); border-color: rgba(16, 185, 129, 0.34); }
.badge-warning { color: #fcd34d; background: var(--amber-soft); border-color: rgba(245, 158, 11, 0.34); }
.badge-danger  { color: #fda4af; background: var(--rose-soft);  border-color: rgba(244, 63, 94, 0.34); }
.badge-critical{ color: #fecdd3; background: rgba(190, 18, 60, 0.28); border-color: rgba(244, 63, 94, 0.5); }
.badge-info    { color: #a5f3fc; background: var(--cyan-soft);  border-color: rgba(34, 211, 238, 0.34); }
.badge-violet  { color: #c4b5fd; background: var(--violet-soft);border-color: rgba(139, 92, 246, 0.34); }
.badge-neutral { color: var(--text-secondary); background: var(--slate-soft); border-color: var(--glass-border); }
.badge-ok      { color: #6ee7b7; background: var(--emerald-soft); border-color: rgba(16, 185, 129, 0.3); }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  font-size: 11.5px; font-weight: 560;
  color: var(--text-secondary);
  background: rgba(148, 163, 184, 0.1);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
}
.chip i { font-size: 10px; }

/* ---------------------------------------------------------------------------
 * 9b. Parameter Analisis panel
 * ------------------------------------------------------------------------ */
.params-card {
  margin-top: 18px;
  background: linear-gradient(150deg, rgba(24, 32, 54, 0.86), rgba(13, 19, 34, 0.78));
  border: 1px solid var(--glass-border-strong);
}

.params-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px; flex-wrap: wrap;
  padding: 17px 20px 15px;
  border-bottom: 1px solid var(--glass-border);
}
.params-head-main { display: flex; align-items: center; gap: 13px; min-width: 0; }
.params-icon {
  width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  font-size: 15px;
  color: var(--cyan);
  background: var(--cyan-soft);
  border-radius: 12px;
}
.params-title { font-size: 15px; font-weight: 680; letter-spacing: -0.015em; }
.params-sub { font-size: 11.8px; color: var(--text-muted); margin-top: 2px; }

.params-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  padding: 18px 20px;
}

.param-box {
  display: flex; flex-direction: column; gap: 10px;
  padding: 15px 16px 14px;
  background: rgba(7, 11, 22, 0.5);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.param-box:focus-within {
  border-color: rgba(34, 211, 238, 0.5);
  background: rgba(9, 14, 26, 0.7);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.1);
}
.param-box.is-warn { border-color: rgba(245, 158, 11, 0.42); }
.param-box.is-warn:focus-within { border-color: rgba(245, 158, 11, 0.6); box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1); }

.param-top { display: flex; align-items: center; gap: 9px; }
.param-ico {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  font-size: 12.5px;
  border-radius: 9px;
}
.param-ico-violet { color: #c4b5fd; background: var(--violet-soft); }
.param-ico-cyan { color: #a5f3fc; background: var(--cyan-soft); }

.param-label {
  flex: 1 1 auto;
  font-size: 12.2px; font-weight: 660; letter-spacing: 0.01em;
}
.param-role {
  font-size: 10px; font-weight: 680; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted);
  padding: 2px 8px;
  background: rgba(148, 163, 184, 0.12);
  border-radius: var(--radius-pill);
}

/* The control itself carries the visual weight — no floating label above it. */
.param-input {
  width: 100%;
  padding: 11px 13px;
  font-family: var(--font-mono);
  font-size: 19px; font-weight: 650;
  letter-spacing: 0.01em;
  color: var(--text-primary);
  background: rgba(4, 7, 15, 0.6);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.param-input:focus {
  outline: none;
  border-color: rgba(34, 211, 238, 0.55);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.14);
}
.param-input::placeholder { color: var(--text-muted); font-weight: 500; }
.param-input.is-invalid {
  border-color: rgba(244, 63, 94, 0.62);
  box-shadow: 0 0 0 3px rgba(244, 63, 94, 0.14);
}
/* Date control renders better slightly smaller than the numeric one */
input[type='date'].param-input { font-size: 16px; font-weight: 600; }

.param-foot {
  display: flex; align-items: flex-start; flex-wrap: wrap; gap: 6px;
  font-size: 11.2px; line-height: 1.5;
  color: var(--text-muted);
  min-height: 17px;
}
.param-foot i { font-size: 10px; margin-top: 3px; }
.param-foot.is-warn { color: #fcd34d; }
.param-foot b { color: var(--text-secondary); font-weight: 650; }

/* Fixed, non-adjustable programme rules */
.params-fixed {
  display: flex; align-items: center; gap: 9px;
  padding: 11px 20px 15px;
  font-size: 11.6px;
  color: var(--text-muted);
  border-top: 1px dashed var(--glass-border);
}
.params-fixed b { color: var(--text-secondary); font-weight: 650; }
.fixed-ico {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  font-size: 10px;
  color: var(--text-muted);
  background: rgba(148, 163, 184, 0.12);
  border-radius: 7px;
}

/* ---------------------------------------------------------------------------
 * 9c. Ingestion status strip
 * ------------------------------------------------------------------------ */
.ingest-strip {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px;
  margin-top: 12px;
  padding: 9px 14px;
  font-size: 11.8px;
  color: var(--text-secondary);
  background: rgba(16, 185, 129, 0.07);
  border: 1px solid rgba(16, 185, 129, 0.24);
  border-radius: 11px;
}
.ingest-total { display: inline-flex; align-items: center; gap: 7px; font-weight: 620; }
.ingest-total i { color: var(--emerald); font-size: 11px; }
.ingest-warn {
  display: inline-flex; align-items: center; gap: 6px;
  color: #fcd34d;
  cursor: help;
}
.ingest-warn i { font-size: 10.5px; }

/* ---------------------------------------------------------------------------
 * 9. Tabs
 * ------------------------------------------------------------------------ */
.tabbar {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  margin-bottom: 22px;
  background: rgba(13, 19, 34, 0.66);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  position: sticky;
  top: calc(var(--header-h) + 10px);
  z-index: 40;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabbar::-webkit-scrollbar { display: none; }

.tab {
  display: inline-flex; align-items: center; gap: 8px;
  flex: 1 1 auto;
  justify-content: center;
  padding: 10px 16px;
  font-size: 13px; font-weight: 620;
  font-family: inherit;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
  border-radius: 10px;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.tab i { font-size: 12.5px; opacity: 0.85; }
.tab:hover { color: var(--text-primary); background: rgba(148, 163, 184, 0.1); }
.tab.is-active {
  color: #fff;
  background: linear-gradient(135deg, rgba(139, 92, 246, 0.9), rgba(99, 102, 241, 0.9));
  box-shadow: var(--glow-violet);
}
.tab.is-active i { opacity: 1; }
.tab:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

.tab-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 19px; height: 19px; padding: 0 6px;
  font-size: 10.5px; font-weight: 700;
  color: #060a14;
  background: var(--emerald);
  border-radius: var(--radius-pill);
}
.tab-badge.hidden { display: none; }

.tabpanel[hidden] { display: none; }

/* Empty state shown inside a tab before its data exists */
/* Empty-state wrapper for the tab panels.
 *
 * Was `display:flex; align-items:center`, which sized the child to its content:
 * the Data Pasien / VL / Audit empty cards measured 298 / 311 / 399px inside a
 * 1392px column, while the Dashboard card — which sits in a plain block
 * `.section` — filled the column. The three tabs looked broken beside it.
 * As a grid with `justify-items: stretch` the card spans the full width, and
 * the min-height still keeps the panel from collapsing vertically. */
.tab-empty { min-height: 320px; display: grid; align-items: center; justify-items: stretch; }
.tab-empty[hidden] { display: none; }

/* ---------------------------------------------------------------------------
 * 9. Upload grid (3 source cards)
 * ------------------------------------------------------------------------ */
.upload-grid {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  align-items: stretch;
}

.upload-card {
  display: flex; flex-direction: column;
  min-height: 210px;
  padding: 18px 18px 16px;
  text-align: left;
  font-family: inherit;
  color: var(--text-primary);
  background: rgba(13, 19, 34, 0.62);
  border: 1.5px dashed var(--glass-border-strong);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
    transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.upload-card:hover {
  border-color: rgba(139, 92, 246, 0.6);
  background: rgba(20, 27, 45, 0.74);
  transform: translateY(-2px);
}
.upload-card.is-dragover {
  border-color: var(--cyan);
  background: rgba(34, 211, 238, 0.1);
  box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.1);
}
.upload-card.is-ready { border-style: solid; border-color: rgba(16, 185, 129, 0.45); background: rgba(16, 185, 129, 0.06); }
.upload-card.is-error { border-style: solid; border-color: rgba(244, 63, 94, 0.5); background: rgba(244, 63, 94, 0.06); }
.upload-card:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

.uc-head { display: flex; align-items: flex-start; gap: 12px; }
.uc-icon {
  width: 42px; height: 42px; flex: none;
  display: grid; place-items: center;
  font-size: 17px;
  border-radius: 13px;
}
.upload-card[data-accent='violet'] .uc-icon { color: #c4b5fd; background: var(--violet-soft); }
.upload-card[data-accent='cyan']   .uc-icon { color: #a5f3fc; background: var(--cyan-soft); }
.upload-card[data-accent='emerald'].uc-icon { color: #6ee7b7; background: var(--emerald-soft); }

.uc-title { font-size: 14px; font-weight: 680; letter-spacing: -0.01em; }
.uc-role { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }

.uc-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 13px; }
.uc-tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  font-size: 10.6px; font-weight: 620;
  color: var(--text-secondary);
  background: rgba(148, 163, 184, 0.1);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
}
.uc-tag.is-req { color: #fcd34d; background: var(--amber-soft); border-color: rgba(245, 158, 11, 0.3); }

/* Loaded-file list */
.uc-body { flex: 1 1 auto; margin-top: 13px; }
.uc-empty {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--text-muted);
  padding: 22px 0;
  justify-content: center;
}
.uc-files { display: flex; flex-direction: column; gap: 6px; max-height: 132px; overflow-y: auto; }
.uc-file {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px;
  font-size: 11.6px;
  background: rgba(9, 14, 26, 0.6);
  border: 1px solid var(--glass-border);
  border-radius: 9px;
}
.uc-file i.fa-circle-check { color: var(--emerald); font-size: 11px; flex: none; }
.uc-file i.fa-circle-exclamation { color: var(--rose); font-size: 11px; flex: none; }
.uc-file-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uc-file-rows { color: var(--text-muted); font-size: 10.8px; white-space: nowrap; }
.uc-file-x {
  flex: none; padding: 2px 5px;
  color: var(--text-muted);
  background: transparent; border: 0; border-radius: 6px;
  cursor: pointer; font-size: 11px;
}
.uc-file-x:hover { color: var(--rose); background: var(--rose-soft); }

.uc-error {
  margin-top: 9px;
  font-size: 11.4px;
  color: #fda4af;
  line-height: 1.45;
}

.uc-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  margin-top: 13px;
  padding-top: 12px;
  border-top: 1px solid var(--glass-border);
}
.uc-count { font-size: 11.6px; color: var(--text-muted); font-weight: 600; }
.uc-cta { font-size: 11.6px; font-weight: 650; color: var(--cyan); display: inline-flex; align-items: center; gap: 6px; }
.uc-hint { font-size: 11px; color: var(--text-muted); margin-top: 4px; }

/* Hidden native inputs live inside the card */
.upload-card input[type='file'] { display: none; }

/* ---------------------------------------------------------------------------
 * 10. Drop zones (legacy grid retained for modal / fallback use)
 * ------------------------------------------------------------------------ */
.dropzone-grid { display: grid; gap: 13px; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }

.dropzone {
  position: relative;
  display: flex; flex-direction: column; gap: 9px;
  padding: 15px 16px;
  background: rgba(13, 19, 34, 0.6);
  border: 1.5px dashed var(--glass-border-strong);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
    transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.dropzone:hover { border-color: rgba(139, 92, 246, 0.6); background: rgba(20, 27, 45, 0.72); }
.dropzone.is-dragover {
  border-color: var(--cyan);
  background: rgba(34, 211, 238, 0.1);
  transform: scale(1.012);
  box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.1);
}
.dropzone.is-loaded { border-style: solid; border-color: rgba(16, 185, 129, 0.45); background: rgba(16, 185, 129, 0.06); }
.dropzone.is-error  { border-style: solid; border-color: rgba(244, 63, 94, 0.5); background: rgba(244, 63, 94, 0.06); }
.dropzone input[type='file'] { display: none; }

.dz-head { display: flex; align-items: center; gap: 11px; }
.dz-icon {
  width: 36px; height: 36px; flex: none;
  display: grid; place-items: center; font-size: 14px;
  color: var(--text-secondary);
  background: rgba(148, 163, 184, 0.12);
  border-radius: 10px;
  transition: color var(--dur), background var(--dur);
}
.dropzone[data-accent='violet'] .dz-icon  { color: #c4b5fd; background: var(--violet-soft); }
.dropzone[data-accent='cyan'] .dz-icon    { color: #a5f3fc; background: var(--cyan-soft); }
.dropzone[data-accent='emerald'] .dz-icon { color: #6ee7b7; background: var(--emerald-soft); }
.dropzone.is-loaded .dz-icon { color: #6ee7b7; background: var(--emerald-soft); }

.dz-label { font-size: 13px; font-weight: 620; }
.dz-hint { font-size: 11.2px; color: var(--text-muted); }
.dz-foot { display: flex; align-items: center; justify-content: space-between; gap: 9px; }

.dz-status { font-size: 11.3px; color: var(--text-muted); display: flex; align-items: center; gap: 6px; min-width: 0; }
.dz-status .dz-filename {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 168px; color: var(--text-secondary);
}
.dz-error { font-size: 11.3px; color: #fda4af; margin-top: 2px; }

/* ---------------------------------------------------------------------------
 * 9. KPI / metric cards
 *
 * Glassmorphic tiles, 4 across x 2 rows = 8 cards.
 *
 * Landscape rather than square: at a 1:1 ratio the tiles were 356px tall for
 * ~100px of content, which pushed the cascade chart below the fold. 5:4 keeps
 * the tile substantial while letting the rest of the dashboard stay in view.
 *
 * The accent colour is carried by a soft radial wash from the top-left corner
 * rather than a stripe down the edge — the stripe read as dated chrome and
 * competed with the value.
 * ------------------------------------------------------------------------ */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.kpi {
  position: relative;
  aspect-ratio: 5 / 4;
  display: flex;
  flex-direction: column;
  padding: 18px 20px;
  background: var(--bg-elevated);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.kpi:hover {
  transform: translateY(-2px);
  border-color: var(--glass-border-strong);
  box-shadow: var(--shadow);
}

/* Accent wash + top highlight. Two stacked gradients give the glass its depth
   without adding any element to the markup. */
.kpi::before {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 90% at 0% 0%, var(--accent-soft, rgba(148,163,184,0.16)), transparent 58%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent 42%);
  pointer-events: none;
}

/* Oversized watermark glyph. Absolutely positioned and pushed below the text in
   stacking order, so it reads as texture and never competes with the value. */
.kpi-mark {
  position: absolute;
  right: -12px; bottom: -18px;
  font-size: 108px;
  line-height: 1;
  color: var(--accent, var(--slate));
  opacity: 0.07;
  pointer-events: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.kpi:hover .kpi-mark { opacity: 0.11; transform: translate(-3px, -3px); }

.kpi > .kpi-top, .kpi > .kpi-value, .kpi > .kpi-foot { position: relative; }

/* Per-card Excel download. Sits to the LEFT of the icon tile and only fades in
   on hover/focus so eight of them do not compete with the numbers, which are
   the message. Kept permanently visible on touch devices, where there is no
   hover.

   The icon keeps its natural place at the end of `.kpi-top`; the button is
   offset past it (17px inset + 32px icon + 4px gap) so the two tiles read as a
   pair with the icon outermost. */
.kpi-dl {
  position: absolute;
  top: 17px; right: 53px;
  z-index: 2;
  width: 32px; height: 32px;
  display: grid; place-items: center;
  font-size: 12.5px;
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur) var(--ease),
    color var(--dur) var(--ease), border-color var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.kpi:hover .kpi-dl, .kpi:focus-within .kpi-dl { opacity: 1; }
.kpi-dl:hover {
  color: var(--emerald);
  background: var(--emerald-soft);
  border-color: rgba(16, 185, 129, 0.44);
}
@media (hover: none) {
  .kpi-dl { opacity: 1; }
}

.kpi-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.kpi-label {
  font-size: 11px; font-weight: 660; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-secondary);
  line-height: 1.35;
  /* Keeps a long label from colliding with the icon in the corner. */
  max-width: calc(100% - 42px);
}
.kpi-icon {
  width: 32px; height: 32px; flex: none;
  display: grid; place-items: center;
  font-size: 13.5px;
  color: var(--accent, var(--text-muted));
  background: var(--accent-soft, rgba(148,163,184,0.14));
  border-radius: 10px;
}
/* The value block is pushed to the vertical centre of the tile, which is what
   makes the landscape proportion feel intentional rather than merely wide. */
.kpi-value {
  margin-top: auto;
  font-size: 40px; font-weight: 720; letter-spacing: -0.035em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.kpi-value small { font-size: 14px; font-weight: 600; color: var(--text-muted); margin-left: 6px; }
.kpi-foot {
  display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
  min-height: 20px;
  margin-top: 9px;
  font-size: 11.6px; color: var(--text-muted);
  line-height: 1.4;
}

.kpi[data-accent='violet']  { --accent: var(--violet);  --accent-soft: var(--violet-soft); }
.kpi[data-accent='cyan']    { --accent: var(--cyan);    --accent-soft: var(--cyan-soft); }
.kpi[data-accent='emerald'] { --accent: var(--emerald); --accent-soft: var(--emerald-soft); }
.kpi[data-accent='amber']   { --accent: var(--amber);   --accent-soft: var(--amber-soft); }
.kpi[data-accent='rose']    { --accent: var(--rose);    --accent-soft: var(--rose-soft); }
.kpi[data-accent='slate']   { --accent: var(--slate);   --accent-soft: var(--slate-soft); }
.kpi[data-accent='indigo']  { --accent: var(--indigo);  --accent-soft: rgba(99, 102, 241, 0.16); }

/* ---------------------------------------------------------------------------
 * 10b. Miss Appointment panel (patients section)
 * ------------------------------------------------------------------------ */

.miss-card {
  margin-bottom: 18px;
  background: linear-gradient(150deg, rgba(30, 20, 34, 0.8), rgba(13, 19, 34, 0.78));
  border: 1px solid rgba(244, 63, 94, 0.22);
}
.miss-card .card-title i { color: var(--rose); }

/* The plot is the only column now that the duplicate urgency panel is gone, so
   it spans the full card width and the dots get the whole span to spread into. */
.miss-grid {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 18px; align-items: stretch;
}
.miss-chart-wrap { min-width: 0; }

/* Reading key for the four urgency bands, sitting directly above the plot it
   decodes. A single row of four equal keys rather than the right-aligned stacked
   list the card header used: it reads as a symmetric scale and each key lines up
   with the band underneath it.
   Scoped through .miss-chart-wrap so it outweighs `.combo-note`'s own
   `flex-direction: column`, which is declared later in the file and would
   otherwise win on equal specificity and stack the keys back into four rows. */
.miss-chart-wrap .miss-legend {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 8px 26px;
  text-align: left;
  margin-bottom: 12px;
}
.miss-chart-wrap .miss-legend .combo-note-item { justify-content: flex-start; gap: 6px; }
.miss-chart-wrap .miss-legend .combo-note-value {
  min-width: 0; text-align: left; order: -1;
  font-size: 13px;
}
#miss-timeline .chart { width: 100%; display: block; }
/* The SVG keeps its own 900×300 viewBox and scales uniformly to the column, so
   no max-width is set here — capping it would re-introduce the dead space that
   made the plot read as small. */
#miss-timeline { min-width: 0; }

/* Shortlist. A button per patient, because the row opens the patient detail —
   this is the working list an officer rings through, not a report. */
.miss-list { margin-top: 16px; border-top: 1px solid var(--glass-border); padding-top: 14px; }
.miss-list-head {
  display: flex; justify-content: space-between; gap: 12px;
  font-size: 11px; font-weight: 650; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 9px;
}
.miss-row {
  display: grid; grid-template-columns: 4px minmax(0, 1fr) auto;
  align-items: center; gap: 12px; width: 100%;
  padding: 9px 11px; margin-bottom: 5px;
  background: rgba(148, 163, 184, 0.055);
  border: 1px solid var(--glass-border); border-radius: 10px;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
  transition: border-color 200ms var(--ease), background 200ms var(--ease), transform 200ms var(--ease);
}
.miss-row:hover {
  border-color: var(--glass-border-strong);
  background: rgba(148, 163, 184, 0.1);
  transform: translateX(2px);
}
.miss-row-band { width: 4px; height: 30px; border-radius: var(--radius-pill); }
.miss-row-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.miss-row-name {
  font-size: 12.5px; font-weight: 620;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.miss-row-meta {
  font-size: 11px; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.miss-row-days {
  display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
  font-size: 11px; color: var(--text-secondary); white-space: nowrap;
}
.miss-row-days b { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.miss-row-days small { font-size: 10.5px; color: var(--text-muted); }

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

/* ---------------------------------------------------------------------------
 * 11. Cascade waterfall
 * ------------------------------------------------------------------------ */

.cascade-wrap { display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 18px; }

.cascade-bars { display: flex; flex-direction: column; gap: 11px; }

.cbar {
  position: relative;
  padding: 13px 15px;
  background: rgba(9, 14, 26, 0.5);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.cbar:hover { border-color: var(--glass-border-strong); transform: translateX(3px); }
.cbar.is-selected { border-color: var(--accent); background: rgba(148, 163, 184, 0.07); }
.cbar[data-accent='slate']   { --accent: var(--slate); }
.cbar[data-accent='violet']  { --accent: var(--violet); }
.cbar[data-accent='cyan']    { --accent: var(--cyan); }
.cbar[data-accent='amber']   { --accent: var(--amber); }
.cbar[data-accent='emerald'] { --accent: var(--emerald); }

.cbar-head { display: flex; align-items: center; gap: 11px; margin-bottom: 9px; }
.cbar-idx {
  width: 26px; height: 26px; flex: none;
  display: grid; place-items: center;
  font-size: 11.5px; font-weight: 720;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 38%, transparent);
  border-radius: 8px;
}
.cbar-name { font-size: 13.2px; font-weight: 640; flex: 1 1 auto; min-width: 0; }
.cbar-count {
  font-size: 19px; font-weight: 720; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.cbar-count small { font-size: 11px; font-weight: 600; color: var(--text-muted); margin-left: 4px; }

.cbar-track {
  height: 10px;
  background: rgba(148, 163, 184, 0.1);
  border-radius: var(--radius-pill);
  overflow: hidden;
  position: relative;
}
.cbar-fill {
  height: 100%;
  width: 0;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 62%, transparent), var(--accent));
  transition: width 900ms var(--ease);
  position: relative;
}
.cbar-target {
  position: absolute; top: -3px; bottom: -3px; width: 2px;
  background: rgba(255, 255, 255, 0.55);
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.4);
  border-radius: 2px;
  transition: left 900ms var(--ease);
}
.cbar-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 7px; font-size: 11.4px; color: var(--text-muted); flex-wrap: wrap; }
.cbar-ratio { font-weight: 700; font-size: 12.6px; color: var(--accent); font-variant-numeric: tabular-nums; }

/* Funnel drop annotations between bars */
.cbar-drop {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 11.2px; color: var(--text-muted);
  padding: 1px 0;
}
.cbar-drop i { font-size: 9.5px; color: var(--rose); }

/* Funnel summary panel */
.funnel-panel { display: flex; flex-direction: column; gap: 13px; }
.retention-gauge { display: grid; place-items: center; padding: 6px 0 2px; }
.gauge-caption { text-align: center; margin-top: 8px; }
.gauge-caption .gc-value { font-size: 22px; font-weight: 720; letter-spacing: -0.02em; }
.gauge-caption .gc-label { font-size: 11.4px; color: var(--text-muted); }

.division-list { display: flex; flex-direction: column; gap: 8px; }
.division {
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 12px;
  background: rgba(148, 163, 184, 0.06);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
}
.division-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
/* Denominator + rating badge share the second line, so all three rows keep the
   same two-line rhythm instead of wrapping unpredictably. */
.division-row-sub { gap: 8px; }
.division-label {
  display: inline-flex; align-items: center; gap: 7px;
  min-width: 0;
  font-size: 12px; font-weight: 620; color: var(--text-secondary);
}
.division-label i { font-size: 11px; color: var(--text-muted); flex: none; }
.division-base {
  font-size: 10.4px; font-weight: 500; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.division-value {
  flex: none;
  font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.division-row-sub .badge { flex: none; }

/* Gender donut — flat neon ring with one slice detached.
   The legend runs horizontally so it stays one row: the card body is only
   ~294px tall and a stacked legend would push the ring out of it. */
.donut-legend {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 8px;
  margin-top: 12px;
}
.donut-legend-item {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: 12px;
  white-space: nowrap;
}
/* Marks the slice that is pulled out of the ring, so the eye can connect the
   detached arc back to its entry. */
.donut-legend-item.is-focus {
  background: rgba(148, 163, 184, 0.1);
  border-color: var(--glass-border);
}
.donut-dot {
  width: 10px; height: 10px; flex: none;
  border-radius: 50%;
}
.donut-name { color: var(--text-secondary); font-weight: 600; }
.donut-count {
  color: var(--text-primary); font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.donut-share {
  color: var(--text-muted); font-size: 11.4px;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------------
 * 11. Charts
 * ------------------------------------------------------------------------ */
.chart { width: 100%; display: block; overflow: visible; }
.chart-wrap { position: relative; width: 100%; }
.chart-empty {
  display: grid; place-items: center; gap: 8px;
  padding: 34px 16px;
  font-size: 12.5px; color: var(--text-muted);
  text-align: center;
}
.chart-empty i { font-size: 22px; opacity: 0.5; }

/* Legend */
.legend { display: flex; flex-wrap: wrap; gap: 8px 16px; margin-top: 12px; }
.legend-item { display: inline-flex; align-items: center; gap: 7px; font-size: 11.6px; color: var(--text-secondary); }
.legend-swatch { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.legend-value { font-weight: 680; color: var(--text-primary); font-variant-numeric: tabular-nums; }

/* Circular marker, to match the target point drawn on the chart */
.legend-dot {
  width: 10px; height: 10px; flex: none;
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgba(11, 16, 32, 0.9);
}

/* Cascade combo chart */
.combo-card { margin-bottom: 18px; }
.combo-card .card-body { padding-bottom: 12px; }
.legend-blocks {
  justify-content: center;
  gap: 10px 22px;
  padding-top: 14px;
  border-top: 1px dashed var(--glass-border);
}
.legend-blocks .legend-item { font-size: 12px; }

/* Separator inside a header chip that carries two figures */
.chip-sep { color: var(--text-muted); opacity: 0.6; }

/* SVG text must not be selectable — it is part of the graphic */
#chart-cascade-combo text { user-select: none; }
/* The SVG scales to fill its container (as every chart in this app does), but
   this one is full-width and label-dense, so its scale factor is capped: past
   ~1.4x the on-chart labels start to look oversized and the card grows tall
   enough to push the rest of the dashboard off screen. */
#chart-cascade-combo { max-width: 1080px; margin: 0 auto; }

/* Row-by-row readout for the care-continuum stacked bar. The bar carries values
   in tooltips only, which print does not show, so the same rows are listed here
   with their share of the total. */
.cont-list {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
  gap: 6px 16px; margin-top: 14px;
}
.cont-item { display: flex; align-items: center; gap: 7px; font-size: 11.8px; }
.cont-dot {
  width: 9px; height: 9px; border-radius: 3px; flex: 0 0 auto;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.06);
}
.cont-label { color: var(--text-secondary); flex: 1 1 auto; min-width: 0; }
.cont-value {
  font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.cont-value small { color: var(--text-muted); font-weight: 500; margin-left: 5px; }

/* Footnote for the combo chart: the small groups that are NOT stacked on
   Step 3. They sit in the card head, one per line, so the reader can see why
   the stack stops short of Step 2 without those groups being drawn as
   unreadable 2–5px slivers. Colour is carried by a dot rather than by the text,
   so both lines stay legible against the card and the two stay tellable apart. */
.combo-note {
  display: flex; flex-direction: column; gap: 6px;
  flex: 0 0 auto; text-align: right;
  font-size: 11.5px; line-height: 1.35;
}
.combo-note:empty { display: none; }
.combo-note .combo-note-item { display: flex; align-items: center; gap: 7px; justify-content: flex-end; }
.combo-note .combo-note-label { color: var(--text-secondary); }
.combo-note .combo-note-value {
  font-weight: 700; font-variant-numeric: tabular-nums;
  min-width: 22px; text-align: right;
}
.combo-note .combo-note-dot {
  width: 8px; height: 8px; border-radius: 50%;
  flex: 0 0 auto; box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.07);
}
#chart-cascade-combo .chart { width: 100%; display: block; }

/* Ranked horizontal bar list */
.ranklist { display: flex; flex-direction: column; gap: 9px; }
.rank-item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px; }
.rank-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; grid-column: 1 / -1; }
.rank-label {
  font-size: 12.2px; color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rank-value { font-size: 12.2px; font-weight: 680; font-variant-numeric: tabular-nums; white-space: nowrap; }
.rank-value small { color: var(--text-muted); font-weight: 560; margin-left: 5px; }
.rank-track { grid-column: 1 / -1; height: 6px; background: rgba(148, 163, 184, 0.1); border-radius: var(--radius-pill); overflow: hidden; }
.rank-fill { height: 100%; border-radius: var(--radius-pill); transition: width 800ms var(--ease); }

/* Tooltip */
.chart-tooltip {
  position: fixed;
  z-index: 200;
  padding: 8px 11px;
  font-size: 12px;
  background: rgba(9, 14, 26, 0.96);
  border: 1px solid var(--glass-border-strong);
  border-radius: 9px;
  box-shadow: var(--shadow-lg);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -110%);
  transition: opacity 120ms;
  max-width: 260px;
}
.chart-tooltip.is-visible { opacity: 1; }
.chart-tooltip .tt-title { font-weight: 660; margin-bottom: 3px; }
.chart-tooltip .tt-row { display: flex; align-items: center; justify-content: space-between; gap: 14px; color: var(--text-secondary); }
.chart-tooltip .tt-row b { color: var(--text-primary); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
 * 12. Tables
 * ------------------------------------------------------------------------ */
.table-wrap { overflow: auto; border-radius: var(--radius); border: 1px solid var(--glass-border); }
table.data-table { width: 100%; border-collapse: collapse; font-size: 12.4px; }
table.data-table thead th {
  position: sticky; top: 0; z-index: 2;
  padding: 10px 12px;
  text-align: left;
  font-size: 10.8px; font-weight: 660; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-muted);
  background: #101728;
  border-bottom: 1px solid var(--glass-border);
  white-space: nowrap;
  user-select: none;
}
table.data-table thead th.sortable { cursor: pointer; }
table.data-table thead th.sortable:hover { color: var(--text-secondary); }
table.data-table thead th .sort-icon { margin-left: 5px; opacity: 0.45; font-size: 9px; }
table.data-table thead th.is-sorted .sort-icon { opacity: 1; color: var(--cyan); }
table.data-table tbody tr { border-bottom: 1px solid rgba(148, 163, 184, 0.08); transition: background 140ms; }
table.data-table tbody tr:hover { background: rgba(148, 163, 184, 0.07); }
table.data-table tbody tr.is-clickable { cursor: pointer; }
table.data-table tbody tr.is-ltfu td:first-child { box-shadow: inset 3px 0 0 var(--rose); }
table.data-table tbody tr.is-excluded { opacity: 0.62; }
table.data-table td { padding: 9px 12px; vertical-align: middle; }
table.data-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.table-scroll-y { max-height: 520px; }

.pager {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 4px 0; font-size: 12px; color: var(--text-muted); flex-wrap: wrap;
}
.pager-btns { display: flex; gap: 6px; align-items: center; }

.filter-bar { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.filter-bar .field { min-width: 138px; }
.filter-bar .field.grow { flex: 1 1 200px; min-width: 180px; }

/* ---------------------------------------------------------------------------
 * 13. Audit / quality list
 * ------------------------------------------------------------------------ */
.qlist { display: flex; flex-direction: column; gap: 9px; }
.qitem {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 13px;
  background: rgba(148, 163, 184, 0.05);
  border: 1px solid var(--glass-border);
  border-left: 3px solid var(--tone, var(--slate));
  border-radius: 10px;
}
.qitem[data-tone='ok']      { --tone: var(--emerald); }
.qitem[data-tone='info']    { --tone: var(--cyan); }
.qitem[data-tone='warning'] { --tone: var(--amber); }
.qitem[data-tone='danger']  { --tone: var(--rose); }
.qitem-body { flex: 1 1 auto; min-width: 0; }
.qitem-label { font-size: 12.4px; font-weight: 620; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.qitem-detail { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.qitem-value { font-size: 15px; font-weight: 720; font-variant-numeric: tabular-nums; color: var(--tone); }

/* ---------------------------------------------------------------------------
 * 14. Modal / drawer
 * ------------------------------------------------------------------------ */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(4, 7, 15, 0.78);
  backdrop-filter: blur(6px);
  display: grid; place-items: center;
  padding: 22px;
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur), visibility var(--dur);
}
.modal-backdrop.is-open { opacity: 1; visibility: visible; }
.modal {
  width: 100%; max-width: 820px; max-height: 88vh;
  display: flex; flex-direction: column;
  background: linear-gradient(180deg, rgba(20, 27, 45, 0.98), rgba(11, 16, 29, 0.98));
  border: 1px solid var(--glass-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  transform: translateY(14px) scale(0.985);
  transition: transform var(--dur) var(--ease);
}
.modal-backdrop.is-open .modal { transform: none; }
.modal-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 19px 22px 15px;
  border-bottom: 1px solid var(--glass-border);
}
.modal-title { font-size: 16px; font-weight: 680; }
.modal-sub { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.modal-body { padding: 18px 22px 22px; overflow-y: auto; }
.modal-foot {
  padding: 14px 22px; border-top: 1px solid var(--glass-border);
  display: flex; justify-content: flex-end; gap: 9px;
}

.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); gap: 11px; }
.detail-item {
  padding: 10px 12px;
  background: rgba(148, 163, 184, 0.06);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
}
.detail-key { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); }
.detail-val { font-size: 13.2px; font-weight: 600; margin-top: 2px; word-break: break-word; }

.detail-section-title {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-muted); font-weight: 660;
  margin: 19px 0 9px;
}
.timeline { display: flex; flex-direction: column; gap: 2px; }
.tl-item { display: grid; grid-template-columns: 15px minmax(0, 1fr); gap: 11px; }
.tl-rail { display: flex; flex-direction: column; align-items: center; }
.tl-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--tone, var(--slate)); margin-top: 5px; flex: none; }
.tl-line { flex: 1 1 auto; width: 1.5px; background: var(--glass-border); margin: 3px 0 -2px; }
.tl-item:last-child .tl-line { display: none; }
.tl-body { padding-bottom: 11px; }
.tl-title { font-size: 12.4px; font-weight: 600; }
.tl-meta { font-size: 11.3px; color: var(--text-muted); }

/* ---------------------------------------------------------------------------
 * 15. Empty state / banners
 * ------------------------------------------------------------------------ */
.empty-state {
  display: grid; place-items: center; gap: 13px;
  padding: 74px 26px;
  text-align: center;
  border: 1.5px dashed var(--glass-border-strong);
  border-radius: var(--radius-lg);
  background: rgba(13, 19, 34, 0.42);
}
.empty-icon {
  width: 68px; height: 68px;
  display: grid; place-items: center;
  font-size: 26px; color: var(--violet);
  background: var(--violet-soft);
  border: 1px solid rgba(139, 92, 246, 0.3);
  border-radius: 20px;
}
.empty-title { font-size: 17px; font-weight: 660; }
.empty-text { font-size: 13px; color: var(--text-muted); max-width: 470px; }
.empty-actions { display: flex; gap: 9px; flex-wrap: wrap; justify-content: center; }

.banner {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 11px 14px;
  border-radius: 11px;
  font-size: 12.4px;
  border: 1px solid;
}
.banner i { margin-top: 2px; }
.banner-info { color: #a5f3fc; background: var(--cyan-soft); border-color: rgba(34, 211, 238, 0.3); }
.banner-warn { color: #fcd34d; background: var(--amber-soft); border-color: rgba(245, 158, 11, 0.3); }
.banner-error { color: #fda4af; background: var(--rose-soft); border-color: rgba(244, 63, 94, 0.3); }
.banner-success { color: #6ee7b7; background: var(--emerald-soft); border-color: rgba(16, 185, 129, 0.3); }
.banner-body { flex: 1 1 auto; min-width: 0; }
.banner-title { font-weight: 640; }
.banner-list { margin: 5px 0 0; padding-left: 17px; }

/* Inside a modal body a banner sits between element blocks that carry no bottom
 * margin, so its top edge used to butt straight against the grid above it
 * (measured 0px between .detail-grid and the referral banner). The inline
 * margin-bottom on those banners is intentional; this supplies the missing top
 * half. Scoped to .modal-body so the ingest banners keep their own spacing. */
.modal-body .banner { margin-top: 16px; }
.modal-body .banner:first-child { margin-top: 0; }

/* ---------------------------------------------------------------------------
 * 16. Progress / loading
 * ------------------------------------------------------------------------ */
.progress-overlay {
  position: fixed; inset: 0; z-index: 400;
  display: grid; place-items: center;
  background: rgba(4, 7, 15, 0.82);
  backdrop-filter: blur(7px);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur), visibility var(--dur);
}
.progress-overlay.is-open { opacity: 1; visibility: visible; }
.progress-box {
  display: flex; flex-direction: column; align-items: center; gap: 15px;
  padding: 32px 38px;
  background: rgba(20, 27, 45, 0.96);
  border: 1px solid var(--glass-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  min-width: 310px;
}
.spinner {
  width: 40px; height: 40px;
  border: 3px solid rgba(148, 163, 184, 0.22);
  border-top-color: var(--cyan);
  border-radius: 50%;
  animation: spin 800ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.progress-text { font-size: 13.5px; font-weight: 600; }
.progress-sub { font-size: 11.8px; color: var(--text-muted); text-align: center; max-width: 280px; }
.progress-bar-track { width: 100%; height: 5px; background: rgba(148, 163, 184, 0.14); border-radius: var(--radius-pill); overflow: hidden; }
.progress-bar-fill { height: 100%; width: 0; background: linear-gradient(90deg, var(--violet), var(--cyan)); transition: width 260ms var(--ease); }

/* Toast */
.toast-stack { position: fixed; right: 20px; bottom: 20px; z-index: 500; display: flex; flex-direction: column; gap: 9px; }
.toast {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 15px;
  min-width: 268px; max-width: 400px;
  background: rgba(20, 27, 45, 0.97);
  border: 1px solid var(--glass-border-strong);
  border-left: 3px solid var(--tone, var(--cyan));
  border-radius: 11px;
  box-shadow: var(--shadow-lg);
  font-size: 12.6px;
  animation: toast-in 260ms var(--ease);
}
.toast[data-tone='success'] { --tone: var(--emerald); }
.toast[data-tone='warning'] { --tone: var(--amber); }
.toast[data-tone='error']   { --tone: var(--rose); }
.toast[data-tone='info']    { --tone: var(--cyan); }
.toast-title { font-weight: 640; }
.toast-text { color: var(--text-secondary); font-size: 11.8px; margin-top: 1px; }
@keyframes toast-in { from { opacity: 0; transform: translateX(26px); } to { opacity: 1; transform: none; } }

/* ---------------------------------------------------------------------------
 * 17. Responsive
 * ------------------------------------------------------------------------ */
@media (max-width: 1280px) {
  .cascade-wrap { grid-template-columns: minmax(0, 1fr); }
  .bento-5 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Square cards get cramped before the other grids do, so they drop a column
     earlier. Columns are stepped 4 -> 3 -> 2 rather than straight to 2, to keep
     each card in the ~280-400px band where a square KPI reads best; letting them
     grow past ~420px leaves a square with a lot of empty middle. */
  .kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .kpi { padding: 17px; }
  .kpi-value { font-size: 40px; }
}
@media (max-width: 1080px) {
  .bento-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bento-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .span-4, .span-3 { grid-column: span 2; }
}
@media (max-width: 820px) {
  .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpi-value { font-size: 34px; }
}
@media (max-width: 820px) {
  .container { padding: 0 16px; }
  .bento-2, .bento-3, .bento-4, .bento-5 { grid-template-columns: minmax(0, 1fr); }
  .span-2, .span-3, .span-4 { grid-column: span 1; }
  .brand-sub { display: none; }
  .app-main { padding-top: 18px; }
  .card-pad, .card-body { padding-left: 16px; padding-right: 16px; }
  .header-actions .btn-label { display: none; }
}
@media (max-width: 560px) {
  .kpi-value { font-size: 23px; }
  /* Slightly tighter tabs so at least two still share a row on a small phone
     instead of each taking a full line. */
  .tab { padding: 10px 9px; font-size: 12.5px; gap: 6px; }
  .tab i { font-size: 12px; }
  .tab-badge { margin-left: auto; }
}

/* ---------------------------------------------------------------------------
 * 17b. Touch refinement (tablet + phone)
 *
 * Measured before this block, at 820px and below:
 *   - every button was 26-29px tall, against the 44px Apple HIG / 48dp Material
 *     minimum, and the per-file clear control was 18x18px;
 *   - the tab strip needed ~650px inside a 361px bar, so three of five tabs were
 *     cut off and the bar had to be scrolled sideways;
 *   - the filter bar's seven controls wrapped into six ragged rows.
 * ------------------------------------------------------------------------ */
@media (max-width: 820px) {
  /* Bigger hit areas. Apple HIG asks 44pt, Material 48dp; 40 is the floor we
     hold for secondary controls so dense toolbars do not overflow. */
  .btn { min-height: 44px; }
  .btn-sm { min-height: 40px; }
  .btn-icon { width: 44px; height: 44px; }
  .tab { min-height: 44px; }
  .chip { min-height: 34px; }
  /* Was 18x18 — unhittable with a thumb. */
  .uc-file-x { min-width: 40px; min-height: 40px; padding: 0 12px; font-size: 14px; }
  .uc-file { min-height: 44px; }
  /* The KPI card is only ~173px wide on a phone, so a 36-44px square here would
     collide with the label above or the value below. Grow the HIT AREA instead
     of the box: the visual stays 32px and the layout does not move. */
  .kpi-dl::after { content: ''; position: absolute; inset: -6px; }
  /* Let the strip wrap the moment the tabs stop fitting, rather than at a
     hand-picked breakpoint. A fixed breakpoint left a 560-700px gap where one
     tab was still clipped and the bar had to be scrolled. With wrapping the
     browser decides: one row while it fits, more rows when it does not. */
  .tabbar { flex-wrap: wrap; overflow-x: visible; }
  .tab { flex: 1 1 auto; }
}

@media (max-width: 560px) {
  /* Seven controls in a wrapped flex row produced six ragged rows of unequal
     width. Two columns with the search box and the export button spanning both
     gives four tidy rows and no narrow orphan fields. */
  .filter-bar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .filter-bar .field,
  .filter-bar .field.grow { min-width: 0; }
  .filter-bar > .field.grow,
  .filter-bar > .btn { grid-column: 1 / -1; }
  .btn-set { width: 100%; }
  .btn-set .btn { flex: 1 1 auto; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ---------------------------------------------------------------------------
 * 18. Print / report
 * ------------------------------------------------------------------------ */
@media print {
  @page { size: A4 landscape; margin: 12mm; }
  body {
    background: #fff !important; color: #111 !important;
    background-image: none !important; font-size: 10.5pt;
  }
  .app-header, .header-actions, .no-print, .toast-stack, .progress-overlay,
  .upload-grid, .dropzone-grid, #section-ingest, .modal-backdrop, .pager, .filter-bar { display: none !important; }
  /* Every tab panel prints, regardless of which one is on screen */
  .tabbar { display: none !important; }
  .tabpanel, .tabpanel[hidden] { display: block !important; }
  .container { max-width: none; padding: 0; }
  .card, .kpi {
    background: #fff !important; border: 1px solid #cbd5e1 !important;
    box-shadow: none !important; backdrop-filter: none !important;
    break-inside: avoid;
  }
  .card-title, .kpi-value, .cbar-count, .section-title { color: #0f172a !important; }
  .kpi-label, .card-subtitle, .section-desc, .dz-hint { color: #475569 !important; }
  .text-muted, .qitem-detail, .rank-label { color: #475569 !important; }
  .cbar { background: #f8fafc !important; border-color: #cbd5e1 !important; }
  .cbar-name, .detail-val, .rank-value { color: #0f172a !important; }
  table.data-table thead th { background: #e2e8f0 !important; color: #0f172a !important; }
  table.data-table td, table.data-table tbody tr { color: #0f172a !important; }
  .table-wrap, .table-scroll-y { max-height: none !important; overflow: visible !important; border-color: #cbd5e1 !important; }
  .badge { border-color: #94a3b8 !important; }
  .section { break-inside: avoid-page; }
}
