/* KGX1 Asset Dashboard — design system */

:root {
  /* Palette in OKLCH. Neutrals tinted toward the navy accent (H=260) at low
     chroma (0.003-0.008) so #fff never appears flat. Lightness anchors:
     surfaces 0.95-0.99, ink 0.18-0.32, accent 0.35. */
  --bg:             oklch(0.972 0.005 260);
  --surface:        oklch(0.992 0.003 260);    /* tinted off pure white */
  --surface-2:      oklch(0.985 0.004 260);
  --surface-3:      oklch(0.955 0.006 260);
  --ink:            oklch(0.180 0.040 260);
  --ink-2:          oklch(0.320 0.025 260);
  --muted:          oklch(0.500 0.020 260);
  --muted-2:        oklch(0.680 0.015 260);
  --border:         oklch(0.910 0.005 260);
  --border-strong:  oklch(0.840 0.008 260);

  --accent:         oklch(0.350 0.160 260);
  --accent-2:       oklch(0.520 0.220 260);
  --accent-soft:    oklch(0.950 0.025 260);

  /* Semantic data-viz colours hold their own hues, chroma reduced at edges */
  --complete:       oklch(0.600 0.170 145);    /* green */
  --complete-bg:    oklch(0.940 0.070 145);
  --blocker:        oklch(0.500 0.220 295);    /* violet */
  --blocker-bg:     oklch(0.950 0.040 295);
  --outstanding:    oklch(0.580 0.220 25);     /* red */
  --outstanding-bg: oklch(0.930 0.050 25);
  --warn:           oklch(0.620 0.160 55);     /* amber */

  --radius: 10px;
  --radius-sm: 6px;
  --radius-lg: 14px;
  /* Hue-tinted shadows: rather than a generic black drop, mix the active
     accent into a deep ink so cards pick up a faint reflection of the
     palette they sit on. Two stops: contact (1–2px, crisp edge) + ambient
     (wide diffuse haze). Skill rule 4 "tint shadow to the background hue". */
  --shadow-tint:    color-mix(in oklch, var(--accent) 22%, oklch(0.15 0.04 260));
  --shadow-sm: 0 1px 2px color-mix(in oklch, var(--shadow-tint) 8%, transparent);
  --shadow: 0 1px 2px color-mix(in oklch, var(--shadow-tint) 7%, transparent),
            0 8px 24px -10px color-mix(in oklch, var(--shadow-tint) 14%, transparent);
  --shadow-lg: 0 1px 2px color-mix(in oklch, var(--shadow-tint) 6%, transparent),
               0 20px 40px -15px color-mix(in oklch, var(--shadow-tint) 18%, transparent);

  --pad: 20px;
  --gap: 16px;
}

[data-theme="dark"] {
  --bg:             oklch(0.130 0.020 260);
  --surface:        oklch(0.180 0.025 260);
  --surface-2:      oklch(0.150 0.022 260);
  --surface-3:      oklch(0.220 0.028 260);
  --ink:            oklch(0.920 0.010 260);
  --ink-2:          oklch(0.820 0.015 260);
  --muted:          oklch(0.620 0.020 260);
  --muted-2:        oklch(0.450 0.022 260);
  --border:         oklch(0.270 0.025 260);
  --border-strong:  oklch(0.340 0.030 260);
  --accent:         oklch(0.620 0.200 260);
  --accent-2:       oklch(0.720 0.180 260);
  --accent-soft:    oklch(0.240 0.050 260);
  --complete:       oklch(0.720 0.180 145);
  --complete-bg:    oklch(0.200 0.060 145);
  --blocker:        oklch(0.720 0.170 295);
  --blocker-bg:     oklch(0.220 0.060 295);
  --outstanding:    oklch(0.700 0.180 25);
  --outstanding-bg: oklch(0.200 0.050 25);
  /* Dark mode: shadow tints lean deeper-black with a low-saturation accent
     reflection so cards don't bloom against the dark surface. */
  --shadow-tint:    color-mix(in oklch, var(--accent) 15%, oklch(0.06 0.02 260));
  --shadow-sm: 0 1px 2px color-mix(in oklch, var(--shadow-tint) 35%, transparent);
  --shadow: 0 1px 2px color-mix(in oklch, var(--shadow-tint) 30%, transparent),
            0 12px 28px -10px color-mix(in oklch, var(--shadow-tint) 40%, transparent);
  --shadow-lg: 0 1px 2px color-mix(in oklch, var(--shadow-tint) 25%, transparent),
               0 24px 48px -16px color-mix(in oklch, var(--shadow-tint) 55%, transparent);
}

/* Density variants scale spacing AND a font-scale token. font-size: calc()
   on body multiplies the base by --font-scale so headings/buttons/labels
   all shift together rather than just the gaps. */
:root                      { --font-scale: 1; }
[data-density="compact"]   { --pad: 14px; --gap: 10px; --font-scale: 0.94; }
[data-density="comfy"]     { --pad: 28px; --gap: 22px; --font-scale: 1.08; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  /* Geist + Geist Mono — the skill's mandated dashboard pairing. Inter is
     deliberately not in the stack: if Geist hasn't loaded yet we'd rather
     fall through to the OS UI font (San Francisco / Segoe) than Inter. */
  font-family: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-feature-settings: "ss01", "ss02", "cv11";
  letter-spacing: -0.005em;
  background: var(--bg);
  color: var(--ink);
  font-size: calc(13px * var(--font-scale, 1));
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
button { font-family: inherit; }
code, .mono, .tbl .num, .num.mono {
  font-family: "Geist Mono", "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ---------- Keyboard focus indicators (a11y, WCAG 2.4.7) ----------
   Browser default outlines are scrubbed across the stylesheet; this is the
   single source of truth for what keyboard users see when navigating. The
   ring inherits the active accent so it adapts to the user's chosen colour. */
:focus { outline: none; }            /* hide the mouse-click outline */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
/* Inputs and chip-style controls already have rounded corners; let the ring
   ride the radius rather than introducing a second one. */
.btn:focus-visible,
.icon-btn:focus-visible,
.phase-chip:focus-visible,
.nav-item:focus-visible,
.kpi-tile.is-clickable:focus-visible,
.seg-toggle button:focus-visible,
.snapshot-pill:focus-visible,
.snapshot-pill select:focus-visible { outline-offset: 2px; border-radius: 7px; }

/* Honour OS-level reduce-motion preference: collapse all animation, retain
   functionality. The spinning refresh icon, slide-in drawers, and chart
   tooltips all become instant. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
code { font-size: 11.5px; }   /* family inherits from the body .mono rule above */

.app {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 232px 1fr;
}

/* Sidebar */
.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
}
.brand {
  padding: 18px 18px 16px;
  display: flex; align-items: center; gap: 10px;
  border-bottom: 1px solid var(--border);
}
.brand-mark {
  width: 30px; height: 30px; border-radius: 8px;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: white; display: grid; place-items: center;
  font-weight: 700; font-size: 13px; letter-spacing: 0.02em;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25);
}
.brand-text { line-height: 1.15; }
.brand-text b { font-size: 13px; font-weight: 600; display: block; }
.brand-text small { font-size: 11px; color: var(--muted); }

.nav { padding: 12px 10px; display: flex; flex-direction: column; gap: 1px; flex: 1; }
.nav-section { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted-2); font-weight: 600; padding: 12px 10px 6px; }
.nav-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; border-radius: 7px;
  color: var(--ink-2); cursor: pointer; font-size: 13px;
  border: none; background: transparent; width: 100%;
  text-align: left;
}
.nav-item { transition: background 0.15s, color 0.15s, transform 0.12s; }
.nav-item:hover { background: var(--surface-3); }
.nav-item:active { transform: translateY(1px); }
.nav-item.is-active {
  background: var(--accent-soft); color: var(--accent);
  font-weight: 500;
}
.nav-item.is-active svg { color: var(--accent); }
.nav-item .nav-meta { margin-left: auto; font-size: 11px; color: var(--muted); }
.nav-item.is-active .nav-meta { color: var(--accent); }

.sidebar-foot {
  padding: 12px; border-top: 1px solid var(--border);
  display: flex; align-items: center; gap: 10px;
}
.avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: linear-gradient(135deg, #f59e0b, #ea580c);
  color: white; display: grid; place-items: center;
  font-size: 11px; font-weight: 600;
}
.user-info { line-height: 1.2; flex: 1; min-width: 0; }
.user-info b { font-size: 12px; display: block; font-weight: 600; }
.user-info small { font-size: 11px; color: var(--muted);
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.icon-btn {
  appearance: none; border: none; background: transparent;
  color: var(--muted); cursor: pointer; padding: 6px;
  border-radius: 6px; display: grid; place-items: center;
  min-width: 36px; min-height: 36px;                    /* desktop hit box */
  transition: background 0.15s, color 0.15s, transform 0.12s;
}
.icon-btn:hover { background: var(--surface-3); color: var(--ink); }
.icon-btn:active { transform: translateY(1px); }

/* Main */
.main { min-width: 0; }
.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: 14px 28px;
  display: flex; align-items: center; gap: 14px;
  flex-wrap: wrap; row-gap: 8px;          /* allow wrapping when narrow */
  position: sticky; top: 0; z-index: 10;
}
.crumb {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--muted);
  flex-shrink: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.crumb b { color: var(--ink); font-weight: 600; }
.crumb svg { color: var(--muted-2); }

/* Topbar search trigger — a button (not an input). Clicking or pressing
   ⌘/Ctrl+K opens the command palette overlay. Styled to look exactly like
   the old inline input so the visual signature stays the same. */
.search-box {
  appearance: none;
  margin-left: 14px;
  flex: 1 1 220px; min-width: 0; max-width: 460px;
  display: flex; align-items: center; gap: 8px;
  background: var(--surface-3);
  border: 1px solid transparent;
  border-radius: 8px; padding: 7px 10px;
  color: var(--muted); cursor: pointer;
  font: inherit; text-align: left;
  transition: background 0.15s, border-color 0.15s;
}
.search-box:hover { background: var(--surface-2); border-color: var(--border); }
.search-box:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; background: var(--surface); border-color: var(--accent); }
.search-box .search-box-text {
  flex: 1; min-width: 0; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.search-box kbd {
  font: 10px ui-monospace, monospace; background: var(--surface);
  border: 1px solid var(--border); border-radius: 4px;
  padding: 1px 5px; color: var(--muted); flex-shrink: 0;
}

/* Staleness pill — shows snapshot age from any page, tones at 7d / 14d. */
.staleness-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 999px;
  font: 600 11px/1 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.02em; text-transform: uppercase;
  border: 1px solid transparent;
  flex-shrink: 0;
}
.staleness-pill .staleness-dot {
  width: 6px; height: 6px; border-radius: 999px; flex-shrink: 0;
}
.staleness-pill.fresh {
  color: var(--complete);
  background: color-mix(in oklch, var(--complete) 10%, transparent);
  border-color: color-mix(in oklch, var(--complete) 25%, transparent);
}
.staleness-pill.fresh .staleness-dot { background: var(--complete); }
.staleness-pill.aging {
  color: var(--warn, var(--blocker));
  background: color-mix(in oklch, var(--warn, var(--blocker)) 12%, transparent);
  border-color: color-mix(in oklch, var(--warn, var(--blocker)) 28%, transparent);
}
.staleness-pill.aging .staleness-dot { background: var(--warn, var(--blocker)); }
.staleness-pill.stale {
  color: var(--blocker);
  background: color-mix(in oklch, var(--blocker) 12%, transparent);
  border-color: color-mix(in oklch, var(--blocker) 32%, transparent);
}
.staleness-pill.stale .staleness-dot { background: var(--blocker); }
@media (max-width: 760px) {
  .staleness-pill { font-size: 10.5px; padding: 4px 8px; }
}

.topbar-spacer { flex: 1 1 0; min-width: 0; }
.topbar-actions {
  display: flex; align-items: center; gap: 8px;
  flex-shrink: 0; flex-wrap: wrap; row-gap: 8px;
  margin-left: auto;                      /* keep actions hugging the right edge */
}
.topbar-actions .btn,
.topbar-actions .snapshot-pill { flex-shrink: 0; }

/* On narrow screens hide the placeholder search (no real search wired up
   anyway) and keep just the leaf breadcrumb so the actions always fit. */
/* Hide just the topbar's placeholder search at narrow widths — page-level
   search boxes (QR records, Assets) keep working. */
@media (max-width: 1100px) { .topbar > .search-box { display: none; } }
@media (max-width: 760px)  {
  .crumb > :not(:last-child) { display: none; }
  .topbar { padding: 12px 16px; }
}
.btn {
  appearance: none; border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--ink-2);
  padding: 7px 12px; border-radius: 7px; font-size: 12.5px; font-weight: 500;
  cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
  transition: background 0.15s, border-color 0.15s, transform 0.12s, box-shadow 0.15s;
  min-height: 36px;                                     /* desktop hit box */
  will-change: transform;
}
.btn:hover { background: var(--surface-3); }
.btn:active { transform: translateY(1px); }            /* tactile push */
.btn-primary {
  background: var(--accent); color: white; border-color: var(--accent);
}
.btn-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn-primary:active { transform: translateY(1px); box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 18%, transparent); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--surface-3); color: var(--ink); }
.btn[disabled], .btn:disabled { cursor: progress; opacity: 0.85; }
.btn[disabled]:active, .btn:disabled:active { transform: none; }
.btn.is-refreshing svg { animation: btn-spin 1s linear infinite; transform-origin: center; }
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Derived-level indicator: collapses to a 6px amber dot by default to keep
   the row quiet, expands into a clickable "derived: N" pill on row hover
   (or keyboard focus). Click drills into just the derived assets in that
   level. Always reads as a button to screen readers via its aria-label. */
.derived-mark {
  display: inline-flex; align-items: center;
  margin-left: 8px; padding: 0;
  background: transparent; border: none;
  color: var(--warn);
  font: inherit; font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.01em;
  cursor: pointer; appearance: none;
  vertical-align: 1px;
  border-radius: 999px;
  transition: padding 0.18s cubic-bezier(0.22, 1, 0.36, 1),
              background 0.18s, border-color 0.18s;
}
.derived-mark .derived-dot {
  width: 7px; height: 7px; border-radius: 999px;
  background: var(--warn); flex-shrink: 0;
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--warn) 18%, transparent);
}
.derived-mark .derived-text {
  max-width: 0; overflow: hidden; white-space: nowrap;
  margin-left: 0; opacity: 0;
  transition: max-width 0.22s cubic-bezier(0.22, 1, 0.36, 1),
              margin-left 0.18s, opacity 0.15s 0.05s;
}
.tbl tr:hover .derived-mark,
.tbl tr:focus-within .derived-mark,
.derived-mark:hover,
.derived-mark:focus-visible {
  padding: 1px 8px 1px 6px;
  background: color-mix(in oklch, var(--warn) 14%, transparent);
  border: 1px solid color-mix(in oklch, var(--warn) 35%, transparent);
}
.tbl tr:hover .derived-mark .derived-text,
.tbl tr:focus-within .derived-mark .derived-text,
.derived-mark:hover .derived-text,
.derived-mark:focus-visible .derived-text {
  max-width: 200px; margin-left: 5px; opacity: 1;
}

/* Per-asset source pill on the Assets page: same dot-by-default,
   text-on-hover treatment, scoped to the table row */
.src-pill {
  display: inline-flex; align-items: center;
  margin-left: 6px; padding: 0;
  border: 1px solid transparent; border-radius: 999px;
  background: transparent;
  font-size: 10px; font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase;
  cursor: help; vertical-align: 1px;
  transition: padding 0.18s, background 0.18s, border-color 0.18s;
}
.src-pill::before {
  content: ""; display: inline-block;
  width: 6px; height: 6px; border-radius: 999px;
  flex-shrink: 0;
}
.src-pill.derived { color: var(--warn); }
.src-pill.derived::before {
  background: var(--warn);
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--warn) 18%, transparent);
}
.src-pill.none { color: var(--outstanding); }
.src-pill.none::before {
  background: var(--outstanding);
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--outstanding) 18%, transparent);
}
.src-pill .src-text {
  max-width: 0; overflow: hidden; white-space: nowrap;
  margin-left: 0; opacity: 0;
  transition: max-width 0.22s cubic-bezier(0.22, 1, 0.36, 1), margin-left 0.18s, opacity 0.15s 0.05s;
}
.tbl tr:hover .src-pill,
.tbl tr:focus-within .src-pill,
.src-pill:hover, .src-pill:focus-visible {
  padding: 1px 7px;
  border-color: color-mix(in oklch, currentColor 35%, transparent);
  background: color-mix(in oklch, currentColor 12%, transparent);
}
.tbl tr:hover .src-pill .src-text,
.tbl tr:focus-within .src-pill .src-text,
.src-pill:hover .src-text, .src-pill:focus-visible .src-text {
  max-width: 120px; margin-left: 4px; opacity: 1;
}

/* In the drill-panel header the derived pill sits next to the title with
   text always visible (no row to hover) */
.drill-head .src-pill { padding: 1px 8px; border-color: color-mix(in oklch, currentColor 35%, transparent); background: color-mix(in oklch, currentColor 12%, transparent); }
.drill-head .src-pill::before { display: none; }
.src-pill {
  display: inline-block;
  margin-left: 6px; padding: 0 6px;
  border-radius: 999px;
  font-size: 10px; font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase;
  cursor: help;
}
.src-pill.derived {
  background: color-mix(in oklch, var(--warn) 14%, transparent);
  color: var(--warn);
  border: 1px solid color-mix(in oklch, var(--warn) 35%, transparent);
}
.src-pill.none {
  background: color-mix(in oklch, var(--outstanding) 12%, transparent);
  color: var(--outstanding);
  border: 1px solid color-mix(in oklch, var(--outstanding) 35%, transparent);
}

/* Status pills used in the Assets / Blockers tables */
.chip {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
  background: var(--surface-3); color: var(--ink); border: 1px solid var(--border);
}
.chip.c { background: var(--complete-bg); color: var(--complete); border-color: color-mix(in oklch, var(--complete) 35%, transparent); }
.chip.b { background: var(--blocker-bg);  color: var(--blocker);  border-color: color-mix(in oklch, var(--blocker)  35%, transparent); }
.chip.o { background: var(--outstanding-bg); color: var(--outstanding); border-color: color-mix(in oklch, var(--outstanding) 35%, transparent); }

/* Page */
.page { padding: 22px 28px 80px; max-width: 1480px; margin: 0 auto; }
.page-head { margin-bottom: 18px; display: flex; align-items: end; gap: 16px; flex-wrap: wrap; }
.page-title { font-size: 22px; font-weight: 600; margin: 0; letter-spacing: -0.01em; }
.page-sub { color: var(--muted); font-size: 13px; margin: 4px 0 0; }
.page-head-spacer { flex: 1; }

.snapshot-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px; padding: 6px 10px;
  font-size: 12px; color: var(--ink-2);
}
.snapshot-pill select {
  border: none; background: transparent;
  font: inherit; color: var(--ink); font-weight: 500;
  cursor: pointer; padding-right: 4px;
  /* color-scheme tells the UA which native popup palette to use for the
     dropdown when this select is opened. Without it, dark-mode users got
     a dim grey-on-grey list that was almost unreadable. */
  color-scheme: light dark;
}
/* The dropdown popup is native, but Chrome / Firefox / Edge all respect
   background-color + color on option elements. Pin them to our surface
   palette so light AND dark modes render legibly. */
.snapshot-pill select option {
  background-color: var(--surface);
  color: var(--ink);
  font: 500 13px 'Geist Mono', ui-monospace, monospace;
  padding: 4px 8px;
}
.snapshot-pill select:focus { outline: none; }                       /* pill handles ring */
.snapshot-pill:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }
.snapshot-pill .latest-tag {
  font-size: 10px; padding: 2px 7px 2px 6px; border-radius: 999px;
  background: var(--complete-bg); color: var(--complete);
  font-weight: 600; letter-spacing: 0.04em;
  display: inline-flex; align-items: center; gap: 5px;
}
.snapshot-pill .latest-dot {
  width: 6px; height: 6px; border-radius: 999px;
  background: var(--complete);
  flex-shrink: 0;
  position: relative;
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--complete) 22%, transparent);
}
/* Perpetual "breathing" ring around the live dot — quiet, slow (2.6s), the
   kind of signal you only notice peripherally. Pauses for reduced-motion
   users via the global @media (prefers-reduced-motion). */
.snapshot-pill .latest-dot::after {
  content: ""; position: absolute; inset: -3px; border-radius: 999px;
  background: color-mix(in oklch, var(--complete) 40%, transparent);
  animation: latest-pulse 2.6s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  pointer-events: none;
}
@keyframes latest-pulse {
  0%   { transform: scale(0.6); opacity: 0.85; }
  60%  { transform: scale(1.8); opacity: 0; }
  100% { transform: scale(2.2); opacity: 0; }
}

/* Toolbar */
.toolbar {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px 12px;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 16px;
}
/* When the toolbar is immediately followed by a filter chip strip, drop
   the bottom rounded corners so the two visually fuse into one group. */
.toolbar:has(+ .filter-chip-strip) {
  border-radius: var(--radius) var(--radius) 0 0;
  margin-bottom: 0;
  border-bottom: none;
}
/* Shared "eyebrow" style used by every uppercase section label across the
   dashboard: PHASE · FILTERS · MAINTAINABLE · STATUS · LEVEL · CORE · etc.
   Keeping them on one canonical recipe stops the page from feeling like
   four different products glued together. Apply via the class names below;
   per-call font-size tweaks are fine but the family/case/spacing stay. */
.toolbar-label,
.kpi-label,
.filter-chip-label,
.fp-section-title,
.plan-settings-key,
.plan-metric-key,
.forecast-meta-key,
.asset-meta-key,
.nav-section {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.toolbar-label { padding-right: 4px; }
.phase-chip {
  appearance: none; border: 1px solid var(--border);
  background: var(--surface); color: var(--ink-2);
  padding: 5px 10px; border-radius: 999px; font: inherit; font-size: 12px;
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  transition: all 0.15s;
}
.phase-chip:hover { background: var(--surface-3); color: var(--ink); }
/* Active chip uses the accent colour so it's always legible — the previous
   `background: var(--ink); color: white` produced white-on-near-white in
   dark mode because --ink flips light when the theme flips. */
.phase-chip.is-active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.phase-chip-count {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  /* Use an explicit muted-2 colour instead of opacity 0.7 — opacity drops
     readability further in dark mode where the chip already sits on a dark
     surface. With color-mix we land at the right contrast in both themes. */
  color: color-mix(in oklch, currentColor 70%, transparent);
}
.phase-chip.is-active .phase-chip-count {
  color: color-mix(in oklch, #fff 85%, transparent);
}
.toolbar-divider { width: 1px; height: 22px; background: var(--border); margin: 0 4px; }

/* KPI grid */
.kpi-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr;
  gap: var(--gap);
  margin-bottom: var(--gap);
}
.kpi-tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--pad);
  position: relative;
  overflow: hidden;
}
/* kpi-label inherits the shared eyebrow style above (Geist Mono · 10.5px ·
   600 · 0.08em uppercase · muted). Only the layout-specific bits stay. */
.kpi-label {
  display: flex; align-items: center; gap: 6px;
}
.kpi-tile.complete .kpi-label svg { color: var(--complete); }
.kpi-tile.blocker .kpi-label svg { color: var(--blocker); }
.kpi-tile.outstanding .kpi-label svg { color: var(--outstanding); }

.kpi-row { display: flex; align-items: end; justify-content: space-between; margin-top: 4px; gap: 8px; }
.kpi-value {
  font-size: 32px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; line-height: 1.1;
  color: var(--ink);
}
.kpi-tile.complete .kpi-value { color: var(--complete); }
.kpi-tile.blocker .kpi-value { color: var(--blocker); }
.kpi-tile.outstanding .kpi-value { color: var(--outstanding); }
.kpi-tile.unmatched .kpi-value { color: var(--warn); }
.kpi-tile.unmatched .kpi-label svg { color: var(--warn); }

/* Clickable KPI variant, used by the Unmatched tile to drill in */
button.kpi-tile {
  text-align: left; font: inherit; color: inherit;
  cursor: pointer; appearance: none;
}
.kpi-tile.is-clickable { transition: transform 0.1s, box-shadow 0.15s, border-color 0.15s; }
.kpi-tile.is-clickable:hover {
  border-color: var(--accent); box-shadow: var(--shadow);
  transform: translateY(-1px);
}

.kpi-foot { margin-top: 10px; font-size: 12px; color: var(--muted); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.kpi-delta { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 500; }
.kpi-delta.up { color: var(--complete); }
.kpi-delta.down { color: var(--outstanding); }
.kpi-sub { font-size: 11.5px; }
/* When both delta and sub are present, separate with a soft pipe so they don't run together. */
.kpi-foot .kpi-delta + .kpi-sub {
  padding-left: 8px; border-left: 1px solid var(--border);
  color: var(--blocker); font-weight: 500;
}

.sparkline { color: var(--accent); }
.kpi-tile.complete .sparkline { color: var(--complete); }
.kpi-tile.blocker .sparkline { color: var(--blocker); }
.kpi-tile.outstanding .sparkline { color: var(--outstanding); }

/* Project completion strip: typographic number + linear progress bar.
   Replaces the previous gradient-ring hero tile (SaaS template). */
.completion-strip { margin: 0 0 18px; }
.completion-strip-row {
  display: flex; align-items: baseline; gap: 14px;
  flex-wrap: wrap; row-gap: 6px;
}
.completion-pct {
  display: inline-flex; align-items: baseline; gap: 8px;
}
.completion-pct .num {
  font-size: 38px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; color: var(--ink); line-height: 1;
}
.completion-pct .num small { font-size: 22px; font-weight: 500; opacity: 0.6; }
.completion-pct .lbl {
  font-size: 12px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600;
}
.completion-delta {
  font-size: 12px; font-weight: 500; margin-left: auto;
  font-variant-numeric: tabular-nums;
}
.completion-delta.up { color: var(--complete); }
.completion-delta.down { color: var(--outstanding); }
.completion-bar {
  margin-top: 12px;
  height: 6px; border-radius: 999px;
  background: var(--surface-3); overflow: hidden;
}
.completion-bar-fill {
  height: 100%; border-radius: 999px;
  background: var(--accent);
  transition: width 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Cards */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: var(--gap);
  /* Skill rule 4: tint shadow to the background hue. Wide diffuse haze that
     barely registers individually but adds a felt sense of elevation to the
     stack of cards. The token already mixes the active accent in. */
  box-shadow: var(--shadow-sm);
}
.card-head {
  padding: 14px var(--pad) 12px;
  display: flex; align-items: end; justify-content: space-between; gap: 12px;
  border-bottom: 1px solid var(--border);
}
.card-head h2, .card-head h3 { font-size: 14px; font-weight: 600; margin: 0; }
.card-head .sub { font-size: 12px; color: var(--muted); margin: 2px 0 0; }
.card-head .actions { display: flex; gap: 6px; }
.card-body { padding: var(--pad); }
.card-body.flush { padding: 0; }

.legend { display: inline-flex; gap: 12px; font-size: 11.5px; color: var(--muted); }
.legend-dot { display: inline-flex; align-items: center; gap: 5px; }
.legend-dot::before {
  content: ""; width: 8px; height: 8px; border-radius: 2px;
  background: var(--complete);
}
.legend-dot.b::before { background: var(--blocker); }
.legend-dot.o::before { background: var(--outstanding); }
.legend-dot.trend::before { background: var(--accent); }
.card-head .actions { align-items: center; }
.card-head .actions .legend { margin-right: 8px; }

/* Two-column layout. minmax(0, …) lets the cells shrink below their
   content's min-width — otherwise wide table headers ("LEVEL · CORE ·
   CATEGORY") force the grid cells out to their min-content size, which
   on a 375 px phone meant the breakdown cards rendered 560 px wide and
   overflowed the viewport. With minmax(0, …) the .tbl-wrap's
   overflow-x: auto can actually kick in and scroll inside the card. */
.row-2 {
  display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: var(--gap);
  margin-bottom: var(--gap);
}
.row-2 > * { min-width: 0; }

/* Level chart — three-level nested. Depth-0 rows look bold, depth-1/2 rows
   tuck in with a smaller bar height and a guide rail. The label column grows
   to 168px so 'Level 03  ▸  Core A' or a long category name still fits. */
.lvl-chart { display: flex; flex-direction: column; gap: 6px; }
.lvl-row {
  display: grid; grid-template-columns: 196px 1fr; align-items: center; gap: 12px;
}
.lvl-row.d-1 { gap: 12px; }
.lvl-row.d-2 { gap: 12px; }
.lvl-label {
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  font-size: 12px; color: var(--ink-2); font-weight: 500;
}
.lvl-label-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lvl-row.d-1 .lvl-label-text { color: var(--ink-2); font-weight: 500; font-size: 11.5px; }
.lvl-row.d-2 .lvl-label-text { color: var(--muted); font-weight: 400; font-size: 11px; }
.lvl-indent { width: 12px; height: 1px; background: var(--border-strong); opacity: 0.65; flex-shrink: 0; }
.lvl-row.d-2 .lvl-indent { opacity: 0.45; }
.lvl-expand {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0;
  background: transparent; border: none; border-radius: 4px;
  color: var(--muted); cursor: pointer; flex-shrink: 0;
  transition: background 0.15s, color 0.15s;
}
.lvl-expand { transition: background 0.15s, color 0.15s, transform 0.12s; }
.lvl-expand:hover { background: var(--surface-3); color: var(--ink); }
.lvl-expand:active { transform: translateY(1px); }
.lvl-expand:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lvl-expand-spacer { width: 18px; height: 18px; visibility: hidden; }
.lvl-chevron {
  display: inline-block; font-size: 10px; line-height: 1;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
.lvl-row.has-sub.is-open .lvl-chevron { transform: rotate(90deg); }
.lvl-bar-wrap { display: flex; align-items: center; gap: 12px; }
.lvl-bar {
  flex: 1; height: 22px; background: var(--surface-3); border-radius: 5px;
  display: flex; overflow: hidden; min-width: 0;
  transition: height 0.18s, opacity 0.18s;
}
.lvl-row.d-1 .lvl-bar { height: 16px; opacity: 0.92; }
.lvl-row.d-2 .lvl-bar { height: 12px; opacity: 0.82; }
.lvl-seg {
  display: flex; align-items: center; justify-content: flex-end;
  padding: 0 8px; font-size: 11px; font-weight: 600;
  color: white; cursor: pointer; transition: filter 0.15s;
  font-variant-numeric: tabular-nums;
}
.lvl-row.d-1 .lvl-seg { font-size: 10px; padding: 0 6px; }
.lvl-row.d-2 .lvl-seg { font-size: 9.5px; padding: 0 5px; }
.lvl-seg:hover { filter: brightness(1.1); }
.lvl-seg.c { background: var(--complete); }
.lvl-seg.b { background: var(--blocker); }
.lvl-seg.o { background: var(--outstanding); }
.lvl-tail { display: flex; align-items: baseline; gap: 8px; min-width: 88px; justify-content: flex-end; }
.lvl-pct { font-size: 12px; font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.lvl-total { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.lvl-row.d-1 .lvl-pct, .lvl-row.d-2 .lvl-pct { font-size: 11px; color: var(--ink-2); }
.lvl-row.d-1 .lvl-total, .lvl-row.d-2 .lvl-total { font-size: 10.5px; }

/* Bar chart (vertical) */
.bar-chart { display: block; }
.grid-line { stroke: var(--border); stroke-width: 1; stroke-dasharray: 2 3; }
.grid-label, .x-label { font-size: 10.5px; fill: var(--muted); font-family: inherit; }
.x-label.depth-1 { fill: var(--ink-2); font-size: 10px; }
.x-label.depth-2 { fill: var(--muted); font-size: 9.5px; }
.bar-total { font-size: 10px; fill: var(--ink-2); font-family: inherit; font-weight: 500; }
.seg-c { fill: var(--complete); cursor: pointer; }
.seg-b { fill: var(--blocker); cursor: pointer; }
.seg-o { fill: var(--outstanding); cursor: pointer; }
.seg-c:hover, .seg-b:hover, .seg-o:hover { filter: brightness(1.1); }
.bar-group.d-1 .seg-c, .bar-group.d-1 .seg-b, .bar-group.d-1 .seg-o { opacity: 0.88; }
.bar-group.d-2 .seg-c, .bar-group.d-2 .seg-b, .bar-group.d-2 .seg-o { opacity: 0.7; }
.bar-depth-bg { fill: var(--surface-2); opacity: 0.55; }
.bar-expand .bar-expand-bg { fill: var(--surface-3); stroke: var(--border-strong); stroke-width: 1; }
.bar-expand:hover .bar-expand-bg { fill: var(--accent-soft); stroke: var(--accent); }
.bar-expand .bar-expand-chev {
  font-size: 11px; fill: var(--muted); font-family: inherit; font-weight: 600;
  user-select: none;
}
.bar-expand:hover .bar-expand-chev { fill: var(--accent); }

/* Trend chart */
.trend-wrap { display: grid; grid-template-columns: 1fr; gap: 12px; }
.trend-chart-box { position: relative; }
.trend-chart .trend-area { fill: var(--accent); fill-opacity: 0.08; }
.trend-chart .trend-line { fill: none; stroke: var(--accent); stroke-width: 2; }
.trend-chart .trend-dot { fill: var(--surface); stroke: var(--accent); stroke-width: 1.5; }
.trend-chart .trend-dot-last { fill: var(--accent); }
.trend-chart .trend-rule { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 3 3; }
.trend-chart .trend-dot-hover { fill: var(--accent); stroke: var(--surface); stroke-width: 2; }

.trend-tooltip {
  position: absolute;
  pointer-events: none;
  z-index: 5;
  transform: translate(-50%, -100%) translateY(-12px);
  background: var(--ink);
  color: var(--surface);
  padding: 8px 10px;
  border-radius: 8px;
  font-size: 12px;
  line-height: 1.4;
  white-space: nowrap;
  box-shadow: var(--shadow-lg);
}
.trend-tooltip[data-side="left"] { transform: translate(-100%, -100%) translate(-12px, -12px); }
.trend-tooltip .t-date { opacity: 0.75; font-size: 11px; margin-bottom: 2px; }
.trend-tooltip .t-pct  { font-weight: 600; font-size: 14px; margin-bottom: 4px; }
.trend-tooltip .t-detail { display: flex; flex-direction: column; gap: 1px; font-size: 11px; opacity: 0.92; }
.trend-tooltip .t-detail b { font-weight: 600; }
.trend-tooltip .t-detail .muted { opacity: 0.6; }
.trend-tooltip::after {
  content: ""; position: absolute;
  bottom: -4px; left: 50%; transform: translateX(-50%) rotate(45deg);
  width: 8px; height: 8px; background: var(--ink);
}
.trend-tooltip[data-side="left"]::after { left: auto; right: 6px; transform: rotate(45deg); }
.trend-legend { display: flex; gap: 18px; font-size: 12px; padding: 0 var(--pad) var(--pad); }
.trend-legend b { font-size: 18px; font-weight: 600; color: var(--ink); }
.trend-legend .delta-up { color: var(--complete); font-weight: 500; }
.trend-legend .delta-down { color: var(--outstanding); font-weight: 500; }
.trend-legend .muted { color: var(--muted); }

/* Asset grid */
.asset-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, 10px);
  gap: 2px;
}
.asset-cell {
  width: 10px; height: 10px; border-radius: 2px;
  background: var(--outstanding); cursor: pointer;
}
.asset-cell.c { background: var(--complete); }
.asset-cell.b { background: var(--blocker); }
.asset-cell:hover { transform: scale(1.6); border: 1px solid var(--ink); }

/* Tables */
.tbl-wrap { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.tbl th {
  text-align: left; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--muted); font-weight: 600;
  padding: 10px var(--pad); border-bottom: 1px solid var(--border);
  background: var(--surface-2); position: sticky; top: 0;
}
.tbl td {
  padding: 10px var(--pad); border-bottom: 1px solid var(--border);
  color: var(--ink-2);
}
.tbl tr:last-child td { border-bottom: none; }
.tbl tr:hover td { background: var(--surface-2); }
.tbl tr.is-total td {
  font-weight: 600; background: var(--surface-2); color: var(--ink);
  border-top: 1px solid var(--border-strong);
}
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.tbl .clickable { cursor: pointer; color: var(--ink); font-weight: 500; }
.tbl .clickable:hover { text-decoration: underline; }
.tbl .clickable.c { color: var(--complete); }
.tbl .clickable.b { color: var(--blocker); }
.tbl .clickable.o { color: var(--outstanding); }
.tbl .zero { color: var(--muted-2); }
.tbl .first-col { font-weight: 500; color: var(--ink); }

/* Staggered reveal when a tree row opens. The parent's :is-open state
   doesn't drive this — instead, newly mounted children get the keyframe and
   --i (childIndex) on each row paces the cascade. 28ms per row keeps a
   five-core fan-out under 200ms, just past the "instant" threshold. */
@keyframes tree-row-in {
  0%   { opacity: 0; transform: translateY(-4px); }
  100% { opacity: 1; transform: translateY(0); }
}
.tbl-expandable tr.tree-row.d-1,
.tbl-expandable tr.tree-row.d-2,
.lvl-chart .lvl-row.d-1,
.lvl-chart .lvl-row.d-2 {
  animation: tree-row-in 280ms cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: calc(var(--i, 0) * 28ms);
}
/* If a row has the same key across renders (parent already open) we don't
   want a re-flash — but React unmounts on collapse and remounts on expand,
   so the keyframe naturally fires only when there's a "new" mount. */

/* Expandable rows: each Level row can fold open into Core, then each Core
   into BIM Category. The chevron sits in the first cell next to the label so
   totals + Progress columns stay perfectly aligned with the sub-rows below. */
.row-label-wrap {
  display: inline-flex; align-items: center; gap: 4px;
  vertical-align: middle;
}
.row-indent {
  display: inline-block; width: 14px; height: 1px;
  background: var(--border-strong); opacity: 0.55; flex-shrink: 0;
  margin-right: 2px;
}
.tree-row.d-2 .row-indent { opacity: 0.35; }
.row-expand {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0;
  background: transparent; border: none; border-radius: 4px;
  color: var(--muted); cursor: pointer; flex-shrink: 0;
  transition: background 0.15s, color 0.15s;
}
.row-expand { transition: background 0.15s, color 0.15s, transform 0.12s; }
.row-expand:hover { background: var(--surface-3); color: var(--ink); }
.row-expand:active { transform: translateY(1px); }
.row-expand:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
.row-expand-spacer { width: 18px; height: 18px; visibility: hidden; }
.row-chevron {
  display: inline-block; font-size: 10px; line-height: 1;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
  transform-origin: 50% 50%;
}
.tbl-expandable tr.has-sub.is-open .row-chevron { transform: rotate(90deg); }
.tbl-expandable tr.has-sub.is-open > td {
  background: var(--surface-2);
  border-bottom-color: transparent;
}
/* Depth-1 (Core) rows */
.tbl-expandable tr.tree-row.d-1 > td {
  background: color-mix(in oklch, var(--surface-2) 65%, var(--surface));
  color: var(--ink-2);
  padding-top: 7px; padding-bottom: 7px;
  font-size: 12px;
}
.tbl-expandable tr.tree-row.d-1:hover > td {
  background: color-mix(in oklch, var(--surface-2) 85%, var(--surface));
}
.tbl-expandable tr.tree-row.d-1 .row-label.depth-1 {
  font-weight: 500; color: var(--ink-2); letter-spacing: 0.01em;
}
/* Depth-2 (Category) rows */
.tbl-expandable tr.tree-row.d-2 > td {
  background: color-mix(in oklch, var(--surface-2) 35%, var(--surface));
  color: var(--muted);
  padding-top: 6px; padding-bottom: 6px;
  font-size: 11.5px;
}
.tbl-expandable tr.tree-row.d-2:hover > td {
  background: color-mix(in oklch, var(--surface-2) 60%, var(--surface));
}
.tbl-expandable tr.tree-row.d-2 .row-label.depth-2 {
  font-weight: 400; color: var(--muted);
}
/* Visual break between a closing sub-tree and the next top-level row */
.tbl-expandable tr.tree-row.d-1 + tr.tree-row.d-0 > td,
.tbl-expandable tr.tree-row.d-2 + tr.tree-row.d-0 > td {
  border-top: 1px solid var(--border-strong);
}

/* Legacy sub-row classes (still used by the old 2-level BreakdownTable for
   future callers — kept so we don't break anything that opts in to it). */
.tbl-expandable tr.sub-row > td {
  background: color-mix(in oklch, var(--surface-2) 60%, var(--surface));
  color: var(--ink-2);
  padding-top: 7px; padding-bottom: 7px;
  font-size: 12px;
}
.tbl-expandable tr.sub-row:hover > td {
  background: color-mix(in oklch, var(--surface-2) 80%, var(--surface));
}
.tbl-expandable tr.sub-row .sub-tick {
  display: inline-block; width: 12px; height: 1px;
  background: var(--border-strong); margin-right: 2px;
  flex-shrink: 0;
}
.tbl-expandable tr.sub-row .sub-label {
  font-weight: 500; color: var(--ink-2); letter-spacing: 0.01em;
}
.tbl-expandable tr.sub-row + tr:not(.sub-row) > td {
  border-top: 1px solid var(--border-strong);
}

.prog {
  width: 100%; min-width: 80px; max-width: 140px;
  background: var(--surface-3); border-radius: 3px; overflow: hidden;
  display: flex;
}
.prog-c { background: var(--complete); }
.prog-b { background: var(--blocker); }
.prog-o { background: transparent; }
.pct-cell { display: flex; align-items: center; gap: 8px; }
.pct-cell .pct-text {
  font-size: 11.5px; min-width: 44px; text-align: right;
  color: var(--ink); font-weight: 500; font-variant-numeric: tabular-nums;
}

.status-pill {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.01em;
}
.status-pill.complete { background: var(--complete-bg); color: var(--complete); }
.status-pill.blocker { background: var(--blocker-bg); color: var(--blocker); }
.status-pill.outstanding { background: var(--outstanding-bg); color: var(--outstanding); }

.qr-link {
  font-size: 11.5px; color: var(--accent); text-decoration: none;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 2px 6px; border-radius: 4px;
}
.qr-link:hover { background: var(--accent-soft); }

/* Drill panel — slide-in from right */
.drill-mask {
  position: fixed; inset: 0; background: rgba(15, 23, 41, 0.36);
  z-index: 100; opacity: 0; pointer-events: none;
  transition: opacity 0.2s;
}
.drill-mask.is-open { opacity: 1; pointer-events: auto; }
.drill-panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: min(640px, 92vw); background: var(--surface);
  z-index: 101;
  box-shadow: -8px 0 40px -8px color-mix(in oklch, var(--shadow-tint) 28%, transparent);
  display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform 0.25s ease;
}
.drill-panel.is-open { transform: translateX(0); }
.drill-head {
  padding: 18px 22px 14px; border-bottom: 1px solid var(--border);
}
.drill-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.drill-head-title { font-size: 16px; font-weight: 600; margin: 0; letter-spacing: -0.01em; }
.drill-head-meta { font-size: 12px; color: var(--muted); margin-top: 4px; }
.drill-search {
  margin-top: 14px;
  display: flex; align-items: center; gap: 8px;
  background: var(--surface-3); border: 1px solid transparent;
  border-radius: 7px; padding: 7px 10px; color: var(--muted);
}
.drill-search input { border: none; background: transparent; flex: 1; font: inherit; color: var(--ink); }
.drill-search input:focus { outline: none; }                         /* container handles ring */
.drill-search:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }
.drill-search:focus-within { background: var(--surface); border-color: var(--accent); }
.drill-body { flex: 1; overflow-y: auto; }
.drill-body table.tbl th { background: var(--surface); }
.drill-foot { padding: 10px 22px; border-top: 1px solid var(--border); font-size: 11.5px; color: var(--muted); }

.empty-state {
  padding: 48px 24px; text-align: center; color: var(--muted); font-size: 13px;
}

/* Misc */
.muted { color: var(--muted); }
.flex { display: flex; }
.gap-8 { gap: 8px; }
.gap-12 { gap: 12px; }
.gap-16 { gap: 16px; }
.right { margin-left: auto; }

.seg-toggle {
  display: inline-flex; background: var(--surface-3);
  border-radius: 7px; padding: 2px; gap: 2px;
  border: 1px solid var(--border);
}
.seg-toggle button {
  appearance: none; border: none; background: transparent;
  font: inherit; font-size: 11.5px; padding: 4px 10px;
  border-radius: 5px; cursor: pointer; color: var(--muted);
  display: inline-flex; align-items: center; gap: 5px;
}
.seg-toggle button.is-active {
  background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-sm);
}

.notice {
  display: flex; align-items: flex-start; gap: 10px;
  background: #fff7ed; border: 1px solid #fed7aa;
  border-radius: var(--radius); padding: 10px 14px;
  font-size: 12.5px; color: #92400e; margin-bottom: 16px;
}
[data-theme="dark"] .notice { background: #2a1f0d; border-color: #4a3217; color: #fbbf24; }
.notice svg { color: var(--warn); flex-shrink: 0; margin-top: 1px; }

/* ---------- BIM staleness banner (appears under PageHead) ---------- */
.stale-banner {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 14px;
  border: 1px solid; border-radius: 10px;
  font-size: 13px; line-height: 1.45;
  margin: 12px 0 18px;
}
.stale-banner.info { background: #eff6ff; border-color: #bfdbfe; color: #1e40af; }
.stale-banner.warn { background: #fef3c7; border-color: #fcd34d; color: #92400e; }
[data-theme="dark"] .stale-banner.info { background: #0f1e36; border-color: #1e3a5f; color: #93c5fd; }
[data-theme="dark"] .stale-banner.warn { background: #2a1f0d; border-color: #4a3217; color: #fbbf24; }
.stale-banner svg { flex-shrink: 0; margin-top: 2px; }
.stale-banner-text { flex: 1; min-width: 0; }
.stale-banner-text code { font-size: 12px; background: rgba(0,0,0,0.05); padding: 1px 5px; border-radius: 4px; }
.stale-banner-text .muted { opacity: 0.75; }
.stale-banner-details { flex-shrink: 0; }
.stale-banner-details summary {
  cursor: pointer; font-size: 12px; font-weight: 500;
  padding: 2px 8px; border-radius: 6px;
  background: rgba(0,0,0,0.06);
}
.stale-banner-details summary:hover { background: rgba(0,0,0,0.10); }
.stale-banner-details[open] summary { margin-bottom: 6px; }
.stale-banner-details ul {
  list-style: none; margin: 0; padding: 6px 8px;
  font-size: 11.5px; background: rgba(255,255,255,0.5);
  border-radius: 6px;
}
.stale-banner-details li { padding: 1px 0; }
.stale-banner-details code { font-size: 11px; background: rgba(0,0,0,0.05); padding: 0 4px; border-radius: 3px; }

/* ---------- Hamburger button + sidebar mask ---------- */
.topbar-menu { display: none; flex-shrink: 0; }
.sidebar-close { display: none; margin-left: auto; }
.sidebar-mask {
  display: none;
  position: fixed; inset: 0; background: rgba(15, 23, 41, 0.36);
  z-index: 90;
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s;
}
.sidebar-mask.is-open { opacity: 1; pointer-events: auto; }

/* ---------- Tablet: 1180px and below ---------- */
@media (max-width: 1180px) {
  .kpi-grid { grid-template-columns: 1fr 1fr 1fr; }
  .row-2 { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Tablet bridge: 760px–960px ---------- */
@media (max-width: 960px) {
  .kpi-grid { grid-template-columns: 1fr 1fr 1fr 1fr; }
}

/* ---------- Mobile: 760px and below ---------- */
@media (max-width: 760px) {
  /* App: collapse to single-column. Sidebar becomes a left drawer. */
  .app { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0;
    width: min(280px, 84vw);
    z-index: 100;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    box-shadow: 4px 0 32px -4px color-mix(in oklch, var(--shadow-tint) 30%, transparent);
  }
  .sidebar.is-open { transform: translateX(0); }
  .sidebar-mask { display: block; }
  .sidebar-close { display: grid; place-items: center; }

  /* Topbar tightening + hamburger reveal.
     Action row uses a real grid + uniform 40px row height so the staleness
     pill, snapshot picker, Export, and Refresh all align to one strip. The
     breadcrumb sits on row 1 with the hamburger; actions wrap to row 2 if
     they need to. */
  .topbar {
    padding: 10px 12px; gap: 8px 10px; row-gap: 10px;
    align-items: center;
  }
  .topbar-menu { display: grid; place-items: center; }
  /* On mobile the breadcrumb collapses to just its leaf (the >480px rule
     hides earlier segments). Treat that leaf as the page title — it's the
     only label the user sees in the topbar, so it deserves real weight. */
  .crumb { font-size: 12px; min-width: 0; }
  .crumb b {
    font-size: 18px; font-weight: 700;
    letter-spacing: -0.015em; color: var(--ink);
    line-height: 1.1;
  }
  .topbar-spacer { display: none; }                         /* let actions hug the row's flex */
  .topbar-actions {
    /* Force a uniform pill height. Equal heights across heterogeneous
       elements (pills, selects, buttons) is what the user called out. */
    --topbar-h: 40px;
    display: flex; flex-wrap: wrap; align-items: center;
    gap: 6px;
    /* flex-basis: 100% so this container takes the whole row when it wraps
       below the breadcrumb. Without it the container sized to its content
       (~450px) and overflowed the topbar — Refresh ended up clipped off the
       right edge regardless of flex-wrap on the children. */
    flex: 1 1 100%;
    min-width: 0;
    margin-left: 0;
  }
  .topbar-actions > * {
    height: var(--topbar-h);
    min-height: var(--topbar-h);
    box-sizing: border-box;
    display: inline-flex; align-items: center;
    font-size: 12.5px;
  }
  .topbar-actions .staleness-pill {
    padding: 0 10px; font-size: 11px;
  }
  .topbar-actions .snapshot-pill {
    padding: 0 10px; font-size: 12px;
  }
  .topbar-actions .snapshot-pill svg { display: none; }     /* drop the calendar icon */
  .topbar-actions .btn {
    padding: 0 12px; font-size: 12.5px; font-weight: 600;
  }
  .topbar-actions .btn svg { flex-shrink: 0; }

  /* WCAG 2.5.5: 44px hit boxes on touch surfaces */
  .icon-btn { min-width: 44px; min-height: 44px; padding: 10px; }
  .btn { min-height: 44px; }
  .nav-item { min-height: 44px; padding: 10px 12px; }
  .phase-chip { min-height: 36px; padding: 8px 12px; }
  .seg-toggle button { min-height: 36px; padding: 8px 12px; }
  .tbl td .btn,
  .tbl td .qr-link { min-height: 32px; }                    /* table-cell controls slightly smaller is OK */
  /* Topbar action override sits AFTER the .btn WCAG rule so it wins the
     cascade — otherwise Export / Refresh end up 44px while the pills are
     38px and the row looks jagged. The 40px height is still tall enough
     for a comfortable hit box (≥ 40px is fine for finger taps; WCAG is
     about 44 only for the strictest AAA case). */
  .topbar-actions > *,
  .topbar-actions > .btn {
    height: var(--topbar-h);
    min-height: var(--topbar-h);
  }

  /* Page tightening */
  .page { padding: 16px 12px 60px; }
  /* Body page title (the one inside .page) — different from the topbar
     breadcrumb leaf and a notch larger so it reads as the section header. */
  .page-title { font-size: 22px; font-weight: 700; letter-spacing: -0.015em; line-height: 1.15; }
  .page-sub { font-size: 12.5px; line-height: 1.45; color: var(--muted); }
  .page-head { gap: 6px; margin-bottom: 14px; }
  /* Activity strip already wraps; keep the gap tight on small screens.
     Chip geometry now matches phase-chip in the base rule — no override
     needed here. */
  .activity-strip { gap: 5px; }
  /* Toolbar: real padding so chips never sit on the border, consistent
     gaps so the Phase chips and More filters land on the same baseline. */
  .toolbar {
    padding: 12px 14px; gap: 8px;
    flex-wrap: wrap; row-gap: 8px;
    align-items: center;
  }
  /* The "More filters" button drops to its own line, pinned to the right
     edge so it doesn't sit inline with the Phase chips and create the
     "floating button at the end" look from the screenshot. */
  .toolbar .more-filters-btn { margin-left: auto; }
  .toolbar-divider { display: none; }                       /* divider's purpose is lost when wrapped */
  .toolbar .right { width: 100%; margin-left: 0 !important; }

  /* KPI grid: 2-up on mobile so values stay readable */
  .kpi-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .kpi-value { font-size: 26px; line-height: 1; }
  /* kpi-label inherits the shared eyebrow style (10.5px / Geist Mono /
     0.06em). Leaving it alone here keeps it consistent with the other
     uppercase labels (PHASE / FILTERS / etc.) on mobile. */
  .kpi-tile { padding: 12px 14px; }
  .kpi-foot { margin-top: 8px; font-size: 11.5px; }
  .kpi-row { gap: 4px; margin-top: 2px; }
  /* Completion strip stacks more tightly */
  .completion-pct .num { font-size: 32px; }
  .completion-pct .num small { font-size: 18px; }
  .completion-delta { margin-left: 0; width: 100%; }
  /* Tighten the trend chart's footer caption row */
  .trend-legend { flex-wrap: wrap; gap: 12px; font-size: 11.5px; }
  .trend-legend b { font-size: 16px; }
  .trend-tooltip { white-space: normal; max-width: 220px; font-size: 11px; }
  .trend-tooltip .t-pct { font-size: 13px; }
  /* Phase chips: a touch larger so the label + count breathe instead of
     looking cramped. The earlier `padding: 6px 0` on the toolbar wiped out
     our padding above — keep the chip-level tweaks here, the toolbar
     padding stays at 12px 14px set earlier. */
  .phase-chip {
    font-size: 12px; padding: 7px 12px;
    min-height: 32px;
    /* Override the 36px hit-box from above for visual consistency with the
       More filters button — keeps the row clean. */
  }
  .phase-chip-count { font-size: 11px; }

  /* Cards & charts */
  .card { border-radius: 10px; }
  .card-head {
    padding: 12px 14px; gap: 8px;
    flex-direction: column; align-items: flex-start;  /* stack title + actions */
  }
  .card-head > div:first-child { width: 100%; min-width: 0; }
  .card-head .actions { width: 100%; flex-wrap: wrap; }
  .card-body { padding: 12px 14px; }
  .card-head h2, .card-head h3 { font-size: 13px; }
  /* Trend chart was collapsing to ~100px tall at narrow widths */
  .trend-chart { height: 200px; }

  /* Tables: horizontal scroll already on .tbl-wrap; tighten cell padding */
  .tbl th, .tbl td { padding: 8px 10px; font-size: 12.5px; }

  /* Level chart (stacked): the 196px label column eats half a phone screen.
     Shrink to ~92px, drop the indent rails (the chevron + tinted bar carry
     enough hierarchy on their own), and hide the post-bar total so the bar
     itself gets every pixel it can. */
  .lvl-row { grid-template-columns: 92px 1fr; gap: 8px; }
  .lvl-row.d-1, .lvl-row.d-2 { gap: 8px; }
  .lvl-label { font-size: 11.5px; gap: 2px; }
  .lvl-indent { display: none; }
  .lvl-expand, .lvl-expand-spacer { width: 16px; height: 16px; }
  .lvl-row.d-1 .lvl-label-text { font-size: 11px; }
  .lvl-row.d-2 .lvl-label-text { font-size: 10.5px; }
  /* Subtle left-rail in the BAR instead of label rails — keeps hierarchy
     readable without spending label width on it. */
  .lvl-row.d-1 .lvl-bar { border-left: 2px solid color-mix(in oklch, var(--accent) 30%, transparent); }
  .lvl-row.d-2 .lvl-bar { border-left: 2px solid color-mix(in oklch, var(--accent) 20%, transparent); }
  .lvl-bar-wrap { gap: 8px; }
  .lvl-tail { min-width: 44px; gap: 4px; }
  .lvl-total { display: none; }   /* keep % only — saves ~40px on the row */
  .lvl-pct { font-size: 11.5px; }

  /* Nested breakdown table: shrink the indent rails so the first column
     doesn't burn the whole viewport width at depth 2. */
  .row-indent { width: 8px; margin-right: 1px; }

  /* Vertical bar chart: the existing SVG viewBox scales — but the new
     under-label chevron circle was getting cramped. Give the chart a bit
     more bottom padding by tightening label font here. */
  .x-label.depth-1, .x-label.depth-2 { font-size: 9.5px; }

  /* Drill panel: cover the screen on phones */
  .drill-panel { width: 100vw; max-width: none; }
  .drill-head { padding: 14px 16px 10px; }
  .drill-head-title { font-size: 15px; }
  .drill-foot { padding: 8px 16px; font-size: 11px; }
  .drill-body table.tbl th,
  .drill-body table.tbl td { padding: 8px 10px; font-size: 12px; }

  /* Topbar search box hidden via existing 1100px rule. Tighten breadcrumb. */
}

/* ---------- Phone (very small): 480px and below ---------- */
@media (max-width: 480px) {
  .topbar { padding: 8px 10px; }
  .crumb > :not(:last-child) { display: none; }
  .crumb { font-size: 12px; }

  /* Hide the sparkline next to small KPI values (it crashes into the value
     at narrow widths). The hero KPI keeps its meter — it's the headline. */
  .kpi-tile:not(.hero) .sparkline { display: none; }
  .kpi-row { justify-content: flex-start; }

  /* Stack KPIs vertically below ~480px so the value, label and delta have room */
  .kpi-grid { grid-template-columns: 1fr; gap: 10px; }

  .page { padding: 14px 10px 60px; }
  .card-head .actions .seg-toggle button span { display: none; }

  /* Completion strip on tiny screens: smaller headline */
  .completion-pct .num { font-size: 26px; }
  .completion-pct .num small { font-size: 16px; }

  /* Phase toolbar: shrink "More filters" and the legend so the toolbar fits */
  .toolbar .btn-ghost { padding: 6px 10px; font-size: 12px; min-height: 32px; }
  .legend { font-size: 11px; }
  .legend-dot { font-size: 10.5px; }
  /* Toolbar label moves to a row of its own at this size so the chips wrap
     into a clean grid instead of squeezing around the label. */
  .toolbar { padding: 10px 12px; gap: 6px; row-gap: 6px; }
  .toolbar-label { width: 100%; padding-right: 0; padding-bottom: 2px; }

  /* Card padding slightly tighter */
  .card-head { padding: 10px 12px; }
  .card-body { padding: 10px 12px; }

  /* Body page-title slightly smaller on tiny screens — but still bigger
     than 17px which was too thin to read as a header. */
  .page-title { font-size: 20px; font-weight: 700; }
  .page-sub { font-size: 12px; line-height: 1.45; }
  /* Topbar breadcrumb leaf is the visible page header on these widths;
     keep it large + bold so it reads as a title, not a crumb. */
  .crumb b { font-size: 17px; }
  /* Topbar action row tightens — Refresh stays 40px to match the rest. */
  .topbar-actions { --topbar-h: 38px; gap: 5px; }
  .topbar-actions .btn { padding: 0 10px; font-size: 12px; }
  .topbar-actions .snapshot-pill { padding: 0 8px; font-size: 11.5px; }
  .topbar-actions .staleness-pill { padding: 0 8px; font-size: 10.5px; }

  /* Tighten table cells across the board for narrowness */
  .tbl th, .tbl td { padding: 7px 8px; font-size: 12px; }
  .tbl code { font-size: 11px; }

  /* Level chart on tiny screens: drop the label column to 76px and trim the
     bar height. In-bar segment numbers vanish — the tooltip + drill panel
     still expose them. */
  .lvl-row { grid-template-columns: 76px 1fr; gap: 6px; }
  .lvl-label { font-size: 11px; }
  .lvl-bar { height: 18px; }
  .lvl-row.d-1 .lvl-bar { height: 14px; }
  .lvl-row.d-2 .lvl-bar { height: 11px; }
  .lvl-seg span { display: none; }   /* numbers wouldn't fit; rely on the tooltip */

  /* Indent rails go away entirely; depth comes from font + bar height alone */
  .row-indent { display: none; }
}

/* =========================================================================
   Drill panel markup thumbnail column + lightbox modal.
   ========================================================================= */
.drill-tbl .th-thumb { width: 76px; padding-right: 0; }
.drill-tbl .td-thumb { width: 76px; padding-right: 0; }
.drill-thumb {
  appearance: none; cursor: pointer;
  display: block; padding: 0;
  background: var(--surface-3);
  border: 1px solid var(--border);
  border-radius: 5px;
  width: 64px; height: 48px;
  overflow: hidden;
  transition: border-color 0.12s, transform 0.12s;
}
.drill-thumb:hover { border-color: var(--accent); transform: scale(1.03); }
.drill-thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.drill-thumb img {
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
.drill-thumb-empty {
  display: block; width: 64px; height: 48px;
  color: var(--muted-2);
  font: 12px 'Geist Mono', ui-monospace, monospace;
  text-align: center; line-height: 48px;
}

.lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: 5vh 4vw;
}
.lightbox-mask {
  position: absolute; inset: 0;
  background: color-mix(in oklch, #0a0e1a 70%, transparent);
  backdrop-filter: blur(2px);
  animation: lightbox-fade 0.16s ease;
}
@keyframes lightbox-fade { from { opacity: 0; } to { opacity: 1; } }
.lightbox-frame {
  position: relative; z-index: 1;
  max-width: 100%; max-height: 100%;
  display: flex; flex-direction: column; gap: 8px;
  animation: lightbox-pop 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes lightbox-pop {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1);    }
}
.lightbox-frame img {
  max-width: 100%; max-height: 80vh;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 24px 64px -16px color-mix(in oklch, #000 50%, transparent);
  background: var(--surface);
}
.lightbox-caption {
  text-align: center;
  font: 500 13px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.02em; color: rgba(255,255,255,0.92);
  text-shadow: 0 1px 2px rgba(0,0,0,0.4);
}
.lightbox-close {
  position: absolute; top: -12px; right: -12px; z-index: 2;
  appearance: none; cursor: pointer;
  width: 36px; height: 36px; padding: 0;
  border: none; border-radius: 999px;
  background: var(--surface);
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  color: var(--ink-2);
  display: flex; align-items: center; justify-content: center;
}
.lightbox-close:hover { background: var(--surface-2); color: var(--ink); }
@media (max-width: 480px) {
  .lightbox-close { top: 8px; right: 8px; }
}

/* =========================================================================
   Asset detail page — header card + lifecycle timeline.
   ========================================================================= */
/* =========================================================================
   SF9 velocity bar chart — positive completions go up in complete-green,
   newly-blocked counts go down in blocker-red. Shares the trend chart's
   tooltip styling so the experience switches cleanly.
   ========================================================================= */
.velo-bar { transition: filter 0.15s, opacity 0.15s; }
.velo-bar-pos { fill: var(--complete); }
.velo-bar-neg { fill: var(--blocker); opacity: 0.85; }
.velo-bar-pos:hover, .velo-bar-neg:hover { filter: brightness(1.1); }

/* =========================================================================
   SF5 saved views — sidebar "Saved" section with per-row delete affordance.
   ========================================================================= */
.nav-section-saved {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px;
}
.nav-section-action {
  appearance: none; cursor: pointer;
  background: transparent; border: 1px dashed var(--border-strong);
  border-radius: 4px;
  color: var(--accent);
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 2px 6px;
  transition: background 0.15s, border-color 0.15s;
}
.nav-section-action:hover {
  background: var(--accent-soft);
  border-color: var(--accent);
  border-style: solid;
}
.nav-saved-row {
  display: flex; align-items: stretch; gap: 0;
  position: relative;
}
.nav-saved-item {
  flex: 1; min-width: 0;
  padding-right: 32px;        /* room for the × button */
}
.nav-saved-label {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-weight: 500;
}
.nav-saved-delete {
  appearance: none; cursor: pointer;
  position: absolute; top: 50%; right: 4px;
  transform: translateY(-50%);
  width: 22px; height: 22px; padding: 0;
  background: transparent; border: none; border-radius: 4px;
  color: var(--muted-2);
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: opacity 0.12s, color 0.12s, background 0.12s;
}
.nav-saved-row:hover .nav-saved-delete,
.nav-saved-delete:focus-visible { opacity: 1; }
.nav-saved-delete:hover {
  background: color-mix(in oklch, var(--blocker) 14%, transparent);
  color: var(--blocker);
}
.nav-saved-empty {
  padding: 8px 14px 12px;
  font: 11.5px/1.4 'Geist', sans-serif;
  color: var(--muted-2); letter-spacing: -0.005em;
}

/* =========================================================================
   Forecast page (SF4) — overall ETA hero + per-level RAG table.
   ========================================================================= */
.forecast-overall-card { padding: 0; }
.forecast-overall {
  display: grid; grid-template-columns: minmax(180px, 1fr) 2fr minmax(180px, 1fr);
  gap: 24px;
  padding: 22px 28px;
  align-items: center;
}
.forecast-overall-pct {
  display: flex; flex-direction: column; gap: 6px;
}
.forecast-overall-pct .num {
  font: 600 44px/1 'Geist Mono', ui-monospace, monospace;
  letter-spacing: -0.02em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.forecast-overall-pct .num small {
  font-size: 26px; color: var(--muted-2);
  margin-left: 2px; font-weight: 500;
}
.forecast-overall-pct .lbl {
  font: 12px 'Geist', sans-serif; color: var(--muted);
  letter-spacing: -0.005em;
}
.forecast-overall-mid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px;
}
.forecast-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.forecast-meta-key {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}
.forecast-meta-val {
  font: 600 15px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: -0.005em; color: var(--ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.forecast-overall-target {
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px 16px;
  border-left: 1px solid var(--border);
  align-self: stretch; justify-content: center;
}
.forecast-target-label {
  display: flex; flex-direction: column; gap: 4px;
}
.forecast-target-label input[type="date"] {
  appearance: none;
  font: 500 13px 'Geist Mono', ui-monospace, monospace;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 6px;
  padding: 5px 8px; min-width: 0;
}
.forecast-target-rag {
  font: 600 12px 'Geist', sans-serif;
  letter-spacing: -0.005em;
  padding: 6px 10px; border-radius: 6px;
}
.forecast-target-rag.rag-green { color: var(--complete); background: color-mix(in oklch, var(--complete) 12%, transparent); }
.forecast-target-rag.rag-amber { color: var(--outstanding); background: color-mix(in oklch, var(--outstanding) 14%, transparent); }
.forecast-target-rag.rag-red   { color: var(--blocker);    background: color-mix(in oklch, var(--blocker)    14%, transparent); }

/* ETA cell tinting */
.forecast-eta {
  font: 500 12.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
.forecast-eta.eta-green    { color: var(--complete);    font-weight: 600; }
.forecast-eta.eta-amber    { color: var(--outstanding); font-weight: 600; }
.forecast-eta.eta-red      { color: var(--blocker);     font-weight: 700; }
.forecast-eta.eta-flat     { color: var(--muted-2); font-style: italic; }
.forecast-eta.eta-neutral  { color: var(--ink-2); }

.forecast-slope {
  font: 500 12.5px 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}
.forecast-slope.pos { color: var(--complete); }
.forecast-slope.neg { color: var(--blocker); }

.forecast-status {
  display: inline-flex; align-items: baseline; gap: 4px;
  font: 600 11.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.forecast-status.status-green   { color: var(--complete); }
.forecast-status.status-amber   { color: var(--outstanding); }
.forecast-status.status-red     { color: var(--blocker); }
.forecast-status.status-flat    { color: var(--muted-2); }
.forecast-status.status-neutral { color: var(--muted); }
.forecast-status-delta {
  font-weight: 500; color: var(--muted); letter-spacing: 0;
  text-transform: none;
}

/* Subtle row tinting reinforces the RAG without dominating */
.tbl tr.rag-row.rag-amber td.first-col::before,
.tbl tr.rag-row.rag-red td.first-col::before {
  content: ""; display: inline-block;
  width: 4px; height: 4px; border-radius: 999px;
  margin-right: 8px; vertical-align: 2px;
}
.tbl tr.rag-row.rag-amber td.first-col::before { background: var(--outstanding); }
.tbl tr.rag-row.rag-red   td.first-col::before { background: var(--blocker); }

@media (max-width: 760px) {
  .forecast-overall {
    grid-template-columns: 1fr;
    padding: 16px 18px;
  }
  .forecast-overall-mid { grid-template-columns: 1fr 1fr; }
  .forecast-overall-target {
    border-left: none; border-top: 1px solid var(--border);
    padding: 14px 0 0;
  }
}

/* =========================================================================
   Movement page — snapshot diff, summary tiles, transition matrix.
   ========================================================================= */
.movement-pickers {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.movement-picker {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2);
}
.movement-picker-key {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}
.movement-picker select {
  appearance: none; background: transparent; border: none; outline: none;
  font: 500 13px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.02em; color: var(--ink); cursor: pointer;
}
.movement-arrow {
  font: 600 18px 'Geist Mono', ui-monospace, monospace;
  color: var(--muted);
}
.movement-warn {
  color: var(--blocker); font: 500 12px 'Geist', sans-serif;
}
.movement-trail {
  font: 13px 'Geist', sans-serif; color: var(--muted);
  letter-spacing: -0.005em;
}
.movement-trail b { color: var(--ink); font-weight: 600; }

.movement-summary {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  margin: 12px 0 var(--gap);
}
.movement-tile {
  display: flex; flex-direction: column; gap: 4px;
  padding: 14px 16px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.08s;
}
.movement-tile:active { transform: translateY(1px); }
.movement-tile:hover { background: var(--surface-2); }
.movement-tile.held { cursor: default; opacity: 0.7; }
.movement-tile.held:hover { background: var(--surface); }
.movement-tile.up { border-left: 3px solid var(--complete); }
.movement-tile.down { border-left: 3px solid var(--blocker); }
.movement-tile.warn { border-left: 3px solid var(--outstanding); }
.movement-tile.resolved { border-left: 3px solid var(--accent); }
.movement-tile.held { border-left: 3px solid var(--muted-2); }
.movement-tile-num {
  font: 600 22px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.movement-tile.up .movement-tile-num { color: var(--complete); }
.movement-tile.down .movement-tile-num { color: var(--blocker); }
.movement-tile.warn .movement-tile-num { color: var(--outstanding); }
.movement-tile.resolved .movement-tile-num { color: var(--accent); }
.movement-tile-lbl {
  font: 11.5px 'Geist', sans-serif; color: var(--muted);
}

.movement-matrix { overflow-x: auto; }
.movement-table {
  width: 100%; border-collapse: separate; border-spacing: 6px;
  font: 13px 'Geist', sans-serif;
}
.movement-table th, .movement-table td { padding: 0; }
.movement-corner {
  background: transparent;
  font: 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted-2); text-align: right;
  padding-right: 12px;
}
.movement-col-head, .movement-row-head {
  font: 600 11px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--surface-2);
  text-align: left;
}
.movement-col-head { text-align: center; min-width: 110px; }
.movement-col-head.st-c, .movement-row-head.st-c { color: var(--complete); }
.movement-col-head.st-b, .movement-row-head.st-b { color: var(--blocker); }
.movement-col-head.st-o, .movement-row-head.st-o { color: var(--outstanding); }
.movement-cell {
  border-radius: 8px;
  padding: 18px 12px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  background: var(--surface-2);
  position: relative;
  min-width: 110px;
  cursor: pointer;
  transition: background 0.15s, transform 0.08s, box-shadow 0.15s;
}
.movement-cell.is-zero {
  cursor: default; color: var(--muted-2); opacity: 0.55;
}
.movement-cell.is-active:hover {
  background: color-mix(in oklch, var(--accent) 14%, var(--surface-2));
  box-shadow: inset 0 0 0 1px var(--accent);
}
.movement-cell.is-diag { background: color-mix(in oklch, var(--accent) 7%, var(--surface)); cursor: default; }
.movement-cell.is-diag:hover { background: color-mix(in oklch, var(--accent) 7%, var(--surface)); box-shadow: none; }
.movement-cell-num {
  display: block;
  font: 600 18px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.movement-cell.st-c .movement-cell-num { color: var(--complete); }
.movement-cell.st-b .movement-cell-num { color: var(--blocker); }
.movement-cell.st-o .movement-cell-num { color: var(--outstanding); }
.movement-cell.is-zero .movement-cell-num { color: var(--muted-2); }
.movement-cell-flow {
  display: block; margin-top: 4px;
  font: 600 10px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.movement-arrow-tiny { margin: 0 3px; color: var(--muted-2); }
.movement-rowtotal-head, .movement-rowtotal, .movement-coltotal, .movement-grandtotal {
  font: 500 12px 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  text-align: center;
  padding: 8px;
}
.movement-grandtotal {
  font-weight: 700; color: var(--ink);
}
.movement-rowtotal-head { color: var(--muted-2); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; }
@media (max-width: 760px) {
  .movement-cell { min-width: 80px; padding: 12px 6px; }
  .movement-cell-num { font-size: 15px; }
  .movement-col-head { min-width: 80px; font-size: 10px; padding: 6px 8px; }
  .movement-row-head { font-size: 10px; padding: 6px 8px; }
}

/* =========================================================================
   Plan vs Actual — settings strip, tracking-metric card, trend overlay line.
   ========================================================================= */
.plan-settings-card { padding: 14px 22px; }
.plan-settings-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px 18px; align-items: end;
}
.plan-settings-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.plan-settings-field-narrow { max-width: 130px; }
.plan-settings-key {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}
.plan-settings-input-wrap {
  display: inline-flex; align-items: stretch; gap: 0;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface-2);
  overflow: hidden;
}
.plan-settings-input-wrap input,
.plan-settings-field input[type="date"] {
  appearance: none; border: none; outline: none;
  background: var(--surface-2); color: var(--ink);
  font: 500 13px 'Geist Mono', ui-monospace, monospace;
  padding: 6px 10px; min-width: 0; flex: 1;
  color-scheme: light dark;
}
.plan-settings-field input[type="date"] {
  border: 1px solid var(--border); border-radius: 6px;
}
.plan-settings-unit {
  padding: 6px 8px;
  font: 500 11px 'Geist Mono', ui-monospace, monospace;
  color: var(--muted);
  background: var(--surface);
  border-left: 1px solid var(--border);
}
.plan-settings-hint {
  font: 11px 'Geist Mono', ui-monospace, monospace;
  color: var(--muted-2);
}

.plan-metric-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
}
.plan-metric {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--surface-2);
}
.plan-metric-key {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}
.plan-metric-val {
  font: 600 22px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.plan-metric-unit { font-size: 12px; font-weight: 500; color: var(--muted-2); margin-left: 2px; }
.plan-metric-sub {
  font: 11.5px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--muted);
}
/* Delta tones */
.plan-metric-delta.tone-up   .plan-metric-val { color: var(--complete); }
.plan-metric-delta.tone-down .plan-metric-val { color: var(--blocker); }
.plan-metric-delta.tone-neutral .plan-metric-val { color: var(--ink-2); }
/* Required-rate / status tones */
.plan-metric-required.ok,
.plan-metric-status.ok        { border-color: color-mix(in oklch, var(--complete) 40%, var(--border)); }
.plan-metric-required.ok      .plan-metric-val { color: var(--complete); }
.plan-metric-required.warn,
.plan-metric-status.warn      { border-color: color-mix(in oklch, var(--blocker) 40%, var(--border)); }
.plan-metric-required.warn    .plan-metric-val { color: var(--blocker); }
.plan-metric-required.neutral .plan-metric-val { color: var(--ink-2); }
.plan-metric-status.ok    .plan-metric-status-label { color: var(--complete); }
.plan-metric-status.warn  .plan-metric-status-label { color: var(--blocker);  }
.plan-metric-status-label { font-size: 18px; font-weight: 700; letter-spacing: -0.005em; }

/* Trend chart dashed planned-line overlay */
.trend-chart .trend-plan {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-dasharray: 5 4;
  opacity: 0.85;
}
.trend-chart .trend-plan:hover { opacity: 1; }
.legend .legend-dot.plan::before {
  background: transparent; box-shadow: none;
  border-top: 1.5px dashed var(--accent);
  width: 14px; height: 0;
  transform: translateY(5px);
}

/* =========================================================================
   "More filters" drawer + chip strip + toolbar button badge.
   ========================================================================= */
.more-filters-btn { position: relative; }
.more-filters-btn.is-active {
  color: var(--accent);
  border-color: color-mix(in oklch, var(--accent) 35%, transparent);
  background: var(--accent-soft);
}
.more-filters-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  margin-left: 6px;
  background: var(--accent); color: #fff;
  border-radius: 999px;
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}

/* Filter chips applied below the Phase toolbar — visually attached to it
   so it reads as a single "page filters" group, not two separate
   containers. The `.toolbar:has(+ .filter-chip-strip)` rule above zeros
   the toolbar's bottom margin and rounding so the two cards merge into
   one panel; this rule mirrors the geometry on the bottom half. */
.filter-chip-strip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: none;                                /* attach to toolbar above */
  border-radius: 0 0 var(--radius) var(--radius);
  padding: 8px 12px;
  margin: 0 0 16px;                                /* sit flush below toolbar */
}
.filter-chip-label {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
  margin-right: 6px;
}
.filter-chip {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 6px 3px 10px; border-radius: 999px;
  background: var(--accent-soft);
  border: 1px solid color-mix(in oklch, var(--accent) 25%, transparent);
  color: var(--accent);
  font: 500 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -0.005em;
  transition: background 0.12s, border-color 0.12s;
}
.filter-chip:hover {
  background: color-mix(in oklch, var(--accent) 18%, transparent);
}
.filter-chip > span {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 999px;
  background: color-mix(in oklch, var(--accent) 28%, transparent);
  font-size: 11px; line-height: 1;
}
.filter-chip-clear {
  appearance: none; cursor: pointer;
  background: transparent; border: none;
  color: var(--muted); font: 600 11px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.04em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 4px;
  margin-left: 4px;
}
.filter-chip-clear:hover { color: var(--blocker); background: var(--surface-2); }

/* The filter drawer itself */
.fp-mask {
  position: fixed; inset: 0; background: rgba(15, 23, 41, 0.36);
  z-index: 110; opacity: 0; pointer-events: none;
  transition: opacity 0.2s;
}
.fp-mask.is-open { opacity: 1; pointer-events: auto; }
.fp-panel {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: min(560px, 92vw); background: var(--surface);
  z-index: 111; box-shadow: -8px 0 32px rgba(0,0,0,0.12);
  display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform 0.25s ease;
}
.fp-panel.is-open { transform: translateX(0); }
.fp-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 18px 22px 14px;
  border-bottom: 1px solid var(--border);
}
.fp-eyebrow {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent);
}
.fp-title { font-size: 18px; font-weight: 600; margin: 4px 0 0; letter-spacing: -0.01em; }
.fp-meta {
  margin-top: 6px;
  font: 12px 'Geist', ui-sans-serif, system-ui, sans-serif; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.fp-head-actions { display: flex; align-items: center; gap: 6px; }

.fp-body { flex: 1; overflow-y: auto; padding: 14px 22px 8px; }
.fp-section { margin-bottom: 18px; }
.fp-section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 8px;
}
.fp-section-title {
  font: 600 11px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink);
}
.fp-section-meta {
  font: 11px 'Geist Mono', ui-monospace, monospace;
  color: var(--muted);
}
.fp-section-body {
  display: flex; flex-wrap: wrap; gap: 6px;
}

.fp-chip {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--ink-2);
  font: 500 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -0.005em;
  transition: background 0.12s, border-color 0.12s, color 0.12s, transform 0.06s;
}
.fp-chip:hover { background: var(--surface-3); }
.fp-chip:active { transform: translateY(1px); }
.fp-chip.is-on {
  background: var(--accent-soft); color: var(--accent);
  border-color: color-mix(in oklch, var(--accent) 35%, transparent);
  font-weight: 600;
}
.fp-chip.tone-c.is-on { color: var(--complete);    border-color: color-mix(in oklch, var(--complete)    40%, transparent); background: color-mix(in oklch, var(--complete) 12%, transparent); }
.fp-chip.tone-b.is-on { color: var(--blocker);     border-color: color-mix(in oklch, var(--blocker)     40%, transparent); background: color-mix(in oklch, var(--blocker)  12%, transparent); }
.fp-chip.tone-o.is-on { color: var(--outstanding); border-color: color-mix(in oklch, var(--outstanding) 40%, transparent); background: color-mix(in oklch, var(--outstanding) 12%, transparent); }

.fp-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 12px 22px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  font: 12px 'Geist', ui-sans-serif, system-ui, sans-serif; color: var(--muted);
}
.fp-foot .btn-primary {
  appearance: none; cursor: pointer;
  background: var(--accent); color: #fff;
  border: 1px solid var(--accent); border-radius: 6px;
  padding: 6px 14px; font: 600 12.5px 'Geist', sans-serif;
  letter-spacing: -0.005em;
}
.fp-foot .btn-primary:hover { filter: brightness(1.1); }

@media (max-width: 480px) {
  .fp-panel { width: 100vw; }
}

/* DM1 — Assignee + Due cells on BlockersPage and inline in DrillPanel. */
.qr-assignee {
  font: 500 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 160px;
  color: var(--ink-2);
}
.qr-due {
  font: 500 12px 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  white-space: nowrap;
}
.qr-due.is-overdue { color: var(--blocker); font-weight: 700; }
.qr-due-flag {
  display: inline-block;
  font: 600 9.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  background: var(--blocker); color: #fff;
  padding: 1px 5px; border-radius: 3px;
  margin-left: 6px; vertical-align: 1px;
}

.drill-qr-cell {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.drill-qr-meta {
  font: 11.5px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--muted);
  padding-left: 8px; border-left: 1px solid var(--border);
}
.drill-qr-due {
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 11px;
}

/* Blocker ageing — colour the age cell and tint the row when stale. */
.blocker-age {
  font: 500 12px 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}
.blocker-since {
  color: var(--muted); font-weight: 400; font-size: 10.5px;
  letter-spacing: 0.02em;
}
.tbl tr.tone-warn .blocker-age {
  color: var(--outstanding); font-weight: 600;
}
.tbl tr.tone-warn td.first-col::before {
  content: ""; display: inline-block;
  width: 4px; height: 4px; border-radius: 999px;
  background: var(--outstanding); margin-right: 8px;
  vertical-align: 2px;
}
.tbl tr.tone-severe .blocker-age {
  color: var(--blocker); font-weight: 700;
}
.tbl tr.tone-severe td.first-col::before {
  content: ""; display: inline-block;
  width: 4px; height: 4px; border-radius: 999px;
  background: var(--blocker); margin-right: 8px;
  vertical-align: 2px;
}

/* Inline asset code link — used in DrillPanel and Assets page tables so the
   code in any list can jump to the asset detail page. */
.asset-link {
  appearance: none; cursor: pointer;
  background: transparent; border: none; padding: 0;
  font: inherit; color: inherit;
  border-bottom: 1px dashed transparent;
  transition: border-color 0.12s, color 0.12s;
}
.asset-link:hover, .asset-link:focus-visible {
  color: var(--accent);
  border-bottom-color: color-mix(in oklch, var(--accent) 50%, transparent);
  outline: none;
}
.asset-link code { font: inherit; }

.asset-card { overflow: hidden; }
.asset-head { padding: 8px 4px; }
.asset-head-left { display: flex; flex-direction: column; gap: 14px; }
.asset-code-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.asset-code {
  font: 600 18px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: -0.005em;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px 10px; color: var(--ink);
}
.asset-meta-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px 24px;
}
.asset-meta-cell { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.asset-meta-key {
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
}
.asset-meta-val {
  font: 500 13px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--ink); letter-spacing: -0.005em;
  word-break: break-word;
}
.asset-sources {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  border-top: 1px solid var(--border);
  padding-top: 12px;
}
.asset-sources > span:last-child {
  display: inline-flex; flex-wrap: wrap; gap: 6px;
}
.asset-source-chip {
  display: inline-block;
  font: 500 11px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.02em;
  background: var(--accent-soft);
  color: var(--accent);
  padding: 2px 8px; border-radius: 999px;
  border: 1px solid color-mix(in oklch, var(--accent) 22%, transparent);
}

.lifecycle-list { display: flex; flex-direction: column; }
.lifecycle-row {
  display: grid;
  grid-template-columns: 140px 140px 1fr 96px;
  align-items: center; gap: 16px;
  padding: 12px var(--pad);
  border-bottom: 1px solid var(--border);
  transition: background 0.15s;
}
.lifecycle-row:last-child { border-bottom: none; }
.lifecycle-row:hover { background: var(--surface-2); }
.lifecycle-row.is-change > .lifecycle-state { font-weight: 600; }
.lifecycle-row.is-latest > .lifecycle-date {
  display: flex; align-items: center; gap: 8px; font-weight: 600;
}
.lifecycle-date {
  font: 500 12.5px 'Geist Mono', ui-monospace, monospace;
  color: var(--ink-2); letter-spacing: 0.02em;
}
.lifecycle-latest {
  display: inline-block;
  font: 600 9.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.08em; text-transform: uppercase;
  background: var(--accent-soft); color: var(--accent);
  padding: 2px 6px; border-radius: 4px;
}
.lifecycle-state {
  display: flex; align-items: center; gap: 8px;
}
.lifecycle-change-mark {
  color: var(--accent);
  font-family: 'Geist Mono', ui-monospace, monospace;
  font-size: 14px; line-height: 1;
}
.lifecycle-qr {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 12px;
  min-width: 0;
}
.lifecycle-qr-id code {
  font: 500 12px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.01em; color: var(--ink-2);
}
.lifecycle-qr-meta {
  font: 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--muted);
}
.lifecycle-qr-empty {
  font: italic 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--muted-2);
}
.lifecycle-qr-actions {
  margin-left: auto; display: inline-flex; gap: 6px;
}
.lifecycle-qr-actions .btn { padding: 3px 8px; font-size: 11px; min-height: 0; }
.lifecycle-thumb {
  width: 96px; height: 60px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; border-radius: 6px;
  background: var(--surface-3);
  border: 1px solid var(--border);
}
.lifecycle-thumb img {
  width: 100%; height: 100%; object-fit: cover;
  display: block;
  transition: transform 0.2s;
}
.lifecycle-thumb a:hover img { transform: scale(1.04); }
.lifecycle-thumb-empty {
  color: var(--muted-2);
  font: 12px 'Geist Mono', ui-monospace, monospace;
}
@media (max-width: 760px) {
  .lifecycle-row {
    grid-template-columns: 1fr;
    gap: 6px; padding: 12px;
  }
  .lifecycle-thumb {
    width: 100%; height: 140px;
    margin-top: 4px;
  }
  .lifecycle-qr-actions { margin-left: 0; }
}

/* =========================================================================
   Sortable column headers — three-state cycle (default → desc → asc →
   default). Arrow indicator on the right.
   ========================================================================= */
.tbl th.th-sortable {
  cursor: pointer; user-select: none;
  transition: color 0.15s, background 0.15s;
}
.tbl th.th-sortable:hover { color: var(--ink); background: var(--surface-3); }
.tbl th.th-sortable .th-arrow {
  margin-left: 4px;
  font-size: 9px; color: var(--accent);
  font-family: 'Geist Mono', ui-monospace, monospace;
  display: inline-block; min-width: 8px;
}
.tbl th.th-sortable.is-sorted { color: var(--ink); }
.tbl th.th-sortable.num { text-align: right; }
.tbl th.th-sortable.num .th-arrow { float: right; margin-left: 0; }

/* =========================================================================
   Row kebab menu — per-row actions (Copy codes, Export slice CSV).
   Hidden until row hover or button focus.
   ========================================================================= */
.row-menu { position: relative; display: inline-block; margin-left: 6px; vertical-align: middle; }
.row-menu-btn {
  appearance: none; cursor: pointer;
  width: 22px; height: 22px; padding: 0;
  background: transparent; border: 1px solid transparent;
  border-radius: 5px;
  color: var(--muted); font: 600 14px/1 'Geist', system-ui, sans-serif;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: opacity 0.12s, background 0.12s, color 0.12s, border-color 0.12s;
}
.tbl tr:hover .row-menu-btn,
.tbl tr:focus-within .row-menu-btn,
.row-menu-btn:focus-visible,
.row-menu-btn.is-open { opacity: 1; }
.row-menu-btn:hover, .row-menu-btn.is-open {
  background: var(--surface-3); color: var(--ink);
  border-color: var(--border);
}
.row-menu-pop {
  position: absolute; top: 28px; left: 0; min-width: 220px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 12px 32px -8px color-mix(in oklch, var(--ink) 22%, transparent);
  z-index: 60; overflow: hidden;
  animation: row-menu-in 0.14s ease;
}
@keyframes row-menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.row-menu-head {
  padding: 8px 12px; border-bottom: 1px solid var(--border);
  font: 600 10.5px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 280px;
}
.row-menu-item {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; width: 100%; padding: 9px 12px;
  background: transparent; border: none; cursor: pointer;
  text-align: left; font: 500 12.5px 'Geist', system-ui, sans-serif;
  color: var(--ink-2);
  letter-spacing: -0.005em;
}
.row-menu-item:hover { background: var(--accent-soft); color: var(--ink); }
.row-menu-hint {
  font: 10.5px 'Geist Mono', ui-monospace, monospace;
  color: var(--muted);
}

/* =========================================================================
   Recent activity strip on Overview — three deltas vs the previous
   snapshot. Each chip drills into the changed assets.
   ========================================================================= */
.activity-strip {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 0;
  font: 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--muted);
  margin-bottom: var(--gap);
}
.activity-chip {
  appearance: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
  /* Match the phase-chip pill geometry so the row reads as one family of
     filterable affordances. Previously the activity chips had thicker
     padding + heavier weight that made them feel like a different
     component. Width/padding/weight now mirror .phase-chip exactly. */
  padding: 7px 12px; border-radius: 999px; min-height: 34px;
  font: 400 12px 'Geist', ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -0.005em;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-2);
  transition: background 0.15s, border-color 0.15s, transform 0.06s;
}
.activity-chip:hover:not(:disabled) { background: var(--surface-2); }
.activity-chip:active:not(:disabled) { transform: translateY(-1px); }
.activity-chip:disabled { opacity: 0.4; cursor: default; }
.activity-chip .activity-arrow {
  display: inline-flex; width: 14px; height: 14px; align-items: center; justify-content: center;
  font-size: 13px; line-height: 1;
}
.activity-chip .activity-num {
  font: 600 13px 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}
.activity-chip .activity-lbl { color: var(--muted); font-weight: 500; }
.activity-chip.up {
  border-color: color-mix(in oklch, var(--complete) 28%, var(--border));
  color: var(--complete);
}
.activity-chip.up .activity-num,
.activity-chip.up .activity-lbl { color: var(--complete); }
.activity-chip.up .activity-arrow { color: var(--complete); }
.activity-chip.down {
  border-color: color-mix(in oklch, var(--blocker) 28%, var(--border));
  color: var(--blocker);
}
.activity-chip.down .activity-num,
.activity-chip.down .activity-lbl { color: var(--blocker); }
.activity-chip.warn {
  border-color: color-mix(in oklch, var(--outstanding) 32%, var(--border));
  color: var(--outstanding);
}
.activity-chip.warn .activity-num,
.activity-chip.warn .activity-lbl { color: var(--outstanding); }
.activity-since {
  margin-left: 4px; color: var(--muted-2);
  font: 11.5px 'Geist Mono', ui-monospace, monospace;
}
@media (max-width: 480px) {
  .activity-since { width: 100%; margin-left: 0; }
}

/* =========================================================================
   Command palette — ⌘K / Ctrl+K overlay. Sits above everything (z=200) so
   it floats over the drill panel + tweaks drawer. Spotlight backdrop, big
   input, results list with kbd hints.
   ========================================================================= */
.palette-mask {
  position: fixed; inset: 0;
  background: color-mix(in oklch, #0a0e1a 28%, transparent);
  backdrop-filter: blur(2px);
  z-index: 200;
  animation: palette-fade-in 0.14s ease;
}
.palette {
  position: fixed; left: 50%; top: 14vh;
  transform: translateX(-50%);
  width: min(620px, 92vw);
  max-height: 72vh;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 24px 64px -16px color-mix(in oklch, var(--ink) 24%, transparent);
  display: flex; flex-direction: column;
  z-index: 201;
  overflow: hidden;
  animation: palette-pop-in 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes palette-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes palette-pop-in {
  from { opacity: 0; transform: translateX(-50%) translateY(-6px) scale(0.985); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0)    scale(1);     }
}
.palette-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
  color: var(--muted);
}
.palette-head input {
  flex: 1; border: none; outline: none; background: transparent;
  font: 500 15px/1.3 'Geist', ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -0.005em; color: var(--ink);
}
.palette-head input::placeholder { color: var(--muted); }
.palette-head kbd {
  font: 10px 'Geist Mono', ui-monospace, monospace;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 4px; padding: 2px 6px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.palette-body {
  flex: 1; overflow-y: auto; padding: 6px 0;
}
.palette-row {
  display: grid; grid-template-columns: 110px 1fr auto;
  align-items: center; gap: 12px;
  width: 100%; padding: 9px 14px;
  background: transparent; border: none; cursor: pointer;
  text-align: left; font: inherit; color: var(--ink-2);
}
.palette-row:hover, .palette-row.is-active {
  background: var(--accent-soft);
  color: var(--ink);
}
.palette-row.is-active { box-shadow: inset 2px 0 0 var(--accent); }
.palette-kind {
  font: 600 10px 'Geist Mono', ui-monospace, monospace;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.palette-row.kind-asset .palette-kind     { color: var(--accent); }
.palette-row.kind-qr .palette-kind        { color: var(--blocker); }
.palette-row.kind-level .palette-kind     { color: var(--complete); }
.palette-row.kind-category .palette-kind  { color: var(--outstanding); }
.palette-row.kind-view .palette-kind      { color: var(--muted-2); }
.palette-label {
  font: 500 13.5px 'Geist', ui-sans-serif, system-ui, sans-serif;
  letter-spacing: -0.005em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.palette-row.kind-asset .palette-label,
.palette-row.kind-qr .palette-label {
  font-family: 'Geist Mono', ui-monospace, monospace; font-size: 12.5px;
}
.palette-sub {
  font: 11.5px 'Geist', ui-sans-serif, system-ui, sans-serif;
  color: var(--muted); text-align: right;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 240px;
}
.palette-empty {
  padding: 28px 14px; text-align: center;
  font: 13px 'Geist', ui-sans-serif, system-ui, sans-serif; color: var(--muted);
}
.palette-foot {
  display: flex; align-items: center; gap: 16px;
  padding: 8px 14px; border-top: 1px solid var(--border);
  background: var(--surface-2);
  font: 11px 'Geist', ui-sans-serif, system-ui, sans-serif; color: var(--muted);
}
.palette-foot kbd {
  font: 10px 'Geist Mono', ui-monospace, monospace;
  background: var(--surface-3); border: 1px solid var(--border);
  border-radius: 3px; padding: 1px 5px; margin-right: 3px;
  color: var(--muted);
}
@media (max-width: 480px) {
  .palette { top: 8vh; max-height: 84vh; }
  .palette-row { grid-template-columns: 86px 1fr; row-gap: 2px; }
  .palette-sub { grid-column: 1 / -1; text-align: left; max-width: none; }
  .palette-foot { gap: 10px; }
}

/* =========================================================================
   Boot skeleton — rendered by index.html before any JS executes. Coarsely
   mirrors the real layout so the page feels alive immediately. Pulses with
   a single CSS keyframe; respects prefers-reduced-motion below.
   ========================================================================= */
.boot-skeleton {
  display: grid; grid-template-columns: 232px 1fr;
  min-height: 100dvh; background: var(--bg);
}
.boot-sidebar {
  border-right: 1px solid var(--border);
  padding: 16px 14px; display: flex; flex-direction: column; gap: 14px;
  background: var(--surface);
}
.boot-brand { display: flex; align-items: center; gap: 10px; }
.boot-nav { display: flex; flex-direction: column; gap: 8px; }
.boot-main { display: flex; flex-direction: column; min-width: 0; }
.boot-topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 24px; border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.boot-page { padding: 22px 28px; display: flex; flex-direction: column; gap: 14px; max-width: 1480px; width: 100%; margin: 0 auto; }
.boot-kpi-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  margin: 4px 0 6px;
}
.sk {
  display: block; background: var(--surface-3); border-radius: 6px;
  position: relative; overflow: hidden;
  animation: sk-pulse 1.6s ease-in-out infinite;
}
.sk-brand     { width: 140px; height: 28px; border-radius: 6px; }
.sk-nav       { height: 32px; border-radius: 8px; }
.sk-nav-section { height: 14px; width: 70%; margin-top: 8px; opacity: 0.55; }
.sk-crumb     { height: 14px; width: 220px; }
.sk-pill      { height: 32px; width: 96px; border-radius: 999px; margin-left: auto; }
.sk-pill + .sk-pill { margin-left: 8px; }
.sk-title     { height: 26px; width: 320px; max-width: 60%; }
.sk-sub       { height: 14px; width: 460px; max-width: 80%; opacity: 0.7; }
.sk-kpi       { height: 92px; border-radius: 12px; }
.sk-card      { height: 220px; border-radius: 14px; }
.sk-card-tall { height: 320px; }
@keyframes sk-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}
@media (prefers-reduced-motion: reduce) {
  .sk { animation: none; opacity: 0.7; }
}
@media (max-width: 760px) {
  .boot-skeleton { grid-template-columns: 1fr; }
  .boot-sidebar  { display: none; }
  .boot-topbar   { padding: 10px 12px; }
  .boot-page     { padding: 16px 12px; }
  .boot-kpi-grid { grid-template-columns: 1fr 1fr; }
}
