/* Dense dashboard stylesheet for 100" 4K displays.
 * Every scene for a page is rendered simultaneously in a CSS grid — no
 * rotation. Type is small (14px base) and tiles are compact so the screen
 * carries as much information as possible. Status colours stay vivid for
 * across-the-room glanceability. */

:root {
  --bg: #0a0e14;
  --bg-elev: #131922;
  --bg-elev-2: #1b2330;
  --fg: #e6edf3;
  --muted: #7a8a9a;
  --dim: #4a5868;
  --border: #232c3a;

  --ok: #2ea043;
  --ok-bright: #56d364;
  --fail: #f85149;
  --fail-bright: #ff7b72;
  --running: #1f6feb;
  --running-bright: #58a6ff;
  --warn: #d29922;
  --pending: #8b949e;
  --skipped: #484f58;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
    "Courier New", monospace;

  /* Fluid root. The whole UI is rem-based, so scaling this one value scales
   * everything together. Without it the design is pinned to CSS pixels: it
   * looks tiny on a high-CSS-px computer monitor (e.g. 4K at 100% scaling) but
   * large on the 98" TV, whose browser exposes only a ~1080p layout viewport.
   * 0.52vw ≈ the old 14px at a ~2700px-wide reference; clamp() keeps it sane on
   * extreme viewports. CALIBRATE the 0.52vw on the real TV + a computer so that
   * 100% browser zoom looks right on both. */
  font-size: clamp(9px, 0.52vw, 24px);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

a { color: inherit; text-decoration: none; }
code { font-family: var(--mono); }
.muted { color: var(--muted); }
.dim { color: var(--dim); }

/* Index landing */
body.index {
  display: grid;
  place-items: center;
  padding: 4rem;
  overflow: auto;
}
body.index main { max-width: 60rem; }
body.index h1 { font-size: 3rem; margin: 0 0 1rem; }
body.index ul { list-style: none; padding: 0; line-height: 2.4; font-size: 1.4rem; }
body.index a { color: var(--running-bright); }

/* Screen layout */
body.screen { display: grid; grid-template-rows: auto 1fr; }

.screen-header {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 0.5rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elev);
}
.screen-header .brand {
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.04em;
}
.screen-header .scene-title {
  text-align: center;
  font-size: 1rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--muted);
}
.screen-header .pagenav {
  display: flex;
  justify-content: center;
  gap: 1.6rem;
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-weight: 600;
}
.screen-header .pagenav a {
  color: var(--muted);
  text-decoration: none;
  padding: 0.15rem 0.25rem;
  border-bottom: 2px solid transparent;
  transition: color 200ms, border-color 200ms;
}
.screen-header .pagenav a:hover { color: var(--fg); }
body[data-page="now"]       .pagenav a[data-link-page="now"],
body[data-page="trends"]    .pagenav a[data-link-page="trends"],
body[data-page="issues"]    .pagenav a[data-link-page="issues"],
body[data-page="sprint"]    .pagenav a[data-link-page="sprint"],
body[data-page="personal"]  .pagenav a[data-link-page="personal"],
body[data-page="artifacts"] .pagenav a[data-link-page="artifacts"],
body[data-page="links"]     .pagenav a[data-link-page="links"] {
  color: var(--running-bright);
  border-bottom-color: var(--running-bright);
  font-weight: 800;
}
.screen-header .clock {
  text-align: right;
  font-family: var(--mono);
  font-size: 1rem;
  letter-spacing: 0.05em;
}

/* Scene grid — every scene for a page renders simultaneously. */
.scene-host {
  display: grid;
  gap: 0.4rem;
  padding: 0.4rem;
  height: 100%;
  overflow: hidden;
  min-height: 0;
}
body[data-page="now"] .scene-host {
  /* Two scenes only: the Pipeline Wall fills the page, the Group Runners
   * strip sits full-width across the bottom. The wall is the
   * highest-priority scene on /screen/now — it takes all the vertical
   * share, runners row is `auto` so wrapped runner tiles aren't clipped. */
  grid-template-columns: 1fr;
  grid-template-rows: 1fr auto;
  grid-template-areas:
    "pipes"
    "runners";
}
body[data-page="trends"] .scene-host {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr 0.55fr;
  grid-template-areas:
    "cycle  health"
    "spot   fame"
    "moments moments";
}
body[data-page="issues"] .scene-host {
  grid-template-columns: 1.4fr 1fr 1.2fr;
  grid-template-rows: 1.2fr 1fr 0.55fr;
  grid-template-areas:
    "ipp    labels  stale"
    "ipp    assigns stale"
    "week   week    week";
}
body[data-page="sprint"] .scene-host {
  /* Two panes: title + stats + label filter up top, the kanban board
   * taking the rest of the page. */
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "stats"
    "board";
  gap: 0.5rem;
}
body[data-page="personal"] .scene-host {
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 0.55fr 1fr 1fr;
  grid-template-areas:
    "kpis     kpis"
    "authored reviews"
    "issues   activity";
}
body[data-page="history"] .scene-host {
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas:
    "summary summary summary"
    "plan ongoing activity";
}
body[data-page="artifacts"] .scene-host {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  grid-template-areas: "list";
}
body[data-page="links"] .scene-host {
  /* Two-pane wiki view: sidebar fixed at 22rem, content takes the rest. */
  grid-template-columns: 22rem 1fr;
  grid-template-rows: 1fr;
  grid-template-areas: "sidebar content";
}
/* The artifacts scene has 4 visual children (::before title, toolbar,
 * body, footer) but the default .scene grid is `auto 1fr auto` and
 * would assign the 1fr slot to the toolbar — pushing dead space
 * around the filter chips. Override so body takes the 1fr instead. */
.scene[data-scene="artifacts-list"] {
  grid-template-rows: auto auto 1fr auto;
}

.scene {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 0.35rem;
  padding: 0.5rem 0.7rem 0.4rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  overflow: hidden;
  min-height: 0;
}
.scene::before {
  content: attr(data-title);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.scene-body { overflow: auto; min-height: 0; }
.scene-body::-webkit-scrollbar { width: 6px; height: 6px; }
.scene-body::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.scene-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.7rem;
  color: var(--muted);
}

/* Map scenes to grid areas */
[data-scene="pipeline-wall"]     { grid-area: pipes; }
[data-scene="runners"]           { grid-area: runners; }
[data-scene="issues-per-project"] { grid-area: ipp; }
[data-scene="issues-by-label"]    { grid-area: labels; }
[data-scene="issues-by-assignee"] { grid-area: assigns; }
[data-scene="stale-issues"]       { grid-area: stale; }
[data-scene="issues-this-week"]   { grid-area: week; }
[data-scene="sprint-stats"]      { grid-area: stats; }
[data-scene="sprint-board"]      { grid-area: board; }
[data-scene="personal-kpis"]      { grid-area: kpis; }
[data-scene="personal-authored"]  { grid-area: authored; }
[data-scene="personal-reviews"]   { grid-area: reviews; }
[data-scene="personal-issues"]    { grid-area: issues; }
[data-scene="personal-activity"]  { grid-area: activity; }
[data-scene="history-summary"]    { grid-area: summary; }
[data-scene="history-plan"]       { grid-area: plan; }
[data-scene="history-ongoing"]    { grid-area: ongoing; }
[data-scene="history-activity"]   { grid-area: activity; }
[data-scene="cycle-time"]        { grid-area: cycle; }
[data-scene="team-health"]       { grid-area: health; }
[data-scene="project-spotlight"] { grid-area: spot; }
[data-scene="hall-of-fame"]      { grid-area: fame; }
[data-scene="confetti-feed"]     { grid-area: moments; }
[data-scene="artifacts-list"]    { grid-area: list; }

.loading {
  display: grid;
  place-items: center;
  height: 100%;
  font-size: 0.9rem;
  color: var(--muted);
}

/* Pipeline wall grid.
 * minmax(8.5rem, 1fr) on rows + align-content: stretch makes rows fill the
 * available scene height; align-content: space-between on the .pipe-tile
 * grid then distributes the five lines vertically inside each tile so we
 * don't waste real estate when the row stretches taller than text needs. */
.pipe-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  /* Each row sizes to its TALLEST tile's content (max-content). DO
   * NOT wrap in `minmax(N, max-content)` — when the grid container
   * is height-constrained (which `.pipe-grid` is, sitting inside a
   * fr-sized scene area), Chromium resolves the row to the MIN of
   * the minmax range and ignores `max-content`. Tiles then lock to
   * the min height (e.g. 16rem = 224px) and their content visibly
   * spills below the tile box at smaller viewports — exactly the
   * all-text-visible / all-content-inside-tile contract violation
   * the visual test catches.
   * `align-items: stretch` makes sparse tiles match the row's
   * tallest sibling, so we don't need a min-height for the
   * "substantial-looking sparse tile" case either. */
  grid-auto-rows: max-content;
  gap: 0.4rem;
  align-content: start;
  align-items: stretch;
  /* Scrollbar restored deliberately. The contract says:
   *   - Pipeline-having projects (pipeline_status != None) must be
   *     visible above the fold, no scroll required.
   *   - Non-pipeline projects (pipeline_status is None) appear below
   *     and MAY require scrolling — never hide them with
   *     `overflow: hidden`.
   * Backend sort in state.to_pipeline_wall() puts pipeline-having
   * projects first, so the scroll affordance lives on the tail. */
  overflow-y: auto;
}
.pipe-grid::-webkit-scrollbar { width: 6px; }
.pipe-grid::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

.pipe-tile {
  position: relative;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left-width: 0.3rem;
  border-radius: 0.3rem;
  padding: 0.55rem 0.75rem;
  display: grid;
  /* Rows auto-sized; align-content:start packs them from the top so a
   * sparse tile reads at the same scale as a full one. NO overflow
   * clipping — the tile MUST fit its info; the .pipe-grid above
   * scrolls instead. */
  grid-auto-rows: auto;
  align-content: start;
  gap: 0.2rem;
  transition: border-color 300ms, background 300ms, box-shadow 300ms;
}

/* Tile head: GitLab project icon next to the namespace + name block. */
.pipe-tile .tile-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.55rem;
  align-items: center;
  min-width: 0;
}
.pipe-tile .tile-icon {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 0.4rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  object-fit: cover;
  flex: 0 0 auto;
  display: block;
}
.pipe-tile .tile-icon-fallback {
  display: grid;
  place-items: center;
  font-weight: 800;
  font-size: 1.2rem;
  color: var(--fg);
  letter-spacing: 0.04em;
}
.pipe-tile .tile-headtext {
  min-width: 0;
}
/* All text inside a .pipe-tile must render in full — no
 * truncation, no ellipsis, no line-clamp. Long values wrap to as
 * many lines as they need; the tile grows vertically to fit (see
 * feedback_card_content_contract.md). */
.pipe-tile .ns {
  font-size: 0.75rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.pipe-tile .name {
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.15;
  overflow-wrap: anywhere;
}
.pipe-tile .tile-desc {
  font-size: 0.85rem;
  line-height: 1.25;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.pipe-tile .tile-commit {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.4rem;
  font-size: 0.95rem;
  color: var(--muted);
}
.pipe-tile .tile-commit-by {
  color: var(--fg);
  font-weight: 600;
  overflow-wrap: anywhere;
  min-width: 0;
}
.pipe-tile .tile-commit-when {
  font-family: var(--mono);
  flex: 0 0 auto;
}
.pipe-tile .tile-mrs {
  display: flex;
  justify-content: space-between;
  gap: 0.4rem;
  font-size: 1.05rem;
  font-family: var(--mono);
}
.pipe-tile .tile-mr-count { color: var(--fg); }
.pipe-tile .tile-mr-age   { font-weight: 700; }
.pipe-tile .tile-mrs.band-ok    .tile-mr-age { color: var(--ok-bright); }
.pipe-tile .tile-mrs.band-warm  .tile-mr-age { color: var(--warn); }
.pipe-tile .tile-mrs.band-bad   .tile-mr-age { color: var(--fail-bright); }
.pipe-tile .tile-mrs.band-empty .tile-mr-count {
  color: var(--dim);
  font-family: var(--font);
  font-size: 0.85rem;
}
.pipe-tile .meta {
  display: flex;
  justify-content: space-between;
  align-items: end;
  font-size: 0.9rem;
  color: var(--muted);
}
.pipe-tile .status {
  font-weight: 700;
  letter-spacing: 0.08em;
  font-size: 0.95rem;
}
/* Only the status word (success/failed/running) is uppercased; the
 * parenthesised duration stays lowercase so "(5.2m)" doesn't render
 * as "(5.2M)". */
.pipe-tile .status .status-text {
  text-transform: uppercase;
}
.pipe-tile .status .status-dur {
  font-weight: 600;
  /* Inherits the per-status colour (green/red/blue) by default; long
   * builds override to amber regardless of outcome. */
}
.pipe-tile .status .status-dur.long { color: var(--warn); }

/* 2x glyph for ✅/❌/⚙ status icons — the symbol is the label, so size it
 * up for across-the-room glance. Reset uppercase + letter-spacing so it
 * doesn't pick up text-transform meant for the word states. */
.status-glyph {
  font-size: 2em;
  line-height: 1;
  vertical-align: middle;
  text-transform: none;
  letter-spacing: 0;
  display: inline-block;
}
/* Non-pass/fail/running statuses (manual, canceled, skipped, pending, …):
 * a monochrome glyph in the muted "pending" tone so it reads as neither
 * green success nor red failure. */
.status-other {
  color: var(--pending);
}
.status-cog {
  display: inline-block;
  font-size: 2.4em;  /* 120% of .status-glyph's 2em — cog is the busiest signal */
  /* The gear glyph's ink box is a hair taller than a line-height:1 box, so
   * give it room — otherwise it reports as vertically clipped (its own
   * scrollHeight > clientHeight), which the pipe-tile no-clip test flags. */
  line-height: 1.2;
  animation: cog-spin 2.4s linear infinite;
  transform-origin: 50% 50%;
  will-change: transform;
  /* Force running-blue regardless of the tile's main verdict — a cog on
   * a red (failed-on-main) tile should still read as "actively building"
   * not as "part of the failure". Use !important to override
   * `.pipe-tile.status-failed .status { color: var(--fail-bright) }`. */
  color: var(--running-bright) !important;
}
/* Runner/job count next to the cog (#41) — same size as the cog, same blue,
 * but NOT spinning. Sits right after the gear as one running-blue block. */
.status-cog-count {
  display: inline-block;
  font-size: 2.4em;  /* match .status-cog */
  line-height: 1.2;
  font-weight: 700;
  margin-left: 0.1em;
  color: var(--running-bright) !important;
}
/* The live-elapsed duration that pairs with the cog also tints blue so
 * the running indicator reads as one cohesive blue block. */
.pipe-tile.is-running .status-dur {
  color: var(--running-bright);
}
@keyframes cog-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Info row: "Linters: Shellcheck, Ruff". When the value list is too
 * long for the tile width, the row WRAPS to a second line — never
 * truncates with an ellipsis. Card-content contract: every populated
 * row must render in full. The tile grows vertically via
 * `grid-auto-rows: max-content` to fit. */
.pipe-tile .tile-info-row {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 0.78rem;
  flex-wrap: wrap;
}
.pipe-tile .tile-info-label {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.65rem;
  flex: 0 0 auto;
}
.pipe-tile .tile-info-value {
  color: var(--fg);
  flex: 1 1 auto;
  min-width: 0;
  /* Wrap on commas / spaces — long lists become multi-line, not
   * truncated. word-break:normal would also keep individual tokens
   * intact (we never split "JavaScript" in half). */
  white-space: normal;
  overflow-wrap: anywhere;
}

/* CVE severity tints — each bucket's count is wrapped in a span so we
 * can colour-code by severity. Critical = bright red, high = orange,
 * medium = warn-amber, low = muted. */
.cve-sev-critical { color: var(--fail-bright); font-weight: 700; }
.cve-sev-high     { color: #ff9c4e;            font-weight: 700; }
.cve-sev-medium   { color: var(--warn);        font-weight: 600; }
.cve-sev-low      { color: var(--muted); }

/* Coverage row — own line in the tile grid, doesn't overlap meta.
 * Wraps if needed; no truncation per the card-content contract. */
.pipe-tile .tile-coverage {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem;
  font-size: 0.95rem;
}
.pipe-tile .tile-cov-label {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.75rem;
}
.pipe-tile .tile-cov-pct {
  font-family: var(--mono);
  font-weight: 800;
  letter-spacing: 0.02em;
}
.pipe-tile .tile-coverage.band-good .tile-cov-pct { color: var(--ok-bright); }
.pipe-tile .tile-coverage.band-ok   .tile-cov-pct { color: var(--warn); }
.pipe-tile .tile-coverage.band-bad  .tile-cov-pct { color: var(--fail-bright); }
.pipe-tile .tile-coverage.band-none .tile-cov-pct { color: var(--dim); }

.pipe-tile.status-success    { border-left-color: var(--ok); }
.pipe-tile.status-success .status { color: var(--ok-bright); }
.pipe-tile.status-failed     { border-left-color: var(--fail); background: #2a1316; }
.pipe-tile.status-failed .status { color: var(--fail-bright); }
.pipe-tile.status-failed     { animation: failpulse 2.4s ease-in-out infinite; }
.pipe-tile.status-running    { border-left-color: var(--running); }
.pipe-tile.status-running .status { color: var(--running-bright); }
/* Wandering blue bar fires whenever ANY pipeline is in flight (main OR
 * an MR branch), independent of the main-branch verdict. Driven by the
 * .is-running class set by the JS renderer when the API reports
 * is_running: true. The tile colour/border stay at the main verdict —
 * a red tile stays red until main itself succeeds. */
.pipe-tile.is-running::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 0.3rem;
  background: linear-gradient(90deg, transparent, var(--running-bright), transparent);
  background-size: 50% 100%;
  background-repeat: no-repeat;
  animation: runslide 1.8s linear infinite;
}
.pipe-tile.status-pending,
.pipe-tile.status-created,
.pipe-tile.status-waiting_for_resource,
.pipe-tile.status-preparing,
.pipe-tile.status-scheduled { border-left-color: var(--warn); }
.pipe-tile.status-pending .status,
.pipe-tile.status-created .status,
.pipe-tile.status-waiting_for_resource .status,
.pipe-tile.status-preparing .status,
.pipe-tile.status-scheduled .status { color: var(--warn); }
.pipe-tile.status-canceled,
.pipe-tile.status-skipped,
.pipe-tile.status-manual { border-left-color: var(--skipped); opacity: 0.75; }
.pipe-tile.status-canceled .status,
.pipe-tile.status-skipped .status,
.pipe-tile.status-manual .status { color: var(--pending); }
.pipe-tile.status-none { border-left-color: var(--dim); opacity: 0.6; }
.pipe-tile.status-none .status { color: var(--dim); }

@keyframes failpulse {
  0%, 100% { box-shadow: 0 0 0 rgba(248,81,73,0); }
  50%      { box-shadow: 0 0 2rem rgba(248,81,73,0.35); }
}
@keyframes runslide {
  from { background-position: -50% 0; }
  to   { background-position: 150% 0; }
}

/* MR review queue — dense */
.mr-list {
  display: grid;
  grid-auto-rows: minmax(2.6rem, auto);
  gap: 0.25rem;
  align-content: start;
}

.mr-row {
  display: grid;
  grid-template-columns: 2.6rem 1fr auto;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.5rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  text-decoration: none;
  color: inherit;
  transition: background 200ms, border-color 200ms;
}
.mr-row.mr-draft { opacity: 0.7; }
.mr-row.age-stale { border-color: rgba(210, 153, 34, 0.4); }
.mr-row.age-cold {
  border-color: rgba(248, 81, 73, 0.45);
  background: linear-gradient(90deg, rgba(248,81,73,0.08), var(--bg-elev-2) 30%);
}

.age-pill {
  display: grid;
  place-items: center;
  height: 1.8rem;
  border-radius: 0.25rem;
  font-weight: 800;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
  font-family: var(--mono);
}
.age-pill.age-fresh { background: rgba(46,160,67,0.2); color: var(--ok-bright); }
.age-pill.age-warm  { background: rgba(210,153,34,0.2); color: var(--warn); }
.age-pill.age-stale { background: rgba(248,81,73,0.2); color: var(--fail-bright); }
.age-pill.age-cold  {
  background: var(--fail);
  color: #fff;
  animation: failpulse 2.6s ease-in-out infinite;
}

.mr-main { min-width: 0; }
.mr-title {
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mr-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.25rem 0.55rem;
  font-size: 0.66rem;
  color: var(--muted);
  margin-top: 0.05rem;
}
.mr-proj { font-weight: 600; color: var(--fg); }
.mr-iid { color: var(--muted); font-family: var(--mono); }
.mr-author { color: var(--muted); }

.badge {
  display: inline-block;
  padding: 0 0.3rem;
  border-radius: 0.2rem;
  font-size: 0.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: var(--bg-elev-2);
  color: var(--muted);
}
.badge-draft    { background: rgba(139,148,158,0.2); color: var(--pending); }
.badge-conflict { background: rgba(248,81,73,0.2); color: var(--fail-bright); }
.badge-ci       { background: rgba(31,111,235,0.2); color: var(--running-bright); }
.badge-notes    { background: rgba(210,153,34,0.15); color: var(--warn); text-transform: none; letter-spacing: 0; }

.mr-reviewers, .mr-no-reviewer {
  display: flex;
  align-items: center;
  gap: 0.2rem;
}
.mr-no-reviewer {
  color: var(--fail-bright);
  font-size: 0.66rem;
  font-style: italic;
  white-space: nowrap;
}

.avatar {
  display: inline-grid;
  place-items: center;
  width: 1.4rem; height: 1.4rem;
  border-radius: 50%;
  overflow: hidden;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  flex: 0 0 auto;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-fallback {
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--fg);
  letter-spacing: 0.05em;
}

.mr-empty {
  display: grid;
  place-items: center;
  height: 100%;
  text-align: center;
  gap: 0.4rem;
}
.mr-empty-icon { font-size: 2.5rem; }
.mr-empty-title { font-size: 1.4rem; font-weight: 800; color: var(--ok-bright); }
.mr-empty-sub { font-size: 1.4rem; color: var(--muted); }

/* Sprint page (SP1 board + SP4 wip) */
.kanban {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.4rem;
  height: 100%;
  min-height: 0;
}
.kanban-col {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 0.25rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  padding: 0.35rem 0.4rem;
  min-height: 0;
}
.kanban-col-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  font-weight: 700;
}
.kanban-col-header .kanban-count {
  font-family: var(--mono);
  color: var(--fg);
}
.kanban-col.col-todo   { border-top: 0.18rem solid var(--dim); }
.kanban-col.col-doing  { border-top: 0.18rem solid var(--running-bright); }
.kanban-col.col-review { border-top: 0.18rem solid var(--warn); }
.kanban-col.col-done   { border-top: 0.18rem solid var(--ok-bright); }
.kanban-col-list {
  display: grid;
  grid-auto-rows: minmax(2.4rem, auto);
  gap: 0.2rem;
  align-content: start;
  overflow: auto;
  min-height: 0;
}
.kanban-card {
  display: block;
  padding: 0.3rem 0.45rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  text-decoration: none;
  color: inherit;
  line-height: 1.2;
}
.kanban-card-title {
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kanban-card-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.58rem;
  color: var(--muted);
  margin-top: 0.15rem;
}
.kanban-card-proj {
  color: var(--fg);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 70%;
}
.kanban-card-iid { font-family: var(--mono); }
.kanban-card-assignees {
  display: flex;
  gap: 0.1rem;
  margin-top: 0.15rem;
}
.kanban-card-assignees .avatar {
  width: 1rem;
  height: 1rem;
}
.kanban-card-labels {
  display: flex;
  gap: 0.15rem;
  margin-top: 0.15rem;
  flex-wrap: wrap;
}
.kanban-card-label-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  flex: 0 0 auto;
}
.kanban-empty {
  display: grid;
  place-items: center;
  height: 100%;
  font-size: 0.65rem;
  color: var(--dim);
  font-style: italic;
}

/* SP4 WIP per Person */
.wip-list {
  display: grid;
  grid-auto-rows: minmax(2.4rem, auto);
  gap: 0.25rem;
  align-content: start;
  overflow: auto;
  min-height: 0;
}
.wip-row {
  display: grid;
  grid-template-columns: 1.4rem 1fr 2.5rem;
  gap: 0.4rem;
  align-items: center;
  padding: 0.3rem 0.5rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.25rem solid var(--ok-bright);
  border-radius: 0.3rem;
}
.wip-row.over-limit {
  border-left-color: var(--warn);
  animation: failpulse 3s ease-in-out infinite;
}
.wip-row.way-over-limit {
  border-left-color: var(--fail);
  animation: failpulse 2.4s ease-in-out infinite;
}
.wip-row .avatar { width: 1.2rem; height: 1.2rem; }
.wip-name {
  font-size: 0.72rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.15;
}
.wip-name-sub {
  font-size: 0.55rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wip-count {
  text-align: right;
  font-family: var(--mono);
  font-weight: 800;
  font-size: 1.15rem;
  line-height: 1;
}
.wip-row.over-limit .wip-count      { color: var(--warn); }
.wip-row.way-over-limit .wip-count  { color: var(--fail-bright); }
.wip-row.unassigned {
  border-left-color: var(--fail);
  background: linear-gradient(90deg, rgba(248,81,73,0.08), var(--bg-elev-2) 30%);
}
.wip-row.unassigned .wip-count { color: var(--fail-bright); }

/* Issues page (I1–I5) — dense breakdowns */

/* I1: Open issues per project — horizontal bars, one per row */
.ipp-list {
  display: grid;
  grid-auto-rows: minmax(1.4rem, auto);
  gap: 0.18rem;
  align-content: start;
}
.ipp-row {
  display: grid;
  grid-template-columns: 11rem 1fr 2.5rem 2.5rem;
  gap: 0.4rem;
  align-items: center;
  padding: 0.18rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  font-size: 0.7rem;
}
.ipp-name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ipp-bar {
  position: relative;
  height: 0.5rem;
  background: var(--bg-elev);
  border-radius: 0.2rem;
  overflow: hidden;
}
.ipp-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--running);
  transition: width 600ms ease;
}
.ipp-bar-fill.bugs {
  background: var(--fail);
  mix-blend-mode: screen;
}
.ipp-row.high .ipp-bar-fill { background: var(--warn); }
.ipp-row.very-high .ipp-bar-fill { background: var(--fail); }
.ipp-count {
  text-align: right;
  font-family: var(--mono);
  font-weight: 700;
}
.ipp-bugs {
  text-align: right;
  font-family: var(--mono);
  color: var(--fail-bright);
  font-weight: 700;
}
.ipp-bugs.zero { color: var(--dim); }

/* I2: Issues by label — stacked bars */
.lbl-list {
  display: grid;
  grid-auto-rows: minmax(1.4rem, auto);
  gap: 0.18rem;
  align-content: start;
}
.lbl-row {
  display: grid;
  grid-template-columns: 8rem 1fr 3rem;
  gap: 0.4rem;
  align-items: center;
  padding: 0.18rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  font-size: 0.68rem;
}
.lbl-name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: flex;
  align-items: center;
  gap: 0.3rem;
}
.lbl-swatch {
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 0.15rem;
  flex: 0 0 auto;
}
.lbl-bar {
  display: flex;
  height: 0.55rem;
  border-radius: 0.2rem;
  overflow: hidden;
  background: var(--bg-elev);
}
.lbl-bar-open   { background: var(--warn); }
.lbl-bar-closed { background: var(--ok); opacity: 0.55; }
.lbl-count {
  text-align: right;
  font-family: var(--mono);
  font-weight: 700;
  font-size: 0.7rem;
}

/* I3: By assignee */
.asgn-list {
  display: grid;
  grid-auto-rows: minmax(1.6rem, auto);
  gap: 0.18rem;
  align-content: start;
}
.asgn-row {
  display: grid;
  grid-template-columns: 1.4rem 1fr 1fr 2.3rem;
  gap: 0.35rem;
  align-items: center;
  padding: 0.18rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  font-size: 0.7rem;
}
.asgn-row .avatar { width: 1.2rem; height: 1.2rem; }
.asgn-name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.asgn-bar {
  position: relative;
  height: 0.5rem;
  background: var(--bg-elev);
  border-radius: 0.2rem;
  overflow: hidden;
}
.asgn-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--running-bright);
}
.asgn-count {
  text-align: right;
  font-family: var(--mono);
  font-weight: 700;
}
.asgn-row.unassigned {
  border-color: rgba(248, 81, 73, 0.4);
  background: linear-gradient(90deg, rgba(248,81,73,0.08), var(--bg-elev-2) 30%);
}
.asgn-row.unassigned .asgn-bar-fill { background: var(--fail-bright); }

/* I4: Stale issues */
.stale-list {
  display: grid;
  grid-auto-rows: minmax(2rem, auto);
  gap: 0.2rem;
  align-content: start;
}
.stale-row {
  display: grid;
  grid-template-columns: 2.4rem 1fr auto;
  gap: 0.4rem;
  align-items: center;
  padding: 0.25rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.2rem solid var(--warn);
  border-radius: 0.25rem;
  text-decoration: none;
  color: inherit;
}
.stale-row.very-stale { border-left-color: var(--fail); }
.stale-age {
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-weight: 800;
  font-size: 0.78rem;
  background: rgba(210,153,34,0.2);
  color: var(--warn);
  border-radius: 0.2rem;
  padding: 0.05rem 0.2rem;
}
.stale-row.very-stale .stale-age {
  background: rgba(248,81,73,0.2);
  color: var(--fail-bright);
}
.stale-main { min-width: 0; line-height: 1.15; }
.stale-title {
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.stale-meta { font-size: 0.6rem; color: var(--muted); }
.stale-meta .stale-proj { color: var(--fg); font-weight: 600; }
.stale-meta .stale-iid { font-family: var(--mono); }
.stale-assignees {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}
.stale-assignees .avatar { width: 1.1rem; height: 1.1rem; }

/* I5: This week — counters + sparkline */
.week-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 0.5rem;
  height: 100%;
  align-items: center;
}
.week-cell {
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  padding: 0.4rem 0.6rem;
  height: 100%;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 0.2rem;
}
.week-lbl {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.week-num {
  font-size: 1.6rem;
  font-weight: 800;
  font-family: var(--mono);
  line-height: 1;
}
.week-cell.created .week-num { color: var(--running-bright); }
.week-cell.closed .week-num { color: var(--ok-bright); }
.week-cell.net .week-num.positive { color: var(--ok-bright); }
.week-cell.net .week-num.negative { color: var(--fail-bright); }
.week-spark {
  position: relative;
  height: 1.2rem;
  display: flex;
  gap: 0.1rem;
  align-items: end;
}
.week-spark-bar {
  flex: 1;
  background: var(--running);
  border-radius: 0.1rem 0.1rem 0 0;
  min-height: 0.05rem;
}
.week-cell.closed .week-spark-bar { background: var(--ok); }
.week-cell.created .week-spark-bar { background: var(--running-bright); }
.week-foot {
  font-size: 0.55rem;
  color: var(--muted);
  text-align: right;
}

/* Group Runners (N6) — horizontal strip on the Now page.
 * Card-content contract: no row inside a runner tile can be clipped,
 * and no entire tile can be hidden behind a scrollbar. The strip
 * wraps to multiple lines if needed; the Now-page grid row hosting
 * the strip is `auto`-sized so wrap lines aren't clipped by a
 * too-short row. Do NOT add `height: 100%` here — that would force
 * the strip to stretch to fill its grid cell and re-create the very
 * clipping problem the auto row was meant to fix. */
/* RAM/CPU for a pure-machine runner, placed in the spare space to the RIGHT
   of the tile text and stretched to the tile's existing height (so the box
   size doesn't change). Only present on runners we have ssh-bridge telemetry
   for; other tiles are unchanged. */
.runner-metrics {
  align-self: stretch;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
  line-height: 1;
  color: var(--muted);
  white-space: nowrap;
}
.runner-metric {
  display: inline-flex;
  align-items: baseline;
  gap: 0.12rem;
}
.runner-metric b {
  font-family: var(--mono);
  /* Fill the tile's existing height with one big row — no extra line. */
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--fg);
}
.runner-metric-u {
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.runner-metrics.stale { color: var(--dim); }
.runner-metrics.stale b { color: var(--warn); }

.runners-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-content: start;
  overflow: hidden;
}
.runners-strip .runner-tile {
  /* Grow to share the strip width equally — with 3 runners on the row
     they each get 1/3 of the available width, filling the group box
     instead of leaving empty space on the right. */
  flex: 1 1 0;
  min-width: 12rem;
}
.runner-tile {
  display: grid;
  /* dot | text | (optional metrics) | last-contact. The 4th column is auto,
     so it collapses to 0 on tiles without telemetry — those render unchanged. */
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 0.35rem;
  padding: 0.15rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.2rem solid var(--dim);
  border-radius: 0.25rem;
  text-decoration: none;
  color: inherit;
  min-width: 0;
}
.runner-tile.online    { border-left-color: var(--ok-bright); }
.runner-tile.busy      { border-left-color: var(--running-bright); }
.runner-tile.busy      { animation: runner-busy 1.6s ease-in-out infinite; }
.runner-tile.stale     {
  border-left-color: var(--warn);
  background: linear-gradient(90deg, rgba(210,153,34,0.10), var(--bg-elev-2) 30%);
}
.runner-tile.offline   {
  border-left-color: var(--fail);
  background: linear-gradient(90deg, rgba(248,81,73,0.10), var(--bg-elev-2) 30%);
  animation: runner-fail 2.4s ease-in-out infinite;
}
.runner-tile.paused    { border-left-color: var(--pending); opacity: 0.65; }

.runner-dot {
  /* Fixed-size status disc, vertically centred in its column — same footprint
   * as the busy cog so online/busy/stale/offline all read consistently to the
   * LEFT of the runner name (the old height:100% disc + wide glow bled onto
   * the text). */
  width: clamp(1.1rem, 3.4vh, 2.2rem);
  height: clamp(1.1rem, 3.4vh, 2.2rem);
  align-self: center;
  border-radius: 50%;
  background: var(--dim);
  flex: 0 0 auto;
}
.runner-tile.online .runner-dot   {
  background: var(--ok-bright);
  box-shadow: 0 0 0 0.1rem rgba(86,211,100,0.18), 0 0 0.45rem rgba(86,211,100,0.55);
}
.runner-tile.busy   .runner-dot   {
  /* When a job is in flight the disc swaps to a spinning cog so the
   * busy state is read across the room as motion, not just a colour. */
  background: transparent;
  box-shadow: none;
  display: grid;
  place-items: center;
  overflow: visible;
}
.runner-tile.busy .runner-dot::before {
  content: "\2699\FE0E"; /* U+2699 gear + U+FE0E text-style variation */
  display: inline-block;
  color: var(--running-bright);
  font-size: clamp(1.2rem, 3.6vh, 2.4rem);
  line-height: 1;
  animation: cog-spin 2.4s linear infinite;
  transform-origin: 50% 50%;
  will-change: transform;
}
.runner-tile.stale  .runner-dot   {
  background: var(--warn);
  box-shadow: 0 0 0 0.1rem rgba(210,153,34,0.18), 0 0 0.45rem rgba(210,153,34,0.5);
}
.runner-tile.offline .runner-dot  {
  background: var(--fail-bright);
  box-shadow: 0 0 0 0.1rem rgba(248,81,73,0.18), 0 0 0.45rem rgba(248,81,73,0.55);
}
.runner-tile.paused .runner-dot   { background: var(--pending); }

.runner-main {
  min-width: 0;
  line-height: 1.1;
  align-self: center;
  display: flex;
  flex-direction: column;
  gap: 0.02rem;
}
.runner-nameline {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  min-width: 0;
}
.runner-name {
  font-size: 0.72rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 0 1 auto;
  min-width: 0;
}
.runner-meta {
  font-size: 0.55rem;
  color: var(--muted);
  display: flex;
  gap: 0.3rem;
  align-items: center;
  white-space: nowrap;
  overflow: hidden;
}
.runner-meta .runner-status {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  flex: 0 0 auto;
}
.runner-tag {
  display: inline-block;
  font-size: 0.5rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0 0.25rem;
  border-radius: 0.2rem;
  background: rgba(110,118,129,0.18);
  color: var(--muted);
  white-space: nowrap;
}
.runner-ver {
  font-family: var(--mono);
  font-size: 0.5rem;
  color: var(--dim);
  flex: 0 0 auto;
  white-space: nowrap;
}
.runner-jobs {
  display: flex;
  gap: 0.25rem;
  font-size: 0.55rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.runner-job {
  font-family: var(--mono);
  color: var(--running-bright);
  background: rgba(88,166,255,0.10);
  border-radius: 0.2rem;
  padding: 0 0.25rem;
  max-width: 8rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.runner-job-more {
  font-family: var(--mono);
  color: var(--muted);
  font-size: 0.55rem;
  align-self: center;
}
.runner-tile.online .runner-status   { color: var(--ok-bright); }
.runner-tile.busy   .runner-status   { color: var(--running-bright); }
.runner-tile.stale  .runner-status   { color: var(--warn); }
.runner-tile.offline .runner-status  { color: var(--fail-bright); }
.runner-tile.paused .runner-status   { color: var(--pending); }

.runner-when {
  font-family: var(--mono);
  font-size: 0.55rem;
  color: var(--muted);
  white-space: nowrap;
}

/* LLM status tile — a sibling of the runner tiles in the same strip
   ("Runners and other services"). Reuses the runner-tile grid; only the
   left-border + dot colour vocabulary differs by up/down/unconfigured. */
.llm-tile.up      { border-left-color: var(--ok-bright); }
.llm-tile.down    {
  border-left-color: var(--fail);
  background: linear-gradient(90deg, rgba(248,81,73,0.10), var(--bg-elev-2) 30%);
  animation: runner-fail 2.4s ease-in-out infinite;
}
.llm-tile.unconfigured { border-left-color: var(--dim); opacity: 0.7; }
.llm-tile.up   .runner-dot {
  background: var(--ok-bright);
  box-shadow: 0 0 0 0.1rem rgba(86,211,100,0.18), 0 0 0.45rem rgba(86,211,100,0.55);
}
.llm-tile.down .runner-dot {
  background: var(--fail-bright);
  box-shadow: 0 0 0 0.1rem rgba(248,81,73,0.18), 0 0 0.45rem rgba(248,81,73,0.55);
}
.llm-tile.unconfigured .runner-dot { background: var(--dim); }
.llm-tile.up   .runner-status { color: var(--ok-bright); }
.llm-tile.down .runner-status { color: var(--fail-bright); }

@keyframes runner-busy {
  0%, 100% { box-shadow: 0 0 0 rgba(31,111,235,0); }
  50%      { box-shadow: 0 0 0.8rem rgba(88,166,255,0.45); }
}
@keyframes runner-fail {
  0%, 100% { box-shadow: 0 0 0 rgba(248,81,73,0); }
  50%      { box-shadow: 0 0 0.8rem rgba(248,81,73,0.45); }
}

/* Activity stream (N5) — live feed of GitLab events on Now page */
.activity-list {
  display: grid;
  grid-auto-rows: minmax(2.2rem, auto);
  gap: 0.2rem;
  align-content: start;
}
.activity-row {
  display: grid;
  grid-template-columns: 1.4rem 1fr 3rem;
  gap: 0.4rem;
  align-items: center;
  padding: 0.25rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.2rem solid var(--border);
  border-radius: 0.25rem;
  text-decoration: none;
  color: inherit;
}
.activity-row.activity-kind-push      { border-left-color: var(--running-bright); }
.activity-row.activity-kind-mr        { border-left-color: var(--ok-bright); }
.activity-row.activity-kind-issue     { border-left-color: var(--warn); }
.activity-row.activity-kind-note      { border-left-color: var(--pending); }
.activity-row.activity-kind-milestone { border-left-color: var(--running); }
.activity-row.activity-kind-wiki      { border-left-color: var(--dim); }

.activity-icon {
  font-size: 0.95rem;
  line-height: 1;
  text-align: center;
}
.activity-main { min-width: 0; line-height: 1.15; }
.activity-text {
  font-size: 0.72rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.activity-text .activity-author { font-weight: 700; color: var(--fg); }
.activity-text .activity-action { color: var(--muted); }
.activity-text .activity-target { color: var(--fg); }
.activity-meta {
  font-size: 0.6rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.activity-meta .activity-proj { color: var(--running-bright); }
.activity-when {
  font-family: var(--mono);
  font-size: 0.62rem;
  color: var(--muted);
  text-align: right;
  white-space: nowrap;
}

/* Latest Deploys (N4) — dense */
.deploys-list {
  display: grid;
  grid-auto-rows: minmax(2.4rem, auto);
  gap: 0.25rem;
  align-content: start;
}
.deploy-row {
  display: grid;
  grid-template-columns: 5rem 1fr auto auto;
  gap: 0.5rem;
  align-items: center;
  padding: 0.3rem 0.5rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.3rem solid var(--border);
  border-radius: 0.3rem;
  text-decoration: none;
  color: inherit;
}
.deploy-row.deploy-tier-production {
  border-left-color: var(--ok-bright);
  background: linear-gradient(90deg, rgba(86, 211, 100, 0.12), var(--bg-elev-2) 35%);
}
.deploy-row.deploy-tier-staging   { border-left-color: var(--running-bright); }
.deploy-row.deploy-tier-testing   { border-left-color: var(--warn); }
.deploy-row.deploy-tier-development { border-left-color: var(--pending); }
.deploy-row.deploy-tier-other     { border-left-color: var(--dim); }

.deploy-row.deploy-status-failed { background: linear-gradient(90deg, rgba(248,81,73,0.12), var(--bg-elev-2) 30%); }
.deploy-row.deploy-status-failed .deploy-status { color: var(--fail-bright); font-weight: 700; }
.deploy-row.deploy-status-success .deploy-status { color: var(--ok-bright); font-weight: 700; }
.deploy-row.deploy-status-running .deploy-status { color: var(--running-bright); font-weight: 700; }

.deploy-env { line-height: 1.15; }
.deploy-env-name {
  font-size: 0.78rem;
  font-weight: 800;
  text-transform: lowercase;
  letter-spacing: 0.02em;
}
.deploy-env-tier {
  font-size: 0.55rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.deploy-row.deploy-tier-production .deploy-env-tier { color: var(--ok-bright); }

.deploy-main { min-width: 0; }
.deploy-proj {
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.deploy-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.5rem;
  font-size: 0.62rem;
  color: var(--muted);
  margin-top: 0.05rem;
}
.deploy-ref { font-family: var(--mono); color: var(--fg); }
.deploy-sha {
  font-family: var(--mono);
  background: var(--bg-elev-2);
  border-radius: 0.25rem;
  padding: 0 0.3rem;
  color: var(--fg);
}
.deploy-status { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.6rem; }

.deploy-deployer {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.66rem;
  color: var(--fg);
  white-space: nowrap;
}
.deploy-when {
  font-family: var(--mono);
  font-size: 0.66rem;
  color: var(--muted);
  white-space: nowrap;
}

/* T2: Cycle Time / Lead Time Trend (ECharts) — dense */
.chart-host {
  width: 100%;
  height: 100%;
  min-height: 0;
}
.chart-empty {
  display: grid;
  place-items: center;
  height: 100%;
  text-align: center;
  gap: 0.4rem;
}
.chart-empty .mr-empty-icon { font-size: 2rem; }
.chart-empty .mr-empty-title { font-size: 1rem; font-weight: 800; color: var(--muted); }
.chart-empty .mr-empty-sub { font-size: 0.7rem; color: var(--muted); max-width: 28rem; }

/* T3: Team Health Leaderboard — dense */
#team-health-body { display: grid; grid-template-rows: auto 1fr; gap: 0.5rem; }
.th-team {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.35rem;
}
.th-stat {
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  padding: 0.4rem 0.55rem;
}
.th-stat.th-pending { opacity: 0.55; }
.th-num {
  font-size: 1.4rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-family: var(--mono);
  line-height: 1;
}
.th-lbl {
  font-size: 0.6rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 0.2rem;
}
.th-board {
  display: grid;
  grid-auto-rows: minmax(1.6rem, auto);
  gap: 0.2rem;
  align-content: start;
  overflow: auto;
  min-height: 0;
}
.th-board-header {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  margin-bottom: 0.2rem;
}
.th-row {
  display: grid;
  grid-template-columns: 9rem 1fr 2.5rem 3rem;
  gap: 0.35rem;
  align-items: center;
  padding: 0.2rem 0.4rem;
  background: var(--bg-elev-2);
  border-radius: 0.25rem;
  font-size: 0.7rem;
}
.th-row-name {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.th-row-bar {
  height: 0.45rem;
  background: var(--bg-elev);
  border-radius: 0.25rem;
  overflow: hidden;
}
.th-row-bar-fill {
  height: 100%;
  background: var(--ok);
  transition: width 600ms ease;
}
.th-row.th-good .th-row-bar-fill { background: var(--ok-bright); }
.th-row.th-ok   .th-row-bar-fill { background: var(--warn); }
.th-row.th-bad  .th-row-bar-fill { background: var(--fail); }
.th-row.th-na   .th-row-bar-fill { background: var(--dim); }
.th-row-pct {
  text-align: right;
  font-family: var(--mono);
  font-weight: 700;
}
.th-row-meta { text-align: right; font-size: 0.6rem; }
.th-empty {
  padding: 1rem;
  text-align: center;
  color: var(--muted);
  font-size: 0.75rem;
}

/* T4: Hall of Fame — every entry visible as its own row, no rotation */
.hall-list {
  display: grid;
  grid-auto-rows: minmax(2.6rem, auto);
  gap: 0.3rem;
  align-content: start;
  overflow: auto;
  min-height: 0;
}
.hall-row {
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  gap: 0.6rem;
  align-items: center;
  padding: 0.4rem 0.55rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.25rem solid var(--ok-bright);
  border-radius: 0.3rem;
}
.hall-row.hall-kind-fast_reviewer { border-left-color: var(--running-bright); }
.hall-row.hall-kind-bug_squasher  { border-left-color: var(--warn); }
.hall-row.hall-kind-pipeline_saviour { border-left-color: var(--ok); }
.hall-row.hall-kind-collecting    { border-left-color: var(--dim); opacity: 0.7; }
.hall-icon { font-size: 1.6rem; line-height: 1; text-align: center; }
.hall-main { min-width: 0; line-height: 1.2; }
.hall-title {
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ok-bright);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.hall-row.hall-kind-fast_reviewer .hall-title { color: var(--running-bright); }
.hall-row.hall-kind-bug_squasher  .hall-title { color: var(--warn); }
.hall-row.hall-kind-pipeline_saviour .hall-title { color: var(--ok); }
.hall-row.hall-kind-collecting    .hall-title { color: var(--muted); }
.hall-sub {
  font-size: 0.72rem;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 0.05rem;
}

/* T5: Project Spotlight — dense */
.ps-grid {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 0.5rem;
  height: 100%;
}
.ps-head {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.8rem;
  align-items: end;
}
.ps-name {
  font-size: 1.1rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ps-stats {
  display: flex;
  gap: 0.7rem;
}
.ps-stat { text-align: right; }
.ps-stat-num {
  font-size: 1rem;
  font-weight: 800;
  font-family: var(--mono);
  line-height: 1;
}
.ps-stat-lbl {
  font-size: 0.55rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.ps-cols {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 0.5rem;
  overflow: hidden;
  min-height: 0;
}
.ps-col-header {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-bottom: 0.2rem;
}
.ps-col {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  overflow: auto;
  min-height: 0;
}
.ps-mr {
  display: block;
  padding: 0.25rem 0.4rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  text-decoration: none;
  color: inherit;
}
.ps-mr-title {
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ps-mr-meta {
  font-size: 0.6rem;
  margin-top: 0.05rem;
}
.ps-contributor {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.2rem 0.4rem;
  background: var(--bg-elev-2);
  border-radius: 0.25rem;
  font-size: 0.7rem;
}
.ps-c-name { font-weight: 700; }
.ps-c-count { font-family: var(--mono); }
.ps-link {
  margin-top: auto;
  font-size: 0.6rem;
  color: var(--muted);
  word-break: break-all;
}
.ps-link a { color: var(--running-bright); }

/* Moment feed (T6 sibling: Trends scene listing recent celebrations) — dense */
.moment-list {
  display: grid;
  grid-auto-rows: minmax(2.2rem, auto);
  gap: 0.25rem;
  align-content: start;
}
.moment-row {
  display: grid;
  grid-template-columns: 1.6rem 1fr;
  gap: 0.5rem;
  align-items: center;
  padding: 0.3rem 0.5rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.25rem solid var(--ok-bright);
  border-radius: 0.3rem;
}
.moment-row.moment-kind-first_mr        { border-left-color: var(--ok-bright); }
.moment-row.moment-kind-main_green_recovery { border-left-color: var(--ok); }
.moment-row.moment-kind-milestone        { border-left-color: var(--warn); }
.moment-row.moment-kind-release          { border-left-color: var(--running-bright); }
.moment-icon { font-size: 1.1rem; line-height: 1; text-align: center; }
.moment-title { font-size: 0.78rem; font-weight: 700; line-height: 1.2; }
.moment-sub  { font-size: 0.66rem; color: var(--muted); }
.moment-meta { font-size: 0.6rem; color: var(--muted); margin-top: 0.05rem; }
.moment-meta a { color: var(--running-bright); }

/* Confetti overlay (T6) */
.confetti-overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: radial-gradient(circle at center, rgba(20, 26, 38, 0.86), rgba(10, 14, 20, 0.94));
  z-index: 1000;
  opacity: 0;
  transition: opacity 350ms ease;
  pointer-events: none;
}
.confetti-overlay.active { opacity: 1; }
.confetti-overlay canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.confetti-card {
  position: relative;
  text-align: center;
  padding: 3rem 5rem;
  background: rgba(19, 25, 34, 0.85);
  border: 2px solid var(--ok);
  border-radius: 1rem;
  box-shadow: 0 1.5rem 4rem rgba(46, 160, 67, 0.25);
  max-width: 60rem;
}
.confetti-icon { font-size: 7rem; line-height: 1; }
.confetti-title {
  font-size: 4rem;
  font-weight: 900;
  margin: 0.6rem 0 0.4rem;
  color: var(--ok-bright);
  letter-spacing: 0.02em;
}
.confetti-sub {
  font-size: 1.6rem;
  color: var(--fg);
  line-height: 1.4;
}


/* Personal page — user picker + KPI strip + workload tiles */
.user-picker-wrap {
  text-align: right;
  font-family: var(--mono);
  font-size: 0.85rem;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.6rem;
}
.user-picker {
  background: var(--bg-elev);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  padding: 0.25rem 0.5rem;
  font-family: inherit;
  font-size: inherit;
  min-width: 14rem;
}
.user-picker:focus {
  outline: none;
  border-color: var(--running-bright);
}

.kpi-strip {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.4rem;
  height: 100%;
  align-items: stretch;
}
.kpi-card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 0.2rem;
  padding: 0.5rem 0.7rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left: 0.25rem solid var(--dim);
  border-radius: 0.3rem;
  min-width: 0;
}
.kpi-card .kpi-label {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kpi-card .kpi-value {
  font-size: 2.2rem;
  font-weight: 800;
  font-family: var(--mono);
  line-height: 1;
}
.kpi-card .kpi-sub {
  font-size: 0.6rem;
  color: var(--muted);
}
.kpi-card.band-ok    { border-left-color: var(--ok); }
.kpi-card.band-ok    .kpi-value { color: var(--ok-bright); }
.kpi-card.band-warm  { border-left-color: var(--warn); }
.kpi-card.band-warm  .kpi-value { color: var(--warn); }
.kpi-card.band-bad   { border-left-color: var(--fail); }
.kpi-card.band-bad   .kpi-value { color: var(--fail-bright); }
.kpi-card.band-bad   { animation: failpulse 2.6s ease-in-out infinite; }
.kpi-card.band-neutral .kpi-value { color: var(--fg); }
.kpi-card.band-info  { border-left-color: var(--running-bright); }
.kpi-card.band-info  .kpi-value { color: var(--running-bright); }

.personal-empty {
  display: grid;
  place-items: center;
  height: 100%;
  text-align: center;
  gap: 0.6rem;
  padding: 1rem;
}
.personal-empty-title {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--muted);
}
.personal-empty-sub {
  font-size: 0.85rem;
  color: var(--dim);
}

/* ===================================================================
 * Artifacts page — per-project cards. Each card carries the project
 * icon + name + description and a stack of downloadable rows
 * (releases, packages, CI artifacts). Built for clicking on a 4K kiosk.
 * =================================================================== */
.artifacts-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0.2rem 0 0.4rem;
  font-size: 1rem;
}
.artifacts-filters {
  display: flex;
  gap: 0.7rem;
}
/* 300% of the prior 0.8rem chip — at 4K viewing distance the type
 * selector needs to be readable across the room. */
.artifact-filter {
  background: var(--bg-elev-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  padding: 0.75rem 2rem;
  font: inherit;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 2.4rem;
  font-weight: 700;
  line-height: 1;
}
.artifact-filter:hover { color: var(--fg); }
.artifact-filter.active {
  color: var(--running-bright);
  border-color: var(--running-bright);
}

/* The card board — auto-fill columns so we paint as many cards per
 * row as fit. 36rem is roughly the minimum width that keeps a long
 * generated filename + size + download fit on one row without ellipsis. */
.artifacts-board {
  display: grid;
  /* 54rem (150% of the prior 36rem) leaves room for long generated
   * filenames like maps-systemtests_integration_8d3f4a91.zip without
   * truncation on a 4K kiosk. */
  grid-template-columns: repeat(auto-fill, minmax(54rem, 1fr));
  /* Cards have a fixed height of ~32vh (twice the prior 16vh) so
   * projects with multiple releases + multiple CI artifacts have room
   * to show them all; long lists scroll inside the card. */
  grid-auto-rows: 32vh;
  gap: 0.8rem;
  align-content: start;
  padding: 0.2rem 0 1rem;
}
.artifact-card.no-artifacts {
  opacity: 0.55;
}
.artifact-card-empty {
  font-size: 0.85rem;
  color: var(--muted);
  padding: 0.4rem 0.2rem;
}

.artifact-card {
  display: grid;
  /* Header sized to content, rows section takes the rest and scrolls
   * internally if there are more artifacts than fit. */
  grid-template-rows: auto 1fr;
  gap: 0.55rem;
  padding: 0.9rem 1.1rem 1rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  min-width: 0;
  overflow: hidden;
}

.artifact-card-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.9rem;
  align-items: center;
  min-width: 0;
}
.artifact-card-icon {
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 0.5rem;
  background: var(--bg-elev);
  object-fit: cover;
  flex: 0 0 auto;
}
.artifact-card-icon-fallback {
  display: grid;
  place-items: center;
  font-size: 1.8rem;
  font-weight: 700;
  color: var(--muted);
}
.artifact-card-headtext { min-width: 0; }
.artifact-card-name {
  font-size: 1.4rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.artifact-card-ns {
  font-size: 0.78rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 0.1rem;
}
.artifact-card-desc {
  margin-top: 0.3rem;
  font-size: 0.95rem;
  color: var(--muted);
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.artifact-card-rows {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-height: 0;
  overflow-y: auto;
  /* Leave a hair of right-padding so the scrollbar doesn't crowd the
   * download icon column. */
  padding-right: 0.2rem;
}
.artifact-card-rows::-webkit-scrollbar { width: 6px; }
.artifact-card-rows::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 3px;
}

.artifact-row {
  display: grid;
  grid-template-columns: auto 1fr 2fr auto auto auto;
  align-items: center;
  gap: 0.7rem;
  padding: 0.5rem 0.7rem;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0.35rem;
  font-size: 0.95rem;
  min-width: 0;
}
.artifact-row > * {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Hide rows that don't match the active filter — and hide whole cards
 * whose rows have all been filtered out, so the board doesn't leak
 * empty cards. :has() is supported on every modern Chromium. */
.artifacts-board[data-filter="release"] .artifact-row:not([data-kind="release"]),
.artifacts-board[data-filter="package"] .artifact-row:not([data-kind="package"]),
.artifacts-board[data-filter="image"]   .artifact-row:not([data-kind="image"]),
.artifacts-board[data-filter="job"]     .artifact-row:not([data-kind="job"]) {
  display: none;
}
.artifacts-board[data-filter="release"] .artifact-card:not(:has(.artifact-row[data-kind="release"])),
.artifacts-board[data-filter="package"] .artifact-card:not(:has(.artifact-row[data-kind="package"])),
.artifacts-board[data-filter="image"]   .artifact-card:not(:has(.artifact-row[data-kind="image"])),
.artifacts-board[data-filter="job"]     .artifact-card:not(:has(.artifact-row[data-kind="job"])) {
  display: none;
}

.artifact-chip {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 800;
  padding: 0.2rem 0.6rem;
  border-radius: 0.3rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
}
.artifact-chip-release  { color: var(--ok-bright);      border-color: var(--ok); }
.artifact-chip-package  { color: var(--warn);           border-color: var(--warn); }
.artifact-chip-image    { color: var(--pending);        border-color: var(--pending); }
.artifact-chip-job      { color: var(--running-bright); border-color: var(--running); }

.artifact-copy {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--pending);
  font-size: 1.4rem;
  font-family: var(--mono);
  padding: 0.1rem 0.5rem;
  border-radius: 0.25rem;
  cursor: pointer;
  line-height: 1;
}
.artifact-copy:hover {
  color: var(--fg);
  background: rgba(139,148,158,0.12);
}

.artifact-label {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  min-width: 0;
}
.artifact-version {
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--fg);
}
.artifact-version-sha {
  color: var(--running-bright);
}
.artifact-sublabel {
  font-size: 0.78rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.artifact-file a {
  font-family: var(--mono);
  font-size: 0.95rem;
  color: var(--running-bright);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline-block;
  max-width: 100%;
}
.artifact-file a:hover { text-decoration: underline; }

.artifact-size,
.artifact-age {
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--muted);
  text-align: right;
}

.artifact-dl a {
  font-size: 1.4rem;
  text-decoration: none;
  color: var(--running-bright);
  padding: 0.15rem 0.5rem;
  border-radius: 0.25rem;
}
.artifact-dl a:hover { background: rgba(31,111,235,0.15); }

.artifacts-empty {
  padding: 3rem;
  text-align: center;
  color: var(--muted);
  font-size: 1.1rem;
}

/* ===================================================================
 * Links page — live VTR wiki view through the dashboard. Sidebar tree
 * of pages on the left, rendered markdown content on the right.
 * =================================================================== */
.wiki-sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  overflow: hidden;
}
.wiki-sidebar-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.7rem 0.9rem 0.5rem;
  border-bottom: 1px solid var(--border);
}
.wiki-sidebar-title {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
}
.wiki-sidebar-tree {
  overflow-y: auto;
  padding: 0.4rem 0.5rem 0.8rem;
  min-height: 0;
}
.wiki-sidebar-tree::-webkit-scrollbar { width: 6px; }
.wiki-sidebar-tree::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.wiki-tree-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.wiki-tree-list ul {
  list-style: none;
  margin: 0;
  padding-left: 0.9rem;
  border-left: 1px solid var(--border);
}
.wiki-tree-item {
  margin: 0.05rem 0;
}
.wiki-tree-folder {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  padding: 0.15rem 0.3rem;
  border-radius: 0.2rem;
  user-select: none;
}
.wiki-tree-folder:hover { color: var(--fg); }
.wiki-tree-folder::before {
  content: "▸";
  display: inline-block;
  width: 1em;
  font-size: 0.8em;
  color: var(--dim);
  transition: transform 120ms;
}
.wiki-tree-folder.open::before { transform: rotate(90deg); }
.wiki-tree-list .wiki-tree-folder.open + ul { display: block; }
.wiki-tree-list .wiki-tree-folder:not(.open) + ul { display: none; }

.wiki-tree-link {
  display: block;
  font-size: 0.85rem;
  padding: 0.2rem 0.35rem 0.2rem 1.2rem;
  border-radius: 0.2rem;
  color: var(--fg);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wiki-tree-link:hover { background: var(--bg-elev-2); color: var(--running-bright); }
.wiki-tree-link.active {
  background: rgba(31,111,235,0.18);
  color: var(--running-bright);
  font-weight: 600;
}

.wiki-content {
  grid-area: content;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  padding: 1.4rem 2rem 2rem;
  overflow-y: auto;
  min-height: 0;
  font-size: 1rem;
  line-height: 1.55;
  color: var(--fg);
}
.wiki-content::-webkit-scrollbar { width: 8px; }
.wiki-content::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.wiki-content h1, .wiki-content h2, .wiki-content h3, .wiki-content h4 {
  color: var(--fg);
  margin: 1.2em 0 0.5em;
  line-height: 1.2;
}
.wiki-content h1 { font-size: 1.7rem; border-bottom: 1px solid var(--border); padding-bottom: 0.3rem; }
.wiki-content h2 { font-size: 1.35rem; }
.wiki-content h3 { font-size: 1.1rem; }
.wiki-content h4 { font-size: 1rem; color: var(--muted); }
.wiki-content p { margin: 0.6em 0; }
.wiki-content a { color: var(--running-bright); text-decoration: underline; text-underline-offset: 2px; }
.wiki-content a:hover { color: var(--fg); }
.wiki-content code {
  background: var(--bg-elev-2);
  padding: 0.05rem 0.35rem;
  border-radius: 0.2rem;
  font-size: 0.92em;
}
.wiki-content pre {
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  padding: 0.7rem 0.9rem;
  overflow-x: auto;
  font-size: 0.85rem;
  line-height: 1.45;
}
.wiki-content pre code { background: none; padding: 0; font-size: inherit; }
.wiki-content blockquote {
  border-left: 0.25rem solid var(--border);
  padding: 0.2rem 0.9rem;
  margin: 0.8em 0;
  color: var(--muted);
}
.wiki-content ul, .wiki-content ol { margin: 0.5em 0 0.5em 1.4em; padding: 0; }
.wiki-content li { margin: 0.2em 0; }
.wiki-content table {
  border-collapse: collapse;
  margin: 0.8em 0;
  font-size: 0.92rem;
}
.wiki-content th, .wiki-content td {
  border: 1px solid var(--border);
  padding: 0.35rem 0.7rem;
  text-align: left;
}
.wiki-content th { background: var(--bg-elev-2); }
.wiki-content img {
  max-width: 100%;
  height: auto;
  border-radius: 0.3rem;
  border: 1px solid var(--border);
}
.wiki-content hr { border: none; border-top: 1px solid var(--border); margin: 1.4em 0; }
.wiki-content .wiki-title {
  font-size: 1.9rem;
  font-weight: 800;
  margin: 0 0 0.4em;
  letter-spacing: 0.01em;
}
.wiki-content .wiki-slug {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--muted);
  margin-bottom: 1.4em;
}
.wiki-empty {
  color: var(--muted);
  font-size: 0.95rem;
  padding: 2rem 0;
  text-align: center;
}

/* ===================================================================
 * Sprint page refactor — Sprint_ongoing-only kanban with bigger fonts,
 * status-coloured tiles + cards, activity roll-ups at the bottom.
 * =================================================================== */
.sprint-stats-scene {
  /* Title + 4 large stat tiles. No scene-body, header, or footer
   * apparatus — that scene chrome would shrink the tiles. */
  grid-template-rows: auto auto !important;
  padding: 0.5rem 0.7rem 0.6rem !important;
}
.sprint-stats-scene::before { content: none !important; }

.sprint-title-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding-bottom: 0.4rem;
}
.sprint-title {
  font-size: 1.7rem;
  font-weight: 800;
  letter-spacing: 0.01em;
}
.sprint-label {
  font-family: var(--mono);
  font-size: 1.45rem;
  color: var(--running-bright);
}
.sprint-subtitle {
  font-size: 0.95rem;
  color: var(--muted);
  font-family: var(--mono);
}

.sprint-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.7rem;
}
.sprint-stat {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 0.5rem 1rem 0.7rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-left-width: 0.45rem;
  border-radius: 0.45rem;
  min-height: 5.2rem;
}
.sprint-stat-count {
  font-size: 3.6rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  font-family: var(--mono);
}
.sprint-stat-label {
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.35rem;
}
.sprint-stat-backlog  { border-left-color: var(--muted);          }
.sprint-stat-backlog  .sprint-stat-count { color: var(--muted); }
.sprint-stat-assigned { border-left-color: var(--warn);           }
.sprint-stat-assigned .sprint-stat-count { color: var(--warn); }
.sprint-stat-active   { border-left-color: var(--running-bright); }
.sprint-stat-active   .sprint-stat-count { color: var(--running-bright); }
.sprint-stat-done     { border-left-color: var(--ok-bright);      }
.sprint-stat-done     .sprint-stat-count { color: var(--ok-bright); }

/* ---- Kanban (refactored) ---- */
.sprint-kanban {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.7rem;
  height: 100%;
}
.sprint-col {
  display: flex;
  flex-direction: column;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  min-height: 0;
  overflow: hidden;
}
.sprint-col-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.5rem 0.8rem 0.4rem;
  border-bottom: 1px solid var(--border);
}
.sprint-col-name {
  font-size: 1.4rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.sprint-col-count {
  font-family: var(--mono);
  font-size: 1.7rem;
  font-weight: 800;
}
.sprint-col.col-backlog  .sprint-col-name,
.sprint-col.col-backlog  .sprint-col-count { color: var(--muted); }
.sprint-col.col-assigned .sprint-col-name,
.sprint-col.col-assigned .sprint-col-count { color: var(--warn); }
.sprint-col.col-active   .sprint-col-name,
.sprint-col.col-active   .sprint-col-count { color: var(--running-bright); }
.sprint-col.col-done     .sprint-col-name,
.sprint-col.col-done     .sprint-col-count { color: var(--ok-bright); }
.sprint-col-list {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.55rem;
  overflow-y: auto;
  min-height: 0;
}
.sprint-col-list::-webkit-scrollbar { width: 6px; }
.sprint-col-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

.sprint-card {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-left-width: 0.4rem;
  border-radius: 0.4rem;
  padding: 0.5rem 0.7rem 0.55rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  text-decoration: none;
  color: inherit;
  /* Compact: just enough to anchor a sparse card. flex:0 0 auto prevents the
   * column scroll container from squashing cards to share remaining height. */
  min-height: 4.5rem;
  flex: 0 0 auto;
  transition: border-color 200ms, background 200ms;
}
.sprint-card:hover { background: var(--bg-elev-2); }
.sprint-card.status-backlog  { border-left-color: var(--muted); }
.sprint-card.status-assigned { border-left-color: var(--warn); }
.sprint-card.status-active   { border-left-color: var(--running-bright); }
.sprint-card.status-done     { border-left-color: var(--ok-bright); opacity: 0.9; }
.sprint-card-title {
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1.25;
  /* Up to 2 lines before tooltip truncation. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.sprint-card-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 1rem;
  color: var(--muted);
  font-family: var(--mono);
}
.sprint-card-meta .sprint-card-proj {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
.sprint-card-meta .sprint-card-iid {
  color: var(--running-bright);
  flex: 0 0 auto;
  margin-left: 0.5rem;
}
.sprint-card-no-assignee {
  font-size: 1rem;
  color: var(--dim);
  font-style: italic;
}
.sprint-card-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.sprint-card-link {
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 600;
  padding: 0.15rem 0.55rem;
  border-radius: 0.25rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  text-decoration: none;
  color: var(--fg);
  white-space: nowrap;
}
.sprint-card-link-mr     { color: var(--running-bright); border-color: var(--running); }
.sprint-card-link-commit { color: var(--ok-bright); border-color: var(--ok); }
.sprint-card-link-branch { color: var(--muted); border-color: var(--border); }
.sprint-card-link:hover { background: var(--bg-elev); }
.sprint-card-dim { color: var(--dim); }

/* Compact signal row: assignee · time · [pipeline-light]commit, all inline. */
.sprint-card-signal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.95rem;
  min-width: 0;
}
.sc-who {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-weight: 600;
  color: var(--fg);
  min-width: 0;
}
.sc-who > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sc-who .avatar { width: 1.5rem; height: 1.5rem; }
/* Active task with nobody assigned — show the last committer in red. */
.sc-who-unassigned { color: var(--fail-bright); font-style: italic; }
.sc-when { color: var(--muted); font-family: var(--mono); white-space: nowrap; }
.sc-sep { color: var(--dim); }
/* Pipeline light in front of the commit hash. */
.pipe-light { display: inline-block; vertical-align: middle; margin-right: 0.3rem; }
.pipe-light.pl-ok,
.pipe-light.pl-fail,
.pipe-light.pl-other { width: 0.7rem; height: 0.7rem; border-radius: 50%; }
.pl-ok    { background: var(--ok-bright);   box-shadow: 0 0 0.3rem rgba(86, 211, 100, 0.6); }
.pl-fail  { background: var(--fail-bright); box-shadow: 0 0 0.3rem rgba(248, 81, 73, 0.6); }
.pl-other { background: var(--pending); }
.pl-cog {
  color: var(--running-bright);
  font-size: 0.95rem;
  line-height: 1;
  animation: cog-spin 2.4s linear infinite;
  display: inline-block;
}

/* Milestone chip — links to the GitLab milestone when the issue has one. */
.sprint-card-milestone {
  align-self: flex-start;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 0.15rem 0.55rem;
  border-radius: 1rem;
  background: rgba(88, 166, 255, 0.12);
  border: 1px solid var(--running);
  color: var(--running-bright);
  text-decoration: none;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sprint-card-milestone:hover { background: rgba(88, 166, 255, 0.2); }

/* Active issue that isn't tagged into the sprint — flag it amber. */
.sprint-card.sprint-card-offsprint {
  border-left-color: var(--warn);
  background: rgba(210, 153, 34, 0.08);
}

/* Label filter row — chips steer the Backlog column. */
.sprint-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.5rem;
}
.sprint-filter-chip {
  font-family: var(--mono);
  font-size: 0.95rem;
  font-weight: 600;
  padding: 0.2rem 0.6rem;
  border-radius: 1rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  color: var(--muted);
  cursor: pointer;
  transition: background 150ms, color 150ms, border-color 150ms;
}
.sprint-filter-chip:hover { color: var(--fg); border-color: var(--muted); }
.sprint-filter-chip.active { color: #fff; }
.sprint-filter-count { opacity: 0.7; }

/* ---------- History page ---------- */
.history-summary-day {
  padding: 0.6rem 0.2rem;
  border-bottom: 1px solid var(--border);
}
.history-summary-day:last-child { border-bottom: none; }
.history-summary-date {
  font-family: var(--mono);
  font-size: 0.9rem;
  color: var(--muted);
  margin-bottom: 0.35rem;
}
.history-summary-text { font-size: 1.15rem; line-height: 1.45; }
.history-summary-text ul { margin: 0; padding-left: 1.3rem; }
.history-summary-text li { margin: 0.15rem 0; }
.history-summary-text p { margin: 0.25rem 0; }
.history-summary-empty { color: var(--muted); font-style: italic; padding: 0.6rem; }

/* History — action plan (Today / next steps + per-item advice) */
/* "What to do today" — the prominent, priority-ordered block at the top. */
.history-today-box {
  margin: 0 0 0.7rem;
  padding: 0.5rem 0.7rem 0.55rem;
  background: rgba(31, 111, 235, 0.1);
  border: 1px solid rgba(88, 166, 255, 0.35);
  border-left: 3px solid var(--running-bright);
  border-radius: 0.35rem;
}
.history-today-head {
  font-size: 0.92rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--running-bright);
  margin-bottom: 0.3rem;
}
.history-today { margin: 0; padding-left: 1.5rem; }
.history-today li { margin: 0.25rem 0; font-size: 1.08rem; line-height: 1.4; font-weight: 500; }
.history-item {
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--border);
  border-left: 3px solid transparent;
}
.history-item:last-child { border-bottom: none; }
/* Agile-conformance highlight — escalated worst-of(rule, LLM). */
.history-item.conf-poor { border-left-color: var(--fail); background: rgba(248, 81, 73, 0.08); }
.history-item.conf-warn { border-left-color: var(--warn); background: rgba(210, 153, 34, 0.07); }
.history-item.conf-ok { border-left-color: var(--ok); }
.history-item-link {
  display: block;
  color: var(--fg);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.98rem;
}
.history-item-link:hover { color: var(--running-bright); }
.history-dim { color: var(--muted); font-weight: 400; }
.history-advice {
  color: var(--fg);
  font-size: 0.92rem;
  line-height: 1.35;
  margin-top: 0.2rem;
}
.history-advice-label {
  color: var(--running-bright);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  margin-right: 0.3rem;
}
.history-expand {
  margin-top: 0.3rem;
  padding: 0.1rem 0.4rem;
  font: inherit;
  font-size: 0.76rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.25rem;
  cursor: pointer;
}
.history-expand:hover { color: var(--fg); border-color: var(--running); }
.history-analysis {
  margin-top: 0.35rem;
  padding: 0.5rem 0.6rem;
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--fg);
  background: var(--bg-elev-2);
  border-radius: 0.3rem;
}
.history-analysis[hidden] { display: none; }

/* Deep obsolescence verdict (issue #13) */
.hist-verdict { display: flex; align-items: baseline; gap: 0.4rem; margin-top: 0.2rem; }
.hist-verdict-badge {
  flex: none;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.03rem 0.4rem;
  border-radius: 0.25rem;
  color: #fff;
}
.verdict-merged .hist-verdict-badge { background: var(--running); }
.verdict-obsolete .hist-verdict-badge { background: var(--fail); }
.verdict-active .hist-verdict-badge { background: var(--ok); }
.hist-verdict-why { font-size: 0.85rem; color: var(--muted); line-height: 1.3; }

/* Delivery-tracking flags (issue link / sprint membership / take-it) */
.track-row { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.2rem; }
.track-tag {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.03rem 0.4rem;
  border-radius: 0.25rem;
  border: 1px solid currentColor;
}
.track-noissue { color: var(--fail-bright); }
.track-nosprint { color: var(--warn); }
.track-take { color: var(--running-bright); }
.activity-untracked {
  border-left: 3px solid var(--fail);
  padding-left: 0.4rem;
  background: rgba(248, 81, 73, 0.06);
}
.activity-untracked .track-tag { margin-left: 0.4rem; }

/* CI Health — master–detail board */
.ci-board {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: 23rem 1fr;
  gap: 0.6rem;
  padding: 0.6rem 0.8rem;
  overflow: hidden;
}
.ci-list, .ci-detail {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  overflow: auto;
  min-height: 0;
}
.ci-list { padding: 0.25rem; }
.ci-detail { padding: 0.7rem 0.95rem; }
.ci-li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.45rem;
  border-radius: 0.3rem;
  cursor: pointer;
  border-left: 3px solid transparent;
}
.ci-li:hover { background: var(--bg-elev-2); }
.ci-li.active { background: var(--bg-elev-2); border-left-color: var(--running-bright); }
.ci-li-overview { border-bottom: 1px solid var(--border); border-radius: 0; margin-bottom: 0.2rem; }
.ci-li-body { min-width: 0; flex: 1; }
.ci-li-title { font-weight: 600; font-size: 0.95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ci-li-sub { font-size: 0.78rem; color: var(--muted); }
.ci-li-red { color: var(--fail-bright); margin-right: 0.2rem; }
.ci-li-dots { display: flex; align-items: center; gap: 0.2rem; margin-top: 0.15rem; }
.ci-dot { width: 0.55rem; height: 0.55rem; border-radius: 50%; display: inline-block; }
.ci-dot.grade-good { background: var(--ok); }
.ci-dot.grade-mid { background: var(--warn); }
.ci-dot.grade-bad { background: var(--fail); }
.ci-dot.grade-na { background: var(--dim); }
.ci-li-min { font-size: 0.72rem; color: var(--muted); margin-left: 0.25rem; }
/* detail pane */
.ci-det-head { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
.ci-det-title { font-weight: 700; font-size: 1.05rem; }
.ci-det-sec {
  margin-top: 0.7rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
}
.ci-det-red { color: var(--fail-bright); }

/* Repo icon/avatar on the CI Health board (#26) */
.ci-li-icon {
  flex: none;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 0.25rem;
  object-fit: cover;
}
.ci-det-icon {
  flex: none;
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 0.3rem;
  object-fit: cover;
}
.ci-icon-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elev-2);
  color: var(--muted);
  font-weight: 700;
  font-size: 0.8rem;
}
.ci-det-desc { font-size: 0.9rem; color: var(--muted); margin: -0.2rem 0 0.4rem; line-height: 1.35; }

/* Per-repo facts (#25) */
.ci-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.7rem;
  margin: 0.35rem 0 0;
  font-size: 0.9rem;
}
.ci-facts dt { color: var(--muted); }
.ci-facts dd { margin: 0; color: var(--fg); }
.ci-fact-warn { color: var(--fail-bright); font-weight: 600; }
.ci-fact-mid { color: var(--warn, #d6a23a); font-weight: 600; }
/* #29 coverage figure */
.ci-cov { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--ok-bright, #4ec97a); }
.ci-cov.ci-fact-mid { color: var(--warn, #d6a23a); }
.ci-cov.ci-fact-warn { color: var(--fail-bright); }

/* #31 DORA metric cards (per-repo + group scorecard) */
.ci-dora {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.5rem;
  margin: 0.4rem 0 0;
}
.ci-dora-card {
  background: var(--panel-2, rgba(255, 255, 255, 0.03));
  border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
  border-radius: 0.5rem;
  padding: 0.5rem 0.6rem;
}
.ci-dora-n { font-size: 1.35rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.ci-dora-l { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.ci-dora-sub { font-size: 0.72rem; color: var(--muted); opacity: 0.8; margin-top: 0.1rem; }

/* SBOM audit (#27) — supply-chain status in the CI Health detail pane */
.ci-sbom-row { display: flex; align-items: baseline; gap: 0.5rem; margin-top: 0.35rem; flex-wrap: wrap; }
.ci-sbom-badge {
  flex: none;
  padding: 0.05rem 0.45rem;
  border-radius: 0.5rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.ci-sbom-ok      { background: rgba(46, 160, 67, 0.18);  color: var(--ok-bright); }
.ci-sbom-missing { background: rgba(255, 123, 114, 0.18); color: var(--fail-bright); }
.ci-sbom-invalid { background: rgba(255, 123, 114, 0.18); color: var(--fail-bright); }
.ci-sbom-stale   { background: rgba(210, 153, 34, 0.18);  color: var(--warn); }
.ci-sbom-reason { font-size: 0.9rem; color: var(--fg); }

/* CI Health page */
.rebuild-btn {
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--fg);
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.3rem;
  padding: 0.2rem 0.6rem;
  cursor: pointer;
}
.rebuild-btn:hover { border-color: var(--running); color: var(--running-bright); }
.rebuild-btn:disabled { opacity: 0.5; cursor: default; }
.ci-action {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.35rem 0.4rem;
  border-bottom: 1px solid var(--border);
}
.ci-action:last-child { border-bottom: none; }
.ci-prio {
  flex: none;
  font-weight: 700;
  font-size: 0.78rem;
  padding: 0.05rem 0.4rem;
  border-radius: 0.25rem;
  color: #fff;
}
.prio-P1 .ci-prio { background: var(--fail); }
.prio-P2 .ci-prio { background: var(--warn); color: #1a1a1a; }
.prio-P3 .ci-prio { background: var(--running); }
.ci-action-text { flex: 1; font-size: 1rem; line-height: 1.35; }
.ci-action-proj { flex: none; color: var(--muted); font-size: 0.8rem; font-family: var(--mono); }
.ci-jobs, .ci-chain { font-size: 0.85rem; color: var(--muted); margin-top: 0.2rem; }
.ci-chain-fail { color: var(--fail-bright); margin-right: 0.5rem; }
.ci-blame {
  margin-top: 0.3rem;
  font-size: 0.85rem;
  color: var(--muted);
  font-family: var(--mono);
}
.ci-blame a { color: var(--running-bright); text-decoration: none; }
.ci-blame-why { font-family: var(--font); margin-top: 0.15rem; color: var(--fg); }
.ci-row, .ci-finding {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.3rem 0.2rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.92rem;
}
.ci-row:last-child, .ci-finding:last-child { border-bottom: none; }
.ci-row-proj { font-family: var(--mono); font-size: 0.82rem; color: var(--fg); flex: none; }
.ci-finding-text { color: var(--muted); }
.ci-gap {
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--warn);
  border: 1px solid var(--warn);
  border-radius: 0.25rem;
  padding: 0.02rem 0.35rem;
}
.ci-dur { margin-left: auto; color: var(--warn); font-weight: 600; }
.ci-gap-row { display: flex; align-items: baseline; gap: 0.4rem; padding: 0.2rem 0; font-size: 0.9rem; flex-wrap: wrap; }
.ci-gap-arrow { color: var(--muted); }
/* CI/CD per-repo grades */
.ci-grade-head { display: flex; align-items: baseline; gap: 0.5rem; }
.ci-grade-overall {
  flex: none;
  font-weight: 800;
  font-size: 1.1rem;
  width: 1.6rem;
  text-align: center;
  border-radius: 0.3rem;
  color: #fff;
}
.ci-grades { display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.3rem; }
.ci-grade {
  font-size: 0.74rem;
  font-weight: 700;
  padding: 0.05rem 0.4rem;
  border-radius: 0.25rem;
  border: 1px solid currentColor;
}
.grade-good { color: var(--ok-bright); }
.grade-good.ci-grade-overall { background: var(--ok); color: #fff; }
.grade-mid { color: var(--warn); }
.grade-mid.ci-grade-overall { background: var(--warn); color: #1a1a1a; }
.grade-bad { color: var(--fail-bright); }
.grade-bad.ci-grade-overall { background: var(--fail); color: #fff; }
.grade-na { color: var(--muted); }
.grade-na.ci-grade-overall { background: var(--dim); color: #fff; }
.ci-agile-findings { margin: 0.3rem 0 0; padding-left: 1.2rem; }
.ci-agile-findings li { margin: 0.2rem 0; font-size: 0.9rem; line-height: 1.35; }
.ci-contract-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; }
.ci-contract-badge {
  flex: none;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 700;
  color: var(--muted);
}
.conf-poor .ci-contract-badge { color: var(--fail-bright); }
.conf-warn .ci-contract-badge { color: var(--warn); }
.conf-ok .ci-contract-badge { color: var(--ok-bright); }

.history-kpis {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}
.history-kpi {
  flex: 1 1 0;
  min-width: 5rem;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  padding: 0.4rem 0.5rem;
  text-align: center;
}
.history-kpi-n { font-size: 1.6rem; font-weight: 800; }
.history-kpi-l { font-size: 0.8rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.history-sub {
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 0.5rem 0 0.25rem;
}
.history-li {
  display: block;
  padding: 0.25rem 0.4rem;
  border-radius: 0.25rem;
  color: var(--fg);
  text-decoration: none;
  font-size: 1rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.history-li:hover { background: var(--bg-elev-2); }

/* ── SBOM / supply-chain page (#28) ─────────────────────────────────────── */
.sbom-cov { margin: 0.4rem 0 0.6rem; }
.sbom-cov-bar {
  height: 0.55rem; border-radius: 0.4rem; background: rgba(255,123,114,0.25);
  overflow: hidden; margin-bottom: 0.25rem;
}
.sbom-cov-bar > span { display: block; height: 100%; background: var(--ok-bright); }
.sbom-cov-repo { font-weight: 600; }

.sbom-vuln {
  border: 1px solid var(--border); border-radius: 0.5rem;
  padding: 0.45rem 0.6rem; margin-top: 0.45rem; background: rgba(255,255,255,0.015);
}
.sbom-vuln.waived { opacity: 0.6; }
.sbom-vuln-head { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.sbom-sev {
  flex: none; padding: 0.03rem 0.4rem; border-radius: 0.45rem;
  font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em;
}
.sbom-sev.sev-high { background: rgba(255,123,114,0.2); color: var(--fail-bright); }
.sbom-sev.sev-mid  { background: rgba(210,153,34,0.2);  color: var(--warn); }
.sbom-sev.sev-low  { background: rgba(139,148,158,0.2); color: var(--muted); }
.sbom-vuln-id { font-weight: 700; }
.sbom-vuln-id a { color: var(--running-bright); text-decoration: none; }
.sbom-vuln-pkg { color: var(--fg); }
.sbom-vuln-repo { margin-left: auto; color: var(--muted); font-size: 0.85rem; }
.sbom-vuln-sum { font-size: 0.88rem; color: var(--muted); margin-top: 0.2rem; }
.sbom-vuln-foot { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.3rem; flex-wrap: wrap; }
.sbom-fixed { color: var(--ok-bright); font-size: 0.82rem; font-weight: 600; }
.sbom-waived-tag { color: var(--muted); font-size: 0.82rem; font-style: italic; }

/* #34 — exploit-in-the-wild signal */
.sbom-vuln.kev    { border-color: rgba(255,123,114,0.55); }
.sbom-vuln.breach { box-shadow: inset 3px 0 0 var(--fail-bright); }
.sbom-kev {
  flex: none; padding: 0.03rem 0.4rem; border-radius: 0.45rem;
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.04em;
  background: var(--fail-bright); color: #1a0d0d;
}
.sbom-epss {
  font-size: 0.78rem; font-weight: 600; color: var(--warn);
  padding: 0.02rem 0.35rem; border: 1px solid rgba(210,153,34,0.4); border-radius: 0.4rem;
}
/* #33 — age + SLA */
.sbom-age {
  font-size: 0.78rem; font-weight: 600;
  padding: 0.02rem 0.35rem; border-radius: 0.4rem;
}
.sbom-age.sla-ok     { color: var(--muted); }
.sbom-age.sla-waived { color: var(--muted); font-style: italic; }
.sbom-age.sla-warn   { color: var(--warn); background: rgba(210,153,34,0.12); }
.sbom-age.sla-breach { color: var(--fail-bright); background: rgba(255,123,114,0.15); font-weight: 700; }
.sbom-vuln-banner { display: flex; gap: 0.6rem; flex-wrap: wrap; margin: 0.3rem 0 0.1rem; }
.sbom-honesty { font-size: 0.8rem; margin: 0.15rem 0 0.5rem; font-style: italic; }
.sbom-mttr-note { margin-top: 0.3rem; font-size: 0.82rem; }
.history-kpi.kpi-alert .history-kpi-n { color: var(--fail-bright); }
.sbom-waive-btn, .sbom-unwaive-btn {
  font: inherit; font-size: 0.78rem; cursor: pointer; margin-left: auto;
  background: transparent; color: var(--running-bright);
  border: 1px solid var(--border); border-radius: 0.4rem; padding: 0.08rem 0.5rem;
}
.sbom-waive-btn:hover, .sbom-unwaive-btn:hover { border-color: var(--running-bright); }

.sbom-reconsider-note { margin: 0.2rem 0 0.5rem; font-size: 0.82rem; }
.sbom-reconsider {
  border: 1px solid var(--border); border-left: 3px solid var(--warn);
  border-radius: 0.5rem; padding: 0.45rem 0.6rem; margin-top: 0.45rem;
  background: rgba(255,255,255,0.015);
}
.sbom-reconsider.reason-unnecessary { border-left-color: var(--running-bright); }
.sbom-reconsider-head { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.sbom-reconsider-reason {
  flex: none; padding: 0.03rem 0.4rem; border-radius: 0.45rem;
  font-size: 0.68rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em;
  background: rgba(210,153,34,0.2); color: var(--warn);
}
.sbom-reconsider-reason.reason-unnecessary { background: rgba(88,166,255,0.18); color: var(--running-bright); }
.sbom-reconsider-pkg { color: var(--fg); }
.sbom-reconsider-sug { font-size: 0.88rem; color: var(--ok-bright); margin-top: 0.25rem; }
.sbom-reconsider-foot { font-size: 0.82rem; color: var(--muted); margin-top: 0.25rem; }
.sbom-reconsider-who { color: var(--fg); }
.sbom-reconsider-who a { color: var(--running-bright); text-decoration: none; }

.sbom-spread { border-bottom: 1px solid var(--border); padding: 0.35rem 0; }
.sbom-spread-name { margin-bottom: 0.15rem; }
.sbom-spread-ver { display: flex; gap: 0.5rem; font-size: 0.85rem; padding: 0.05rem 0 0.05rem 0.6rem; }
.sbom-ver { font-weight: 700; color: var(--warn); min-width: 5rem; }

.sbom-lic { display: flex; align-items: baseline; gap: 0.55rem; padding: 0.18rem 0; }
.sbom-lic-risk {
  flex: none; min-width: 5.5rem; text-align: center;
  padding: 0.02rem 0.4rem; border-radius: 0.4rem;
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
.sbom-lic-risk.risk-copyleft   { background: rgba(255,123,114,0.18); color: var(--fail-bright); }
.sbom-lic-risk.risk-unknown    { background: rgba(210,153,34,0.18);  color: var(--warn); }
.sbom-lic-risk.risk-other      { background: rgba(139,148,158,0.18); color: var(--muted); }
.sbom-lic-risk.risk-permissive { background: rgba(46,160,67,0.16);   color: var(--ok-bright); }
.sbom-lic-name { font-weight: 600; }

.sbom-waiver { border-bottom: 1px solid var(--border); padding: 0.35rem 0; position: relative; }
.sbom-waiver-cmt { font-size: 0.88rem; color: var(--fg); margin-top: 0.15rem; }
.sbom-waiver-note { font-size: 0.82rem; color: var(--warn); margin-top: 0.1rem; }
