/* ════════════════════════════════════════════════════════════════════
   AIREP — base.css · v0.1
   Design system for an Intelli AI / AIREP Django ERP, with Nova chat.
   Drop into a Django app as static/css/airep.css and load in base.html.
   ════════════════════════════════════════════════════════════════════ */

/* ─── 01 · DESIGN TOKENS ─────────────────────────────────────────── */
:root {
  /* Brand */
  --color-ink:        #0d1220;
  --color-ink-soft:   rgba(13,18,32,0.72);
  --color-muted:      rgba(13,18,32,0.55);
  --color-paper:      #f0eee9;
  --color-paper-2:    #fdfcf9;
  --color-surface:    #ffffff;
  --color-rule:       rgba(13,18,32,0.10);
  --color-rule-strong:rgba(13,18,32,0.22);

  --color-accent:     #4da6ff;        /* primary blue — Nova */
  --color-accent-ink: #0d1220;
  --color-accent-soft:rgba(77,166,255,0.12);

  /* Semantic */
  --color-good:       #1f8a5b;
  --color-good-soft:  rgba(31,138,91,0.10);
  --color-warn:       #c5601a;
  --color-warn-soft:  rgba(197,96,26,0.10);
  --color-danger:     #c1573e;
  --color-danger-soft:rgba(193,87,62,0.10);
  --color-info:       #2e5e8c;
  --color-info-soft:  rgba(46,94,140,0.10);

  /* Typography */
  --font-display:     'Inter Tight', Inter, system-ui, sans-serif;
  --font-body:        'Inter', system-ui, sans-serif;
  --font-mono:        'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;

  --fs-eyebrow: 10px;   --ls-eyebrow: 0.16em;
  --fs-body-sm: 12.5px;
  --fs-body:    14px;
  --fs-body-lg: 16px;
  --fs-h6:      15px;
  --fs-h5:      17px;
  --fs-h4:      20px;
  --fs-h3:      24px;
  --fs-h2:      32px;
  --fs-h1:      42px;
  --fs-hero:    56px;

  /* Spacing — 4px base */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px;
  --space-4: 16px; --space-5: 20px; --space-6: 24px;
  --space-7: 32px; --space-8: 40px; --space-9: 56px; --space-10: 72px;

  /* Radii */
  --radius-xs: 4px; --radius-sm: 6px; --radius-md: 10px;
  --radius-lg: 14px; --radius-xl: 20px; --radius-pill: 999px;

  /* Shadows */
  --shadow-card:   0 1px 2px rgba(13,18,32,0.06);
  --shadow-pop:    0 8px 24px rgba(13,18,32,0.10), 0 2px 6px rgba(13,18,32,0.05);
  --shadow-modal:  0 24px 80px rgba(13,18,32,0.30), 0 4px 16px rgba(13,18,32,0.15);

  /* Layout */
  --rail-w: 220px; --rail-narrow-w: 64px;
  --topbar-h: 56px;
  --content-max: 1280px;
  --focus-ring: 0 0 0 3px var(--color-accent-soft);
}

html[data-theme='dark'] {
  --color-ink:        #f4f1ea;
  --color-ink-soft:   rgba(244,241,234,0.72);
  --color-muted:      rgba(244,241,234,0.50);
  --color-paper:      #0c0b0e;
  --color-paper-2:    #0a0a0e;
  --color-surface:    #16141a;
  --color-rule:       rgba(244,241,234,0.10);
  --color-rule-strong:rgba(244,241,234,0.22);
  --color-accent-ink: #0c0b0e;
  --color-accent-soft:rgba(77,166,255,0.18);
  --color-good:       #7cf5c9;
  --color-good-soft:  rgba(124,245,201,0.14);
  --color-warn:       #ffd93d;
  --color-warn-soft:  rgba(255,217,61,0.14);
  --color-danger:     #ff8a5b;
  --color-danger-soft:rgba(255,138,91,0.16);
  --shadow-card:      0 1px 2px rgba(0,0,0,0.40);
  --shadow-pop:       0 12px 30px rgba(0,0,0,0.55);
  --shadow-modal:     0 24px 80px rgba(0,0,0,0.65);
}

/* ─── 02 · RESET + BASE ──────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
  text-wrap: pretty;
}
h1 { font-size: var(--fs-h1); letter-spacing: -0.03em; line-height: 1.05; }
h2 { font-size: var(--fs-h2); letter-spacing: -0.025em; line-height: 1.1; }
h3 { font-size: var(--fs-h3); letter-spacing: -0.02em; line-height: 1.15; }
h4 { font-size: var(--fs-h4); line-height: 1.2; }
h5 { font-size: var(--fs-h5); line-height: 1.25; }
h6 { font-size: var(--fs-h6); line-height: 1.3; }
p { margin: 0 0 var(--space-3); }
a { color: var(--color-ink); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--color-rule-strong); }
code, pre, .mono { font-family: var(--font-mono); }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* ─── 03 · BUTTONS ───────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 16px;
  border: 1px solid transparent; border-radius: var(--radius-md);
  background: var(--color-surface); color: var(--color-ink);
  font-family: var(--font-body); font-size: 13.5px; font-weight: 600; letter-spacing: -0.1px;
  cursor: pointer; text-decoration: none; line-height: 1.2;
  transition: background 120ms ease, border-color 120ms ease, transform 80ms ease;
}
.btn:hover { background: var(--color-rule); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.btn .icon { font-family: var(--font-mono); font-size: 14px; line-height: 1; }

.btn-primary  { background: var(--color-accent); color: var(--color-accent-ink); border-color: var(--color-accent); font-weight: 700; }
.btn-primary:hover  { filter: brightness(0.95); background: var(--color-accent); }
.btn-secondary{ background: var(--color-surface); color: var(--color-ink); border-color: var(--color-rule-strong); }
.btn-ghost    { background: transparent; border-color: transparent; color: var(--color-ink-soft); }
.btn-ghost:hover { background: var(--color-rule); color: var(--color-ink); }
.btn-danger   { background: var(--color-danger); color: #fff; border-color: var(--color-danger); font-weight: 700; }
.btn-danger:hover { filter: brightness(0.95); }
.btn-link     { background: transparent; padding: 0; border: none; color: var(--color-ink);
                text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--color-accent); }

/* .btn-xs: extra-small button used on date-range pickers in production schedules.
   Bootstrap 5 dropped the v3 .btn-xs; we keep it as a kit size variant so AIREP
   templates can write `class="btn btn-xs"` without inline padding/font-size shims. */
.btn-xs { padding: 2px 8px; font-size: 0.75rem; }

.btn-sm { padding: 6px 11px; font-size: 12px; border-radius: var(--radius-sm); }
.btn-lg { padding: 13px 22px; font-size: 15px; border-radius: var(--radius-md); }
.btn[disabled], .btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* ─── 03B · MOTION SAFETY ────────────────────────────────────────── */
/* Honour the OS-level "reduce motion" preference. Strips the .btn hover
   transition + active-press translate so users who set the system flag don't
   get incidental motion from kit chrome. Phase 3 Nova burst/ray/shimmer
   animations should wrap themselves in this same media query so the scaffold
   extends cleanly without re-deciding the policy. */
@media (prefers-reduced-motion: reduce) {
  .btn        { transition: none; }
  .btn:active { transform: none; }
}

/* ─── 04 · FORMS ─────────────────────────────────────────────────── */
.field        { display: flex; flex-direction: column; gap: 6px; }
.field-label  { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1.6px; font-weight: 700;
                color: var(--color-muted); text-transform: uppercase; }
.field-hint   { font-size: 11.5px; color: var(--color-muted); }
.field-error  { font-size: 11.5px; color: var(--color-danger); }

.input, .select, .textarea {
  width: 100%;
  padding: 10px 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-rule-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-body); font-size: 14px; color: var(--color-ink);
  line-height: 1.4;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--color-accent);
}
.input:focus-visible, .select:focus-visible, .textarea:focus-visible {
  outline: none; box-shadow: var(--focus-ring);
}
.input[readonly], .input:disabled { background: var(--color-paper-2); color: var(--color-muted); }
.textarea { resize: vertical; min-height: 96px; }
/* .input--mono: monospace numeric inputs only. There is intentionally no
   .select--mono or .textarea--mono — mono selects/textareas read as odd UX.
   For non-input mono content (JS-injected <td>s, code, IDs in tables) use
   the scoped .mono rule inside .table (§08) or the global .mono / code / pre
   rule (§02). */
.input--mono { font-family: var(--font-mono); font-size: 13px; }

.field-row { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.checkbox, .radio { width: 16px; height: 16px; accent-color: var(--color-accent); }

/* ─── 05 · PILLS / BADGES ────────────────────────────────────────── */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 9px 3px 8px; border-radius: var(--radius-pill);
  background: var(--color-rule); color: var(--color-ink);
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.4px; line-height: 1.4;
}
.pill .dot { width: 6px; height: 6px; border-radius: 3px; background: currentColor; }
.pill-good   { background: var(--color-good-soft);   color: var(--color-good); }
.pill-warn   { background: var(--color-warn-soft);   color: var(--color-warn); }
.pill-danger { background: var(--color-danger-soft); color: var(--color-danger); }
.pill-info   { background: var(--color-info-soft);   color: var(--color-info); }
.pill-accent { background: var(--color-accent-soft); color: var(--color-ink); }

/* ─── 06 · CARDS ─────────────────────────────────────────────────── */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}
.card-pop { box-shadow: var(--shadow-card); }
.card-hd  { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: var(--space-3); }
.card-hd h3 { margin: 0; }

/* ─── 06B · DIALOG ───────────────────────────────────────────────── */
/* Native <dialog> primitive — paired with Phase 5's Bootstrap-modal
   replacement (HTMX/Alpine). Use the semantic <dialog> element plus the
   .dialog-hd / .dialog-body / .dialog-ft triplet that mirrors .card-hd above
   so confirm modals don't need bespoke chrome per consumer. */
.dialog {
  padding: var(--space-6);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg);
  background: var(--color-surface); color: var(--color-ink);
  box-shadow: var(--shadow-modal);
  max-width: 540px;
}
.dialog::backdrop { background: rgba(13,18,32,0.45); }
.dialog-hd   { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: var(--space-3); }
.dialog-hd h3 { margin: 0; }
.dialog-body { font-size: 14px; line-height: 1.55; }
.dialog-ft   { display: flex; justify-content: flex-end; gap: 10px; margin-top: var(--space-5); }

/* ─── 07 · ALERTS ────────────────────────────────────────────────── */
.alert {
  display: flex; gap: 12px; padding: 12px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-rule);
  background: var(--color-paper-2);
  font-size: 13.5px; line-height: 1.5;
}
.alert .icon  { font-family: var(--font-mono); font-weight: 700; flex: none; }
.alert-info   { border-color: rgba(46,94,140,0.30);  background: var(--color-info-soft);   }
.alert-good   { border-color: rgba(31,138,91,0.30);  background: var(--color-good-soft);   }
.alert-warn   { border-color: rgba(197,96,26,0.30);  background: var(--color-warn-soft);   }
.alert-danger { border-color: rgba(193,87,62,0.30);  background: var(--color-danger-soft); }
.alert-accent { border-color: rgba(77,166,255,0.40); background: var(--color-accent-soft); }

/* ─── 07B · TOASTS ───────────────────────────────────────────────── */
/* Transient notification primitive. Position via .toast-container (fixed
   bottom-right by default); each .toast renders as a card-shaped tile with
   one of the .alert-* tone counterparts. Container is pointer-events:none so
   the toast strip doesn't shadow underlying page chrome; each .toast
   re-enables pointer-events so dismiss / Undo controls stay clickable. */
.toast-container {
  position: fixed; right: var(--space-5); bottom: var(--space-5);
  display: flex; flex-direction: column; gap: var(--space-2);
  z-index: 1080; pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; gap: 12px; padding: 12px 14px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-rule);
  background: var(--color-surface);
  box-shadow: var(--shadow-pop);
  font-size: 13.5px; line-height: 1.5;
  max-width: 360px;
}
.toast .icon  { font-family: var(--font-mono); font-weight: 700; flex: none; }
.toast-good   { border-color: rgba(31,138,91,0.30);  background: var(--color-good-soft);   }
.toast-warn   { border-color: rgba(197,96,26,0.30);  background: var(--color-warn-soft);   }
.toast-danger { border-color: rgba(193,87,62,0.30);  background: var(--color-danger-soft); }
.toast-info   { border-color: rgba(46,94,140,0.30);  background: var(--color-info-soft);   }
.toast-accent { border-color: rgba(77,166,255,0.40); background: var(--color-accent-soft); }

/* ─── 08 · TABLES ────────────────────────────────────────────────── */
.table { width: 100%; border-collapse: collapse; font-size: 13px; background: var(--color-surface); }
.table thead th {
  text-align: left; padding: 10px 14px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 1.4px; font-weight: 700;
  color: var(--color-muted); text-transform: uppercase;
  border-bottom: 1px solid var(--color-rule);
  background: var(--color-paper-2);
  position: sticky; top: 0;
}
.table tbody td { padding: 11px 14px; border-bottom: 1px dashed var(--color-rule); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--color-paper-2); }
.table .num    { text-align: right; font-family: var(--font-mono); font-weight: 700; }
.table .mono   { font-family: var(--font-mono); }
.table .strong { font-weight: 600; }

/* ─── 09 · PAGE CHROME ───────────────────────────────────────────── */
.page-header  { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; margin-bottom: var(--space-7); }
.crumbs       { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.6px; color: var(--color-muted); text-transform: uppercase; }
.crumbs a     { color: var(--color-muted); text-decoration: none; }
.crumbs a:hover { color: var(--color-ink); }
.page-title   { font-size: var(--fs-h1); margin-top: 6px; }
.page-actions { display: flex; gap: 10px; }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--color-rule); margin-bottom: var(--space-5); }
.tab {
  padding: 10px 14px; border: none; background: transparent;
  font-family: var(--font-body); font-size: 13.5px; font-weight: 600;
  color: var(--color-ink-soft); border-bottom: 2px solid transparent;
  cursor: pointer; margin-bottom: -1px;
}
.tab:hover { color: var(--color-ink); }
.tab.is-active { color: var(--color-ink); border-bottom-color: var(--color-accent); }
.tab:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
.tab .count {
  display: inline-block; margin-left: 6px; padding: 1px 7px;
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  background: var(--color-rule); border-radius: var(--radius-pill); color: var(--color-ink-soft);
}

/* ─── 09B · PAGINATION ───────────────────────────────────────────── */
/* Pagination strip — chip-shaped page links. Use on a <nav> wrapping a flex
   container of .page links (works on either <ul><li> or plain <a> markup
   thanks to the list-reset on .pagination). Mark the current page with
   .is-current (matches .chip-primary tone) and disabled controls (e.g.
   Prev/Next at the edges) with .is-disabled. */
.pagination {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  list-style: none; margin: 0; padding: 0;
}
.page {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: var(--radius-pill);
  background: var(--color-surface); border: 1px solid var(--color-rule);
  font-family: var(--font-body); font-size: 12px; font-weight: 600;
  color: var(--color-ink); text-decoration: none; cursor: pointer;
}
.page:hover         { background: var(--color-rule); }
.page:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.page.is-current    { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-ink); }
.page.is-disabled   { opacity: 0.45; cursor: not-allowed; pointer-events: none; }

/* ─── 10 · KPI ───────────────────────────────────────────────────── */
/* Two KPI patterns share this section, both prefixed `.kpi`:
   - `.kpi` / `.kpi-value` / `.kpi-delta.up|down` — summary strip (one number
     + trend delta). Used by the brief's §10 KPI row.
   - `.kpi-card` / `.kpi-icon` / `.kpi-actual` / `.kpi-progress` / `.kpi-flare`
     with `[data-tier]` accents — goal-tracking card (actual vs manager-set
     target, progressbar, 4 tiers, celebration animations). Used by
     templates/partials/dashboard/kpi.html. The card-family rules used to
     live in core/static/core/css/kpi.css; folded in here so the dashboard
     and the brief share one §10 namespace. */
.kpi              { padding: 16px; background: var(--color-surface); border: 1px solid var(--color-rule); border-radius: var(--radius-md); }
.kpi .kpi-label   { font-family: var(--font-mono); font-size: 10px; letter-spacing: 1.6px; font-weight: 700;
                    color: var(--color-muted); text-transform: uppercase; }
.kpi .kpi-value   { font-family: var(--font-display); font-size: 26px; font-weight: 700; letter-spacing: -0.5px; margin-top: 6px; line-height: 1; }
.kpi .kpi-delta   { font-family: var(--font-mono); font-size: 11px; font-weight: 700; margin-top: 4px; letter-spacing: 0.4px; }
.kpi .kpi-delta.up   { color: var(--color-good); }
.kpi .kpi-delta.down { color: var(--color-danger); }

/* ── Goal-tracking card variant ──────────────────────────────────────────── */
/* Chrome reads Bootstrap CSS vars so it tracks Bootstrap's theme switch; the
   tier accents stay legible in both light + dark without needing the kit's
   own [data-theme="dark"] token swap. */
.kpi-card {
  border: 1px solid var(--bs-border-color, rgba(255, 255, 255, 0.1));
  transition: border-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
}

.kpi-card .kpi-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 0.4rem;
  background: var(--bs-body-bg, transparent);
  font-size: 0.95rem;
  color: var(--bs-secondary-color, #6c757d);
}
/* Scoped label override — the card variant runs a slightly larger,
   wider-tracked label than the kit's `.kpi .kpi-label`; the two coexist
   because they're scoped under different parents. */
.kpi-card .kpi-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--bs-secondary-color, #6c757d);
  font-weight: 600;
}
.kpi-card .kpi-actual {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.1;
}
.kpi-card .kpi-progress {
  height: 6px;
  background: var(--bs-secondary-bg, rgba(255, 255, 255, 0.1));
}
.kpi-card .kpi-progress .progress-bar {
  transition: width 0.6s ease;
}
.kpi-card .kpi-copy {
  color: var(--bs-secondary-color, #6c757d);
  min-height: 2.4em; /* keep cards equal height even with short copy */
}

/* Tier accents — data-tier drives border, value colour, and progressbar fill. */
.kpi-card[data-tier="not_started"] {
  border-color: var(--bs-secondary-border-subtle, rgba(108, 117, 125, 0.4));
}
.kpi-card[data-tier="not_started"] .progress-bar { background-color: var(--bs-secondary, #6c757d); }

.kpi-card[data-tier="starting"] {
  border-color: var(--bs-warning-border-subtle, rgba(255, 193, 7, 0.5));
}
.kpi-card[data-tier="starting"] .kpi-actual { color: var(--bs-warning, #ffc107); }
.kpi-card[data-tier="starting"] .progress-bar { background-color: var(--bs-warning, #ffc107); }

.kpi-card[data-tier="on_track"] {
  border-color: var(--bs-primary-border-subtle, rgba(13, 110, 253, 0.5));
}
.kpi-card[data-tier="on_track"] .kpi-actual { color: var(--bs-primary, #0d6efd); }
.kpi-card[data-tier="on_track"] .progress-bar { background-color: var(--bs-primary, #0d6efd); }

.kpi-card[data-tier="smashing"] {
  border-color: var(--bs-success, #198754);
  border-width: 2px;
  animation: kpi-pulse 2.4s ease-in-out infinite;
}
.kpi-card[data-tier="smashing"] .kpi-actual { color: var(--bs-success, #198754); }
.kpi-card[data-tier="smashing"] .progress-bar {
  background: linear-gradient(90deg, var(--bs-success, #198754), #6cd49b, var(--bs-success, #198754));
  background-size: 200% 100%;
  animation: kpi-shimmer 2.5s linear infinite;
}
.kpi-card[data-tier="smashing"] .kpi-icon {
  background: rgba(25, 135, 84, 0.15);
  color: var(--bs-success, #198754);
}

/* The ✨ flare — floats up and fades in a loop. */
.kpi-card .kpi-flare {
  font-size: 1.2rem;
  display: inline-block;
  animation: kpi-flare 2.2s ease-in-out infinite;
  transform-origin: center;
}

@keyframes kpi-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(25, 135, 84, 0); }
  50%      { box-shadow: 0 0 0 10px rgba(25, 135, 84, 0.18); }
}

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

@keyframes kpi-flare {
  0%, 100% { transform: translateY(0) rotate(0deg) scale(1); opacity: 0.85; }
  25%      { transform: translateY(-3px) rotate(-12deg) scale(1.15); opacity: 1; }
  50%      { transform: translateY(-1px) rotate(8deg) scale(0.95); opacity: 0.7; }
  75%      { transform: translateY(-4px) rotate(-4deg) scale(1.1); opacity: 1; }
}

/* Stop celebratory animations when the user prefers reduced motion; tier
   still reads via colour alone, so the dashboard remains legible. */
@media (prefers-reduced-motion: reduce) {
  .kpi-card,
  .kpi-card .progress-bar,
  .kpi-card .kpi-flare {
    animation: none !important;
    transition: none !important;
  }
}

/* Empty-state card stays subdued so it doesn't compete with real KPI cards. */
.kpi-empty {
  background: var(--bs-body-bg, transparent);
  border-style: dashed;
}

/* ─── 11 · EMPTY STATE ───────────────────────────────────────────── */
.empty       { padding: 56px 32px; text-align: center; border: 1px dashed var(--color-rule-strong);
               border-radius: var(--radius-md); background: var(--color-paper-2); }
.empty .icon { font-size: 32px; font-family: var(--font-mono); color: var(--color-muted); margin-bottom: 10px; }
.empty h4    { margin: 0 0 6px; }
.empty p     { color: var(--color-ink-soft); margin: 0 auto 18px; max-width: 44ch; }

/* ─── 12 · NOVA — BUBBLES, COMPOSER, CHIPS ──────────────────────── */
.nova-msg               { display: flex; gap: 12px; }
.nova-msg .av           { width: 30px; height: 30px; border-radius: 999px; flex: none;
                          background: var(--color-accent-soft); color: var(--color-ink);
                          display: inline-flex; align-items: center; justify-content: center; }
.nova-msg .av svg       { width: 18px; height: 18px; }
.nova-msg .body         { flex: 1; min-width: 0; }
.nova-msg .meta         { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.nova-msg .meta .who    { font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: 1.6px; }
.nova-msg .meta .tag    { font-family: var(--font-mono); font-size: 9px; font-weight: 700; letter-spacing: 1.4px;
                          color: var(--color-accent); border: 1px solid rgba(77,166,255,0.45);
                          border-radius: 3px; padding: 2px 6px; }
.nova-msg .meta .time   { font-family: var(--font-mono); font-size: 9.5px; color: var(--color-muted);
                          margin-left: auto; font-weight: 700; }
.nova-bubble {
  background: var(--color-surface);
  border: 1px solid var(--color-rule);
  border-radius: 4px 14px 14px 14px;
  padding: 14px 18px; line-height: 1.55; font-size: 14.5px;
}

/* Stacked rows under a Nova reply: chips toolbar + sources eyebrow row.
   Owned by the kit so partials/nova/_msg_nova.html doesn't carry inline
   style="" attributes — flex-wrap keeps long chip strips from overflowing
   the .body column on narrow widths. */
.nova-msg .body .nova-chips,
.nova-msg .body .nova-sources {
  display: flex; gap: var(--space-2);
  flex-wrap: wrap; align-items: center;
  margin-top: var(--space-3);
}

.user-msg     { display: flex; justify-content: flex-end; gap: 12px; }
.user-bubble  {
  background: var(--color-ink); color: var(--color-paper);
  padding: 12px 16px; border-radius: 14px 14px 4px 14px;
  font-size: 14.5px; line-height: 1.5; max-width: 540px;
}
.user-msg .av {
  width: 30px; height: 30px; border-radius: 999px;
  background: #dad3c4; color: var(--color-ink);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 700; font-size: 13px;
}

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px; border-radius: var(--radius-pill);
  background: var(--color-surface); border: 1px solid var(--color-rule);
  font-size: 12px; font-weight: 600; cursor: pointer; color: var(--color-ink);
}
.chip:hover { background: var(--color-rule); }
.chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.chip-primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-ink); }

.source {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 8px 3px 5px; border-radius: 6px; background: var(--color-rule);
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  color: var(--color-ink-soft); letter-spacing: 0.4px;
}
.source .n {
  width: 14px; height: 14px; border-radius: 3px;
  background: var(--color-ink); color: var(--color-paper);
  display: inline-flex; align-items: center; justify-content: center; font-size: 9px;
}

.composer {
  background: var(--color-surface); border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg); padding: 14px 16px 12px;
  display: flex; flex-direction: column; gap: 10px;
}
.composer.is-focused { border-color: var(--color-accent); box-shadow: var(--focus-ring); }
.composer textarea {
  width: 100%; border: none; background: transparent; resize: none;
  font: inherit; color: var(--color-ink); outline: none; min-height: 22px;
}
.composer textarea::placeholder { color: var(--color-muted); }
.composer .row    { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.composer .tools  { display: flex; gap: 6px; flex-wrap: wrap; }
.composer .tools .chip { padding: 5px 10px; font-size: 11.5px; background: var(--color-rule); border-color: transparent; }
.composer .send   { background: var(--color-accent); color: var(--color-accent-ink);
                    border: none; border-radius: var(--radius-md); padding: 9px 16px;
                    font-weight: 700; font-size: 13px; cursor: pointer; }
.composer textarea:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
.composer .send:focus-visible    { outline: none; box-shadow: var(--focus-ring); }
.composer .hint   { font-family: var(--font-mono); font-size: 10px; color: var(--color-muted);
                    letter-spacing: 1.2px; font-weight: 700; }

/* ─── 12B · NOVA — STATE TAGS + ACTION CARDS ────────────────────── */
/* Eight Nova state tags (brief §10 STATE row). Default .tag colour is
   accent (set in §12 above); these variants override colour + border for
   the seven non-resting states. tag-streaming / tag-working / tag-needs-
   info / tag-held-policy / tag-failed / tag-hard-stop / tag-answered.
   The JS DOM builder (nova_chat.js::tagSlugKit) normalises the visible
   string ("HARD STOP" / "ANSWERED · 1.2s") into a kebab-case suffix; the
   "ANSWERED" duration variant drops the seconds tail so every timed
   answer shares the same tag-answered chip colour. */
.nova-msg .meta .tag-streaming  { color: var(--color-accent); border-color: rgba(77,166,255,0.45); }
.nova-msg .meta .tag-working    { color: var(--color-accent); border-color: rgba(77,166,255,0.45);
                                  background: var(--color-accent-soft); }
.nova-msg .meta .tag-needs-info { color: var(--color-warn);   border-color: rgba(197,96,26,0.45);
                                  background: var(--color-warn-soft); }
.nova-msg .meta .tag-held-policy{ color: var(--color-danger); border-color: rgba(193,87,62,0.45);
                                  background: var(--color-danger-soft); }
.nova-msg .meta .tag-failed     { color: var(--color-danger); border-color: rgba(193,87,62,0.45);
                                  background: var(--color-danger-soft); }
.nova-msg .meta .tag-hard-stop  { color: #fff; background: var(--color-danger);
                                  border-color: var(--color-danger); }
.nova-msg .meta .tag-answered   { color: var(--color-muted); border-color: var(--color-rule-strong);
                                  background: var(--color-paper-2); }

/* Nova action card — kit primitive (Phase 3). Hangs inside .nova-msg .body
   under the bubble; the legacy nova_drive.css ``.nova-action-card`` rules
   are scoped tight enough not to leak into the kit variant when both are
   loaded in parallel (NOVA_KIT flag off). Margin-top puts breathing space
   between the bubble and the card so the card reads as a follow-on, not
   a continuation of the bubble. */
.nova-msg .body .nova-action-card--kit {
  margin-top: var(--space-3);
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-paper-2);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
}
/* HARD STOP card — strong danger-coloured left border so the guardrail is
   visible at a glance. Matches the brief PDF p.13 callout pattern (orange
   left-rule on a light card). The .tag-hard-stop chip in the bubble's
   .meta row reinforces it; the card itself does not repeat the policy
   icon so the bubble body owns the explanatory text. */
.nova-msg .body .nova-action-card--kit.nova-action-card--hard-stop {
  border-left: 4px solid var(--color-warn);
  background: var(--color-paper);
}
/* Generic destructive card (non-HARD-STOP destructive verbs like post_*,
   send_*, delete_*) — softer danger accent so the user can tell the
   two tiers apart. */
.nova-msg .body .nova-action-card--kit.nova-action-card-destructive {
  border-left: 4px solid var(--color-danger);
}

/* Policy banner — single-line warning at the top of the card. ``style``-
   coupled to the existing ``.nova-action-destructive-warning`` class so
   the legacy banner pattern keeps working even when nested inside the
   kit card. Kit variant uses warn-soft fill for HARD STOP, danger-soft
   for plain destructive. */
.nova-msg .body .nova-action-card--kit .nova-action-destructive-warning {
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  letter-spacing: 0.6px; color: var(--color-ink);
  padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--color-warn-soft);
  display: flex; align-items: center; gap: 8px;
}
.nova-msg .body .nova-action-card--kit.nova-action-card-destructive:not(.nova-action-card--hard-stop)
  .nova-action-destructive-warning { background: var(--color-danger-soft); }
.nova-msg .body .nova-action-card--kit .nova-action-destructive-warning i { font-size: 14px; }

/* Preview pane — server-supplied summary rows. Two shapes:
   • <dl> with paired <dt>/<dd> rows (most common — array shape from the
     JS DOM builder when pending_action.preview is an array of
     {label, value}).
   • Free-form HTML when pending_action.preview is a trusted string.
   <dl> uses a two-column grid so labels stay in their column and money
   amounts can be mono-aligned. */
.nova-msg .body .nova-action-card--kit .nova-action-preview {
  margin: 0; padding: 10px 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  font-size: 13px; line-height: 1.5;
}
.nova-msg .body .nova-action-card--kit dl.nova-action-preview {
  display: grid; grid-template-columns: max-content 1fr;
  column-gap: var(--space-4); row-gap: var(--space-1);
}
.nova-msg .body .nova-action-card--kit dl.nova-action-preview dt {
  font-family: var(--font-mono); font-size: 10px; font-weight: 700;
  letter-spacing: 0.8px; color: var(--color-muted);
  text-transform: uppercase; align-self: baseline;
}
.nova-msg .body .nova-action-card--kit dl.nova-action-preview dd {
  margin: 0; color: var(--color-ink); font-weight: 600;
}

/* Action buttons row — primary CTA + cancel chip, right-aligned so the
   "approve" verb sits where the eye lands last. Reusable .btn primitives
   (§03) carry their own colour + focus ring; this rule only handles
   layout. */
.nova-msg .body .nova-action-card--kit .nova-action-buttons {
  display: flex; gap: var(--space-2); flex-wrap: wrap;
  justify-content: flex-end; align-items: center;
}

/* Accepted / cancelled badges — reuse the kit .pill primitive (§07). The
   JS DOM builder swaps the card's innerHTML to a single .pill after the
   server confirms accept/reject. Optional follow-up link (.nova-action-
   link) carries the created record's URL — kit ink colour with an
   underline on hover so it doesn't compete with the badge's tone. */
.nova-msg .body .nova-action-card--kit .nova-action-link {
  color: var(--color-ink); text-decoration: underline; font-weight: 700;
  margin-left: var(--space-2);
}
.nova-msg .body .nova-action-card--kit .nova-action-link:hover { color: var(--color-accent); }

/* ─── 13 · UTILITIES ─────────────────────────────────────────────── */
/* .is-hidden: kit-native equivalent of Bootstrap's .d-none. The !important
   matches Bootstrap's existing precedence so JS that swaps the class today
   keeps working when Phase 5 removes the Bootstrap CDN. New code that needs
   to toggle hidden state should classList.add('is-hidden') rather than set
   inline style.display so the kit owns the rule. */
.is-hidden { display: none !important; }

.muted   { color: var(--color-muted); }
.soft    { color: var(--color-ink-soft); }
.row     { display: flex; gap: var(--space-3); align-items: center; }
.col     { display: flex; flex-direction: column; gap: var(--space-3); }
.gap-2   { gap: var(--space-2); }
.gap-4   { gap: var(--space-4); }
.between { justify-content: space-between; }
.grow    { flex: 1; }

/* .cursor-pointer: pointer cursor on non-button clickable elements (clickable
   table rows, custom checkboxes, draggable list items). Bootstrap 5.3.3 does
   not ship this utility; kit-provided so templates avoid inline `cursor:pointer`. */
.cursor-pointer { cursor: pointer; }

/* .step-dot: 2rem square used as the numbered bullet in multi-step wizards
   (opening balances, migration). Pairs with Bootstrap's .rounded-circle +
   flex centring; kit-provided so the size is consistent across wizards and
   templates avoid duplicating `style="width:2rem;height:2rem"`. */
.step-dot { width: 2rem; height: 2rem; }

/* Sub-Bootstrap-`small` font-size utilities. Templates were drifting across
   0.6 / 0.65 / 0.7 / 0.72 / 0.75rem inline values that read as one visual
   "tiny" tier; consolidating to two kit classes removes the accidental
   ~7% drift between callsites. Used by line_row partials (buttons +
   metadata captions), badges, and gantt-chart tags. */
.text-xs   { font-size: 0.7rem; }
.text-meta { font-size: 0.75rem; }
