/* Resilient Actions Policy — operator dashboard.
   Dark is the canonical theme and the one the brand sheet specifies. The light
   block redefines token VALUES only; no rule below it knows which theme is on.
   Surfaces ascend in lightness away from the canvas in both themes, so depth
   reads the same either way. */
:root {
  color-scheme: dark light;

  --canvas: #06080d;
  --surface: #0d1219;
  --surface-raised: #141b26;
  --border: #1e2836;
  --text: #f2f5f9;
  --text-muted: #8b9bb0;
  --accent: #1c6ef2;
  /* accent-text is a LIGHTER blue than --accent on purpose: #1c6ef2 on the
     canvas measures ~4.3:1, which is fine for borders and fills and short of
     WCAG AA for body text. */
  --accent-text: #4d8ffd;
  --warn: #f0913f;
  --danger: #ff6b6b;
  --warn-bg: #f0913f1f;
  --danger-bg: #ff6b6b1f;

  --radius-card: 10px;
  --radius-control: 6px;
  --font-sans: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;
}

@media (prefers-color-scheme: light) {
  :root {
    --canvas: #eef1f6;
    --surface: #f8fafc;
    --surface-raised: #ffffff;
    --border: #dde3ec;
    --text: #0d1219;
    --text-muted: #5a6b80;
    --accent: #1557c9;
    --accent-text: #1349ab;
    --warn: #b3541e;
    --danger: #c0341f;
    --warn-bg: #b3541e14;
    --danger-bg: #c0341f14;
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--font-sans);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent-text); }

/* One focus treatment everywhere. Keyboard traversal of the filter bars is a
   stated acceptance criterion, and a themed ring is how it stays visible. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-control);
}

/* ---- header ------------------------------------------------------------ */

header {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0.85rem 1.75rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.brand > span { display: inline-flex; align-items: center; gap: 0.55rem; }
/* The logo is capped at one line of brand text so it never grows the bar. */
.brand img { height: 1.5em; width: auto; flex: none; }
.brand .mark { color: var(--text); flex: none; }
.brand .mark-chevron { stroke: var(--accent); }
.brand .product { color: var(--accent-text); }

.topnav { display: flex; gap: 1.25rem; flex: 1; flex-wrap: wrap; }
.topnav a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.9rem;
  padding: 0.35rem 0;
  border-bottom: 2px solid transparent;
}
.topnav a:hover { color: var(--text); }
.topnav a[aria-current="page"] {
  color: var(--text);
  border-bottom-color: var(--accent);
}

/* Scoped to header, not bare ".identity": runner_org.html also has a
   <dl class="identity"> (the org state summary). A bare .identity here would
   match that <dl> too and turn it into a flex row; Task 3 gives it its own
   grid rule (dl.identity, or a renamed dl.identity-list). Keep this scoped to
   the header so a future component rule for that list never collides with
   it, and so the <dl> is not mis-styled in the meantime. */
header .identity { display: flex; align-items: center; gap: 0.75rem; font-size: 0.85rem; }

main { max-width: 76rem; margin: 0 auto; padding: 1.75rem; }

h2 { font-size: 1.35rem; letter-spacing: -0.02em; margin: 0 0 0.35rem; }
h3 { font-size: 1rem; letter-spacing: -0.01em; margin: 1.5rem 0 0.5rem; }
.muted { color: var(--text-muted); }

/* ---- buttons ----------------------------------------------------------- */

.btn {
  display: inline-block;
  padding: 0.4rem 0.9rem;
  font: inherit;
  font-size: 0.875rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: var(--surface-raised);
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
}
.btn:hover { border-color: var(--accent); }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 500;
}
/* Destructive affordance: the delete controls on the policy page. Same shape
   as .btn-primary, --danger tokens instead of --accent, so a destructive
   action never reads as the routine primary one. */
.btn-danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  font-weight: 500;
}

/* ---- cards and panels -------------------------------------------------- */

.card, .panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 1.1rem 1.25rem;
  margin: 0 0 1.1rem;
}
.panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.6rem;
}
.panel-head h3 { margin: 0; }
.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 1.1rem;
}

/* ---- tables ------------------------------------------------------------ */

.table-wrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; margin: 0.4rem 0 1.4rem; font-size: 0.9rem; }
th, td { text-align: left; padding: 0.55rem 0.8rem; border-bottom: 1px solid var(--border); }
thead th {
  /* No position: sticky here: every table is wrapped in .table-wrap
     {overflow-x: auto}, which per CSS overflow rules computes the wrapper's
     overflow-y to auto as well (not visible), making the wrapper — not the
     viewport — the sticky element's scrollport. The wrapper has no height
     constraint, so it never scrolls vertically and the header never sticks.
     Re-adding sticky here without also giving .table-wrap a bounded height
     (and re-verifying scroll behaviour) will silently do nothing. */
  background: var(--surface);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  font-weight: 600;
}
tbody tr:hover td { background: var(--surface-raised); }
table caption { text-align: left; font-size: 0.8rem; color: var(--text-muted); padding: 0 0.8rem 0.4rem; }
/* Timestamps and SHAs are read by comparison down a column, so they get
   fixed-width digits and a monospace face. */
td time, td .sha { font-variant-numeric: tabular-nums; font-family: var(--font-mono); font-size: 0.85em; }
code {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.05rem 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.85em;
}
pre {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 0.85rem;
  overflow-x: auto;
}
pre code { background: none; border: none; padding: 0; }
tr.drift td { background: var(--warn-bg); }

/* ---- badges ------------------------------------------------------------ */

/* Colour is never the only carrier. Each variant pairs a tint with a glyph in
   ::before and keeps its own text, because "block" sits beside a near-identical
   "allow" that means the opposite. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.badge-muted { color: var(--text-muted); }
.badge-info { color: var(--accent, #1f6feb); border-color: currentColor; }
.badge-block {
  color: var(--danger);
  background: var(--danger-bg);
  border-color: var(--danger);
}
.badge-block::before { content: "\2716"; }
.badge-warn {
  color: var(--warn);
  background: var(--warn-bg);
  border-color: var(--warn);
}
.badge-warn::before { content: "\26A0"; }

/* Trust score column: a bare ratio, and the "not counted" unknown-signal
   caption in the expandable detail beside it. */
.score { font-variant-numeric: tabular-nums; }
.signal-unknown { color: var(--text-muted); font-style: italic; }
.signal-posture { color: var(--text-muted); }
.signal-change { color: var(--text-muted); font-size: 0.9em; margin: 0.1rem 0 0.3rem 1rem; }

/* ---- filters ----------------------------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  align-items: end;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 0.9rem 1rem;
  margin: 0.6rem 0 1.1rem;
}
.filters label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.78rem;
  color: var(--text-muted);
}
.filters input[type=text], .filters input[type=date], .filters select {
  font: inherit;
  font-size: 0.875rem;
  padding: 0.35rem 0.45rem;
  color: var(--text);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
}
/* ---- notices and empty states ------------------------------------------ */

/* The refusal and empty-state prose is the most load-bearing writing in this
   UI — "an empty result is not a clean bill of health". It gets a surface of
   its own rather than the grey of a table caption. */
.notice {
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-card);
  background: var(--surface);
  padding: 0.85rem 1rem;
  margin: 0.7rem 0 1.1rem;
}
.notice-err { border-left-color: var(--danger); background: var(--danger-bg); }
/* Caution rather than failure: a destructive action pending confirmation,
   not a broken or refused one. Same shape as .notice-err, --warn tokens
   instead of --danger — the two states read as siblings, not duplicates. */
.notice-warn { border-left-color: var(--warn); background: var(--warn-bg); }
.notice ul { margin: 0.45rem 0 0; padding-left: 1.2rem; }
.empty {
  border: 1px dashed var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  padding: 1.1rem 1.25rem;
  margin: 0.7rem 0 1.1rem;
  color: var(--text-muted);
}
.empty strong, .empty em { color: var(--text); }
.fielderr { color: var(--danger); font-size: 0.75rem; max-width: 18rem; }

dl.identity-list { display: grid; grid-template-columns: max-content 1fr; gap: 0.3rem 1.1rem; margin: 0.5rem 0 1.4rem; }
dl.identity-list dt { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); }
dl.identity-list dd { margin: 0; }
.repos { margin: 0.4rem 0 0; padding-left: 1.1rem; }
.navform { display: inline; margin: 0; }
td.detail code { display: block; max-width: 28rem; overflow-x: auto; white-space: pre; }

/* ---- inline text emphasis ----------------------------------------------- */

/* Bare text-level emphasis used inline within prose — e.g. the SHA vocabulary
   legend's "unresolved" — as opposed to a badge chip. The word itself is
   already the carrier of meaning (colour is never the only one); this rule
   only makes sure that emphasis actually renders, matching the same --warn
   token .badge-warn uses for the identical state, so the two never disagree
   with each other. Without this rule the class in that legend is exactly the
   defect this file's component layer exists to close: a class name applied
   for decoration with no CSS behind it. */
.warn { color: var(--warn); font-weight: 600; }

/* ---- repository pages -------------------------------------------------- */

.segmented {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  overflow: hidden;
  margin: 0.25rem 0 0.75rem;
}
.segmented a {
  padding: 0.25rem 0.75rem;
  text-decoration: none;
  color: inherit;
}
.segmented a + a { border-left: 1px solid var(--border); }
/* Selected window: a filled pill, not just a colour shift, so the state
   reads without relying on hue perception alone. Text goes to #fff to match
   the one other filled-accent surface in this file (.btn-primary), which
   needs the same treatment for the same reason and — like that rule — is
   not overridden in the light block either. */
.segmented a[aria-current="true"] {
  background: var(--accent);
  color: #fff;
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.6rem;
  margin: 0.75rem 0 1rem;
}
.stat {
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  padding: 0.6rem 0.75rem;
  text-align: center;
}
.stat strong {
  display: block;
  font-size: 1.4rem;
  font-variant-numeric: tabular-nums;
}
.stat-bad { color: var(--danger); }

/* Collapsible workflow > job > action drill-down. Native <details>/<summary>
   supply the disclosure semantics and keyboard behaviour; this only styles
   the nesting so each level reads as a step down rather than a flat list. */
.wf-tree,
.wf-tree ul {
  list-style: none;
  padding-left: 0;
  margin: 0;
}
.wf-tree > li {
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  padding: 0.4rem 0.75rem;
  margin: 0.4rem 0;
}
.wf-tree details > ul {
  padding-left: 1.25rem;
  margin: 0.4rem 0 0.2rem;
}
.wf-tree summary { cursor: pointer; }
.wf-tree li { margin: 0.25rem 0; }

/* Policy editor: the document beside a check reference column. The column is
   sticky with its own scroll so it stays next to the textarea; under 900px
   it stacks below the form. */
.policy-editor {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 22rem;
  gap: 1.5rem;
  align-items: start;
}
.policy-editor textarea { width: 100%; box-sizing: border-box; }
.check-ref {
  position: sticky;
  top: 1rem;
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 0.75rem 1rem;
  font-size: 0.85rem;
}
.check-ref h2 { font-size: 1rem; }
.check-ref details {
  border-top: 1px solid var(--border);
  padding: 0.4rem 0;
}
.check-ref summary { cursor: pointer; }
.check-ref dl { margin: 0.4rem 0 0; }
.check-ref dt { margin-top: 0.4rem; overflow-wrap: anywhere; }
.check-ref dd { margin: 0.1rem 0 0 0.75rem; color: var(--text-muted); }
@media (max-width: 900px) {
  .policy-editor { grid-template-columns: minmax(0, 1fr); }
  .check-ref { position: static; max-height: none; }
}
