/* Greyscale wireframe — operational tool */
:root {
  --ink: #1a1a1a;
  --ink-2: #3a3a3a;
  --muted: #6b6b6b;
  --muted-2: #9a9a9a;
  --line: #cfcfcf;
  --line-2: #e2e2e2;
  --bg: #f6f6f6;
  --bg-2: #ececec;
  --paper: #ffffff;
  --hl: #1a1a1a;
  --warn: #6b6b6b;
  --shadow: 0 8px 24px rgba(0,0,0,0.08);
  --mono: "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; background: var(--bg); color: var(--ink); font-family: var(--sans); font-size: 13px; line-height: 1.4; }
button { font: inherit; color: inherit; cursor: pointer; }
a { color: inherit; }

/* App shell */
.app {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-rows: 100vh;
  height: 100vh;
  overflow: hidden;
}
.sidebar {
  background: #efefef;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: 16px 0;
  min-height: 0;
  overflow: auto;
}
.sidebar .brand {
  padding: 0 18px 18px;
  border-bottom: 1px dashed var(--line);
  margin-bottom: 12px;
}
.sidebar .brand .name { font-family: var(--display); font-size: 16px; font-weight: 700; letter-spacing: -0.02em; }
.sidebar .brand .sub { font-family: var(--mono); font-size: 10px; color: var(--muted); margin-top: 2px; text-transform: uppercase; letter-spacing: 0.08em; }
/* UIFX-16: the mark sits on one row with the wordmark; the type treatment above is unchanged. */
.sidebar .brand .brand-row { display: flex; align-items: center; gap: 10px; }
.sidebar .brand .mark { flex: 0 0 auto; display: block; }

.nav { display: flex; flex-direction: column; padding: 0 8px; gap: 2px; }
.nav-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  border-radius: 4px;
  border: none;
  background: transparent;
  text-align: left;
  color: var(--ink);
  font-size: 13px;
}
.nav-item:hover { background: rgba(0,0,0,0.05); }
.nav-item.active { background: var(--ink); color: var(--paper); }
.nav-item .badge {
  font-family: var(--mono);
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 8px;
  background: rgba(0,0,0,0.12);
  min-width: 18px;
  text-align: center;
}
.nav-item.active .badge { background: rgba(255,255,255,0.2); color: var(--paper); }

.sidebar .spacer { flex: 1; }

.uploads-strip {
  border-top: 1px dashed var(--line);
  padding: 10px 14px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-2);
}
.uploads-strip .head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.uploads-strip .upload-row { display: flex; flex-direction: column; gap: 2px; margin-bottom: 6px; }
.uploads-strip .upload-row .nm { font-size: 11px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uploads-strip .upload-row .meta { color: var(--muted); font-size: 10px; }
.uploads-strip .pbar { height: 3px; background: var(--line-2); position: relative; border-radius: 2px; overflow: hidden; }
.uploads-strip .pbar > div { background: var(--ink); height: 100%; transition: width 200ms linear; }

/* Main pane */
/* UIFX-01 root cause: the notification drawer is position:absolute, and without a positioned
   ancestor it resolves against the initial containing block, so .app's viewport clip
   (height:100vh; overflow:hidden) never applies to it and a long drawer grows the document.
   .content below already carries position:relative — that is precisely why the slide-in .panel
   never had this bug, and why .main needs the same. */
.main { display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); position: relative; }

.topbar {
  height: 48px;
  background: var(--paper);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 16px;
}
.topbar .crumb { font-family: var(--mono); font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
.topbar .crumb .here { color: var(--ink); }
.topbar .spacer { flex: 1; }
.topbar .icon-btn {
  position: relative;
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--line); border-radius: 4px;
}
.topbar .icon-btn:hover { background: var(--bg-2); }
.topbar .icon-btn .dot {
  position: absolute; top: 4px; right: 4px;
  background: var(--ink); color: var(--paper);
  font-family: var(--mono); font-size: 9px;
  padding: 1px 4px; border-radius: 6px; line-height: 1.1;
  min-width: 14px; text-align: center;
}
.topbar .user {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px 4px 4px; border: 1px solid var(--line); border-radius: 20px;
}
.topbar .user .avatar { width: 24px; height: 24px; border-radius: 50%; background: var(--ink); color: var(--paper); display: inline-flex; align-items: center; justify-content: center; font-family: var(--mono); font-size: 10px; }
.topbar .user .nm { font-size: 12px; }

.content { flex: 1; min-height: 0; overflow: auto; position: relative; }
.content-inner { padding: 20px 24px; }

/* Page header */
.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  margin-bottom: 16px;
  gap: 16px;
}
.page-head h1 { font-family: var(--display); font-size: 22px; font-weight: 600; margin: 0; letter-spacing: -0.02em; }
.page-head .sub { font-family: var(--mono); font-size: 11px; color: var(--muted); margin-top: 2px; text-transform: uppercase; letter-spacing: 0.06em; }
.page-head .actions { display: flex; gap: 8px; align-items: center; }

/* Buttons */
.btn { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 1px solid var(--line); background: var(--paper); border-radius: 4px; font-size: 12px; }
.btn:hover { background: var(--bg-2); }
.btn-primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn-primary:hover { background: #000; }
.btn-ghost { border-color: transparent; background: transparent; }
.btn-ghost:hover { background: var(--bg-2); }
.btn-danger { color: #5a1818; border-color: #c9a8a8; }
.btn-sm { padding: 3px 8px; font-size: 11px; }

/* Filter chips */
.chips { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; align-items: center; }
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 10px;
  border: 1px solid var(--line); background: var(--paper);
  border-radius: 14px;
  font-size: 11px;
  font-family: var(--mono);
}
.chip:hover { background: var(--bg-2); }
.chip.active { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.chip .x { font-size: 9px; opacity: 0.6; }
.chips .label { font-family: var(--mono); font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-right: 4px; }

/* Page-size control (UIFX-02) — an inline caption plus a compact native select, sized to sit
   level with the .btn-sm buttons it shares a row with. */
.pagesize {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 10px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.pagesize select {
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--paper); color: var(--ink);
  font: inherit; font-size: 11px; text-transform: none; letter-spacing: 0;
  padding: 3px 6px;
  cursor: pointer;
}
.pagesize select:focus-visible { outline: 1px solid var(--ink); border-color: var(--ink); }

/* Multi-select dropdown (UIFX-09). The toggle also carries .chip, so the closed control reads as
   one more pill in the filter row and .chip.active already supplies its selected treatment. The
   panel is capped and scrolls: the reason-code vocabulary is 13 entries wide and must not grow
   the page. Its stacking order sits above the table and below the drawer (z-index 10). */
.msel { position: relative; display: inline-flex; }
.msel-toggle::after { content: "▾"; font-size: 9px; opacity: 0.6; }
.msel-panel {
  position: absolute; top: calc(100% + 4px); left: 0;
  min-width: 200px; max-width: 320px;
  max-height: 260px; overflow: auto;
  padding: 4px 0;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--shadow);
  z-index: 5;
}
.msel-opt {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  font-family: var(--mono); font-size: 11px; color: var(--ink-2);
  cursor: pointer;
}
.msel-opt:hover { background: var(--bg-2); }
.msel-opt input { flex: none; margin: 0; cursor: pointer; }
.msel-foot {
  display: flex; justify-content: flex-end;
  margin-top: 4px; padding: 6px 10px;
  border-top: 1px dashed var(--line-2);
}

/* Tables */
.table-wrap { background: var(--paper); border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.tbl { width: 100%; border-collapse: collapse; font-size: 12px; }
.tbl thead th { background: #f3f3f3; text-align: left; padding: 8px 12px; font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); border-bottom: 1px solid var(--line); }
.tbl tbody td { padding: 9px 12px; border-bottom: 1px solid var(--line-2); vertical-align: middle; }
.tbl tbody tr:last-child td { border-bottom: none; }
.tbl tbody tr { cursor: pointer; }
.tbl tbody tr:hover { background: #f7f7f7; }
.tbl tbody tr.selected { background: #ececec; }
.tbl .mono { font-family: var(--mono); font-size: 11px; color: var(--ink-2); }
.tbl .row-actions { display: flex; gap: 4px; justify-content: flex-end; opacity: 0; transition: opacity 100ms; }
.tbl tbody tr:hover .row-actions { opacity: 1; }
/* A locked-out (incompatible) skip row must explain itself at rest, not on hover (SC3/FIX-03) —
   scoped to tr.muted so every other table keeps hover-reveal. The second rule is why there are
   two: there is no global .btn:disabled rule in this file, so a permanently-visible disabled
   btn-primary would otherwise read as a live action. Deliberately NOT global. */
.tbl tbody tr.muted .row-actions { opacity: 1; }
.tbl .row-actions .btn:disabled { opacity: 0.45; cursor: not-allowed; }
.tbl .num { font-family: var(--mono); text-align: right; }

/* Status badges (greyscale, hairline accents) */
.badge-status {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px;
  font-family: var(--mono); font-size: 10px;
  border-radius: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-2);
}
.badge-status::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--muted-2);
}
.badge-status.running::before { background: var(--ink); animation: pulse 1.4s infinite; }
.badge-status.running { color: var(--ink); border-color: var(--ink); }
.badge-status.done::before { background: var(--muted); }
.badge-status.failed::before { background: var(--ink); }
.badge-status.failed { color: var(--ink); border-style: dashed; }
.badge-status.cancelled::before { background: var(--muted-2); }
.badge-status.queued::before { background: transparent; border: 1px solid var(--muted); width: 6px; height: 6px; }

@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }

/* Slide-in panel */
.panel-backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,0.04);
  pointer-events: none;
  opacity: 0; transition: opacity 160ms;
}
.panel-backdrop.open { opacity: 1; }
.panel {
  position: absolute; top: 0; right: 0; bottom: 0;
  width: 520px;
  background: var(--paper);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow);
  transform: translateX(100%);
  transition: transform 180ms ease-out;
  display: flex; flex-direction: column;
}
.panel.open { transform: translateX(0); }
.panel-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
}
.panel-head h2 { margin: 0; font-family: var(--display); font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.panel-head .meta { font-family: var(--mono); font-size: 11px; color: var(--muted); margin-top: 4px; }
.panel-body { flex: 1; overflow: auto; padding: 16px 18px; }
.panel-foot { padding: 12px 18px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end; }

/* Sections inside panels / pages */
.section { margin-bottom: 20px; }
.section-title {
  font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted); margin-bottom: 8px;
  display: flex; align-items: center; gap: 8px;
}
.section-title::after { content: ""; flex: 1; border-bottom: 1px dashed var(--line); }

/* Tree */
.tree { font-family: var(--mono); font-size: 11px; }
.tree .row { padding: 2px 0 2px 0; display: flex; gap: 4px; align-items: center; }
.tree .row.dir { color: var(--ink); font-weight: 600; }
.tree .row.file { color: var(--ink-2); }
.tree .indent { display: inline-block; width: 14px; }
/* Collapsible tree controls (UIFX-06). The twisty is sized to the .indent width above so a
   directory row stays aligned with the rows beneath it. */
.tree .row .twisty {
  width: 14px; flex: none;
  padding: 0; border: none; background: none;
  color: var(--muted);
  font-family: var(--mono); font-size: 10px; line-height: 1; text-align: center;
}
.tree .row .twisty:hover { color: var(--ink); }
.tree .row .twisty.expanded { transform: rotate(90deg); }
.tree .row .size { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
.tree-toggle {
  margin-bottom: 6px; padding: 2px 8px;
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--paper); color: var(--muted);
  font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
}
.tree-toggle:hover { background: var(--bg-2); color: var(--ink); }

/* Definition / kv list */
.kv { display: grid; grid-template-columns: 130px 1fr; gap: 6px 12px; font-size: 12px; }
.kv dt { color: var(--muted); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; }
.kv dd { margin: 0; }

/* Schema list */
.schema-list { font-family: var(--mono); font-size: 11px; }
.schema-list .row { display: flex; justify-content: space-between; padding: 4px 0; border-bottom: 1px dashed var(--line-2); }
.schema-list .row .nm { color: var(--ink); }
.schema-list .row .ty { color: var(--muted); }

/* Code/sample */
.code { font-family: var(--mono); font-size: 11px; background: #fafafa; border: 1px solid var(--line-2); padding: 10px 12px; border-radius: 4px; white-space: pre-wrap; color: var(--ink-2); }

/* Pipeline steps */
.steps { display: flex; flex-direction: column; gap: 4px; }
.steps .step {
  display: grid; grid-template-columns: 24px 1fr auto; gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line-2);
  border-radius: 4px;
  font-size: 12px;
  background: var(--paper);
  align-items: center;
}
.steps .step .n { font-family: var(--mono); color: var(--muted); font-size: 11px; }
.steps .step .nm { font-weight: 600; }
.steps .step .sub { font-size: 11px; color: var(--muted); margin-top: 1px; }
.steps .step .ver { font-family: var(--mono); font-size: 10px; color: var(--muted); }

/* STEP-01: only the steps list that carries switches gets the fourth column, so the run
   detail's read-only list keeps its three-column geometry untouched. */
.steps.configurable .step { grid-template-columns: 24px 1fr auto auto; }
.steps .step .toggle { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; text-transform: uppercase; letter-spacing: 0.04em; }
.steps .step .toggle input { cursor: pointer; }
/* UIFX-07: the step control reads as a switch. No markup change was needed — the label wrapper
   around the native checkbox already existed (ui/screens-jobtypes.jsx), so this is pure CSS on
   the existing input. The track uses the palette's line/ink properties; no new colour literal. */
.steps .step .toggle input {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  position: relative;
  flex: none;
  width: 26px;
  height: 14px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--line-2);
  transition: background 120ms ease-out, border-color 120ms ease-out;
}
.steps .step .toggle input:checked { background: var(--ink); border-color: var(--ink); }
.steps .step .toggle input::after {
  content: "";
  position: absolute; top: 1px; left: 1px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 1px 2px rgba(0,0,0,0.25);
  transition: transform 120ms ease-out;
}
.steps .step .toggle input:checked::after { transform: translateX(12px); }
/* Keyboard reachability survives the appearance reset. */
.steps .step .toggle input:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .steps .step .toggle input,
  .steps .step .toggle input::after { transition: none; }
}
/* A switched-off step, on BOTH screens — one greyed treatment so they read as one system. */
.steps .step.disabled { background: #fafafa; border-style: dashed; }
.steps .step.disabled .nm { color: var(--muted); font-weight: 500; }
.steps-actions { display: flex; justify-content: flex-end; margin-top: 8px; }
.steps-actions .btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* JobType cards */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px,1fr)); gap: 12px; }
.card {
  background: var(--paper); border: 1px solid var(--line); border-radius: 4px;
  padding: 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.card:hover { background: #fafafa; cursor: pointer; }
.card h3 { margin: 0; font-size: 14px; font-family: var(--mono); }
.card .desc { font-size: 12px; color: var(--ink-2); }
.card .meta { font-family: var(--mono); font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; display: flex; gap: 10px; }

/* Stage funnel */
.funnel-wrap {
  background: var(--paper); border: 1px solid var(--line); border-radius: 4px;
  padding: 16px; margin-bottom: 16px;
}
.funnel {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  gap: 6px;
  position: relative;
}
.stage {
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 10px 8px;
  display: flex; flex-direction: column; gap: 6px;
  background: var(--paper);
  position: relative;
  cursor: pointer;
}
.stage:hover { background: #fafafa; }
.stage.active { background: #f0f0f0; border-color: var(--ink); }
.stage.has-current { border-color: var(--ink); }
.stage .nm { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.stage .cur {
  font-family: var(--display); font-size: 24px; font-weight: 600; line-height: 1;
  color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.stage.has-current .cur { color: var(--ink); }
.stage:not(.has-current) .cur { color: var(--muted-2); }
.stage .breakdown { font-family: var(--mono); font-size: 10px; color: var(--muted); display: flex; flex-direction: column; gap: 1px; }
.stage .breakdown .pass::before { content: "↗ "; color: var(--muted-2); }
.stage .breakdown .skip::before { content: "✕ "; color: var(--muted-2); }
.stage .spark { height: 18px; }
/* D-05: a stage whose step is switched off — greyed, dashed border, and the reason in place of
   the sparkline. The dash itself comes from the markup, never from a fabricated count. */
.stage.disabled { background: #fafafa; border-style: dashed; }
.stage.disabled .cur, .stage.disabled .breakdown, .stage.disabled .nm { color: var(--muted-2); }
.stage .off-note { height: 18px; color: var(--muted-2); text-transform: uppercase; letter-spacing: 0.04em; }

.funnel-arrow {
  position: absolute; top: 50%; right: -10px; transform: translateY(-50%);
  font-family: var(--mono); color: var(--muted); font-size: 10px;
}

/* Counters bar */
.counters {
  display: grid; grid-template-columns: repeat(6,1fr); gap: 8px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 4px;
  padding: 12px 14px; margin-bottom: 16px;
}
.counter { display: flex; flex-direction: column; gap: 2px; border-right: 1px dashed var(--line-2); padding-right: 8px; }
.counter:last-child { border-right: none; }
.counter .k { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.counter .v { font-family: var(--display); font-size: 20px; font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.counter .sub { font-family: var(--mono); font-size: 10px; color: var(--muted); }

.progress { height: 6px; background: var(--line-2); border-radius: 3px; overflow: hidden; margin-top: 6px; }
.progress > div { background: var(--ink); height: 100%; }

/* Tabs */
.tabs { display: flex; gap: 0; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.tab {
  padding: 8px 14px; border: none; background: transparent;
  border-bottom: 2px solid transparent;
  font-size: 12px; color: var(--muted);
  font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.04em;
}
.tab:hover { color: var(--ink); }
.tab.active { color: var(--ink); border-bottom-color: var(--ink); }

/* Run detail — master/detail split (UX_SPEC §5.4) */
.md-split { display: grid; grid-template-columns: 320px 1fr; gap: 0; min-height: 0; }
.md-list { border-right: 1px solid var(--line); background: var(--paper); overflow: auto; }
.md-list .run-row {
  padding: 12px 14px; border-bottom: 1px solid var(--line-2); cursor: pointer;
  display: flex; flex-direction: column; gap: 4px;
}
.md-list .run-row:hover { background: #f7f7f7; }
.md-list .run-row.selected { background: #ececec; border-left: 3px solid var(--ink); padding-left: 11px; }
.md-list .run-row .nm { font-size: 13px; font-weight: 600; }
.md-list .run-row .meta { font-family: var(--mono); font-size: 10px; color: var(--muted); }
.md-detail { overflow: auto; padding: 20px 24px; }

/* Review worker — document pane.
   D-15.1-07a deleted the dead review-split rules that used to sit here: the outer split grid,
   every list-pane rule under it, the inner work grid and the document-frame rules.
   CORRECTION for a later reader: the decision named a WIDER line range than was actually dead.
   `.preview-pane` and all three `.preview-toolbar` rules below are still mounted by
   ui/screens-review.jsx and were deliberately kept; the `.action-pane` rules further down are
   live too and were never in scope. Do not repeat the mistake by sweeping this whole region.
   The one value worth keeping from the deleted split grid was `height: calc(100vh - 48px)` —
   recorded in plans 15.1-06 and 15.1-11, which prefer the flex full-height pattern the run
   detail and review worker screens already use. */
.preview-pane { background: #2a2a2a; color: #ddd; padding: 24px; overflow: auto; }
.preview-toolbar { display: flex; gap: 6px; padding: 8px 12px; background: #1a1a1a; border-bottom: 1px solid #444; font-family: var(--mono); font-size: 11px; color: #ccc; align-items: center; }
.preview-toolbar .btn { background: #333; color: #ddd; border-color: #555; padding: 3px 8px; font-size: 10px; }
.preview-toolbar .btn:hover { background: #444; }

.action-pane { background: var(--paper); border-left: 1px solid var(--line); overflow: hidden; }
.action-pane .form { padding: 14px; display: flex; flex-direction: column; gap: 12px; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.field input, .field textarea, .field select {
  border: 1px solid var(--line); border-radius: 3px; padding: 6px 8px;
  font: inherit; font-size: 12px; background: var(--paper); color: var(--ink);
}
.field input:focus, .field textarea:focus { outline: 1px solid var(--ink); border-color: var(--ink); }
.field .hint { font-family: var(--mono); font-size: 10px; color: var(--muted); }
.field .flag { font-family: var(--mono); font-size: 10px; color: var(--ink); }

/* Notifications drawer */
.notif-drawer {
  position: absolute; top: 48px; right: 20px;
  width: 360px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--shadow);
  z-index: 10;
  /* UIFX-01: viewport minus the 48px topbar minus a 20px breathing gap, with its own scroll, so a
     long notification list scrolls inside the drawer instead of growing the document. */
  max-height: calc(100vh - 48px - 20px);
  overflow: auto;
  transform: translateY(-8px); opacity: 0; pointer-events: none;
  transition: all 140ms;
}
.notif-drawer.open { transform: translateY(0); opacity: 1; pointer-events: auto; }
.notif-drawer .head { padding: 10px 14px; border-bottom: 1px solid var(--line-2); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); display: flex; justify-content: space-between; align-items: center; }
.notif-drawer .item { padding: 10px 14px; border-bottom: 1px solid var(--line-2); cursor: pointer; display: flex; flex-direction: column; gap: 2px; }
.notif-drawer .item:hover { background: #f7f7f7; }
.notif-drawer .item.unread { background: #fafafa; }
.notif-drawer .item .ttl { font-size: 12px; }
.notif-drawer .item .meta { font-family: var(--mono); font-size: 10px; color: var(--muted); }

/* Toasts */
.toasts { position: fixed; bottom: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 20; }
.toast {
  background: var(--ink); color: var(--paper);
  padding: 10px 14px; border-radius: 4px;
  font-size: 12px; max-width: 320px;
  box-shadow: var(--shadow);
}

/* Login overlay (D-01) — full-viewport gate above everything, same .open toggle idiom as .notif-drawer */
.login-overlay {
  position: fixed; inset: 0; z-index: 40;
  display: flex; align-items: center; justify-content: center;
  background: rgba(26,26,26,0.32);
  opacity: 0; pointer-events: none;
  transition: opacity 140ms;
}
.login-overlay.open { opacity: 1; pointer-events: auto; }
/* Startup / post-logout variant: same card, but an opaque full page (no console behind it) */
.login-overlay.as-screen { background: var(--paper); z-index: 50; }
.login-overlay .card {
  width: 320px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 4px;
  box-shadow: var(--shadow);
}
.login-overlay .head { padding: 12px 16px; border-bottom: 1px solid var(--line-2); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.login-overlay .body { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.login-overlay .row { display: flex; flex-direction: column; gap: 4px; }
.login-overlay .row span { font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.login-overlay .row input {
  border: 1px solid var(--line); border-radius: 3px; padding: 7px 8px;
  font: inherit; font-size: 12px; background: var(--paper); color: var(--ink);
}
.login-overlay .row input:focus { outline: 1px solid var(--ink); border-color: var(--ink); }
.login-overlay .err { font-family: var(--mono); font-size: 11px; color: var(--ink); }
.login-overlay .submit {
  padding: 8px 10px; border: 1px solid var(--ink); border-radius: 3px;
  background: var(--ink); color: var(--paper); font-size: 12px; cursor: pointer;
}
.login-overlay .submit:hover { background: var(--ink-2); }
.login-overlay .submit:disabled { opacity: 0.5; cursor: default; }
.topbar .user .logout { padding: 3px 8px; cursor: pointer; }

/* Drag-drop zone */
.dropzone {
  border: 2px dashed var(--line);
  border-radius: 6px;
  background: #fafafa;
  padding: 36px 20px;
  text-align: center;
  font-family: var(--mono); font-size: 12px; color: var(--muted);
}
.dropzone.dragover { background: #f0f0f0; border-color: var(--ink); color: var(--ink); }
.dropzone .big { font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--ink); margin-bottom: 6px; }

/* Annotations */
.annot {
  font-family: var(--sans); font-size: 12px;
  color: var(--ink-2);
  background: #fafafa;
  border-left: 2px solid var(--muted-2);
  border-radius: 0;
  padding: 6px 10px;
  margin: 8px 0;
}
.annot::before { content: "note · "; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-right: 4px; }

/* Stage drill-down (below funnel) */
.drilldown {
  margin-top: 12px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 4px;
  padding: 12px;
}
.drilldown .head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 8px;
}
.drilldown .head .ttl { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-2); }

/* Throughput / sparkline */
.spark-svg { width: 100%; height: 100%; }

/* Search */
.search {
  display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--line); background: var(--paper);
  border-radius: 4px; padding: 4px 8px;
}
.search input { border: none; outline: none; font: inherit; font-size: 12px; width: 100%; background: transparent; }

/* Timeline */
.timeline { display: flex; flex-direction: column; gap: 0; font-family: var(--mono); font-size: 11px; }
.timeline .ev { display: grid; grid-template-columns: 90px 12px 1fr; gap: 8px; padding: 6px 0; border-bottom: 1px dashed var(--line-2); align-items: center; }
.timeline .ev .t { color: var(--muted); }
.timeline .ev .marker { width: 6px; height: 6px; background: var(--ink); border-radius: 50%; justify-self: center; }
.timeline .ev.minor .marker { background: var(--line); border: 1px solid var(--muted-2); }
/* A file event names its file (UIFX-14 / D-15.2-07). The name gets its own bounded track, and the
   widened grid is applied ONLY to a row that has a name, so a run-level row keeps the original
   three columns and gains no empty slot. minmax(0, …) is load-bearing: without it the track's
   min-content floor is the whole untruncated path, which would squeeze the summary to nothing. */
.timeline .ev.named { grid-template-columns: 90px 12px minmax(0, 0.55fr) 1fr; }
/* Truncate from the START — the end of a path is the part that identifies the file. Turning the
   box rtl moves the overflow, and therefore the ellipsis, to the left edge. The inner bdi is an
   isolated ltr run so the path's own characters keep their written order; a bare rtl box would
   reorder trailing neutrals (the extension dot lands on the wrong side of the name). */
.timeline .ev .ev-file {
  direction: rtl; text-align: left;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--muted);
}
.timeline .ev .ev-file bdi { direction: ltr; unicode-bidi: isolate; }
.timeline .ev.clickable { cursor: pointer; }
.timeline .ev.clickable:hover { background: #f7f7f7; }

/* Utility */
.hstack { display: flex; gap: 8px; align-items: center; }
.vstack { display: flex; flex-direction: column; gap: 8px; }
.spacer-h { flex: 1; }
.muted { color: var(--muted); }
.mono { font-family: var(--mono); }
.display { font-family: var(--display); }
.tiny { font-size: 10px; }
.small { font-size: 11px; }

/* Variant note pin */
.pin {
  display: inline-block;
  font-family: var(--mono); font-size: 9px; text-transform: uppercase; letter-spacing: 0.06em;
  background: var(--ink); color: var(--paper);
  padding: 1px 6px; border-radius: 8px;
}
