/* Elire SPOT Tracker — single stylesheet, no external assets (CSP: 'self'). */
:root {
  --bg: #f6f6f4;
  --panel: #ffffff;
  --panel-2: #fbfbf9;
  --border: #dcdcd4;
  --text: #1e2220;
  --muted: #6b7370;
  --accent: #2f6f4e;
  --accent-soft: #e6f0ea;
  --ok: #2f6f4e;
  --warn: #9a6a10;
  --crit: #a63b2a;
  --info: #2b5c86;
  --radius: 8px;
  --shadow: 0 1px 2px rgba(0, 0, 0, .06), 0 4px 12px rgba(0, 0, 0, .04);
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141815;
    --panel: #1c211e;
    --panel-2: #232925;
    --border: #333b36;
    --text: #e6eae7;
    --muted: #9aa5a0;
    --accent: #6bbd91;
    --accent-soft: #22302a;
    --ok: #6bbd91;
    --warn: #d9a441;
    --crit: #e2765f;
    --info: #74aad8;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 12px rgba(0, 0, 0, .3);
  }
}

* { box-sizing: border-box; }
body {
  margin: 0;
  font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3 { margin: 0 0 .5rem; font-weight: 600; line-height: 1.25; }
h1 { font-size: 1.35rem; }
h2 { font-size: 1.05rem; }
h3 { font-size: .9rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }

/* --- chrome --------------------------------------------------------------- */
header.topbar {
  display: flex; align-items: center; gap: 1rem;
  padding: .7rem 1.25rem;
  background: var(--panel); border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
}
.brand { font-weight: 700; letter-spacing: -.01em; }
.brand span { color: var(--accent); }
nav.tabs { display: flex; gap: .25rem; margin-left: 1rem; flex-wrap: wrap; }
nav.tabs button {
  background: none; border: 1px solid transparent; color: var(--muted);
  padding: .35rem .7rem; border-radius: var(--radius); cursor: pointer; font: inherit;
}
nav.tabs button:hover { background: var(--panel-2); color: var(--text); }
nav.tabs button[aria-current="true"] { background: var(--accent-soft); color: var(--accent); border-color: var(--border); font-weight: 600; }
.spacer { flex: 1; }
.whoami { color: var(--muted); font-size: .85rem; }

main { padding: 1.25rem; max-width: 1500px; margin: 0 auto; }

/* --- primitives ----------------------------------------------------------- */
.card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1rem; box-shadow: var(--shadow);
}
.grid { display: grid; gap: 1rem; }
.grid.stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.grid.two { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.stat .n { font-size: 1.8rem; font-weight: 650; letter-spacing: -.02em; }
.stat .l { color: var(--muted); font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; }
.stat.crit .n { color: var(--crit); }
.stat.warn .n { color: var(--warn); }

.badge {
  display: inline-block; padding: .1rem .45rem; border-radius: 999px;
  font-size: .72rem; font-weight: 600; border: 1px solid var(--border);
  background: var(--panel-2); color: var(--muted); white-space: nowrap;
}
.badge.ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, transparent); background: color-mix(in srgb, var(--ok) 10%, transparent); }
.badge.warning { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); background: color-mix(in srgb, var(--warn) 12%, transparent); }
.badge.critical, .badge.expired, .badge.bad { color: var(--crit); border-color: color-mix(in srgb, var(--crit) 40%, transparent); background: color-mix(in srgb, var(--crit) 12%, transparent); }
.badge.info { color: var(--info); border-color: color-mix(in srgb, var(--info) 40%, transparent); background: color-mix(in srgb, var(--info) 12%, transparent); }

table { width: 100%; border-collapse: collapse; font-size: .875rem; }
th, td { text-align: left; padding: .5rem .6rem; border-bottom: 1px solid var(--border); vertical-align: top; }
th { color: var(--muted); font-weight: 600; font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; }
tbody tr:hover { background: var(--panel-2); }
.table-wrap { overflow-x: auto; }

button.btn, .btn {
  font: inherit; cursor: pointer; padding: .4rem .8rem; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--panel-2); color: var(--text);
}
button.btn:hover { border-color: var(--accent); }
button.btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
@media (prefers-color-scheme: dark) { button.btn.primary { color: #10201a; } }
button.btn.danger { color: var(--crit); }
button.btn.tiny { padding: .15rem .45rem; font-size: .78rem; }

input, select, textarea {
  font: inherit; width: 100%; padding: .4rem .55rem; color: var(--text);
  background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--radius);
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
label { display: block; font-size: .78rem; color: var(--muted); margin: .6rem 0 .2rem; font-weight: 600; }
textarea { min-height: 80px; resize: vertical; }

.row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.muted { color: var(--muted); }
.small { font-size: .8rem; }
.mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; font-size: .82em; }
.right { text-align: right; }
.mt { margin-top: 1rem; }
.empty { color: var(--muted); padding: 1.5rem; text-align: center; font-style: italic; }

/* --- timeline ------------------------------------------------------------- */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { position: relative; padding: .6rem 0 .6rem 1.4rem; border-bottom: 1px solid var(--border); }
.timeline li::before {
  content: ''; position: absolute; left: .25rem; top: 1rem;
  width: 8px; height: 8px; border-radius: 50%; background: var(--muted);
}
.timeline li.t-feedback::before { background: var(--info); }
.timeline li.t-incident::before { background: var(--crit); }
.timeline li.t-license::before { background: var(--warn); }
.timeline li.t-deploy::before, .timeline li.t-change::before { background: var(--accent); }
.timeline .when { color: var(--muted); font-size: .78rem; }
.timeline .body { white-space: pre-wrap; margin-top: .25rem; }

/* --- dialog --------------------------------------------------------------- */
dialog {
  border: 1px solid var(--border); border-radius: var(--radius); padding: 0;
  background: var(--panel); color: var(--text); width: min(640px, 94vw); box-shadow: var(--shadow);
}
dialog::backdrop { background: rgba(0, 0, 0, .45); }
dialog .dlg-head { padding: .85rem 1rem; border-bottom: 1px solid var(--border); font-weight: 600; }
dialog .dlg-body { padding: 1rem; max-height: 65vh; overflow-y: auto; }
dialog .dlg-foot { padding: .75rem 1rem; border-top: 1px solid var(--border); display: flex; gap: .5rem; justify-content: flex-end; }

/* --- field help ----------------------------------------------------------- */
/* A "?" beside a label that reveals how to obtain the value. Collapsed by
   default so a familiar operator sees an uncluttered form, and the hint sits in
   the flow (not a hover tooltip) so it works on touch and for screen readers. */
.hint-btn {
  display: inline-grid; place-items: center; width: 1.05rem; height: 1.05rem;
  margin-left: .35rem; padding: 0; vertical-align: middle;
  border: 1px solid var(--border); border-radius: 50%; background: var(--panel-2);
  color: var(--muted); font-size: .7rem; font-weight: 700; line-height: 1;
  cursor: help; font-family: inherit;
}
.hint-btn:hover, .hint-btn:focus-visible { border-color: var(--accent); color: var(--accent); }
.hint-btn[aria-expanded="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.field-hint {
  margin: .3rem 0 .1rem; padding: .5rem .6rem;
  background: var(--panel-2); border-left: 2px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  font-size: .78rem; font-weight: 400; color: var(--text); line-height: 1.45;
}
.field-hint code {
  display: inline-block; background: var(--bg); border: 1px solid var(--border);
  border-radius: 4px; padding: 0 .25rem; font-size: .74rem;
}
.field-hint .cmd { display: block; margin: .3rem 0 0; white-space: pre-wrap; word-break: break-word; }

#toast {
  position: fixed; bottom: 1.25rem; right: 1.25rem; z-index: 100;
  background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius); padding: .6rem .9rem; box-shadow: var(--shadow);
  opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; pointer-events: none;
}
#toast.show { opacity: 1; transform: none; }
#toast.err { border-left-color: var(--crit); }

/* --- login ---------------------------------------------------------------- */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 1rem; }
.login-card { width: min(380px, 100%); }
.login-card h1 { text-align: center; margin-bottom: 1.25rem; }
.login-err { color: var(--crit); font-size: .85rem; min-height: 1.2em; margin-top: .6rem; }

/* --- discovery Q&A -------------------------------------------------------- */
.qa-list { display: grid; gap: .6rem; margin-top: .5rem; }
.qa {
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius); padding: .7rem .85rem; background: var(--panel-2);
}
.qa-q { font-weight: 600; margin-top: .4rem; white-space: pre-wrap; }
.qa-a { margin-top: .4rem; white-space: pre-wrap; font-size: .9rem; }
.qa-n {
  margin-top: .5rem; padding-top: .45rem; border-top: 1px dashed var(--border);
  font-size: .82rem; color: var(--muted); white-space: pre-wrap;
}

/* --- discovery: category sidebar ----------------------------------------- */
.qa-layout {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: 1.25rem;
  margin-top: .9rem;
  align-items: start;
}
.qa-nav {
  display: flex; flex-direction: column; gap: 1px;
  position: sticky; top: 4.5rem;          /* clears the sticky topbar */
  max-height: calc(100vh - 6rem); overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel-2); padding: .3rem;
}
.qa-nav-item {
  display: flex; align-items: center; gap: .5rem;
  width: 100%; text-align: left; font: inherit; font-size: .84rem;
  padding: .42rem .55rem; border: 1px solid transparent;
  border-radius: calc(var(--radius) - 2px);
  background: none; color: var(--muted); cursor: pointer;
}
.qa-nav-item:hover { background: var(--panel); color: var(--text); }
.qa-nav-item[aria-current="true"] {
  background: var(--accent-soft); color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 35%, transparent); font-weight: 600;
}
.qa-nav-label { flex: 1; line-height: 1.3; }
.qa-nav-counts { display: flex; align-items: center; gap: .25rem; flex-shrink: 0; }
.qa-nav-n {
  font-variant-numeric: tabular-nums; font-size: .78rem;
  color: var(--muted); min-width: 1.4em; text-align: right;
}
.qa-nav-item[aria-current="true"] .qa-nav-n { color: var(--accent); }
.qa-nav-sep { height: 1px; background: var(--border); margin: .3rem .2rem; }

.qa-main { min-width: 0; }
.qa-section + .qa-section { margin-top: 1.4rem; }

/* Stack the sidebar above the list on narrow screens rather than squeezing it. */
@media (max-width: 900px) {
  .qa-layout { grid-template-columns: 1fr; }
  .qa-nav {
    position: static; max-height: none;
    flex-direction: row; flex-wrap: wrap; gap: .3rem;
  }
  .qa-nav-item { width: auto; }
  .qa-nav-sep { display: none; }
}

/* --- delivery build-out ---------------------------------------------------- */

/* Promotion model: gold main -> export gate -> dist -> fan-out -> per-client. */
.flow { display: flex; align-items: stretch; gap: .5rem; flex-wrap: wrap; }
.flow-node {
  flex: 1 1 170px; min-width: 0;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel-2); padding: .7rem .75rem;
  display: flex; flex-direction: column; gap: .3rem;
}
.flow-node.internal { border-color: color-mix(in srgb, var(--crit) 40%, var(--border)); }
.flow-node.export   { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.flow-node.dist     { border-color: color-mix(in srgb, var(--ok) 45%, var(--border)); }
.flow-node.client   { border-color: color-mix(in srgb, var(--accent) 55%, var(--border));
                      background: var(--accent-soft); }
.flow-title { font-weight: 650; font-size: .88rem; letter-spacing: -.01em; word-break: break-word; }
.flow-sub { font-size: .74rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.flow-body { font-size: .78rem; line-height: 1.45; flex: 1; }
.flow-node .badge { align-self: flex-start; }
.flow-arrow { align-self: center; color: var(--muted); font-size: 1.1rem; flex: 0 0 auto; }

/* Phase swimlanes. */
.phases { display: grid; gap: 1.2rem; }
.phase-head { display: flex; align-items: baseline; gap: .5rem; }
.phase-head h3 { font-size: .95rem; }
.phase-bar { height: 3px; background: var(--border); border-radius: 2px; margin: .35rem 0 .1rem; }
.phase-bar span { display: block; height: 100%; background: var(--accent); border-radius: 2px; }
.phase-when { margin: 0 0 .7rem; }
.ritems { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: .7rem; }

.ritem {
  border: 1px solid var(--border); border-left: 3px solid var(--muted);
  border-radius: var(--radius); background: var(--panel-2); padding: .65rem .75rem;
  display: flex; flex-direction: column; gap: .35rem;
}
.ritem.blocked  { border-left-color: var(--warn); }
.ritem.active   { border-left-color: var(--info); }
.ritem.done     { border-left-color: var(--ok); opacity: .62; }
.ritem.deferred { border-left-color: var(--border); opacity: .55; }
.ritem-head { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.ritem-title { font-size: .9rem; font-weight: 620; line-height: 1.35; margin: 0; }
.rref { font-weight: 650; color: var(--muted); }
.tiny-badge { font-size: .68rem; }
.rstatus { font-size: .75rem; padding: .12rem .3rem; }

/* The concrete GitLab object, so "what do I click" needs no cross-reference. */
.rgl {
  background: var(--panel); border: 1px solid var(--border); border-radius: 5px;
  padding: .25rem .4rem; word-break: break-word;
}
.rgl-l {
  color: var(--muted); text-transform: uppercase; letter-spacing: .05em;
  font-size: .68rem; margin-right: .4rem;
}
.rdeps { display: flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
.rblast {
  font-size: .78rem; line-height: 1.45;
  border-left: 2px solid var(--crit); padding: .25rem .5rem;
  background: color-mix(in srgb, var(--crit) 6%, transparent); border-radius: 0 5px 5px 0;
}
.rdetail summary { cursor: pointer; font-size: .78rem; color: var(--accent); }
.rdetail > div { white-space: pre-wrap; font-size: .8rem; line-height: 1.5; margin-top: .35rem; }
.rfoot { gap: .3rem; }

/* Track colours — categorical, so a track reads at a glance without a legend. */
.badge.track-gitlab       { color: var(--info);   border-color: color-mix(in srgb, var(--info) 35%, transparent); }
.badge.track-supply-chain { color: #6b4ea6;       border-color: color-mix(in srgb, #6b4ea6 35%, transparent); }
.badge.track-security     { color: var(--crit);   border-color: color-mix(in srgb, var(--crit) 35%, transparent); }
.badge.track-infra        { color: #1f6f74;       border-color: color-mix(in srgb, #1f6f74 35%, transparent); }
.badge.track-docs         { color: var(--warn);   border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.badge.track-process      { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.badge.track-peoplesoft   { color: #8a5a2b;       border-color: color-mix(in srgb, #8a5a2b 35%, transparent); }

/* Per-client onboarding runbook. */
.csteps { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.cstep { display: flex; gap: .6rem; align-items: flex-start; }
.cstep-n {
  flex: 0 0 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center; font-size: .78rem; font-weight: 650;
}
.cstep.done .cstep-n { background: var(--ok); color: #fff; }
.cstep-body { flex: 1; min-width: 0; border-bottom: 1px solid var(--border); padding-bottom: .5rem; }
.cstep:last-child .cstep-body { border-bottom: 0; }

.chk { display: inline-flex; align-items: center; gap: .3rem; }
.chk input { width: auto; }
tr.dec-open td { background: color-mix(in srgb, var(--warn) 5%, transparent); }

@media (max-width: 720px) {
  .flow { flex-direction: column; }
  .flow-arrow { transform: rotate(90deg); align-self: flex-start; margin-left: 1.2rem; }
  .ritems { grid-template-columns: 1fr; }
}

/* Input plus an inline action (e.g. Generate a UUID). */
.field-row { display: flex; gap: .4rem; align-items: stretch; }
.field-row > input { flex: 1 1 auto; min-width: 0; }
.field-row > .gen-btn { flex: 0 0 auto; white-space: nowrap; align-self: stretch; }
.field-row > .ref-btn { flex: 0 0 auto; white-space: nowrap; align-self: stretch; }

/* --- install panel -------------------------------------------------------- */
/* Was a fixed panel docked to the right of the viewport. That detached the
   guidance from the build it describes, so with two builds it silently talked
   about the newest one. It is now an expandable row inside the builds table:
   it cannot be about any build but the one it sits under, and it pushes the
   table down instead of covering it. */
.install-row > td { background: var(--bg-alt, rgba(0, 0, 0, .02)); padding: 0; }
.install-body {
  padding: .75rem .9rem;
  border-left: 3px solid var(--accent, #4a7);
}
.install-steps { margin: .5rem 0 .6rem; padding-left: 1.15rem; }
.install-steps li { margin: .25rem 0; }
.install-body .dock-actions { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .5rem; }

/* --- documents ------------------------------------------------------------ */
/* The panel reuses .qa-layout / .qa-nav from Discovery so the two read as the
   same control, and only needs the section spacing here. */
.doc-section { margin-bottom: 1.25rem; }
.doc-section:last-of-type { margin-bottom: 0; }
.doc-section > h3 {
  margin: 0 0 .4rem; padding-bottom: .3rem;
  border-bottom: 1px solid var(--border);
}


/* --- build detail (View) --------------------------------------------------- */
/* View used to print the manifest JSON, which is the same bytes the Manifest
   button downloads — the right artifact to hand to an installer, the wrong one
   to read. These styles carry the readable rendering. */
.bd-sect { margin: 0 0 1rem; }
.bd-sect > h4 {
  margin: 0 0 .4rem; font-size: .82rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); font-weight: 600;
}
.bd-sect.bd-warn {
  border-left: 3px solid var(--warn, #c80); padding: .5rem .75rem;
  background: rgba(204, 136, 0, .07); border-radius: 4px;
}
.bd-sect.bd-ok {
  border-left: 3px solid var(--ok, #3a7); padding: .5rem .75rem;
  background: rgba(51, 170, 119, .07); border-radius: 4px;
}
.bd-sect.bd-warn > h4, .bd-sect.bd-ok > h4 { color: inherit; }
.bd-sect ul { margin: .2rem 0; padding-left: 1.1rem; }
.bd-sect li { margin: .2rem 0; }

/* Definition grid: label column sized to content, value takes the rest. */
dl.kv { display: grid; grid-template-columns: minmax(9rem, max-content) 1fr; gap: .3rem .9rem; margin: 0; }
dl.kv dt { color: var(--muted); font-size: .82rem; }
dl.kv dd { margin: 0; font-size: .86rem; word-break: break-word; }

/* Wide tables scroll inside the dialog rather than widening it. */
table.bd-table { width: 100%; border-collapse: collapse; display: block; overflow-x: auto; }
table.bd-table th, table.bd-table td {
  text-align: left; padding: .28rem .5rem; border-bottom: 1px solid var(--border); vertical-align: top;
}
table.bd-table th { color: var(--muted); font-weight: 600; white-space: nowrap; }

details.bd-sect > summary { cursor: pointer; color: var(--muted); }
.manifest-raw { white-space: pre-wrap; max-height: 50vh; overflow: auto; margin-top: .5rem; }

/* --- R&D studies ---------------------------------------------------------- */
/* Studies are framed, not inlined: each carries its own :root tokens and would
   otherwise repaint the whole tracker. The frame is chrome-less and grows to the
   document's height (see renderRnd) so the study never gets a second scrollbar
   inside the page's own. */
.rnd-nav-group {
  font-size: .68rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); padding: .5rem .55rem .3rem;
}
.rnd-frame {
  margin-top: .9rem; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); overflow: hidden;
}
.rnd-frame iframe {
  display: block; width: 100%; border: 0;
  min-height: 60vh;      /* before the height is measured, and the fallback if it cannot be */
}
@media print {
  /* Printing from the tracker chrome prints the chrome. The Print button targets
     the study's own window instead; this is just a sensible fallback. */
  .qa-nav, .topbar { display: none !important; }
  .rnd-frame { border: none; }
}

/* ── build progress ──────────────────────────────────────────────────────────
   A bundle build takes tens of minutes. The status cell used to show a static
   "building…" badge for the whole run, which is indistinguishable from a build
   that died — and six EF builds this week did die, all stalling in the same
   phase. The bar is driven by the producer's own phase counter, never by
   elapsed time: it advances when real work completes and visibly stops when the
   work does. That is the point of it. */
.bprog { min-width: 9rem; }
.bprog .bar {
  position: relative; height: 6px; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--border); overflow: hidden;
}
.bprog .bar > i {
  display: block; height: 100%; border-radius: 999px;
  background: var(--accent); transition: width .6s ease;
}
/* Stalled: the producer has printed nothing for a while. Recoloured rather than
   animated, because an animation would imply progress that is not happening. */
.bprog.stalled .bar > i { background: var(--warn); }
.bprog.failing .bar > i { background: var(--crit); }
.bprog .lbl {
  display: flex; justify-content: space-between; gap: .5rem;
  font-size: .68rem; color: var(--muted); margin-top: .2rem;
}
.bprog .lbl b { font-weight: 600; color: var(--text); }
.bprog .err { color: var(--crit); font-size: .68rem; margin-top: .2rem; }
