@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

/* Quality ConTroll's control panel.
   Chrome is the Focus Toolbox App Layout Standard (control-center wiki); the
   token values below are lifted from Smarty rather than re-derived, because
   two sibling apps on one box that are almost the same shade of blue is worse
   than either shade on its own. */

:root {
  /* FoE brand (smarty/focus_branding.md) */
  --foe-blue: #034ea2;
  --foe-green: #00ab4e;
  --foe-body: #3c3c3c;
  --font-family: 'Inter', sans-serif;

  --surface: #faf8ff;
  --surface-low: #f2f3ff;
  --on-surface-variant: #45464d;
  --outline-variant: #c4c6d0;
  --card-radius: 0.5rem;
  --inner-radius: 0.375rem;
  --card-shadow: 0 2px 12px rgba(19, 27, 46, 0.08);
}

* { box-sizing: border-box; }
html, body { max-width: 100%; overflow-x: hidden; }
body { margin: 0; font-family: var(--font-family); color: var(--foe-body); background: var(--surface); }

/* ── Header: white logo bar / blue app bar / pill tab strip ────────────── */
.app-header { position: sticky; top: 0; z-index: 40; }

.logo-bar {
  height: 80px; background: #fff; border-bottom: 1px solid var(--outline-variant);
  display: flex; align-items: center; padding: 0 1.25rem;
}
.logo-bar .logo { height: 64px; width: auto; }

.app-bar {
  height: 34px; background: var(--foe-blue);
  display: flex; align-items: center; padding: 0 1.25rem;
}
.app-bar-title {
  color: #fff; font-size: .72rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
}
.app-bar-viewer { margin-left: auto; color: rgba(255,255,255,.7); font-size: .72rem; white-space: nowrap; }

.tab-strip {
  height: 40px; background: #fff; border-bottom: 1px solid var(--outline-variant);
  display: flex; align-items: center; padding: 0 1.25rem; gap: .25rem;
}
.tab-strip a {
  padding: .3rem .7rem; border-radius: var(--inner-radius);
  color: var(--on-surface-variant); text-decoration: none;
  font-size: .8125rem; font-weight: 500; white-space: nowrap;
}
.tab-strip a.active { background: #d7f3e3; color: #0f6b3a; font-weight: 600; }
.tab-strip a:not(.active):hover { background: var(--surface-low); color: var(--foe-body); }

main { padding: .9rem 1.25rem 3.5rem; min-width: 0; }
.hidden { display: none !important; }

.card {
  background: #fff; border: 1px solid var(--outline-variant);
  border-radius: var(--card-radius); box-shadow: var(--card-shadow);
  padding: 1rem 1.25rem; margin-bottom: 1rem;
}

.search-row { display: flex; gap: .5rem; margin-bottom: .6rem; }
.search-wrap { position: relative; flex: 1; display: flex; min-width: 0; }
.search-wrap .search-ic {
  position: absolute; left: .7rem; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; color: #9aa0a6; pointer-events: none;
}
.search-wrap input[type=text] {
  flex: 1; padding: .42rem .75rem .42rem 2rem;
  border: 1px solid var(--outline-variant); border-radius: 999px;
  font-family: inherit; font-size: .8125rem; min-width: 0; background: #fff;
}
.search-row select {
  flex: none; width: 190px; padding: .35rem .6rem;
  border: 1px solid var(--outline-variant); border-radius: var(--inner-radius);
  font-family: inherit; font-size: .8125rem; color: var(--foe-body); background: #fff;
}

/* Table action buttons: right-aligned, inside the table card, above the
   header row — the standard's sixth element. */
.toolbar {
  display: flex; gap: .25rem; align-items: center; flex-wrap: wrap;
  padding: .45rem .6rem; border-bottom: 1px solid var(--outline-variant);
}
.toolbar .spacer { flex: 1; }
.toolbar .role-note { font-size: .75rem; color: var(--on-surface-variant); padding-left: .35rem; }
.runs-toolbar { background: #fff; border: 1px solid var(--outline-variant);
  border-radius: var(--card-radius); box-shadow: var(--card-shadow); margin-bottom: .8rem; }
.inline-toggle { font-size: .75rem; color: var(--on-surface-variant); display: inline-flex;
  align-items: center; gap: .35rem; padding-left: .35rem; cursor: pointer; }

.ic { width: 14px; height: 14px; flex: none; }

.tool-btn {
  display: inline-flex; align-items: center; gap: .35rem;
  background: transparent; border: none; cursor: pointer;
  color: #4b5563; font-family: inherit; font-weight: 500; font-size: .78rem;
  padding: .35rem .6rem; border-radius: var(--inner-radius); white-space: nowrap;
}
.tool-btn:hover:not(:disabled) { background: var(--surface-low); color: var(--foe-blue); }
.tool-btn:disabled { opacity: .45; cursor: not-allowed; }
#toll-delete:hover:not(:disabled) { background: #fdeceb; color: #93000a; }

button.primary, button.secondary, button.danger {
  font-family: inherit; font-weight: 600; font-size: .85rem;
  border: none; border-radius: var(--inner-radius);
  padding: .5rem .9rem; cursor: pointer; white-space: nowrap;
}
button.primary { background: var(--foe-blue); color: #fff; }
button.primary:hover { background: #023d80; }
button.secondary { background: var(--surface-low); color: var(--foe-blue); }
button.danger { background: #ffdad6; color: #93000a; }
button:disabled { opacity: .5; cursor: not-allowed; }

/* ── Tables ────────────────────────────────────────────────────────────── */
.table-card { padding: 0; }
table { width: 100%; table-layout: fixed; border-collapse: collapse; font-size: .8125rem; }
th, td { text-align: left; padding: .38rem .7rem; border-bottom: 1px solid #e8eaf0;
         overflow: hidden; text-overflow: ellipsis; }
td.wrap { white-space: normal; word-break: break-word; }
th { color: var(--on-surface-variant); font-weight: 600; font-size: .7rem;
     letter-spacing: .02em; background: #fff; border-bottom: 1px solid var(--outline-variant);
     position: sticky; top: 0; user-select: none; white-space: nowrap; }
th[data-sort] { cursor: pointer; }
th[data-sort]:hover { color: var(--foe-blue); }
th[data-sort].sorted[data-sort-dir="asc"]::after { content: '\2191'; margin-left: .25em; }
th[data-sort].sorted[data-sort-dir="desc"]::after { content: '\2193'; margin-left: .25em; }

#tab-tolls th:nth-child(1) { width: 130px; }
#tab-tolls th:nth-child(3) { width: 115px; }
#tab-tolls th:nth-child(4) { width: 115px; }
#tab-tolls th:nth-child(5) { width: 190px; }

#tab-reassignments th:nth-child(2) { width: 160px; }
#tab-reassignments th:nth-child(3) { width: 32%; }
#tab-reassignments th:nth-child(4) { width: 160px; }

#tab-runs th:nth-child(2) { width: 110px; }
#tab-runs th:nth-child(3) { width: 130px; }
#tab-runs th:nth-child(4) { width: 80px; }
#tab-runs th:nth-child(5) { width: 80px; }
#tab-runs th:nth-child(6) { width: 30%; }

tbody tr:last-child td { border-bottom: none; }
tbody tr { cursor: pointer; }
tr:hover td { background: #f7f9fc; }
tr.selected td { background: #e6f6ec; }
td a { color: var(--foe-blue); }
#tab-runs tbody tr, #tab-reassignments tbody tr { cursor: default; }
#tab-runs tbody tr:hover td { background: inherit; }

.empty-row td { color: var(--on-surface-variant); font-style: italic; padding: 1.1rem .7rem; }

.tag { display: inline-block; padding: .08rem .5rem; border-radius: 999px;
       font-size: .7rem; font-weight: 600; white-space: nowrap; }
.tag-running { background: #d7f3e3; color: #0f6b3a; }
.tag-inactive { background: #f1f5f9; color: #475569; }
.tag-dev { background: #ffe4c9; color: #8a4b00; }
.tag-failed { background: #ffdad6; color: #93000a; }
.tag-missing { background: #fff3bf; color: #7a5b00; }

/* Every toll that flagged an approval gets its own chip. `why_flagged` is
   newline-joined names; the Retool table showed it as one truncated line, so
   the second reason was invisible. */
.chip {
  display: inline-block; padding: .08rem .45rem; margin: .1rem .15rem .1rem 0;
  border-radius: 999px; background: var(--surface-low); color: #334155;
  font-size: .7rem; font-weight: 500; white-space: normal;
}

.pagination { display: flex; align-items: center; gap: .6rem; padding: .5rem .7rem;
  font-size: .78rem; color: var(--on-surface-variant); border-top: 1px solid var(--outline-variant); }
.pagination button { padding: .25rem .6rem; font-size: .78rem; }
.pagination .spacer { flex: 1; }

.footnote { font-size: .75rem; color: var(--on-surface-variant); margin: .2rem .2rem 0; }

.state-card { text-align: center; padding: 3rem 1rem; max-width: 560px; margin: 3rem auto; }
.state-card button { margin-top: 1rem; }

/* ── Run Health ────────────────────────────────────────────────────────── */
.nav-badge {
  display: inline-block; min-width: 1.15rem; padding: .05rem .35rem; margin-left: .3rem;
  border-radius: 999px; background: #ba1a1a; color: #fff;
  font-size: .68rem; font-weight: 700; text-align: center; vertical-align: text-top;
}
.banner {
  border-radius: var(--card-radius); padding: .7rem .9rem; margin-bottom: .8rem;
  font-size: .85rem; border: 1px solid transparent;
}
.banner strong { display: block; margin-bottom: .15rem; }
.banner-ok { background: #e7f6ec; border-color: #b7e2c6; color: #0f6b3a; }
.banner-warn { background: #fff8e1; border-color: #f4dfa0; color: #7a5b00; }
.banner-bad { background: #ffdad6; border-color: #f3b9b2; color: #93000a; }
.banner + .banner { margin-top: -.4rem; }

.run-error {
  font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: .72rem;
  color: var(--on-surface-variant); word-break: break-word; white-space: pre-wrap;
}

/* ── Metrics (qc_troll#10) ─────────────────────────────────────────────────
   Same tokens, same card treatment and the same tile/rank/trend vocabulary as
   Smarty's Metrics screen. Two sibling apps answering the same question with
   two different visual languages is how a reader learns to distrust both. */

.metrics-toolbar { display: flex; align-items: center; gap: .6rem; margin-bottom: .8rem; flex-wrap: wrap; }
.metrics-toolbar .spacer { flex: 1; }
.metrics-toolbar .range-label { font-size: .8rem; color: var(--on-surface-variant); }
.metrics-toolbar select {
  padding: .3rem .5rem; border: 1px solid var(--outline-variant);
  border-radius: var(--inner-radius); background: #fff;
  font-family: var(--font-family); font-size: .8rem; color: var(--foe-body);
}
.metrics-toolbar .role-note { font-size: .75rem; color: var(--on-surface-variant); }

.tile-row { display: flex; gap: .75rem; flex-wrap: wrap; margin-bottom: 1rem; }
.tile {
  flex: 1 1 9rem; background: #fff; border: 1px solid var(--outline-variant);
  border-radius: var(--card-radius); box-shadow: var(--card-shadow);
  padding: .8rem .9rem; text-align: left; font-family: var(--font-family);
}
.tile-value { font-size: 1.5rem; font-weight: 700; color: var(--foe-body); line-height: 1.15; }
.tile-label { font-size: .72rem; color: var(--on-surface-variant); margin-top: .25rem; }
/* Which run the number describes, under the label it belongs to. */
.tile-sub {
  font-size: .62rem; color: var(--on-surface-variant); margin-top: .3rem;
  line-height: 1.3;
}
.tile-click { cursor: pointer; }
.tile-click:hover { border-color: var(--foe-blue); }
/* A check that has never caught anything is the one number here that means
   "go and look" — it is either dead weight or quietly broken. */
.tile-alert { border-color: #f3b9b2; background: #fff5f5; }
.tile-alert .tile-value { color: #93000a; }

/* Two panels to a row, not four (qc_troll#27). At four-up every card was about
   350px wide, and check names run past sixty characters — so every name in
   both check panels was cut off, and two different checks rendered as the
   identical string `Application Received Date Exceeds Requir...`. The panel
   was unreadable because of the grid, not because of the label.

   `align-items: start` because the panels hold wildly different amounts: a
   three-row assignee list stretched to the height of a fifteen-row check list
   left a void underneath it. */
.metrics-grid {
  display: grid; grid-template-columns: minmax(0, 1fr);
  align-items: start; gap: 1rem; margin-bottom: 1rem;
}
@media (min-width: 62rem) {
  .metrics-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.metrics-card { padding: 1rem; }
.metrics-card h3 { margin: 0 0 .75rem; font-size: .9rem; font-weight: 600; color: var(--foe-body); }
/* The caveat rides with the heading rather than sitting at the foot of the
   page, so a panel can't be read — or screenshotted — without it. */
.panel-sub {
  display: block; font-size: .7rem; font-weight: 400; line-height: 1.45;
  color: var(--on-surface-variant); margin-top: .2rem;
}

.rank-list { display: flex; flex-direction: column; gap: .25rem; }
.rank-row {
  display: grid; grid-template-columns: minmax(0, 1fr) 4.5rem auto;
  align-items: center; gap: .6rem; width: 100%;
  padding: .3rem .35rem; border: 0; background: none; text-align: left;
  font-family: var(--font-family); font-size: .8rem; color: var(--foe-body);
  border-radius: var(--inner-radius);
}
.rank-click { cursor: pointer; }
.rank-click:hover { background: var(--surface-low); }
/* Names wrap; they are never shortened. The `title` attribute used to be
   the only way to read the rest of one, and a tooltip is nothing on touch
   and nothing to a keyboard user (qc_troll#27). */
.rank-name { overflow-wrap: anywhere; }
.rank-bar { background: var(--surface-low); border-radius: 999px; height: .45rem; overflow: hidden; }
.rank-bar > span { display: block; height: 100%; background: var(--foe-blue); border-radius: 999px; }
.rank-count { font-variant-numeric: tabular-nums; color: var(--on-surface-variant); }
.id-flag {
  font-size: .6rem; text-transform: uppercase; letter-spacing: .03em;
  background: var(--surface-low); color: var(--on-surface-variant);
  border-radius: 3px; padding: 0 .25rem; margin-left: .25rem; white-space: nowrap;
}

.idle-list { display: flex; flex-direction: column; gap: .25rem; }
.idle-row {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .3rem .35rem; font-size: .8rem; border-radius: var(--inner-radius);
}
.idle-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.idle-when { font-size: .72rem; color: var(--on-surface-variant); white-space: nowrap; }
/* A check that has never even run is a different problem from one that runs
   every night and finds nothing. */
.idle-never { color: #93000a; font-weight: 600; }

.program-list { display: flex; flex-direction: column; gap: .1rem; }
.program-row {
  display: grid; grid-template-columns: minmax(6rem, 1fr) 3.5rem 3.5rem 4rem;
  gap: .5rem; align-items: baseline; padding: .28rem .35rem; font-size: .8rem;
}
.program-head {
  font-size: .68rem; font-weight: 600; letter-spacing: .02em;
  color: var(--on-surface-variant); border-bottom: 1px solid var(--outline-variant);
}
.program-head span:not(:first-child), .program-num { text-align: right; }
.program-name { min-width: 0; overflow-wrap: anywhere; }
.program-num { font-variant-numeric: tabular-nums; }

/* The reassignments chart (qc_troll#27). It was a row of bars floating in
   white space — no baseline, no scale, no gridlines — so the only way to
   compare two weeks was to read the number printed under each bar.

   The bars now stand on a real baseline against a labelled scale. Heights and
   gridlines are both percentages of the same plot height, so a bar meets its
   gridline exactly. */
.trend-chart {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: start; gap: .5rem;
}
/* The 2px of headroom is the top gridline's: it sits at `bottom: 100%`, which
   is one pixel above the plot, and `.trend-scroll` clips it away without it —
   `overflow-x: auto` forces the vertical axis to scroll too. The axis carries
   the same offset so its labels stay level with their lines. */
.trend-yaxis { position: relative; height: 11rem; min-width: 2rem; margin-top: 2px; }
.trend-ytick {
  position: absolute; right: 0; transform: translateY(50%);
  font-size: .62rem; line-height: 1; color: var(--on-surface-variant);
  font-variant-numeric: tabular-nums;
}
/* The bucket labels hang below the baseline, inside this box's padding rather
   than outside it: `overflow-x: auto` forces the vertical axis to scroll too,
   so anything sticking out of the top or bottom would be clipped. */
.trend-scroll { overflow-x: auto; padding-top: 2px; padding-bottom: 1.7rem; }
/* `space-evenly` because the bars are capped: five weekly buckets in a
   full-width card would otherwise huddle against the left-hand edge with the
   gridlines running off into empty space. Twelve monthly buckets fill the
   width on their own and the rule costs them nothing. */
.trend-cols {
  position: relative; display: flex; align-items: flex-end;
  justify-content: space-evenly; gap: .4rem;
  height: 11rem; min-width: 100%;
}
.trend-gridline {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 1px dashed var(--outline-variant); pointer-events: none;
}
.trend-baseline { border-top-style: solid; }
.trend-col {
  position: relative; z-index: 1; flex: 1 1 0;
  min-width: 1.75rem; max-width: 3.5rem; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  align-items: center;
}
.trend-bar { width: 100%; background: var(--foe-blue); border-radius: 3px 3px 0 0; }
.trend-value {
  font-size: .65rem; color: var(--foe-body); font-variant-numeric: tabular-nums;
  line-height: 1.1; margin-bottom: .15rem;
}
.trend-label {
  position: absolute; top: calc(100% + .35rem); left: -.25rem; right: -.25rem;
  text-align: center; font-size: .6rem; color: var(--on-surface-variant);
  white-space: nowrap;
}

.empty-note { font-size: .8rem; color: var(--on-surface-variant); margin: .5rem 0; font-style: italic; }

/* ── The Control Center dock ───────────────────────────────────────────── */
/*
 * Element 5 of the Focus Toolbox layout standard: fixed bottom-left, a solid
 * opaque white card. Values are the standard's, and match Smarty, which is the
 * reference app for this element.
 *
 * This rule was simply missing. `index.html` has carried
 * `<div class="cc-dock">` since #5, but nothing ever styled it, so the dock was
 * an ordinary block element at the end of <body> and sat wherever the document
 * ended — under the page rather than pinned to the corner. On a long tab like
 * Reassignments you had to scroll past every row to reach the account menu.
 *
 * `main` already reserves 3.5rem of bottom padding, so pinning this does not
 * cover the last row of a table.
 */
.cc-dock {
  position: fixed; left: 16px; bottom: 16px;
  /* Above the sticky header (40), deliberately below the modal backdrop (50):
     the account menu should float over the page, but never over an open
     dialog. Smarty uses 60 and does sit over its own modals; that is the one
     place this diverges, and the standard does not specify a layer. */
  z-index: 45;
  background: #fff; border: 1px solid #e5e7eb;
  border-radius: var(--inner-radius);
  box-shadow: 0 4px 16px rgba(0,0,0,.10);
  padding: 6px 8px;
}

/* ── Modal ─────────────────────────────────────────────────────────────── */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(19,27,46,0.4);
  display: flex; align-items: center; justify-content: center; z-index: 50;
}
.modal {
  position: relative; background: #fff; border-radius: var(--card-radius);
  box-shadow: 0 8px 32px rgba(19,27,46,0.14);
  width: 560px; max-width: 92vw; max-height: 85vh; overflow: auto; padding: 1.5rem;
}
.modal.modal-wide { width: 820px; }
.modal h3 { margin-top: 0; padding-right: 2.25rem; }
.modal label { display: block; font-weight: 600; font-size: .85rem; margin: .75rem 0 .25rem; }
.modal input[type=text], .modal select, .modal textarea {
  width: 100%; padding: .5rem .6rem; border: 1px solid var(--outline-variant);
  border-radius: var(--inner-radius); font-family: inherit; font-size: .9rem;
}
.modal .actions { display: flex; justify-content: flex-end; gap: .5rem; margin-top: 1.25rem; }
.modal .hint { font-size: .75rem; color: var(--on-surface-variant); margin: .25rem 0 0; }

.modal-tabs { display: flex; gap: .35rem; border-bottom: 1px solid var(--outline-variant); margin: .75rem 0 0; }
.modal-tab {
  background: transparent; border: none; cursor: pointer; font-family: inherit;
  color: var(--on-surface-variant); font-weight: 600; font-size: .85rem;
  padding: .5rem .9rem; border-radius: 999px 999px 0 0; margin-bottom: -1px;
}
.modal-tab.active { background: #d7f3e3; color: #0f6b3a; }
.modal-tab-body { padding-top: .25rem; }

/* The SQL check's answer lands next to the query, not in an alert() that
   vanishes on OK. */
.sql-check { margin-top: .6rem; font-size: .8rem; white-space: pre-wrap; }
.sql-check.good { color: #0f6b3a; }
.sql-check.warn { color: #7a5b00; }
.sql-check.bad { color: #93000a; }
.sql-check:empty { display: none; }

.quill-host, .quill-host .ql-editor, .quill-host .ql-toolbar { font-family: var(--font-family) !important; }
.quill-host { background: #fff; }
.quill-host .ql-toolbar { border-radius: var(--inner-radius) var(--inner-radius) 0 0; border-color: var(--outline-variant); }
.quill-host .ql-container {
  border-radius: 0 0 var(--inner-radius) var(--inner-radius); border-color: var(--outline-variant);
  min-height: 280px; max-height: 55vh; overflow-y: auto; font-size: .92rem;
}
.quill-host .ql-editor.quill-readonly { padding: 1rem; }
.quill-host .ql-editor pre.ql-syntax {
  background: #1e1e1e; color: #d4d4d4; border-radius: var(--inner-radius);
  font-family: 'JetBrains Mono', ui-monospace, monospace !important; font-size: .82rem; padding: .85rem;
}

/* ── Narrow viewports ──────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .logo-bar { height: 64px; }
  .logo-bar .logo { height: 48px; }
  main { padding: .75rem .75rem 4rem; }
  .tab-strip { overflow-x: auto; }
  .search-row { flex-wrap: wrap; }
  .search-row select { width: 100%; }
}

/* ---- Starting a run (qc_troll#23) --------------------------------------- */

/* Element 7 of the Focus Toolbox layout standard: a control that fires a
   request shows motion the instant it is clicked and goes un-clickable until
   the answer arrives. Drawn in `currentColor` and defined here rather than
   pulled from a CDN or an icon font — the moment the network is slow enough
   for a busy state to matter is the moment a remote asset has not arrived. */
.spin {
  display: inline-block;
  width: .85em; height: .85em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin .6s linear infinite;
  vertical-align: -.1em;
  flex: none;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* The wider in-progress verb must not wrap the button. */
.tool-btn, button.primary, button.secondary, button.danger { white-space: nowrap; }

.runs-picker {
  display: flex; align-items: center; gap: .5rem;
  margin: 0 0 .6rem; padding: .45rem .7rem;
  background: #fff; border: 1px solid var(--outline-variant); border-radius: 10px;
  font-size: .8rem;
}
.runs-picker label { color: var(--on-surface-variant); }
.runs-picker select { padding: .2rem .4rem; font-size: .8rem; max-width: 24rem; }

.run-live {
  margin: 0 0 .6rem;
  border: 1px solid var(--outline-variant); border-radius: 10px;
  background: #fff; overflow: hidden;
}
.run-live-head {
  display: flex; align-items: center; gap: .5rem;
  padding: .45rem .7rem; border-bottom: 1px solid var(--outline-variant);
  font-size: .8rem; font-weight: 600;
}
.run-live-head .spacer { flex: 1; }
.run-output {
  margin: 0; padding: .6rem .7rem;
  max-height: 20rem; overflow: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .74rem; line-height: 1.45;
  white-space: pre-wrap; word-break: break-word;
  background: #0f172a; color: #e2e8f0;
}
.run-output:empty::before { content: "Waiting for output…"; color: #94a3b8; }

/* The gate panel inside the Run now dialog. Four rows, one per required Night
   Shift task, because "which one is stale and by how much" is the whole
   question — a single red sentence cannot answer it. */
.gate-list { list-style: none; margin: .4rem 0 0; padding: 0; font-size: .78rem; }
.gate-list li {
  display: flex; gap: .5rem; align-items: baseline;
  padding: .22rem 0; border-top: 1px solid var(--outline-variant);
}
.gate-list li:first-child { border-top: 0; }
.gate-list .gate-task { flex: 1; min-width: 0; word-break: break-word; }
.gate-list .gate-age { color: var(--on-surface-variant); white-space: nowrap; }

/* `.modal label` sets display/weight/margins for the editor's fields, so these
   are scoped the same way to win — a choice card is a label, not a field. */
.modal label.run-choice {
  display: block; padding: .5rem .6rem; border: 1px solid var(--outline-variant);
  border-radius: 8px; margin: .5rem 0 0; cursor: pointer; font-weight: 400;
}
.modal label.run-choice:hover { background: var(--surface-low); }
.modal label.run-choice input { margin-right: .45rem; }
.modal label.run-choice strong { font-size: .85rem; font-weight: 600; }
.modal label.run-choice .run-choice-note {
  display: block; margin: .15rem 0 0 1.35rem;
  font-size: .76rem; font-weight: 400; color: var(--on-surface-variant);
}
.modal label.run-choice.run-choice-selected { border-color: var(--foe-blue); background: #f3f8ff; }
.modal label.inline-toggle { display: inline-flex; font-weight: 400; margin: .6rem 0 0; }
.modal label.footnote { display: block; font-weight: 400; margin: .75rem 0 .2rem; }

.confirm-type { width: 100%; margin-top: .4rem; }
.modal-error { margin-top: .6rem; }

/* ---- Which copy of the app is this? (qc_troll#24) ----------------------- */

/* Sits in the blue app-name bar. Amber against that blue is the loudest thing
   on the page without being an error state, which is right: a practice copy is
   not broken, it is just not the one you can be careless in. */
.env-chip {
  margin-left: .6rem;
  padding: .12rem .5rem;
  border-radius: 999px;
  background: #ffd54f;
  color: #4a3200;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .02em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The Real run choice on a copy that may not do one. Deliberately styled as a
   disabled card rather than removed: "you cannot do this here, and here is
   why" beats a dialog that silently has one option. */
.modal .run-choice-off {
  display: block; padding: .5rem .6rem;
  border: 1px dashed var(--outline-variant);
  border-radius: 8px; margin: .5rem 0 0;
  background: var(--surface-low); color: var(--on-surface-variant);
}
.modal .run-choice-off strong { font-size: .85rem; font-weight: 600; }
.modal .run-choice-off .run-choice-note {
  display: block; margin: .15rem 0 0; font-size: .76rem;
}
